camunda-python 0.1.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (46) hide show
  1. camunda/__init__.py +10 -0
  2. camunda/api/__init__.py +14 -0
  3. camunda/api/app.py +80 -0
  4. camunda/api/deps.py +17 -0
  5. camunda/api/errors.py +84 -0
  6. camunda/api/pagination.py +74 -0
  7. camunda/api/routers/__init__.py +5 -0
  8. camunda/api/routers/decision.py +57 -0
  9. camunda/api/routers/deployment.py +139 -0
  10. camunda/api/routers/history.py +128 -0
  11. camunda/api/routers/process_definition.py +49 -0
  12. camunda/api/routers/process_instance.py +106 -0
  13. camunda/api/routers/task.py +92 -0
  14. camunda/api/schemas.py +200 -0
  15. camunda/common/__init__.py +19 -0
  16. camunda/common/clock.py +30 -0
  17. camunda/common/exceptions.py +34 -0
  18. camunda/common/idgen.py +23 -0
  19. camunda/common/timers.py +106 -0
  20. camunda/dmn/__init__.py +5 -0
  21. camunda/dmn/engine.py +219 -0
  22. camunda/dmn/feel.py +392 -0
  23. camunda/engine/__init__.py +9 -0
  24. camunda/engine/behavior.py +51 -0
  25. camunda/engine/expression.py +126 -0
  26. camunda/engine/process_engine.py +3237 -0
  27. camunda/job/__init__.py +9 -0
  28. camunda/job/executor.py +136 -0
  29. camunda/model/__init__.py +48 -0
  30. camunda/model/bpmn.py +326 -0
  31. camunda/model/dmn.py +101 -0
  32. camunda/model/execution.py +121 -0
  33. camunda/model/job.py +88 -0
  34. camunda/model/task.py +33 -0
  35. camunda/model/variable.py +35 -0
  36. camunda/parser/__init__.py +5 -0
  37. camunda/parser/bpmn_parser.py +646 -0
  38. camunda/parser/dmn_parser.py +225 -0
  39. camunda/persistence/__init__.py +21 -0
  40. camunda/persistence/entities.py +202 -0
  41. camunda/persistence/store.py +721 -0
  42. camunda_python-0.1.0.dist-info/METADATA +377 -0
  43. camunda_python-0.1.0.dist-info/RECORD +46 -0
  44. camunda_python-0.1.0.dist-info/WHEEL +5 -0
  45. camunda_python-0.1.0.dist-info/licenses/LICENSE +200 -0
  46. camunda_python-0.1.0.dist-info/top_level.txt +1 -0
