Skip to content

Commit e284dd8

Browse files
committed
corrections and tweaks to documentation
1 parent 4b2e626 commit e284dd8

16 files changed

Lines changed: 184 additions & 158 deletions

doc/bpmn/advanced.rst

Lines changed: 55 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,13 @@ A More In-Depth Look at Some of SpiffWorkflow's Features
44
BPMN Task Specs
55
---------------
66

7-
BPMN Tasks inherit quite a few attributes from `SpiffWorkflow.specs.base.TaskSpec`, but only a few are used.
7+
BPMN Tasks inherit quite a few attributes from :code:`SpiffWorkflow.specs.base.TaskSpec`, but only a few are used.
88

9-
* `name`: the unique id of the task spec, and it will correspond to the BPMN ID if that is present
9+
* `name`: the unique id of the TaskSpec, and it will correspond to the BPMN ID if that is present
1010
* `description`: we use this attribute to provide a description of the BPMN type (the text that appears here can be overridden in the parser)
11-
* `inputs`: a list of task spec `names` that are parents of this task spec
12-
* `outputs`: a list of task spec `names` that are children of this task spec
13-
* `manual`: :code:`True` if human input is required to complete tasks associated with this spec
11+
* `inputs`: a list of TaskSpec `names` that are parents of this TaskSpec
12+
* `outputs`: a list of TaskSpec `names` that are children of this TaskSpec
13+
* `manual`: :code:`True` if human input is required to complete tasks associated with this TaskSpec
1414

1515
BPMN Tasks have the following additional attributes.
1616

@@ -20,12 +20,12 @@ BPMN Tasks have the following additional attributes.
2020
* `documentation`: the contents of the BPMN `documentation` element for the Task
2121
* `data_input_associations`: a list of incoming data object references
2222
* `data_output_associtions`: a list of outgoing data object references
23-
* `io_specification`: the BPMN IO Specification of the Task
23+
* `io_specification`: the BPMN IO specification of the Task
2424

2525
Filtering Tasks
2626
---------------
2727

28-
Tasks by lane
28+
Tasks by Lane
2929
^^^^^^^^^^^^^
3030

