Comments (14)
I found some code on the internet and modified it a bit to make it work in simple cases:
# import logging
# logger = logging.getLogger(__name__)
# logger.addHandler(logging.StreamHandler())
# logger.setLevel(logging.INFO)
# Source: http://sunshout.tistory.com/1773
from io import BytesIO
from SpiffWorkflow.bpmn.workflow import BpmnWorkflow
from SpiffWorkflow.bpmn.serializer.BpmnSerializer import BpmnSerializer
from SpiffWorkflow.bpmn.serializer.CompactWorkflowSerializer import CompactWorkflowSerializer
from SpiffWorkflow import Task
from SpiffWorkflow.specs import WorkflowSpec
from SpiffWorkflow.bpmn.serializer.Packager import Packager
from SpiffWorkflow.bpmn.parser.BpmnParser import BpmnParser
from SpiffWorkflow.bpmn.specs.BpmnSpecMixin import BpmnSpecMixin
from SpiffWorkflow.specs.Simple import Simple
from SpiffWorkflow.bpmn.parser.TaskParser import TaskParser
from SpiffWorkflow.bpmn.parser.util import *
from SpiffWorkflow.bpmn.specs.UserTask import UserTask
class ServiceTask(Simple, BpmnSpecMixin):
#class ServiceTask(UserTask):
"""
Task Spec for a bpmn:serviceTask node.
"""
def is_engine_task(self):
return False
def entering_complete_state(self, task):
print("Do command : %s" % task.get_description())
class ServiceTaskParser(TaskParser):
pass
class ScriptTask(Simple, BpmnSpecMixin):
"""
Task Spec for a bpmn:scriptTask node.
"""
def __init__(self, wf_spec, name, script, **kwargs):
"""
Constructor.
:param script: the script that must be executed by the script engine.
"""
super(ScriptTask, self).__init__(wf_spec, name, **kwargs)
self.script = script
def _on_complete_hook(self, task):
if task.workflow._is_busy_with_restore():
return
assert not task.workflow.read_only
task.workflow.script_engine.execute(task, self.script)
super(ScriptTask, self)._on_complete_hook(task)
class ScriptTaskParser(TaskParser):
"""
Parses a script task
"""
def create_task(self):
script = self.get_script()
return self.spec_class(self.spec, self.get_task_spec_name(), script, description=self.node.get('name', None))
# def get_script(self):
# """
# Gets the script content from the node. A subclass can override this method, if the script needs
# to be pre-parsed. The result of this call will be passed to the Script Engine for execution.
# """
# return one(self.xpath('.//bpmn:script')).text
def get_script(self):
"""
Gets the script content from the node. A subclass can override this method, if the script needs
to be pre-parsed. The result of this call will be passed to the Script Engine for execution.
"""
return """print('HAHAHA')"""
class CloudBpmnParser(BpmnParser):
OVERRIDE_PARSER_CLASSES = {
full_tag('serviceTask') : (ServiceTaskParser, ServiceTask),
full_tag('scriptTask') : (ScriptTaskParser, ScriptTask),
}
class InMemoryPackager(Packager):
"""
Creates spiff's wf packages on the fly.
"""
PARSER_CLASS = CloudBpmnParser
@classmethod
def package_in_memory(cls, workflow_name, workflow_files, editor='signavio'):
"""
Generates wf packages from workflow diagrams.
Args:
workflow_name: Name of wf
workflow_files: Diagram file.
Returns:
Workflow package (file like) object
"""
s = BytesIO()
p = cls(s, workflow_name, meta_data=[], editor=editor)
p.add_bpmn_files_by_glob(workflow_files)
p.create_package()
return s.getvalue()
class Node(object):
"""
Keep the Task information
"""
def __init__(self, task):
self.input = {}
self.output = {}
self.task = None
self.task_type = None
self.task_name = None
self.description = None
self.activity = None
self.init_task(task)
def init_task(self, task):
self.task = task
self.task_type = task.task_spec.__class__.__name__
self.task_name = task.get_name()
self.description = task.get_description()
self.activity = getattr(task.task_spec, 'service_class', '')
def show(self):
print("task type:%s" % self.task_type)
print("task name:%s" % self.task_name)
print("description:%s" % self.description)
print("activity :%s" % self.activity)
print("state name:%s" % self.task.get_state_name())
print("\n")
class BpmnEngine:
def __init__(self, path, name):
self.spec = self.load_spec(path, name)
self.workflow = BpmnWorkflow(self.spec)
self.run_engine()
# def create_workflow(self):
# self.workflow_spec = self.load_workflow_spec()
def load_spec(self, content_path, workflow_name):
return self.load_workflow_spec(content_path, workflow_name)
def load_workflow_spec(self, content_path, workflow_name):
package = InMemoryPackager.package_in_memory(workflow_name, content_path)
return BpmnSerializer().deserialize_workflow_spec(package)
# def start_engine(self, **kwargs):
# self.setUp()
def run_engine(self): # Old? Simple test?
for task in self.workflow.get_tasks():
task_name = task.get_name()
print(task_name)
def run_engine(self):
while 1:
self.workflow.do_engine_steps()
tasks = self.workflow.get_tasks(Task.READY)
if len(tasks) == 0:
break
for task in tasks:
current_node = Node(task)
current_node.show()
self.workflow.complete_task_from_id(task.id)
#BpmnEngine('tests/PizzaSimple.bpmn', '_6-2')
#BpmnEngine('tests/PizzaSimple.bpmn', 'Hungry for pizza') # Does not work because the process should have a name (we are not triggering a start event)
#BpmnEngine('tests/PizzaSimpleWithScriptTask.bpmn', '_6-2')
BpmnEngine('tests/PizzaSimpleWithScriptTaskAndCondition.bpmn', '_6-2') # TODO because does not work
I will extend my code and make it better the next days/weeks/months.
from spiffworkflow.
Oh, that's cool, Thanks! That will definitely help in writing the docs.
from spiffworkflow.
I have a much cleaner code now. If you want to have an example of how to use BPMN and how to run it properly, please contact me.
from spiffworkflow.
Hi Denny, Please, that would be great!
from spiffworkflow.
@DennyWeinberg That would be awesome 👍
from spiffworkflow.
Will release it in some days/weeks (A BPMN (based on SpiffWorkflow)+DMN library!)
:)
Currently I am working on a BPMN workflow that includes a DMN decision table.
from spiffworkflow.
https://github.com/labsolutionlu/bpmn_dmn
from spiffworkflow.
@DennyWeinberg Awesome!
I was only to glance over most of your implementation, but does it make sense to merge it into SpiffWorkflow master?
Even if it doesn't, there are parts that make me wonder: For example, does the CamundaExclusiveGatewayParser do anything on top of the BPMN standard, or should we just improve our ExclusiveGatewayParser to make the life of Camunda users easier?
I also see some other classes that seem to be pretty much "general purpose", e.g. you Packager, possibly BPMNXMLWorkflowRunner?
from spiffworkflow.
Hello,
CamundaExclusiveGatewayParser
adds the possibility to use "External Resource" Script condition types, that are executed exactly like a normal "Expression" condition:
See exclusive_gateway_complex.bpmn
You are right, the InMemoryPackager
and the BPMNXMLWorkflowRunner
are generic classes that can be re used.
You are free to copy what you want. But you can also let your library be independent, and the users who want to have specific helper functions and features of bpmn and dmn will switch to my library. Should be ok since I use your library in background so you have still full control over the workflow engine.
You have the coice... As you said, InMemoryPackager
and the BPMNXMLWorkflowRunner
are generic classes that may be also very useful in your library.
from spiffworkflow.
I've got a pull request out that merges the DMN portion of this effort into SpiffWorkflow. Denny, I've tried to give you credit in the commit.
#94
from spiffworkflow.
Nice. I see you also took over the unit tests. I remember there was an important todo in DMN. I think I mentioned it inside my readme file.
from spiffworkflow.
You added "Implement all different modes that are available for DMN tables", but that isn't much to go on, can you elaborate?
from spiffworkflow.
I think it was that value. You can switch between and/or/... I think. I'm not sure and I'm not on my PC right now...
Unfortunately we are still not using that library... but I think one time we will.
from spiffworkflow.
We have some basic support of DMN, we are still missing some core pieces, most notably the DMN evaluation mode described here. Closing this ticket, but will potentially open new tickets for broader support of DMN in the future.
from spiffworkflow.
Related Issues (20)
- Cycle timer child task doesn't inherit parent task data HOT 2
- Workflow with endless cycle timer boundary event never completes HOT 2
- first cycle of cycle timer executes immediately HOT 2
- Error "IllegalMonthError: bad month number 13; must be 1-12" on Boundary Cycle Timer 1 month
- Figure out how to keep the example repo in sync wth this one
- Workflow Prematurely Ends After Timer Start Event in SpiffWorkflow v3.0.0rc2 HOT 2
- Type in the releast notes. HOT 1
- Multiple Inputs to a Task HOT 1
- Workflow gets bogged down when a task has too many children HOT 2
- update parser to handle correlations on recieve tasks
- Allow Schema / Validator on Workflow Data (inputs/outputs/stores) in Spiffworkflow lib
- Question: How to send BPMN signals from python and catch them in the BPMN diagram? HOT 6
- Rewrite parser
- Evaluate performance improvements to MI tasks
- Bounty Test Issue - SpiffWorkFlow - Open - Claim
- Multi-Instance Task: Parallel Execution Issue with Data Store Inputs HOT 1
- Process Instance Migration: Compare two process models to find differences HOT 1
- Process Instance Migration: Find all completed tasks in a Process Instance HOT 2
- Process Instance Migration: Update the process instance with a new model HOT 2
- Refactor event based gateways
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from spiffworkflow.