Skip to content

Commit 3ca0a57

Browse files
committed
add docs for new examples
1 parent 18a6350 commit 3ca0a57

6 files changed

+401
-95
lines changed

doc/bpmn/application.rst

+3-2
Original file line numberDiff line numberDiff line change
@@ -123,7 +123,7 @@ We initialize a scripting enviroment:
123123
.. code-block:: python
124124
125125
script_env = TaskDataEnvironment({'datetime': datetime })
126-
>script_engine = PythonScriptEngine(script_env)
126+
script_engine = PythonScriptEngine(script_env)
127127
128128
The :code:`PythonScriptEngine` handles execution of script tasks and evaluation of gateway and DMN conditions.
129129
We'll create the script engine based on it; execution and evaluation will occur in the context of this enviroment.
@@ -159,5 +159,6 @@ We then create our BPMN engine (:app:`engine/engine.py`) using each of these com
159159
.. code-block:: python
160160
161161
from ..engine import BpmnEngine
162-
engine = BpmnEngine(parser, serializer, handlers, script_env)
162+
engine = BpmnEngine(parser, serializer, script_env)
163163
164+
The handlers are automatically passed to the curses UI by the main runner.

doc/bpmn/custom_task_spec.rst

+44-44
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,27 @@ starts with a timer, the timer waits until the event occurs; this might be days
77
Of course, we can always check that it's waiting and serialize the workflow until that time. However, we might decide that
88
we don't want SpiffWorkflow to manage this at all. We could do this with a custom task spec.
99

10-
First we'll create a new class
10+
The code for this example can be found in :app:`misc/custom_start_event.py`.
11+
12+
There is a very simple diagram :bpmn:`timer_start.bpmn` with the process ID `timer_start` with a Start Event
13+
with a Duration Timer of one day that can be used to illustrate how the custom task works. If you run this workflow
14+
with any of the configurations provided, you'll see a `WAITING` Start Event; if you use the parser and serializer we
15+
just created, you'll be propmted to complete the User Task immediately.
16+
17+
To run this model with the custom spec:
18+
19+
.. code:: python
20+
21+
./runner.py -e spiff_example.misc.custom_start_event add -p timer_start -b bpmn/tutorial/timer_start.bpmn
22+
./runner.py -e spiff_example.misc.custom_start_event
23+
24+
First we'll create a new class.
25+
26+
.. note::
27+
28+
It might be better have the class's init method take both the event definition to use *and* the timer event
29+
definition. Unfortunately, our parser is not terribly intuitive or easily extendable, so I've done it this
30+
way to make this a little easier to follow.
1131

1232
.. code:: python
1333
@@ -27,7 +47,7 @@ First we'll create a new class
2747
super().__init__(wf_spec, bpmn_id, event_definition, **kwargs)
2848
self.timer_event = None
2949
30-
When we create our custom event, we'll check to see if we're creating a Start Event with a :code:`TimerEventDefinition`, and
50+
When we create our custom spec, we'll check to see if we're creating a Start Event with a :code:`TimerEventDefinition`, and
3151
if so, we'll replace it with a :code:`NoneEventDefinition`. There are three different types of Timer Events, so we'll use
3252
the base class for all three to make sure we account for TimeDate, Duration, and Cycle.
3353

@@ -47,57 +67,44 @@ Whenever we create a custom task spec, we'll need to create a converter for it s
4767
.. code:: python
4868
4969
from SpiffWorkflow.bpmn.serializer import BpmnWorkflowSerializer
50-
from SpiffWorkflow.bpmn.serializer.default import EventConverter
5170
from SpiffWorkflow.spiff.serializer.task_spec import SpiffBpmnTaskConverter
5271
from SpiffWorkflow.spiff.serializer import DEFAULT_CONFIG
5372
5473
class CustomStartEventConverter(SpiffBpmnTaskConverter):
5574
56-
def __init__(self, registry):
57-
super().__init__(CustomStartEvent, registry)
58-
5975
def to_dict(self, spec):
6076
dct = super().to_dict(spec)
61-
if spec.timer_event is not None:
62-
dct['event_definition'] = self.registry.convert(spec.timer_event)
63-
else:
64-
dct['event_definition'] = self.registry.convert(spec.event_definition)
77+
dct['event_definition'] = self.registry.convert(spec.event_definition)
78+
dct['timer_event'] = self.registry.convert(spec.timer_event)
6579
return dct
6680
67-
68-
DEFAULT_CONFIG['task_specs'].remove(StartEventConverter)
69-
DEFAULT_CONFIG['task_specs'].append(CustomStartEventConverter)
70-
registry = BpmnWorkflowSerializer.configure(DEFAULT_CONFIG)
71-
serializer = BpmnWorkflowSerializer(registry)
81+
def from_dict(self, dct):
82+
spec = super().from_dict(dct)
83+
spec.event_definition = self.registry.restore(dct['event_definition'])
84+
spec.timer_event = self.registry.restore(dct['timer_event'])
85+
return spec
7286
7387
Our converter will inherit from the :code:`SpiffBpmnTaskConverter`, since that's our base generic BPMN mixin class.
88+
The parent converter will handle serializing the standard BPMN attributes, as well as attributes added in the
89+
:code:`spiff` package. There is a similar base converter in the :code:`bpmn.serializer.helpers` package.
7490