3131
The :code:`workflow.get_ready_user_tasks` method optionally takes the argument `lane`, which can be used to
@@ -44,13 +44,14 @@ To retrieve a list of tasks associated with a particular task spec, use :code:`w
4444

4545
.. code:: python
4646
47-
tasks = workflow.get_tasks_from_spec_name('customize_prodcut')
47+
tasks = workflow.get_tasks_from_spec_name('customize_product')
4848
4949
will return a list containing the Call Actitivities for the customization of a product in our example workflow.
5050

5151
.. note::
5252

53-
The `name` paramter here refers to the task spec name, not the BPMN name
53+
The `name` paramter here refers to the task spec name, not the BPMN name (for visible tasks, this will
54+
be the same as the `bpmn_id`)
5455

5556
Tasks by State
5657
^^^^^^^^^^^^^^
@@ -70,7 +71,7 @@ Tasks in a Subprocess or Call Activity
7071
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
7172

7273
The :code:`BpmnWorkflow` class maintains a dictionary of subprocesses (the key is the `id` of the Call Activity or
73-
Subprocess task). :code:`workflow.get_tasks` will start at the top level workflow and recurse through the subprocesses
74+
Subprocess Task). :code:`workflow.get_tasks` will start at the top level workflow and recurse through the subprocesses
7475
to create a list of all tasks. It is also possible to start from a particular subprocess:
7576

7677
.. code:: python
@@ -83,7 +84,7 @@ will limit the list of returned tasks to only those in the first product customi
8384

8485
.. note::
8586

86-
Each :code:`Task` object has a reference to its workflow; so with a task inside a subprocess, we can call
87+
Each :code:`Task` object has a reference to its workflow; so with a Task inside a subprocess, we can call
8788
:code:`workflow.get_tasks(workflow=task.workflow)` to start from our current workflow.
8889

8990
Logging
@@ -104,19 +105,22 @@ we define a custom log level
104105

105106
.. code:: python
106107
107-
logging.addLevelName(15, 'DATA_LOG')
108+
logging.addLevelName(15, 'DATA')
108109
109110
so that we can see the task data in the logs without fully enabling debugging.
110111

111112
The workflow runners take an `-l` argument that can be used to specify the logging level used when running the example workflows.
112113

113114
We'll write the logs to a file called `data.log` instead of the console to avoid printing very long messages during the workflow.
114115

116+
Our logging configuration code can be found in `runner/shared.py`. Most of the code is about logging
117+
configuration in Python rather than anything specific to SpiffWorkflow, so we won't go over it in depth.
118+
115119
Parsing
116120
-------
117121

118122
Each of the BPMN pacakges (:code:`bpmn`, :code:`spiff`, or :code:`camunda`) has a parser that is preconfigured with
119-
the specs in that package (if a particular task spec is not implemented in the package, :code:`bpmn` task is used).
123+
the specs in that package (if a particular TaskSpec is not implemented in the package, :code:`bpmn` TaskSpec is used).
120124

121125
See the example in :doc:`synthesis` for the basics of creating a parser. The parser can optionally be initialized with
122126

@@ -126,27 +130,27 @@ See the example in :doc:`synthesis` for the basics of creating a parser. The pa
126130
:code:`SpiffWorkflow.bpmn.parser.spec_descriptions`. These values will be added to the Task Spec in the `description` attribute
127131
and are intended as a user-friendly description of what the task is.
128132

129-
The :code:`BpmnValidator` can be used independently of the parser as well; call :code:`validate` with an :code:`lxml`
130-
parsed tree.
133+
The :code:`BpmnValidator` can be used and extended independently of the parser as well; call :code:`validate` with
134+
an :code:`lxml` parsed tree.
131135

132136
Loading BPMN Files
133137
^^^^^^^^^^^^^^^^^^
134138

135-
In addition to `load_bpmn_file`, there are similar functions `load_bpmn_str` which can load the XML from a string, and
136-
`load_bpmn_io`, which can load XML from any object implementing the IO interface, and `add_bpmn_xml`, which can load
139+
In addition to :code:`load_bpmn_file`, there are similar functions :code:`load_bpmn_str` which can load the XML from a string, and
140+
:code:`load_bpmn_io`, which can load XML from any object implementing the IO interface, and :code:`add_bpmn_xml`, which can load
137141
BPMN specs from an :code:`lxml` parsed tree.
138142

139143
Dependencies
140144
^^^^^^^^^^^^
141145

142146
The following methods are available for discovering the names of processes and DMN files that may be defined externally:
143147

144-
- `get_subprocess_specs`: Returns a mapping of name -> :code:`BpmnWorkflowSpec` for any Call Activities referenced by the
148+
- :code:`get_subprocess_specs`: Returns a mapping of name -> :code:`BpmnWorkflowSpec` for any Call Activities referenced by the
145149
provided spec (searches recursively)
146-
- `find_all_spec`: Returns a mapping of name -> :code:`BpmnWorkflowSpec` for all processes used in all files that have been
150+
- :code:`find_all_spec`: Returns a mapping of name -> :code:`BpmnWorkflowSpec` for all processes used in all files that have been
147151
provided to the parser at that point.
148-
- `get_process_dependences`: Returns a list of process IDs referenced by the provided process ID
149-
- `get_dmn_dependencies`: Returns a list of DMN IDs referenced byt he provided process ID
152+
- :code:`get_process_dependences`: Returns a list of process IDs referenced by the provided process ID
153+
- :code:`get_dmn_dependencies`: Returns a list of DMN IDs referenced byt he provided process ID
150154

151155

152156
Serialization
@@ -157,7 +161,7 @@ The :code:`BpmnWorkflowSerializer` has two components
157161
* the `workflow_spec_converter` (which handles serialization of objects that SpiffWorkflow knows about)
158162
* the `data_converter` (which handles serialization of custom objects)
159163

160-
Unless you have overriden any of the task specs with custom specs, you should be able to use the serializer
164+
Unless you have overriden any of TaskSpecs with custom specs, you should be able to use the serializer
161165
configuration from the package you are importing the parser from (:code:`bpmn`, :code:`spiff`, or :code:`camunda`).
162166
See :doc:`synthesis` for an example.
163167

@@ -167,12 +171,12 @@ Serializing Custom Objects
167171
In `Custom Script Engines`_ , we add some custom methods and objects to our scripting environment. We create a simple
168172
class (a :code:`namedtuple`) that holds the product information for each product.
169173

170-
In this particular case, Python will serialize instances of :code:`ProductInfo`, but they'll be converted to lists. And
171-
of course, in most cases where you would use a custom class, it is probably *not* going to be JSON-serializable. So we'll
172-
use this example to show how you might handle such a case.
174+
We'd like to be ble to save and restore our custom object.
173175

174176
.. code:: python
175177
178+
ProductInfo = namedtuple('ProductInfo', ['color', 'size', 'style', 'price'])
179+
176180
def product_info_to_dict(obj):
177181
return {
178182
'color': obj.color,
@@ -196,7 +200,7 @@ Registering an object sets up relationships between the class and the serializat
196200
over how this works in a little more detail in `Custom Serialization in More Depth`_.
197201

198202
It is also possible to bypass using a :code:`DictionaryConverter` at all for the data serialization process (but not for
199-
the spec serialization process). The only requirement the `data_converter` requires is that it implement the methods
203+
the spec serialization process). The only requirement for the the `data_converter` is that it implement the methods
200204

201205
- `convert`, which takes an object and returns something JSON-serializable
202206
- `restore`, which takes a serialized version and returns an object
@@ -220,7 +224,7 @@ to the next if they were serialized in an earlier format.
220224

221225
If you've overridden the serializer version, you may need to incorporate our serialization changes with
222226
your own. You can find our conversions in
223-
`version_migrations.py <https://github.com/sartography/SpiffWorkflow/blob/main/SpiffWorkflow/bpmn/serializer/version_migration.py>`_
227+
`SpiffWorkflow/bpmn/serilaizer/migrations <https://github.com/sartography/SpiffWorkflow/tree/main/SpiffWorkflow/bpmn/serializer/migration>`_
224228

