[Top][All Lists]
[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()
[Prev in Thread] |
Current Thread |
[Next in Thread] |
- [gnue] r8582 - trunk/gnue-common/src/utils,
reinhard <=