<commit_before>"""
Allows XML files to be operated on like Python objects.

Features:
    - load XML source from file pathnames, readable file objects or raw strings
    - add, get and set tag attributes like with python attributes
    - iterate over nodes
    - save the modified XMLFile or XMLObject to file

Example XML file::

    <?xml version="1.0" encoding="UTF-8"?>
    <rapsheets>
     <person name="John Smith" age="42">
        <!-- John Smith has an appeal in process against his last conviction -->
        <crime name="Armed robbery" date="March 11, 1994"/>
        <crime name="Aggravated burglary" date="June 9, 2001"/>
     </person>
     <person name="Mary Jones" age="33">
        <crime name="Prostitution" date="January 8, 1997"/>
        <crime name="Selling heroin" date="September 4, 2002"/>
        <crime name="Manslaughter" date="December 21, 2004"/>
     </person>
    </rapsheets>

Example usage::

    >> from xmlobject import XMLFile

    >> x = XMLFile(path="sample.xml")

    >> print x
    <xmlobj.XMLFile instance at 0xb7ccc52c>

    >> print x.root
    <XMLNode: rapsheets>

    >> print x.root._children
    [<XMLNode: text>, <XMLNode: person>, <XMLNode: text>,
     <XMLNode: person>, <XMLNode: text>]

    >> print x.root.person
    [<XMLNode: person>, <XMLNode: person>]

    >> print x.root.person[0].name
    John Smith

    >> john = x.root.person[0]

    >> john.height = 184

    >> c = john._addNode("crime")

    >> c.name = "Grand Theft Auto"

    >> c.date = "4 May, 2005"

    >> print x.toxml()
    <?xml version="1.0" ?>
    <rapsheets>
     <person age="42" height="184" name="John Smith">
        <!-- John Smith has an appeal in process against his last conviction -->
        <crime date="March 11, 1994" name="Armed robbery"/>
        <crime date="June 9, 2001" name="Aggravated burglary"/>
     <crime date="4 May, 2005" name="Grand Theft Auto"/></person>
     <person age="33" name="Mary Jones">
        <crime date="January 8, 1997" name="Prostitution"/>
        <crime date="September 4, 2002" name="Selling heroin"/>
        <crime date="December 21, 2004" name="Manslaughter"/>
     </person>
    </rapsheets>

    >>

"""

import sys, os
import xml.dom
import xml.dom.minidom
from xml.dom.minidom import parse, parseString, getDOMImplementation

impl = getDOMImplementation()

class MissingRootTag(Exception):
    """root tag name was not given"""

class InvalidXML(Exception):
    """failed to parse XML input"""

class CannotSave(Exception):
    """unable to save"""

class InvalidNode(Exception):
    """not a valid minidom node"""

class XMLFile:
    """
    Allows an xml file to be viewed and operated on
    as a python object.

    (If you're viewing the epydoc-generated HTML documentation, click the 'show private'
    link at the top right of this page to see all the methods)

    Holds the root node in the .root attribute, also in an attribute
    with the same name as this root node.
    """
    def __init__(self, **kw):
        """
        Create an XMLFile

        Keywords:
            - path - a pathname from which the file can be read
            - file - an open file object from which the raw xml
              can be read
            - raw - the raw xml itself
            - root - name of root tag, if not reading content

        Usage scenarios:
            1. Working with existing content - you must supply input in
               one of the following ways:
                   - 'path' must be an existing file, or
                   - 'file' must be a readable file object, or
                   - 'raw' must contain raw xml as a string
            2. Creating whole new content - you must give the name
               of the root tag in the 'root' keyword

        Notes:
            - Keyword precedence governing existing content is:
                1. path (if existing file)
                2. file
                3. raw
            - If working with existing content:
                - if the 'root' is given, then the content's toplevel tag
                  MUST match the value given for 'root'
                - trying to _save will raise an exception unless 'path'
                  has been given
            - if not working with existing content:
                - 'root' must be given
                - _save() will raise an exception unless 'path' has been given
        """
        path = kw.get("path", None)
        fobj = kw.get("file", None)
        raw = kw.get("raw", None)
        root = kw.get("root", None)
        textfilter = kw.get("textfilter", None)

        if path:
            self.path = path
            try:
                fobj = file(path)
            except IOError:
                pass
        else:
            self.path = None

        if fobj:
            raw = fobj.read()

        if raw:
            self.dom = xml.dom.minidom.parseString(raw)
        else:
            # could not source content, so create a blank slate
            if not root:
                # in which case, must give a root node name
                raise MissingRootTag(
                        "No existing content, so must specify root")

            # ok, create a blank dom
            self.dom = impl.createDocument(None, root, None)

        # get the root node, save it as attributes 'root' and name of node
        rootnode = self.dom.documentElement

        # now validate root tag
        if root:
            if rootnode.nodeName != root:
                raise IncorrectRootTag("Gave root='%s', input has root='%s'" % (
                    root, rootnode.nodeName))

        if textfilter:
            self.textfilter = textfilter
        else:
            self.textfilter = lambda x: x

        # need this for recursion in XMLNode
        self._childrenByName = {}
        self._children = []

        # add all the child nodes
        for child in self.dom.childNodes:
            childnode = XMLNode(self, child)
            #print "compare %s to %s" % (rootnode, child)
            if child == rootnode:
                #print "found root"
                self.root = childnode
        setattr(self, rootnode.nodeName, self.root)

    def save(self, where=None, obj=None):
        """
        Saves the document.

        If argument 'where' is given, saves to it, otherwise
        tries to save to the original given 'path' (or barfs)

        Value can be a string (taken to be a file path), or an open
        file object.
        """
        obj = obj or self.dom

        if not where:
            if self._root.path:
                where = self._root.path

        if isinstance(where, str):
            where = file(where, "w")

        if not where:
            raise CannotSave("No save destination, and no original path")

        where.write(obj.toxml())
        where.flush()

    def saveAs(self, path):
        """
        save this time, and all subsequent times, to filename 'path'
        """
        self.path = path
        self.save()

    def toxml(self):
        return self.dom.toxml()

    def __len__(self):
        """
        returns number of child nodes
        """
        return len(self._children)

    def __getitem__(self, idx):
        if isinstance(idx, int):
            return self._children[idx]
        else:
            return self._childrenByName[idx]

class XMLNode:
    """
    This is the workhorse for the xml object interface

    (If you're viewing the epydoc-generated HTML documentation, click the 'show private'
    link at the top right of this page to see all the methods)

    """
    def __init__(self, parent, node):
        """
        You shouldn't need to instantiate this directly
        """
        self._parent = parent
        if isinstance(parent, XMLFile):
            self._root = parent
        else:
            self._root = parent._root
        self._node = node
        self._childrenByName = {}
        self._children = []

        # add ourself to parent's children registry
        parent._children.append(self)

        # the deal with named subtags is that we store the first instance
        # as itself, and with second and subsequent instances, we make a list
        parentDict = self._parent._childrenByName
        nodeName = node.nodeName
        if not parentDict.has_key(nodeName):
            parentDict[nodeName] = parent.__dict__[nodeName] = self
        else:
            if isinstance(parentDict[nodeName], XMLNode):
                # this is the second child node of a given tag name, so convert
                # the instance to a list
                parentDict[nodeName] = parent.__dict__[nodeName] = [parentDict[nodeName]]
            parentDict[nodeName].append(self)

        # figure out our type
        self._value = None
        if isinstance(node, xml.dom.minidom.Text):
            self._type = "text"
            self._value = self._root.textfilter(node.nodeValue)
        elif isinstance(node, xml.dom.minidom.Element):
            self._type = "node"
        elif isinstance(node, xml.dom.minidom.Comment):
            self._type = "comment"
            self._value = node.nodeValue
        else:
            raise InvalidNode("node class %s" % node.__class__)

        # and wrap all the child nodes
        for child in node.childNodes:
            XMLNode(self, child)

    def _render(self):
        """
        Produces well-formed XML of this node's contents,
        indented as required
        """
        return self._node.toxml()

    def __repr__(self):
        if self._type == "node":
            return "<XMLNode: %s>" % self._node.nodeName
        else:
            return "<XMLNode: %s>" % self._type

    def __getattr__(self, attr):
        """
        Fetches an attribute or child node of this tag

        If it's an attribute, then returns the attribute value as a string.

        If a child node, then:
            - if there is only one child node of that name, return it
            - if there is more than one child node of that name, return a list
              of child nodes of that tag name

        Supports some magic attributes:
            - _text - the value of the first child node of type text
        """
        #print "%s: __getattr__: attr=%s" % (self, attr)

        if attr == '_text':
            # magic attribute to return text
            tnode = self['#text']
            if isinstance(tnode, list):
                tnode = tnode[0]
            return tnode._value

        if self._type in ['text', 'comment']:
            if attr == '_value':
                return self._node.nodeValue
            else:
                raise AttributeError(attr)

        if self._node.hasAttribute(attr):
            return self._node.getAttribute(attr)
        elif self._childrenByName.has_key(attr):
            return self._childrenByName[attr]

        #elif attr == 'value':
            # magic attribute

        else:
            raise AttributeError(attr)

    def __setattr__(self, attr, val):
        """
        Change the value of an attribute of this tag

        The magic attribute '_text' can be used to set the first child
        text node's value

        For example::

            Consider:

              <somenode>
                <child>foo</child>
              </somenode>

            >> somenode
            <XMLNODE: somenode>
            >> somenode.child
            <XMLNODE: child>
            >> somenode.child._text
            'foo'
            >> somenode._toxml()
            u'<somenode><child>foo</child></somenode>'
            >> somenode.child._text = 'bar'
            >> somenode.child._text
            'bar'
            >> somenode.child._toxml()
            u'<somenode><child>bar/child></somenode>'

        """
        if attr.startswith("_"):

            # magic attribute for setting _text
            if attr == '_text':
                tnode = self['#text']
                if isinstance(tnode, list):
                    tnode = tnode[0]
                tnode._node.nodeValue = val
                tnode._value = val
                return

            self.__dict__[attr] = val
        elif self._type in ['text', 'comment']:
            self._node.nodeValue = val
        else:
            # discern between attribute and child node
            if self._childrenByName.has_key(attr):
                raise Exception("Attribute Exists")
            self._node.setAttribute(attr, str(val))

    def _keys(self):
        """
        Return a list of attribute names
        """
        return self._node.attributes.keys()

    def _values(self):
        """
        Returns a list of (attrname, attrval) tuples for this tag
        """
        return [self._node.getAttribute(k) for k in self._node.attributes.keys()]

    def _items(self):
        """
        returns a list of attribute values for this tag
        """
        return [(k, self._node.getAttribute(k)) for k in self._node.attributes.keys()]

    def _has_key(self, k):
        """
        returns True if this tag has an attribute of the given name
        """
        return self._node.hasAttribute(k) or self._childrenByName.has_key(k)

    def _get(self, k, default=None):
        """
        returns the value of attribute k, or default if no such attribute
        """
        if self._has_key(k):
            return getattr(self, k)
        else:
            return default
    def __len__(self):
        """
        returns number of child nodes
        """
        return len(self._children)

    def __getitem__(self, idx):
        """
        if given key is numeric, return the nth child, otherwise
        try to return the child tag (or list of child tags) having
        the key as the tag name
        """
        #print "__getitem__: idx=%s" % str(idx)

        if isinstance(idx, slice) or isinstance(idx, int):
            return self._children[idx]
        elif isinstance(idx, str):
            return self._childrenByName[idx]
        else:
            raise IndexError(idx)

    def _addNode(self, child):
        """
        Tries to append a child node to the tree, and returns it

        Value of 'child' must be one of:
            - a string (in which case it is taken to be the name
              of the new node's tag)
            - a dom object, in which case it will be wrapped and added
            - an XMLNode object, in which case it will be added without
              wrapping
        """

        if isinstance(child, XMLNode):

            # add it to our children registry
            self._children.append(child)

            parentDict = self._childrenByName
            nodeName = child._node.nodeName

            if not parentDict.has_key(nodeName):
                parentDict[nodeName] = parent.__dict__[nodeName] = child
            else:
                if isinstance(parentDict[nodeName], XMLNode):
                    # this is the second child node of a given tag name, so convert
                    # the instance to a list
                    parentDict[nodeName] = self.__dict__[nodeName] = [parentDict[nodeName]]
                parentDict[nodeName].append(child)

            # and stick it in the dom
            self._node.appendChild(child._node)

            return child

        elif isinstance(child, str):
            childNode = self._root.dom.createElement(child)
            self._node.appendChild(childNode)

        elif isinstance(child, xml.dom.minidom.Element):
            childNode = child
            child = childNode.nodeName
            self._node.appendChild(childNode)

        return XMLNode(self, childNode)

    def _addText(self, value):
        """
        Tries to append a child text node, with the given text, to the tree,
        and returns the created node object
        """
        childNode = self._root.dom.createTextNode(value)
        self._node.appendChild(childNode)
        return XMLNode(self, childNode)

    def _addComment(self, comment):
        """
        Tries to append a child comment node (with the given text value)
        to the tree, and returns the create node object
        """
        childNode = self._root.dom.createCommentNode(comment)
        self._node.appendChild(childNode)
        return XMLNode(self, childNode)

    def _save(self, where=None):
        """
        Generates well-formed XML from just this node, and saves it
        to a file.

        Argument 'where' is either an open file object, or a pathname

        If 'where' is not given, then saves the entire document tree.
        """
        if not where:
            self._root.save()
        else:
            self._root.save(where, self._node)

    def _toxml(self):
        """
        renders just this node out to raw xml code
        """
        return self._node.toxml()