@@ -0,0 +1,121 @@
1
+ """运行时执行模型:Execution 树 / ProcessInstance / ActivityInstance。
2
+
3
+ 对齐 Camunda ACT_RU_EXECUTION 语义:
4
+ - ProcessInstance 是树的根(process_instance_id == 根 execution id 场景下,Camunda
5
+ 的 root execution 与 process instance 是两条记录,这里 M1 合并为一条根 Execution)
6
+ - 并行网关 fork 时创建子 Execution(parent 停驻成为 scope)
7
+ - 每条「活动中的路径」由一条 Execution 携带:activity_id 指向当前所在节点
8
+ """
9
+
10
+ from __future__ import annotations
11
+
12
+ from dataclasses import dataclass, field
13
+ from enum import Enum
14
+ from typing import Any, Dict, List, Optional, TYPE_CHECKING
15
+
16
+ if TYPE_CHECKING: # 仅类型检查,避免与 task.py 循环(task 不依赖 execution)
17
+ from camunda.model.task import Task
18
+
19
+
20
+ class ExecutionState(str, Enum):
21
+ ACTIVE = "ACTIVE" # 正等待:用户任务 / join / scope 停驻
22
+ ENDED = "ENDED" # 已走完(endEvent 或实例结束)
23
+
24
+
25
+ class ProcessInstanceState(str, Enum):
26
+ ACTIVE = "ACTIVE"
27
+ COMPLETED = "COMPLETED" # 正常走完 endEvent
28
+ TERMINATED = "TERMINATED" # 保留字段(M3+ 支持终止)
29
+
30
+
31
+ @dataclass
32
+ class Execution:
33
+ """一条执行路径(token 载体)。id 全局唯一。
34
+
35
+ role:
36
+ - TOKEN : 活动 token,沿流程推进,可停在 userTask / join 等待
37
+ - SCOPE : 并行 fork 后停驻的父 execution(等待子 TOKEN 完成后再恢复)
38
+ """
39
+
40
+ id: str
41
+ process_instance_id: str
42
+ parent_id: Optional[str] = None
43
+ role: str = "TOKEN" # TOKEN | SCOPE
44
+ # None 表示该 execution 当前不在具体活动上(如 fork 后等待、根 scope)
45
+ activity_id: Optional[str] = None
46
+ state: ExecutionState = ExecutionState.ACTIVE
47
+ # 子 execution(并行网关 fork 产生)
48
+ children: List["Execution"] = field(default_factory=list)
49
+ # 当前停留活动实例(_open_activity 写入,_close_activity 结算时间后清空)
50
+ open_activity: Optional["ActivityInstance"] = None
51
+ # 多实例状态(M4-2c):None = 非多实例执行。
52
+ # MI 容器(有 "total" 键):{sequential, total, active, completed, next_index,
53
+ # items, element_variable, completion_condition} —— parallel 容器挂在转 SCOPE
54
+ # 的宿主 token 上;sequential 容器挂在宿主 token 自身(token 兼作实例载体)。
55
+ # MI 实例(仅并行 child,{"index": i}):标识该实例序号(收束回报计数用)。
56
+ mi: Optional[Dict[str, Any]] = None
57
+
58
+ # ---- 便捷 ----
59
+ @property
60
+ def is_root(self) -> bool:
61
+ return self.parent_id is None
62
+
63
+ def is_ended(self) -> bool:
64
+ return self.state == ExecutionState.ENDED
65
+
66
+ @property
67
+ def is_mi_container(self) -> bool:
68
+ """是否为多实例容器载体(挂 total 键的 MI 状态)。"""
69
+ return self.mi is not None and "total" in self.mi
70
+
71
+
72
+ @dataclass
73
+ class ActivityInstance:
74
+ """活动实例历史痕迹(M1 内存版,M2 落 ACT_HI_ACTINST)。
75
+
76
+ 每次「进入某节点」记录一条,start_time 进入、end_time 离开。
77
+ """
78
+
79
+ id: str
80
+ process_instance_id: str
81
+ activity_id: str
82
+ activity_name: Optional[str] = None
83
+ execution_id: str = ""
84
+ start_time: Optional[str] = None
85
+ end_time: Optional[str] = None
86
+
87
+
88
+ @dataclass
89
+ class ProcessInstance:
90
+ """流程实例(对齐 ACT_HI_PROCINST 运行时视图)。"""
91
+
92
+ id: str
93
+ process_definition_key: str
94
+ business_key: Optional[str] = None
95
+ state: ProcessInstanceState = ProcessInstanceState.ACTIVE
96
+ variables: Dict[str, Any] = field(default_factory=dict)
97
+ root_execution: Optional[Execution] = None
98
+ start_time: Optional[str] = None
99
+ end_time: Optional[str] = None
100
+ # execution id 索引(与树冗余,便于 O(1) 查找)
101
+ executions: Dict[str, Execution] = field(default_factory=dict)
102
+ # 并行网关 join 到达登记:gateway_id -> 已到达的 execution id 列表
103
+ join_arrivals: Dict[str, List[str]] = field(default_factory=dict)
104
+ # 活动痕迹(ACT_HI_ACTINST 内存版)
105
+ activity_history: List[ActivityInstance] = field(default_factory=list)
106
+ # 已完成任务归档(complete 后从 engine 任务表移入,HI_TASKINST 落库)
107
+ completed_tasks: List["Task"] = field(default_factory=list)
108
+
109
+ @property
110
+ def is_completed(self) -> bool:
111
+ return self.state != ProcessInstanceState.ACTIVE
112
+
113
+ # ---- 并行网关 join 辅助 ----
114
+ def register_join_arrival(self, join_activity_id: str, execution_id: str) -> None:
115
+ self.join_arrivals.setdefault(join_activity_id, []).append(execution_id)
116
+
117
+ def join_arrived(self, join_activity_id: str) -> List[str]:
118
+ return self.join_arrivals.get(join_activity_id, [])
119
+
120
+ def clear_join_arrivals(self, join_activity_id: str) -> None:
121
+ self.join_arrivals.pop(join_activity_id, None)
camunda/model/job.py ADDED
@@ -0,0 +1,88 @@
1
+ """可调度作业模型(对齐 ACT_RU_JOB 语义,M3)。
2
+
3
+ Camunda JobEntity 关键字段:ID_ / TYPE_ / DUEDATE_ / RETRIES_ / LOCK_OWNER_ /
4
+ LOCK_EXP_TIME_ / EXECUTION_ID_ / PROCESS_INSTANCE_ID_ / PROCESS_DEFINITION_ID_ /
5
+ ACTIVITY_ID_。M3 保留核心子集。
6
+
7
+ job_type(对齐 Camunda Job.TYPE_ 取值语义):
8
+ - "timer-catch" : token 停在 intermediateCatchEvent(timer),duedate 到期继续流转
9
+ - "timer-start" : 定义级作业(无 process_instance),到点启动流程实例;
10
+ timerCycle 触发后按 repeat 续排下一个 duedate
11
+ - "timer-boundary" : timer 边界事件(M4-1 中断式;M4-2b4 起 cancelActivity=false
12
+ 非中断式 = 触发不取消宿主、spawn 并发线)。宿主活动等待期内
13
+ 到点触发,中断式取消宿主并让 token 改走边界事件出边
14
+ - "timer-event-start" : 事件子流程的 timer start 订阅(M4-2b3,实例级,execution_id
15
+ = 宿主 scope,activity_id = 订阅容器 subProcess id,None=
16
+ 流程级=根 Process 容器)。宿主 scope 激活期单发,到点触发
17
+ 中断式(取消宿主)或非中断式(并行 spawn)事件子流程
18
+ - "async-continuation" : camunda:asyncBefore 拆分出的「节点行为执行」作业
19
+ (Camunda 里即 async continuation job)
20
+ - "async-after" : camunda:asyncAfter 拆分出的「离开推进」作业(M4-1;
21
+ serviceTask/XOR 行为完成后异步流转,XOR 离开时重求值条件)
22
+ """
23
+
24
+ from __future__ import annotations
25
+
26
+ from dataclasses import dataclass, field
27
+ from typing import Any, Dict, Optional
28
+
29
+ # 默认重试次数与失败延迟(对齐 Camunda 默认行为;M3 不解析 failedJobRetryTimeCycle,
30
+ # retry 间隔固定可配。文档化差异)
31
+ DEFAULT_MAX_RETRIES = 3
32
+ DEFAULT_RETRY_DELAY_SECONDS = 5.0
33
+
34
+
35
+ @dataclass
36
+ class Job:
37
+ """一条待执行作业。"""
38
+
39
+ id: str
40
+ job_type: str # timer-catch | timer-start | async-continuation
41
+ duedate: str # 定长 ISO "%Y-%m-%dT%H:%M:%S"(与 clock.now() 同格式,可字典序比较)
42
+ created: str
43
+ # 实例级(timer-catch / async-continuation)
44
+ process_instance_id: Optional[str] = None
45
+ execution_id: Optional[str] = None
46
+ # 定义级(timer-start):指向 process key;node_id 为 startEvent id
47
+ process_definition_key: Optional[str] = None
48
+ node_id: Optional[str] = None
49
+ # timer-event-start:订阅容器 subProcess id(None = 流程级/根 Process 容器);
50
+ # 与 execution_id(宿主 scope)共同唯一定位「哪个容器上的订阅」,撤销精确匹配
51
+ activity_id: Optional[str] = None
52
+ # 重试策略
53
+ retries: int = DEFAULT_MAX_RETRIES
54
+ max_retries: int = DEFAULT_MAX_RETRIES
55
+ retry_delay_seconds: float = DEFAULT_RETRY_DELAY_SECONDS
56
+ # timer-start cycle 续排参数({"kind": "interval"|"cron", ...},见 common/timers)
57
+ repeat: Optional[Dict[str, Any]] = None
58
+ # 抢占锁(多实例 JobExecutor 预留;M3 单进程不使用)
59
+ lock_owner: Optional[str] = None
60
+ lock_expire_time: Optional[str] = None
61
+
62
+ @property
63
+ def is_definition_level(self) -> bool:
64
+ """定义级作业(timer-start)不挂在任何实例上。"""
65
+ return self.process_instance_id is None
66
+
67
+ def is_due(self, now: str) -> bool:
68
+ return self.duedate <= now
69
+
70
+ def is_dead(self) -> bool:
71
+ return self.retries <= 0
72
+
73
+ def to_dict(self) -> dict:
74
+ return {
75
+ "id": self.id,
76
+ "job_type": self.job_type,
77
+ "process_instance_id": self.process_instance_id,
78
+ "execution_id": self.execution_id,
79
+ "process_definition_key": self.process_definition_key,
80
+ "node_id": self.node_id,
81
+ "activity_id": self.activity_id,
82
+ "duedate": self.duedate,
83
+ "created": self.created,
84
+ "retries": self.retries,
85
+ "repeat": self.repeat,
86
+ "lock_owner": self.lock_owner,
87
+ "lock_expire_time": self.lock_expire_time,
88
+ }
camunda/model/task.py ADDED
@@ -0,0 +1,33 @@
1
+ """人工任务模型(对齐 ACT_RU_TASK 语义)。"""
2
+
3
+ from __future__ import annotations
4
+
5
+ from dataclasses import dataclass, field
6
+ from typing import List, Optional
7
+
8
+
9
+ @dataclass
10
+ class Task:
11
+ """用户任务运行时实例:等待用户 complete。"""
12
+
13
+ id: str
14
+ name: Optional[str] = None
15
+ process_instance_id: str = ""
16
+ execution_id: str = "" # 持有该任务的 execution
17
+ task_definition_key: str = "" # BPMN userTask id
18
+ assignee: Optional[str] = None
19
+ candidate_users: List[str] = field(default_factory=list)
20
+ candidate_groups: List[str] = field(default_factory=list)
21
+ create_time: Optional[str] = None
22
+ end_time: Optional[str] = None # complete 后写入(HI_TASKINST 归档)
23
+
24
+ def to_dict(self) -> dict:
25
+ return {
26
+ "id": self.id,
27
+ "name": self.name,
28
+ "process_instance_id": self.process_instance_id,
29
+ "task_definition_key": self.task_definition_key,
30
+ "assignee": self.assignee,
31
+ "create_time": self.create_time,
32
+ "end_time": self.end_time,
33
+ }
@@ -0,0 +1,35 @@
1
+ """流程变量体系(M1 简化版)。
2
+
3
+ 对齐 Camunda 变量语义的 Python 映射:
4
+ - Camunda 变量的 Java 类型名 -> Python 类型判断,序列化策略 JSON
5
+ - ObjectValue(Java 序列化对象)在 Python 侧无等价物:M1 用 JSON 可序列化对象表示,
6
+ 文档化差异(M2 持久化时落 TEXT/JSON 列)
7
+ """
8
+
9
+ from __future__ import annotations
10
+
11
+ from typing import Any, Dict
12
+
13
+ # Java 类型 -> 判定函数(按需扩展)
14
+ _JAVA_TYPE_OF = [
15
+ ("String", lambda v: isinstance(v, str)),
16
+ ("Integer", lambda v: isinstance(v, int) and not isinstance(v, bool)),
17
+ ("Boolean", lambda v: isinstance(v, bool)),
18
+ ("Double", lambda v: isinstance(v, float)),
19
+ ]
20
+
21
+
22
+ def java_type_name(value: Any) -> str:
23
+ """推断变量值的 Java 类型名(Camunda REST API 的 type 字段)。"""
24
+ for name, check in _JAVA_TYPE_OF:
25
+ if check(value):
26
+ return name
27
+ return "Object" # dict/list/None 等统一按对象处理
28
+
29
+
30
+ def to_typed_dict(variables: Dict[str, Any]) -> Dict[str, dict]:
31
+ """把 {key: value} 转成 Camunda REST 风格 {key: {type, value}}(供 API 层/调试用)。"""
32
+ return {
33
+ k: {"type": java_type_name(v), "value": v}
34
+ for k, v in variables.items()
35
+ }
@@ -0,0 +1,5 @@
1
+ """parser 包:BPMN 2.0 XML 解析(lxml 自研,对齐 Camunda bpmn-model 职责)。"""
2
+
3
+ from camunda.parser.bpmn_parser import parse_bpmn_xml, parse_bpmn_file
4
+
5
+ __all__ = ["parse_bpmn_xml", "parse_bpmn_file"]