dex-python-sdk 0.0.2__tar.gz → 0.1.2__tar.gz
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.
- dex_python_sdk-0.1.2/PKG-INFO +295 -0
- dex_python_sdk-0.1.2/README.md +278 -0
- {dex_python_sdk-0.0.2 → dex_python_sdk-0.1.2}/dex/__init__.py +30 -3
- dex_python_sdk-0.1.2/dex/_async_value_hydrator.py +223 -0
- dex_python_sdk-0.1.2/dex/_async_worker_dispatcher.py +155 -0
- dex_python_sdk-0.1.2/dex/_async_worker_service.py +65 -0
- dex_python_sdk-0.1.2/dex/_grpc_errors.py +145 -0
- {dex_python_sdk-0.0.2 → dex_python_sdk-0.1.2}/dex/_invocation_context.py +3 -1
- {dex_python_sdk-0.0.2 → dex_python_sdk-0.1.2}/dex/_value_mapper.py +56 -0
- {dex_python_sdk-0.0.2 → dex_python_sdk-0.1.2}/dex/_worker_dispatcher.py +68 -39
- dex_python_sdk-0.1.2/dex/async_client.py +1084 -0
- dex_python_sdk-0.1.2/dex/async_worker.py +189 -0
- dex_python_sdk-0.1.2/dex/attribute.py +243 -0
- dex_python_sdk-0.1.2/dex/blob_cache.py +145 -0
- dex_python_sdk-0.1.2/dex/channel.py +342 -0
- {dex_python_sdk-0.0.2 → dex_python_sdk-0.1.2}/dex/client.py +392 -24
- {dex_python_sdk-0.0.2 → dex_python_sdk-0.1.2}/dex/client_options.py +9 -0
- {dex_python_sdk-0.0.2 → dex_python_sdk-0.1.2}/dex/codec.py +143 -4
- {dex_python_sdk-0.0.2 → dex_python_sdk-0.1.2}/dex/condition.py +17 -0
- dex_python_sdk-0.1.2/dex/context.py +169 -0
- dex_python_sdk-0.1.2/dex/dexpb/dex_pb2.py +395 -0
- {dex_python_sdk-0.0.2 → dex_python_sdk-0.1.2}/dex/dexpb/dex_pb2.pyi +82 -31
- {dex_python_sdk-0.0.2 → dex_python_sdk-0.1.2}/dex/dexpb/dex_pb2_grpc.py +43 -0
- {dex_python_sdk-0.0.2 → dex_python_sdk-0.1.2}/dex/flow.py +250 -25
- dex_python_sdk-0.1.2/dex/flow_config.py +59 -0
- dex_python_sdk-0.1.2/dex/flow_info.py +107 -0
- dex_python_sdk-0.1.2/dex/flow_options.py +214 -0
- dex_python_sdk-0.1.2/dex/runtime_errors.py +285 -0
- dex_python_sdk-0.1.2/dex/step.py +427 -0
- {dex_python_sdk-0.0.2 → dex_python_sdk-0.1.2}/dex/step_execution.py +36 -0
- dex_python_sdk-0.1.2/dex/timer.py +44 -0
- dex_python_sdk-0.1.2/dex/wait.py +108 -0
- dex_python_sdk-0.1.2/dex/worker.py +214 -0
- dex_python_sdk-0.1.2/dex/worker_options.py +52 -0
- {dex_python_sdk-0.0.2 → dex_python_sdk-0.1.2}/pyproject.toml +12 -3
- {dex_python_sdk-0.0.2 → dex_python_sdk-0.1.2}/sdk-rust/Cargo.lock +299 -0
- {dex_python_sdk-0.0.2 → dex_python_sdk-0.1.2}/sdk-rust/Cargo.toml +8 -0
- {dex_python_sdk-0.0.2 → dex_python_sdk-0.1.2}/sdk-rust/crates/dex-blob-cache/src/config.rs +31 -0
- {dex_python_sdk-0.0.2 → dex_python_sdk-0.1.2}/sdk-rust/crates/dex-blob-cache/src/error.rs +11 -0
- {dex_python_sdk-0.0.2 → dex_python_sdk-0.1.2}/sdk-rust/crates/dex-blob-cache/src/lib.rs +76 -0
- dex_python_sdk-0.0.2/PKG-INFO +0 -202
- dex_python_sdk-0.0.2/README.md +0 -184
- dex_python_sdk-0.0.2/dex/_grpc_errors.py +0 -73
- dex_python_sdk-0.0.2/dex/attribute.py +0 -87
- dex_python_sdk-0.0.2/dex/blob_cache.py +0 -73
- dex_python_sdk-0.0.2/dex/channel.py +0 -165
- dex_python_sdk-0.0.2/dex/command_request.py +0 -120
- dex_python_sdk-0.0.2/dex/command_results.py +0 -107
- dex_python_sdk-0.0.2/dex/communication.py +0 -136
- dex_python_sdk-0.0.2/dex/communication_schema.py +0 -54
- dex_python_sdk-0.0.2/dex/context.py +0 -86
- dex_python_sdk-0.0.2/dex/data_attributes.py +0 -70
- dex_python_sdk-0.0.2/dex/dexpb/dex_pb2.py +0 -381
- dex_python_sdk-0.0.2/dex/errors.py +0 -109
- dex_python_sdk-0.0.2/dex/flow_config.py +0 -29
- dex_python_sdk-0.0.2/dex/flow_info.py +0 -51
- dex_python_sdk-0.0.2/dex/flow_options.py +0 -122
- dex_python_sdk-0.0.2/dex/object_encoder.py +0 -799
- dex_python_sdk-0.0.2/dex/persistence.py +0 -89
- dex_python_sdk-0.0.2/dex/persistence_options.py +0 -12
- dex_python_sdk-0.0.2/dex/persistence_schema.py +0 -51
- dex_python_sdk-0.0.2/dex/registry.py +0 -204
- dex_python_sdk-0.0.2/dex/reset_workflow_type_and_options.py +0 -67
- dex_python_sdk-0.0.2/dex/rpc.py +0 -93
- dex_python_sdk-0.0.2/dex/runtime_errors.py +0 -81
- dex_python_sdk-0.0.2/dex/search_attributes.py +0 -184
- dex_python_sdk-0.0.2/dex/state_decision.py +0 -153
- dex_python_sdk-0.0.2/dex/state_execution_locals.py +0 -66
- dex_python_sdk-0.0.2/dex/state_movement.py +0 -115
- dex_python_sdk-0.0.2/dex/state_schema.py +0 -48
- dex_python_sdk-0.0.2/dex/step.py +0 -194
- dex_python_sdk-0.0.2/dex/stop_workflow_options.py +0 -18
- dex_python_sdk-0.0.2/dex/tests/__init__.py +0 -80
- dex_python_sdk-0.0.2/dex/tests/dex-service-env/docker-compose-init.sh +0 -44
- dex_python_sdk-0.0.2/dex/tests/dex-service-env/docker-compose.yml +0 -97
- dex_python_sdk-0.0.2/dex/tests/dex-service-env/dynamicconfig/README.md +0 -39
- dex_python_sdk-0.0.2/dex/tests/dex-service-env/dynamicconfig/development-sql.yaml +0 -9
- dex_python_sdk-0.0.2/dex/tests/dex-service-env/dynamicconfig/docker.yaml +0 -2
- dex_python_sdk-0.0.2/dex/tests/test_abnormal_exit_workflow.py +0 -43
- dex_python_sdk-0.0.2/dex/tests/test_basic_workflow.py +0 -70
- dex_python_sdk-0.0.2/dex/tests/test_conditional_complete.py +0 -50
- dex_python_sdk-0.0.2/dex/tests/test_describe_workflow.py +0 -40
- dex_python_sdk-0.0.2/dex/tests/test_empty_data_decodes_properly.py +0 -74
- dex_python_sdk-0.0.2/dex/tests/test_internal_channel.py +0 -28
- dex_python_sdk-0.0.2/dex/tests/test_internal_channel_with_no_prefix_channel.py +0 -41
- dex_python_sdk-0.0.2/dex/tests/test_persistence_data_attributes.py +0 -62
- dex_python_sdk-0.0.2/dex/tests/test_persistence_search_attributes.py +0 -127
- dex_python_sdk-0.0.2/dex/tests/test_persistence_state_execution_locals.py +0 -38
- dex_python_sdk-0.0.2/dex/tests/test_rpc.py +0 -64
- dex_python_sdk-0.0.2/dex/tests/test_rpc_with_memo.py +0 -195
- dex_python_sdk-0.0.2/dex/tests/test_rpc_with_memo_duplicate_java_tests.py +0 -117
- dex_python_sdk-0.0.2/dex/tests/test_signal.py +0 -51
- dex_python_sdk-0.0.2/dex/tests/test_skip_wait_until.py +0 -76
- dex_python_sdk-0.0.2/dex/tests/test_state_failure_recovery.py +0 -28
- dex_python_sdk-0.0.2/dex/tests/test_timer.py +0 -35
- dex_python_sdk-0.0.2/dex/tests/test_wait_for_state_execution_completion.py +0 -53
- dex_python_sdk-0.0.2/dex/tests/test_workflow_errors.py +0 -87
- dex_python_sdk-0.0.2/dex/tests/test_workflow_state_options.py +0 -118
- dex_python_sdk-0.0.2/dex/tests/test_workflow_state_options_override.py +0 -44
- dex_python_sdk-0.0.2/dex/tests/worker_server.py +0 -64
- dex_python_sdk-0.0.2/dex/tests/workflows/abnormal_exit_workflow.py +0 -42
- dex_python_sdk-0.0.2/dex/tests/workflows/basic_workflow.py +0 -62
- dex_python_sdk-0.0.2/dex/tests/workflows/conditional_complete_workflow.py +0 -95
- dex_python_sdk-0.0.2/dex/tests/workflows/describe_workflow.py +0 -46
- dex_python_sdk-0.0.2/dex/tests/workflows/empty_data_workflow.py +0 -45
- dex_python_sdk-0.0.2/dex/tests/workflows/internal_channel_workflow.py +0 -129
- dex_python_sdk-0.0.2/dex/tests/workflows/internal_channel_workflow_with_no_prefix_channel.py +0 -100
- dex_python_sdk-0.0.2/dex/tests/workflows/java_duplicate_rpc_memo_workflow.py +0 -276
- dex_python_sdk-0.0.2/dex/tests/workflows/persistence_data_attributes_workflow.py +0 -98
- dex_python_sdk-0.0.2/dex/tests/workflows/persistence_search_attributes_workflow.py +0 -159
- dex_python_sdk-0.0.2/dex/tests/workflows/persistence_state_execution_local_workflow.py +0 -63
- dex_python_sdk-0.0.2/dex/tests/workflows/recovery_workflow.py +0 -82
- dex_python_sdk-0.0.2/dex/tests/workflows/rpc_memo_workflow.py +0 -231
- dex_python_sdk-0.0.2/dex/tests/workflows/rpc_workflow.py +0 -117
- dex_python_sdk-0.0.2/dex/tests/workflows/state_options_override_workflow.py +0 -93
- dex_python_sdk-0.0.2/dex/tests/workflows/state_options_workflow.py +0 -84
- dex_python_sdk-0.0.2/dex/tests/workflows/timer_workflow.py +0 -46
- dex_python_sdk-0.0.2/dex/tests/workflows/wait_for_state_with_state_execution_id_workflow.py +0 -70
- dex_python_sdk-0.0.2/dex/tests/workflows/wait_for_state_with_wait_for_key_workflow.py +0 -71
- dex_python_sdk-0.0.2/dex/tests/workflows/wait_internal_channel_workflow.py +0 -47
- dex_python_sdk-0.0.2/dex/tests/workflows/wait_signal_workflow.py +0 -147
- dex_python_sdk-0.0.2/dex/timer.py +0 -21
- dex_python_sdk-0.0.2/dex/type_store.py +0 -99
- dex_python_sdk-0.0.2/dex/unregistered_client.py +0 -585
- dex_python_sdk-0.0.2/dex/utils/__init__.py +0 -3
- dex_python_sdk-0.0.2/dex/utils/dex_typing.py +0 -25
- dex_python_sdk-0.0.2/dex/utils/persistence_utils.py +0 -32
- dex_python_sdk-0.0.2/dex/wait.py +0 -49
- dex_python_sdk-0.0.2/dex/worker.py +0 -121
- dex_python_sdk-0.0.2/dex/worker_options.py +0 -22
- dex_python_sdk-0.0.2/dex/worker_service.py +0 -432
- dex_python_sdk-0.0.2/dex/workflow.py +0 -79
- dex_python_sdk-0.0.2/dex/workflow_context.py +0 -44
- dex_python_sdk-0.0.2/dex/workflow_info.py +0 -16
- dex_python_sdk-0.0.2/dex/workflow_options.py +0 -74
- dex_python_sdk-0.0.2/dex/workflow_state.py +0 -123
- dex_python_sdk-0.0.2/dex/workflow_state_options.py +0 -154
- {dex_python_sdk-0.0.2 → dex_python_sdk-0.1.2}/LEGACY_NOTICES.md +0 -0
- {dex_python_sdk-0.0.2 → dex_python_sdk-0.1.2}/LICENSE +0 -0
- {dex_python_sdk-0.0.2 → dex_python_sdk-0.1.2}/dex/_native.pyi +0 -0
- {dex_python_sdk-0.0.2 → dex_python_sdk-0.1.2}/dex/_utils.py +0 -0
- {dex_python_sdk-0.0.2 → dex_python_sdk-0.1.2}/dex/_value_hydrator.py +0 -0
- {dex_python_sdk-0.0.2 → dex_python_sdk-0.1.2}/dex/_worker_service.py +0 -0
- {dex_python_sdk-0.0.2 → dex_python_sdk-0.1.2}/dex/dexpb/__init__.py +0 -0
- {dex_python_sdk-0.0.2 → dex_python_sdk-0.1.2}/dex/py.typed +0 -0
- {dex_python_sdk-0.0.2 → dex_python_sdk-0.1.2}/sdk-rust/crates/dex-blob-cache/Cargo.toml +0 -0
- {dex_python_sdk-0.0.2 → dex_python_sdk-0.1.2}/sdk-rust/crates/dex-blob-cache/LICENSE +0 -0
- {dex_python_sdk-0.0.2 → dex_python_sdk-0.1.2}/sdk-rust/crates/dex-blob-cache/src/entry.rs +0 -0
- {dex_python_sdk-0.0.2 → dex_python_sdk-0.1.2}/sdk-rust/crates/dex-blob-cache/src/format.rs +0 -0
- {dex_python_sdk-0.0.2 → dex_python_sdk-0.1.2}/sdk-rust/crates/dex-blob-cache/src/policy.rs +0 -0
- {dex_python_sdk-0.0.2 → dex_python_sdk-0.1.2}/sdk-rust/crates/dex-blob-cache/src/store.rs +0 -0
- {dex_python_sdk-0.0.2 → dex_python_sdk-0.1.2}/sdk-rust/crates/dex-blob-cache/tests/blob_cache_integration.rs +0 -0
- {dex_python_sdk-0.0.2 → dex_python_sdk-0.1.2}/sdk-rust/crates/dex-blob-cache-python/Cargo.toml +0 -0
- {dex_python_sdk-0.0.2 → dex_python_sdk-0.1.2}/sdk-rust/crates/dex-blob-cache-python/LICENSE +0 -0
- {dex_python_sdk-0.0.2 → dex_python_sdk-0.1.2}/sdk-rust/crates/dex-blob-cache-python/src/lib.rs +0 -0
|
@@ -0,0 +1,295 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: dex-python-sdk
|
|
3
|
+
Version: 0.1.2
|
|
4
|
+
Requires-Dist: grpcio>=1.83.0
|
|
5
|
+
Requires-Dist: grpcio-status>=1.83.0
|
|
6
|
+
Requires-Dist: protobuf>=7.35.1
|
|
7
|
+
License-File: LICENSE
|
|
8
|
+
License-File: LEGACY_NOTICES.md
|
|
9
|
+
Summary: Python SDK for the Dex workflow engine
|
|
10
|
+
Author: Super Durable
|
|
11
|
+
License-Expression: LicenseRef-Super-Durable-1.0
|
|
12
|
+
Requires-Python: >=3.11
|
|
13
|
+
Description-Content-Type: text/markdown; charset=UTF-8; variant=GFM
|
|
14
|
+
Project-URL: Homepage, https://github.com/superdurable/dex/tree/main/sdk-python
|
|
15
|
+
Project-URL: Repository, https://github.com/superdurable/dex
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
# Dex SDK for Python
|
|
19
|
+
|
|
20
|
+
Python SDK for [Dex workflow engine](https://github.com/superdurable/dex)
|
|
21
|
+
|
|
22
|
+
## New user contracts
|
|
23
|
+
|
|
24
|
+
The rewrite targets Python 3.11+ and exposes strongly typed workflow contracts
|
|
25
|
+
from `dex`. This phase includes definitions, attributes, channels, waits,
|
|
26
|
+
decisions, codecs, registry validation, synchronous client calls, and synchronous
|
|
27
|
+
worker handlers. Python owns its gRPC Client and Worker transport;
|
|
28
|
+
the shared Rust Core is used only for BlobCache.
|
|
29
|
+
|
|
30
|
+
```python
|
|
31
|
+
from datetime import timedelta
|
|
32
|
+
|
|
33
|
+
import dex
|
|
34
|
+
|
|
35
|
+
counter = dex.Attribute("counter", int)
|
|
36
|
+
counters_by_region = dex.AttributeMap("counters-by-region", int)
|
|
37
|
+
|
|
38
|
+
class Run(dex.Step[str]):
|
|
39
|
+
def wait_for(
|
|
40
|
+
self, context: dex.Context, input: str
|
|
41
|
+
) -> dex.Wait:
|
|
42
|
+
return dex.Wait.until(
|
|
43
|
+
dex.Timer.by_duration(timedelta(seconds=1))
|
|
44
|
+
)
|
|
45
|
+
|
|
46
|
+
def execute(
|
|
47
|
+
self, context: dex.Context, input: str
|
|
48
|
+
) -> dex.StepDecision:
|
|
49
|
+
return dex.graceful_complete(input)
|
|
50
|
+
|
|
51
|
+
class CounterFlow(dex.Flow[str]):
|
|
52
|
+
run = Run()
|
|
53
|
+
|
|
54
|
+
def get_flow_type(self) -> str:
|
|
55
|
+
return "Counter"
|
|
56
|
+
|
|
57
|
+
def get_steps(self) -> dex.StepList[str]:
|
|
58
|
+
return dex.StepList.start_step(self.run)
|
|
59
|
+
|
|
60
|
+
def get_persistence_schema(self) -> dex.PersistenceSchema:
|
|
61
|
+
return dex.PersistenceSchema.of(counter, counters_by_region)
|
|
62
|
+
|
|
63
|
+
@dex.rpc(name="Increment")
|
|
64
|
+
def increment(
|
|
65
|
+
self, context: dex.Context, input: int
|
|
66
|
+
) -> dex.RPCResult[int]:
|
|
67
|
+
return dex.RPCResult(input + 1)
|
|
68
|
+
|
|
69
|
+
flow = CounterFlow()
|
|
70
|
+
registry = dex.Registry((flow,))
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
Registry derives codecs from declared Python types and handler annotations.
|
|
74
|
+
Built-in scalar types and dataclasses need no codec arguments. Register an
|
|
75
|
+
explicit codec only for a custom encoding or a type Registry cannot derive.
|
|
76
|
+
`PersistenceSchema.of(...)` accepts attributes and channels together and
|
|
77
|
+
partitions them by definition type.
|
|
78
|
+
|
|
79
|
+
`Worker` and `AsyncWorker` synchronize all registered Indexed Attributes with
|
|
80
|
+
Dex Server before opening their listener. Existing indexes return immediately;
|
|
81
|
+
failure or the default two-minute deadline aborts startup. An indexed
|
|
82
|
+
`AttributeMap` must provide one fixed `index_key`.
|
|
83
|
+
|
|
84
|
+
Initial attributes retain their value types without a public wrapper class:
|
|
85
|
+
|
|
86
|
+
```python
|
|
87
|
+
options = (
|
|
88
|
+
dex.StartFlowOptions()
|
|
89
|
+
.with_attribute(counter, 1)
|
|
90
|
+
.with_attribute(counters_by_region, "us-west", 1)
|
|
91
|
+
)
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
Opt in when declaring an Attribute or AttributeMap, and select the Store in
|
|
95
|
+
Flow configuration:
|
|
96
|
+
|
|
97
|
+
```python
|
|
98
|
+
email = dex.Attribute("customer-email", str, sync_to_attribute_store=True)
|
|
99
|
+
config = dex.FlowConfig(attribute_store_name="profiles")
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
The Store is an asynchronous latest-state projection. Deletion writes SQL
|
|
103
|
+
`NULL`, and projection failures do not roll back Flow Attributes. `None`
|
|
104
|
+
preserves the current target; an explicit empty string disables future
|
|
105
|
+
synchronization while retaining protocol presence.
|
|
106
|
+
|
|
107
|
+
```
|
|
108
|
+
pip install dex-python-sdk==0.1.0
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
See [samples](../examples/python) for use case examples.
|
|
112
|
+
|
|
113
|
+
## Requirements
|
|
114
|
+
|
|
115
|
+
- Python 3.11+
|
|
116
|
+
- [Dex server](https://github.com/superdurable/dex#how-to-use)
|
|
117
|
+
|
|
118
|
+
## Concepts
|
|
119
|
+
|
|
120
|
+
Applications implement two generic interfaces from [`dex`](dex/):
|
|
121
|
+
|
|
122
|
+
- `Flow[START_INPUT]` returns `StepList.start_step(...)`, followed by optional
|
|
123
|
+
`.other_steps(...)`, from one `get_steps()` method. The `StepList` generic
|
|
124
|
+
binds the Flow input to the starting Step input. Use `StepList.empty()` when
|
|
125
|
+
a Flow has no Steps.
|
|
126
|
+
- `Step[INPUT]` implements `execute` and optionally `wait_for`. The default
|
|
127
|
+
Worker path requires synchronous handlers. With `AsyncWorker` and
|
|
128
|
+
`Registry(..., allow_async_handlers=True)`, handlers may be `async def` and
|
|
129
|
+
`await` an `AsyncClient`.
|
|
130
|
+
|
|
131
|
+
`StepOptions.wait_for_method_timeout` and `execute_method_timeout` bound the
|
|
132
|
+
two handler calls. Timer and channel conditions determine how long a Step waits.
|
|
133
|
+
|
|
134
|
+
`Registry` validates every Flow, Step, RPC signature, durable name, lock, and
|
|
135
|
+
codec before Client or Worker startup. `Client` methods use these typed objects
|
|
136
|
+
instead of raw Flow, Step, or RPC strings.
|
|
137
|
+
|
|
138
|
+
### Errors
|
|
139
|
+
|
|
140
|
+
Client calls raise concrete `DexServiceError` subclasses. Existing-Flow reads
|
|
141
|
+
(`get_attribute`, `describe_flow`, `wait_for_flow`, and `reset_flow`) raise
|
|
142
|
+
`FlowNotFoundError` when the Flow does not exist. Mutations, RPCs, timer/Step
|
|
143
|
+
waits, config updates, and continue-as-new triggers raise
|
|
144
|
+
`FlowNotActiveError` when no running Flow can accept the operation.
|
|
145
|
+
|
|
146
|
+
```python
|
|
147
|
+
try:
|
|
148
|
+
client.publish(flow_id, orders.approved, order_id)
|
|
149
|
+
except dex.FlowNotActiveError:
|
|
150
|
+
# The Flow is missing or already closed.
|
|
151
|
+
pass
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
Duplicate starts, worker failures, RPC lock contention, and long-poll timeouts
|
|
155
|
+
raise `FlowAlreadyStartedError`, `WorkerInvocationError`,
|
|
156
|
+
`RpcLockConflictError`, and `LongPollTimeoutError`. All service errors retain
|
|
157
|
+
`code`, `sub_status`, `detail`, `operation`, `flow_id`, and the original gRPC
|
|
158
|
+
exception through Python exception chaining. Worker failures also expose
|
|
159
|
+
`worker_code`, `worker_error_type`, and `worker_error_detail`. Registration,
|
|
160
|
+
serialization, and invalid handler returns use `FlowDefinitionError`,
|
|
161
|
+
`ValueMappingError`, and `InvalidStepResultError`.
|
|
162
|
+
|
|
163
|
+
### Sync vs asyncio
|
|
164
|
+
|
|
165
|
+
- **Sync (default):** `Client` and `Worker` use blocking gRPC and a thread-pool
|
|
166
|
+
Worker. Blocking `Client` calls inside `Step.execute` are safe (one pool
|
|
167
|
+
thread is occupied; other RPCs still run).
|
|
168
|
+
- **Asyncio:** `AsyncClient` and `AsyncWorker` use `grpc.aio`. Use
|
|
169
|
+
`Registry(..., allow_async_handlers=True)` when Steps/RPCs are coroutines.
|
|
170
|
+
Inside async `execute`, inject `AsyncClient` — do not call sync `Client` on
|
|
171
|
+
the Worker event loop. Sync `Worker` still rejects coroutine handlers at
|
|
172
|
+
registry construction unless `allow_async_handlers=True` (and even then the
|
|
173
|
+
sync Worker dispatcher rejects awaitable return values).
|
|
174
|
+
|
|
175
|
+
Integration scenarios live under
|
|
176
|
+
[`tests/integ`](tests/integ/README.md). They exercise the same workflows,
|
|
177
|
+
client operations, and assertions as the Java suite against an isolated
|
|
178
|
+
`dexcli dev` environment.
|
|
179
|
+
|
|
180
|
+
## Implementation status
|
|
181
|
+
|
|
182
|
+
The strongly typed contracts, registry, synchronous Client/Worker, optional
|
|
183
|
+
`AsyncClient`/`AsyncWorker` (`grpc.aio`), and Rust-backed BlobCache are
|
|
184
|
+
implemented. Python owns its gRPC transport; the native bridge is limited to
|
|
185
|
+
the shared BlobCache. Design notes:
|
|
186
|
+
[`docs/design/plan/python-sdk-async-apis.md`](../docs/design/plan/python-sdk-async-apis.md).
|
|
187
|
+
|
|
188
|
+
## Running dex-server locally
|
|
189
|
+
|
|
190
|
+
### Option 1: use docker compose
|
|
191
|
+
See [dex README](https://github.com/superdurable/dex#using-docker-image--docker-compose)
|
|
192
|
+
|
|
193
|
+
### Option 2: VSCode Dev Container
|
|
194
|
+
|
|
195
|
+
Dev Container is an easy way to get dex-server running locally. Follow these steps to launch a dev container:
|
|
196
|
+
- Install Docker, VSCode, and [VSCode Dev Container plugin](https://marketplace.visualstudio.com/items?itemName=ms-vscode-remote.remote-containers).
|
|
197
|
+
- Open the project in VSCode.
|
|
198
|
+
```bash
|
|
199
|
+
cd dex-python-sdk
|
|
200
|
+
code .
|
|
201
|
+
```
|
|
202
|
+
- Launch the Remote-Containers: Reopen in Container command from Command Palette (Ctrl + Shift + P). You can also click in the bottom left corner to access the remote container menu.
|
|
203
|
+
- Once the dev container starts, dex-server will be listening on port 8801.
|
|
204
|
+
|
|
205
|
+
## How To Contribute
|
|
206
|
+
|
|
207
|
+
This project uses [uv](https://docs.astral.sh/uv/) for Python versions,
|
|
208
|
+
dependencies, virtual environments, locking, building, and publishing.
|
|
209
|
+
|
|
210
|
+
To install requirements:
|
|
211
|
+
|
|
212
|
+
```bash
|
|
213
|
+
uv sync --locked
|
|
214
|
+
```
|
|
215
|
+
|
|
216
|
+
Run the complete Python SDK integration suite with an isolated Dex development
|
|
217
|
+
environment:
|
|
218
|
+
|
|
219
|
+
```bash
|
|
220
|
+
./run-integration-tests.sh
|
|
221
|
+
```
|
|
222
|
+
|
|
223
|
+
### Measure integration coverage
|
|
224
|
+
|
|
225
|
+
Run the same integration suite with Python source coverage:
|
|
226
|
+
|
|
227
|
+
```bash
|
|
228
|
+
./run-integration-tests.sh --coverage
|
|
229
|
+
```
|
|
230
|
+
|
|
231
|
+
Only the integration scenarios contribute execution data, and only production
|
|
232
|
+
Python modules under `dex` are measured. Generated protobuf modules under
|
|
233
|
+
`dex/dexpb` are excluded. The
|
|
234
|
+
terminal report lists uncovered line ranges. The browser report starts at
|
|
235
|
+
`coverage/html/index.html`; `coverage/coverage.xml` and `coverage/lcov.info`
|
|
236
|
+
are also generated.
|
|
237
|
+
|
|
238
|
+
CI uploads LCOV to Codecov with GitHub OIDC under the
|
|
239
|
+
`sdk-python-integration` flag and retains the full report as the
|
|
240
|
+
`sdk-python-integration-coverage` Actions artifact.
|
|
241
|
+
|
|
242
|
+
#### Update IDL
|
|
243
|
+
|
|
244
|
+
Edit [`protos/dex.proto`](../protos/dex.proto). Rename catalog: [`docs/design/idl-renames.md`](../docs/design/idl-renames.md).
|
|
245
|
+
|
|
246
|
+
#### Generate stubs from IDL
|
|
247
|
+
|
|
248
|
+
```bash
|
|
249
|
+
make -C ../protos proto-python
|
|
250
|
+
```
|
|
251
|
+
|
|
252
|
+
Checked-in Python stubs land in `dex/dexpb/`.
|
|
253
|
+
#### Linting
|
|
254
|
+
|
|
255
|
+
Validate that every `dex.__all__` class, function, constant, public method,
|
|
256
|
+
argument, return value, dataclass field, enum value, and public instance
|
|
257
|
+
attribute has a Google-style docstring:
|
|
258
|
+
|
|
259
|
+
```bash
|
|
260
|
+
uv run --frozen python scripts/check_public_docs.py
|
|
261
|
+
```
|
|
262
|
+
|
|
263
|
+
The checker resolves definitions from the public package export table, so
|
|
264
|
+
private helpers and generated protobuf modules are excluded. Use `help(dex.Client)`
|
|
265
|
+
or IDE hover information to read the same documentation. To run all other
|
|
266
|
+
linting for this project:
|
|
267
|
+
|
|
268
|
+
```bash
|
|
269
|
+
uv run --frozen pre-commit run --show-diff-on-failure --color=always --all-files
|
|
270
|
+
```
|
|
271
|
+
|
|
272
|
+
## Code of Conduct
|
|
273
|
+
This project is governed by the [Contributor Covenant v 1.4.1](CODE_OF_CONDUCT.md). (Review the Code of Conduct and remove this sentence before publishing your project.)
|
|
274
|
+
|
|
275
|
+
## Publishing to PyPI
|
|
276
|
+
|
|
277
|
+
1. Optionally run **Publish Python SDK to PyPI** via workflow_dispatch with a version and
|
|
278
|
+
`publish=false` to validate all distributions without uploading.
|
|
279
|
+
2. Create a GitHub Release with tag `sdk-python/vX.Y.Z` (for example `sdk-python/v0.1.0`).
|
|
280
|
+
CI stamps that version into `pyproject.toml` for the build (same idea as the TypeScript
|
|
281
|
+
SDK release), then builds and smoke-tests Linux x86_64/ARM64, macOS x86_64/ARM64, and
|
|
282
|
+
Windows x86_64 wheels, verifies the source distribution, and publishes with `PYPI_TOKEN`.
|
|
283
|
+
3. After publishing, bump the committed `pyproject.toml` / docs install line when you want
|
|
284
|
+
the repo tip to reflect the released version.
|
|
285
|
+
|
|
286
|
+
A manual run publishes only from `main`, and only when `publish` is explicitly selected.
|
|
287
|
+
The dispatch `version` input is stamped the same way as a release tag.
|
|
288
|
+
|
|
289
|
+
See [CONTRIBUTING.md](../CONTRIBUTING.md#releases-monorepo-tags) for monorepo tag conventions.
|
|
290
|
+
|
|
291
|
+
## License
|
|
292
|
+
|
|
293
|
+
[Super Durable Source License 1.0](LICENSE), with legacy portions under their
|
|
294
|
+
original terms as described in [LEGACY_NOTICES.md](LEGACY_NOTICES.md).
|
|
295
|
+
|
|
@@ -0,0 +1,278 @@
|
|
|
1
|
+
|
|
2
|
+
# Dex SDK for Python
|
|
3
|
+
|
|
4
|
+
Python SDK for [Dex workflow engine](https://github.com/superdurable/dex)
|
|
5
|
+
|
|
6
|
+
## New user contracts
|
|
7
|
+
|
|
8
|
+
The rewrite targets Python 3.11+ and exposes strongly typed workflow contracts
|
|
9
|
+
from `dex`. This phase includes definitions, attributes, channels, waits,
|
|
10
|
+
decisions, codecs, registry validation, synchronous client calls, and synchronous
|
|
11
|
+
worker handlers. Python owns its gRPC Client and Worker transport;
|
|
12
|
+
the shared Rust Core is used only for BlobCache.
|
|
13
|
+
|
|
14
|
+
```python
|
|
15
|
+
from datetime import timedelta
|
|
16
|
+
|
|
17
|
+
import dex
|
|
18
|
+
|
|
19
|
+
counter = dex.Attribute("counter", int)
|
|
20
|
+
counters_by_region = dex.AttributeMap("counters-by-region", int)
|
|
21
|
+
|
|
22
|
+
class Run(dex.Step[str]):
|
|
23
|
+
def wait_for(
|
|
24
|
+
self, context: dex.Context, input: str
|
|
25
|
+
) -> dex.Wait:
|
|
26
|
+
return dex.Wait.until(
|
|
27
|
+
dex.Timer.by_duration(timedelta(seconds=1))
|
|
28
|
+
)
|
|
29
|
+
|
|
30
|
+
def execute(
|
|
31
|
+
self, context: dex.Context, input: str
|
|
32
|
+
) -> dex.StepDecision:
|
|
33
|
+
return dex.graceful_complete(input)
|
|
34
|
+
|
|
35
|
+
class CounterFlow(dex.Flow[str]):
|
|
36
|
+
run = Run()
|
|
37
|
+
|
|
38
|
+
def get_flow_type(self) -> str:
|
|
39
|
+
return "Counter"
|
|
40
|
+
|
|
41
|
+
def get_steps(self) -> dex.StepList[str]:
|
|
42
|
+
return dex.StepList.start_step(self.run)
|
|
43
|
+
|
|
44
|
+
def get_persistence_schema(self) -> dex.PersistenceSchema:
|
|
45
|
+
return dex.PersistenceSchema.of(counter, counters_by_region)
|
|
46
|
+
|
|
47
|
+
@dex.rpc(name="Increment")
|
|
48
|
+
def increment(
|
|
49
|
+
self, context: dex.Context, input: int
|
|
50
|
+
) -> dex.RPCResult[int]:
|
|
51
|
+
return dex.RPCResult(input + 1)
|
|
52
|
+
|
|
53
|
+
flow = CounterFlow()
|
|
54
|
+
registry = dex.Registry((flow,))
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
Registry derives codecs from declared Python types and handler annotations.
|
|
58
|
+
Built-in scalar types and dataclasses need no codec arguments. Register an
|
|
59
|
+
explicit codec only for a custom encoding or a type Registry cannot derive.
|
|
60
|
+
`PersistenceSchema.of(...)` accepts attributes and channels together and
|
|
61
|
+
partitions them by definition type.
|
|
62
|
+
|
|
63
|
+
`Worker` and `AsyncWorker` synchronize all registered Indexed Attributes with
|
|
64
|
+
Dex Server before opening their listener. Existing indexes return immediately;
|
|
65
|
+
failure or the default two-minute deadline aborts startup. An indexed
|
|
66
|
+
`AttributeMap` must provide one fixed `index_key`.
|
|
67
|
+
|
|
68
|
+
Initial attributes retain their value types without a public wrapper class:
|
|
69
|
+
|
|
70
|
+
```python
|
|
71
|
+
options = (
|
|
72
|
+
dex.StartFlowOptions()
|
|
73
|
+
.with_attribute(counter, 1)
|
|
74
|
+
.with_attribute(counters_by_region, "us-west", 1)
|
|
75
|
+
)
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
Opt in when declaring an Attribute or AttributeMap, and select the Store in
|
|
79
|
+
Flow configuration:
|
|
80
|
+
|
|
81
|
+
```python
|
|
82
|
+
email = dex.Attribute("customer-email", str, sync_to_attribute_store=True)
|
|
83
|
+
config = dex.FlowConfig(attribute_store_name="profiles")
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
The Store is an asynchronous latest-state projection. Deletion writes SQL
|
|
87
|
+
`NULL`, and projection failures do not roll back Flow Attributes. `None`
|
|
88
|
+
preserves the current target; an explicit empty string disables future
|
|
89
|
+
synchronization while retaining protocol presence.
|
|
90
|
+
|
|
91
|
+
```
|
|
92
|
+
pip install dex-python-sdk==0.1.0
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
See [samples](../examples/python) for use case examples.
|
|
96
|
+
|
|
97
|
+
## Requirements
|
|
98
|
+
|
|
99
|
+
- Python 3.11+
|
|
100
|
+
- [Dex server](https://github.com/superdurable/dex#how-to-use)
|
|
101
|
+
|
|
102
|
+
## Concepts
|
|
103
|
+
|
|
104
|
+
Applications implement two generic interfaces from [`dex`](dex/):
|
|
105
|
+
|
|
106
|
+
- `Flow[START_INPUT]` returns `StepList.start_step(...)`, followed by optional
|
|
107
|
+
`.other_steps(...)`, from one `get_steps()` method. The `StepList` generic
|
|
108
|
+
binds the Flow input to the starting Step input. Use `StepList.empty()` when
|
|
109
|
+
a Flow has no Steps.
|
|
110
|
+
- `Step[INPUT]` implements `execute` and optionally `wait_for`. The default
|
|
111
|
+
Worker path requires synchronous handlers. With `AsyncWorker` and
|
|
112
|
+
`Registry(..., allow_async_handlers=True)`, handlers may be `async def` and
|
|
113
|
+
`await` an `AsyncClient`.
|
|
114
|
+
|
|
115
|
+
`StepOptions.wait_for_method_timeout` and `execute_method_timeout` bound the
|
|
116
|
+
two handler calls. Timer and channel conditions determine how long a Step waits.
|
|
117
|
+
|
|
118
|
+
`Registry` validates every Flow, Step, RPC signature, durable name, lock, and
|
|
119
|
+
codec before Client or Worker startup. `Client` methods use these typed objects
|
|
120
|
+
instead of raw Flow, Step, or RPC strings.
|
|
121
|
+
|
|
122
|
+
### Errors
|
|
123
|
+
|
|
124
|
+
Client calls raise concrete `DexServiceError` subclasses. Existing-Flow reads
|
|
125
|
+
(`get_attribute`, `describe_flow`, `wait_for_flow`, and `reset_flow`) raise
|
|
126
|
+
`FlowNotFoundError` when the Flow does not exist. Mutations, RPCs, timer/Step
|
|
127
|
+
waits, config updates, and continue-as-new triggers raise
|
|
128
|
+
`FlowNotActiveError` when no running Flow can accept the operation.
|
|
129
|
+
|
|
130
|
+
```python
|
|
131
|
+
try:
|
|
132
|
+
client.publish(flow_id, orders.approved, order_id)
|
|
133
|
+
except dex.FlowNotActiveError:
|
|
134
|
+
# The Flow is missing or already closed.
|
|
135
|
+
pass
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
Duplicate starts, worker failures, RPC lock contention, and long-poll timeouts
|
|
139
|
+
raise `FlowAlreadyStartedError`, `WorkerInvocationError`,
|
|
140
|
+
`RpcLockConflictError`, and `LongPollTimeoutError`. All service errors retain
|
|
141
|
+
`code`, `sub_status`, `detail`, `operation`, `flow_id`, and the original gRPC
|
|
142
|
+
exception through Python exception chaining. Worker failures also expose
|
|
143
|
+
`worker_code`, `worker_error_type`, and `worker_error_detail`. Registration,
|
|
144
|
+
serialization, and invalid handler returns use `FlowDefinitionError`,
|
|
145
|
+
`ValueMappingError`, and `InvalidStepResultError`.
|
|
146
|
+
|
|
147
|
+
### Sync vs asyncio
|
|
148
|
+
|
|
149
|
+
- **Sync (default):** `Client` and `Worker` use blocking gRPC and a thread-pool
|
|
150
|
+
Worker. Blocking `Client` calls inside `Step.execute` are safe (one pool
|
|
151
|
+
thread is occupied; other RPCs still run).
|
|
152
|
+
- **Asyncio:** `AsyncClient` and `AsyncWorker` use `grpc.aio`. Use
|
|
153
|
+
`Registry(..., allow_async_handlers=True)` when Steps/RPCs are coroutines.
|
|
154
|
+
Inside async `execute`, inject `AsyncClient` — do not call sync `Client` on
|
|
155
|
+
the Worker event loop. Sync `Worker` still rejects coroutine handlers at
|
|
156
|
+
registry construction unless `allow_async_handlers=True` (and even then the
|
|
157
|
+
sync Worker dispatcher rejects awaitable return values).
|
|
158
|
+
|
|
159
|
+
Integration scenarios live under
|
|
160
|
+
[`tests/integ`](tests/integ/README.md). They exercise the same workflows,
|
|
161
|
+
client operations, and assertions as the Java suite against an isolated
|
|
162
|
+
`dexcli dev` environment.
|
|
163
|
+
|
|
164
|
+
## Implementation status
|
|
165
|
+
|
|
166
|
+
The strongly typed contracts, registry, synchronous Client/Worker, optional
|
|
167
|
+
`AsyncClient`/`AsyncWorker` (`grpc.aio`), and Rust-backed BlobCache are
|
|
168
|
+
implemented. Python owns its gRPC transport; the native bridge is limited to
|
|
169
|
+
the shared BlobCache. Design notes:
|
|
170
|
+
[`docs/design/plan/python-sdk-async-apis.md`](../docs/design/plan/python-sdk-async-apis.md).
|
|
171
|
+
|
|
172
|
+
## Running dex-server locally
|
|
173
|
+
|
|
174
|
+
### Option 1: use docker compose
|
|
175
|
+
See [dex README](https://github.com/superdurable/dex#using-docker-image--docker-compose)
|
|
176
|
+
|
|
177
|
+
### Option 2: VSCode Dev Container
|
|
178
|
+
|
|
179
|
+
Dev Container is an easy way to get dex-server running locally. Follow these steps to launch a dev container:
|
|
180
|
+
- Install Docker, VSCode, and [VSCode Dev Container plugin](https://marketplace.visualstudio.com/items?itemName=ms-vscode-remote.remote-containers).
|
|
181
|
+
- Open the project in VSCode.
|
|
182
|
+
```bash
|
|
183
|
+
cd dex-python-sdk
|
|
184
|
+
code .
|
|
185
|
+
```
|
|
186
|
+
- Launch the Remote-Containers: Reopen in Container command from Command Palette (Ctrl + Shift + P). You can also click in the bottom left corner to access the remote container menu.
|
|
187
|
+
- Once the dev container starts, dex-server will be listening on port 8801.
|
|
188
|
+
|
|
189
|
+
## How To Contribute
|
|
190
|
+
|
|
191
|
+
This project uses [uv](https://docs.astral.sh/uv/) for Python versions,
|
|
192
|
+
dependencies, virtual environments, locking, building, and publishing.
|
|
193
|
+
|
|
194
|
+
To install requirements:
|
|
195
|
+
|
|
196
|
+
```bash
|
|
197
|
+
uv sync --locked
|
|
198
|
+
```
|
|
199
|
+
|
|
200
|
+
Run the complete Python SDK integration suite with an isolated Dex development
|
|
201
|
+
environment:
|
|
202
|
+
|
|
203
|
+
```bash
|
|
204
|
+
./run-integration-tests.sh
|
|
205
|
+
```
|
|
206
|
+
|
|
207
|
+
### Measure integration coverage
|
|
208
|
+
|
|
209
|
+
Run the same integration suite with Python source coverage:
|
|
210
|
+
|
|
211
|
+
```bash
|
|
212
|
+
./run-integration-tests.sh --coverage
|
|
213
|
+
```
|
|
214
|
+
|
|
215
|
+
Only the integration scenarios contribute execution data, and only production
|
|
216
|
+
Python modules under `dex` are measured. Generated protobuf modules under
|
|
217
|
+
`dex/dexpb` are excluded. The
|
|
218
|
+
terminal report lists uncovered line ranges. The browser report starts at
|
|
219
|
+
`coverage/html/index.html`; `coverage/coverage.xml` and `coverage/lcov.info`
|
|
220
|
+
are also generated.
|
|
221
|
+
|
|
222
|
+
CI uploads LCOV to Codecov with GitHub OIDC under the
|
|
223
|
+
`sdk-python-integration` flag and retains the full report as the
|
|
224
|
+
`sdk-python-integration-coverage` Actions artifact.
|
|
225
|
+
|
|
226
|
+
#### Update IDL
|
|
227
|
+
|
|
228
|
+
Edit [`protos/dex.proto`](../protos/dex.proto). Rename catalog: [`docs/design/idl-renames.md`](../docs/design/idl-renames.md).
|
|
229
|
+
|
|
230
|
+
#### Generate stubs from IDL
|
|
231
|
+
|
|
232
|
+
```bash
|
|
233
|
+
make -C ../protos proto-python
|
|
234
|
+
```
|
|
235
|
+
|
|
236
|
+
Checked-in Python stubs land in `dex/dexpb/`.
|
|
237
|
+
#### Linting
|
|
238
|
+
|
|
239
|
+
Validate that every `dex.__all__` class, function, constant, public method,
|
|
240
|
+
argument, return value, dataclass field, enum value, and public instance
|
|
241
|
+
attribute has a Google-style docstring:
|
|
242
|
+
|
|
243
|
+
```bash
|
|
244
|
+
uv run --frozen python scripts/check_public_docs.py
|
|
245
|
+
```
|
|
246
|
+
|
|
247
|
+
The checker resolves definitions from the public package export table, so
|
|
248
|
+
private helpers and generated protobuf modules are excluded. Use `help(dex.Client)`
|
|
249
|
+
or IDE hover information to read the same documentation. To run all other
|
|
250
|
+
linting for this project:
|
|
251
|
+
|
|
252
|
+
```bash
|
|
253
|
+
uv run --frozen pre-commit run --show-diff-on-failure --color=always --all-files
|
|
254
|
+
```
|
|
255
|
+
|
|
256
|
+
## Code of Conduct
|
|
257
|
+
This project is governed by the [Contributor Covenant v 1.4.1](CODE_OF_CONDUCT.md). (Review the Code of Conduct and remove this sentence before publishing your project.)
|
|
258
|
+
|
|
259
|
+
## Publishing to PyPI
|
|
260
|
+
|
|
261
|
+
1. Optionally run **Publish Python SDK to PyPI** via workflow_dispatch with a version and
|
|
262
|
+
`publish=false` to validate all distributions without uploading.
|
|
263
|
+
2. Create a GitHub Release with tag `sdk-python/vX.Y.Z` (for example `sdk-python/v0.1.0`).
|
|
264
|
+
CI stamps that version into `pyproject.toml` for the build (same idea as the TypeScript
|
|
265
|
+
SDK release), then builds and smoke-tests Linux x86_64/ARM64, macOS x86_64/ARM64, and
|
|
266
|
+
Windows x86_64 wheels, verifies the source distribution, and publishes with `PYPI_TOKEN`.
|
|
267
|
+
3. After publishing, bump the committed `pyproject.toml` / docs install line when you want
|
|
268
|
+
the repo tip to reflect the released version.
|
|
269
|
+
|
|
270
|
+
A manual run publishes only from `main`, and only when `publish` is explicitly selected.
|
|
271
|
+
The dispatch `version` input is stamped the same way as a release tag.
|
|
272
|
+
|
|
273
|
+
See [CONTRIBUTING.md](../CONTRIBUTING.md#releases-monorepo-tags) for monorepo tag conventions.
|
|
274
|
+
|
|
275
|
+
## License
|
|
276
|
+
|
|
277
|
+
[Super Durable Source License 1.0](LICENSE), with legacy portions under their
|
|
278
|
+
original terms as described in [LEGACY_NOTICES.md](LEGACY_NOTICES.md).
|
|
@@ -17,6 +17,8 @@ from dex.attribute import (
|
|
|
17
17
|
)
|
|
18
18
|
from dex.blob_cache import BlobCache, BlobCacheConfig, open_blob_cache
|
|
19
19
|
from dex.channel import Channel, ChannelMap
|
|
20
|
+
from dex.async_client import AsyncClient
|
|
21
|
+
from dex.async_worker import AsyncWorker
|
|
20
22
|
from dex.client import Client
|
|
21
23
|
from dex.client_options import ClientOptions
|
|
22
24
|
from dex.codec import (
|
|
@@ -35,7 +37,13 @@ from dex.condition import ConditionCombination
|
|
|
35
37
|
from dex.context import Context
|
|
36
38
|
from dex.flow import Flow, PersistenceSchema, Registry, RPCResult, rpc
|
|
37
39
|
from dex.flow_config import ActiveStepSearchMode, FlowConfig
|
|
38
|
-
from dex.flow_info import
|
|
40
|
+
from dex.flow_info import (
|
|
41
|
+
FlowInfo,
|
|
42
|
+
FlowStatus,
|
|
43
|
+
HealthInfo,
|
|
44
|
+
SearchFlowEntry,
|
|
45
|
+
SearchFlowsPage,
|
|
46
|
+
)
|
|
39
47
|
from dex.flow_options import (
|
|
40
48
|
IdReusePolicy,
|
|
41
49
|
ResetFlowOptions,
|
|
@@ -45,11 +53,19 @@ from dex.flow_options import (
|
|
|
45
53
|
StopType,
|
|
46
54
|
)
|
|
47
55
|
from dex.runtime_errors import (
|
|
48
|
-
|
|
56
|
+
DexServiceError,
|
|
49
57
|
ErrorSubStatus,
|
|
58
|
+
FlowAlreadyStartedError,
|
|
59
|
+
FlowDefinitionError,
|
|
50
60
|
FlowErrorType,
|
|
61
|
+
FlowNotActiveError,
|
|
62
|
+
FlowNotFoundError,
|
|
51
63
|
FlowUncompletedError,
|
|
64
|
+
InvalidStepResultError,
|
|
52
65
|
LongPollTimeoutError,
|
|
66
|
+
RpcLockConflictError,
|
|
67
|
+
ValueMappingError,
|
|
68
|
+
WorkerInvocationError,
|
|
53
69
|
)
|
|
54
70
|
from dex.step import (
|
|
55
71
|
RetryPolicy,
|
|
@@ -85,6 +101,8 @@ __all__ = [
|
|
|
85
101
|
"AttributeIndex",
|
|
86
102
|
"AttributeLock",
|
|
87
103
|
"AttributeMap",
|
|
104
|
+
"AsyncClient",
|
|
105
|
+
"AsyncWorker",
|
|
88
106
|
"BlobCache",
|
|
89
107
|
"BlobCacheConfig",
|
|
90
108
|
"Channel",
|
|
@@ -95,26 +113,33 @@ __all__ = [
|
|
|
95
113
|
"CodecRegistry",
|
|
96
114
|
"ConditionCombination",
|
|
97
115
|
"Context",
|
|
98
|
-
"
|
|
116
|
+
"DexServiceError",
|
|
99
117
|
"ErrorSubStatus",
|
|
100
118
|
"Flow",
|
|
119
|
+
"FlowAlreadyStartedError",
|
|
101
120
|
"FlowConfig",
|
|
121
|
+
"FlowDefinitionError",
|
|
102
122
|
"FlowErrorType",
|
|
103
123
|
"FlowInfo",
|
|
124
|
+
"FlowNotActiveError",
|
|
125
|
+
"FlowNotFoundError",
|
|
104
126
|
"FlowStatus",
|
|
105
127
|
"FlowUncompletedError",
|
|
106
128
|
"HealthInfo",
|
|
107
129
|
"IdReusePolicy",
|
|
130
|
+
"InvalidStepResultError",
|
|
108
131
|
"IndexType",
|
|
109
132
|
"JsonCodec",
|
|
110
133
|
"LongPollTimeoutError",
|
|
111
134
|
"PersistenceSchema",
|
|
112
135
|
"RPCResult",
|
|
136
|
+
"RpcLockConflictError",
|
|
113
137
|
"Registry",
|
|
114
138
|
"ResetFlowOptions",
|
|
115
139
|
"ResetType",
|
|
116
140
|
"RetryPolicy",
|
|
117
141
|
"SearchFlowEntry",
|
|
142
|
+
"SearchFlowsPage",
|
|
118
143
|
"StartFlowOptions",
|
|
119
144
|
"StepExecutionId",
|
|
120
145
|
"StepDecision",
|
|
@@ -128,10 +153,12 @@ __all__ = [
|
|
|
128
153
|
"Timer",
|
|
129
154
|
"TimerId",
|
|
130
155
|
"Value",
|
|
156
|
+
"ValueMappingError",
|
|
131
157
|
"Wait",
|
|
132
158
|
"WaitForFailurePolicy",
|
|
133
159
|
"WireKind",
|
|
134
160
|
"Worker",
|
|
161
|
+
"WorkerInvocationError",
|
|
135
162
|
"WorkerOptions",
|
|
136
163
|
"WorkerTarget",
|
|
137
164
|
"dead_end",
|