<commit_msg>minor update<commit_after>"""
Allows XML files to be operated on like Python objects.

Features:
    - load XML source from file pathnames, readable file objects or raw strings
    - add, get and set tag attributes like with python attributes
    - iterate over nodes
    - save the modified XMLFile or XMLObject to file

Example XML file::

    <?xml version="1.0" encoding="UTF-8"?>
    <rapsheets>
     <person name="John Smith" age="42">
        <!-- John Smith has an appeal in process against his last conviction -->
        <crime name="Armed robbery" date="March 11, 1994"/>
        <crime name="Aggravated burglary" date="June 9, 2001"/>
     </person>
     <person name="Mary Jones" age="33">
        <crime name="Prostitution" date="January 8, 1997"/>
        <crime name="Selling heroin" date="September 4, 2002"/>
        <crime name="Manslaughter" date="December 21, 2004"/>
     </person>
    </rapsheets>

Example usage::

    >> from xmlobject import XMLFile

    >> x = XMLFile(path="sample.xml")

    >> print x
    <xmlobj.XMLFile instance at 0xb7ccc52c>

    >> print x.root
    <XMLNode: rapsheets>

    >> print x.root._children
    [<XMLNode: text>, <XMLNode: person>, <XMLNode: text>,
     <XMLNode: person>, <XMLNode: text>]

    >> print x.root.person
    [<XMLNode: person>, <XMLNode: person>]

    >> print x.root.person[0].name
    John Smith

    >> john = x.root.person[0]

    >> john.height = 184

    >> c = john._addNode("crime")

    >> c.name = "Grand Theft Auto"

    >> c.date = "4 May, 2005"

    >> print x.toxml()
    <?xml version="1.0" ?>
    <rapsheets>
     <person age="42" height="184" name="John Smith">
        <!-- John Smith has an appeal in process against his last conviction -->
        <crime date="March 11, 1994" name="Armed robbery"/>
        <crime date="June 9, 2001" name="Aggravated burglary"/>
     <crime date="4 May, 2005" name="Grand Theft Auto"/></person>
     <person age="33" name="Mary Jones">
        <crime date="January 8, 1997" name="Prostitution"/>
        <crime date="September 4, 2002" name="Selling heroin"/>
        <crime date="December 21, 2004" name="Manslaughter"/>
     </person>
    </rapsheets>

    >>

"""

import sys, os
import xml.dom
import xml.dom.minidom
from xml.dom.minidom import parse, parseString, getDOMImplementation

impl = getDOMImplementation()

class MissingRootTag(Exception):
    """root tag name was not given"""

class InvalidXML(Exception):
    """failed to parse XML input"""

class CannotSave(Exception):
    """unable to save"""

class InvalidNode(Exception):
    """not a valid minidom node"""

class XMLFile:
    """
    Allows an xml file to be viewed and operated on
    as a python object.

    (If you're viewing the epydoc-generated HTML documentation, click the 'show private'
    link at the top right of this page to see all the methods)

    Holds the root node in the .root attribute, also in an attribute
    with the same name as this root node.
    """
    def __init__(self, **kw):
        """
        Create an XMLFile

        Keywords:
            - path - a pathname from which the file can be read
            - file - an open file object from which the raw xml
              can be read
            - raw - the raw xml itself
            - root - name of root tag, if not reading content

        Usage scenarios:
            1. Working with existing content - you must supply input in
               one of the following ways:
                   - 'path' must be an existing file, or
                   - 'file' must be a readable file object, or
                   - 'raw' must contain raw xml as a string
            2. Creating whole new content - you must give the name
               of the root tag in the 'root' keyword

        Notes:
            - Keyword precedence governing existing content is:
                1. path (if existing file)
                2. file
                3. raw
            - If working with existing content:
                - if the 'root' is given, then the content's toplevel tag
                  MUST match the value given for 'root'
                - trying to _save will raise an exception unless 'path'
                  has been given
            - if not working with existing content:
                - 'root' must be given
                - _save() will raise an exception unless 'path' has been given
        """
        path = kw.get("path", None)
        fobj = kw.get("file", None)
        raw = kw.get("raw", None)
        root = kw.get("root", None)
        textfilter = kw.get("textfilter", None)

        if path:
            self.path = path
            try:
                fobj = file(path)
            except IOError:
                pass
        else:
            self.path = None

        if fobj:
            raw = fobj.read()

        if raw:
            self.dom = xml.dom.minidom.parseString(raw)
        else:
            # could not source content, so create a blank slate
            if not root:
                # in which case, must give a root node name
                raise MissingRootTag(
                        "No existing content, so must specify root")

            # ok, create a blank dom
            self.dom = impl.createDocument(None, root, None)

        # get the root node, save it as attributes 'root' and name of node
        rootnode = self.dom.documentElement

        # now validate root tag
        if root:
            if rootnode.nodeName != root:
                raise IncorrectRootTag("Gave root='%s', input has root='%s'" % (
                    root, rootnode.nodeName))

        if textfilter:
            self.textfilter = textfilter
        else:
            self.textfilter = lambda x: x

        # need this for recursion in XMLNode
        self._childrenByName = {}
        self._children = []

        # add all the child nodes
        for child in self.dom.childNodes:
            childnode = XMLNode(self, child)
            #print "compare %s to %s" % (rootnode, child)
            if child == rootnode:
                #print "found root"
                self.root = childnode
        setattr(self, rootnode.nodeName, self.root)

    def save(self, where=None, obj=None):
        """
        Saves the document.

        If argument 'where' is given, saves to it, otherwise
        tries to save to the original given 'path' (or barfs)

        Value can be a string (taken to be a file path), or an open
        file object.
        """
        obj = obj or self.dom

        if not where:
            if self._root.path:
                where = self._root.path

        if isinstance(where, str):
            where = file(where, "w")

        if not where:
            raise CannotSave("No save destination, and no original path")

        where.write(obj.toxml())
        where.flush()

    def saveAs(self, path):
        """
        save this time, and all subsequent times, to filename 'path'
        """
        self.path = path
        self.save()

    def toxml(self):
        return self.dom.toxml()

    def __len__(self):
        """
        returns number of child nodes
        """
        return len(self._children)

    def __getitem__(self, idx):
        if isinstance(idx, int):
            return self._children[idx]
        else:
            return self._childrenByName[idx]

