Skip to content

Commit

Permalink
documentation & cleanup
Browse files Browse the repository at this point in the history
  • Loading branch information
essweine committed Sep 19, 2023
1 parent 46d6b36 commit 3baebb2
Show file tree
Hide file tree
Showing 10 changed files with 300 additions and 191 deletions.
2 changes: 1 addition & 1 deletion SpiffWorkflow/bpmn/serializer/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,6 @@
BpmnEventConverter,
)
from .helpers.spec import BpmnDataSpecificationConverter, EventDefinitionConverter
from .default.data_spec import IOSpecificationConverter
from .default.process_spec import BpmnProcessSpecConverter
from .default.task_spec import (
BpmnTaskSpecConverter,
Expand All @@ -99,6 +98,7 @@
ParallelGatewayConverter,
EventConverter,
BoundaryEventConverter,
IOSpecificationConverter,
)
from .default.event_definition import (
TimerEventDefinitionConverter,
Expand Down
34 changes: 0 additions & 34 deletions SpiffWorkflow/bpmn/serializer/default/data_spec.py

This file was deleted.

4 changes: 2 additions & 2 deletions SpiffWorkflow/bpmn/serializer/default/process_spec.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,10 @@
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
# 02110-1301 USA

from ..helpers.spec import WorkflowSpecConverter
from ..helpers.registry import BpmnConverter


class BpmnProcessSpecConverter(WorkflowSpecConverter):
class BpmnProcessSpecConverter(BpmnConverter):

def convert_task_spec_extensions(self, task_spec, dct):
# Extensions will be moved out of the base parser, but since we currently add them to some
Expand Down
70 changes: 68 additions & 2 deletions SpiffWorkflow/bpmn/serializer/default/task_spec.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,20 +19,77 @@


from SpiffWorkflow.bpmn.specs.bpmn_task_spec import _BpmnCondition
from ..helpers.spec import BpmnConverter
from ..helpers.spec import TaskSpecConverter

class IOSpecificationConverter(BpmnConverter):
"""The converter for an IOSpecification"""

def to_dict(self, spec):
"""Converts an IO spec to a dictionary representation
Arguments:
spec (BpmnIOSpecification): the `BpmnIOSpecification` of a `BpmnTaskSpec`
Returns:
dict: a dictionary representation of the IO spec
"""
return {
'data_inputs': [self.registry.convert(item) for item in spec.data_inputs],
'data_outputs': [self.registry.convert(item) for item in spec.data_outputs],
}

def from_dict(self, dct):
"""Restore a `BpmnIOSpecification` from a dictionary representation
Arguments:
dct (dict): the dictionary representation
Returns:
`BpmnIOSpecification`: a `BpmnTaskSpec` IO spec
"""
return self.target_class(
data_inputs=[self.registry.restore(item) for item in dct['data_inputs']],
data_outputs=[self.registry.restore(item) for item in dct['data_outputs']],
)


class BpmnTaskSpecConverter(TaskSpecConverter):
"""The base converter for a `BpmnTaskSpec`
This converter can be extended for customized task specs with additional attributes (e.g. the
ones defined in this module, which can serve as examples for anyone who has created a custom
BPMN task spec.
"""

def to_dict(self, spec):
dct = self.get_default_attributes(spec)
return dct
"""Create a dictionary representation of the shared `BpmnTaskSpec` attributes
Arguments:
spec: the spec to be converter to a dictionary
Returns:
dict: a dictionary representation of shared attributes
"""
return self.get_default_attributes(spec)

def from_dict(self, dct):
"""Restore a `BpmnTaskSpec` from a dictionary of attributes
If you have added only custom attributes that can be passed to `__init__`, you won't need
to extend this.
Arguments:
dct (dict): the task spec's dictionary representation
Returns:
an instance of the target class
"""
return self.task_spec_from_dict(dct)


class ScriptTaskConverter(BpmnTaskSpecConverter):
"""The default converter for `ScriptTask`"""

def to_dict(self, spec):
dct = self.get_default_attributes(spec)
Expand All @@ -41,6 +98,7 @@ def to_dict(self, spec):


class StandardLoopTaskConverter(BpmnTaskSpecConverter):
"""The default converter for `StandardLoopTask`"""

def to_dict(self, spec):
dct = self.get_default_attributes(spec)
Expand All @@ -49,6 +107,7 @@ def to_dict(self, spec):


class MultiInstanceTaskConverter(BpmnTaskSpecConverter):
"""The default converter for Parallel and Sequential MultiInstance Tasks"""

def to_dict(self, spec):
dct = self.get_default_attributes(spec)
Expand All @@ -70,13 +129,15 @@ def from_dict(self, dct):


class BoundaryEventJoinConverter(BpmnTaskSpecConverter):
"""The default converter for `BoundaryEventJoin`"""

def to_dict(self, spec):
dct = super().to_dict(spec)
dct.update(self.get_join_attributes(spec))
return dct

class SubWorkflowConverter(BpmnTaskSpecConverter):
"""The default converter for subworkflows (`SubWOrkflowTask`, `CallActivity`, `TransactionSubprocess`)"""

def to_dict(self, spec):
dct = super().to_dict(spec)
Expand All @@ -89,6 +150,7 @@ def from_dict(self, dct):


class ConditionalGatewayConverter(BpmnTaskSpecConverter):
"""A converter class that adds attributes for a `TaskSpec` with conditional outputs"""

def to_dict(self, spec):
dct = super().to_dict(spec)
Expand All @@ -114,6 +176,7 @@ def bpmn_condition_to_dict(self, condition):


class ExclusiveGatewayConverter(ConditionalGatewayConverter):
"""THe default converterfor `ExclusiveGateway`task specs"""

def to_dict(self, spec):
dct = super().to_dict(spec)
Expand All @@ -128,6 +191,7 @@ def from_dict(self, dct):


class ParallelGatewayConverter(BpmnTaskSpecConverter):
"""The default converter for `ParallelGateway` task specs """

def to_dict(self, spec):
dct = super().to_dict(spec)
Expand All @@ -139,6 +203,7 @@ def from_dict(self, dct):


class EventConverter(BpmnTaskSpecConverter):
"""The default converter for BPMN events"""

def to_dict(self, spec):
dct = super().to_dict(spec)
Expand All @@ -151,6 +216,7 @@ def from_dict(self, dct):


class BoundaryEventConverter(EventConverter):
"""The default converter for `BoundaryEvent` task specs"""

def to_dict(self, spec):
dct = super().to_dict(spec)
Expand Down
50 changes: 30 additions & 20 deletions SpiffWorkflow/bpmn/serializer/helpers/dictionary.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,8 +41,12 @@ class DictionaryConverter:
If a registered `typename` is found, the supplied `from_dict` function will be
called. Unrecognized objects will be returned as-is.
For a simple example of how to use this class, see the `BpmnDataConverter` in
`registry`.
For a simple example of how to use this class, see `registry.DefaultRegistry`.
Attributes:
typenames (dict): a mapping class to typename
convert_to_dict (dict): a mapping of typename to function
convert_from_dct (dict): a mapping of typename to function
"""

def __init__(self):
Expand All @@ -53,41 +57,46 @@ def __init__(self):
def register(self, cls, to_dict, from_dict, typename=None):
"""Register a conversion/restoration.
The `to_dict` function must return a dictionary; if no `typename` is given,
the unquallified class name will be used.
Arguments:
cls: the class that will be converted/restored
to_dict (function): a function that will be called with the object as an argument
from_dict (function): a function that restores the object from the dict
typename (str): an optional typename for identifying the converted object
:param cls: the class that will be converted/restored
:param to_dict: a function that will be called with the object as an argument
:param from_dict: a function that restores the object from the dict
:param typename: an optional typename for identifying the converted object
Notes:
The `to_dict` function must return a dictionary; if no `typename` is given,
the unquallified class name will be used.
"""
typename = cls.__name__ if typename is None else typename
self.typenames[cls] = typename
self.convert_to_dict[typename] = partial(self.obj_to_dict, typename, to_dict)
self.convert_from_dict[typename] = partial(self.obj_from_dict, from_dict)
self.convert_to_dict[typename] = partial(self._obj_to_dict, typename, to_dict)
self.convert_from_dict[typename] = partial(self._obj_from_dict, from_dict)

@staticmethod
def obj_to_dict(typename, func, obj, **kwargs):
def _obj_to_dict(typename, func, obj, **kwargs):
"""A method for automatically inserting the typename in the dictionary returned by to_dict."""
dct = func(obj, **kwargs)
dct.update({'typename': typename})
return dct

@staticmethod
def obj_from_dict(func, dct, **kwargs):
def _obj_from_dict(func, dct, **kwargs):
"""A method for calling the from_dict function on recognized objects."""
return func(dct, **kwargs)

def convert(self, obj, **kwargs):
"""
"""Convert a known object to a dictionary.
This is the public conversion method. It will be applied to dictionary
values, list items, and the object itself, applying the to_dict functions
of any registered type to the objects, or return the object unchanged if
it is not recognized.
:param obj: the object to be converter
Arguments:
obj: the object to be converter
Returns:
the dictionary representation for registered objects or the original
for unregistered objects
dict: the dictionary representation for registered objects or the original for unregistered objects
"""
typename = self.typenames.get(obj.__class__)
if typename in self.convert_to_dict:
Expand All @@ -101,17 +110,18 @@ def convert(self, obj, **kwargs):
return obj

def restore(self, val, **kwargs):
"""
"""Restore a known object from a dictionary.
This is the public restoration method. It will be applied to dictionary
values, list items, and the value itself, checking for a `typename` key and
applying the from_dict function of any registered type, or return the value
unchanged if it is not recognized.
:param val: the value to be converted
Arguments:
val: the value to be converted
Returns:
the restored object for registered objects or the original for
unregistered values
dict: the restored object for registered objects or the original for unregistered values
"""
if isinstance(val, dict) and 'typename' in val:
from_dict = self.convert_from_dict.get(val.pop('typename'))
Expand Down
Loading

0 comments on commit 3baebb2

Please sign in to comment.