[Zope-CMF] Re: Zope 3 events from workflow

Martin Aspeli optilude at gmx.net
Thu Dec 28 21:32:22 EST 2006


Tres Seaver wrote:

> I think I'll be able to review and merge it this week.

> That's fine, although they might end up getting merged at the "same
> time" if you get the second patch in before I get to reviewing the first.

Who needs sleep, ey.... I've done the second patch (pasted below for 
your inspection) and added it to the collector at 
http://www.zope.org/Collectors/CMF/461.

Comments welcome! Hopefully both of these should be ready for merge now.

Martin

Index: interfaces/__init__.py
===================================================================
--- interfaces/__init__.py	(revision 71665)
+++ interfaces/__init__.py	(working copy)
@@ -17,6 +17,7 @@

  from _content import *
  from _tools import *
+from _events import *

  import CachingPolicyManager
  import Contentish
Index: interfaces/_events.py
===================================================================
--- interfaces/_events.py	(revision 0)
+++ interfaces/_events.py	(revision 0)
@@ -0,0 +1,30 @@
+from zope.interface import Attribute
+from zope.component.interfaces import IObjectEvent
+
+
+class IWorkflowActionEvent(IObjectEvent):
+
+    """Base interface for events around workflow action invocation
+    """
+
+    workflow = Attribute("The workflow definition object")
+    action = Attribute("The name of the action being invoked")
+
+class IActionWillBeInvokedEvent(IWorkflowActionEvent):
+
+    """Event fired immediately before a workflow action is invoked
+    """
+
+class IActionRaisedExceptionEvent(IWorkflowActionEvent):
+
+    """Event fired when a workflow action raised an exception
+    """
+
+    exc = Attribute("The exception info for the exception raised")
+
+class IActionSucceededEvent(IWorkflowActionEvent):
+
+    """Event fired when a workflow action succeeded
+    """
+
+    result = Attribute("The result of the workflow action")
\ No newline at end of file
Index: WorkflowTool.py
===================================================================
--- WorkflowTool.py	(revision 71665)
+++ WorkflowTool.py	(working copy)
@@ -25,6 +25,7 @@
  from OFS.Folder import Folder
  from OFS.ObjectManager import IFAwareObjectManager
  from zope.interface import implements
+from zope.event import notify

  from ActionProviderBase import ActionProviderBase
  from interfaces import IConfigurableWorkflowTool
@@ -39,8 +40,10 @@
  from WorkflowCore import ObjectDeleted
  from WorkflowCore import ObjectMoved
  from WorkflowCore import WorkflowException
+from WorkflowCore import ActionWillBeInvokedEvent
+from WorkflowCore import ActionRaisedExceptionEvent
+from WorkflowCore import ActionSucceededEvent

-
  _marker = []  # Create a new marker object.


@@ -293,6 +296,7 @@
          wfs = self.getWorkflowsFor(ob)
          for wf in wfs:
              wf.notifyBefore(ob, action)
+            notify(ActionWillBeInvokedEvent(ob, wf, action))

      security.declarePrivate('notifySuccess')
      def notifySuccess(self, ob, action, result=None):
@@ -301,6 +305,7 @@
          wfs = self.getWorkflowsFor(ob)
          for wf in wfs:
              wf.notifySuccess(ob, action, result)
+            notify(ActionSucceededEvent(ob, wf, action, result))

      security.declarePrivate('notifyException')
      def notifyException(self, ob, action, exc):
@@ -309,6 +314,7 @@
          wfs = self.getWorkflowsFor(ob)
          for wf in wfs:
              wf.notifyException(ob, action, exc)
+            notify(ActionRaisedExceptionEvent(ob, wf, action, exc))

      security.declarePrivate('getHistoryOf')
      def getHistoryOf(self, wf_id, ob):
@@ -516,6 +522,7 @@
          reindex = 1
          for w in wfs:
              w.notifyBefore(ob, action)
+            notify(ActionWillBeInvokedEvent(ob, w, action))
          try:
              res = func(*args, **kw)
          except ObjectDeleted, ex:
@@ -529,11 +536,13 @@
              try:
                  for w in wfs:
                      w.notifyException(ob, action, exc)
+                    notify(ActionRaisedExceptionEvent(ob, w, action, exc))
                  raise exc[0], exc[1], exc[2]
              finally:
                  exc = None
          for w in wfs:
              w.notifySuccess(ob, action, res)
+            notify(ActionSucceededEvent(ob, w, action, res))
          if reindex:
              self._reindexWorkflowVariables(ob)
          return res
Index: tests/test_WorkflowTool.py
===================================================================
--- tests/test_WorkflowTool.py	(revision 71665)
+++ tests/test_WorkflowTool.py	(working copy)
@@ -20,6 +20,10 @@

  from OFS.SimpleItem import SimpleItem

