quantumcore.experiments / node.py

from exc import ObjectNotFound, DuplicateNodeName

class Node(object):
    """a node which implements the INode interface"""
    
    __parent__ = None
    __path__ = []
    
    ###
    ### constructor and the method for creating new children
    ###
    
    def __init__(self, node_id, name=u'', parent_id = None):
        """instantiates a node"""
        
        self.node_id = node_id
        # here we cannot use the setter because it already needs the storage 
        # defined which does not work in tests
        self._name = name 
        self.parent_id = parent_id
        
    def _getStorage(self):
        return self._storage
        
    @property
    def url(self):
        return '/'+'/'.join(self.__path__)
        
    ###
    ### children and parent navigation
    ###
    
    @property
    def children(self):
        """return all child nodes of this node"""
        storage = self._getStorage()
        return storage.get_children(self)


    def _parent_get(self):
        """return the parent node or None if not existing"""
        if self.parent_id is None:
            return None
        storage = self._getStorage()
        # TODO: actually if parent_id is not None but the storage cannot find it, 
        # then something is wrong here as data is inconsistent
        # Probably the storage layer here needs to test this properly but we maybe should at least log it!
        try:
            return storage.get(self.parent_id)
        except ObjectNotFound:
            # TODO: add the logging statement here!
            return None
    
    def _parent_set(self, parent_node):
        """set a new parent but check for name collisions first"""
        storage = self._getStorage()
        
        # the passed node is the parent and we are the child
        sub_node = storage.get_by_name(parent_node, self.name)
        
        if sub_node is not None:
            raise DuplicateNodeName(self, sub_node, parent_node, self.name)
        self.parent_id = parent_node.node_id
        
    parent = __parent__ = property(_parent_get, _parent_set)

    @property
    def is_root_node(self):
        return self.parent_id is None
    
    ###
    ### BFG related traversal methods (getitem and __name__)
    ###

    def __getitem__(self, name):
        """retrieve the child node with this name"""
        
        # TODO better!
        storage = self._getStorage()
        node = storage.get_by_name(self, name)
        if node is None:
            raise KeyError, name
        return node

    
    # we need to override name here so that it equals nodename
    def _name_set(self, name):
        """set the name but test for a name collision. Here we actually need to
        make the _name attribute a property so that collision checking can be
        performed. Moreover we have the ``name`` and ``__name__`` attributes
        having the same content which both are sourced from the internal ``_name``
        attribute. We have a small difference in the getter for those two attributes
        though as ``__name__`` needs to be None in case it's a root node. Otherwise
        the traversal machinery produces the incorrect URL (see ``_name_get2``)."""
        storage = self._getStorage()
        parent = self.parent
        if parent is not None:
            sub_node = storage.get_by_name(parent, name)
            if sub_node is not None:
                raise DuplicateNodeName(self, sub_node, parent, name)        
        self._name = name

    def _name_get1(self):
        return self._name

    def _name_get2(self):
        # special case for root nodes, they need to return None as __name__
        if self.parent_id is None:
            return None
        return self._name

    name = property(_name_get1, _name_set)
    __name__ = property(_name_get2, _name_set)

    ### make us printable with some information useful for debugging

    def __str__(self):
        """print ourselves"""
        return u"<Node id='%s' name='%s' parent=%s>" %(self.node_id, 
                    self.name, self.parent_id)

    __repr__ = __str__
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.