75-
The :code:`SpiffBpmnTaskConverter` itself inherits from
76-
:code:`SpiffWorkflow.bpmn.serializer.helpers.task_spec.BpmnTaskSpecConverter`. which provides some helper methods for
77-
extracting standard attributes from tasks; the :code:`SpiffBpmnTaskConverter` does the same for extensions from the
78-
:code:`spiff` package.
79-
80-
We don't have to do much -- all we do is replace the event definition with the original. The timer event will be
81-
moved when the task is restored, and this saves us from having to write a custom parser.
82-
83-
.. note::
84-
85-
It might be better have the class's init method take both the event definition to use *and* the timer event
86-
definition. Unfortunately, our parser is not terribly intuitive or easily extendable, so I've done it this
87-
way to make this a little easier to follow.
91+
A converter needs to implement two methods: :code:`to_dict` (which takes a task spec and returns a JSON-serializable
92+
dictionary of its attributes) and :code:`from_dict` (which takes the dictionary and returns a task spec of the
93+
appropriate type. We call the base method to do most of the work, and then update the result to reflect the changes
94+
we made, in this case ensuring that both event definitions are handled. The parent converter also provides :code:`convert`
95+
and :code:`restore` methods to serialize any object that Spiff's serializer knows how to handle. For more details about
96+
the serializer, see :doc:`serialization`.
8897

89-
When we create our serializer, we need to tell it about this task. We'll remove the converter for the standard Start
90-
Event and add the one we created to the configuration. We then get a registry of classes that the serializer knows
91-
about that includes our custom spec, as well as all the other specs and initialize the serializer with it.
98+
When we create our serializer, we need to tell it about this task. The serializer is initialized with a mapping
99+
of object class to converter class, so we just need to add an entry for this mapping.
92100

93-
.. note::
101+
.. code:: python
94102
95-
The reason there are two steps involved (regurning a registry and *then* passing it to the serializer) rather
96-
that using the configuration directly is to allow further customization of the :code:`registry`. Workflows
97-
can contain arbtrary data, we want to provide developers the ability to serialization code for any object. See
98-
:ref:`serializing_custom_objects` for more information about how this works.
103+
SPIFF_CONFIG[CustomStartEvent] = CustomStartEventConverter
104+
registry = FileSerializer.configure(SPIFF_CONFIG)
105+
serializer = FileSerializer(dirname, registry=registry)
99106
100-
Finally, we have to update our parser:
107+
We also have to tell the parser to use our class instead of the standard class.
101108

102109
.. code:: python
103110
@@ -114,10 +121,3 @@ will use. This is a bit unintuitive, but that's how it works.
114121

115122
Fortunately, we were able to reuse an existing Task Spec parser, which simplifies the process quite a bit.
116123

117-
Having created a parser and serializer, we could create a configuration module and instantiate an engine with these
118-
components.
119-
120-
There is a very simple diagram :bpmn:`timer_start.bpmn` with the process ID `timer_start` with a Start Event
121-
with a Duration Timer of one day that can be used to illustrate how the custom task works. If you run this workflow
122-
with any of the configurations provided, you'll see a `WAITING` Start Event; if you use the parser and serializer we
123-
just created, you'll be propmted to complete the User Task immediately.

doc/bpmn/imports.rst

+1-1
Original file line numberDiff line numberDiff line change
@@ -124,7 +124,7 @@ Examples
124124
--------
125125

126126
- :doc:`serialization`
127-
- :doc:`custom_task_specs`
127+
- :doc:`custom_task_spec`
128128

129129
DMN
130130
===

0 commit comments

Comments
 (0)