[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[gnue] r8407 - in trunk/gnue-common/src/logic: . adapters
From: |
reinhard |
Subject: |
[gnue] r8407 - in trunk/gnue-common/src/logic: . adapters |
Date: |
Fri, 14 Apr 2006 18:04:57 -0500 (CDT) |
Author: reinhard
Date: 2006-04-14 18:04:56 -0500 (Fri, 14 Apr 2006)
New Revision: 8407
Modified:
trunk/gnue-common/src/logic/GTriggerCore.py
trunk/gnue-common/src/logic/NamespaceCore.py
trunk/gnue-common/src/logic/adapters/Base.py
Log:
Cleaning up.
Modified: trunk/gnue-common/src/logic/GTriggerCore.py
===================================================================
--- trunk/gnue-common/src/logic/GTriggerCore.py 2006-04-14 17:52:16 UTC (rev
8406)
+++ trunk/gnue-common/src/logic/GTriggerCore.py 2006-04-14 23:04:56 UTC (rev
8407)
@@ -1,66 +1,89 @@
+# GNU Enterprise Common Library - Trigger Enabled Base Classes
#
+# Copyright 2000-2006 Free Software Foundation
+#
# This file is part of GNU Enterprise.
#
-# GNU Enterprise is free software; you can redistribute it
+# GNU Enterprise is free software; you can redistribute it
# and/or modify it under the terms of the GNU General Public
-# License as published by the Free Software Foundation; either
+# License as published by the Free Software Foundation; either
# version 2, or (at your option) any later version.
#
# GNU Enterprise is distributed in the hope that it will be
-# useful, but WITHOUT ANY WARRANTY; without even the implied
-# warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+# useful, but WITHOUT ANY WARRANTY; without even the implied
+# warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
# PURPOSE. See the GNU General Public License for more details.
#
-# You should have received a copy of the GNU General Public
-# License along with program; see the file COPYING. If not,
-# write to the Free Software Foundation, Inc., 59 Temple Place
+# You should have received a copy of the GNU General Public
+# License along with program; see the file COPYING. If not,
+# write to the Free Software Foundation, Inc., 59 Temple Place
# - Suite 330, Boston, MA 02111-1307, USA.
#
-# Copyright 2000-2006 Free Software Foundation
-#
-#
-# FILE:
-# GCoreTrigger.py
-#
-# DESCRIPTION:
-# A base class inherited by GObj. It's only purpose
-# is to keep all the trigger code in one place instead
-# of tacking some trigger code into GObj directly
-# It's in it's own file to prevent circular imports
-#
-# NOTES:
-#
+# $Id$
+"""
+Base Classes to derive from to make use of the action/trigger system.
+"""
-#
-# GTriggerCore
-#
-#
+__all__ = ['GTriggerCore']
+
+
+# =============================================================================
+# Base class for all objects that are exported to trigger namespace
+# =============================================================================
+
class GTriggerCore:
- def __init__(self):
- self._triggerGlobal = 0
- self._triggerFunctions = {}
+ """
+ Base class for all objects that can be exported to action/trigger
+ namespace.
- self._triggerProperties = {}
+ Descendants can define how they want to be seen in action/trigger code by
+ setting the following properties:
- #
- # Dictionary representing this object's
- # local namespace. Populated as part of
- # GTriggerNamespace.constructTriggerObject
- #
- self._localTriggerNamespace = {}
-
- #
- # Links to functions to be used when
- # trigger attempts to directly set or get
- # the objects by name
- #
- self._triggerSet = None
- self._triggerGet = None
+ @ivar _triggerGlobal: If set to True, this object is added to the global
+ namespace. Otherwise, the object is only available as a property of its
+ parent object.
+ @ivar _triggerGet: Can be set to a method that returns the string value of
+ the object. In action/trigger code, "str(object)" will implicitly call
+ this function.
+ @ivar _triggerSet: Can be set to a method that sets the value of this
+ object. In action/trigger code, "parent.object = 'foo' will implicitly
+ call this function.
+ @ivar _triggerFunctions: Dictionary defining the functions this object
+ should present in action/trigger code. Keys in this dictionary are the
+ function names how they should be visible in the action/trigger code.
+ Values are dictionaries, where the key 'function' contains the method
+ to call, and the key 'global' can be set to True to make this a global
+ function.
+ @ivar _triggerProperties: Dictionary defining the properties this object
+ should present in action/trigger code. Keys in this dictionary are the
+ property names how they should be visible in action/trigger code.
+ Values are dictionaries, where the key 'get' contains the method used
+ to read the property, and the key 'set' optionally contains the method
+ used to set the property. Properties with no 'set' key are read only
+ properties.
+ """
+ # -------------------------------------------------------------------------
+ # Constructor
+ # -------------------------------------------------------------------------
- #
- # Dict of triggers that are valid for this specific
- # object
- #
- self._validTriggers = {}
+ def __init__(self):
+ """
+ Initialize a GTriggerCore instance.
+ """
+ self._triggerGlobal = 0
+ self._triggerGet = None
+ self._triggerSet = None
+ self._triggerFunctions = {}
+ self._triggerProperties = {}
+
+ # Dictionary representing this object's
+ # local namespace. Populated as part of
+ # GTriggerNamespace.constructTriggerObject
+ # FIXME: Belongs into GTriggerExtension?
+ self._localTriggerNamespace = {}
+
+ # Dict of triggers that are valid for this specific object
+ # FIXME: Belongs into GTriggerExtension?
+ self._validTriggers = {}
Modified: trunk/gnue-common/src/logic/NamespaceCore.py
===================================================================
--- trunk/gnue-common/src/logic/NamespaceCore.py 2006-04-14 17:52:16 UTC
(rev 8406)
+++ trunk/gnue-common/src/logic/NamespaceCore.py 2006-04-14 23:04:56 UTC
(rev 8407)
@@ -1,4 +1,7 @@
+# GNU Enterprise Common Library - Namespace Handling
#
+# Copyright 2000-2006 Free Software Foundation
+#
# This file is part of GNU Enterprise.
#
# GNU Enterprise is free software; you can redistribute it
@@ -16,345 +19,292 @@
# write to the Free Software Foundation, Inc., 59 Temple Place
# - Suite 330, Boston, MA 02111-1307, USA.
#
-# Copyright 2000-2006 Free Software Foundation
-#
-#
-# FILE:
-# NamespaceCore.py
-#
-# DESCRIPTION:
-# Provides the basic classes needed by the generic trigger system
-#
-# NOTES:
-#
-import sys
+# $Id$
+"""
+Classes to build up a namespace object tree from an XML object tree.
+
+Namespace objects are available within action and trigger code. They mirror the
+XML object tree of the document, but the namespace objects are limited to the
+functions and properties that the objects explicitly want to provide.
+"""
+
import types
-import string
-import copy
+
from gnue.common.definitions.GObjects import GObj
-from gnue.common.apps import GDebug
-from gnue.common.formatting import GTypecast
-from xml.sax import saxutils
+from gnue.common.logic.GTriggerCore import GTriggerCore
+__all__ = ['GObjNamespace', 'NamespaceElement']
-#######################################################################
-#
-# Trigger/Function namespace classes
-#
-# Classes used in implementing the trigger/function namespaces
-#
-#
+
+# =============================================================================
# GObjNamespace
-#
-# Manager class for a namespace. Passed a GObj based
-# tree at __init__ which it uses to construct a new
-# NamespaceElement based tree
-#
-class GObjNamespace(GObj):
- def __init__(self,objectTree = None, rootName="root"):
- self._globalNamespace = {'True' : 1,
- 'False': 0,
- }
+# =============================================================================
- self._rname = rootName
+class GObjNamespace:
+ """
+ Helper object to build up a tree of namespace objects. For internal use of
+ the trigger system only.
+ """
- if objectTree:
- self._globalNamespace[self._rname] =
self.constructTriggerObject(objectTree)
- else:
- assert gDebug(1,'GObjNamespace was passed an empty object tree')
+ # -------------------------------------------------------------------------
+ # Constructor
+ # -------------------------------------------------------------------------
- #
- # constructTriggerObject
- #
- # Travels down thru a GObj based tree and builds a set
- # of NamespaceElements that will implement the namespace
- # inside triggers/formulas.
- #
- def constructTriggerObject(self, gobjObject, triggerParent=None):
- triggerObject = None
- # Some items in a GObj tree may not be GObj based (GContent for instance)
+ def __init__(self, xml_object, rootName = "root"):
+ """
+ Initialize a GObjNamespace instance.
+ """
- if isinstance(gobjObject,GObj) and hasattr(gobjObject,'name'):
- triggerObject = NamespaceElement(triggerParent)
- triggerObject._object = gobjObject
+ # FIXME: This should rather check for GRootObj, but that causes a
+ # circular import
+ checktype (xml_object, GObj)
- # Add this triggerObject to global namespace if the GObj requests it
- if gobjObject._triggerGlobal:
- self._globalNamespace[gobjObject.name] = triggerObject
+ self._globalNamespace = {}
- # setup get and set functions when they exist in the GObj
- triggerObject._triggerSet = gobjObject._triggerSet
- triggerObject._triggerGet = gobjObject._triggerGet
+ self._globalNamespace[rootName] = \
+ self.constructTriggerObject(xml_object)
- # Add any trigger methods defined by GObj
- if len(gobjObject._triggerFunctions):
- for item in gobjObject._triggerFunctions.keys():
- if type(gobjObject._triggerFunctions[item]['function']) ==
types.MethodType:
- object =
NamespaceFunction(item,gobjObject._triggerFunctions[item]['function'])
- triggerObject.__dict__[item] = object
+ # -------------------------------------------------------------------------
+ # Construct a namespace object tree for an XML object tree
+ # -------------------------------------------------------------------------
+
+ def constructTriggerObject(self, xml_object):
+ """
+ Construct a namespace object tree from an XML (L{GObject.GObj}) object
+ tree.
+
+ This function creates a L{NamespaceElement} object for each
+ L{GObject.GObj} in the object.
+ """
+
+ # Do not create a namespace object for xml objects that are not trigger
+ # enabled.
+ if not isinstance(xml_object, GTriggerCore):
+ return None
+
+ # Do not create a namespace object for xml objects with no "name"
+ # property.
+ if not hasattr(xml_object, 'name') or xml_object.name is None:
+ return None
+
+ # Create dictionary with methods as defined
+ methods = {}
+ for (name, definition) in xml_object._triggerFunctions.items():
+ function = definition.get('function')
+ assert isinstance(function, types.MethodType)
+ methods[name] = function
# Add this function to global namespace if the GObj requests it
- if gobjObject._triggerFunctions[item].get('global',0):
- self._globalNamespace[item] = object
+ if definition.get('global', False):
+ self._globalNamespace[name] = function
- else:
- raise 'Only functions are supported in an objects
_triggerFunctions (%s %s)' % (gobjObject,item)
+ # Create dictionary with properties as defined
+ properties = {}
+ for (name, definition) in xml_object._triggerProperties.items():
+ get_function = definition.get('get')
+ set_function = definition.get('set')
+ assert isinstance(get_function, types.MethodType)
+ if set_function is not None:
+ assert isinstance(set_function, types.MethodType)
+ properties[name] = (get_function, set_function)
- sys.exit()
+ # Create the namespace object
+ namespace_object = NamespaceElement(
+ xml_object = xml_object,
+ get_method = xml_object._triggerGet,
+ set_method = xml_object._triggerSet,
+ methods = methods,
+ properties = properties)
- # Load the defined __properties__ into this object's
- # NamespaceElementProperties instance
- if len(gobjObject._triggerProperties):
- for item in gobjObject._triggerProperties.keys():
- if gobjObject._triggerProperties[item].has_key('set'):
- setFunc = gobjObject._triggerProperties[item]['set']
- else:
- setFunc = None
-
triggerObject._triggerProperties.addProperty(item,gobjObject._triggerProperties[item]['get'],
setFunc)
+ # Process the children of this xml object
+ if len(xml_object._children):
+ self.__add_children(xml_object._children, namespace_object)
- # Process the children of this Gobj
- if len(gobjObject._children):
- self.addChildNames(gobjObject._children, triggerObject)
+ # Add the namespace object to global namespace if the xml object
+ # requests it
+ if xml_object._triggerGlobal:
+ self._globalNamespace[xml_object.name] = namespace_object
- #
- # populate the GObj's _localTriggerNamespace
- localNamespace = {'self':triggerObject}
- localNamespace.update(triggerObject.__dict__)
- gobjObject._localTriggerNamespace = localNamespace
+ # populate the GObj's _localTriggerNamespace
+ # FIXME: This would only have to be done for all objects that can have
+ # triggers attached, not for all objects that can appear in the trigger
+ # namespace.
+ xml_object._localTriggerNamespace = {'self': namespace_object}
- return triggerObject
+ return namespace_object
- def addChildNames(self, children, triggerObject):
+
+ # -------------------------------------------------------------------------
+ # Add children to a Namespace object matching the children of the GObj
+ # -------------------------------------------------------------------------
+
+ def __add_children(self, children, namespace_object):
+ """
+ Create child namespace objects according to child XML objects
+ """
for child in children:
- object = self.constructTriggerObject(child, triggerObject)
+ child_object = self.constructTriggerObject(child)
- # Add this objects children to it's namespace by their name
- if object:
- if child.name is not None:
- # skip on GRPassThru objects
- if child.name [:2] != '__':
- triggerObject.__dict__[child.name] = object
- else:
- if len(child._children):
- self.addChildNames(child._children, triggerObject)
-
+ # Add this objects children to it's namespace by their name
+ if child_object:
+ # skip on GRPassThru objects
+ if child.name.startswith('__'):
+ if len(child._children):
+ self.__add_children(child._children, namespace_object)
+ else:
+ namespace_object.__dict__[child.name] = child_object
-#
-# NamespaceElement
-#
-# Inherits GObj to gain it's parent/child system
-#
-class NamespaceElement(GObj):
- def __init__(self, parent):
- GObj.__init__(self,parent)
- # TODO: Check wether this _parent attribute is really needed, since it
- # should be a weak reference (or replaced by getParent ())
- self.__dict__['_parent'] = parent
- self._triggerProperties = NamespaceElementProperties()
- self._triggerSet = None
- self._triggerGet = None
- self._object = None
- #
- #
- #
- def __repr__(self):
- try:
- return "NamespaceElement(%s) at %s" % (self._object.__class__, id(self))
- except:
- return "NamespaceElement at %s" % (id(self))
+# =============================================================================
+# Namespace object
+# =============================================================================
+class NamespaceElement(object):
+ """
+ Proxy object that represents an object from an XML tree within the
+ action/trigger namespace.
+ """
- #
- # showTree
- #
- # Handy function to dump a rough look at the namespace
- # doesn't show things nested properly though
- def showTree(self, indent=0):
- print ' ' * indent + `self._type` + `self`
- for item in self.__dict__.keys():
- if item[:1] != '_':
- print ' ' * indent + ' :' + item
- for child in self._children:
- child.showTree(indent + 2)
+ # -------------------------------------------------------------------------
+ # Constructor
+ # -------------------------------------------------------------------------
- #
- # __setattr__
- #
- # This is called when trying to write something inside a trigger object
- # namespace. It checks to see if the var name is already linked to a
- # NamespaceElement based object and calls that objects _triggerSet if it
- # exists.
- #
- # Example: form.block1.entry1 = "foo"
- #
- # The __setattr__ will execute at the block1 and call the functions that
- # are part of the entry1 object to set it's value
- #
- def __setattr__(self, name, value):
- if self.__dict__.has_key(name) and \
- isinstance(self.__dict__[name], NamespaceElement):
- if isinstance(self.__dict__[name], NamespaceElement):
- if self.__dict__[name]._triggerSet:
- self.__dict__[name]._triggerSet(value)
- else:
- assert gDebug(1,'Trigger attempting to reset a form object')
- else:
- self.__dict__[name] = value
+ def __init__(self, xml_object, get_method, set_method, methods,
+ properties):
+ """
+ Initialize a namespace proxy object.
+ """
- #
- # __getattr__
- #
- # Only needed to return the NamespaceElementProperties
- # object
- #
- def __getattr__(self,name):
- if name == '__properties__':
- return self._triggerProperties
- else:
-# GDebug.printMesg(1,"AttributeError: %s" % name)
-# print self.__dict__
- raise AttributeError, '%s' % (name)
+ checktype (xml_object, GTriggerCore)
- #
- # __str__
- #
- # This executes at a different level than the __setattr__
- # While __setattr__ is executed in the parent object to protect
- # it's namespace object links, this routine is called by the
- # object referenced
- #
- # Example: foo = form.block1.entry1
- #
- # This __str__ would execute against the entry1 object
- #
- def __str__(self):
- if self._triggerGet:
- return str(self._triggerGet())
- else:
- return ""
+ self.__xml_object = xml_object
+ self.__get_method = get_method
+ self.__set_method = set_method
+ self.__methods = methods
+ self.__properties = properties
- #
- # __str__
- #
- # This executes at a different level than the __setattr__
- # While __setattr__ is executed in the parent object to protect
- # it's namespace object links, this routine is called by the
- # object referenced
- #
- # Example: foo = int(form.block1.entry1)
- #
- # This __int__ would execute against the entry1 object
- #
- def __int__(self):
- if self._triggerGet:
- return int(self._triggerGet())
- else:
- return 0
- #
- # __cmp__
- #
- # Forces the system to compare the string values of
- # NamespaceElement objects and not their instances
- #
- def __cmp__(self,other):
- selfvalue = "%s" % self
- othervalue = "%s" % other
+ # -------------------------------------------------------------------------
+ # Nice string representation
+ # -------------------------------------------------------------------------
- if selfvalue == othervalue:
- return 0
- elif selfvalue < othervalue:
- return -1
- else:
- return 1
+ def __repr__(self):
+ return self.__xml_object.name
- #
- # __nonzero__
- #
- # Needed to make __len__ function below play nice
- #
- def __nonzero__(self):
- return 1
+ # -------------------------------------------------------------------------
+ # Getting and setting attributes
+ # -------------------------------------------------------------------------
- #
- # __len__
- #
- # Implements len() support
- #
- def __len__(self):
- string = "%s" % self
- return len(string)
+ def __getattr__(self, name):
- #
- # __getitem__
- #
- # implements support for sub selections of strings
- #
- # example: block1.fieldname[0:4]
- #
- def __getitem__(self, key) :
- string = self.__str__()
- return string[key.start:key.stop]
+ # Handle methods and properties. Child objects (which are stored in the
+ # native __dict__ of the object) have highest priority.
+ if self.__methods.has_key(name):
+ return self.__methods[name]
+ elif self.__properties.has_key(name):
+ return self.__properties[name][0]()
- #
- # __iter__
- #
- # Python iterator support
- #
- def __iter__(self):
- return iter(self._object)
+ # -------------------------------------------------------------------------
-#
-# NamespaceFunction
-#
-# Accessor class for functions that are made available in the trigger
-# namespace
-#
-class NamespaceFunction:
- def __init__(self, name, functionLink):
- self._name = name
- self._objectFunction = functionLink
+ def __setattr__(self, name, value):
- def __call__(self, *args, **kwargs):
- return self._objectFunction(*args, **kwargs)
+ # This is called when trying to write something inside a trigger object
+ # namespace. It checks to see if the var name is already linked to a
+ # NamespaceElement based object and calls that objects _triggerSet if
+ # it exists.
+ #
+ # Example: form.block1.entry1 = "foo"
+ #
+ # The __setattr__ will execute at the block1 and call the functions
+ # that are part of the entry1 object to set it's value.
+ #
+ # Apart from that, this also handles properties.
-#
-# NamespaceElementProperties
-#
-# Accessor class for properties that are made available in this an
-# object's __properties__ namespace
-#
-class NamespaceElementProperties:
- def __init__(self):
- self._properties = {}
+ # Directly set for private variables, otherwise we will recurse in
+ # __init__.
+ if name.startswith('_NamespaceElement__'):
+ self.__dict__[name] = value
+ return
- def addProperty(self,name, getFunc, setFunc):
- self._properties[name] = {'get':getFunc,
- 'set':setFunc,
- }
+ attr = self.__dict__.get(name)
- def __setattr__(self, name, value):
- # Hack to ensure that self._properties exists
- if not self.__dict__.has_key('_properties'):
- self.__dict__['_properties'] = {}
+ if isinstance(attr, NamespaceElement):
+ if attr.__set_method is None:
+ # TODO: Make this a good exception
+ raise "Cannot set value of %s" % name
+ attr.__set_method(value)
- if self._properties.has_key(name):
- # If none the it's readonly
- if self._properties[name]['set']:
- self._properties[name]['set'](value)
- else:
- assert gDebug(1,'Attempt to set readonly property :%s' %(name))
- else:
- self.__dict__[name] = value
+ elif self.__properties.has_key(name):
+ set_function = self.__properties[name][1]
+ if set_function is None:
+ # TODO: Make this a good exception
+ raise "Cannot set read only property %s" % name
+ set_function(value)
- def __getattr__(self,name):
- if self.__dict__['_properties'].has_key(name):
- return self._properties[name]['get']()
- else:
- raise AttributeError
+ else:
+ self.__dict__[name] = value
+ # -------------------------------------------------------------------------
+ # String and Integer values
+ # -------------------------------------------------------------------------
+
+ def __str__(self):
+
+ # This executes at a different level than __setattr__.
+ # While __setattr__ is executed in the parent object to protect its
+ # namespace object links, this routine is called by the referenced
+ # object.
+ #
+ # Example: foo = str(form.block1.entry1)
+ #
+ # This __str__ would execute for the entry1 object.
+
+ if self.__get_method:
+ return str(self.__get_method())
+ else:
+ return self.__xml_object.name
+
+ # -------------------------------------------------------------------------
+
+ def __int__(self):
+
+ if self.__get_method:
+ return int(self.__get_method())
+ else:
+ return 0
+
+ # -------------------------------------------------------------------------
+
+ def __cmp__(self, other):
+
+ # Forces the system to compare the string values of NamespaceElement
+ # objects rather than their instances
+
+ return cmp(str(self), str(other))
+
+ # -------------------------------------------------------------------------
+
+ def __nonzero__(self):
+ return True
+
+ # -------------------------------------------------------------------------
+
+ def __len__(self):
+ return len(str(self))
+
+ # -------------------------------------------------------------------------
+
+ def __getitem__(self, key) :
+ return str(self)[key.start:key.stop]
+
+
+ # -------------------------------------------------------------------------
+ # Iterator support in case the underlying GObj object supports it
+ # -------------------------------------------------------------------------
+
+ def __iter__(self):
+ return iter(self.__xml_object)
Modified: trunk/gnue-common/src/logic/adapters/Base.py
===================================================================
--- trunk/gnue-common/src/logic/adapters/Base.py 2006-04-14 17:52:16 UTC
(rev 8406)
+++ trunk/gnue-common/src/logic/adapters/Base.py 2006-04-14 23:04:56 UTC
(rev 8407)
@@ -20,12 +20,10 @@
#
# $Id$
-import sys
-import traceback
-import string
+import types
from gnue.common.logic.language import ImplementationError, AbortRequest
-from gnue.common.logic.NamespaceCore import NamespaceElement, NamespaceFunction
+from gnue.common.logic.NamespaceCore import NamespaceElement
# =============================================================================
@@ -82,7 +80,7 @@
"""
for (name, value) in addNS.items ():
if name is not None:
- if isinstance (value, NamespaceFunction):
+ if isinstance (value, types.MethodType):
self.bindFunction (name, value, asGlobal)
if isinstance (value, NamespaceElement):
[Prev in Thread] |
Current Thread |
[Next in Thread] |
- [gnue] r8407 - in trunk/gnue-common/src/logic: . adapters,
reinhard <=