225229
These are broken up into functions that handle each individual change, which will hopefully make it easier to incoporate them
226230
into your upgrade process, and also provides some documentation on what has changed.
@@ -309,7 +313,7 @@ implement the calls in functions and add those functions to the scripting enviro
309313
can be called by Script Tasks.
310314

311315
We are not going to actually include a database or API and write code for connecting to and querying
312-
it, but we can model our database with a simple dictionary lookup since we only have 7 products
316+
it, but since we only have 7 products we can model our database with a simple dictionary lookup
313317
and just return the same static info for shipping for the purposes of the tutorial.
314318

315319
We'll define some resources in `product_info.py`
@@ -390,6 +394,19 @@ script. We've imported our custom methods into `subprocess.py` so they are auto
390394
This example is needlessly complex for the work we're doing in this case, but the point of the example is to demonstrate
391395
that this could be a Docker container with a complex environment, an HTTP API running somewhere else entirely.
392396

397+
.. note::
398+
399+
Note that our execute method returns :code:`True`. We could check the status of our process here and return
400+
:code:`False` to force our task into an `ERROR` state if the task failed to execute.
401+
402+
We could also return :code:`None`
403+
if the task is not finished; this will cause the task to go into the `STARTED` state. You would have to manually
404+
complete a task that has been `STARTED`. The purpose of the state is to tell SpiffWorkflow your application will
405+
handle monitoring and updating this task and other branches that do not depend on this task may proceed. It is
406+
intended to be used with potentially long-running tasks.
407+
408+
See :doc:`../concepts` for more information about Task States and Workflow execution.
409+
393410
Service Tasks
394411
-------------
395412

@@ -433,7 +450,7 @@ This is our script engine and scripting enviroment:
433450
434451
Instead of adding our custom functions to the enviroment, we'll override :code:`call_service` and call them directly
435452
according to the `operation_name` that was given. The :code:`spiff` Service Task also evaluates the parameters
436-
against the task data for us, so we can use those values when we do. The Service Task will also store our result in
453+
against the task data for us, so we can pass those in directly. The Service Task will also store our result in
437454
a user-specified variable.
438455

439456
We need to send the result back as json, so we'll reuse the functions we wrote for the serializer.
@@ -459,15 +476,18 @@ The XML for the Service Task looks like this:
459476
<bpmn:outgoing>Flow_06k811b</bpmn:outgoing>
460477
</bpmn:serviceTask>
461478
462-
Getting this information into the task is a little bit beyond the scope of this tutorial, as it involves more than
463-
just SpiffWorkflow. I hand edited this XML; I do not recommend that (though it worked well enough for this case).
479+
Getting this information into the XML is a little bit beyond the scope of this tutorial, as it involves more than
480+
just SpiffWorkflow. I hand edited it for this case, but you can hardly ask your BPMN authors to do that!
464481

465-
Our `bpmn.js <https://github.com/sartography/bpmn-js-spiffworkflow>`_ has a means of providing a list of services and
466-
their parameters that can be displayed to a BPMN author. There is an example of hard-coding a list of services in
482+
Our `modeler <https://github.com/sartography/bpmn-js-spiffworkflow>`_ has a means of providing a list of services and
483+
their parameters that can be displayed to a BPMN author in the Service Task configurtion panel. There is an example of
484+
hard-coding a list of services in
467485
`app.js <https://github.com/sartography/bpmn-js-spiffworkflow/blob/0a9db509a0e85aa7adecc8301d8fbca9db75ac7c/app/app.js#L47>`_
468-
and as suggested, you could replace this with a API call.
486+
and as suggested, it would be reasonably straightforward to replace this with a API call. SpiffArena has robust
487+
mechanisms for handling this that might serve as a model for you.
469488

470-
How this all works is obviously heavily dependent on your application, so we won't go into further detail here.
489+
How this all works is obviously heavily dependent on your application, so we won't go into further detail here, except
490+
to give you a bare bones starting point for implementing something yourself that meets your own needs.
471491

