[Zope3-checkins] CVS: Packages3/workflow/stateful - definition.py:1.8 instance.py:1.12 xmlimportexport.py:1.6

Ulrich Eck ueck@net-labs.de
Fri, 28 Mar 2003 13:17:08 -0500


Update of /cvs-repository/Packages3/workflow/stateful
In directory cvs.zope.org:/tmp/cvs-serv4403/stateful

Modified Files:
	definition.py instance.py xmlimportexport.py 
Log Message:
added script support for Transitions (condition and script need to evaluate 
to True that the transition can be fired)
cleaned up some parts of the import/export (unittests will follow next week)
added unittest for transition-script-support



=== Packages3/workflow/stateful/definition.py 1.7 => 1.8 ===
--- Packages3/workflow/stateful/definition.py:1.7	Thu Mar 27 11:26:13 2003
+++ Packages3/workflow/stateful/definition.py	Fri Mar 28 13:16:37 2003
@@ -57,11 +57,12 @@
     __implements__ = ITransition
 
     def __init__(self, source=None, destination=None, condition=None,
-                 permission=None, triggerMode=None):
+                 script=None, permission=None, triggerMode=None):
         super(Transition, self).__init__()
         self.__source = source
         self.__destination = destination
         self.__condition = condition or None
+        self.__script = script or None
         self.__permission = permission or None
         self.__triggerMode = triggerMode
 
@@ -84,6 +85,12 @@
     def setCondition(self, condition):
         self.__condition = condition or None
 
+    def getScript(self):
+        return self.__script
+
+    def setScript(self, script):
+        self.__script = script or None
+
     def getPermission(self):
         return self.__permission
 
@@ -105,6 +112,9 @@
 
     condition = property(getCondition, setCondition, None,
                          "Condition for Transition.")
+
+    script = property(getScript, setScript, None,
+                         "Script for Transition.")
 
     permission = property(getPermission, setPermission, None,
                           "Permission for Transition.")


=== Packages3/workflow/stateful/instance.py 1.11 => 1.12 ===
--- Packages3/workflow/stateful/instance.py:1.11	Thu Mar 27 10:12:40 2003
+++ Packages3/workflow/stateful/instance.py	Fri Mar 28 13:16:37 2003
@@ -29,7 +29,7 @@
 from zope.component import getServiceManager
 
 from zope.proxy.introspection import removeAllProxies
-from zope.proxy.context import ContextMethod
+from zope.proxy.context import ContextMethod, getWrapperContainer
 from zope.proxy.context import ContextWrapper,ContextAware
 
 from zope.security.management import getSecurityManager
@@ -103,6 +103,7 @@
         return self._outgoingTransitions(clean_pd)
     getOutgoingTransitions = ContextMethod(getOutgoingTransitions)
 
+
     def fireTransition(self, id):
         pd = self._getProcessDefinition()
         clean_pd = removeAllProxies(pd)
@@ -127,28 +128,44 @@
     _getProcessDefinition = ContextMethod(_getProcessDefinition)
 
 
-
-    def _getContext(self, transition):
+    def _getContext(self):
         ctx = {}
         # data should be readonly for condition-evaluation
         ctx['data'] = self.data
         ctx['principal'] = getSecurityManager().getPrincipal()
+        ctx['content'] = getWrapperContainer(self)
+        return ctx
+    _getContext = ContextMethod(_getContext)
+
+
+    def _extendContext(self, transition, ctx={}):
         ctx['state_change'] = StateChangeInfo(transition)
         return ctx
 
-    def _evaluateCondition(self, transition):
+    
+    def _evaluateCondition(self, transition, contexts):
         """Evaluate a condition in context of relevant-data.
         """
         if not transition.condition:
             return True
         expr = Engine.compile(transition.condition)
-        return expr(Engine.getContext( contexts=self._getContext(transition) ))
+        return expr(Engine.getContext( contexts=contexts ))
+
+
+    def _evaluateScript(self, transition, contexts):
+        script = transition.script
+        if not script:
+            return True
+        if type(script) in StringTypes:
+            sm = getServiceManager(self)
+            script =  sm.resolve(script)
+        return script(contexts)
+    _evaluateScript = ContextMethod(_evaluateScript)
 
 
     def _buildRelevantData(self, schema):
         """Create a new data object and initialize with Schema defaults.
         """
-
         data = RelevantData()
         data.__implements__ = schema
         if schema is not None:
@@ -160,6 +177,8 @@
     def _outgoingTransitions(self, clean_pd):
         sm = getSecurityManager()
         ret = []
+        contexts = self._getContext()
+        
         for name, trans in clean_pd.transitions.items():
             if self.status == trans.sourceState:
                 # check permissions
@@ -169,25 +188,36 @@
                     and not sm.checkPermission(permission, self)
                     ):
                     continue
-                    
+
+                ctx = self._extendContext(trans, contexts)
                 # evaluate conditions
                 if trans.condition is not None:
                     try:
