[Checkins] SVN: hurry.workflow/trunk/ turn WorkflowInfo.info() and WorkflowInfo.state() functions into classmethods as they are not of much use otherwise
Jan-Wijbrand Kolman
janwijbrand at gmail.com
Mon May 2 09:25:50 EDT 2011
Log message for revision 121510:
turn WorkflowInfo.info() and WorkflowInfo.state() functions into classmethods as they are not of much use otherwise
Changed:
U hurry.workflow/trunk/CHANGES.txt
U hurry.workflow/trunk/buildout.cfg
U hurry.workflow/trunk/src/hurry/workflow/workflow.py
U hurry.workflow/trunk/src/hurry/workflow/workflow.txt
-=-
Modified: hurry.workflow/trunk/CHANGES.txt
===================================================================
--- hurry.workflow/trunk/CHANGES.txt 2011-05-02 12:12:50 UTC (rev 121509)
+++ hurry.workflow/trunk/CHANGES.txt 2011-05-02 13:25:50 UTC (rev 121510)
@@ -1,12 +1,13 @@
+======================
hurry.workflow changes
-**********************
+======================
0.12 (unreleased)
=================
-- Nothing changed yet.
+- Make the info() and state() functions on the WorkflowInfo class into
+ classmethods as they are not of much use otherwise.
-
0.11 (2010-04-16)
=================
@@ -44,7 +45,7 @@
Bug fixes
---------
-* zope.security changes broke imports in hurry.workflow.
+* zope.security changes broke imports in hurry.workflow.
* localUtility directive is now deprecated, so don't use it anymore.
Modified: hurry.workflow/trunk/buildout.cfg
===================================================================
--- hurry.workflow/trunk/buildout.cfg 2011-05-02 12:12:50 UTC (rev 121509)
+++ hurry.workflow/trunk/buildout.cfg 2011-05-02 13:25:50 UTC (rev 121510)
@@ -1,9 +1,9 @@
[buildout]
-develop = .
+develop = .
parts = test
newest = false
[test]
recipe = zc.recipe.testrunner
eggs = hurry.workflow [test]
-defaults = ['--tests-pattern', '^f?tests$', '-v']
+defaults = ['--tests-pattern', '^f?tests$', '-v', '--auto-color']
Modified: hurry.workflow/trunk/src/hurry/workflow/workflow.py
===================================================================
--- hurry.workflow/trunk/src/hurry/workflow/workflow.py 2011-05-02 12:12:50 UTC (rev 121509)
+++ hurry.workflow/trunk/src/hurry/workflow/workflow.py 2011-05-02 13:25:50 UTC (rev 121510)
@@ -48,7 +48,7 @@
self.permission = permission
self.order = order
self.user_data = user_data
-
+
def __cmp__(self, other):
return cmp(self.order, other.order)
@@ -59,7 +59,7 @@
# mixes these in if you need persistent workflow
class Workflow(object):
implements(IWorkflow)
-
+
def __init__(self, transitions):
self.refresh(transitions)
@@ -74,13 +74,13 @@
for transition in transitions:
self._register(transition)
self._p_changed = True
-
+
def getTransitions(self, source):
try:
return self._sources[source].values()
except KeyError:
return []
-
+
def getTransition(self, source, transition_id):
transition = self._id_transitions[transition_id]
if transition.source != source:
@@ -106,34 +106,36 @@
wf_versions = component.queryUtility(IWorkflowVersions)
if wf_versions is not None:
self.setId(wf_versions.createVersionId())
-
+
def setState(self, state):
if state != self.getState():
self._annotations[self.state_key] = state
-
+
def setId(self, id):
# XXX catalog should be informed (or should it?)
self._annotations[self.id_key] = id
-
+
def getState(self):
return self._annotations.get(self.state_key, None)
def getId(self):
return self._annotations.get(self.id_key, None)
-
+
class WorkflowInfo(object):
implements(IWorkflowInfo)
name = u''
-
+
def __init__(self, context):
self.context = context
self.wf = component.getUtility(IWorkflow, name=self.name)
- def info(self, obj):
- return component.getAdapter(obj, IWorkflowInfo, name=self.name)
+ @classmethod
+ def info(cls, obj):
+ return component.getAdapter(obj, IWorkflowInfo, name=cls.name)
- def state(self, obj):
- return component.getAdapter(obj, IWorkflowState, name=self.name)
+ @classmethod
+ def state(cls, obj):
+ return component.getAdapter(obj, IWorkflowState, name=cls.name)
def fireTransition(self, transition_id, comment=None, side_effect=None,
check_security=True):
@@ -153,7 +155,7 @@
if not checkPermission(
transition.permission, self.context):
raise Unauthorized(self.context,
- 'transition: %s' % transition_id,
+ 'transition: %s' % transition_id,
transition.permission)
# now make sure transition can still work in this context
if not transition.condition(self, self.context):
@@ -202,7 +204,7 @@
raise interfaces.AmbiguousTransitionError
return self.fireTransition(transition_ids[0],
comment, side_effect, check_security)
-
+
def fireTransitionForVersions(self, state, transition_id):
id = self.state(self.context).getId()
wf_versions = component.getUtility(IWorkflowVersions)
@@ -223,12 +225,12 @@
# if we actually managed to fire a transition,
# we're done with this one now.
return
-
+
def hasVersion(self, state):
wf_versions = component.getUtility(IWorkflowVersions)
id = self.state(self.context).getId()
return wf_versions.hasVersion(state, id)
-
+
def getManualTransitionIds(self):
try:
checkPermission = getInteraction().checkPermission
@@ -247,7 +249,7 @@
def getFireableTransitionIds(self):
return self.getManualTransitionIds() + self.getSystemTransitionIds()
-
+
def getFireableTransitionIdsToward(self, state):
result = []
for transition_id in self.getFireableTransitionIds():
@@ -255,7 +257,7 @@
if transition.destination == state:
result.append(transition_id)
return result
-
+
def getAutomaticTransitionIds(self):
return [transition.transition_id for transition in
self._getTransitions(AUTOMATIC)]
@@ -272,7 +274,7 @@
# transitions in this context, and return their ids
return [transition for transition in transitions if
transition.trigger == trigger]
-
+
class WorkflowVersions(object):
implements(IWorkflowVersions)
Modified: hurry.workflow/trunk/src/hurry/workflow/workflow.txt
===================================================================
--- hurry.workflow/trunk/src/hurry/workflow/workflow.txt 2011-05-02 12:12:50 UTC (rev 121509)
+++ hurry.workflow/trunk/src/hurry/workflow/workflow.txt 2011-05-02 13:25:50 UTC (rev 121510)
@@ -10,12 +10,12 @@
Let's first make a content object that can go into a workflow::
>>> from zope.interface import implements, Attribute
-
+
>>> from zope.annotation.interfaces import IAttributeAnnotatable
>>> class IDocument(IAttributeAnnotatable):
... title = Attribute('Title')
>>> class Document(object):
- ... implements(IDocument)
+ ... implements(IDocument)
... def __init__(self, title):
... self.title = title
@@ -38,9 +38,9 @@
But let's set it back to None again, so we can start again in a
pristine state for this document::
-
+
>>> state.setState(None)
-
+
It's not recommended use setState() do this ourselves, though: usually
we'll let the workflow system take care of state transitions and the
setting of the initial state.
@@ -59,14 +59,14 @@
Now let's construct a transition::
- >>> from hurry.workflow import workflow
- >>> transition = workflow.Transition(
- ... transition_id='a_to_b',
- ... title='A to B',
- ... source='a',
- ... destination='b',
- ... condition=NullCondition,
- ... action=NullAction,
+ >>> from hurry.workflow import workflow
+ >>> transition = workflow.Transition(
+ ... transition_id='a_to_b',
+ ... title='A to B',
+ ... source='a',
+ ... destination='b',
+ ... condition=NullCondition,
+ ... action=NullAction,
... trigger=interfaces.MANUAL)
The transition trigger is either MANUAL, AUTOMATIC or SYSTEM. MANUAL
@@ -91,7 +91,7 @@
... title='Delete',
... source='b',
... destination=None)
-
+
Now let's put the transitions in an workflow utility::
>>> wf = workflow.Workflow([transition, init_transition, final_transition])
@@ -260,6 +260,21 @@
>>> state.getState()
'paid'
+To make it easier to get the state and info adapters for a particular context
+object, there are two convenience functions on the workflow info object. The
+info object "knows" what workflow utility to look for, as they are associated
+by name::
+
+ >>> info_ = InvoiceWorkflowInfo.info(invoice)
+ >>> interfaces.IWorkflowInfo.providedBy(info_)
+ True
+
+ >>> state_ = InvoiceWorkflowInfo.state(invoice)
+ >>> interfaces.IWorkflowState.providedBy(state_)
+ True
+ >>> state.getState() is state_.getState()
+ True
+
Of course, this document always have the default unnamed workflow::
>>> info = interfaces.IWorkflowInfo(invoice)
@@ -268,7 +283,6 @@
>>> state.getState()
'a'
-
Multi-version workflow
----------------------
@@ -358,9 +372,9 @@
from the CLOSED version::
>>> def CanCopyCondition(wf, context):
- ... return (not wf.hasVersion(UNPUBLISHED) and
+ ... return (not wf.hasVersion(UNPUBLISHED) and
... not wf.hasVersion(PUBLISHED))
-
+
>>> copy_closed_transition = workflow.Transition(
... transition_id='copy_closed',
... title='Copy',
@@ -385,7 +399,7 @@
Now let's build and provide the workflow utility::
- >>> wf = workflow.Workflow([init_transition,
+ >>> wf = workflow.Workflow([init_transition,
... publish_transition, close_transition,
... copy_transition, copy_closed_transition,
... archive_transition])
@@ -499,9 +513,9 @@
>>> interfaces.IWorkflowState(document3).getState()
'published'
-
+
And the previously published version is now closed::
-
+
>>> interfaces.IWorkflowState(document2).getState()
'closed'
@@ -576,7 +590,7 @@
>>> workflow_versions.fireAutomatic()
Nothing should have happened as we are still at time moment 0::
-
+
>>> state = interfaces.IWorkflowState(document)
>>> state.getState()
'unpublished'
@@ -590,7 +604,7 @@
>>> workflow_versions.fireAutomatic()
The transition has fired, so the state will be 'published'::
-
+
>>> state.getState()
'published'
@@ -696,8 +710,8 @@
Now set up the workflow using these transitions, plus our
init_transition::
- >>> wf = workflow.Workflow([init_transition,
- ... publish_1_transition, publish_2_transition,
+ >>> wf = workflow.Workflow([init_transition,
+ ... publish_1_transition, publish_2_transition,
... publish_auto_transition])
>>> component.provideUtility(wf, interfaces.IWorkflow)
@@ -746,12 +760,12 @@
Let's set up the security context::
- >>> from zope.security.interfaces import Unauthorized
+ >>> from zope.security.interfaces import Unauthorized
>>> from zope.security.management import newInteraction, endInteraction
>>> class Principal:
... def __init__(self, id):
... self.id = id
- ... self.groups = []
+ ... self.groups = []
>>> class Participation:
... interaction = None
... def __init__(self, principal):
@@ -775,8 +789,8 @@
The system user is however allowed to do it::
- >>> from zope.security.management import system_user
- >>> endInteraction()
+ >>> from zope.security.management import system_user
+ >>> endInteraction()
>>> newInteraction(Participation(system_user))
>>> info.fireTransition('publish')
@@ -804,7 +818,7 @@
however, it would get information about the new copy *before* the
editing took place. To allow an editing to take place between the
creation of the new copy and the firing of the event, a side effect
-function can be passed along when a transition is fired.
+function can be passed along when a transition is fired.
The sequence of execution then is:
@@ -843,9 +857,9 @@
Now fire the transition, with a side effect::
>>> new_version = info.fireTransition('foo', side_effect=side_effect)
-
+
The title of the new version should now have a ! at the end::
-
+
>>> new_version.title[-1] == '!'
True
More information about the checkins
mailing list