工作流管理联盟工作流引擎
shoobx.wfmc的Python项目详细描述
详细文档
工作流管理联盟工作流引擎
此包提供工作流管理的实现
联盟(WFMC)工作流引擎。发动机作为
工作流流程组件的集合。工作流过程可以是
用python或通过xml过程定义语言xpdl定义。
在本文档中,我们将查看python定义的流程定义:
< Buff行情>
>>> from shoobx.wfmc import process
>>> pd = process.ProcessDefinition('sample')
进程的参数是进程ID。
一个过程有许多部分。让我们看一个样本回顾
流程:
-----------
-->| Publish |
---------- ---------- / -----------
| Author |-->| Review |- ----------
---------- ---------- \-->| Reject |
----------
这里我们有一个开始活动和两个结束活动。我们可以
已经用单端活动对此进行了建模,但这不是
必修的。需要一个启动活动
。过程定义
有一组活动,它们之间有转换。让我们来定义
流程定义的活动:
< Buff行情>
>>> pd.defineActivities(
... author = process.ActivityDefinition(),
... review = process.ActivityDefinition(),
... publish = process.ActivityDefinition(),
... reject = process.ActivityDefinition(),
... )
我们提供活动作为关键字参数。参数名提供
定义转换时将使用的活动标识:
< Buff行情>
>>> pd.defineTransitions(
... process.TransitionDefinition('author', 'review'),
... process.TransitionDefinition('review', 'publish'),
... process.TransitionDefinition('review', 'reject'),
... )
每个转换都由一个用于开始的标识符构造
活动,以及结束活动的标识符。
在使用工作流定义之前,我们必须将其注册为
实用工具。这是必要的,以便流程实例可以找到
定义。此外,实用程序名称必须与进程ID匹配:
< Buff行情>
>>> import zope.component
>>> from shoobx.wfmc.process import StaticProcessDefinitionFactory
>>> pdfactory = StaticProcessDefinitionFactory()
>>> zope.component.provideUtility(pdfactory)
>>> pdfactory.register(pd)
现在,有了这个定义,我们就可以执行我们的工作流了。我们还没有
已经定义了任何工作,但是我们可以看到工作流的执行。我们会看到的
通过注册记录工作流的订阅服务器来执行的工作流
事件:
< Buff行情>
>>> def log_workflow(event):
... print (event)
>>> import zope.event
>>> zope.event.subscribers.append(log_workflow)
要使用工作流定义,我们需要创建一个实例:
< Buff行情>
>>> proc = pd()
现在,如果我们启动工作流:
< Buff行情>
>>> proc.start()
ProcessStarted(Process('sample'))
Transition(None, Activity('sample.author'))
ActivityStarted(Activity('sample.author'))
ActivityFinished(Activity('sample.author'))
Transition(Activity('sample.author'), Activity('sample.review'))
ActivityStarted(Activity('sample.review'))
ActivityFinished(Activity('sample.review'))
Transition(Activity('sample.review'), Activity('sample.publish'))
ActivityStarted(Activity('sample.publish'))
ActivityFinished(Activity('sample.publish'))
ProcessFinished(Process('sample'))
我们看到我们立即过渡到作者活动,然后
发表评论。通常,我们需要在每个
活动和转换只有在工作完成后才能继续
但是,在本例中,我们没有定义任何工作,所以
活动立即完成。
注意,我们没有转换到被拒绝的活动。通过
默认情况下,当活动完成时,第一个转换
其条件评估为
true
被使用。默认情况下,转换
具有计算结果为
true
的布尔条件,因此转换
使用to
publish
是因为它是在转换到
拒绝
。我们想要的是转换到
发布
批准要发布的内容,但如果审阅者
拒绝要发布的内容。我们可以使用以下条件:
< Buff行情>
>>> from shoobx.wfmc import process
>>> pd = process.ProcessDefinition('sample')
0
>>> from shoobx.wfmc import process
>>> pd = process.ProcessDefinition('sample')
1
我们重新定义了工作流过程,为
转换到
发布
。布尔条件只是可调用的对象
获取一个数据对象并返回一个布尔值。数据对象是
称为"工作流相关数据"。流程实例具有数据对象
包含此数据。在上面的例子中,条件只是
返回
publish
属性的值。这个属性如何
准备好了吗?它需要由评审活动设置。为此,我们
需要安排活动来设置数据。这让我们想到
应用程序。
流程定义用于不同的
应用。因此,流程定义不包括
应用程序逻辑。它们所包含的是
要调用的应用程序和与工作流相关的数据流
从申请表上。现在,我们可以定义我们的应用程序:
< Buff行情>
>>> from shoobx.wfmc import process
>>> pd = process.ProcessDefinition('sample')
2
我们对应用程序使用的名称与
活动。这不是必需的,但却是一种常见的做法。注意
应用程序包含输出的规范
参数。既然我们已经定义了应用程序,我们需要修改
我们使用它们的活动:
< Buff行情>
>>> from shoobx.wfmc import process
>>> pd = process.ProcessDefinition('sample')
3
一个活动可以使用许多应用程序,因此我们调用
addapplication
。
在"审查"申请的申请定义中,我们
提供与工作流相关的数据变量的名称
为应用程序定义的输出参数。当使用
活动中的应用程序,与工作流相关的数据变量名
必须为
申请的签名。在活动中使用应用程序时,
为每个输入参数和
由每个输出参数设置。在本例中,输出
参数,将用于向工作流添加
publish
属性
相关数据。
参与者
我们已经宣布了一些申请,我们已经把它们连接到
活动,但我们仍然没有指定任何应用程序代码。以前
我们可以指定应用程序代码,我们需要考虑
正在执行应用程序。工作流应用程序通常
由人或其他外部行为体执行。与应用程序一样,
流程定义允许声明工作流中的参与者
与活动有关。我们宣布参与者与我们
声明应用程序,除非没有参数:
< Buff行情>
>>> from shoobx.wfmc import process
>>> pd = process.ProcessDefinition('sample')
4
在本例中,我们碰巧重用了一个活动名,但是
不是两个参与者。在定义了这些参与者之后,我们
可以将它们与活动关联:
< Buff行情>
>>> from shoobx.wfmc import process
>>> pd = process.ProcessDefinition('sample')
5
应用程序集成
要使用流程定义来控制应用程序逻辑,我们需要
将其与"集成"对象相关联。
当流程需要获取参与者时,它调用createparticipant
在其integration属性上,传递进程id和
执行者ID。如果活动没有
执行者,则上面的过程与空的执行者ID一起使用。
类似地,当流程需要工作项时,它调用createworkitem
在其integration属性上,传递进程id和
应用程序ID.
工作项提供用于启动工作的
start
方法
并传递输入参数。这是工作项目的责任,
稍后,调用
活动,通知活动工作项
完整的。输出参数被传递到工作项finished
方法:
创建集成对象的一个简单方法是
shoobx.wfmc.attributeintegration.attributeintegration
< Buff行情>
>>> from shoobx.wfmc import process
>>> pd = process.ProcessDefinition('sample')
6
我们将首先定义一个简单的参与者类:
< Buff行情>
>>> from shoobx.wfmc import process
>>> pd = process.ProcessDefinition('sample')
7
>>> from shoobx.wfmc import process
>>> pd = process.ProcessDefinition('sample')
8
我们为每个参与者设置集成属性:
< Buff行情>
>>> from shoobx.wfmc import process
>>> pd = process.ProcessDefinition('sample')
9
我们还为参与者定义了一个属性,用于
有表演者:
< Buff行情>
-----------
-->| Publish |
---------- ---------- / -----------
| Author |-->| Review |- ----------
---------- ---------- \-->| Reject |
----------
0
现在我们将定义我们的工作项。首先,我们将定义一些类:
< Buff行情>
-----------
-->| Publish |
---------- ---------- / -----------
| Author |-->| Review |- ----------
---------- ---------- \-->| Reject |
----------
1
-----------
-->| Publish |
---------- ---------- / -----------
| Author |-->| Review |- ----------
---------- ---------- \-->| Reject |
----------
2
-----------
-->| Publish |
---------- ---------- / -----------
| Author |-->| Review |- ----------
---------- ---------- \-->| Reject |
----------
3
-----------
-->| Publish |
---------- ---------- / -----------
| Author |-->| Review |- ----------
---------- ---------- \-->| Reject |
----------
4
-----------
-->| Publish |
---------- ---------- / -----------
| Author |-->| Review |- ----------
---------- ---------- \-->| Reject |
----------
5
然后我们将它们连接到集成对象:
< Buff行情>
-----------
-->| Publish |
---------- ---------- / -----------
| Author |-->| Review |- ----------
---------- ---------- \-->| Reject |
----------
6
使用工作流过程
要使用流程定义,请将其实例化并调用其start方法
开始执行:
< Buff行情>
-----------
-->| Publish |
---------- ---------- / -----------
| Author |-->| Review |- ----------
---------- ---------- \-->| Reject |
----------
7
我们进入作者活动,等待工作完成。
为了继续前进,我们需要找到创作工作项,这样我们就可以
完成它。我们的工作项添加到工作列表中,这样我们就可以
从列表中获取项目。
< Buff行情>
-----------
-->| Publish |
---------- ---------- / -----------
| Author |-->| Review |- ----------
---------- ---------- \-->| Reject |
----------
8
现在,我们可以通过调用其finish方法来完成工作项:
< Buff行情>
-----------
-->| Publish |
---------- ---------- / -----------
| Author |-->| Review |- ----------
---------- ---------- \-->| Reject |
----------
9
我们看到我们过渡到了审查活动。请注意
finish
方法不是工作流api的一部分。它的定义是
我们的示例类。其他应用程序可以使用不同的机制。
现在,我们将通过调用评审工作项的
完成
。我们将通过
false
,表明内容不应
出版日期:
< Buff行情>
>>> pd.defineActivities(
... author = process.ActivityDefinition(),
... review = process.ActivityDefinition(),
... publish = process.ActivityDefinition(),
... reject = process.ActivityDefinition(),
... )
0
排序输出转换
通常,传出转换按转换顺序排列
使用定义和给定活动的所有转换。
如果转换是以不方便的顺序定义的,则工作流
可能无法按预期工作。例如,让我们修改上面的
通过改变一些
转变。我们将重用以前的集成对象
将其传递给定义构造函数的示例:
< Buff行情>
>>> pd.defineActivities(
... author = process.ActivityDefinition(),
... review = process.ActivityDefinition(),
... publish = process.ActivityDefinition(),
... reject = process.ActivityDefinition(),
... )
1
>>> pd.defineActivities(
... author = process.ActivityDefinition(),
... review = process.ActivityDefinition(),
... publish = process.ActivityDefinition(),
... reject = process.ActivityDefinition(),
... )
2
>>> from shoobx.wfmc import process
>>> pd = process.ProcessDefinition('sample')
2
>>> from shoobx.wfmc import process
>>> pd = process.ProcessDefinition('sample')
3
>>> from shoobx.wfmc import process
>>> pd = process.ProcessDefinition('sample')
4
>>> from shoobx.wfmc import process
>>> pd = process.ProcessDefinition('sample')
5
运行我们的流程:
< Buff行情>
-----------
-->| Publish |
---------- ---------- / -----------
| Author |-->| Review |- ----------
---------- ---------- \-->| Reject |
----------
7
>>> pd.defineActivities(
... author = process.ActivityDefinition(),
... review = process.ActivityDefinition(),
... publish = process.ActivityDefinition(),
... reject = process.ActivityDefinition(),
... )
8
这次,我们会说我们应该发布:
< Buff行情>
>>> pd.defineActivities(
... author = process.ActivityDefinition(),
... review = process.ActivityDefinition(),
... publish = process.ActivityDefinition(),
... reject = process.ActivityDefinition(),
... )
9
但我们还是去了拒绝活动。为什么?因为转换
按顺序测试。因为到拒绝活动的转换是
先测试,没有条件,我们没有检查
转换到发布活动的条件。我们可以解决这个问题
通过直接在审阅者活动上指定传出转换。
为此,我们还需要在转换中指定id。让我们
重新定义流程:
< Buff行情>
>>> pd.defineActivities(
... author = process.ActivityDefinition(),
... review = process.ActivityDefinition(),
... publish = process.ActivityDefinition(),
... reject = process.ActivityDefinition(),
... )
1
>>> pd.defineTransitions(
... process.TransitionDefinition('author', 'review'),
... process.TransitionDefinition('review', 'publish'),
... process.TransitionDefinition('review', 'reject'),
... )
1
>>> from shoobx.wfmc import process
>>> pd = process.ProcessDefinition('sample')
2
>>> from shoobx.wfmc import process
>>> pd = process.ProcessDefinition('sample')
3
>>> from shoobx.wfmc import process
>>> pd = process.ProcessDefinition('sample')
4
>>> from shoobx.wfmc import process
>>> pd = process.ProcessDefinition('sample')
5
>>> pd.defineTransitions(
... process.TransitionDefinition('author', 'review'),
... process.TransitionDefinition('review', 'publish'),
... process.TransitionDefinition('review', 'reject'),
... )
6
现在,当我们运行这个过程时,我们将以
需要:
< Buff行情>
-----------
-->| Publish |
---------- ---------- / -----------
| Author |-->| Review |- ----------
---------- ---------- \-->| Reject |
----------
7
>>> pd.defineActivities(
... author = process.ActivityDefinition(),
... review = process.ActivityDefinition(),
... publish = process.ActivityDefinition(),
... reject = process.ActivityDefinition(),
... )
8
>>> pd.defineTransitions(
... process.TransitionDefinition('author', 'review'),
... process.TransitionDefinition('review', 'publish'),
... process.TransitionDefinition('review', 'reject'),
... )
9
让我们看看另一种方法,我们应该转换到拒绝:
< Buff行情>
-----------
-->| Publish |
---------- ---------- / -----------
| Author |-->| Review |- ----------
---------- ---------- \-->| Reject |
----------
7
>>> pd.defineActivities(
... author = process.ActivityDefinition(),
... review = process.ActivityDefinition(),
... publish = process.ActivityDefinition(),
... reject = process.ActivityDefinition(),
... )
8
>>> pd.defineActivities(
... author = process.ActivityDefinition(),
... review = process.ActivityDefinition(),
... publish = process.ActivityDefinition(),
... reject = process.ActivityDefinition(),
... )
0
复杂流
让我们看一个更复杂的例子。在本例中,我们将扩展
与多个审阅者一起工作的过程。我们还将
工作列表处理更复杂一些。我们还将介绍
一些新概念:
-
拆分和联接
-
处理参数
考虑出版
流程如下所示:
>>> import zope.component
>>> from shoobx.wfmc.process import StaticProcessDefinitionFactory
>>> pdfactory = StaticProcessDefinitionFactory()
>>> zope.component.provideUtility(pdfactory)
>>> pdfactory.register(pd)
3
在这里,我们将流程图排列成列,其中
每个参与者的活动。我们有四个参与者,
作者、两名技术评审员和一名编辑评审员。这个
作者准备了一份草稿。作者将草稿发送到
both
技术评审员进行评审。当技术评审
完成后,编辑评论将进行初步编辑
复习。根据技术评论,编辑可以选择:
-
拒绝文档
-
按原样发布文档
-
请求技术更改(基于技术评审员
注释),或
-
请求编辑更改。
如果需要进行技术更改,则工作将返回到
"准备"活动。如果有必要进行编辑性修改,那么
流向"准备最终"活动。当作者制作了
编辑修改,工作流程到"审查最终"。编辑可以
请求其他更改,在这种情况下,工作流程返回到"准备
"最终",否则,工作将流向"发布"。
这个例子说明了不同类型的"连接"和"拆分"。这个
术语"join"是指传入活动的转换方式
处理。连接有两种:"and"和"xor"。加上"和"
join,活动将等待每个传入的转换。在
本例中,"编辑评论"活动的输入构成
"和"加入。编辑评论要等到每个技术
评审完成。本例中的其余连接是
"异或"连接。活动在转换为活动时开始。
"拆分"一词是指从一个活动向外转换的方式
都处理好了。通常,一个活动的一个转换是
使用。这称为"异或"分裂。加上"和"分开,全部
使用计算结果为
true
的布尔条件转换。
在本例中,"prepare"活动有一个"and"分隔符。工作
同时流向两个技术审查活动。其余的
本例中的拆分是"异或"拆分。
让我们创建新的工作流过程。我们会重新利用现有的
集成对象:
< Buff行情>
>>> import zope.component
>>> from shoobx.wfmc.process import StaticProcessDefinitionFactory
>>> pdfactory = StaticProcessDefinitionFactory()
>>> zope.component.provideUtility(pdfactory)
>>> pdfactory.register(pd)
4
>>> import zope.component
>>> from shoobx.wfmc.process import StaticProcessDefinitionFactory
>>> pdfactory = StaticProcessDefinitionFactory()
>>> zope.component.provideUtility(pdfactory)
>>> pdfactory.register(pd)
5
在这里,我们将字符串传递给活动定义
名字。名称必须是Unicode或ASCII字符串。
我们定义转换:
< Buff行情>
>>> import zope.component
>>> from shoobx.wfmc.process import StaticProcessDefinitionFactory
>>> pdfactory = StaticProcessDefinitionFactory()
>>> zope.component.provideUtility(pdfactory)
>>> pdfactory.register(pd)
6
我们指定"和"拆分并加入:
< Buff行情>
>>> import zope.component
>>> from shoobx.wfmc.process import StaticProcessDefinitionFactory
>>> pdfactory = StaticProcessDefinitionFactory()
>>> zope.component.provideUtility(pdfactory)
>>> pdfactory.register(pd)
7
我们定义参与者和应用程序:
< Buff行情>
>>> import zope.component
>>> from shoobx.wfmc.process import StaticProcessDefinitionFactory
>>> pdfactory = StaticProcessDefinitionFactory()
>>> zope.component.provideUtility(pdfactory)
>>> pdfactory.register(pd)
8
>>> import zope.component
>>> from shoobx.wfmc.process import StaticProcessDefinitionFactory
>>> pdfactory = StaticProcessDefinitionFactory()
>>> zope.component.provideUtility(pdfactory)
>>> pdfactory.register(pd)
9
>>> def log_workflow(event):
... print (event)
0
>>> def log_workflow(event):
... print (event)
1
>>> def log_workflow(event):
... print (event)
2
>>> def log_workflow(event):
... print (event)
3
>>> def log_workflow(event):
... print (event)
4
>>> def log_workflow(event):
... print (event)
5
>>> def log_workflow(event):
... print (event)
6
我们希望在启动进程时能够指定作者。
我们还想知道最后的处理过程。到
完成此操作后,我们将为流程定义参数:
< Buff行情>
>>> def log_workflow(event):
... print (event)
7
既然我们已经定义了流程,我们需要提供参与者和
应用程序组件。让我们从参与者开始。宁愿
与共享单个工作列表相比,我们将为每个用户提供他们自己的
工作清单。我们还将创建先前存在的参与者并返回
他们。最后,我们将创建多个作者并使用选定的作者:
< Buff行情>
>>> def log_workflow(event):
... print (event)
8
>>> def log_workflow(event):
... print (event)
9
>>> import zope.event
>>> zope.event.subscribers.append(log_workflow)
0
>>> import zope.event
>>> zope.event.subscribers.append(log_workflow)
1
在本例中,我们需要为每个参与者定义一个单独的属性:
< Buff行情>
>>> import zope.event
>>> zope.event.subscribers.append(log_workflow)
2
创建进程时,将传入作者名并
分配给工作流相关数据。我们的author类使用这个
选择指定用户的信息。
< Buff行情>
>>> import zope.event
>>> zope.event.subscribers.append(log_workflow)
3
>>> import zope.event
>>> zope.event.subscribers.append(log_workflow)
4
>>> import zope.event
>>> zope.event.subscribers.append(log_workflow)
5
我们将利用我们的原始参与课程进行
表演者:
< Buff行情>
-----------
-->| Publish |
---------- ---------- / -----------
| Author |-->| Review |- ----------
---------- ---------- \-->| Reject |
----------
0
现在我们将创建我们的应用程序。让我们从作者开始:
< Buff行情>
>>> import zope.event
>>> zope.event.subscribers.append(log_workflow)
7
>>> import zope.event
>>> zope.event.subscribers.append(log_workflow)
8
>>> import zope.event
>>> zope.event.subscribers.append(log_workflow)
9
因为我们使用了"准备修订申请"和"初始修订申请"
准备,我们提供了一个总结方法来说明我们必须做什么。
这里我们得到作者创建的文档,它作为
finish方法的参数。在更现实的实施中,
author任务将在任务开始时创建文档,并且
提供用户界面供用户编辑。我们存储
文档作为应用程序相关数据,因为我们希望审阅者
能够访问它,但我们不需要它直接用于工作流
控制,
< Buff行情>
>>> proc = pd()
0
>>> proc = pd()
1
在这里,我们提供了一种访问原始文档的方法。
< Buff行情>
>>> proc = pd()
2
>>> proc = pd()
3
在这个实现中,如果
技术编辑建议拒绝并将工作发回
如果有任何技术变更,请做好准备。我们还将
techreview
获取
getdoc
方法。
我们将重用前一个应用程序中的
publish
和
reject
应用程序
例子:
< Buff行情>
>>> proc = pd()
4
>>> proc = pd()
5
在这个应用程序中,我们只是更新文档以反映
变化:
< Buff行情>
>>> proc = pd()
6
>>> proc = pd()
7
我们的进程现在返回数据。当我们创建一个流程时,我们需要
提供一个可以调用的对象:
< Buff行情>
>>> proc = pd()
8
现在,让我们试试我们的流程:
< Buff行情>
>>> proc = pd()
9
我们应该在鲍勃的工作清单上加上一项。我们去拿吧
完成它,提交文档:
< Buff行情>
>>> proc.start()
ProcessStarted(Process('sample'))
Transition(None, Activity('sample.author'))
ActivityStarted(Activity('sample.author'))
ActivityFinished(Activity('sample.author'))
Transition(Activity('sample.author'), Activity('sample.review'))
ActivityStarted(Activity('sample.review'))
ActivityFinished(Activity('sample.review'))
Transition(Activity('sample.review'), Activity('sample.publish'))
ActivityStarted(Activity('sample.publish'))
ActivityFinished(Activity('sample.publish'))
ProcessFinished(Process('sample'))
0
注意,我们转换到了
两个
活动,
tech1
和
技术2
。这是因为准备活动有一个"和"分隔。
现在我们做一个技术回顾。让我们看看Tech1有哪些功能:
< Buff行情>
>>> proc.start()
ProcessStarted(Process('sample'))
Transition(None, Activity('sample.author'))
ActivityStarted(Activity('sample.author'))
ActivityFinished(Activity('sample.author'))
Transition(Activity('sample.author'), Activity('sample.review'))
ActivityStarted(Activity('sample.review'))
ActivityFinished(Activity('sample.review'))
Transition(Activity('sample.review'), Activity('sample.publish'))
ActivityStarted(Activity('sample.publish'))
ActivityFinished(Activity('sample.publish'))
ProcessFinished(Process('sample'))
1
让我们告诉作者将"美国人"改为"地球人":
< Buff行情>
>>> proc.start()
ProcessStarted(Process('sample'))
Transition(None, Activity('sample.author'))
ActivityStarted(Activity('sample.author'))
ActivityFinished(Activity('sample.author'))
Transition(Activity('sample.author'), Activity('sample.review'))
ActivityStarted(Activity('sample.review'))
ActivityFinished(Activity('sample.review'))
Transition(Activity('sample.review'), Activity('sample.publish'))
ActivityStarted(Activity('sample.publish'))
ActivityFinished(Activity('sample.publish'))
ProcessFinished(Process('sample'))
2
在这里我们转到了编辑评论活动,但是我们没有
开始吧。这是因为编辑评论活动有一个"and"
连接,这意味着在两个转换都
发生。
现在我们将进行另一项技术回顾:
< Buff行情>
>>> proc.start()
ProcessStarted(Process('sample'))
Transition(None, Activity('sample.author'))
ActivityStarted(Activity('sample.author'))
ActivityFinished(Activity('sample.author'))
Transition(Activity('sample.author'), Activity('sample.review'))
ActivityStarted(Activity('sample.review'))
ActivityFinished(Activity('sample.review'))
Transition(Activity('sample.review'), Activity('sample.publish'))
ActivityStarted(Activity('sample.publish'))
ActivityFinished(Activity('sample.publish'))
ProcessFinished(Process('sample'))
3
现在,当我们转到编辑评论活动时,我们开始
因为每个输入转换都发生了。我们的社论
审核申请自动将工作发回准备,
因为有技术评论。当然,作者仍然是鲍勃。
让我们发表评论:
< Buff行情>
>>> proc.start()
ProcessStarted(Process('sample'))
Transition(None, Activity('sample.author'))
ActivityStarted(Activity('sample.author'))
ActivityFinished(Activity('sample.author'))
Transition(Activity('sample.author'), Activity('sample.review'))
ActivityStarted(Activity('sample.review'))
ActivityFinished(Activity('sample.review'))
Transition(Activity('sample.review'), Activity('sample.publish'))
ActivityStarted(Activity('sample.publish'))
ActivityFinished(Activity('sample.publish'))
ProcessFinished(Process('sample'))
4
>>> proc.start()
ProcessStarted(Process('sample'))
Transition(None, Activity('sample.author'))
ActivityStarted(Activity('sample.author'))
ActivityFinished(Activity('sample.author'))
Transition(Activity('sample.author'), Activity('sample.review'))
ActivityStarted(Activity('sample.review'))
ActivityFinished(Activity('sample.review'))
Transition(Activity('sample.review'), Activity('sample.publish'))
ActivityStarted(Activity('sample.publish'))
ActivityFinished(Activity('sample.publish'))
ProcessFinished(Process('sample'))
5
和以前一样,在完成最初的编辑之后,我们开始
再次回顾活动。我们再复习一遍。这次,我们没有
注释,因为作者应用了我们请求的更改:
< Buff行情>
>>> proc.start()
ProcessStarted(Process('sample'))
Transition(None, Activity('sample.author'))
ActivityStarted(Activity('sample.author'))
ActivityFinished(Activity('sample.author'))
Transition(Activity('sample.author'), Activity('sample.review'))
ActivityStarted(Activity('sample.review'))
ActivityFinished(Activity('sample.review'))
Transition(Activity('sample.review'), Activity('sample.publish'))
ActivityStarted(Activity('sample.publish'))
ActivityFinished(Activity('sample.publish'))
ProcessFinished(Process('sample'))
6
>>> proc.start()
ProcessStarted(Process('sample'))
Transition(None, Activity('sample.author'))
ActivityStarted(Activity('sample.author'))
ActivityFinished(Activity('sample.author'))
Transition(Activity('sample.author'), Activity('sample.review'))
ActivityStarted(Activity('sample.review'))
ActivityFinished(Activity('sample.review'))
Transition(Activity('sample.review'), Activity('sample.publish'))
ActivityStarted(Activity('sample.publish'))
ActivityFinished(Activity('sample.publish'))
ProcessFinished(Process('sample'))
7
这次,我们留在技术评审活动中,因为
没有任何技术上的改变。我们准备好做社论评论了。
我们将请求编辑更改:
< Buff行情>
>>> proc.start()
ProcessStarted(Process('sample'))
Transition(None, Activity('sample.author'))
ActivityStarted(Activity('sample.author'))
ActivityFinished(Activity('sample.author'))
Transition(Activity('sample.author'), Activity('sample.review'))
ActivityStarted(Activity('sample.review'))
ActivityFinished(Activity('sample.review'))
Transition(Activity('sample.review'), Activity('sample.publish'))
ActivityStarted(Activity('sample.publish'))
ActivityFinished(Activity('sample.publish'))
ProcessFinished(Process('sample'))
8
>>> proc.start()
ProcessStarted(Process('sample'))
Transition(None, Activity('sample.author'))
ActivityStarted(Activity('sample.author'))
ActivityFinished(Activity('sample.author'))
Transition(Activity('sample.author'), Activity('sample.review'))
ActivityStarted(Activity('sample.review'))
ActivityFinished(Activity('sample.review'))
Transition(Activity('sample.review'), Activity('sample.publish'))
ActivityStarted(Activity('sample.publish'))
ActivityFinished(Activity('sample.publish'))
ProcessFinished(Process('sample'))
9
因为我们要求修改社论,所以我们转到了决赛
编辑活动,以便作者(仍然是bob)可以进行更改:
< Buff行情>
α
>>> from shoobx.wfmc import process
>>> pd = process.ProcessDefinition('sample')
00
>>> from shoobx.wfmc import process
>>> pd = process.ProcessDefinition('sample')
01
我们转向行动用于审阅最终编辑的ITY。我们
审阅文档并批准发布:
< Buff行情>
>>> from shoobx.wfmc import process
>>> pd = process.ProcessDefinition('sample')
02
>>> from shoobx.wfmc import process
>>> pd = process.ProcessDefinition('sample')
03
在这一点上,剩下的过程会自动完成。在
此外,决策记录在流程上下文对象中:
< Buff行情>
>>> from shoobx.wfmc import process
>>> pd = process.ProcessDefinition('sample')
04
即将推出
-
超时/异常
另请参见
http://www.wfmc.org
http://www.wfmc.org/standards/standards.htm
xpdl导入
我们可以从xml进程中的文件导入进程定义
定义语言(xpdl)格式。xpdl文件包含多个
在包中排列的进程定义。当我们加载文件时
获取包含一些进程定义的包。
让我们看一个例子。文件
publication.xpdl
包含在
"readme.txt"文件。我们可以使用xpdl模块阅读:
< Buff行情>
>>> from shoobx.wfmc import process
>>> pd = process.ProcessDefinition('sample')
05
此软件包包含单个定义:
< Buff行情>
>>> from shoobx.wfmc import process
>>> pd = process.ProcessDefinition('sample')
06
>>> from shoobx.wfmc import process
>>> pd = process.ProcessDefinition('sample')
07
现在,在阅读了流程定义之后,我们可以像以前那样使用它
之前(在"readme.txt"中)。和以前一样,我们将创建一个事件订阅服务器
这样我们就可以看到发生了什么:
< Buff行情>
>>> from shoobx.wfmc import process
>>> pd = process.ProcessDefinition('sample')
08
>>> import zope.event
>>> zope.event.subscribers.append(log_workflow)
我们将把进程定义注册为实用程序:
< Buff行情>
>>> import zope.component
>>> from shoobx.wfmc.process import StaticProcessDefinitionFactory
>>> pdfactory = StaticProcessDefinitionFactory()
>>> zope.component.provideUtility(pdfactory)
>>> pdfactory.register(pd)
我们将定义并注册参与者和应用程序适配器:
< Buff行情>
>>> from shoobx.wfmc import process
>>> pd = process.ProcessDefinition('sample')
7
>>> from shoobx.wfmc import process
>>> pd = process.ProcessDefinition('sample')
8
>>> def log_workflow(event):
... print (event)
8
>>> def log_workflow(event):
... print (event)
9
>>> import zope.event
>>> zope.event.subscribers.append(log_workflow)
0
>>> from shoobx.wfmc import process
>>> pd = process.ProcessDefinition('sample')
16
>>> import zope.event
>>> zope.event.subscribers.append(log_workflow)
2
>>> import zope.event
>>> zope.event.subscribers.append(log_workflow)
3
>>> import zope.event
>>> zope.event.subscribers.append(log_workflow)
4
>>> import zope.event
>>> zope.event.subscribers.append(log_workflow)
5
>>> from shoobx.wfmc import process
>>> pd = process.ProcessDefinition('sample')
21
>>> import zope.event
>>> zope.event.subscribers.append(log_workflow)
7
>>> from shoobx.wfmc import process
>>> pd = process.ProcessDefinition('sample')
23
>>> import zope.event
>>> zope.event.subscribers.append(log_workflow)
9
>>> proc = pd()
0
>>> proc = pd()
1
>>> from shoobx.wfmc import process
>>> pd = process.ProcessDefinition('sample')
27
>>> proc = pd()
3
>>> from shoobx.wfmc import process
>>> pd = process.ProcessDefinition('sample')
29
>>> proc = pd()
5
>>> from shoobx.wfmc import process
>>> pd = process.ProcessDefinition('sample')
31
>>> proc = pd()
7
>>> from shoobx.wfmc import process
>>> pd = process.ProcessDefinition('sample')
33
>>> from shoobx.wfmc import process
>>> pd = process.ProcessDefinition('sample')
34
>>> from shoobx.wfmc import process
>>> pd = process.ProcessDefinition('sample')
35
>>> from shoobx.wfmc import process
>>> pd = process.ProcessDefinition('sample')
36
以及进程上下文,以便我们可以传递参数:
< Buff行情>
>>> proc = pd()
8
现在,让我们试试我们的流程。我们会按照之前的步骤
"readme.txt",得到相同的结果:
< Buff行情>
αααα138
>>> from shoobx.wfmc import process
>>> pd = process.ProcessDefinition('sample')
39
>>> from shoobx.wfmc import process
>>> pd = process.ProcessDefinition('sample')
40
>>> from shoobx.wfmc import process
>>> pd = process.ProcessDefinition('sample')
41
>>> from shoobx.wfmc import process
>>> pd = process.ProcessDefinition('sample')
42
αααα143
>>> from shoobx.wfmc import process
>>> pd = process.ProcessDefinition('sample')
44
>>> from shoobx.wfmc import process
>>> pd = process.ProcessDefinition('sample')
45
>>> from shoobx.wfmc import process
>>> pd = process.ProcessDefinition('sample')
46
αααα147
αααα148
αααα149
>>> from shoobx.wfmc import process
>>> pd = process.ProcessDefinition('sample')
50
>>> from shoobx.wfmc import process
>>> pd = process.ProcessDefinition('sample')
51
>>> from shoobx.wfmc import process
>>> pd = process.ProcessDefinition('sample')
52
>>> from shoobx.wfmc import process
>>> pd = process.ProcessDefinition('sample')
04
说明
大多数流程元素都可以有名称和说明。
< Buff行情>
>>> from shoobx.wfmc import process
>>> pd = process.ProcessDefinition('sample')
54
>>> from shoobx.wfmc import process
>>> pd = process.ProcessDefinition('sample')
55
>>> from shoobx.wfmc import process
>>> pd = process.ProcessDefinition('sample')
56
>>> from shoobx.wfmc import process
>>> pd = process.ProcessDefinition('sample')
57
>>> from shoobx.wfmc import process
>>> pd = process.ProcessDefinition('sample')
58
>>> from shoobx.wfmc import process
>>> pd = process.ProcessDefinition('sample')
59
>>> from shoobx.wfmc import process
>>> pd = process.ProcessDefinition('sample')
60
>>> from shoobx.wfmc import process
>>> pd = process.ProcessDefinition('sample')
61
>>> from shoobx.wfmc import process
>>> pd = process.ProcessDefinition('sample')
62
>>> from shoobx.wfmc import process
>>> pd = process.ProcessDefinition('sample')
63
更改
4.2.0(2018-11-12)
-
添加Python3.7支持。
-
删除python 3.5支持。
-
删除所有折旧和资源警告。
4.1.1(2018-02-08)
-
更多的python 3兼容性。
4.1.0(2018-02-06)
-
支持Python 3。
4.0.4(2017-11-01)
-
立即使
功能可插入。
4.0.3(2017-06-20)
-
什么都没变。
4.0.2(2017-05-25)
-
更新和改进trove分类器。
4.0.1(2017-05-25)
-
修复小的rest问题,以便pypi描述能够呈现出来。
4.0.0(2017-05-25)
从
zope.wfmc
重命名为
shoobx.wfmc
增加了对社区CI和覆盖工具的支持。
在单个
扩展属性
容器
使用IProcessDefinitionFactory检索流程定义,而不是
命名实用程序。这个额外的间接层允许生成
定义动态调用Y.P/P>
支持同步和异步执行WFMC子流。
子流作为主进程的一部分执行,但是它们有各自的
状态(工作流变量)。
简单的python
evaluate(expr,locals)
函数已被替换
通过pythonexpressionevaluator组件,它是来自
i处理
到
ipythonexpressionevaluator
。求值局部变量命名空间
自动填充与工作流和应用程序相关的数据
属性、进程的上下文和传入的局部变量。
evaluate()
的所有调用都已更新为使用适配器。
这种变化使得评估引擎的更换变得容易
一个安全的python引擎(即restrictedpython)并提供更多的名称空间
条目.
转换条件现在可以在
处理,而不仅仅是与工作流相关的数据。因此他们的召唤
签名从
条件(数据)
更改为
条件(过程、数据)
textcondition
已更改为使用pythonexpressionevaluator
组件。另外,编译优化也被删除了,因为
expression evalautor可以更有效地执行此操作。
支持中止流程和活动。
工作项可以通过实现
iabortworkitem
来中止。
如果工作项实现了icleanupWorkitem,则可以对其进行清理。
活动跟踪已完成的工作项。
活动可以通过清理工作项来自我清理。
流程跟踪已完成的活动。
当进程中止时,将执行以下操作:
所有活动都将中止。
所有已完成的活动都已清除。
< Buff行情>
-
在进程上设置了isaborted标志。
添加了对读取xpdl-2.1的支持
从xpdl添加了读取池和通道
3.5.0(2009年7月24日)
-
将测试更新到最新的软件包版本。
3.4.0(2007-11-02)
-
独立于主zope树的初始版本。
参与者
我们已经宣布了一些申请,我们已经把它们连接到 活动,但我们仍然没有指定任何应用程序代码。以前 我们可以指定应用程序代码,我们需要考虑 正在执行应用程序。工作流应用程序通常 由人或其他外部行为体执行。与应用程序一样, 流程定义允许声明工作流中的参与者 与活动有关。我们宣布参与者与我们 声明应用程序,除非没有参数:
< Buff行情>>>> from shoobx.wfmc import process >>> pd = process.ProcessDefinition('sample')4
在本例中,我们碰巧重用了一个活动名,但是 不是两个参与者。在定义了这些参与者之后,我们 可以将它们与活动关联:
< Buff行情>>>> from shoobx.wfmc import process >>> pd = process.ProcessDefinition('sample')5
应用程序集成
要使用流程定义来控制应用程序逻辑,我们需要 将其与"集成"对象相关联。
当流程需要获取参与者时,它调用createparticipant 在其integration属性上,传递进程id和 执行者ID。如果活动没有 执行者,则上面的过程与空的执行者ID一起使用。
类似地,当流程需要工作项时,它调用createworkitem 在其integration属性上,传递进程id和 应用程序ID.
工作项提供用于启动工作的 start 方法 并传递输入参数。这是工作项目的责任, 稍后,调用 活动,通知活动工作项 完整的。输出参数被传递到工作项finished 方法:
创建集成对象的一个简单方法是 shoobx.wfmc.attributeintegration.attributeintegration
< Buff行情>>>> from shoobx.wfmc import process >>> pd = process.ProcessDefinition('sample')6
我们将首先定义一个简单的参与者类:
< Buff行情>>>> from shoobx.wfmc import process >>> pd = process.ProcessDefinition('sample')7
>>> from shoobx.wfmc import process >>> pd = process.ProcessDefinition('sample')8
我们为每个参与者设置集成属性:
< Buff行情>>>> from shoobx.wfmc import process >>> pd = process.ProcessDefinition('sample')9
我们还为参与者定义了一个属性,用于 有表演者:
< Buff行情>----------- -->| Publish | ---------- ---------- / ----------- | Author |-->| Review |- ---------- ---------- ---------- \-->| Reject | ----------0
现在我们将定义我们的工作项。首先,我们将定义一些类:
< Buff行情>----------- -->| Publish | ---------- ---------- / ----------- | Author |-->| Review |- ---------- ---------- ---------- \-->| Reject | ----------1
----------- -->| Publish | ---------- ---------- / ----------- | Author |-->| Review |- ---------- ---------- ---------- \-->| Reject | ----------2
----------- -->| Publish | ---------- ---------- / ----------- | Author |-->| Review |- ---------- ---------- ---------- \-->| Reject | ----------3
----------- -->| Publish | ---------- ---------- / ----------- | Author |-->| Review |- ---------- ---------- ---------- \-->| Reject | ----------4
----------- -->| Publish | ---------- ---------- / ----------- | Author |-->| Review |- ---------- ---------- ---------- \-->| Reject | ----------5
然后我们将它们连接到集成对象:
< Buff行情>----------- -->| Publish | ---------- ---------- / ----------- | Author |-->| Review |- ---------- ---------- ---------- \-->| Reject | ----------6
使用工作流过程
要使用流程定义,请将其实例化并调用其start方法 开始执行:
< Buff行情>----------- -->| Publish | ---------- ---------- / ----------- | Author |-->| Review |- ---------- ---------- ---------- \-->| Reject | ----------7
我们进入作者活动,等待工作完成。 为了继续前进,我们需要找到创作工作项,这样我们就可以 完成它。我们的工作项添加到工作列表中,这样我们就可以 从列表中获取项目。
< Buff行情>----------- -->| Publish | ---------- ---------- / ----------- | Author |-->| Review |- ---------- ---------- ---------- \-->| Reject | ----------8
现在,我们可以通过调用其finish方法来完成工作项:
< Buff行情>----------- -->| Publish | ---------- ---------- / ----------- | Author |-->| Review |- ---------- ---------- ---------- \-->| Reject | ----------9
我们看到我们过渡到了审查活动。请注意 finish 方法不是工作流api的一部分。它的定义是 我们的示例类。其他应用程序可以使用不同的机制。
现在,我们将通过调用评审工作项的 完成 。我们将通过 false ,表明内容不应 出版日期:
< Buff行情>>>> pd.defineActivities( ... author = process.ActivityDefinition(), ... review = process.ActivityDefinition(), ... publish = process.ActivityDefinition(), ... reject = process.ActivityDefinition(), ... )0
排序输出转换
通常,传出转换按转换顺序排列 使用定义和给定活动的所有转换。
如果转换是以不方便的顺序定义的,则工作流 可能无法按预期工作。例如,让我们修改上面的 通过改变一些 转变。我们将重用以前的集成对象 将其传递给定义构造函数的示例:
< Buff行情>>>> pd.defineActivities( ... author = process.ActivityDefinition(), ... review = process.ActivityDefinition(), ... publish = process.ActivityDefinition(), ... reject = process.ActivityDefinition(), ... )1
>>> pd.defineActivities( ... author = process.ActivityDefinition(), ... review = process.ActivityDefinition(), ... publish = process.ActivityDefinition(), ... reject = process.ActivityDefinition(), ... )2
>>> from shoobx.wfmc import process >>> pd = process.ProcessDefinition('sample')2
>>> from shoobx.wfmc import process >>> pd = process.ProcessDefinition('sample')3
>>> from shoobx.wfmc import process >>> pd = process.ProcessDefinition('sample')4
>>> from shoobx.wfmc import process >>> pd = process.ProcessDefinition('sample')5
运行我们的流程:
< Buff行情>----------- -->| Publish | ---------- ---------- / ----------- | Author |-->| Review |- ---------- ---------- ---------- \-->| Reject | ----------7
>>> pd.defineActivities( ... author = process.ActivityDefinition(), ... review = process.ActivityDefinition(), ... publish = process.ActivityDefinition(), ... reject = process.ActivityDefinition(), ... )8
这次,我们会说我们应该发布:
< Buff行情>>>> pd.defineActivities( ... author = process.ActivityDefinition(), ... review = process.ActivityDefinition(), ... publish = process.ActivityDefinition(), ... reject = process.ActivityDefinition(), ... )9
但我们还是去了拒绝活动。为什么?因为转换 按顺序测试。因为到拒绝活动的转换是 先测试,没有条件,我们没有检查 转换到发布活动的条件。我们可以解决这个问题 通过直接在审阅者活动上指定传出转换。 为此,我们还需要在转换中指定id。让我们 重新定义流程:
< Buff行情>>>> pd.defineActivities( ... author = process.ActivityDefinition(), ... review = process.ActivityDefinition(), ... publish = process.ActivityDefinition(), ... reject = process.ActivityDefinition(), ... )1
>>> pd.defineTransitions( ... process.TransitionDefinition('author', 'review'), ... process.TransitionDefinition('review', 'publish'), ... process.TransitionDefinition('review', 'reject'), ... )1
>>> from shoobx.wfmc import process >>> pd = process.ProcessDefinition('sample')2
>>> from shoobx.wfmc import process >>> pd = process.ProcessDefinition('sample')3
>>> from shoobx.wfmc import process >>> pd = process.ProcessDefinition('sample')4
>>> from shoobx.wfmc import process >>> pd = process.ProcessDefinition('sample')5
>>> pd.defineTransitions( ... process.TransitionDefinition('author', 'review'), ... process.TransitionDefinition('review', 'publish'), ... process.TransitionDefinition('review', 'reject'), ... )6
现在,当我们运行这个过程时,我们将以 需要:
< Buff行情>----------- -->| Publish | ---------- ---------- / ----------- | Author |-->| Review |- ---------- ---------- ---------- \-->| Reject | ----------7
>>> pd.defineActivities( ... author = process.ActivityDefinition(), ... review = process.ActivityDefinition(), ... publish = process.ActivityDefinition(), ... reject = process.ActivityDefinition(), ... )8
>>> pd.defineTransitions( ... process.TransitionDefinition('author', 'review'), ... process.TransitionDefinition('review', 'publish'), ... process.TransitionDefinition('review', 'reject'), ... )9
让我们看看另一种方法,我们应该转换到拒绝:
< Buff行情>----------- -->| Publish | ---------- ---------- / ----------- | Author |-->| Review |- ---------- ---------- ---------- \-->| Reject | ----------7
>>> pd.defineActivities( ... author = process.ActivityDefinition(), ... review = process.ActivityDefinition(), ... publish = process.ActivityDefinition(), ... reject = process.ActivityDefinition(), ... )8
>>> pd.defineActivities( ... author = process.ActivityDefinition(), ... review = process.ActivityDefinition(), ... publish = process.ActivityDefinition(), ... reject = process.ActivityDefinition(), ... )0
复杂流
让我们看一个更复杂的例子。在本例中,我们将扩展 与多个审阅者一起工作的过程。我们还将 工作列表处理更复杂一些。我们还将介绍 一些新概念:
- 拆分和联接
- 处理参数
考虑出版 流程如下所示:
>>> import zope.component >>> from shoobx.wfmc.process import StaticProcessDefinitionFactory >>> pdfactory = StaticProcessDefinitionFactory() >>> zope.component.provideUtility(pdfactory) >>> pdfactory.register(pd)3
在这里,我们将流程图排列成列,其中 每个参与者的活动。我们有四个参与者, 作者、两名技术评审员和一名编辑评审员。这个 作者准备了一份草稿。作者将草稿发送到 both 技术评审员进行评审。当技术评审 完成后,编辑评论将进行初步编辑 复习。根据技术评论,编辑可以选择:
- 拒绝文档
- 按原样发布文档
- 请求技术更改(基于技术评审员 注释),或
- 请求编辑更改。
如果需要进行技术更改,则工作将返回到 "准备"活动。如果有必要进行编辑性修改,那么 流向"准备最终"活动。当作者制作了 编辑修改,工作流程到"审查最终"。编辑可以 请求其他更改,在这种情况下,工作流程返回到"准备 "最终",否则,工作将流向"发布"。
这个例子说明了不同类型的"连接"和"拆分"。这个 术语"join"是指传入活动的转换方式 处理。连接有两种:"and"和"xor"。加上"和" join,活动将等待每个传入的转换。在 本例中,"编辑评论"活动的输入构成 "和"加入。编辑评论要等到每个技术 评审完成。本例中的其余连接是 "异或"连接。活动在转换为活动时开始。
"拆分"一词是指从一个活动向外转换的方式 都处理好了。通常,一个活动的一个转换是 使用。这称为"异或"分裂。加上"和"分开,全部 使用计算结果为 true 的布尔条件转换。 在本例中,"prepare"活动有一个"and"分隔符。工作 同时流向两个技术审查活动。其余的 本例中的拆分是"异或"拆分。
让我们创建新的工作流过程。我们会重新利用现有的 集成对象:
< Buff行情>>>> import zope.component >>> from shoobx.wfmc.process import StaticProcessDefinitionFactory >>> pdfactory = StaticProcessDefinitionFactory() >>> zope.component.provideUtility(pdfactory) >>> pdfactory.register(pd)4
>>> import zope.component >>> from shoobx.wfmc.process import StaticProcessDefinitionFactory >>> pdfactory = StaticProcessDefinitionFactory() >>> zope.component.provideUtility(pdfactory) >>> pdfactory.register(pd)5
在这里,我们将字符串传递给活动定义 名字。名称必须是Unicode或ASCII字符串。
我们定义转换:
< Buff行情>>>> import zope.component >>> from shoobx.wfmc.process import StaticProcessDefinitionFactory >>> pdfactory = StaticProcessDefinitionFactory() >>> zope.component.provideUtility(pdfactory) >>> pdfactory.register(pd)6
我们指定"和"拆分并加入:
< Buff行情>>>> import zope.component >>> from shoobx.wfmc.process import StaticProcessDefinitionFactory >>> pdfactory = StaticProcessDefinitionFactory() >>> zope.component.provideUtility(pdfactory) >>> pdfactory.register(pd)7
我们定义参与者和应用程序:
< Buff行情>>>> import zope.component >>> from shoobx.wfmc.process import StaticProcessDefinitionFactory >>> pdfactory = StaticProcessDefinitionFactory() >>> zope.component.provideUtility(pdfactory) >>> pdfactory.register(pd)8
>>> import zope.component >>> from shoobx.wfmc.process import StaticProcessDefinitionFactory >>> pdfactory = StaticProcessDefinitionFactory() >>> zope.component.provideUtility(pdfactory) >>> pdfactory.register(pd)9
>>> def log_workflow(event): ... print (event)0
>>> def log_workflow(event): ... print (event)1
>>> def log_workflow(event): ... print (event)2
>>> def log_workflow(event): ... print (event)3
>>> def log_workflow(event): ... print (event)4
>>> def log_workflow(event): ... print (event)5
>>> def log_workflow(event): ... print (event)6
我们希望在启动进程时能够指定作者。 我们还想知道最后的处理过程。到 完成此操作后,我们将为流程定义参数:
< Buff行情>>>> def log_workflow(event): ... print (event)7
既然我们已经定义了流程,我们需要提供参与者和 应用程序组件。让我们从参与者开始。宁愿 与共享单个工作列表相比,我们将为每个用户提供他们自己的 工作清单。我们还将创建先前存在的参与者并返回 他们。最后,我们将创建多个作者并使用选定的作者:
< Buff行情>>>> def log_workflow(event): ... print (event)8
>>> def log_workflow(event): ... print (event)9
>>> import zope.event >>> zope.event.subscribers.append(log_workflow)0
>>> import zope.event >>> zope.event.subscribers.append(log_workflow)1
在本例中,我们需要为每个参与者定义一个单独的属性:
< Buff行情>>>> import zope.event >>> zope.event.subscribers.append(log_workflow)2
创建进程时,将传入作者名并 分配给工作流相关数据。我们的author类使用这个 选择指定用户的信息。
< Buff行情>>>> import zope.event >>> zope.event.subscribers.append(log_workflow)3
>>> import zope.event >>> zope.event.subscribers.append(log_workflow)4
>>> import zope.event >>> zope.event.subscribers.append(log_workflow)5
我们将利用我们的原始参与课程进行 表演者:
< Buff行情>----------- -->| Publish | ---------- ---------- / ----------- | Author |-->| Review |- ---------- ---------- ---------- \-->| Reject | ----------0
现在我们将创建我们的应用程序。让我们从作者开始:
< Buff行情>>>> import zope.event >>> zope.event.subscribers.append(log_workflow)7
>>> import zope.event >>> zope.event.subscribers.append(log_workflow)8
>>> import zope.event >>> zope.event.subscribers.append(log_workflow)9
因为我们使用了"准备修订申请"和"初始修订申请" 准备,我们提供了一个总结方法来说明我们必须做什么。
这里我们得到作者创建的文档,它作为 finish方法的参数。在更现实的实施中, author任务将在任务开始时创建文档,并且 提供用户界面供用户编辑。我们存储 文档作为应用程序相关数据,因为我们希望审阅者 能够访问它,但我们不需要它直接用于工作流 控制,
< Buff行情>>>> proc = pd()0
>>> proc = pd()1
在这里,我们提供了一种访问原始文档的方法。
< Buff行情>>>> proc = pd()2
>>> proc = pd()3
在这个实现中,如果 技术编辑建议拒绝并将工作发回 如果有任何技术变更,请做好准备。我们还将 techreview 获取 getdoc 方法。
我们将重用前一个应用程序中的 publish 和 reject 应用程序 例子:
< Buff行情>>>> proc = pd()4
>>> proc = pd()5
在这个应用程序中,我们只是更新文档以反映 变化:
< Buff行情>>>> proc = pd()6
>>> proc = pd()7
我们的进程现在返回数据。当我们创建一个流程时,我们需要 提供一个可以调用的对象:
< Buff行情>>>> proc = pd()8
现在,让我们试试我们的流程:
< Buff行情>>>> proc = pd()9
我们应该在鲍勃的工作清单上加上一项。我们去拿吧 完成它,提交文档:
< Buff行情>>>> proc.start() ProcessStarted(Process('sample')) Transition(None, Activity('sample.author')) ActivityStarted(Activity('sample.author')) ActivityFinished(Activity('sample.author')) Transition(Activity('sample.author'), Activity('sample.review')) ActivityStarted(Activity('sample.review')) ActivityFinished(Activity('sample.review')) Transition(Activity('sample.review'), Activity('sample.publish')) ActivityStarted(Activity('sample.publish')) ActivityFinished(Activity('sample.publish')) ProcessFinished(Process('sample'))0
注意,我们转换到了 两个 活动, tech1 和 技术2 。这是因为准备活动有一个"和"分隔。 现在我们做一个技术回顾。让我们看看Tech1有哪些功能:
< Buff行情>>>> proc.start() ProcessStarted(Process('sample')) Transition(None, Activity('sample.author')) ActivityStarted(Activity('sample.author')) ActivityFinished(Activity('sample.author')) Transition(Activity('sample.author'), Activity('sample.review')) ActivityStarted(Activity('sample.review')) ActivityFinished(Activity('sample.review')) Transition(Activity('sample.review'), Activity('sample.publish')) ActivityStarted(Activity('sample.publish')) ActivityFinished(Activity('sample.publish')) ProcessFinished(Process('sample'))1
让我们告诉作者将"美国人"改为"地球人":
< Buff行情>>>> proc.start() ProcessStarted(Process('sample')) Transition(None, Activity('sample.author')) ActivityStarted(Activity('sample.author')) ActivityFinished(Activity('sample.author')) Transition(Activity('sample.author'), Activity('sample.review')) ActivityStarted(Activity('sample.review')) ActivityFinished(Activity('sample.review')) Transition(Activity('sample.review'), Activity('sample.publish')) ActivityStarted(Activity('sample.publish')) ActivityFinished(Activity('sample.publish')) ProcessFinished(Process('sample'))2
在这里我们转到了编辑评论活动,但是我们没有 开始吧。这是因为编辑评论活动有一个"and" 连接,这意味着在两个转换都 发生。
现在我们将进行另一项技术回顾:
< Buff行情>>>> proc.start() ProcessStarted(Process('sample')) Transition(None, Activity('sample.author')) ActivityStarted(Activity('sample.author')) ActivityFinished(Activity('sample.author')) Transition(Activity('sample.author'), Activity('sample.review')) ActivityStarted(Activity('sample.review')) ActivityFinished(Activity('sample.review')) Transition(Activity('sample.review'), Activity('sample.publish')) ActivityStarted(Activity('sample.publish')) ActivityFinished(Activity('sample.publish')) ProcessFinished(Process('sample'))3
现在,当我们转到编辑评论活动时,我们开始 因为每个输入转换都发生了。我们的社论 审核申请自动将工作发回准备, 因为有技术评论。当然,作者仍然是鲍勃。 让我们发表评论:
< Buff行情>>>> proc.start() ProcessStarted(Process('sample')) Transition(None, Activity('sample.author')) ActivityStarted(Activity('sample.author')) ActivityFinished(Activity('sample.author')) Transition(Activity('sample.author'), Activity('sample.review')) ActivityStarted(Activity('sample.review')) ActivityFinished(Activity('sample.review')) Transition(Activity('sample.review'), Activity('sample.publish')) ActivityStarted(Activity('sample.publish')) ActivityFinished(Activity('sample.publish')) ProcessFinished(Process('sample'))4
>>> proc.start() ProcessStarted(Process('sample')) Transition(None, Activity('sample.author')) ActivityStarted(Activity('sample.author')) ActivityFinished(Activity('sample.author')) Transition(Activity('sample.author'), Activity('sample.review')) ActivityStarted(Activity('sample.review')) ActivityFinished(Activity('sample.review')) Transition(Activity('sample.review'), Activity('sample.publish')) ActivityStarted(Activity('sample.publish')) ActivityFinished(Activity('sample.publish')) ProcessFinished(Process('sample'))5
和以前一样,在完成最初的编辑之后,我们开始 再次回顾活动。我们再复习一遍。这次,我们没有 注释,因为作者应用了我们请求的更改:
< Buff行情>>>> proc.start() ProcessStarted(Process('sample')) Transition(None, Activity('sample.author')) ActivityStarted(Activity('sample.author')) ActivityFinished(Activity('sample.author')) Transition(Activity('sample.author'), Activity('sample.review')) ActivityStarted(Activity('sample.review')) ActivityFinished(Activity('sample.review')) Transition(Activity('sample.review'), Activity('sample.publish')) ActivityStarted(Activity('sample.publish')) ActivityFinished(Activity('sample.publish')) ProcessFinished(Process('sample'))6
>>> proc.start() ProcessStarted(Process('sample')) Transition(None, Activity('sample.author')) ActivityStarted(Activity('sample.author')) ActivityFinished(Activity('sample.author')) Transition(Activity('sample.author'), Activity('sample.review')) ActivityStarted(Activity('sample.review')) ActivityFinished(Activity('sample.review')) Transition(Activity('sample.review'), Activity('sample.publish')) ActivityStarted(Activity('sample.publish')) ActivityFinished(Activity('sample.publish')) ProcessFinished(Process('sample'))7
这次,我们留在技术评审活动中,因为 没有任何技术上的改变。我们准备好做社论评论了。 我们将请求编辑更改:
< Buff行情>>>> proc.start() ProcessStarted(Process('sample')) Transition(None, Activity('sample.author')) ActivityStarted(Activity('sample.author')) ActivityFinished(Activity('sample.author')) Transition(Activity('sample.author'), Activity('sample.review')) ActivityStarted(Activity('sample.review')) ActivityFinished(Activity('sample.review')) Transition(Activity('sample.review'), Activity('sample.publish')) ActivityStarted(Activity('sample.publish')) ActivityFinished(Activity('sample.publish')) ProcessFinished(Process('sample'))8
>>> proc.start() ProcessStarted(Process('sample')) Transition(None, Activity('sample.author')) ActivityStarted(Activity('sample.author')) ActivityFinished(Activity('sample.author')) Transition(Activity('sample.author'), Activity('sample.review')) ActivityStarted(Activity('sample.review')) ActivityFinished(Activity('sample.review')) Transition(Activity('sample.review'), Activity('sample.publish')) ActivityStarted(Activity('sample.publish')) ActivityFinished(Activity('sample.publish')) ProcessFinished(Process('sample'))9
因为我们要求修改社论,所以我们转到了决赛 编辑活动,以便作者(仍然是bob)可以进行更改:
< Buff行情> α>>> from shoobx.wfmc import process >>> pd = process.ProcessDefinition('sample')00
>>> from shoobx.wfmc import process >>> pd = process.ProcessDefinition('sample')01
我们转向行动用于审阅最终编辑的ITY。我们 审阅文档并批准发布:
< Buff行情>>>> from shoobx.wfmc import process >>> pd = process.ProcessDefinition('sample')02
>>> from shoobx.wfmc import process >>> pd = process.ProcessDefinition('sample')03
在这一点上,剩下的过程会自动完成。在 此外,决策记录在流程上下文对象中:
< Buff行情>>>> from shoobx.wfmc import process >>> pd = process.ProcessDefinition('sample')04
即将推出
- 超时/异常
另请参见
http://www.wfmc.org http://www.wfmc.org/standards/standards.htm
xpdl导入
我们可以从xml进程中的文件导入进程定义 定义语言(xpdl)格式。xpdl文件包含多个 在包中排列的进程定义。当我们加载文件时 获取包含一些进程定义的包。
让我们看一个例子。文件 publication.xpdl 包含在 "readme.txt"文件。我们可以使用xpdl模块阅读:
< Buff行情>>>> from shoobx.wfmc import process >>> pd = process.ProcessDefinition('sample')05
此软件包包含单个定义:
< Buff行情>>>> from shoobx.wfmc import process >>> pd = process.ProcessDefinition('sample')06
>>> from shoobx.wfmc import process >>> pd = process.ProcessDefinition('sample')07
现在,在阅读了流程定义之后,我们可以像以前那样使用它 之前(在"readme.txt"中)。和以前一样,我们将创建一个事件订阅服务器 这样我们就可以看到发生了什么:
< Buff行情>>>> from shoobx.wfmc import process >>> pd = process.ProcessDefinition('sample')08
>>> import zope.event >>> zope.event.subscribers.append(log_workflow)
我们将把进程定义注册为实用程序:
< Buff行情>>>> import zope.component >>> from shoobx.wfmc.process import StaticProcessDefinitionFactory >>> pdfactory = StaticProcessDefinitionFactory() >>> zope.component.provideUtility(pdfactory) >>> pdfactory.register(pd)
我们将定义并注册参与者和应用程序适配器:
< Buff行情>>>> from shoobx.wfmc import process >>> pd = process.ProcessDefinition('sample')7
>>> from shoobx.wfmc import process >>> pd = process.ProcessDefinition('sample')8
>>> def log_workflow(event): ... print (event)8
>>> def log_workflow(event): ... print (event)9
>>> import zope.event >>> zope.event.subscribers.append(log_workflow)0
>>> from shoobx.wfmc import process >>> pd = process.ProcessDefinition('sample')16
>>> import zope.event >>> zope.event.subscribers.append(log_workflow)2
>>> import zope.event >>> zope.event.subscribers.append(log_workflow)3
>>> import zope.event >>> zope.event.subscribers.append(log_workflow)4
>>> import zope.event >>> zope.event.subscribers.append(log_workflow)5
>>> from shoobx.wfmc import process >>> pd = process.ProcessDefinition('sample')21
>>> import zope.event >>> zope.event.subscribers.append(log_workflow)7
>>> from shoobx.wfmc import process >>> pd = process.ProcessDefinition('sample')23
>>> import zope.event >>> zope.event.subscribers.append(log_workflow)9
>>> proc = pd()0
>>> proc = pd()1
>>> from shoobx.wfmc import process >>> pd = process.ProcessDefinition('sample')27
>>> proc = pd()3
>>> from shoobx.wfmc import process >>> pd = process.ProcessDefinition('sample')29
>>> proc = pd()5
>>> from shoobx.wfmc import process >>> pd = process.ProcessDefinition('sample')31
>>> proc = pd()7
>>> from shoobx.wfmc import process >>> pd = process.ProcessDefinition('sample')33
>>> from shoobx.wfmc import process >>> pd = process.ProcessDefinition('sample')34
>>> from shoobx.wfmc import process >>> pd = process.ProcessDefinition('sample')35
>>> from shoobx.wfmc import process >>> pd = process.ProcessDefinition('sample')36
以及进程上下文,以便我们可以传递参数:
< Buff行情>>>> proc = pd()8
现在,让我们试试我们的流程。我们会按照之前的步骤 "readme.txt",得到相同的结果:
< Buff行情> αααα138>>> from shoobx.wfmc import process >>> pd = process.ProcessDefinition('sample')39
>>> from shoobx.wfmc import process >>> pd = process.ProcessDefinition('sample')40
>>> from shoobx.wfmc import process >>> pd = process.ProcessDefinition('sample')41
>>> from shoobx.wfmc import process >>> pd = process.ProcessDefinition('sample')42 αααα143
>>> from shoobx.wfmc import process >>> pd = process.ProcessDefinition('sample')44
>>> from shoobx.wfmc import process >>> pd = process.ProcessDefinition('sample')45
>>> from shoobx.wfmc import process >>> pd = process.ProcessDefinition('sample')46 αααα147 αααα148 αααα149
>>> from shoobx.wfmc import process >>> pd = process.ProcessDefinition('sample')50
>>> from shoobx.wfmc import process >>> pd = process.ProcessDefinition('sample')51
>>> from shoobx.wfmc import process >>> pd = process.ProcessDefinition('sample')52
>>> from shoobx.wfmc import process >>> pd = process.ProcessDefinition('sample')04
说明
大多数流程元素都可以有名称和说明。
< Buff行情>>>> from shoobx.wfmc import process >>> pd = process.ProcessDefinition('sample')54
>>> from shoobx.wfmc import process >>> pd = process.ProcessDefinition('sample')55
>>> from shoobx.wfmc import process >>> pd = process.ProcessDefinition('sample')56
>>> from shoobx.wfmc import process >>> pd = process.ProcessDefinition('sample')57
>>> from shoobx.wfmc import process >>> pd = process.ProcessDefinition('sample')58
>>> from shoobx.wfmc import process >>> pd = process.ProcessDefinition('sample')59
>>> from shoobx.wfmc import process >>> pd = process.ProcessDefinition('sample')60
>>> from shoobx.wfmc import process >>> pd = process.ProcessDefinition('sample')61
>>> from shoobx.wfmc import process >>> pd = process.ProcessDefinition('sample')62
>>> from shoobx.wfmc import process >>> pd = process.ProcessDefinition('sample')63
更改
4.2.0(2018-11-12)
- 添加Python3.7支持。
- 删除python 3.5支持。
- 删除所有折旧和资源警告。
4.1.1(2018-02-08)
- 更多的python 3兼容性。
4.1.0(2018-02-06)
- 支持Python 3。
4.0.4(2017-11-01)
- 立即使 功能可插入。
4.0.3(2017-06-20)
- 什么都没变。
4.0.2(2017-05-25)
- 更新和改进trove分类器。
4.0.1(2017-05-25)
- 修复小的rest问题,以便pypi描述能够呈现出来。
4.0.0(2017-05-25)
从 zope.wfmc 重命名为 shoobx.wfmc
增加了对社区CI和覆盖工具的支持。
在单个 扩展属性 容器
使用IProcessDefinitionFactory检索流程定义,而不是 命名实用程序。这个额外的间接层允许生成 定义动态调用Y.P/P>
支持同步和异步执行WFMC子流。 子流作为主进程的一部分执行,但是它们有各自的 状态(工作流变量)。
简单的python evaluate(expr,locals) 函数已被替换 通过pythonexpressionevaluator组件,它是来自 i处理 到 ipythonexpressionevaluator 。求值局部变量命名空间 自动填充与工作流和应用程序相关的数据 属性、进程的上下文和传入的局部变量。
evaluate() 的所有调用都已更新为使用适配器。
这种变化使得评估引擎的更换变得容易 一个安全的python引擎(即restrictedpython)并提供更多的名称空间 条目.
转换条件现在可以在 处理,而不仅仅是与工作流相关的数据。因此他们的召唤 签名从 条件(数据) 更改为 条件(过程、数据)
textcondition 已更改为使用pythonexpressionevaluator 组件。另外,编译优化也被删除了,因为 expression evalautor可以更有效地执行此操作。
支持中止流程和活动。
工作项可以通过实现 iabortworkitem 来中止。
如果工作项实现了icleanupWorkitem,则可以对其进行清理。
活动跟踪已完成的工作项。
活动可以通过清理工作项来自我清理。
流程跟踪已完成的活动。
当进程中止时,将执行以下操作:
所有活动都将中止。
所有已完成的活动都已清除。
< Buff行情>- 在进程上设置了isaborted标志。
添加了对读取xpdl-2.1的支持
从xpdl添加了读取池和通道
3.5.0(2009年7月24日)
- 将测试更新到最新的软件包版本。
3.4.0(2007-11-02)
- 独立于主zope树的初始版本。