-                      include = self._evaluateCondition(trans)
+                      include = self._evaluateCondition(trans, ctx)
+                    except Unauthorized:
+                        include = 0
+                    if not include:
+                        continue
+                    
+                if trans.script is not None:
+                    try:
+                        include = self._evaluateScript(trans, ctx)
                     except Unauthorized:
                         include = 0
                     if not include:
                         continue
-                
+                    
                 # append transition name
                 ret.append(name)
         return ret
+    _outgoingTransitions = ContextMethod(_outgoingTransitions)
         
 
     def _checkAndFireAuto(self, clean_pd):
         outgoing_transitions = self.getOutgoingTransitions()
         for name in outgoing_transitions:
             trans = clean_pd.transitions[name]
+            # XXX Use Constants instead of strings
             if trans.triggerMode == 'Automatic':
                 self.fireTransition(name)
                 return


=== Packages3/workflow/stateful/xmlimportexport.py 1.5 => 1.6 ===
--- Packages3/workflow/stateful/xmlimportexport.py:1.5	Thu Mar 27 11:26:13 2003
+++ Packages3/workflow/stateful/xmlimportexport.py	Fri Mar 28 13:16:37 2003
@@ -33,8 +33,9 @@
 from zope.app.workflow.stateful.definition import State, Transition
 
 class XMLStatefulImporter(ContentHandler):
-    def __init__(self, context):
+    def __init__(self, context, encoding='latin-1'):
         self.context = context
+        self.encoding = encoding
     
     def startElement(self, name, attrs):
         handler = getattr(self, 'start' + name.title().replace('-', ''), None)
@@ -55,40 +56,38 @@
     startTransitions = noop
 
     def startWorkflow(self, attrs):
-        title = attrs['title'].encode('latin-1')
-        getAdapter(self.context, IZopeDublinCore).setQualifiedTitles([('',title)])
+        dc = getAdapter(self.context, IZopeDublinCore)
+        dc.title = attrs.get('title', u'')
 
     def startSchema(self, attrs):
-        name = attrs['name'].encode('latin-1')
+        name = attrs['name'].encode(self.encoding)
         self.context.setRelevantDataSchema(name)
 
     def startState(self, attrs):
-        title = attrs.get('title', '').encode('latin-1')
-        name  = attrs['name'].encode('latin-1')
+        encoding = self.encoding
+        name  = attrs['name'].encode(encoding)
         if name == 'INITIAL':
             state = self.context.getState('INITIAL')
-            getAdapter(state, IZopeDublinCore).setQualifiedTitles([('',title)])
+            dc = getAdapter(state, IZopeDublinCore)
+            dc.title = attrs.get('title', u'')
         else:
             state = State()
-            getAdapter(state, IZopeDublinCore).setQualifiedTitles([('',title)])
+            dc = getAdapter(state, IZopeDublinCore)
+            dc.title = attrs.get('title', u'')
             self.context.addState(name, state)
 
     def startTransition(self, attrs):
-        title  = attrs.get('title', '').encode('latin-1')
-        source = attrs['sourceState'].encode('latin-1')
-        dest   = attrs['destinationState'].encode('latin-1')
-        condi  = attrs.get('condition', '').encode('latin-1')
-        permi  = attrs.get('permission', '').encode('latin-1')
-        triggM = attrs['triggerMode'].encode('latin-1')
-        name   = attrs['name'].encode('latin-1')
-        trans = Transition(source      = source,
-                           destination = dest,
-                           condition   = condi,
-                           permission  = permi,
-                           triggerMode = triggM)
-        getAdapter(trans, IZopeDublinCore).setQualifiedTitles([('',title)])
+        encoding = self.encoding
+        name   = attrs['name'].encode(encoding)
+        trans = Transition(source = attrs['sourceState'].encode(encoding),
+                           destination = attrs['destinationState'].encode(encoding),
+                           condition = attrs.get('condition', '').encode(encoding),
+                           script = attrs.get('script', '').encode(encoding),
+                           permission = attrs.get('permission', '').encode(encoding),
+                           triggerMode = attrs['triggerMode'].encode(encoding))
+        dc = getAdapter(trans, IZopeDublinCore)
+        dc.title = attrs.get('title', u'')
         self.context.addTransition(name, trans)
-            
 
 
         
@@ -100,6 +99,7 @@
         return True
 
     def doImport(self, context, data):
+        # XXX Manually clean ProcessDefinition ??
         context.clear()
         if not hasattr(data, "read"):
             data = StringIO(data)
@@ -124,13 +124,4 @@
 
     def getDublinCore(self, obj):
         return getAdapter(obj, IZopeDublinCore)
-
-# not working, schema-class should be in an filesystem based module
-# which gets imported separately
-##    def getSchemaClass(self):
-##        schema = self.process_definition.getRelevantDataSchema()
-##        if type(schema) in StringTypes:
-##            sm = getServiceManager(self.context)
-##            schema =  sm.resolve(schema)
-##        return schema