class XMLNode:
    """
    This is the workhorse for the xml object interface

    (If you're viewing the epydoc-generated HTML documentation, click the 'show private'
    link at the top right of this page to see all the methods)

    """
    def __init__(self, parent, node):
        """
        You shouldn't need to instantiate this directly
        """
        self._parent = parent
        if isinstance(parent, XMLFile):
            self._root = parent
        else:
            self._root = parent._root
        self._node = node
        self._childrenByName = {}
        self._children = []

        # add ourself to parent's children registry
        parent._children.append(self)

        # the deal with named subtags is that we store the first instance
        # as itself, and with second and subsequent instances, we make a list
        parentDict = self._parent._childrenByName
        nodeName = node.nodeName
        if not parentDict.has_key(nodeName):
            parentDict[nodeName] = parent.__dict__[nodeName] = self
        else:
            if isinstance(parentDict[nodeName], XMLNode):
                # this is the second child node of a given tag name, so convert
                # the instance to a list
                parentDict[nodeName] = parent.__dict__[nodeName] = [parentDict[nodeName]]
            parentDict[nodeName].append(self)

        # figure out our type
        self._value = None
        if isinstance(node, xml.dom.minidom.Text):
            self._type = "text"
            self._value = self._root.textfilter(node.nodeValue)
        elif isinstance(node, xml.dom.minidom.Element):
            self._type = "node"
        elif isinstance(node, xml.dom.minidom.Comment):
            self._type = "comment"
            self._value = node.nodeValue
        else:
            raise InvalidNode("node class %s" % node.__class__)

        # and wrap all the child nodes
        for child in node.childNodes:
            XMLNode(self, child)

    def _render(self):
        """
        Produces well-formed XML of this node's contents,
        indented as required
        """
        return self._node.toxml()

    def __repr__(self):
        if self._type == "node":
            return "<XMLNode: %s>" % self._node.nodeName
        else:
            return "<XMLNode: %s>" % self._type

    def __getattr__(self, attr):
        """
        Fetches an attribute or child node of this tag

        If it's an attribute, then returns the attribute value as a string.

        If a child node, then:
            - if there is only one child node of that name, return it
            - if there is more than one child node of that name, return a list
              of child nodes of that tag name

        Supports some magic attributes:
            - _text - the value of the first child node of type text
        """
        #print "%s: __getattr__: attr=%s" % (self, attr)

        if attr == '_text':
            # magic attribute to return text
            tnode = self['#text']
            if isinstance(tnode, list):
                tnode = tnode[0]
            return tnode._value

        if self._type in ['text', 'comment']:
            if attr == '_value':
                return self._node.nodeValue
            else:
                raise AttributeError(attr)

        if self._node.hasAttribute(attr):
            return self._node.getAttribute(attr)
        elif self._childrenByName.has_key(attr):
            return self._childrenByName[attr]

        #elif attr == 'value':
            # magic attribute

        else:
            raise AttributeError(attr)

    def __setattr__(self, attr, val):
        """
        Change the value of an attribute of this tag

        The magic attribute '_text' can be used to set the first child
        text node's value

        For example::

            Consider:

              <somenode>
                <child>foo</child>
              </somenode>

            >> somenode
            <XMLNODE: somenode>
            >> somenode.child
            <XMLNODE: child>
            >> somenode.child._text
            'foo'
            >> somenode._toxml()
            u'<somenode><child>foo</child></somenode>'
            >> somenode.child._text = 'bar'
            >> somenode.child._text
            'bar'
            >> somenode.child._toxml()
            u'<somenode><child>bar/child></somenode>'

        """
        if attr.startswith("_"):

            # magic attribute for setting _text
            if attr == '_text':
                tnode = self['#text']
                if isinstance(tnode, list):
                    tnode = tnode[0]
                tnode._node.nodeValue = val
                tnode._value = val
                return

            self.__dict__[attr] = val
        elif self._type in ['text', 'comment']:
            self._node.nodeValue = val
        else:
            # discern between attribute and child node
            if self._childrenByName.has_key(attr):
                raise Exception("Attribute Exists")
            self._node.setAttribute(attr, str(val))

    def _keys(self):
        """
        Return a list of attribute names
        """
        return self._node.attributes.keys()

    def _values(self):
        """
        Returns a list of (attrname, attrval) tuples for this tag
        """
        return [self._node.getAttribute(k) for k in self._node.attributes.keys()]

    def _items(self):
        """
        returns a list of attribute values for this tag
        """
        return [(k, self._node.getAttribute(k)) for k in self._node.attributes.keys()]

    def _has_key(self, k):
        """
        returns True if this tag has an attribute of the given name
        """
        return self._node.hasAttribute(k) or self._childrenByName.has_key(k)

    def _get_name(self):
        if self._type == "node":
            return self._node.nodeName
        else:
            return self._type

    def _get(self, k, default=None):
        """
        returns the value of attribute k, or default if no such attribute
        """
        if self._has_key(k):
            return getattr(self, k)
        else:
            return default

    def __len__(self):
        """
        returns number of child nodes
        """
        return len(self._children)

    def __getitem__(self, idx):
        """
        if given key is numeric, return the nth child, otherwise
        try to return the child tag (or list of child tags) having
        the key as the tag name
        """
        #print "__getitem__: idx=%s" % str(idx)

        if isinstance(idx, slice) or isinstance(idx, int):
            return self._children[idx]
        elif isinstance(idx, str):
            return self._childrenByName[idx]
        else:
            raise IndexError(idx)

    def _addNode(self, child):
        """
        Tries to append a child node to the tree, and returns it

        Value of 'child' must be one of:
            - a string (in which case it is taken to be the name
              of the new node's tag)
            - a dom object, in which case it will be wrapped and added
            - an XMLNode object, in which case it will be added without
              wrapping
        """

        if isinstance(child, XMLNode):

            # add it to our children registry
            self._children.append(child)

            parentDict = self._childrenByName
            nodeName = child._node.nodeName

            if not parentDict.has_key(nodeName):
                parentDict[nodeName] = parent.__dict__[nodeName] = child
            else:
                if isinstance(parentDict[nodeName], XMLNode):
                    # this is the second child node of a given tag name, so convert
                    # the instance to a list
                    parentDict[nodeName] = self.__dict__[nodeName] = [parentDict[nodeName]]
                parentDict[nodeName].append(child)

            # and stick it in the dom
            self._node.appendChild(child._node)

            return child

        elif isinstance(child, str):
            childNode = self._root.dom.createElement(child)
            self._node.appendChild(childNode)

        elif isinstance(child, xml.dom.minidom.Element):
            childNode = child
            child = childNode.nodeName
            self._node.appendChild(childNode)

        return XMLNode(self, childNode)

    def _addText(self, value):
        """
        Tries to append a child text node, with the given text, to the tree,
        and returns the created node object
        """
        childNode = self._root.dom.createTextNode(value)
        self._node.appendChild(childNode)
        return XMLNode(self, childNode)

    def _addComment(self, comment):
        """
        Tries to append a child comment node (with the given text value)
        to the tree, and returns the create node object
        """
        childNode = self._root.dom.createCommentNode(comment)
        self._node.appendChild(childNode)
        return XMLNode(self, childNode)

    def _save(self, where=None):
        """
        Generates well-formed XML from just this node, and saves it
        to a file.

        Argument 'where' is either an open file object, or a pathname

        If 'where' is not given, then saves the entire document tree.
        """
        if not where:
            self._root.save()
        else:
            self._root.save(where, self._node)

    def _toxml(self):
        """
        renders just this node out to raw xml code
        """
        return self._node.toxml()

    def _treeWalker(self, node, nodes):
        for child in node._children:
            if child._type == 'node':
                nodes.append(child)
                self._treeWalker(child, nodes)

    def _toflat(self):
        ret = [self]
        self._treeWalker(self, ret)
        return ret

    _name = property(_get_name)
<|endoftext|>


<commit_before>import os.path

import doctest
import logging
import os
import tic
import unittest

def get_unit_tests(args=None):

    if not args:
        files = tic.loader.locate("*.py")

    elif _is_args_dir(args):
        files = tic.loader.locate("*.py",
            root=os.path.join(os.curdir, _convert_module_to_path(args)))
    elif _is_args_module(args):
        module = _is_args_module(args)
        module_suites = unittest.defaultTestLoader.loadTestsFromModule(module)
        if module_suites.countTestCases():
            return [module_suites]
    elif _is_args_TestCase(args):
        return [unittest.defaultTestLoader.loadTestsFromTestCase(_is_args_TestCase(args))]
    else:
        #maybe its a method?
        testcase = unittest.defaultTestLoader.loadTestsFromName(args)
        return [testcase]
#        raise Exception('Cant find test: %s' % args)

    suites = []
    for file in files:
        p = "%s%s" % (os.path.join(os.curdir, "lib"), os.sep)
        if file.startswith(p):
            continue
        module_name = tic.loader._get_module_name(file)
        module = tic.utils.importlib.import_module(module_name)
        module_suites = unittest.defaultTestLoader.loadTestsFromModule(module)
        try:
            module_suites.addTests(doctest.DocTestSuite(module))
        except:
            pass
        if not module_suites.countTestCases():
            continue
        suites.append(module_suites)

    return suites

def _is_args_TestCase(args):
    module_name, TestCase = args.rsplit('.', 1)
    module = _is_args_module(module_name)
    if module and hasattr(module, TestCase):
        return getattr(module, TestCase)
    return False

def _is_args_module(args):
    try:
        module = tic.utils.importlib.import_module(args)
        return module
    except:
        return None

def _is_args_dir(args):
    if args:
        dir = os.path.join(os.curdir, _convert_module_to_path(args))
        return os.path.isdir(dir)
    return False

def _convert_module_to_path(module):
    """
    converts 'a.b.c' to 'a/b/c'
    """
    return module.replace('.', os.sep)

def run(args):
    """
    Runs all the unit tests available
    """
    os.environ['APPLICATION_ID'] = "tic-testing-framework"
    os.environ['AUTH_DOMAIN'] = 'localhost'
    os.environ['SERVER_SOFTWARE'] = 'Development/1.0 (AppEngineTest)'
    logging.basicConfig(level=logging.DEBUG)

    t = unittest.TestSuite()
    for suite in get_unit_tests(args):
        if hasattr(suite, "_tests"):
            t.addTests(suite._tests)
        else:
            t.addTests([suite])
    unittest.TextTestRunner(verbosity=1).run(t)

if __name__ == '__main__':
    run()

<commit_msg>bug fix.. ignore tests in lib dir<commit_after>import os.path

import doctest
import logging
import os
import tic
import unittest

def get_unit_tests(args=None):

    if not args:
        files = tic.loader.locate("*.py")

    elif _is_args_dir(args):
        files = tic.loader.locate("*.py",
            root=os.path.join(os.curdir, _convert_module_to_path(args)))
    elif _is_args_module(args):
        module = _is_args_module(args)
        module_suites = unittest.defaultTestLoader.loadTestsFromModule(module)
        if module_suites.countTestCases():
            return [module_suites]
    elif _is_args_TestCase(args):
        return [unittest.defaultTestLoader.loadTestsFromTestCase(_is_args_TestCase(args))]
    else:
        #maybe its a method?
        testcase = unittest.defaultTestLoader.loadTestsFromName(args)
        return [testcase]