472492
To run this workflow (you'll have to manually change which script engine you import):
473493

doc/bpmn/camunda/tasks.rst

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ User Tasks
77
Creating a User Task
88
^^^^^^^^^^^^^^^^^^^^
99

10-
When you click on a user task in a BPMN modeler, the Properties Panel includes a form tab. Use this
10+
When you click on a user task in the BPMN modeler, the Properties Panel includes a form tab. Use this
1111
tab to build your questions.
1212

1313
The following example shows how a form might be set up in Camumda.
@@ -46,7 +46,7 @@ following command:
4646

4747
.. code-block:: console
4848
49-
./camunda-bpmn-runner.py -p order_product -d bpmn/camunda/product_prices.dmn -b bpmn/camunda/task_types.bpmn
49+
./camunda-bpmn-runner.py -p order_product -d bpmn/tutorial/product_prices.dmn -b bpmn/camunda/task_types.bpmn
5050
5151
Example Application Code
5252
------------------------

doc/bpmn/custom_task_spec.rst

Lines changed: 16 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -31,10 +31,12 @@ we'll replace it with a NoneEventDefinition.
3131

3232
.. note::
3333

34-
Our class inherits from two classes. We import a mixin class that defines generic BPMN Start Task behavior from
35-
:code:`SpiffWorkflow.bpmn.specs.mixins.events.start_event` and the :code:`SpiffBpmnTask`, which extends the default
36-
:code:`SpiffWorkflow.bpmn.specs.mixins.bpmn_task_spec.BpmnSpecMixim`. We've split the basic BPMN behavior for Specification
37-
task types from the `BpmnSpecMixin` to make it easier to extend them without running into MRO issues.
34+
Our class inherits from two classes. We import a mixin class that defines generic BPMN Start Event behavior from
35+
:code:`StartEvent` in the :code:`bpmn` package and the :code:`SpiffBpmnTask` from the :code:`spiff` package, which
36+
extends the default :code:`BpmnSpecMixin`.
37+
38+
We've split the basic behavior for specific BPMN tasks from the :code:`BpmnSpecMixin` to make it easier to extend
39+
them without running into MRO issues.
3840

3941
In general, if you implement a custom task spec, you'll need to inherit from bases of both categories.
4042

@@ -75,13 +77,13 @@ extracting standard attributes from tasks; the :code:`SpiffBpmnTaskConverter` do
7577
:code:`spiff` package.
7678

7779
We don't have to do much -- all we do is replace the event definition with the original. The timer event will be
78-
removed when the task is restored.
80+
moved when the task is restored.
7981

8082
.. note::
8183

8284
It might be better have the class's init method take both the event definition to use *and* the timer event
83-
definition. Unfortunately, our parser is not terrible intuitive, so I've done it this way to make this a little
84-
easier to follow.
85+
definition. Unfortunately, our parser is not terribly intuitive or easily extendable, so I've done it this
86+
way to make this a little easier to follow.
8587

8688
When we create our serializer, we need to tell it about this task. We'll remove the converter for the standard Start
8789
Event and add the one we created to the confiuration and create the :code:`workflow_spec_converter` from the updated
@@ -90,16 +92,16 @@ config.
9092
.. note::
9193

9294
We have not instantiated our converter class. When we call :code:`configure_workflow_spec_converter` with a
93-
configuration (which is essentially a list of classes, split up into sections for organization purposes),
95+
configuration (which is essentially a list of classes, split up into sections for organizational purposes),
9496
*it* instantiates the classes for us, using the same `registry` for every class. At the end of the configuration
9597
if returns this registry, which now knows about all of the classes that will be used for SpiffWorkflow
9698
specifications. It is possible to pass a separately created :code:`DictionaryConverter` preconfigured with
9799
other converters; in that case, it will be used as the base `registry`, to which specification conversions will
98100
be added.
99101

100-
Because we've built up the `registry` in such a way, we can make use of the `registry.convert` and `registry.restore`
101-
methods rather than figuring out how to serialize them, though we didn't need to `restore` anything since the
102-
default method works fine.
102+
Because we've built up the `registry` in such a way, we can make use of the :code:`registry.convert` and
103+
:code:`registry.restore` methods rather than figuring out how to serialize them. We can use these methods on any
104+
objects that SpiffWorkflow knows about.
103105

104106
See :doc:`advanced` for more information about the serializer.
105107

@@ -126,4 +128,6 @@ I am going to leave creating a script that makes use of them to readers of this
126128
how to do.
127129

128130
There is a very simple diagram `bpmn/tutorial/timer_start.bpmn` with the process ID `timer_start` with a Start Event
129-
with a Duration Timer of one day that can be used to illustrate how the custom task works.
131+
with a Duration Timer of one day that can be used to illustrate how the custom task works. If you run this workflow
132+
with `spiff-bpmn-runner.py`, you'll see a `WAITING` Start Event; if you use the parser and serializer we just created,
133+
you'll be propmted to complete the User Task immediately.

0 commit comments

Comments
 (0)