From 004834bd3e3b0e3aadd6ea98c3c587817877e426 Mon Sep 17 00:00:00 2001 From: Jim Fulton Date: Wed, 23 Feb 2005 23:09:04 +0000 Subject: [PATCH] Fixed a bug in handling multiple process-input parameters. Created some interfaces for some of the events. Need to do more later. --- interfaces.py | 69 +++++++++++++++++++++++++++++++++------------------ process.py | 57 +++++++++++++++++++++--------------------- tests.py | 64 +++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 137 insertions(+), 53 deletions(-) diff --git a/interfaces.py b/interfaces.py index dba65e8..46ee5ed 100644 --- a/interfaces.py +++ b/interfaces.py @@ -16,13 +16,13 @@ $Id$ """ -import zope.interface +from zope import interface -class IProcessDefinition(zope.interface.Interface): +class IProcessDefinition(interface.Interface): """Process definition """ - id = zope.interface.Attribute("Process-definition identifier") + id = interface.Attribute("Process-definition identifier") def defineActivities(**activities): """Add activity definitions to the collection of defined activities @@ -66,11 +66,11 @@ def defineParameters(*parameters): """ -class IActivityDefinition(zope.interface.Interface): +class IActivityDefinition(interface.Interface): """Activity definition """ - id = zope.interface.Attribute("Activity identifier") + id = interface.Attribute("Activity identifier") def addApplication(id, *parameters): """Declare that the activity uses the identified activity @@ -102,17 +102,17 @@ def setAndJoin(setting): If the setting is true, then the activity will use an "and" join. """ -class ITransitionDefinition(zope.interface.Interface): +class ITransitionDefinition(interface.Interface): """Activity definition """ -class IProcess(zope.interface.Interface): +class IProcess(interface.Interface): """Process instance """ - definition = zope.interface.Attribute("Process definition") + definition = interface.Attribute("Process definition") - workflowRelevantData = zope.interface.Attribute( + workflowRelevantData = interface.Attribute( """Workflow-relevant data Object with attributes containing data used in conditions and @@ -120,7 +120,7 @@ class IProcess(zope.interface.Interface): """ ) - applicationRelevantData = zope.interface.Attribute( + applicationRelevantData = interface.Attribute( """Application-relevant data Object with attributes containing data used to pass data as @@ -129,7 +129,7 @@ class IProcess(zope.interface.Interface): """ ) -class IProcessContext(zope.interface.Interface): +class IProcessContext(interface.Interface): """Object that can recieve process results. """ @@ -137,53 +137,53 @@ def processFinished(process, *results): """Recieve notification of process completion, with results """ -class IActivity(zope.interface.Interface): +class IActivity(interface.Interface): """Activity instance """ - id = zope.interface.Attribute( + id = interface.Attribute( """Activity identifier This identifier is set by the process instance """) - definition = zope.interface.Attribute("Activity definition") + definition = interface.Attribute("Activity definition") def workItemFinished(work_item, *results): """Notify the activity that the work item has been completed. """ -class IApplicationDefinition(zope.interface.Interface): +class IApplicationDefinition(interface.Interface): """Application definition """ - parameters = zope.interface.Attribute( + parameters = interface.Attribute( "A sequence of parameter definitions") -class IParameterDefinition(zope.interface.Interface): +class IParameterDefinition(interface.Interface): """Parameter definition """ - name = zope.interface.Attribute("Parameter name") + name = interface.Attribute("Parameter name") - input = zope.interface.Attribute("Is this an input parameter?") + input = interface.Attribute("Is this an input parameter?") - output = zope.interface.Attribute("Is this an output parameter?") + output = interface.Attribute("Is this an output parameter?") -class IParticipantDefinition(zope.interface.Interface): +class IParticipantDefinition(interface.Interface): """Participant definition """ -class IParticipant(zope.interface.Interface): +class IParticipant(interface.Interface): """Workflow participant """ -class IWorkItem(zope.interface.Interface): +class IWorkItem(interface.Interface): """Work items """ - id = zope.interface.Attribute( + id = interface.Attribute( """Item identifier This identifier is set by the activity instance @@ -193,3 +193,24 @@ class IWorkItem(zope.interface.Interface): def start(*arguments): """Start the work """ + + +class InvalidProcessDefinition(Exception): + """A process definition isn't valid in some way. + """ + +class ProcessError(Exception): + """An error occured in execution of a process + """ + +class IProcessStarted(interface.Interface): + """A process has begun executing + """ + + process = interface.Attribute("The process") + +class IProcessFinished(interface.Interface): + """A process has finished executing + """ + + process = interface.Attribute("The process") diff --git a/process.py b/process.py index d11fcd6..b06e608 100644 --- a/process.py +++ b/process.py @@ -19,24 +19,18 @@ import sets import persistent + import zope.cachedescriptors.property -import zope.component -import zope.event -import zope.interface -from zope.wfmc import interfaces +from zope import component, interface -class InvalidProcessDefinition(Exception): - """A process definition isn't valid in some way. - """ +import zope.event -class ProcessError(Exception): - """An error occured in execution of a process - """ +from zope.wfmc import interfaces class ProcessDefinition: - zope.interface.implements(interfaces.IProcessDefinition) + interface.implements(interfaces.IProcessDefinition) def __init__(self, id): self.id = id @@ -97,16 +91,19 @@ def _start(self): if not activity.incoming: start += ((aid, activity), ) if not activity.outgoing: - raise InvalidProcessDefinition( + raise interfaces.InvalidProcessDefinition( "Activity %s has no transitions", aid) if len(start) != 1: if start: - raise InvalidProcessDefinition("Multiple start activities", - [id for (id, a) in start]) + raise interfaces.InvalidProcessDefinition( + "Multiple start activities", + [id for (id, a) in start] + ) else: - raise InvalidProcessDefinition("No start activities") + raise interfaces.InvalidProcessDefinition( + "No start activities") return TransitionDefinition(None, start[0][0]) @@ -123,7 +120,7 @@ def _dirty(self): class ActivityDefinition: - zope.interface.implements(interfaces.IActivityDefinition) + interface.implements(interfaces.IActivityDefinition) performer = '' process = None @@ -152,7 +149,7 @@ def definePerformer(self, performer): class TransitionDefinition: - zope.interface.implements(interfaces.ITransitionDefinition) + interface.implements(interfaces.ITransitionDefinition) def __init__(self, from_, to, condition=lambda data: True): self.from_ = from_ @@ -162,7 +159,7 @@ def __init__(self, from_, to, condition=lambda data: True): class Process(persistent.Persistent): - zope.interface.implements(interfaces.IProcess) + interface.implements(interfaces.IProcess) def __init__(self, definition, start, context=None): self.process_definition_identifier = definition.id @@ -174,7 +171,7 @@ def __init__(self, definition, start, context=None): self.applicationRelevantData = WorkflowData() def definition(self): - return zope.component.getUtility( + return component.getUtility( interfaces.IProcessDefinition, self.process_definition_identifier, ) @@ -189,7 +186,7 @@ def start(self, *arguments): args = arguments for parameter in definition.parameters: if parameter.input: - arg, args = arguments[0], args[1:] + arg, args = args[0], args[1:] setattr(data, parameter.__name__, arg) if args: raise TypeError("Too many arguments. Expected %s. got %s", @@ -250,6 +247,7 @@ class WorkflowData(persistent.Persistent): """ class ProcessStarted: + interface.implements(interfaces.IProcessStarted) def __init__(self, process): self.process = process @@ -258,6 +256,7 @@ def __repr__(self): return "ProcessStarted(%r)" % self.process class ProcessFinished: + interface.implements(interfaces.IProcessFinished) def __init__(self, process): self.process = process @@ -268,7 +267,7 @@ def __repr__(self): class Activity(persistent.Persistent): - zope.interface.implements(interfaces.IActivity) + interface.implements(interfaces.IActivity) def __init__(self, process, definition): self.process = process @@ -277,23 +276,23 @@ def __init__(self, process, definition): workitems = {} if definition.applications: - performer = zope.component.queryAdapter( + performer = component.queryAdapter( self, interfaces.IParticipant, process.process_definition_identifier + '.' + definition.performer) if performer is None: - performer = zope.component.getAdapter( + performer = component.getAdapter( self, interfaces.IParticipant, '.' + definition.performer) i = 0 for application, formal, actual in definition.applications: - workitem = zope.component.queryAdapter( + workitem = component.queryAdapter( performer, interfaces.IWorkItem, process.process_definition_identifier + '.' + application) if workitem is None: - workitem = zope.component.getAdapter( + workitem = component.getAdapter( performer, interfaces.IWorkItem, '.' + application) i += 1 @@ -315,7 +314,7 @@ def start(self, transition): if definition.andJoinSetting: if transition in self.incoming: - raise ProcessError( + raise interfaces.ProcessError( "Repeated incoming transition while waiting for and " "completion") self.incoming += (transition, ) @@ -414,7 +413,7 @@ def __repr__(self): class Parameter: - zope.interface.implements(interfaces.IParameterDefinition) + interface.implements(interfaces.IParameterDefinition) input = output = False @@ -435,7 +434,7 @@ class InputOutputParameter(InputParameter, OutputParameter): class Application: - zope.interface.implements(interfaces.IApplicationDefinition) + interface.implements(interfaces.IApplicationDefinition) def __init__(self, *parameters): self.parameters = parameters @@ -445,7 +444,7 @@ def defineParameters(self, *parameters): class Participant: - zope.interface.implements(interfaces.IParticipantDefinition) + interface.implements(interfaces.IParticipantDefinition) def __init__(self, name=None): self.__name__ = name diff --git a/tests.py b/tests.py index 0b5eecd..2ecdf49 100644 --- a/tests.py +++ b/tests.py @@ -28,6 +28,68 @@ def setUp(test): test.globs['this_directory'] = os.path.dirname(__file__) testing.setUp(test) +def test_multiple_input_parameters(): + """ + We'll create a very simple process that inputs two variables and + has a single activity that just outputs them. + + >>> from zope.wfmc import process + >>> pd = process.ProcessDefinition('sample') + >>> from zope import component, interface + >>> component.provideUtility(pd, name=pd.id) + + >>> pd.defineParameters( + ... process.InputParameter('x'), + ... process.InputParameter('y'), + ... ) + + >>> pd.defineActivities( + ... eek = process.ActivityDefinition(), + ... ook = process.ActivityDefinition(), + ... ) + + >>> pd.defineTransitions(process.TransitionDefinition('eek', 'ook')) + + >>> pd.defineApplications( + ... eek = process.Application( + ... process.InputParameter('x'), + ... process.InputParameter('y'), + ... ) + ... ) + + >>> pd.activities['eek'].addApplication('eek', ['x', 'y']) + + >>> from zope.wfmc import interfaces + + >>> class Participant(object): + ... zope.component.adapts(interfaces.IActivity) + ... zope.interface.implements(interfaces.IParticipant) + ... + ... def __init__(self, activity): + ... self.activity = activity + + >>> component.provideAdapter(Participant, name=".") + + >>> class Eek: + ... component.adapts(interfaces.IParticipant) + ... interface.implements(interfaces.IWorkItem) + ... + ... def __init__(self, participant): + ... self.participant = participant + ... + ... def start(self, x, y): + ... print x, y + + >>> component.provideAdapter(Eek, name='.eek') + + >>> proc = pd() + >>> proc.start(99, 42) + 99 42 + + + """ + + def test_suite(): from zope.testing import doctest suite = unittest.TestSuite() @@ -37,6 +99,8 @@ def test_suite(): suite.addTest(doctest.DocFileSuite( 'xpdl.txt', tearDown=tearDown, setUp=setUp, optionflags=doctest.NORMALIZE_WHITESPACE)) + suite.addTest(doctest.DocTestSuite(tearDown=testing.tearDown, + setUp=testing.setUp)) return suite if __name__ == '__main__':