#        raise Exception('Cant find test: %s' % args)

    suites = []
    for file in files:
        p = "%s%s" % (os.path.join(os.path.abspath(os.curdir), "lib"), os.sep)
        print file, p
        if file.startswith(p):
            continue
        module_name = tic.loader._get_module_name(file)
        module = tic.utils.importlib.import_module(module_name)
        module_suites = unittest.defaultTestLoader.loadTestsFromModule(module)
        try:
            module_suites.addTests(doctest.DocTestSuite(module))
        except:
            pass
        if not module_suites.countTestCases():
            continue
        suites.append(module_suites)

    return suites

def _is_args_TestCase(args):
    module_name, TestCase = args.rsplit('.', 1)
    module = _is_args_module(module_name)
    if module and hasattr(module, TestCase):
        return getattr(module, TestCase)
    return False

def _is_args_module(args):
    try:
        module = tic.utils.importlib.import_module(args)
        return module
    except:
        return None

def _is_args_dir(args):
    if args:
        dir = os.path.join(os.curdir, _convert_module_to_path(args))
        return os.path.isdir(dir)
    return False

def _convert_module_to_path(module):
    """
    converts 'a.b.c' to 'a/b/c'
    """
    return module.replace('.', os.sep)

def run(args):
    """
    Runs all the unit tests available
    """
    os.environ['APPLICATION_ID'] = "tic-testing-framework"
    os.environ['AUTH_DOMAIN'] = 'localhost'
    os.environ['SERVER_SOFTWARE'] = 'Development/1.0 (AppEngineTest)'
    logging.basicConfig(level=logging.DEBUG)

    t = unittest.TestSuite()
    for suite in get_unit_tests(args):
        if hasattr(suite, "_tests"):
            t.addTests(suite._tests)
        else:
            t.addTests([suite])
    unittest.TextTestRunner(verbosity=1).run(t)

if __name__ == '__main__':
    run()

<|endoftext|>


<commit_before>#!/usr/bin/env python

# Copyright 2021 Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""
A sample script showing how to create, list and delete Google Compute Engine
instances using the google-cloud-compute library. It can be run from command
line to create, list and delete an instance in a given project in a given zone.
"""

# [START compute_instances_create]
# [START compute_instances_delete]
import sys

# [START compute_instances_list]
# [START compute_instances_list_all]
# [START compute_instances_operation_check]
import typing

import google.cloud.compute_v1 as compute_v1

# [END compute_instances_operation_check]
# [END compute_instances_list_all]
# [END compute_instances_list]
# [END compute_instances_delete]
# [END compute_instances_create]

# [START compute_instances_list]
def list_instances(project_id: str, zone: str) -> typing.Iterable[compute_v1.Instance]:
    """
    Gets a list of instances created in given project in given zone.
    Returns an iterable collection of Instance objects.

    Args:
        project_id: ID or number of the project you want to use.
        zone: Name of the zone you want to check, for example: us-west3-b

    Returns:
        An iterable collection of Instance objects.
    """
    instance_client = compute_v1.InstancesClient()
    instance_list = instance_client.list(project=project_id, zone=zone)

    print(f"Instances found in zone {zone}:")
    for instance in instance_list:
        print(f" - {instance.name} ({instance.machine_type})")

    return instance_list

# [END compute_instances_list]

# [START compute_instances_list_all]
def list_all_instances(
    project_id: str,
) -> typing.Dict[str, typing.Iterable[compute_v1.Instance]]:
    """
    Returns a dictionary of all instances present in a project, grouped by their zone.

    Args:
        project_id: ID or number of the project you want to use.

    Returns:
        A dictionary with zone names as keys (in form of "zones/{zone_name}") and
        iterable collections of Instance objects as values.
    """
    instance_client = compute_v1.InstancesClient()
    agg_list = instance_client.aggregated_list(project=project_id)
    all_instances = {}
    print("Instances found:")
    for zone, response in agg_list:
        if response.instances:
            all_instances[zone] = response.instances
            print(f" {zone}:")
            for instance in response.instances:
                print(f" - {instance.name} ({instance.machine_type})")
    return all_instances

# [END compute_instances_list_all]

# [START compute_instances_create]
def create_instance(
    project_id: str,
    zone: str,
    instance_name: str,
    machine_type: str = "n1-standard-1",
    source_image: str = "projects/debian-cloud/global/images/family/debian-10",
    network_name: str = "global/networks/default",
) -> compute_v1.Instance:
    """
    Sends an instance creation request to GCP and waits for it to complete.

    Args:
        project_id: ID or number of the project you want to use.
        zone: Name of the zone you want to use, for example: us-west3-b
        instance_name: Name of the new machine.
        machine_type: Machine type you want to create in following format:
            "zones/{zone}/machineTypes/{type_name}". For example:
            "zones/europe-west3-c/machineTypes/f1-micro"
            You can find the list of available machine types using:
            https://cloud.google.com/sdk/gcloud/reference/compute/machine-types/list
        source_image: Path the the disk image you want to use for your boot
            disk. This can be one of the public images
            (e.g. "projects/debian-cloud/global/images/family/debian-10")
            or a private image you have access to.
            You can check the list of available public images using:
            $ gcloud compute images list
        network_name: Name of the network you want the new instance to use.
            For example: global/networks/default - if you want to use the
            default network.

    Returns:
        Instance object.
    """
    instance_client = compute_v1.InstancesClient()

    # Every machine requires at least one persistent disk
    disk = compute_v1.AttachedDisk()
    initialize_params = compute_v1.AttachedDiskInitializeParams()
    initialize_params.source_image = (
        source_image  # "projects/debian-cloud/global/images/family/debian-10"
    )
    initialize_params.disk_size_gb = "10"
    disk.initialize_params = initialize_params
    disk.auto_delete = True
    disk.boot = True
    disk.type_ = compute_v1.AttachedDisk.Type.PERSISTENT

    # Every machine needs to be connected to a VPC network.
    # The 'default' network is created automatically in every project.
    network_interface = compute_v1.NetworkInterface()
    network_interface.name = network_name

    # Collecting all the information into the Instance object
    instance = compute_v1.Instance()
    instance.name = instance_name
    instance.disks = [disk]
    full_machine_type_name = f"zones/{zone}/machineTypes/{machine_type}"
    instance.machine_type = full_machine_type_name
    instance.network_interfaces = [network_interface]

    # Preparing the InsertInstanceRequest
    request = compute_v1.InsertInstanceRequest()
    request.zone = zone
    request.project = project_id
    request.instance_resource = instance

    print(f"Creating the {instance_name} instance in {zone}...")
    operation = instance_client.insert(request=request)
    if operation.status == compute_v1.Operation.Status.RUNNING:
        operation_client = compute_v1.ZoneOperationsClient()
        operation = operation_client.wait(
            operation=operation.name, zone=zone, project=project_id
        )
    if operation.error:
        print("Error during creation:", operation.error, file=sys.stderr)
    if operation.warnings:
        print("Warning during creation:", operation.warnings, file=sys.stderr)
    print(f"Instance {instance_name} created.")
    return instance

# [END compute_instances_create]

# [START compute_instances_delete]
def delete_instance(project_id: str, zone: str, machine_name: str) -> None:
    """
    Sends a delete request to GCP and waits for it to complete.

    Args:
        project_id: ID or number of the project you want to use.
        zone: Name of the zone you want to use, for example: us-west3-b
        machine_name: Name of the machine you want to delete.
    """
    instance_client = compute_v1.InstancesClient()

    print(f"Deleting {machine_name} from {zone}...")
    operation = instance_client.delete(
        project=project_id, zone=zone, instance=machine_name
    )
    if operation.status == compute_v1.Operation.Status.RUNNING:
        operation_client = compute_v1.ZoneOperationsClient()
        operation = operation_client.wait(
            operation=operation.name, zone=zone, project=project_id
        )
    if operation.error:
        print("Error during deletion:", operation.error, file=sys.stderr)
    if operation.warnings:
        print("Warning during deletion:", operation.warnings, file=sys.stderr)
    print(f"Instance {machine_name} deleted.")
    return

# [END compute_instances_delete]

# [START compute_instances_operation_check]
def wait_for_operation(
    operation: compute_v1.Operation, project_id: str
) -> compute_v1.Operation:
    """
    This method waits for an operation to be completed. Calling this function
    will block until the operation is finished.

    Args:
        operation: The Operation object representing the operation you want to
            wait on.
        project_id: ID or number of the project owning the operation.

    Returns:
        Finished Operation object.
    """
    kwargs = {"project": project_id, "operation": operation.name}
    if operation.zone:
        client = compute_v1.ZoneOperationsClient()
        # Operation.zone is a full URL address of a zone, so we need to extract just the name
        kwargs["zone"] = operation.zone.rsplit("/", maxsplit=1)[1]
    elif operation.region:
        client = compute_v1.RegionOperationsClient()
        # Operation.region is a full URL address of a zone, so we need to extract just the name
        kwargs["region"] = operation.region.rsplit("/", maxsplit=1)[1]
    else:
        client = compute_v1.GlobalOperationsClient()
    return client.wait(**kwargs)

# [END compute_instances_operation_check]

def main(project_id: str, zone: str, instance_name: str) -> None:

    create_instance(project_id, zone, instance_name)

    zone_instances = list_instances(project_id, zone)
    print(f"Instances found in {zone}:", ", ".join(i.name for i in zone_instances))

    all_instances = list_all_instances(project_id)
    print(f"Instances found in project {project_id}:")
    for i_zone, instances in all_instances.items():
        print(f"{i_zone}:", ", ".join(i.name for i in instances))

    delete_instance(project_id, zone, instance_name)

if __name__ == "__main__":
    import uuid
    import google.auth
    import google.auth.exceptions

    try:
        default_project_id = google.auth.default()[1]
    except google.auth.exceptions.DefaultCredentialsError:
        print(
            "Please use `gcloud auth application-default login` "
            "or set GOOGLE_APPLICATION_CREDENTIALS to use this script."
        )
    else:
        instance_name = "quickstart-" + uuid.uuid4().hex[:10]
        instance_zone = "europe-central2-b"
        main(default_project_id, instance_zone, instance_name)
<commit_msg>docs: samples docstring and comments update (#69)<commit_after>#!/usr/bin/env python

# Copyright 2021 Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""
A sample script showing how to create, list and delete Google Compute Engine
instances using the google-cloud-compute library. It can be run from command
line to create, list and delete an instance in a given project in a given zone.
"""

