dex-python-sdk 0.12.1__tar.gz → 0.13.0__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.12.1 → dex_python_sdk-0.13.0}/PKG-INFO +25 -1
- {dex_python_sdk-0.12.1 → dex_python_sdk-0.13.0}/README.md +24 -0
- {dex_python_sdk-0.12.1 → dex_python_sdk-0.13.0}/dex/__init__.py +2 -0
- {dex_python_sdk-0.12.1 → dex_python_sdk-0.13.0}/dex/async_client.py +32 -4
- {dex_python_sdk-0.12.1 → dex_python_sdk-0.13.0}/dex/client.py +32 -4
- {dex_python_sdk-0.12.1 → dex_python_sdk-0.13.0}/dex/flow.py +63 -0
- dex_python_sdk-0.13.0/dex/rpc_invoke_options.py +42 -0
- {dex_python_sdk-0.12.1 → dex_python_sdk-0.13.0}/pyproject.toml +1 -1
- {dex_python_sdk-0.12.1 → dex_python_sdk-0.13.0}/LEGACY_NOTICES.md +0 -0
- {dex_python_sdk-0.12.1 → dex_python_sdk-0.13.0}/LICENSE +0 -0
- {dex_python_sdk-0.12.1 → dex_python_sdk-0.13.0}/dex/_async_value_hydrator.py +0 -0
- {dex_python_sdk-0.12.1 → dex_python_sdk-0.13.0}/dex/_async_worker_dispatcher.py +0 -0
- {dex_python_sdk-0.12.1 → dex_python_sdk-0.13.0}/dex/_async_worker_service.py +0 -0
- {dex_python_sdk-0.12.1 → dex_python_sdk-0.13.0}/dex/_grpc_errors.py +0 -0
- {dex_python_sdk-0.12.1 → dex_python_sdk-0.13.0}/dex/_invocation_context.py +0 -0
- {dex_python_sdk-0.12.1 → dex_python_sdk-0.13.0}/dex/_native.pyi +0 -0
- {dex_python_sdk-0.12.1 → dex_python_sdk-0.13.0}/dex/_server_protocol.py +0 -0
- {dex_python_sdk-0.12.1 → dex_python_sdk-0.13.0}/dex/_utils.py +0 -0
- {dex_python_sdk-0.12.1 → dex_python_sdk-0.13.0}/dex/_value_hydrator.py +0 -0
- {dex_python_sdk-0.12.1 → dex_python_sdk-0.13.0}/dex/_value_mapper.py +0 -0
- {dex_python_sdk-0.12.1 → dex_python_sdk-0.13.0}/dex/_worker_dispatcher.py +0 -0
- {dex_python_sdk-0.12.1 → dex_python_sdk-0.13.0}/dex/_worker_service.py +0 -0
- {dex_python_sdk-0.12.1 → dex_python_sdk-0.13.0}/dex/async_worker.py +0 -0
- {dex_python_sdk-0.12.1 → dex_python_sdk-0.13.0}/dex/attribute.py +0 -0
- {dex_python_sdk-0.12.1 → dex_python_sdk-0.13.0}/dex/attribute_match.py +0 -0
- {dex_python_sdk-0.12.1 → dex_python_sdk-0.13.0}/dex/blob_cache.py +0 -0
- {dex_python_sdk-0.12.1 → dex_python_sdk-0.13.0}/dex/channel.py +0 -0
- {dex_python_sdk-0.12.1 → dex_python_sdk-0.13.0}/dex/client_options.py +0 -0
- {dex_python_sdk-0.12.1 → dex_python_sdk-0.13.0}/dex/codec.py +0 -0
- {dex_python_sdk-0.12.1 → dex_python_sdk-0.13.0}/dex/condition.py +0 -0
- {dex_python_sdk-0.12.1 → dex_python_sdk-0.13.0}/dex/context.py +0 -0
- {dex_python_sdk-0.12.1 → dex_python_sdk-0.13.0}/dex/dexpb/__init__.py +0 -0
- {dex_python_sdk-0.12.1 → dex_python_sdk-0.13.0}/dex/dexpb/dex_pb2.py +0 -0
- {dex_python_sdk-0.12.1 → dex_python_sdk-0.13.0}/dex/dexpb/dex_pb2.pyi +0 -0
- {dex_python_sdk-0.12.1 → dex_python_sdk-0.13.0}/dex/dexpb/dex_pb2_grpc.py +0 -0
- {dex_python_sdk-0.12.1 → dex_python_sdk-0.13.0}/dex/flow_config.py +0 -0
- {dex_python_sdk-0.12.1 → dex_python_sdk-0.13.0}/dex/flow_info.py +0 -0
- {dex_python_sdk-0.12.1 → dex_python_sdk-0.13.0}/dex/flow_options.py +0 -0
- {dex_python_sdk-0.12.1 → dex_python_sdk-0.13.0}/dex/flow_result.py +0 -0
- {dex_python_sdk-0.12.1 → dex_python_sdk-0.13.0}/dex/py.typed +0 -0
- {dex_python_sdk-0.12.1 → dex_python_sdk-0.13.0}/dex/runtime_errors.py +0 -0
- {dex_python_sdk-0.12.1 → dex_python_sdk-0.13.0}/dex/step.py +0 -0
- {dex_python_sdk-0.12.1 → dex_python_sdk-0.13.0}/dex/step_execution.py +0 -0
- {dex_python_sdk-0.12.1 → dex_python_sdk-0.13.0}/dex/stream.py +0 -0
- {dex_python_sdk-0.12.1 → dex_python_sdk-0.13.0}/dex/subflow.py +0 -0
- {dex_python_sdk-0.12.1 → dex_python_sdk-0.13.0}/dex/timer.py +0 -0
- {dex_python_sdk-0.12.1 → dex_python_sdk-0.13.0}/dex/wait.py +0 -0
- {dex_python_sdk-0.12.1 → dex_python_sdk-0.13.0}/dex/wait_options.py +0 -0
- {dex_python_sdk-0.12.1 → dex_python_sdk-0.13.0}/dex/worker.py +0 -0
- {dex_python_sdk-0.12.1 → dex_python_sdk-0.13.0}/dex/worker_options.py +0 -0
- {dex_python_sdk-0.12.1 → dex_python_sdk-0.13.0}/sdk-rust/Cargo.lock +0 -0
- {dex_python_sdk-0.12.1 → dex_python_sdk-0.13.0}/sdk-rust/Cargo.toml +0 -0
- {dex_python_sdk-0.12.1 → dex_python_sdk-0.13.0}/sdk-rust/crates/dex-blob-cache/Cargo.toml +0 -0
- {dex_python_sdk-0.12.1 → dex_python_sdk-0.13.0}/sdk-rust/crates/dex-blob-cache/LICENSE +0 -0
- {dex_python_sdk-0.12.1 → dex_python_sdk-0.13.0}/sdk-rust/crates/dex-blob-cache/src/config.rs +0 -0
- {dex_python_sdk-0.12.1 → dex_python_sdk-0.13.0}/sdk-rust/crates/dex-blob-cache/src/entry.rs +0 -0
- {dex_python_sdk-0.12.1 → dex_python_sdk-0.13.0}/sdk-rust/crates/dex-blob-cache/src/error.rs +0 -0
- {dex_python_sdk-0.12.1 → dex_python_sdk-0.13.0}/sdk-rust/crates/dex-blob-cache/src/format.rs +0 -0
- {dex_python_sdk-0.12.1 → dex_python_sdk-0.13.0}/sdk-rust/crates/dex-blob-cache/src/lib.rs +0 -0
- {dex_python_sdk-0.12.1 → dex_python_sdk-0.13.0}/sdk-rust/crates/dex-blob-cache/src/policy.rs +0 -0
- {dex_python_sdk-0.12.1 → dex_python_sdk-0.13.0}/sdk-rust/crates/dex-blob-cache/src/store.rs +0 -0
- {dex_python_sdk-0.12.1 → dex_python_sdk-0.13.0}/sdk-rust/crates/dex-blob-cache/tests/blob_cache_integration.rs +0 -0
- {dex_python_sdk-0.12.1 → dex_python_sdk-0.13.0}/sdk-rust/crates/dex-blob-cache-python/Cargo.toml +0 -0
- {dex_python_sdk-0.12.1 → dex_python_sdk-0.13.0}/sdk-rust/crates/dex-blob-cache-python/LICENSE +0 -0
- {dex_python_sdk-0.12.1 → dex_python_sdk-0.13.0}/sdk-rust/crates/dex-blob-cache-python/src/lib.rs +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: dex-python-sdk
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.13.0
|
|
4
4
|
Requires-Dist: grpcio>=1.83.0
|
|
5
5
|
Requires-Dist: grpcio-status>=1.83.0
|
|
6
6
|
Requires-Dist: protobuf>=7.35.1
|
|
@@ -58,6 +58,30 @@ atomic commit and Channel deletion validation. Attribute locks add isolation
|
|
|
58
58
|
only among cooperating Steps and RPCs using the same lock. Write-only publish
|
|
59
59
|
and delete operations do not require loading.
|
|
60
60
|
|
|
61
|
+
### Invocation-time map instances
|
|
62
|
+
|
|
63
|
+
The `@rpc` decorator remains the registration-time contract for timeout,
|
|
64
|
+
transactionality, locks, and fixed state loads. Pass frozen `RPCInvokeOptions`
|
|
65
|
+
through the keyword-only `options` argument when the caller chooses an exact map
|
|
66
|
+
instance at runtime:
|
|
67
|
+
|
|
68
|
+
```python
|
|
69
|
+
options = dex.RPCInvokeOptions(
|
|
70
|
+
lock_attribute_map_instances=(profiles.lock(partition_name),),
|
|
71
|
+
load_attribute_map_instances=(profiles.load(partition_name),),
|
|
72
|
+
)
|
|
73
|
+
result = client.invoke_rpc(
|
|
74
|
+
directory.upsert_customer_profile,
|
|
75
|
+
flow_id,
|
|
76
|
+
profile,
|
|
77
|
+
options=options,
|
|
78
|
+
)
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
`Client` and `AsyncClient` union, sort, and deduplicate these selections with the
|
|
82
|
+
registered ones. Locking and loading are independent; read-modify-write handlers
|
|
83
|
+
need both for the same instance.
|
|
84
|
+
|
|
61
85
|
## Step and timeout-handler state loading
|
|
62
86
|
|
|
63
87
|
`StepOptions` provides the same five selections independently for `wait_for` and
|
|
@@ -42,6 +42,30 @@ atomic commit and Channel deletion validation. Attribute locks add isolation
|
|
|
42
42
|
only among cooperating Steps and RPCs using the same lock. Write-only publish
|
|
43
43
|
and delete operations do not require loading.
|
|
44
44
|
|
|
45
|
+
### Invocation-time map instances
|
|
46
|
+
|
|
47
|
+
The `@rpc` decorator remains the registration-time contract for timeout,
|
|
48
|
+
transactionality, locks, and fixed state loads. Pass frozen `RPCInvokeOptions`
|
|
49
|
+
through the keyword-only `options` argument when the caller chooses an exact map
|
|
50
|
+
instance at runtime:
|
|
51
|
+
|
|
52
|
+
```python
|
|
53
|
+
options = dex.RPCInvokeOptions(
|
|
54
|
+
lock_attribute_map_instances=(profiles.lock(partition_name),),
|
|
55
|
+
load_attribute_map_instances=(profiles.load(partition_name),),
|
|
56
|
+
)
|
|
57
|
+
result = client.invoke_rpc(
|
|
58
|
+
directory.upsert_customer_profile,
|
|
59
|
+
flow_id,
|
|
60
|
+
profile,
|
|
61
|
+
options=options,
|
|
62
|
+
)
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
`Client` and `AsyncClient` union, sort, and deduplicate these selections with the
|
|
66
|
+
registered ones. Locking and loading are independent; read-modify-write handlers
|
|
67
|
+
need both for the same instance.
|
|
68
|
+
|
|
45
69
|
## Step and timeout-handler state loading
|
|
46
70
|
|
|
47
71
|
`StepOptions` provides the same five selections independently for `wait_for` and
|
|
@@ -79,6 +79,7 @@ from dex.runtime_errors import (
|
|
|
79
79
|
ValueMappingError,
|
|
80
80
|
WorkerInvocationError,
|
|
81
81
|
)
|
|
82
|
+
from dex.rpc_invoke_options import RPCInvokeOptions
|
|
82
83
|
from dex.step import (
|
|
83
84
|
RetryPolicy,
|
|
84
85
|
Step,
|
|
@@ -169,6 +170,7 @@ __all__ = [
|
|
|
169
170
|
"RequestTimeoutError",
|
|
170
171
|
"PersistenceSchema",
|
|
171
172
|
"RPCResult",
|
|
173
|
+
"RPCInvokeOptions",
|
|
172
174
|
"RecoveryErrorInfo",
|
|
173
175
|
"RetryAfterError",
|
|
174
176
|
"RpcLockConflictError",
|
|
@@ -46,6 +46,7 @@ from dex.flow_options import (
|
|
|
46
46
|
)
|
|
47
47
|
from dex.flow_result import FlowResult, flow_result_from_proto
|
|
48
48
|
from dex.runtime_errors import DexServiceError, FlowErrorType, LongPollTimeoutError
|
|
49
|
+
from dex.rpc_invoke_options import RPCInvokeOptions
|
|
49
50
|
from dex.step import RetryPolicy, StepDurability
|
|
50
51
|
from dex.step_execution import StepExecutionId, TimerId
|
|
51
52
|
from dex.stream import Stream, StreamMessage, StreamMessagesPage
|
|
@@ -214,6 +215,7 @@ class AsyncClient:
|
|
|
214
215
|
input: InputT,
|
|
215
216
|
*,
|
|
216
217
|
run_id: str = "",
|
|
218
|
+
options: RPCInvokeOptions = RPCInvokeOptions(),
|
|
217
219
|
) -> OutputT: ...
|
|
218
220
|
|
|
219
221
|
@overload
|
|
@@ -223,6 +225,7 @@ class AsyncClient:
|
|
|
223
225
|
flow_id: str,
|
|
224
226
|
*,
|
|
225
227
|
run_id: str = "",
|
|
228
|
+
options: RPCInvokeOptions = RPCInvokeOptions(),
|
|
226
229
|
) -> OutputT: ...
|
|
227
230
|
|
|
228
231
|
@overload
|
|
@@ -233,6 +236,7 @@ class AsyncClient:
|
|
|
233
236
|
input: InputT,
|
|
234
237
|
*,
|
|
235
238
|
run_id: str = "",
|
|
239
|
+
options: RPCInvokeOptions = RPCInvokeOptions(),
|
|
236
240
|
) -> None: ...
|
|
237
241
|
|
|
238
242
|
@overload
|
|
@@ -242,6 +246,7 @@ class AsyncClient:
|
|
|
242
246
|
flow_id: str,
|
|
243
247
|
*,
|
|
244
248
|
run_id: str = "",
|
|
249
|
+
options: RPCInvokeOptions = RPCInvokeOptions(),
|
|
245
250
|
) -> None: ...
|
|
246
251
|
|
|
247
252
|
async def invoke_rpc(
|
|
@@ -251,6 +256,7 @@ class AsyncClient:
|
|
|
251
256
|
input: object = None,
|
|
252
257
|
*,
|
|
253
258
|
run_id: str = "",
|
|
259
|
+
options: RPCInvokeOptions = RPCInvokeOptions(),
|
|
254
260
|
) -> Any:
|
|
255
261
|
"""Invoke a registered RPC and await its typed result.
|
|
256
262
|
|
|
@@ -267,6 +273,7 @@ class AsyncClient:
|
|
|
267
273
|
input: The annotated input, or ``None`` for an input-free RPC.
|
|
268
274
|
run_id: Optional exact run. With ``""``, the server resolves the current
|
|
269
275
|
execution.
|
|
276
|
+
options: Additive runtime AttributeMap locks and exact map-instance loads.
|
|
270
277
|
|
|
271
278
|
Returns:
|
|
272
279
|
The decoded ``RPCResult.output``, or ``None`` for a no-output RPC.
|
|
@@ -279,7 +286,12 @@ class AsyncClient:
|
|
|
279
286
|
DexServiceError: If the selected path requires an active execution or the
|
|
280
287
|
service call otherwise fails.
|
|
281
288
|
"""
|
|
282
|
-
|
|
289
|
+
registered_flow, rpc = self.registry._rpc_for_method(rpc_method)
|
|
290
|
+
(
|
|
291
|
+
invocation_locks,
|
|
292
|
+
invocation_attribute_map_loads,
|
|
293
|
+
invocation_channel_map_loads,
|
|
294
|
+
) = self.registry._resolve_rpc_invoke_options(registered_flow, options)
|
|
283
295
|
encoded_input = (
|
|
284
296
|
self._values.encode(input, rpc.input_codec)
|
|
285
297
|
if rpc.input_codec is not None
|
|
@@ -300,12 +312,28 @@ class AsyncClient:
|
|
|
300
312
|
rpc_name=rpc.name,
|
|
301
313
|
input=encoded_input,
|
|
302
314
|
timeout_seconds=timeout,
|
|
303
|
-
lock_attribute_keys=
|
|
315
|
+
lock_attribute_keys=tuple(
|
|
316
|
+
sorted(set(rpc.locks + invocation_locks))
|
|
317
|
+
),
|
|
304
318
|
request_id=str(uuid4()),
|
|
305
319
|
is_transactional=rpc.options.is_transactional,
|
|
306
|
-
load_attribute_map_instances=
|
|
320
|
+
load_attribute_map_instances=tuple(
|
|
321
|
+
sorted(
|
|
322
|
+
set(
|
|
323
|
+
rpc.load_attribute_map_instances
|
|
324
|
+
+ invocation_attribute_map_loads
|
|
325
|
+
)
|
|
326
|
+
)
|
|
327
|
+
),
|
|
307
328
|
load_channel_names=rpc.load_channel_names,
|
|
308
|
-
load_channel_map_instances=
|
|
329
|
+
load_channel_map_instances=tuple(
|
|
330
|
+
sorted(
|
|
331
|
+
set(
|
|
332
|
+
rpc.load_channel_map_instances
|
|
333
|
+
+ invocation_channel_map_loads
|
|
334
|
+
)
|
|
335
|
+
)
|
|
336
|
+
),
|
|
309
337
|
),
|
|
310
338
|
"invoke_rpc",
|
|
311
339
|
flow_id,
|
|
@@ -46,6 +46,7 @@ from dex.flow_options import (
|
|
|
46
46
|
)
|
|
47
47
|
from dex.flow_result import FlowResult, flow_result_from_proto
|
|
48
48
|
from dex.runtime_errors import DexServiceError, FlowErrorType, LongPollTimeoutError
|
|
49
|
+
from dex.rpc_invoke_options import RPCInvokeOptions
|
|
49
50
|
from dex.step import RetryPolicy, StepDurability
|
|
50
51
|
from dex.step_execution import StepExecutionId, TimerId
|
|
51
52
|
from dex.stream import Stream, StreamMessage, StreamMessagesPage
|
|
@@ -213,6 +214,7 @@ class Client:
|
|
|
213
214
|
input: InputT,
|
|
214
215
|
*,
|
|
215
216
|
run_id: str = "",
|
|
217
|
+
options: RPCInvokeOptions = RPCInvokeOptions(),
|
|
216
218
|
) -> OutputT: ...
|
|
217
219
|
|
|
218
220
|
@overload
|
|
@@ -222,6 +224,7 @@ class Client:
|
|
|
222
224
|
flow_id: str,
|
|
223
225
|
*,
|
|
224
226
|
run_id: str = "",
|
|
227
|
+
options: RPCInvokeOptions = RPCInvokeOptions(),
|
|
225
228
|
) -> OutputT: ...
|
|
226
229
|
|
|
227
230
|
@overload
|
|
@@ -232,6 +235,7 @@ class Client:
|
|
|
232
235
|
input: InputT,
|
|
233
236
|
*,
|
|
234
237
|
run_id: str = "",
|
|
238
|
+
options: RPCInvokeOptions = RPCInvokeOptions(),
|
|
235
239
|
) -> None: ...
|
|
236
240
|
|
|
237
241
|
@overload
|
|
@@ -241,6 +245,7 @@ class Client:
|
|
|
241
245
|
flow_id: str,
|
|
242
246
|
*,
|
|
243
247
|
run_id: str = "",
|
|
248
|
+
options: RPCInvokeOptions = RPCInvokeOptions(),
|
|
244
249
|
) -> None: ...
|
|
245
250
|
|
|
246
251
|
def invoke_rpc(
|
|
@@ -250,6 +255,7 @@ class Client:
|
|
|
250
255
|
input: object = None,
|
|
251
256
|
*,
|
|
252
257
|
run_id: str = "",
|
|
258
|
+
options: RPCInvokeOptions = RPCInvokeOptions(),
|
|
253
259
|
) -> Any:
|
|
254
260
|
"""Synchronously invoke a registered RPC on a Flow execution.
|
|
255
261
|
|
|
@@ -266,6 +272,7 @@ class Client:
|
|
|
266
272
|
input: The annotated RPC input, or ``None`` for an input-free RPC.
|
|
267
273
|
run_id: Optional exact run. With ``""``, the server resolves the current
|
|
268
274
|
execution.
|
|
275
|
+
options: Additive runtime AttributeMap locks and exact map-instance loads.
|
|
269
276
|
|
|
270
277
|
Returns:
|
|
271
278
|
The decoded ``RPCResult.output``, or ``None`` for a no-output RPC.
|
|
@@ -278,7 +285,12 @@ class Client:
|
|
|
278
285
|
DexServiceError: If the selected path requires an active execution or the
|
|
279
286
|
service call otherwise fails.
|
|
280
287
|
"""
|
|
281
|
-
|
|
288
|
+
registered_flow, rpc = self.registry._rpc_for_method(rpc_method)
|
|
289
|
+
(
|
|
290
|
+
invocation_locks,
|
|
291
|
+
invocation_attribute_map_loads,
|
|
292
|
+
invocation_channel_map_loads,
|
|
293
|
+
) = self.registry._resolve_rpc_invoke_options(registered_flow, options)
|
|
282
294
|
encoded_input = (
|
|
283
295
|
self._values.encode(input, rpc.input_codec)
|
|
284
296
|
if rpc.input_codec is not None
|
|
@@ -299,12 +311,28 @@ class Client:
|
|
|
299
311
|
rpc_name=rpc.name,
|
|
300
312
|
input=encoded_input,
|
|
301
313
|
timeout_seconds=timeout,
|
|
302
|
-
lock_attribute_keys=
|
|
314
|
+
lock_attribute_keys=tuple(
|
|
315
|
+
sorted(set(rpc.locks + invocation_locks))
|
|
316
|
+
),
|
|
303
317
|
request_id=str(uuid4()),
|
|
304
318
|
is_transactional=rpc.options.is_transactional,
|
|
305
|
-
load_attribute_map_instances=
|
|
319
|
+
load_attribute_map_instances=tuple(
|
|
320
|
+
sorted(
|
|
321
|
+
set(
|
|
322
|
+
rpc.load_attribute_map_instances
|
|
323
|
+
+ invocation_attribute_map_loads
|
|
324
|
+
)
|
|
325
|
+
)
|
|
326
|
+
),
|
|
306
327
|
load_channel_names=rpc.load_channel_names,
|
|
307
|
-
load_channel_map_instances=
|
|
328
|
+
load_channel_map_instances=tuple(
|
|
329
|
+
sorted(
|
|
330
|
+
set(
|
|
331
|
+
rpc.load_channel_map_instances
|
|
332
|
+
+ invocation_channel_map_loads
|
|
333
|
+
)
|
|
334
|
+
)
|
|
335
|
+
),
|
|
308
336
|
),
|
|
309
337
|
"invoke_rpc",
|
|
310
338
|
flow_id,
|
|
@@ -41,6 +41,7 @@ from dex.codec import Codec, CodecRegistry
|
|
|
41
41
|
from dex.context import AsyncContext, Context
|
|
42
42
|
from dex.dexpb import dex_pb2 as pb
|
|
43
43
|
from dex.runtime_errors import FlowDefinitionError
|
|
44
|
+
from dex.rpc_invoke_options import RPCInvokeOptions
|
|
44
45
|
from dex.step import Step, StepDecision, StepList, StepMovement, StepOutput, _StepDef
|
|
45
46
|
from dex.stream import Stream
|
|
46
47
|
from dex.wait import Wait
|
|
@@ -969,3 +970,65 @@ class Registry:
|
|
|
969
970
|
if registered_function is function:
|
|
970
971
|
return flow, registered_rpc
|
|
971
972
|
raise FlowDefinitionError("RPC method is not registered")
|
|
973
|
+
|
|
974
|
+
def _resolve_rpc_invoke_options(
|
|
975
|
+
self,
|
|
976
|
+
flow: _RegisteredFlow,
|
|
977
|
+
options: RPCInvokeOptions,
|
|
978
|
+
) -> tuple[tuple[str, ...], tuple[str, ...], tuple[str, ...]]:
|
|
979
|
+
lock_attribute_map_instances: list[str] = []
|
|
980
|
+
for lock in options.lock_attribute_map_instances:
|
|
981
|
+
if not isinstance(lock, AttributeLock) or not isinstance(
|
|
982
|
+
lock.attribute, AttributeMap
|
|
983
|
+
):
|
|
984
|
+
raise FlowDefinitionError(
|
|
985
|
+
"RPCInvokeOptions lock must target an AttributeMap instance"
|
|
986
|
+
)
|
|
987
|
+
if lock.instance is None:
|
|
988
|
+
raise FlowDefinitionError(
|
|
989
|
+
"RPCInvokeOptions AttributeMap lock needs an instance"
|
|
990
|
+
)
|
|
991
|
+
self._require_rpc_invoke_definition(flow, lock.attribute, "AttributeMap")
|
|
992
|
+
lock_attribute_map_instances.append(
|
|
993
|
+
lock.attribute.load(lock.instance).physical_name
|
|
994
|
+
)
|
|
995
|
+
|
|
996
|
+
load_attribute_map_instances: list[str] = []
|
|
997
|
+
for attribute_map_load in options.load_attribute_map_instances:
|
|
998
|
+
if not isinstance(attribute_map_load, AttributeMapLoad):
|
|
999
|
+
raise FlowDefinitionError(
|
|
1000
|
+
"RPCInvokeOptions has an invalid AttributeMap load"
|
|
1001
|
+
)
|
|
1002
|
+
self._require_rpc_invoke_definition(
|
|
1003
|
+
flow, attribute_map_load.attribute_map, "AttributeMap"
|
|
1004
|
+
)
|
|
1005
|
+
load_attribute_map_instances.append(attribute_map_load.physical_name)
|
|
1006
|
+
|
|
1007
|
+
load_channel_map_instances: list[str] = []
|
|
1008
|
+
for channel_map_load in options.load_channel_map_instances:
|
|
1009
|
+
if not isinstance(channel_map_load, ChannelMapLoad):
|
|
1010
|
+
raise FlowDefinitionError(
|
|
1011
|
+
"RPCInvokeOptions has an invalid ChannelMap load"
|
|
1012
|
+
)
|
|
1013
|
+
self._require_rpc_invoke_definition(
|
|
1014
|
+
flow, channel_map_load.channel_map, "ChannelMap"
|
|
1015
|
+
)
|
|
1016
|
+
load_channel_map_instances.append(channel_map_load.physical_name)
|
|
1017
|
+
|
|
1018
|
+
return (
|
|
1019
|
+
tuple(sorted(set(lock_attribute_map_instances))),
|
|
1020
|
+
tuple(sorted(set(load_attribute_map_instances))),
|
|
1021
|
+
tuple(sorted(set(load_channel_map_instances))),
|
|
1022
|
+
)
|
|
1023
|
+
|
|
1024
|
+
@staticmethod
|
|
1025
|
+
def _require_rpc_invoke_definition(
|
|
1026
|
+
flow: _RegisteredFlow,
|
|
1027
|
+
definition: object,
|
|
1028
|
+
kind: str,
|
|
1029
|
+
) -> None:
|
|
1030
|
+
registered = flow.persistence.get(getattr(definition, "name", ""))
|
|
1031
|
+
if registered is not definition:
|
|
1032
|
+
raise FlowDefinitionError(
|
|
1033
|
+
f"Flow {flow.name} does not register {kind} definition"
|
|
1034
|
+
)
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
# Copyright (c) 2026 Super Durable, Inc.
|
|
2
|
+
#
|
|
3
|
+
# Licensed under the Sustainable Use License 1.0.
|
|
4
|
+
# You may not use this file except in compliance with the License.
|
|
5
|
+
# See the LICENSE file in the repository root.
|
|
6
|
+
#
|
|
7
|
+
# SPDX-License-Identifier: LicenseRef-Sustainable-Use-1.0
|
|
8
|
+
|
|
9
|
+
from __future__ import annotations
|
|
10
|
+
|
|
11
|
+
from dataclasses import dataclass
|
|
12
|
+
|
|
13
|
+
from dex.attribute import AttributeLock, AttributeMapLoad
|
|
14
|
+
from dex.channel import ChannelMapLoad
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
@dataclass(frozen=True)
|
|
18
|
+
class RPCInvokeOptions:
|
|
19
|
+
"""Add runtime-selected map instances to one RPC invocation.
|
|
20
|
+
|
|
21
|
+
Dex unions these selections with the RPC decorator's fixed locks and state loads,
|
|
22
|
+
then sorts and deduplicates their physical names. Locking and loading are
|
|
23
|
+
independent. A read-modify-write handler must include the same AttributeMap
|
|
24
|
+
instance in both collections.
|
|
25
|
+
|
|
26
|
+
Attributes:
|
|
27
|
+
lock_attribute_map_instances: AttributeMap instance locks for this call.
|
|
28
|
+
load_attribute_map_instances: Exact AttributeMap instance snapshots.
|
|
29
|
+
load_channel_map_instances: Exact ChannelMap pending-message snapshots.
|
|
30
|
+
|
|
31
|
+
Examples:
|
|
32
|
+
>>> options = RPCInvokeOptions(
|
|
33
|
+
... lock_attribute_map_instances=(profiles.lock(partition),),
|
|
34
|
+
... load_attribute_map_instances=(profiles.load(partition),),
|
|
35
|
+
... )
|
|
36
|
+
>>> client.invoke_rpc(directory.upsert_customer_profile, flow_id, profile,
|
|
37
|
+
... options=options)
|
|
38
|
+
"""
|
|
39
|
+
|
|
40
|
+
lock_attribute_map_instances: tuple[AttributeLock, ...] = ()
|
|
41
|
+
load_attribute_map_instances: tuple[AttributeMapLoad, ...] = ()
|
|
42
|
+
load_channel_map_instances: tuple[ChannelMapLoad, ...] = ()
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "dex-python-sdk"
|
|
3
3
|
# Publish uses tag sdk-python/v*; CI stamps this for release builds.
|
|
4
|
-
version = "0.
|
|
4
|
+
version = "0.13.0"
|
|
5
5
|
description = "Python SDK for the Dex workflow engine"
|
|
6
6
|
authors = [{name = "Super Durable"}]
|
|
7
7
|
readme = "README.md"
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{dex_python_sdk-0.12.1 → dex_python_sdk-0.13.0}/sdk-rust/crates/dex-blob-cache/src/config.rs
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{dex_python_sdk-0.12.1 → dex_python_sdk-0.13.0}/sdk-rust/crates/dex-blob-cache/src/format.rs
RENAMED
|
File without changes
|
|
File without changes
|
{dex_python_sdk-0.12.1 → dex_python_sdk-0.13.0}/sdk-rust/crates/dex-blob-cache/src/policy.rs
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{dex_python_sdk-0.12.1 → dex_python_sdk-0.13.0}/sdk-rust/crates/dex-blob-cache-python/Cargo.toml
RENAMED
|
File without changes
|
{dex_python_sdk-0.12.1 → dex_python_sdk-0.13.0}/sdk-rust/crates/dex-blob-cache-python/LICENSE
RENAMED
|
File without changes
|
{dex_python_sdk-0.12.1 → dex_python_sdk-0.13.0}/sdk-rust/crates/dex-blob-cache-python/src/lib.rs
RENAMED
|
File without changes
|