+from zope.component import adapter, provideHandler
+from Products.CMFCore.interfaces import IActionWillBeInvokedEvent
+from Products.CMFCore.interfaces import IActionRaisedExceptionEvent
+from Products.CMFCore.interfaces import IActionSucceededEvent

  class Dummy( SimpleItem ):

@@ -98,7 +102,18 @@
      def notifyException( self, ob, action, exc ):
          self.notified( 'exception' ).append( ( ob, action, exc ) )

+ at adapter(IActionWillBeInvokedEvent)
+def notifyBeforeHandler(evt):
+    evt.workflow.notified( 'before-evt' ).append( (evt.object, 
evt.action) )
+
+ at adapter(IActionSucceededEvent)
+def notifySuccessHandler(evt):
+    evt.workflow.notified( 'success-evt' ).append( (evt.object, 
evt.action, evt.result ) )

+ at adapter(IActionRaisedExceptionEvent)
+def notifyExceptionHandler(evt):
+    evt.workflow.notified( 'exception-evt' ).append( (evt.object, 
evt.action, evt.exc) )
+
  class DummyContent( Dummy ):

      meta_type = 'Dummy'
@@ -328,6 +343,8 @@

      def test_notifyBefore( self ):

+        provideHandler(notifyBeforeHandler)
+
          tool = self._makeWithTypesAndChain()

          ob = DummyContent( 'dummy' )
@@ -337,9 +354,15 @@
              notified = wf.notified( 'before' )
              self.assertEqual( len( notified ), 1 )
              self.assertEqual( notified[0], ( ob, 'action' ) )
+
+            notified = wf.notified( 'before-evt' )
+            self.assertEqual( len( notified ), 1 )
+            self.assertEqual( notified[0], ( ob, 'action' ) )

      def test_notifySuccess( self ):

+        provideHandler(notifySuccessHandler)
+
          tool = self._makeWithTypesAndChain()

          ob = DummyContent( 'dummy' )
@@ -349,9 +372,15 @@
              notified = wf.notified( 'success' )
              self.assertEqual( len( notified ), 1 )
              self.assertEqual( notified[0], ( ob, 'action', None ) )
+
+            notified = wf.notified( 'success-evt' )
+            self.assertEqual( len( notified ), 1 )
+            self.assertEqual( notified[0], ( ob, 'action', None ) )

      def test_notifyException( self ):

+        provideHandler(notifyExceptionHandler)
+
          tool = self._makeWithTypesAndChain()

          ob = DummyContent( 'dummy' )
@@ -361,6 +390,10 @@
              notified = wf.notified( 'exception' )
              self.assertEqual( len( notified ), 1 )
              self.assertEqual( notified[0], ( ob, 'action', 'exception' ) )
+
+            notified = wf.notified( 'exception-evt' )
+            self.assertEqual( len( notified ), 1 )
+            self.assertEqual( notified[0], ( ob, 'action', 'exception' ) )

      def xxx_test_updateRoleMappings( self ):
          """
Index: WorkflowCore.py
===================================================================
--- WorkflowCore.py	(revision 71665)
+++ WorkflowCore.py	(working copy)
@@ -15,12 +15,20 @@
  $Id$
  """

+from zope.interface import implements
+from zope.component.interfaces import ObjectEvent
+
+from Products.CMFCore.interfaces import IWorkflowActionEvent
+from Products.CMFCore.interfaces import IActionWillBeInvokedEvent
+from Products.CMFCore.interfaces import IActionRaisedExceptionEvent
+from Products.CMFCore.interfaces import IActionSucceededEvent
+
  class WorkflowException( Exception ):

      """ Exception while invoking workflow.
      """
+

-
  class ObjectDeleted( Exception ):

      """ Raise to tell the workflow tool that the object has been deleted.
@@ -49,3 +57,31 @@

      def getNewObject(self):
          return self._ob
+
+# Events
+
+class WorkflowActionEvent(ObjectEvent):
+    implements(IWorkflowActionEvent)
+
+    def __init__(self, object, workflow, action):
+        ObjectEvent.__init__(self, object)
+        self.workflow = workflow
+        self.action = action
+
+class ActionWillBeInvokedEvent(WorkflowActionEvent):
+    implements(IActionWillBeInvokedEvent)
+
+
+class ActionRaisedExceptionEvent(WorkflowActionEvent):
+    implements(IActionRaisedExceptionEvent)
+
+    def __init__(self, object, workflow, action, exc):
+        WorkflowActionEvent.__init__(self, object, workflow, action)
+        self.exc = exc
+
+class ActionSucceededEvent(WorkflowActionEvent):
+    implements(IActionSucceededEvent)
+
+    def __init__(self, object, workflow, action, result):
+        WorkflowActionEvent.__init__(self, object, workflow, action)
+        self.result = result
\ No newline at end of file



More information about the Zope-CMF mailing list