# [START compute_instances_create]
# [START compute_instances_delete]
import sys

# [START compute_instances_list]
# [START compute_instances_list_all]
# [START compute_instances_operation_check]
import typing

import google.cloud.compute_v1 as compute_v1

# [END compute_instances_operation_check]
# [END compute_instances_list_all]
# [END compute_instances_list]
# [END compute_instances_delete]
# [END compute_instances_create]

# [START compute_instances_list]
def list_instances(project_id: str, zone: str) -> typing.Iterable[compute_v1.Instance]:
    """
    List all instances in the given zone in the specified project.

    Args:
        project_id: project ID or project number of the Cloud project you want to use.
        zone: name of the zone you want to use. For example: “us-west3-b”
    Returns:
        An iterable collection of Instance objects.
    """
    instance_client = compute_v1.InstancesClient()
    instance_list = instance_client.list(project=project_id, zone=zone)

    print(f"Instances found in zone {zone}:")
    for instance in instance_list:
        print(f" - {instance.name} ({instance.machine_type})")

    return instance_list
# [END compute_instances_list]

# [START compute_instances_list_all]
def list_all_instances(
    project_id: str,
) -> typing.Dict[str, typing.Iterable[compute_v1.Instance]]:
    """
    Return a dictionary of all instances present in a project, grouped by their zone.

    Args:
        project_id: project ID or project number of the Cloud project you want to use.
    Returns:
        A dictionary with zone names as keys (in form of "zones/{zone_name}") and
        iterable collections of Instance objects as values.
    """
    instance_client = compute_v1.InstancesClient()
    agg_list = instance_client.aggregated_list(project=project_id)
    all_instances = {}
    print("Instances found:")
    for zone, response in agg_list:
        if response.instances:
            all_instances[zone] = response.instances
            print(f" {zone}:")
            for instance in response.instances:
                print(f" - {instance.name} ({instance.machine_type})")
    return all_instances
# [END compute_instances_list_all]

# [START compute_instances_create]
def create_instance(
    project_id: str,
    zone: str,
    instance_name: str,
    machine_type: str = "n1-standard-1",
    source_image: str = "projects/debian-cloud/global/images/family/debian-10",
    network_name: str = "global/networks/default",
) -> compute_v1.Instance:
    """
    Send an instance creation request to the Compute Engine API and wait for it to complete.

    Args:
        project_id: project ID or project number of the Cloud project you want to use.
        zone: name of the zone you want to use. For example: “us-west3-b”
        instance_name: name of the new virtual machine.
        machine_type: machine type of the VM being created. This value uses the
            following format: "zones/{zone}/machineTypes/{type_name}".
            For example: "zones/europe-west3-c/machineTypes/f1-micro"
        source_image: path to the operating system image to mount on your boot
            disk. This can be one of the public images
            (like "projects/debian-cloud/global/images/family/debian-10")
            or a private image you have access to.
        network_name: name of the network you want the new instance to use.
            For example: "global/networks/default" represents the `default`
            network interface, which is created automatically for each project.
    Returns:
        Instance object.
    """
    instance_client = compute_v1.InstancesClient()

    # Describe the size and source image of the boot disk to attach to the instance.
    disk = compute_v1.AttachedDisk()
    initialize_params = compute_v1.AttachedDiskInitializeParams()
    initialize_params.source_image = (
        source_image  # "projects/debian-cloud/global/images/family/debian-10"
    )
    initialize_params.disk_size_gb = "10"
    disk.initialize_params = initialize_params
    disk.auto_delete = True
    disk.boot = True
    disk.type_ = compute_v1.AttachedDisk.Type.PERSISTENT

    # Use the network interface provided in the network_name argument.
    network_interface = compute_v1.NetworkInterface()
    network_interface.name = network_name

    # Collect information into the Instance object.
    instance = compute_v1.Instance()
    instance.name = instance_name
    instance.disks = [disk]
    full_machine_type_name = f"zones/{zone}/machineTypes/{machine_type}"
    instance.machine_type = full_machine_type_name
    instance.network_interfaces = [network_interface]

    # Prepare the request to insert an instance.
    request = compute_v1.InsertInstanceRequest()
    request.zone = zone
    request.project = project_id
    request.instance_resource = instance

    # Wait for the create operation to complete.
    print(f"Creating the {instance_name} instance in {zone}...")
    operation = instance_client.insert(request=request)
    if operation.status == compute_v1.Operation.Status.RUNNING:
        operation_client = compute_v1.ZoneOperationsClient()
        operation = operation_client.wait(
            operation=operation.name, zone=zone, project=project_id
        )
    if operation.error:
        print("Error during creation:", operation.error, file=sys.stderr)
    if operation.warnings:
        print("Warning during creation:", operation.warnings, file=sys.stderr)
    print(f"Instance {instance_name} created.")
    return instance
# [END compute_instances_create]

# [START compute_instances_delete]
def delete_instance(project_id: str, zone: str, machine_name: str) -> None:
    """
    Send an instance deletion request to the Compute Engine API and wait for it to complete.

    Args:
        project_id: project ID or project number of the Cloud project you want to use.
        zone: name of the zone you want to use. For example: “us-west3-b”
        machine_name: name of the machine you want to delete.
    """
    instance_client = compute_v1.InstancesClient()

    print(f"Deleting {machine_name} from {zone}...")
    operation = instance_client.delete(
        project=project_id, zone=zone, instance=machine_name
    )
    if operation.status == compute_v1.Operation.Status.RUNNING:
        operation_client = compute_v1.ZoneOperationsClient()
        operation = operation_client.wait(
            operation=operation.name, zone=zone, project=project_id
        )
    if operation.error:
        print("Error during deletion:", operation.error, file=sys.stderr)
    if operation.warnings:
        print("Warning during deletion:", operation.warnings, file=sys.stderr)
    print(f"Instance {machine_name} deleted.")
    return
# [END compute_instances_delete]

# [START compute_instances_operation_check]
def wait_for_operation(
    operation: compute_v1.Operation, project_id: str
) -> compute_v1.Operation:
    """
    This method waits for an operation to be completed. Calling this function
    will block until the operation is finished.

    Args:
        operation: The Operation object representing the operation you want to
            wait on.
        project_id: project ID or project number of the Cloud project you want to use.

    Returns:
        Finished Operation object.
    """
    kwargs = {"project": project_id, "operation": operation.name}
    if operation.zone:
        client = compute_v1.ZoneOperationsClient()
        # Operation.zone is a full URL address of a zone, so we need to extract just the name
        kwargs["zone"] = operation.zone.rsplit("/", maxsplit=1)[1]
    elif operation.region:
        client = compute_v1.RegionOperationsClient()
        # Operation.region is a full URL address of a region, so we need to extract just the name
        kwargs["region"] = operation.region.rsplit("/", maxsplit=1)[1]
    else:
        client = compute_v1.GlobalOperationsClient()
    return client.wait(**kwargs)
# [END compute_instances_operation_check]

def main(project_id: str, zone: str, instance_name: str) -> None:

    create_instance(project_id, zone, instance_name)

    zone_instances = list_instances(project_id, zone)
    print(f"Instances found in {zone}:", ", ".join(i.name for i in zone_instances))

    all_instances = list_all_instances(project_id)
    print(f"Instances found in project {project_id}:")
    for i_zone, instances in all_instances.items():
        print(f"{i_zone}:", ", ".join(i.name for i in instances))

    delete_instance(project_id, zone, instance_name)

if __name__ == "__main__":
    import uuid
    import google.auth
    import google.auth.exceptions

    try:
        default_project_id = google.auth.default()[1]
    except google.auth.exceptions.DefaultCredentialsError:
        print(
            "Please use `gcloud auth application-default login` "
            "or set GOOGLE_APPLICATION_CREDENTIALS to use this script."
        )
    else:
        instance_name = "quickstart-" + uuid.uuid4().hex[:10]
        instance_zone = "europe-central2-b"
        main(default_project_id, instance_zone, instance_name)
<|endoftext|>


<commit_before>"""Replacement authentication decorators that work around redirection loops"""

try:
    from functools import wraps
except ImportError:
    from django.utils.functional import wraps

from django.contrib.auth import REDIRECT_FIELD_NAME
from django.contrib.auth.decorators import login_required
from django.http import HttpResponseForbidden, HttpResponseRedirect
from django.utils.http import urlquote

__all__ = ['login_required', 'permission_required', 'user_passes_test']

