processcube-etw-library 2026.1.22.145211__py3-none-any.whl → 2026.1.29.103633__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.
- processcube_etw_library/__init__.py +7 -5
- processcube_etw_library/create_external_task_client.py +4 -2
- processcube_etw_library/etw_app.py +18 -5
- processcube_etw_library/health/built_in.py +3 -4
- processcube_etw_library/health/check.py +14 -4
- processcube_etw_library/identity_provider.py +0 -2
- processcube_etw_library/processcube_client/__init__.py +22 -0
- processcube_etw_library/processcube_client/app_info/__init__.py +1 -0
- processcube_etw_library/processcube_client/app_info/app_info_client.py +36 -0
- processcube_etw_library/processcube_client/client_factory.py +37 -0
- processcube_etw_library/processcube_client/core/__init__.py +2 -0
- processcube_etw_library/processcube_client/core/api/__init__.py +13 -0
- processcube_etw_library/processcube_client/core/api/base_client.py +235 -0
- processcube_etw_library/processcube_client/core/api/client.py +816 -0
- processcube_etw_library/processcube_client/core/api/helpers/__init__.py +0 -0
- processcube_etw_library/processcube_client/core/api/helpers/application_info.py +34 -0
- processcube_etw_library/processcube_client/core/api/helpers/data_object_instances.py +61 -0
- processcube_etw_library/processcube_client/core/api/helpers/empty_tasks.py +86 -0
- processcube_etw_library/processcube_client/core/api/helpers/events.py +39 -0
- processcube_etw_library/processcube_client/core/api/helpers/external_tasks.py +142 -0
- processcube_etw_library/processcube_client/core/api/helpers/flow_node_instances.py +80 -0
- processcube_etw_library/processcube_client/core/api/helpers/manual_tasks.py +87 -0
- processcube_etw_library/processcube_client/core/api/helpers/process_definitions.py +46 -0
- processcube_etw_library/processcube_client/core/api/helpers/process_instances.py +96 -0
- processcube_etw_library/processcube_client/core/api/helpers/process_models.py +51 -0
- processcube_etw_library/processcube_client/core/api/helpers/user_tasks.py +130 -0
- processcube_etw_library/processcube_client/core/base_client.py +175 -0
- processcube_etw_library/processcube_client/core/loop_helper.py +200 -0
- processcube_etw_library/processcube_client/event/__init__.py +1 -0
- processcube_etw_library/processcube_client/event/event_client.py +43 -0
- processcube_etw_library/processcube_client/external_task/__init__.py +3 -0
- processcube_etw_library/processcube_client/external_task/client_wrapper.py +28 -0
- processcube_etw_library/processcube_client/external_task/external_task_client.py +195 -0
- processcube_etw_library/processcube_client/external_task/external_task_worker.py +205 -0
- processcube_etw_library/processcube_client/external_task/functional_error.py +17 -0
- processcube_etw_library/processcube_client/flow_node_instance/__init__.py +1 -0
- processcube_etw_library/processcube_client/flow_node_instance/flow_node_instance_client.py +43 -0
- processcube_etw_library/processcube_client/notification/__init__.py +1 -0
- processcube_etw_library/processcube_client/notification/notification_client.py +103 -0
- processcube_etw_library/processcube_client/process_definition/__init__.py +2 -0
- processcube_etw_library/processcube_client/process_definition/process_definition_client.py +94 -0
- processcube_etw_library/processcube_client/process_definition/start_callback_type.py +6 -0
- processcube_etw_library/processcube_client/process_instance/__init__.py +1 -0
- processcube_etw_library/processcube_client/process_instance/process_instance_client.py +32 -0
- processcube_etw_library/processcube_client/user_task/__init__.py +1 -0
- processcube_etw_library/processcube_client/user_task/user_task_client.py +63 -0
- processcube_etw_library/settings.py +35 -9
- {processcube_etw_library-2026.1.22.145211.dist-info → processcube_etw_library-2026.1.29.103633.dist-info}/METADATA +13 -11
- processcube_etw_library-2026.1.29.103633.dist-info/RECORD +58 -0
- {processcube_etw_library-2026.1.22.145211.dist-info → processcube_etw_library-2026.1.29.103633.dist-info}/WHEEL +1 -1
- processcube_etw_library-2026.1.22.145211.dist-info/RECORD +0 -18
- {processcube_etw_library-2026.1.22.145211.dist-info → processcube_etw_library-2026.1.29.103633.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,816 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Synchronous HTTP client for ProcessCube® Engine API.
|
|
3
|
+
|
|
4
|
+
This client provides a high-level, synchronous interface to all ProcessCube® Engine
|
|
5
|
+
features. It is designed for Robot Framework and other synchronous contexts.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
import logging
|
|
9
|
+
from pathlib import Path
|
|
10
|
+
from typing import Any, Callable, Dict, List, Optional
|
|
11
|
+
|
|
12
|
+
from dataclasses import dataclass, field
|
|
13
|
+
from dataclasses_json import dataclass_json, LetterCase
|
|
14
|
+
|
|
15
|
+
from .helpers.application_info import ApplicationInfo, ApplicationInfoHandler
|
|
16
|
+
from .helpers.data_object_instances import (
|
|
17
|
+
DataObjectInstanceHandler,
|
|
18
|
+
DataObjectInstancesQuery,
|
|
19
|
+
DataObjectInstanceResponse,
|
|
20
|
+
)
|
|
21
|
+
from .helpers.empty_tasks import EmptyTaskHandler, EmptyTaskQuery, EmptyTaskResponse
|
|
22
|
+
from .helpers.events import EventsHandler, MessageTriggerRequest
|
|
23
|
+
from .helpers.external_tasks import (
|
|
24
|
+
ExtendLockRequest,
|
|
25
|
+
FetchAndLockRequestPayload,
|
|
26
|
+
ExternalTask,
|
|
27
|
+
ExternalTaskHandler,
|
|
28
|
+
FinishExternalTaskRequestPayload,
|
|
29
|
+
BpmnErrorRequest,
|
|
30
|
+
ServiceErrorRequest,
|
|
31
|
+
)
|
|
32
|
+
from .helpers.flow_node_instances import (
|
|
33
|
+
FlowNodeInstanceHandler,
|
|
34
|
+
FlowNodeInstanceResponse,
|
|
35
|
+
FlowNodeInstancesQuery,
|
|
36
|
+
)
|
|
37
|
+
from .helpers.manual_tasks import ManualTaskHandler, ManualTaskQuery, ManualTaskResponse
|
|
38
|
+
from .helpers.process_definitions import (
|
|
39
|
+
ProcessDefinitionUploadPayload,
|
|
40
|
+
ProcessDefinitionHandler,
|
|
41
|
+
)
|
|
42
|
+
from .helpers.process_instances import (
|
|
43
|
+
ProcessInstanceHandler,
|
|
44
|
+
ProcessInstanceQueryRequest,
|
|
45
|
+
ProcessInstanceQueryResponse,
|
|
46
|
+
)
|
|
47
|
+
from .helpers.process_models import (
|
|
48
|
+
ProcessStartRequest,
|
|
49
|
+
ProcessStartResponse,
|
|
50
|
+
ProcessModelHandler,
|
|
51
|
+
)
|
|
52
|
+
from .helpers.user_tasks import (
|
|
53
|
+
UserTaskHandler,
|
|
54
|
+
UserTaskQuery,
|
|
55
|
+
UserTaskResponse,
|
|
56
|
+
ReserveUserTaskRequest,
|
|
57
|
+
)
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
@dataclass_json(letter_case=LetterCase.CAMEL)
|
|
61
|
+
@dataclass
|
|
62
|
+
class DeployResult:
|
|
63
|
+
"""
|
|
64
|
+
Result of a single process model deployment.
|
|
65
|
+
|
|
66
|
+
Attributes:
|
|
67
|
+
filename: Path to the deployed file
|
|
68
|
+
deployed: Whether deployment was successful
|
|
69
|
+
"""
|
|
70
|
+
|
|
71
|
+
filename: str
|
|
72
|
+
deployed: bool = True
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
@dataclass_json(letter_case=LetterCase.CAMEL)
|
|
76
|
+
@dataclass
|
|
77
|
+
class DeployResults:
|
|
78
|
+
"""
|
|
79
|
+
Collection of deployment results.
|
|
80
|
+
|
|
81
|
+
Attributes:
|
|
82
|
+
deployed_files: List of individual deployment results
|
|
83
|
+
"""
|
|
84
|
+
|
|
85
|
+
deployed_files: List[DeployResult] = field(default_factory=list)
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
class Client:
|
|
89
|
+
"""
|
|
90
|
+
Synchronous client for ProcessCube® Engine API.
|
|
91
|
+
|
|
92
|
+
This client provides a high-level interface to all ProcessCube® Engine features
|
|
93
|
+
using synchronous HTTP requests. It is designed for use with Robot Framework
|
|
94
|
+
and other synchronous contexts.
|
|
95
|
+
|
|
96
|
+
The client automatically handles the ProcessCube API base path:
|
|
97
|
+
- Default: /atlas_engine/api/v1
|
|
98
|
+
|
|
99
|
+
Args:
|
|
100
|
+
url: Base URL of the ProcessCube® Engine (e.g., "http://localhost:56100")
|
|
101
|
+
identity: Optional callable that returns identity dict with 'token' key.
|
|
102
|
+
If None, uses default dummy token: ZHVtbXlfdG9rZW4=
|
|
103
|
+
api_version: API version to use (default: "v1")
|
|
104
|
+
|
|
105
|
+
Example:
|
|
106
|
+
>>> # Simple usage with default identity
|
|
107
|
+
>>> client = Client("http://localhost:56100")
|
|
108
|
+
>>> info = client.info()
|
|
109
|
+
>>>
|
|
110
|
+
>>> # With custom identity provider
|
|
111
|
+
>>> def get_identity():
|
|
112
|
+
... return {"token": "my_token"}
|
|
113
|
+
>>> client = Client("http://localhost:56100", identity=get_identity)
|
|
114
|
+
>>>
|
|
115
|
+
>>> # Start a process
|
|
116
|
+
>>> result = client.process_model_start(
|
|
117
|
+
... "MyProcess",
|
|
118
|
+
... ProcessStartRequest(start_event_id="StartEvent_1")
|
|
119
|
+
... )
|
|
120
|
+
"""
|
|
121
|
+
|
|
122
|
+
def __init__(
|
|
123
|
+
self,
|
|
124
|
+
url: str,
|
|
125
|
+
identity: Optional[Callable[[], Dict[str, str]]] = None,
|
|
126
|
+
api_version: str = "v1",
|
|
127
|
+
):
|
|
128
|
+
"""
|
|
129
|
+
Initialize the Client.
|
|
130
|
+
|
|
131
|
+
Args:
|
|
132
|
+
url: Base URL of the ProcessCube® Engine (e.g., "http://localhost:56100")
|
|
133
|
+
identity: Optional callable returning dict with 'token' key
|
|
134
|
+
api_version: API version to use (default: "v1")
|
|
135
|
+
"""
|
|
136
|
+
self._url = url
|
|
137
|
+
self._identity = identity
|
|
138
|
+
self._api_version = api_version
|
|
139
|
+
self.logger = logging.getLogger(__name__)
|
|
140
|
+
|
|
141
|
+
# =========================================================================
|
|
142
|
+
# Application Info
|
|
143
|
+
# =========================================================================
|
|
144
|
+
|
|
145
|
+
def info(self) -> ApplicationInfo:
|
|
146
|
+
"""
|
|
147
|
+
Get application information from the ProcessCube® Engine.
|
|
148
|
+
|
|
149
|
+
API Endpoint: GET /info
|
|
150
|
+
|
|
151
|
+
Returns:
|
|
152
|
+
Application information including version, name, etc.
|
|
153
|
+
|
|
154
|
+
Example:
|
|
155
|
+
>>> client = Client("http://localhost:56100")
|
|
156
|
+
>>> info = client.info()
|
|
157
|
+
>>> print(f"Engine version: {info.version}")
|
|
158
|
+
"""
|
|
159
|
+
handler = ApplicationInfoHandler(self._url, self._identity, self._api_version)
|
|
160
|
+
return handler.info()
|
|
161
|
+
|
|
162
|
+
def authority(self) -> str:
|
|
163
|
+
"""
|
|
164
|
+
Get the authority/identity service URL.
|
|
165
|
+
|
|
166
|
+
API Endpoint: GET /authority
|
|
167
|
+
|
|
168
|
+
Returns:
|
|
169
|
+
Authority service URL
|
|
170
|
+
|
|
171
|
+
Example:
|
|
172
|
+
>>> client = Client("http://localhost:56100")
|
|
173
|
+
>>> authority = client.authority()
|
|
174
|
+
"""
|
|
175
|
+
handler = ApplicationInfoHandler(self._url, self._identity, self._api_version)
|
|
176
|
+
return handler.authority()
|
|
177
|
+
|
|
178
|
+
# =========================================================================
|
|
179
|
+
# Process Definitions
|
|
180
|
+
# =========================================================================
|
|
181
|
+
|
|
182
|
+
def process_definition_upload(
|
|
183
|
+
self, payload: ProcessDefinitionUploadPayload
|
|
184
|
+
) -> None:
|
|
185
|
+
"""
|
|
186
|
+
Upload a process definition to the ProcessCube® Engine.
|
|
187
|
+
|
|
188
|
+
API Endpoint: POST /process_definitions
|
|
189
|
+
|
|
190
|
+
Args:
|
|
191
|
+
payload: Upload payload containing BPMN XML
|
|
192
|
+
|
|
193
|
+
Example:
|
|
194
|
+
>>> from processcube_client.core.api.helpers.process_definitions import (
|
|
195
|
+
... ProcessDefinitionUploadPayload
|
|
196
|
+
... )
|
|
197
|
+
>>>
|
|
198
|
+
>>> payload = ProcessDefinitionUploadPayload(
|
|
199
|
+
... xml="<bpmn:definitions>...</bpmn:definitions>",
|
|
200
|
+
... overwrite_existing=True
|
|
201
|
+
... )
|
|
202
|
+
>>> client.process_definition_upload(payload)
|
|
203
|
+
"""
|
|
204
|
+
handler = ProcessDefinitionHandler(self._url, self._identity, self._api_version)
|
|
205
|
+
handler.upload(payload)
|
|
206
|
+
|
|
207
|
+
def process_definition_delete(
|
|
208
|
+
self, process_definition_id: str, delete_all_related_data: bool = False
|
|
209
|
+
) -> None:
|
|
210
|
+
"""
|
|
211
|
+
Delete a process definition from the ProcessCube® Engine.
|
|
212
|
+
|
|
213
|
+
API Endpoint: DELETE /process_definitions/{processDefinitionId}
|
|
214
|
+
|
|
215
|
+
Args:
|
|
216
|
+
process_definition_id: ID of the process definition to delete
|
|
217
|
+
delete_all_related_data: Whether to delete all related data
|
|
218
|
+
|
|
219
|
+
Example:
|
|
220
|
+
>>> client.process_definition_delete("myProcess_12345678")
|
|
221
|
+
"""
|
|
222
|
+
handler = ProcessDefinitionHandler(self._url, self._identity, self._api_version)
|
|
223
|
+
handler.delete(process_definition_id, delete_all_related_data)
|
|
224
|
+
|
|
225
|
+
# =========================================================================
|
|
226
|
+
# Process Models
|
|
227
|
+
# =========================================================================
|
|
228
|
+
|
|
229
|
+
def process_model_start(
|
|
230
|
+
self, process_model_id: str, payload: ProcessStartRequest
|
|
231
|
+
) -> ProcessStartResponse:
|
|
232
|
+
"""
|
|
233
|
+
Start a new process instance.
|
|
234
|
+
|
|
235
|
+
API Endpoint: POST /process_models/{processModelId}/start
|
|
236
|
+
|
|
237
|
+
Args:
|
|
238
|
+
process_model_id: ID of the process model to start
|
|
239
|
+
payload: Start request payload
|
|
240
|
+
|
|
241
|
+
Returns:
|
|
242
|
+
Process start response with instance ID
|
|
243
|
+
|
|
244
|
+
Example:
|
|
245
|
+
>>> from processcube_client.core.api.helpers.process_models import (
|
|
246
|
+
... ProcessStartRequest,
|
|
247
|
+
... StartCallbackType
|
|
248
|
+
... )
|
|
249
|
+
>>>
|
|
250
|
+
>>> request = ProcessStartRequest(
|
|
251
|
+
... start_event_id="StartEvent_1",
|
|
252
|
+
... return_on=StartCallbackType.CALLBACK_ON_PROCESS_INSTANCE_FINISHED
|
|
253
|
+
... )
|
|
254
|
+
>>> result = client.process_model_start("MyProcess", request)
|
|
255
|
+
>>> print(f"Started process: {result.process_instance_id}")
|
|
256
|
+
"""
|
|
257
|
+
handler = ProcessModelHandler(self._url, self._identity, self._api_version)
|
|
258
|
+
return handler.start(process_model_id, payload)
|
|
259
|
+
|
|
260
|
+
# =========================================================================
|
|
261
|
+
# Process Instances
|
|
262
|
+
# =========================================================================
|
|
263
|
+
|
|
264
|
+
def process_instance_query(
|
|
265
|
+
self, request: ProcessInstanceQueryRequest
|
|
266
|
+
) -> List[ProcessInstanceQueryResponse]:
|
|
267
|
+
"""
|
|
268
|
+
Query process instances.
|
|
269
|
+
|
|
270
|
+
API Endpoint: GET /process_instances/query
|
|
271
|
+
|
|
272
|
+
Args:
|
|
273
|
+
request: Query parameters
|
|
274
|
+
|
|
275
|
+
Returns:
|
|
276
|
+
List of query responses with matching process instances
|
|
277
|
+
|
|
278
|
+
Example:
|
|
279
|
+
>>> from processcube_client.core.api.helpers.process_instances import (
|
|
280
|
+
... ProcessInstanceQueryRequest
|
|
281
|
+
... )
|
|
282
|
+
>>>
|
|
283
|
+
>>> query = ProcessInstanceQueryRequest(
|
|
284
|
+
... process_model_id="MyProcess",
|
|
285
|
+
... limit=10
|
|
286
|
+
... )
|
|
287
|
+
>>> response = client.process_instance_query(query)
|
|
288
|
+
>>> print(f"Found {response.total_count} instances")
|
|
289
|
+
"""
|
|
290
|
+
handler = ProcessInstanceHandler(self._url, self._identity, self._api_version)
|
|
291
|
+
return handler.query(request)
|
|
292
|
+
|
|
293
|
+
def process_instance_terminate(self, process_instance_id: str) -> bool:
|
|
294
|
+
"""
|
|
295
|
+
Terminate a running process instance.
|
|
296
|
+
|
|
297
|
+
API Endpoint: PUT /process_instances/{processInstanceId}/terminate
|
|
298
|
+
|
|
299
|
+
Args:
|
|
300
|
+
process_instance_id: ID of the process instance to terminate
|
|
301
|
+
|
|
302
|
+
Returns:
|
|
303
|
+
True if successful
|
|
304
|
+
|
|
305
|
+
Example:
|
|
306
|
+
>>> client.process_instance_terminate("myProcessInstance_12345678")
|
|
307
|
+
"""
|
|
308
|
+
handler = ProcessInstanceHandler(self._url, self._identity, self._api_version)
|
|
309
|
+
return handler.terminate(process_instance_id)
|
|
310
|
+
|
|
311
|
+
# =========================================================================
|
|
312
|
+
# User Tasks
|
|
313
|
+
# =========================================================================
|
|
314
|
+
|
|
315
|
+
def user_task_query(self, query: UserTaskQuery) -> List[UserTaskResponse]:
|
|
316
|
+
"""
|
|
317
|
+
Query user tasks.
|
|
318
|
+
|
|
319
|
+
API Endpoint: GET /user_tasks (with query parameters)
|
|
320
|
+
|
|
321
|
+
Args:
|
|
322
|
+
query: Query parameters
|
|
323
|
+
|
|
324
|
+
Returns:
|
|
325
|
+
List of responses with matching user tasks
|
|
326
|
+
|
|
327
|
+
Example:
|
|
328
|
+
>>> from processcube_client.core.api.helpers.user_tasks import UserTaskQuery
|
|
329
|
+
>>>
|
|
330
|
+
>>> query = UserTaskQuery(process_instance_id="myProcessInstance_12345678")
|
|
331
|
+
>>> response = client.user_task_query(query)
|
|
332
|
+
>>> print(f"Found {response.total_count} user tasks")
|
|
333
|
+
"""
|
|
334
|
+
handler = UserTaskHandler(self._url, self._identity, self._api_version)
|
|
335
|
+
return handler.query(query)
|
|
336
|
+
|
|
337
|
+
def user_task_finish(
|
|
338
|
+
self, user_task_instance_id: str, result: Dict[str, Any]
|
|
339
|
+
) -> bool:
|
|
340
|
+
"""
|
|
341
|
+
Finish a user task.
|
|
342
|
+
|
|
343
|
+
API Endpoint: PUT /user_tasks/{userTaskInstanceId}/finish
|
|
344
|
+
|
|
345
|
+
Args:
|
|
346
|
+
user_task_instance_id: ID of the user task instance
|
|
347
|
+
result: Result payload
|
|
348
|
+
|
|
349
|
+
Returns:
|
|
350
|
+
True if successful
|
|
351
|
+
|
|
352
|
+
Example:
|
|
353
|
+
>>> client.user_task_finish(
|
|
354
|
+
... "myUserTask_12345678",
|
|
355
|
+
... {"approved": True, "comment": "Looks good"}
|
|
356
|
+
... )
|
|
357
|
+
"""
|
|
358
|
+
handler = UserTaskHandler(self._url, self._identity, self._api_version)
|
|
359
|
+
return handler.finish(user_task_instance_id, result)
|
|
360
|
+
|
|
361
|
+
def user_task_reserve(
|
|
362
|
+
self, user_task_instance_id: str, request: ReserveUserTaskRequest
|
|
363
|
+
) -> bool:
|
|
364
|
+
"""
|
|
365
|
+
Reserve a user task.
|
|
366
|
+
|
|
367
|
+
API Endpoint: PUT /user_tasks/{userTaskInstanceId}/reserve
|
|
368
|
+
|
|
369
|
+
Args:
|
|
370
|
+
user_task_instance_id: ID of the user task instance
|
|
371
|
+
request: Reserve request with actual owner ID
|
|
372
|
+
|
|
373
|
+
Returns:
|
|
374
|
+
True if successful
|
|
375
|
+
|
|
376
|
+
Example:
|
|
377
|
+
>>> from processcube_client.core.api.helpers.user_tasks import (
|
|
378
|
+
... ReserveUserTaskRequest
|
|
379
|
+
... )
|
|
380
|
+
>>>
|
|
381
|
+
>>> request = ReserveUserTaskRequest(actual_owner_id="user123")
|
|
382
|
+
>>> client.user_task_reserve("myUserTask_12345678", request)
|
|
383
|
+
"""
|
|
384
|
+
handler = UserTaskHandler(self._url, self._identity, self._api_version)
|
|
385
|
+
return handler.reserve(user_task_instance_id, request)
|
|
386
|
+
|
|
387
|
+
def user_task_cancel_reservation(self, user_task_instance_id: str) -> bool:
|
|
388
|
+
"""
|
|
389
|
+
Cancel a user task reservation.
|
|
390
|
+
|
|
391
|
+
API Endpoint: DELETE /user_tasks/{userTaskInstanceId}/cancel-reservation
|
|
392
|
+
|
|
393
|
+
Args:
|
|
394
|
+
user_task_instance_id: ID of the user task instance
|
|
395
|
+
|
|
396
|
+
Returns:
|
|
397
|
+
True if successful
|
|
398
|
+
|
|
399
|
+
Example:
|
|
400
|
+
>>> client.user_task_cancel_reservation("myUserTask_12345678")
|
|
401
|
+
"""
|
|
402
|
+
handler = UserTaskHandler(self._url, self._identity, self._api_version)
|
|
403
|
+
return handler.cancel_reservation(user_task_instance_id)
|
|
404
|
+
|
|
405
|
+
# =========================================================================
|
|
406
|
+
# Manual Tasks
|
|
407
|
+
# =========================================================================
|
|
408
|
+
|
|
409
|
+
def manual_task_query(self, query: ManualTaskQuery) -> List[ManualTaskResponse]:
|
|
410
|
+
"""
|
|
411
|
+
Query manual tasks.
|
|
412
|
+
|
|
413
|
+
Args:
|
|
414
|
+
query: Query parameters
|
|
415
|
+
|
|
416
|
+
Returns:
|
|
417
|
+
List of responses with matching manual tasks
|
|
418
|
+
|
|
419
|
+
Example:
|
|
420
|
+
>>> from processcube_client.core.api.helpers.manual_tasks import ManualTaskQuery
|
|
421
|
+
>>>
|
|
422
|
+
>>> query = ManualTaskQuery(process_instance_id="myProcessInstance_12345678")
|
|
423
|
+
>>> response = client.manual_task_query(query)
|
|
424
|
+
"""
|
|
425
|
+
handler = ManualTaskHandler(self._url, self._identity, self._api_version)
|
|
426
|
+
return handler.query(query)
|
|
427
|
+
|
|
428
|
+
def manual_task_finish(self, manual_task_instance_id: str) -> bool:
|
|
429
|
+
"""
|
|
430
|
+
Finish a manual task.
|
|
431
|
+
|
|
432
|
+
API Endpoint: PUT /manual_tasks/{manualTaskInstanceId}/finish
|
|
433
|
+
|
|
434
|
+
Args:
|
|
435
|
+
manual_task_instance_id: ID of the manual task instance
|
|
436
|
+
|
|
437
|
+
Returns:
|
|
438
|
+
True if successful
|
|
439
|
+
|
|
440
|
+
Example:
|
|
441
|
+
>>> client.manual_task_finish("myManualTask_12345678")
|
|
442
|
+
"""
|
|
443
|
+
handler = ManualTaskHandler(self._url, self._identity, self._api_version)
|
|
444
|
+
return handler.finish(manual_task_instance_id)
|
|
445
|
+
|
|
446
|
+
# =========================================================================
|
|
447
|
+
# Empty Tasks (deprecated - use Untyped Tasks)
|
|
448
|
+
# =========================================================================
|
|
449
|
+
|
|
450
|
+
def empty_task_query(self, query: EmptyTaskQuery) -> List[EmptyTaskResponse]:
|
|
451
|
+
"""
|
|
452
|
+
Query empty tasks (deprecated - use untyped_task_query).
|
|
453
|
+
|
|
454
|
+
Args:
|
|
455
|
+
query: Query parameters
|
|
456
|
+
|
|
457
|
+
Returns:
|
|
458
|
+
List of responses with matching empty tasks
|
|
459
|
+
"""
|
|
460
|
+
handler = EmptyTaskHandler(self._url, self._identity, self._api_version)
|
|
461
|
+
return handler.query(query)
|
|
462
|
+
|
|
463
|
+
def empty_task_finish(self, empty_activity_instance_id: str) -> bool:
|
|
464
|
+
"""
|
|
465
|
+
Finish an empty task (deprecated - use untyped_task_finish).
|
|
466
|
+
|
|
467
|
+
Args:
|
|
468
|
+
empty_activity_instance_id: ID of the empty task instance
|
|
469
|
+
|
|
470
|
+
Returns:
|
|
471
|
+
True if successful
|
|
472
|
+
"""
|
|
473
|
+
handler = EmptyTaskHandler(self._url, self._identity, self._api_version)
|
|
474
|
+
return handler.finish(empty_activity_instance_id)
|
|
475
|
+
|
|
476
|
+
# =========================================================================
|
|
477
|
+
# External Tasks
|
|
478
|
+
# =========================================================================
|
|
479
|
+
|
|
480
|
+
def external_task_fetch_and_lock(
|
|
481
|
+
self, payload: FetchAndLockRequestPayload
|
|
482
|
+
) -> List[ExternalTask]:
|
|
483
|
+
"""
|
|
484
|
+
Fetch and lock external tasks.
|
|
485
|
+
|
|
486
|
+
API Endpoint: POST /external_tasks/fetch_and_lock
|
|
487
|
+
|
|
488
|
+
Args:
|
|
489
|
+
payload: Fetch and lock request payload
|
|
490
|
+
|
|
491
|
+
Returns:
|
|
492
|
+
List of locked external tasks
|
|
493
|
+
|
|
494
|
+
Example:
|
|
495
|
+
>>> from processcube_client.core.api.helpers.external_tasks import (
|
|
496
|
+
... FetchAndLockRequestPayload
|
|
497
|
+
... )
|
|
498
|
+
>>>
|
|
499
|
+
>>> payload = FetchAndLockRequestPayload(
|
|
500
|
+
... worker_id="myWorker",
|
|
501
|
+
... topic_name="myTopic",
|
|
502
|
+
... max_tasks=5,
|
|
503
|
+
... long_polling_timeout=10000,
|
|
504
|
+
... lock_duration=30000
|
|
505
|
+
... )
|
|
506
|
+
>>> tasks = client.external_task_fetch_and_lock(payload)
|
|
507
|
+
"""
|
|
508
|
+
handler = ExternalTaskHandler(self._url, self._identity, self._api_version)
|
|
509
|
+
return handler.fetch_and_lock(payload)
|
|
510
|
+
|
|
511
|
+
def external_task_extend_lock(
|
|
512
|
+
self, external_task_id: str, request: ExtendLockRequest
|
|
513
|
+
) -> bool:
|
|
514
|
+
"""
|
|
515
|
+
Extend the lock of an external task.
|
|
516
|
+
|
|
517
|
+
API Endpoint: PUT /external_tasks/{externalTaskId}/extend_lock
|
|
518
|
+
|
|
519
|
+
Args:
|
|
520
|
+
external_task_id: ID of the external task
|
|
521
|
+
request: Extend lock request with duration
|
|
522
|
+
|
|
523
|
+
Returns:
|
|
524
|
+
True if successful
|
|
525
|
+
|
|
526
|
+
Example:
|
|
527
|
+
>>> from processcube_client.core.api.helpers.external_tasks import (
|
|
528
|
+
... ExtendLockRequest
|
|
529
|
+
... )
|
|
530
|
+
>>>
|
|
531
|
+
>>> request = ExtendLockRequest(
|
|
532
|
+
... worker_id="myWorker",
|
|
533
|
+
... additional_duration=30000
|
|
534
|
+
... )
|
|
535
|
+
>>> client.external_task_extend_lock("myTask_12345678", request)
|
|
536
|
+
"""
|
|
537
|
+
handler = ExternalTaskHandler(self._url, self._identity, self._api_version)
|
|
538
|
+
return handler.extend_lock(external_task_id, request)
|
|
539
|
+
|
|
540
|
+
def external_task_finish(
|
|
541
|
+
self, external_task_id: str, payload: FinishExternalTaskRequestPayload
|
|
542
|
+
) -> bool:
|
|
543
|
+
"""
|
|
544
|
+
Finish an external task.
|
|
545
|
+
|
|
546
|
+
API Endpoint: PUT /external_tasks/{externalTaskId}/finish
|
|
547
|
+
|
|
548
|
+
Args:
|
|
549
|
+
external_task_id: ID of the external task
|
|
550
|
+
payload: Finish request with result
|
|
551
|
+
|
|
552
|
+
Returns:
|
|
553
|
+
True if successful
|
|
554
|
+
|
|
555
|
+
Example:
|
|
556
|
+
>>> from processcube_client.core.api.helpers.external_tasks import (
|
|
557
|
+
... FinishExternalTaskRequestPayload
|
|
558
|
+
... )
|
|
559
|
+
>>>
|
|
560
|
+
>>> payload = FinishExternalTaskRequestPayload(
|
|
561
|
+
... worker_id="myWorker",
|
|
562
|
+
... result={"status": "completed"}
|
|
563
|
+
... )
|
|
564
|
+
>>> client.external_task_finish("myTask_12345678", payload)
|
|
565
|
+
"""
|
|
566
|
+
handler = ExternalTaskHandler(self._url, self._identity, self._api_version)
|
|
567
|
+
return handler.finish(external_task_id, payload)
|
|
568
|
+
|
|
569
|
+
def external_task_handle_bpmn_error(
|
|
570
|
+
self, external_task_id: str, request: BpmnErrorRequest
|
|
571
|
+
) -> bool:
|
|
572
|
+
"""
|
|
573
|
+
Report a BPMN error for an external task.
|
|
574
|
+
|
|
575
|
+
API Endpoint: PUT /external_tasks/{externalTaskId}/error
|
|
576
|
+
|
|
577
|
+
Args:
|
|
578
|
+
external_task_id: ID of the external task
|
|
579
|
+
request: BPMN error request
|
|
580
|
+
|
|
581
|
+
Returns:
|
|
582
|
+
True if successful
|
|
583
|
+
|
|
584
|
+
Example:
|
|
585
|
+
>>> from processcube_client.core.api.helpers.external_tasks import (
|
|
586
|
+
... BpmnErrorRequest
|
|
587
|
+
... )
|
|
588
|
+
>>>
|
|
589
|
+
>>> error = BpmnErrorRequest(
|
|
590
|
+
... worker_id="myWorker",
|
|
591
|
+
... error_code="ValidationError",
|
|
592
|
+
... error_message="Invalid data"
|
|
593
|
+
... )
|
|
594
|
+
>>> client.external_task_handle_bpmn_error("myTask_12345678", error)
|
|
595
|
+
"""
|
|
596
|
+
handler = ExternalTaskHandler(self._url, self._identity, self._api_version)
|
|
597
|
+
return handler.handle_bpmn_error(external_task_id, request)
|
|
598
|
+
|
|
599
|
+
def external_task_handle_service_error(
|
|
600
|
+
self, external_task_id: str, request: ServiceErrorRequest
|
|
601
|
+
) -> bool:
|
|
602
|
+
"""
|
|
603
|
+
Report a service error for an external task.
|
|
604
|
+
|
|
605
|
+
API Endpoint: PUT /external_tasks/{externalTaskId}/error
|
|
606
|
+
|
|
607
|
+
Args:
|
|
608
|
+
external_task_id: ID of the external task
|
|
609
|
+
request: Service error request
|
|
610
|
+
|
|
611
|
+
Returns:
|
|
612
|
+
True if successful
|
|
613
|
+
|
|
614
|
+
Example:
|
|
615
|
+
>>> from processcube_client.core.api.helpers.external_tasks import (
|
|
616
|
+
... ServiceErrorRequest
|
|
617
|
+
... )
|
|
618
|
+
>>>
|
|
619
|
+
>>> error = ServiceErrorRequest(
|
|
620
|
+
... worker_id="myWorker",
|
|
621
|
+
... error_message="Service unavailable",
|
|
622
|
+
... error_details={"service": "payment-api"}
|
|
623
|
+
... )
|
|
624
|
+
>>> client.external_task_handle_service_error("myTask_12345678", error)
|
|
625
|
+
"""
|
|
626
|
+
handler = ExternalTaskHandler(self._url, self._identity, self._api_version)
|
|
627
|
+
return handler.handle_service_error(external_task_id, request)
|
|
628
|
+
|
|
629
|
+
# =========================================================================
|
|
630
|
+
# Events
|
|
631
|
+
# =========================================================================
|
|
632
|
+
|
|
633
|
+
def trigger_message(
|
|
634
|
+
self, message_name: str, request: MessageTriggerRequest
|
|
635
|
+
) -> bool:
|
|
636
|
+
"""
|
|
637
|
+
Trigger a message event.
|
|
638
|
+
|
|
639
|
+
API Endpoint: POST /messages/{eventName}/trigger
|
|
640
|
+
|
|
641
|
+
Args:
|
|
642
|
+
message_name: Name of the message event
|
|
643
|
+
request: Message trigger request
|
|
644
|
+
|
|
645
|
+
Returns:
|
|
646
|
+
True if successful
|
|
647
|
+
|
|
648
|
+
Example:
|
|
649
|
+
>>> from processcube_client.core.api.helpers.events import (
|
|
650
|
+
... MessageTriggerRequest
|
|
651
|
+
... )
|
|
652
|
+
>>>
|
|
653
|
+
>>> request = MessageTriggerRequest(
|
|
654
|
+
... process_instance_id="myProcessInstance_12345678",
|
|
655
|
+
... payload={"data": "value"}
|
|
656
|
+
... )
|
|
657
|
+
>>> client.event_trigger_message_event("OrderReceived", request)
|
|
658
|
+
"""
|
|
659
|
+
handler = EventsHandler(self._url, self._identity, self._api_version)
|
|
660
|
+
return handler.trigger_message(message_name, request)
|
|
661
|
+
|
|
662
|
+
def trigger_signal(self, signal_name: str) -> bool:
|
|
663
|
+
"""
|
|
664
|
+
Trigger a signal event.
|
|
665
|
+
|
|
666
|
+
API Endpoint: POST /signals/{eventName}/trigger
|
|
667
|
+
|
|
668
|
+
Args:
|
|
669
|
+
signal_name: Name of the signal event
|
|
670
|
+
|
|
671
|
+
Returns:
|
|
672
|
+
True if successful
|
|
673
|
+
|
|
674
|
+
Example:
|
|
675
|
+
>>> client.event_trigger_signal_event("EmergencyShutdown")
|
|
676
|
+
"""
|
|
677
|
+
handler = EventsHandler(self._url, self._identity, self._api_version)
|
|
678
|
+
return handler.trigger_signal(signal_name)
|
|
679
|
+
|
|
680
|
+
# =========================================================================
|
|
681
|
+
# Flow Node Instances
|
|
682
|
+
# =========================================================================
|
|
683
|
+
|
|
684
|
+
def flow_node_instance_query(
|
|
685
|
+
self, query: FlowNodeInstancesQuery
|
|
686
|
+
) -> List[FlowNodeInstanceResponse]:
|
|
687
|
+
"""
|
|
688
|
+
Query flow node instances.
|
|
689
|
+
|
|
690
|
+
API Endpoint: GET /flow_node_instances
|
|
691
|
+
|
|
692
|
+
Args:
|
|
693
|
+
query: Query parameters
|
|
694
|
+
|
|
695
|
+
Returns:
|
|
696
|
+
List of responses with matching flow node instances
|
|
697
|
+
|
|
698
|
+
Example:
|
|
699
|
+
>>> from processcube_client.core.api.helpers.flow_node_instances import (
|
|
700
|
+
... FlowNodeInstancesQuery
|
|
701
|
+
... )
|
|
702
|
+
>>>
|
|
703
|
+
>>> query = FlowNodeInstancesQuery(
|
|
704
|
+
... process_instance_id="myProcessInstance_12345678"
|
|
705
|
+
... )
|
|
706
|
+
>>> response = client.flow_node_instance_query(query)
|
|
707
|
+
"""
|
|
708
|
+
handler = FlowNodeInstanceHandler(self._url, self._identity, self._api_version)
|
|
709
|
+
return handler.query(query)
|
|
710
|
+
|
|
711
|
+
# =========================================================================
|
|
712
|
+
# Data Object Instances
|
|
713
|
+
# =========================================================================
|
|
714
|
+
|
|
715
|
+
def data_object_instance_query(
|
|
716
|
+
self, query: DataObjectInstancesQuery
|
|
717
|
+
) -> List[DataObjectInstanceResponse]:
|
|
718
|
+
"""
|
|
719
|
+
Query data object instances.
|
|
720
|
+
|
|
721
|
+
API Endpoint: GET /data_object_instances/query
|
|
722
|
+
|
|
723
|
+
Args:
|
|
724
|
+
query: Query parameters
|
|
725
|
+
|
|
726
|
+
Returns:
|
|
727
|
+
List of responses with matching data object instances
|
|
728
|
+
|
|
729
|
+
Example:
|
|
730
|
+
>>> from processcube_client.core.api.helpers.data_object_instances import (
|
|
731
|
+
... DataObjectInstancesQuery
|
|
732
|
+
... )
|
|
733
|
+
>>>
|
|
734
|
+
>>> query = DataObjectInstancesQuery(
|
|
735
|
+
... process_instance_id="myProcessInstance_12345678"
|
|
736
|
+
... )
|
|
737
|
+
>>> response = client.data_object_instance_query(query)
|
|
738
|
+
"""
|
|
739
|
+
handler = DataObjectInstanceHandler(
|
|
740
|
+
self._url, self._identity, self._api_version
|
|
741
|
+
)
|
|
742
|
+
return handler.query(query)
|
|
743
|
+
|
|
744
|
+
# =========================================================================
|
|
745
|
+
# Convenience Methods
|
|
746
|
+
# =========================================================================
|
|
747
|
+
|
|
748
|
+
def deploy_bpmn_from_path(self, path: str | Path) -> DeployResults:
|
|
749
|
+
"""
|
|
750
|
+
Deploy BPMN file(s) from a path.
|
|
751
|
+
|
|
752
|
+
Args:
|
|
753
|
+
path: Path to BPMN file or directory containing BPMN files
|
|
754
|
+
|
|
755
|
+
Returns:
|
|
756
|
+
Deployment results
|
|
757
|
+
|
|
758
|
+
Example:
|
|
759
|
+
>>> # Deploy single file
|
|
760
|
+
>>> result = client.deploy_bpmn_from_path("process.bpmn")
|
|
761
|
+
>>>
|
|
762
|
+
>>> # Deploy directory
|
|
763
|
+
>>> result = client.deploy_bpmn_from_path("processes/")
|
|
764
|
+
>>> for deployed in result.deployed_files:
|
|
765
|
+
... print(f"{deployed.filename}: {deployed.deployed}")
|
|
766
|
+
"""
|
|
767
|
+
path_obj = Path(path)
|
|
768
|
+
results = DeployResults()
|
|
769
|
+
|
|
770
|
+
if path_obj.is_file():
|
|
771
|
+
# Deploy single file
|
|
772
|
+
with open(path_obj, "r", encoding="utf-8") as f:
|
|
773
|
+
xml = f.read()
|
|
774
|
+
|
|
775
|
+
payload = ProcessDefinitionUploadPayload(xml=xml, overwrite_existing=True)
|
|
776
|
+
|
|
777
|
+
try:
|
|
778
|
+
self.process_definition_upload(payload)
|
|
779
|
+
results.deployed_files.append(
|
|
780
|
+
DeployResult(filename=str(path_obj), deployed=True)
|
|
781
|
+
)
|
|
782
|
+
except Exception as e:
|
|
783
|
+
self.logger.error(f"Failed to deploy {path_obj}: {e}")
|
|
784
|
+
results.deployed_files.append(
|
|
785
|
+
DeployResult(filename=str(path_obj), deployed=False)
|
|
786
|
+
)
|
|
787
|
+
|
|
788
|
+
elif path_obj.is_dir():
|
|
789
|
+
# Deploy all BPMN files in directory
|
|
790
|
+
for bpmn_file in path_obj.glob("**/*.bpmn"):
|
|
791
|
+
with open(bpmn_file, "r", encoding="utf-8") as f:
|
|
792
|
+
xml = f.read()
|
|
793
|
+
|
|
794
|
+
payload = ProcessDefinitionUploadPayload(
|
|
795
|
+
xml=xml, overwrite_existing=True
|
|
796
|
+
)
|
|
797
|
+
|
|
798
|
+
try:
|
|
799
|
+
self.process_definition_upload(payload)
|
|
800
|
+
results.deployed_files.append(
|
|
801
|
+
DeployResult(filename=str(bpmn_file), deployed=True)
|
|
802
|
+
)
|
|
803
|
+
except Exception as e:
|
|
804
|
+
self.logger.error(f"Failed to deploy {bpmn_file}: {e}")
|
|
805
|
+
results.deployed_files.append(
|
|
806
|
+
DeployResult(filename=str(bpmn_file), deployed=False)
|
|
807
|
+
)
|
|
808
|
+
|
|
809
|
+
return results
|
|
810
|
+
|
|
811
|
+
def __repr__(self) -> str:
|
|
812
|
+
"""String representation of the client."""
|
|
813
|
+
return f"Client(url='{self._url}', api_version='{self._api_version}')"
|
|
814
|
+
|
|
815
|
+
|
|
816
|
+
__all__ = ["Client", "DeployResult", "DeployResults"]
|