commit-gnue
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[gnue] r8582 - trunk/gnue-common/src/utils


From: reinhard
Subject: [gnue] r8582 - trunk/gnue-common/src/utils
Date: Mon, 21 Aug 2006 16:32:02 -0500 (CDT)

Author: reinhard
Date: 2006-08-21 16:32:02 -0500 (Mon, 21 Aug 2006)
New Revision: 8582

Modified:
   trunk/gnue-common/src/utils/tree.py
Log:
Committing current state of tree.py. Still work in progress, but I probably
won't have much time to continue on this over the next few weeks.


Modified: trunk/gnue-common/src/utils/tree.py
===================================================================
--- trunk/gnue-common/src/utils/tree.py 2006-08-21 13:58:28 UTC (rev 8581)
+++ trunk/gnue-common/src/utils/tree.py 2006-08-21 21:32:02 UTC (rev 8582)
@@ -19,10 +19,12 @@
 # write to the Free Software Foundation, Inc., 59 Temple Place
 # - Suite 330, Boston, MA 02111-1307, USA.
 #
-# $Id: http.py 8129 2006-01-18 21:25:44Z jcater $
+# $Id$
 
 """
 Classes representing a node in a tree structure.
+
+TODO: This module is work in progress.
 """
 
 import locale
@@ -31,7 +33,7 @@
 
 __all__ = ['CircularReferenceError', 'DuplicateChildNameError',
         'DuplicateDescendantNameError', 'NodeDictNotAvailableError',
-        'Node', 'NamedNode']
+        'Node', 'NamedNode', 'AttribNode']
 
 
 # =============================================================================
@@ -289,19 +291,23 @@
 
 class NamedNode(Node):
     """
-    A Node in an n-ary tree with a node type and a name.
+    A node in an n-ary tree with a node type and a name.
 
     C{NamedNode}s introduce a L{I{node type} <node_type>} and a L{I{node name}
     <node_name>}. While for a given subclass of C{NamedNode}, all instances
     share the same node type, each instance has a different node name.
 
-    Instances of this class support searching descendants L{for a given node
+    Children of C{NamedNode}s that are also C{NamedNode}s can be L{accessed
+    with their name <get_child>}.
+
+    Instances of this class support searching ancestors L{for a given node type
+    <find_ancestor_of_type>} and searching descendants L{for a given node
     name <find_descendant>} or L{for a given node type
     <find_descendant_of_type>}.
 
     Every C{NamedNode} instance can define a list of node types it is
     interested in. Descendants of each of these types will be hashed in a
-    dictionary (a separate dictionary per type).
+    L{dictionary <get_node_dict>} (a separate dictionary per type).
 
     @cvar _node_type_: Type of this node. Defined by subclasses.
     @type _node_type_: str
@@ -661,21 +667,121 @@
 
 
 # =============================================================================
-# Notes
+# AttribNode class
 # =============================================================================
 
-# Some quick notes on descendant classes so I don't forget it:
-# 
-# AttributeNode adds handling of [XML] attributes. Descendants of this class
-# defined in a self-contained way details about the valid attributes (what is
-# now defined in those getXMLelements() functions). Initializes default
-# attributes for new instances from these definitions. Checks validity of
-# attribute values on setting of attributes. Allows only dictionary-style
-# access to those attributes, e.g. only myBlock['datasource'], not
-# myBlock.datasource. Better name for "attribute" is welcome, as "attribute" is
-# already used in Python for instance variables (getattr() etc).
+class AttribNode(NamedNode):
+    """
+    A node in an n-ary tree with node attributes.
 
+    Every subclass of this class can define a set of valid attributes that
+    nodes of this subclass will have, of what type the attributes are, and what
+    default value these attributes will have.
 
+    TODO: document structure of _node_attribs_ dictionary, and give examples
+    how to use it (especially how to extend the inherited dictionary in
+    subclasses).
+
+    Instances of this class expose their attributes through dictionary access.
+    The attribute 'my_attr' of the object instance 'my_node' can be read and
+    written as C{my_node['my_attr']}.
+
+    On creation of new instances, attributes are initialized with their default
+    value, or with C{None} if no default value is defined.
+
+    Whenever an attribute value is set, it is typecast to the defined type. If
+    this typecast fails, the value is not changed, and an exception is raised.
+
+    Attribute types can not only be ordinary data types (like C{unicode},
+    C{str}, or C{int}, but they can also be subclasses of L{NamedNode}. In this
+    case, both C{my_node['my_attr'] = other_node} and
+    C{my_node['my_attr'] = 'other_node_name'} are valid, and will cause
+    C{my_node['my_attr'] to evaluate to other_node, provided that other_node
+    has a name of 'other_node_name', both my_node and other_node are in the
+    same tree, and the type of other_node is registered in the root node's
+    C{_node_dicts_} list.
+    """
+
+    # -------------------------------------------------------------------------
+    # Class variables
+    # -------------------------------------------------------------------------
+
+    _node_attribs_ = {
+            'name': {
+                   'type': str,
+                   'label': u_("name"),
+                   'description': u_("Name of this element"),
+                   'default': None}}
+
+
+    # -------------------------------------------------------------------------
+    # Constructor
+    # -------------------------------------------------------------------------
+
+    def __init__(self, parent):
+        """
+        Initialize a new attributed node.
+
+        @param parent: Parent node.
+        @type parent: Node
+        """
+
+        NamedNode.__init__(self, parent)
+
+        #: Attributes
+        self.__attribs = {}
+
+        for (name, definition) in self._node_attribs_:
+            self.__attribs[name] = definition.get('default')
+
+
+    # -------------------------------------------------------------------------
+    # Dictionary style attribute access
+    # -------------------------------------------------------------------------
+
+    def __getitem__(self, name):
+
+        try:
+            definition = self._node_attribs_[name]
+        except KeyError:
+            raise InvalidAttributeError(self, name)
+
+       # if this is a reference to another node, look for it in the parent's
+       # node dictionary
+       target_type = definition['type']
+
+       # TODO: find node type for wanted class, look up name in root's node
+       # dictionary.
+
+        return self.__attribs[name]
+
+    # -------------------------------------------------------------------------
+
+    def __setitem__(self, name, value):
+
+        try:
+            definition = self._node_attribs_[name]
+        except KeyError:
+            raise InvalidAttributeError(self, name)
+
+       # typecast if necessary
+       target_type = definition['type']
+
+       # if this is a reference to another node, we need to store the name
+       if issubclass(target_type, NamedNode):
+           target_type = unicode
+
+       if not isinstance(value, target_type):
+           try:
+               value = target_type(value)
+           except Exception, e:
+               raise InvalidAttributeValueError(self, name, value, e)
+
+       # TODO: check if value is in list of allowed values if defined in
+       # _node_attribs_
+        self.__attribs[name] = value
+
+
 # =============================================================================
 # Self test code
 # =============================================================================
@@ -857,3 +963,4 @@
 
     test_node_class()
     test_named_node_class()
+    # TODO: test_attrib_node_class()





reply via email to

[Prev in Thread] Current Thread [Next in Thread]