def user_passes_test(test_func, login_url=None,
                     redirect_field_name=REDIRECT_FIELD_NAME):
    """Replacement for django.contrib.auth.decorators.user_passes_test that
    returns 403 Forbidden if the user is already logged in.
    """

    if not login_url:
        from django.conf import settings
        login_url = settings.LOGIN_URL

    def decorator(view_func):
        @wraps(view_func)
        def wrapper(request, *args, **kwargs):
            if test_func(request.user):
                return view_func(request, *args, **kwargs)
            elif request.user.is_authenticated():
                return HttpResponseForbidden('
Permission denied
')
            else:
                path = '%s?%s=%s' % (login_url, redirect_field_name,
                                     urlquote(request.get_full_path()))
                return HttpResponseRedirect(path)
        return wrapper
    return decorator

def permission_required(perm, login_url=None):
    """Replacement for django.contrib.auth.decorators.permission_required that
    returns 403 Forbidden if the user is already logged in.
    """

    return user_passes_test(lambda u: u.has_perm(perm), login_url=login_url)

def gateway():
    if settings.CAS_GATEWAY == False:
        raise ImproperlyConfigured('CAS_GATEWAY must be set to True')
    def wrap(func):
        def wrapped_f(*args):

            from django_cas.views import login
            request = args[0]

            if request.user.is_authenticated():
                #Not Authed
                pass
            else:
                #Not Authed
                print request.GET
                gatewayed = request.GET.get('gatewayed')
                if gatewayed == 'true':
                    if request.GET.get('ticket'):
                        #Not Authed, but have a ticket!
                        #Try to authenticate
                        return login(request, request.GET.get('next'), False, True)
                    else:
                        #Not Authed, but that's okay
                        pass
                else:
                    #Not Authed, try to authenticate
                    return login(request, request.GET.get('next'), False, True)

            return func(*args)
        return wrapped_f
    return wrap<commit_msg>decorator imports and docstring<commit_after>"""Replacement authentication decorators that work around redirection loops"""

try:
    from functools import wraps
except ImportError:
    from django.utils.functional import wraps

from django.contrib.auth import REDIRECT_FIELD_NAME
from django.contrib.auth.decorators import login_required
from django.http import HttpResponseForbidden, HttpResponseRedirect
from django.utils.http import urlquote

__all__ = ['login_required', 'permission_required', 'user_passes_test']

def user_passes_test(test_func, login_url=None,
                     redirect_field_name=REDIRECT_FIELD_NAME):
    """Replacement for django.contrib.auth.decorators.user_passes_test that
    returns 403 Forbidden if the user is already logged in.
    """

    if not login_url:
        from django.conf import settings
        login_url = settings.LOGIN_URL

    def decorator(view_func):
        @wraps(view_func)
        def wrapper(request, *args, **kwargs):
            if test_func(request.user):
                return view_func(request, *args, **kwargs)
            elif request.user.is_authenticated():
                return HttpResponseForbidden('
Permission denied
')
            else:
                path = '%s?%s=%s' % (login_url, redirect_field_name,
                                     urlquote(request.get_full_path()))
                return HttpResponseRedirect(path)
        return wrapper
    return decorator

def permission_required(perm, login_url=None):
    """Replacement for django.contrib.auth.decorators.permission_required that
    returns 403 Forbidden if the user is already logged in.
    """

    return user_passes_test(lambda u: u.has_perm(perm), login_url=login_url)

from django.conf import settings
from django.core.exceptions import ImproperlyConfigured

def gateway():
    """Authenticates single sign on session if ticket is available,
    but doesn't redirect to sign in url otherwise.
    """
    if settings.CAS_GATEWAY == False:
        raise ImproperlyConfigured('CAS_GATEWAY must be set to True')
    def wrap(func):
        def wrapped_f(*args):

            from django_cas.views import login
            request = args[0]

            if request.user.is_authenticated():
                #Not Authed
                pass
            else:
                #Not Authed
                print request.GET
                gatewayed = request.GET.get('gatewayed')
                if gatewayed == 'true':
                    if request.GET.get('ticket'):
                        #Not Authed, but have a ticket!
                        #Try to authenticate
                        return login(request, request.GET.get('next'), False, True)
                    else:
                        #Not Authed, but that's okay
                        pass
                else:
                    #Not Authed, try to authenticate
                    return login(request, request.GET.get('next'), False, True)

            return func(*args)
        return wrapped_f
    return wrap<|endoftext|>


<commit_before># -*- coding:utf-8 -*-
# Author: hankcs
# Date: 2019-12-31 19:24
import os
import traceback
from sys import exit

from hanlp_common.constant import HANLP_VERBOSE

from hanlp import pretrained
from hanlp.common.component import Component
from hanlp.utils.io_util import get_resource, get_latest_info_from_pypi
from hanlp_common.io import load_json, eprint
from hanlp_common.reflection import object_from_classpath, str_to_type
from hanlp import version

def load_from_meta_file(save_dir: str, meta_filename='meta.json', transform_only=False, verbose=HANLP_VERBOSE,
                        **kwargs) -> Component:
    """

    Args:
        save_dir:
        meta_filename (str): The meta file of that saved component, which stores the classpath and version.
        transform_only:
        **kwargs:

    Returns:

    """
    identifier = save_dir
    load_path = save_dir
    save_dir = get_resource(save_dir)
    if save_dir.endswith('.json'):
        meta_filename = os.path.basename(save_dir)
        save_dir = os.path.dirname(save_dir)
    metapath = os.path.join(save_dir, meta_filename)
    if not os.path.isfile(metapath):
        tf_model = False
        metapath = os.path.join(save_dir, 'config.json')
    else:
        tf_model = True
    if not os.path.isfile(metapath):
        tips = ''
        if save_dir.isupper():
            from difflib import SequenceMatcher
            similar_keys = sorted(pretrained.ALL.keys(),
                                  key=lambda k: SequenceMatcher(None, save_dir, metapath).ratio(),
                                  reverse=True)[:5]
            tips = f'Check its spelling based on the available keys:\n' + \
                   f'{sorted(pretrained.ALL.keys())}\n' + \
                   f'Tips: it might be one of {similar_keys}'
        raise FileNotFoundError(f'The identifier {save_dir} resolves to a non-exist meta file {metapath}. {tips}')
    meta: dict = load_json(metapath)
    cls = meta.get('classpath', None)
    if not cls:
        cls = meta.get('class_path', None)  # For older version
    if tf_model:
        # tf models are trained with version <= 2.0. To migrate them to 2.1, map their classpath to new locations
        upgrade = {
            'hanlp.components.tok.TransformerTokenizer': 'hanlp.components.tok_tf.TransformerTokenizerTF',
            'hanlp.components.pos.RNNPartOfSpeechTagger': 'hanlp.components.pos_tf.RNNPartOfSpeechTaggerTF',
            'hanlp.components.pos.CNNPartOfSpeechTagger': 'hanlp.components.pos_tf.CNNPartOfSpeechTaggerTF',
            'hanlp.components.ner.TransformerNamedEntityRecognizer': 'hanlp.components.ner_tf.TransformerNamedEntityRecognizerTF',
            'hanlp.components.parsers.biaffine_parser.BiaffineDependencyParser': 'hanlp.components.parsers.biaffine_parser_tf.BiaffineDependencyParserTF',
            'hanlp.components.parsers.biaffine_parser.BiaffineSemanticDependencyParser': 'hanlp.components.parsers.biaffine_parser_tf.BiaffineSemanticDependencyParserTF',
            'hanlp.components.tok.NgramConvTokenizer': 'hanlp.components.tok_tf.NgramConvTokenizerTF',
            'hanlp.components.classifiers.transformer_classifier.TransformerClassifier': 'hanlp.components.classifiers.transformer_classifier_tf.TransformerClassifierTF',
            'hanlp.components.taggers.transformers.transformer_tagger.TransformerTagger': 'hanlp.components.taggers.transformers.transformer_tagger_tf.TransformerTaggerTF',
        }
        cls = upgrade.get(cls, cls)
    assert cls, f'{meta_filename} doesn\'t contain classpath field'
    try:
        obj: Component = object_from_classpath(cls)
        if hasattr(obj, 'load'):
            if transform_only:
                # noinspection PyUnresolvedReferences
                obj.load_transform(save_dir)
            else:
                if os.path.isfile(os.path.join(save_dir, 'config.json')):
                    obj.load(save_dir, verbose=verbose, **kwargs)
                else:
                    obj.load(metapath, **kwargs)
            obj.config['load_path'] = load_path
        return obj
    except Exception as e:
        eprint(f'Failed to load {identifier}. See traceback below:')
        eprint(f'{"ERROR LOG BEGINS":=^80}')
        traceback.print_exc()
        eprint(f'{"ERROR LOG ENDS":=^80}')
        if isinstance(e, ModuleNotFoundError):
            eprint('Some modules required by this model are missing. Please install the full version:\n'
                   'pip install hanlp[full]')
        from pkg_resources import parse_version
        model_version = meta.get("hanlp_version", "unknown")
        if model_version == '2.0.0':  # Quick fix: the first version used a wrong string
            model_version = '2.0.0-alpha.0'
        model_version = parse_version(model_version)
        installed_version = parse_version(version.__version__)
        try:
            latest_version = get_latest_info_from_pypi()
        except:
            latest_version = None
        if model_version > installed_version:
            eprint(f'{identifier} was created with hanlp-{model_version}, '
                   f'while you are running a lower version: {installed_version}. ')
        if installed_version != latest_version:
            eprint(
                f'Please upgrade hanlp with:\n'
                f'pip install --upgrade hanlp\n')
        eprint(
            'If the problem still persists, please submit an issue to https://github.com/hankcs/HanLP/issues\n'
            'When reporting an issue, make sure to paste the FULL ERROR LOG above.')
        exit(1)

def load_from_meta(meta: dict) -> Component:
    if 'load_path' in meta:
        return load_from_meta_file(meta['load_path'])
    cls = meta.get('class_path', None) or meta.get('classpath', None)
    assert cls, f'{meta} doesn\'t contain classpath field'
    cls = str_to_type(cls)
    return cls.from_config(meta)
<commit_msg>Report system info for convenience<commit_after># -*- coding:utf-8 -*-
# Author: hankcs
# Date: 2019-12-31 19:24
import os
import traceback
from sys import exit

from hanlp_common.constant import HANLP_VERBOSE

from hanlp import pretrained
from hanlp.common.component import Component
from hanlp.utils.io_util import get_resource, get_latest_info_from_pypi
from hanlp_common.io import load_json, eprint
from hanlp_common.reflection import object_from_classpath, str_to_type
from hanlp import version

def load_from_meta_file(save_dir: str, meta_filename='meta.json', transform_only=False, verbose=HANLP_VERBOSE,
                        **kwargs) -> Component:
    """

    Args:
        save_dir:
        meta_filename (str): The meta file of that saved component, which stores the classpath and version.
        transform_only:
        **kwargs:

    Returns:

    """
    identifier = save_dir
    load_path = save_dir
    save_dir = get_resource(save_dir)
    if save_dir.endswith('.json'):
        meta_filename = os.path.basename(save_dir)
        save_dir = os.path.dirname(save_dir)
    metapath = os.path.join(save_dir, meta_filename)
    if not os.path.isfile(metapath):
        tf_model = False
        metapath = os.path.join(save_dir, 'config.json')
    else:
        tf_model = True
    if not os.path.isfile(metapath):
        tips = ''
        if save_dir.isupper():
            from difflib import SequenceMatcher
            similar_keys = sorted(pretrained.ALL.keys(),
                                  key=lambda k: SequenceMatcher(None, save_dir, metapath).ratio(),
                                  reverse=True)[:5]
            tips = f'Check its spelling based on the available keys:\n' + \
                   f'{sorted(pretrained.ALL.keys())}\n' + \
                   f'Tips: it might be one of {similar_keys}'
        raise FileNotFoundError(f'The identifier {save_dir} resolves to a non-exist meta file {metapath}. {tips}')
    meta: dict = load_json(metapath)
    cls = meta.get('classpath', None)
    if not cls:
        cls = meta.get('class_path', None)  # For older version
    if tf_model:
        # tf models are trained with version <= 2.0. To migrate them to 2.1, map their classpath to new locations
        upgrade = {
            'hanlp.components.tok.TransformerTokenizer': 'hanlp.components.tok_tf.TransformerTokenizerTF',
            'hanlp.components.pos.RNNPartOfSpeechTagger': 'hanlp.components.pos_tf.RNNPartOfSpeechTaggerTF',
            'hanlp.components.pos.CNNPartOfSpeechTagger': 'hanlp.components.pos_tf.CNNPartOfSpeechTaggerTF',
            'hanlp.components.ner.TransformerNamedEntityRecognizer': 'hanlp.components.ner_tf.TransformerNamedEntityRecognizerTF',
            'hanlp.components.parsers.biaffine_parser.BiaffineDependencyParser': 'hanlp.components.parsers.biaffine_parser_tf.BiaffineDependencyParserTF',
            'hanlp.components.parsers.biaffine_parser.BiaffineSemanticDependencyParser': 'hanlp.components.parsers.biaffine_parser_tf.BiaffineSemanticDependencyParserTF',
            'hanlp.components.tok.NgramConvTokenizer': 'hanlp.components.tok_tf.NgramConvTokenizerTF',
            'hanlp.components.classifiers.transformer_classifier.TransformerClassifier': 'hanlp.components.classifiers.transformer_classifier_tf.TransformerClassifierTF',
            'hanlp.components.taggers.transformers.transformer_tagger.TransformerTagger': 'hanlp.components.taggers.transformers.transformer_tagger_tf.TransformerTaggerTF',
        }
        cls = upgrade.get(cls, cls)
    assert cls, f'{meta_filename} doesn\'t contain classpath field'
    try:
        obj: Component = object_from_classpath(cls)
        if hasattr(obj, 'load'):
            if transform_only:
                # noinspection PyUnresolvedReferences
                obj.load_transform(save_dir)
            else:
                if os.path.isfile(os.path.join(save_dir, 'config.json')):
                    obj.load(save_dir, verbose=verbose, **kwargs)
                else:
                    obj.load(metapath, **kwargs)
            obj.config['load_path'] = load_path
        return obj
    except Exception as e:
        eprint(f'Failed to load {identifier}. See traceback below:')
        eprint(f'{"ERROR LOG BEGINS":=^80}')
        traceback.print_exc()
        eprint(f'{"ERROR LOG ENDS":=^80}')
        if isinstance(e, ModuleNotFoundError):
            eprint('Some modules required by this model are missing. Please install the full version:\n'
                   'pip install hanlp[full]')
        from pkg_resources import parse_version
        model_version = meta.get("hanlp_version", "unknown")
        if model_version == '2.0.0':  # Quick fix: the first version used a wrong string
            model_version = '2.0.0-alpha.0'
        model_version = parse_version(model_version)
        installed_version = parse_version(version.__version__)
        try:
            latest_version = get_latest_info_from_pypi()
        except:
            latest_version = None
        if model_version > installed_version:
            eprint(f'{identifier} was created with hanlp-{model_version}, '
                   f'while you are running a lower version: {installed_version}. ')
        if installed_version != latest_version:
            eprint(
                f'Please upgrade hanlp with:\n'
                f'pip install --upgrade hanlp\n')
        eprint(
            'If the problem still persists, please submit an issue to https://github.com/hankcs/HanLP/issues\n'
            'When reporting an issue, make sure to paste the FULL ERROR LOG above and the system info below.')

        import platform
        eprint(f'OS: {platform.platform()}')
        eprint(f'Python: {platform.python_version()}')
        import torch
        eprint(f'PyTorch: {torch.__version__}')
        eprint(f'HanLP: {version}')
        exit(1)

def load_from_meta(meta: dict) -> Component:
    if 'load_path' in meta:
        return load_from_meta_file(meta['load_path'])
    cls = meta.get('class_path', None) or meta.get('classpath', None)
    assert cls, f'{meta} doesn\'t contain classpath field'
    cls = str_to_type(cls)
    return cls.from_config(meta)
<|endoftext|>


<commit_before>import numpy as np

from .tensor import TensorBase
from .tensor import _ensure_tensorbase

__all__ = [

    'cumprod','cumsum','ceil','dot', 'matmul',
]

def dot(tensor1, tensor2):
    """Returns inner product of two tensors.

    N-dimensional tensors are flattened into 1-D vectors, therefore this method should only be used on vectors.
    """

    tensor1 = _ensure_tensorbase(tensor1)
    tensor2 = _ensure_tensorbase(tensor2)

    if tensor1.encrypted is True or tensor2.encrypted is True:
        return NotImplemented
    return np.vdot(tensor1.data, tensor2.data)

def matmul(tensor1, tensor2):
    """Performs matrix multiplication between two tensors.

    Exact behavior depends on the input tensors' dimensionality like so:
    * If both tensors are 1-dimensional, their dot product is returned.
    * If both tensors are 2-dimensional, their matrix-matrix product is returned.
    * If either tensor has dimensionality > 2, the last 2 dimensions are treated as matrices and multiplied.
    * If tensor1 is 1-dimensional, it is converted to a matrix by prepending a 1 to its dimensions.
      This prepended dimension is removed after the matrix multiplication.
    * If tensor2 is 1-dimensional, it is converted to a matrix by prepending a 1 to its dimensions.
      This prepended dimension is removed after the matrix multiplication.
    """

    tensor1 = _ensure_tensorbase(tensor1)
    tensor2 = _ensure_tensorbase(tensor2)

    if tensor1.encrypted is True or tensor2.encrypted is True:
        return NotImplemented

    if tensor1.dim() == 1 and tensor2.dim() == 1:
        return dot(tensor1, tensor2)
    else:
        return TensorBase(np.matmul(tensor1.data, tensor2.data))

def ceil(tensor):
    """
    Returns the ceilling input tensor,element wise .

    Ceilling of an input scalar is the smallest integer such as :
    for each floating pount number x : a >= x

    Behavior is independent of a tensor's shape.

    :input: TensorBase tensor\n
    :return: TensorBase tensor
    """

    tensor = _ensure_tensorbase(tensor)
    if tensor.encrypted is True :
        return NotImplemented
    return TensorBase(np.ceil(tensor.data))

def cumsum(tensor,dim=0):
    """
    Returns the cumulative sum of the elements along a given dimension

    **Parameters**:
    * TensorBase tensor
    * Dimension on which the operation is done

    **returns**  A new 1D Tensor holding the result
    """

    tensor = _ensure_tensorbase(tensor)
    if tensor.encrypted is True:
        return NotImplemented
    return TensorBase(np.cumsum(tensor.data,dim))

def cumprod(tensor,dim=0):
    """
    Returns the cumulative product of the elements along a given axis

    **Parameters**:
    * TensorBase tensor
    * Dimension on which the operation is done

    **returns** A new 1D Tensor holding the result
    """

    tensor = _ensure_tensorbase(tensor)
    if tensor.encrypted is True:
        return NotImplemented
    return TensorBase(np.cumprod(tensor.data,dim))

ef addmm(tensor1, tensor2, mat, beta=1, alpha=1):
        """Performs ((Mat*Beta)+((Tensor1.Tensor2)*Alpha)) and  returns the result as a Tensor
            Tensor1.Tensor2 is performed as Matrix product of two array The behavior depends on the arguments in the following way.
            *If both tensors are 1-dimensional, their dot product is returned.
            *If both arguments are 2-D they are multiplied like conventional matrices.
            *If either argument is N-D, N > 2, it is treated as a stack of matrices residing in the last two indexes and broadcast accordingly.
            *If the first argument is 1-D, it is promoted to a matrix by prepending a 1 to its dimensions. After matrix multiplication the prepended 1 is removed.
            *If the second argument is 1-D, it is promoted to a matrix by appending a 1 to its dimensions. After matrix multiplication the appended 1 is removed.
            """
        _ensure_tensorbase(tensor1)
        _ensure_tensorbase(tensor2)
        _ensure_tensorbase(mat)
        if tensor1.encrypted or tensor2.encrypted or mat.encrypted:
            return NotImplemented
        else:
            return TensorBase(np.array(((mat.data)*beta)+((np.matmul(tensor1.data, tensor2.data))*alpha)))

def addcmul(tensor1, tensor2, mat, value=1):

    """Performs the element-wise multiplication of tensor1 by tensor2,  multiply the result by the scalar value and add it to mat."""
    _ensure_tensorbase(tensor1)
    _ensure_tensorbase(tensor2)
    _ensure_tensorbase(mat)
    if tensor1.encrypted or tensor2.encrypted or mat.encrypted:
        return NotImplemented
    else:
        out = (mat.data)+((tensor1.data*tensor2.data)*value)
        return TensorBase(out)

def addcdiv(tensor1, tensor2, mat, value=1):
    """Performs the element-wise division of tensor1 by tensor2,  multiply the result by the scalar value and add it to mat."""
    _ensure_tensorbase(tensor1)
    _ensure_tensorbase(tensor2)
    _ensure_tensorbase(mat)
    if tensor1.encrypted or tensor2.encrypted or mat.encrypted:
        return NotImplemented
    else:
        out = (mat.data)+((tensor1.data/tensor2.data)*value)
        return TensorBase(out)

def addmv(tensor1, mat, vec, beta=1, alpha=1):
    """"Performs a matrix-vector product of the matrix mat and the vector vec. The vector tensor is added to the final result.
          tensor1 and vec are 1d tensors
          out=(beta∗tensor)+(alpha∗(mat@vec2))"""
    _ensure_tensorbase(tensor1)
    _ensure_tensorbase(vec)
    _ensure_tensorbase(mat)
    if vec.data.ndim != 1:
        print("dimension of vec is not 1")
    elif tensor1.data.ndim != 1:
        print("dimension of vec is not 1")
    elif tensor1.encrypted or vec.encrypted or mat.encrypted:
        return NotImplemented
    else:
        out =( tensor1.data*beta)+(np.matmul(mat.data, vec.data)*alpha)
        return TensorBase(out)

def addbmm(tensor1, tensor2, mat, beta=1, alpha=1):
    """Performs a batch matrix-matrix product of matrices stored in batch1(tensor1) and batch2(tensor2),
     with a reduced add step (all matrix multiplications get accumulated along the first dimension).
     mat is added to the final result.
     res=(beta∗M)+(alpha∗sum(batch1i@batch2i, i=0, b))
    * batch1 and batch2 must be 3D Tensors each containing the same number of matrices."""
    _ensure_tensorbase(tensor1)
    _ensure_tensorbase(tensor2)
    _ensure_tensorbase(mat)
    if tensor2.data.ndim != 3:
        print("dimension of tensor2 is not 3")
    elif tensor1.data.ndim != 3:
        print("dimension of tensor1 is not 3")
    elif tensor1.encrypted or tensor2.encrypted or mat.encrypted:
        return NotImplemented
    else:
        mm = np.matmul(tensor1.data, tensor2.data)
        sum = 0
        for i in range(len(mm)):
            sum += mm[i]
        out = (mat.data * beta) + (alpha * sum)
        return TensorBase(out)

def baddbmm(tensor1, tensor2, mat, beta=1, alpha=1):
    """Performs a batch matrix-matrix product of matrices in batch1(tensor1) and batch2(tensor2). mat is added to the final result.
      resi=(beta∗Mi)+(alpha∗batch1i×batch2i)
      *batch1 and batch2 must be 3D Tensors each containing the same number of matrices."""
    _ensure_tensorbase(tensor1)
    _ensure_tensorbase(tensor2)
    _ensure_tensorbase(mat)
    if tensor2.data.ndim != 3:
        print("dimension of tensor2 is not 3")
    elif tensor1.data.ndim != 3:
        print("dimension of tensor1 is not 3")
    elif mat.data.ndim != 3:
        print("dimension of mat is not 3")
    elif tensor1.encrypted or tensor2.encrypted or mat.encrypted:
        return NotImplemented
    else:
        mm = np.matmul(tensor1.data, tensor2.data)
        out = (mat.data*beta)+(mm*alpha)
        return TensorBase(out)

<commit_msg>Update math.py<commit_after>import numpy as np

from .tensor import TensorBase
from .tensor import _ensure_tensorbase

__all__ = [

    'cumprod','cumsum','ceil','dot', 'matmul',
]

def dot(tensor1, tensor2):
    """Returns inner product of two tensors.

    N-dimensional tensors are flattened into 1-D vectors, therefore this method should only be used on vectors.
    """

    tensor1 = _ensure_tensorbase(tensor1)
    tensor2 = _ensure_tensorbase(tensor2)

    if tensor1.encrypted is True or tensor2.encrypted is True:
        return NotImplemented
    return np.vdot(tensor1.data, tensor2.data)

def matmul(tensor1, tensor2):
    """Performs matrix multiplication between two tensors.

    Exact behavior depends on the input tensors' dimensionality like so:
    * If both tensors are 1-dimensional, their dot product is returned.
    * If both tensors are 2-dimensional, their matrix-matrix product is returned.
    * If either tensor has dimensionality > 2, the last 2 dimensions are treated as matrices and multiplied.
    * If tensor1 is 1-dimensional, it is converted to a matrix by prepending a 1 to its dimensions.
      This prepended dimension is removed after the matrix multiplication.
    * If tensor2 is 1-dimensional, it is converted to a matrix by prepending a 1 to its dimensions.
      This prepended dimension is removed after the matrix multiplication.
    """

    tensor1 = _ensure_tensorbase(tensor1)
    tensor2 = _ensure_tensorbase(tensor2)

    if tensor1.encrypted is True or tensor2.encrypted is True:
        return NotImplemented

    if tensor1.dim() == 1 and tensor2.dim() == 1:
        return dot(tensor1, tensor2)
    else:
        return TensorBase(np.matmul(tensor1.data, tensor2.data))

def ceil(tensor):
    """
    Returns the ceilling input tensor,element wise .

    Ceilling of an input scalar is the smallest integer such as :
    for each floating pount number x : a >= x

    Behavior is independent of a tensor's shape.

    :input: TensorBase tensor\n
    :return: TensorBase tensor
    """

    tensor = _ensure_tensorbase(tensor)
    if tensor.encrypted is True :
        return NotImplemented
    return TensorBase(np.ceil(tensor.data))

def cumsum(tensor,dim=0):
    """
    Returns the cumulative sum of the elements along a given dimension

    **Parameters**:
    * TensorBase tensor
    * Dimension on which the operation is done

    **returns**  A new 1D Tensor holding the result
    """

    tensor = _ensure_tensorbase(tensor)
    if tensor.encrypted is True:
        return NotImplemented
    return TensorBase(np.cumsum(tensor.data,dim))

def cumprod(tensor,dim=0):
    """
    Returns the cumulative product of the elements along a given axis

    **Parameters**:
    * TensorBase tensor
    * Dimension on which the operation is done

    **returns** A new 1D Tensor holding the result
    """

    tensor = _ensure_tensorbase(tensor)
    if tensor.encrypted is True:
        return NotImplemented
    return TensorBase(np.cumprod(tensor.data,dim))

def addmm(tensor1, tensor2, mat, beta=1, alpha=1):
        """Performs ((Mat*Beta)+((Tensor1.Tensor2)*Alpha)) and  returns the result as a Tensor
            Tensor1.Tensor2 is performed as Matrix product of two array The behavior depends on the arguments in the following way.
            *If both tensors are 1-dimensional, their dot product is returned.
            *If both arguments are 2-D they are multiplied like conventional matrices.
            *If either argument is N-D, N > 2, it is treated as a stack of matrices residing in the last two indexes and broadcast accordingly.
            *If the first argument is 1-D, it is promoted to a matrix by prepending a 1 to its dimensions. After matrix multiplication the prepended 1 is removed.
            *If the second argument is 1-D, it is promoted to a matrix by appending a 1 to its dimensions. After matrix multiplication the appended 1 is removed.
            """
        _ensure_tensorbase(tensor1)
        _ensure_tensorbase(tensor2)
        _ensure_tensorbase(mat)
        if tensor1.encrypted or tensor2.encrypted or mat.encrypted:
            return NotImplemented
        else:
            return TensorBase(np.array(((mat.data)*beta)+((np.matmul(tensor1.data, tensor2.data))*alpha)))

def addcmul(tensor1, tensor2, mat, value=1):

    """Performs the element-wise multiplication of tensor1 by tensor2,  multiply the result by the scalar value and add it to mat."""
    _ensure_tensorbase(tensor1)
    _ensure_tensorbase(tensor2)
    _ensure_tensorbase(mat)
    if tensor1.encrypted or tensor2.encrypted or mat.encrypted:
        return NotImplemented
    else:
        out = (mat.data)+((tensor1.data*tensor2.data)*value)
        return TensorBase(out)

def addcdiv(tensor1, tensor2, mat, value=1):
    """Performs the element-wise division of tensor1 by tensor2,  multiply the result by the scalar value and add it to mat."""
    _ensure_tensorbase(tensor1)
    _ensure_tensorbase(tensor2)
    _ensure_tensorbase(mat)
    if tensor1.encrypted or tensor2.encrypted or mat.encrypted:
        return NotImplemented
    else:
        out = (mat.data)+((tensor1.data/tensor2.data)*value)
        return TensorBase(out)

def addmv(tensor1, mat, vec, beta=1, alpha=1):
    """"Performs a matrix-vector product of the matrix mat and the vector vec. The vector tensor is added to the final result.
          tensor1 and vec are 1d tensors
          out=(beta∗tensor)+(alpha∗(mat@vec2))"""
    _ensure_tensorbase(tensor1)
    _ensure_tensorbase(vec)
    _ensure_tensorbase(mat)
    if vec.data.ndim != 1:
        print("dimension of vec is not 1")
    elif tensor1.data.ndim != 1:
        print("dimension of vec is not 1")
    elif tensor1.encrypted or vec.encrypted or mat.encrypted:
        return NotImplemented
    else:
        out =( tensor1.data*beta)+(np.matmul(mat.data, vec.data)*alpha)
        return TensorBase(out)

def addbmm(tensor1, tensor2, mat, beta=1, alpha=1):
    """Performs a batch matrix-matrix product of matrices stored in batch1(tensor1) and batch2(tensor2),
     with a reduced add step (all matrix multiplications get accumulated along the first dimension).
     mat is added to the final result.
     res=(beta∗M)+(alpha∗sum(batch1i@batch2i, i=0, b))
    * batch1 and batch2 must be 3D Tensors each containing the same number of matrices."""
    _ensure_tensorbase(tensor1)
    _ensure_tensorbase(tensor2)
    _ensure_tensorbase(mat)
    if tensor2.data.ndim != 3:
        print("dimension of tensor2 is not 3")
    elif tensor1.data.ndim != 3:
        print("dimension of tensor1 is not 3")
    elif tensor1.encrypted or tensor2.encrypted or mat.encrypted:
        return NotImplemented
    else:
        mm = np.matmul(tensor1.data, tensor2.data)
        sum = 0
        for i in range(len(mm)):
            sum += mm[i]
        out = (mat.data * beta) + (alpha * sum)
        return TensorBase(out)

def baddbmm(tensor1, tensor2, mat, beta=1, alpha=1):
    """Performs a batch matrix-matrix product of matrices in batch1(tensor1) and batch2(tensor2). mat is added to the final result.
      resi=(beta∗Mi)+(alpha∗batch1i×batch2i)
      *batch1 and batch2 must be 3D Tensors each containing the same number of matrices."""
    _ensure_tensorbase(tensor1)
    _ensure_tensorbase(tensor2)
    _ensure_tensorbase(mat)
    if tensor2.data.ndim != 3:
        print("dimension of tensor2 is not 3")
    elif tensor1.data.ndim != 3:
        print("dimension of tensor1 is not 3")
    elif mat.data.ndim != 3:
        print("dimension of mat is not 3")
    elif tensor1.encrypted or tensor2.encrypted or mat.encrypted:
        return NotImplemented
    else:
        mm = np.matmul(tensor1.data, tensor2.data)
        out = (mat.data*beta)+(mm*alpha)
        return TensorBase(out)

<|endoftext|>