[Checkins] SVN: hurry.workflow/trunk/ Merged r108441 from multiple-workflows branch
Vincent Fretin
vincent.fretin at gmail.com
Wed Jan 27 02:08:23 EST 2010
Log message for revision 108551:
Merged r108441 from multiple-workflows branch
Changed:
U hurry.workflow/trunk/CHANGES.txt
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 2010-01-27 06:27:32 UTC (rev 108550)
+++ hurry.workflow/trunk/CHANGES.txt 2010-01-27 07:08:22 UTC (rev 108551)
@@ -4,9 +4,13 @@
0.11 (unreleased)
=================
-- Nothing changed yet.
+* Do IAnnotations(self.context) only once in WorkflowState.
+* An IWorkflowVersions implementation is now optional.
+* Added multiple workflows support.
+
+
0.10 (2009-11-19)
=================
Modified: hurry.workflow/trunk/src/hurry/workflow/workflow.py
===================================================================
--- hurry.workflow/trunk/src/hurry/workflow/workflow.py 2010-01-27 06:27:32 UTC (rev 108550)
+++ hurry.workflow/trunk/src/hurry/workflow/workflow.py 2010-01-27 07:08:22 UTC (rev 108551)
@@ -92,50 +92,54 @@
class WorkflowState(object):
implements(IWorkflowState)
+ state_key = "hurry.workflow.state"
+ id_key = "hurry.workflow.id"
def __init__(self, context):
# XXX okay, I'm tired of it not being able to set annotations, so
# we'll do this. Ugh.
from zope.security.proxy import removeSecurityProxy
self.context = removeSecurityProxy(context)
+ self._annotations = IAnnotations(self.context)
def initialize(self):
- wf_versions = component.getUtility(IWorkflowVersions)
- self.setId(wf_versions.createVersionId())
+ wf_versions = component.queryUtility(IWorkflowVersions)
+ if wf_versions is not None:
+ self.setId(wf_versions.createVersionId())
def setState(self, state):
if state != self.getState():
- IAnnotations(self.context)[
- 'hurry.workflow.state'] = state
+ self._annotations[self.state_key] = state
def setId(self, id):
# XXX catalog should be informed (or should it?)
- IAnnotations(self.context)['hurry.workflow.id'] = id
+ self._annotations[self.id_key] = id
def getState(self):
- try:
- return IAnnotations(self.context)['hurry.workflow.state']
- except KeyError:
- return None
+ return self._annotations.get(self.state_key, None)
def getId(self):
- try:
- return IAnnotations(self.context)['hurry.workflow.id']
- except KeyError:
- return None
+ 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)
+
+ def state(self, obj):
+ return component.getAdapter(obj, IWorkflowState, name=self.name)
+
def fireTransition(self, transition_id, comment=None, side_effect=None,
check_security=True):
- state = IWorkflowState(self.context)
- wf = component.getUtility(IWorkflow)
+ state = self.state(self.context)
# this raises InvalidTransitionError if id is invalid for current state
- transition = wf.getTransition(state.getState(), transition_id)
+ transition = self.wf.getTransition(state.getState(), transition_id)
# check whether we may execute this workflow transition
try:
interaction = getInteraction()
@@ -158,10 +162,10 @@
result = transition.action(self, self.context)
if result is not None:
if transition.source is None:
- IWorkflowState(result).initialize()
+ self.state(result).initialize()
# stamp it with version
- state = IWorkflowState(result)
- state.setId(IWorkflowState(self.context).getId())
+ state = self.state(result)
+ state.setId(self.state(self.context).getId())
# execute any side effect:
if side_effect is not None:
side_effect(result)
@@ -171,7 +175,7 @@
transition, comment)
else:
if transition.source is None:
- IWorkflowState(self.context).initialize()
+ self.state(self.context).initialize()
# execute any side effect
if side_effect is not None:
side_effect(self.context)
@@ -200,12 +204,12 @@
comment, side_effect, check_security)
def fireTransitionForVersions(self, state, transition_id):
- id = IWorkflowState(self.context).getId()
+ id = self.state(self.context).getId()
wf_versions = component.getUtility(IWorkflowVersions)
for version in wf_versions.getVersions(state, id):
if version is self.context:
continue
- IWorkflowInfo(version).fireTransition(transition_id)
+ self.info(version).fireTransition(transition_id)
def fireAutomatic(self):
for transition_id in self.getAutomaticTransitionIds():
@@ -222,7 +226,7 @@
def hasVersion(self, state):
wf_versions = component.getUtility(IWorkflowVersions)
- id = IWorkflowState(self.context).getId()
+ id = self.state(self.context).getId()
return wf_versions.hasVersion(state, id)
def getManualTransitionIds(self):
@@ -245,10 +249,9 @@
return self.getManualTransitionIds() + self.getSystemTransitionIds()
def getFireableTransitionIdsToward(self, state):
- wf = component.getUtility(IWorkflow)
result = []
for transition_id in self.getFireableTransitionIds():
- transition = wf.getTransitionById(transition_id)
+ transition = self.wf.getTransitionById(transition_id)
if transition.destination == state:
result.append(transition_id)
return result
@@ -263,9 +266,8 @@
def _getTransitions(self, trigger):
# retrieve all possible transitions from workflow utility
- wf = component.getUtility(IWorkflow)
- transitions = wf.getTransitions(
- IWorkflowState(self.context).getState())
+ transitions = self.wf.getTransitions(
+ self.state(self.context).getState())
# now filter these transitions to retrieve all possible
# transitions in this context, and return their ids
return [transition for transition in transitions if
Modified: hurry.workflow/trunk/src/hurry/workflow/workflow.txt
===================================================================
--- hurry.workflow/trunk/src/hurry/workflow/workflow.txt 2010-01-27 06:27:32 UTC (rev 108550)
+++ hurry.workflow/trunk/src/hurry/workflow/workflow.txt 2010-01-27 07:08:22 UTC (rev 108551)
@@ -189,6 +189,85 @@
'b'
>>> events[-1].destination is None
True
+
+
+Multiple workflows
+------------------
+
+We have previously registered a workflow as a unnamed utility.
+You can also register a workflow as a named utility to provide
+several workflows for a site.
+
+Let's create a, invoice document::
+
+ >>> class IInvoiceDocument(IDocument):
+ ... title = Attribute('Title')
+
+ >>> class InvoiceDocument(object):
+ ... implements(IInvoiceDocument)
+ ... def __init__(self, title, amount):
+ ... self.title = title
+ ... self.amount = amount
+
+We define our workflow::
+
+ >>> invoice_init = workflow.Transition(
+ ... transition_id='init_invoice',
+ ... title='Invoice Received',
+ ... source=None,
+ ... destination='received')
+ >>>
+ >>> invoice_paid = workflow.Transition(
+ ... transition_id='invoice_paid',
+ ... title='Invoice Paid',
+ ... source='received',
+ ... destination='paid')
+
+ >>> invoice_wf = workflow.Workflow( [ invoice_init, invoice_paid ] )
+
+We register a new workflow utility, WorkflowState and WorkflowInfo adapters, all
+named "invoice"::
+
+ >>> from hurry.workflow import workflow
+ >>> from zope.annotation import interfaces as annotation_interfaces
+ >>> component.provideUtility(invoice_wf, interfaces.IWorkflow, name="invoice")
+ >>> class InvoiceWorkflowInfo(workflow.WorkflowInfo):
+ ... name="invoice"
+ >>> component.provideAdapter(
+ ... InvoiceWorkflowInfo,
+ ... (annotation_interfaces.IAnnotatable,),
+ ... interfaces.IWorkflowInfo,
+ ... name="invoice")
+ >>> class InvoiceWorkflowState(workflow.WorkflowState):
+ ... state_key = "invoice.state"
+ ... id_key = "invoice.id"
+ >>> component.provideAdapter(
+ ... InvoiceWorkflowState,
+ ... (annotation_interfaces.IAnnotatable,),
+ ... interfaces.IWorkflowState,
+ ... name="invoice")
+
+Now we can utilize the workflow::
+
+ >>> invoice = InvoiceDocument('abc', 22)
+
+ >>> info = component.getAdapter(invoice, interfaces.IWorkflowInfo, name="invoice")
+ >>> info.fireTransition('init_invoice')
+ >>> state = component.getAdapter(invoice, interfaces.IWorkflowState, name="invoice")
+ >>> state.getState()
+ 'received'
+ >>> info.fireTransition('invoice_paid')
+ >>> state.getState()
+ 'paid'
+
+Of course, this document always have the default unnamed workflow::
+
+ >>> info = interfaces.IWorkflowInfo(invoice)
+ >>> info.fireTransition('to_a')
+ >>> state = interfaces.IWorkflowState(invoice)
+ >>> state.getState()
+ 'a'
+
Multi-version workflow
----------------------
More information about the checkins
mailing list