processcube-etw-library 2026.1.22.145211__py3-none-any.whl → 2026.1.29.71849b0__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 (52) hide show
  1. processcube_etw_library/__init__.py +7 -5
  2. processcube_etw_library/create_external_task_client.py +4 -2
  3. processcube_etw_library/etw_app.py +18 -5
  4. processcube_etw_library/health/built_in.py +3 -4
  5. processcube_etw_library/health/check.py +14 -4
  6. processcube_etw_library/identity_provider.py +0 -2
  7. processcube_etw_library/processcube_client/__init__.py +22 -0
  8. processcube_etw_library/processcube_client/app_info/__init__.py +1 -0
  9. processcube_etw_library/processcube_client/app_info/app_info_client.py +36 -0
  10. processcube_etw_library/processcube_client/client_factory.py +37 -0
  11. processcube_etw_library/processcube_client/core/__init__.py +2 -0
  12. processcube_etw_library/processcube_client/core/api/__init__.py +13 -0
  13. processcube_etw_library/processcube_client/core/api/base_client.py +235 -0
  14. processcube_etw_library/processcube_client/core/api/client.py +816 -0
  15. processcube_etw_library/processcube_client/core/api/helpers/__init__.py +0 -0
  16. processcube_etw_library/processcube_client/core/api/helpers/application_info.py +34 -0
  17. processcube_etw_library/processcube_client/core/api/helpers/data_object_instances.py +61 -0
  18. processcube_etw_library/processcube_client/core/api/helpers/empty_tasks.py +86 -0
  19. processcube_etw_library/processcube_client/core/api/helpers/events.py +39 -0
  20. processcube_etw_library/processcube_client/core/api/helpers/external_tasks.py +142 -0
  21. processcube_etw_library/processcube_client/core/api/helpers/flow_node_instances.py +80 -0
  22. processcube_etw_library/processcube_client/core/api/helpers/manual_tasks.py +87 -0
  23. processcube_etw_library/processcube_client/core/api/helpers/process_definitions.py +46 -0
  24. processcube_etw_library/processcube_client/core/api/helpers/process_instances.py +96 -0
  25. processcube_etw_library/processcube_client/core/api/helpers/process_models.py +51 -0
  26. processcube_etw_library/processcube_client/core/api/helpers/user_tasks.py +130 -0
  27. processcube_etw_library/processcube_client/core/base_client.py +175 -0
  28. processcube_etw_library/processcube_client/core/loop_helper.py +200 -0
  29. processcube_etw_library/processcube_client/event/__init__.py +1 -0
  30. processcube_etw_library/processcube_client/event/event_client.py +43 -0
  31. processcube_etw_library/processcube_client/external_task/__init__.py +3 -0
  32. processcube_etw_library/processcube_client/external_task/client_wrapper.py +28 -0
  33. processcube_etw_library/processcube_client/external_task/external_task_client.py +195 -0
  34. processcube_etw_library/processcube_client/external_task/external_task_worker.py +205 -0
  35. processcube_etw_library/processcube_client/external_task/functional_error.py +17 -0
  36. processcube_etw_library/processcube_client/flow_node_instance/__init__.py +1 -0
  37. processcube_etw_library/processcube_client/flow_node_instance/flow_node_instance_client.py +43 -0
  38. processcube_etw_library/processcube_client/notification/__init__.py +1 -0
  39. processcube_etw_library/processcube_client/notification/notification_client.py +103 -0
  40. processcube_etw_library/processcube_client/process_definition/__init__.py +2 -0
  41. processcube_etw_library/processcube_client/process_definition/process_definition_client.py +94 -0
  42. processcube_etw_library/processcube_client/process_definition/start_callback_type.py +6 -0
  43. processcube_etw_library/processcube_client/process_instance/__init__.py +1 -0
  44. processcube_etw_library/processcube_client/process_instance/process_instance_client.py +32 -0
  45. processcube_etw_library/processcube_client/user_task/__init__.py +1 -0
  46. processcube_etw_library/processcube_client/user_task/user_task_client.py +63 -0
  47. processcube_etw_library/settings.py +35 -9
  48. {processcube_etw_library-2026.1.22.145211.dist-info → processcube_etw_library-2026.1.29.71849b0.dist-info}/METADATA +13 -11
  49. processcube_etw_library-2026.1.29.71849b0.dist-info/RECORD +58 -0
  50. {processcube_etw_library-2026.1.22.145211.dist-info → processcube_etw_library-2026.1.29.71849b0.dist-info}/WHEEL +1 -1
  51. processcube_etw_library-2026.1.22.145211.dist-info/RECORD +0 -18
  52. {processcube_etw_library-2026.1.22.145211.dist-info → processcube_etw_library-2026.1.29.71849b0.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"]