Author: reinhard
Date: 2009-10-12 15:32:31 -0500 (Mon, 12 Oct 2009)
New Revision: 9962
Modified:
trunk/gnue-common/src/base/tree.py
Log:
Added option to allow/disallow None values for attribs.
Modified: trunk/gnue-common/src/base/tree.py
===================================================================
--- trunk/gnue-common/src/base/tree.py 2009-10-12 19:38:44 UTC (rev 9961)
+++ trunk/gnue-common/src/base/tree.py 2009-10-12 20:32:31 UTC (rev 9962)
@@ -668,11 +668,13 @@
_node_attribs_['color'] = {
'type': str,
'allowed_values': ['white', 'blue', 'red', 'green'],
+ 'required': False,
'default': 'white',
'label': u_("Background Color"),
'description': u_("Color on the screen")}
_node_attribs_['speed'] = {
'type': int,
+ 'required': True,
'default': 0,
'label': u_("Speed"),
'description': u_("Speed in km per hour")}
@@ -688,6 +690,11 @@
allowed_values: Limited value set for this attribute. If not included in
the dictionary, all possible values of the defined type are valid.
+ required: False means that the attribute may also be set to None, True
+ means that this is not allowed. If not included in the dictionary, it
+ defaults to False. Required attributes must be set at object initialization
+ unless a default value exists.
+
label: Short name for the attribute to present to users (e.g. in
gnue-designer).
@@ -765,10 +772,17 @@
if name is not None:
self.name = name
+ # Set attributes given in object constructor.
for (attrib, value) in kwargs.items():
self.__set_attrib__(attrib, value)
+ # Check whether all required attribs have been initialized.
+ for (attrib, definition) in self._node_attribs_.items():
+ if definition.get('required', False):
+ if self.__get_attrib__(attrib) is None:
+ raise AttribRequiredError(self, attrib)
+
# -------------------------------------------------------------------------
# Access attribs as object attributes
# -------------------------------------------------------------------------
@@ -826,7 +840,7 @@
if issubclass(target_type, NamedNode) and value is not None:
return self.__root__.__get_node_dict__(target_type)[value]
else:
- value
+ return value
# -------------------------------------------------------------------------
@@ -844,11 +858,13 @@
definition = self._node_attribs_[name]
- # TODO: Add option to allow/disallow setting to None.
+ # Check if setting to None is allowed.
+ if value is None and definition.get('required', False):
+ raise AttribRequiredError(self, name)
target_type = definition['type']
- # If this is a reference to another node, we need to store the name
+ # If this is a reference to another node, we need to store the name.
if issubclass(target_type, NamedNode):
target_type = unicode
@@ -856,15 +872,18 @@
if not isinstance(value, target_type):
value = target_type(value)
+ # Check if value is allowed.
if definition.has_key('allowed_values'):
if value not in definition['allowed_values']:
raise ValueError
+ # Call _change_foo_ method of the object.
if '_change_' + name + '_' in dir(self):
getattr(self, '_change_' + name + '_')(value)
self.__attribs[name] = value
+ # The attrib 'name' doubles as the node name.
if name == 'name':
self.__node_name__ = value
@@ -995,6 +1014,25 @@
# =============================================================================
+
+class AttribRequiredError(errors.ApplicationError):
+ """
+ The attribute is required.
+
+ A required attribute is missing at object creation or attempt to set
+ required attribute to None.
+ """
+ def __init__(self, node, attrib_name):
+ message = u_(
+ "Attribute '%(attrib_name)s' is required for node "
+ "'%(node_name)s' of of class '%(node_class)s'")
+ errors.ApplicationError.__init__(self, message % {
+ 'attrib_name': attrib_name,
+ 'node_name': unicode(node),
+ 'node_class': node.__class__.__name__})
+
+
+# =============================================================================
# Self test code
# =============================================================================
@@ -1212,10 +1250,10 @@
_allowed_children_ = {}
def _change_supervisor_(self, value):
print "Hey, %s's supervisor has changed to %s" % (self, value)
- Member._node_attribs_ = AttribNode._node_attribs_
+ Member._node_attribs_ = AttribNode._node_attribs_.copy()
Member._node_attribs_.update({
- 'rank': {'type': str},
- 'supervisor': {'type': Member}})
+ 'rank': {'type': str, 'required': True},
+ 'supervisor': {'type': Member}})
class Crew(AttribNode):
_allowed_children_ = {Member: {}}
_node_dicts_ = [Member]
@@ -1239,6 +1277,16 @@
name="Nyota Uhura",
rank="Communication Officer")])
+ # Test check of required attributes.
+ try:
+ Member(parent=crew, name='Guest')
+ except AttribRequiredError, error:
+ print "Correctly got an exception:", error
+ try:
+ crew.Spock.rank = None
+ except AttribRequiredError, error:
+ print "Correctly got an exception:", error
+
# Test attribute access for children.
print "Spock can be directly accessed:",
print crew.Spock
lmpx.com only provides a reader for public news (NNTP) servers. It is not
affiliated with the servers or forums shown here and is not responsible for
the content of articles, which is written by their respective authors.