dex-python-sdk 0.4.0__tar.gz → 0.6.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.4.0 → dex_python_sdk-0.6.0}/PKG-INFO +17 -9
- {dex_python_sdk-0.4.0 → dex_python_sdk-0.6.0}/README.md +16 -8
- {dex_python_sdk-0.4.0 → dex_python_sdk-0.6.0}/dex/__init__.py +2 -0
- {dex_python_sdk-0.4.0 → dex_python_sdk-0.6.0}/dex/async_client.py +69 -376
- {dex_python_sdk-0.4.0 → dex_python_sdk-0.6.0}/dex/client.py +69 -375
- dex_python_sdk-0.6.0/dex/dexpb/dex_pb2.py +501 -0
- {dex_python_sdk-0.4.0 → dex_python_sdk-0.6.0}/dex/dexpb/dex_pb2.pyi +22 -0
- {dex_python_sdk-0.4.0 → dex_python_sdk-0.6.0}/dex/dexpb/dex_pb2_grpc.py +43 -0
- {dex_python_sdk-0.4.0 → dex_python_sdk-0.6.0}/dex/stream.py +17 -1
- {dex_python_sdk-0.4.0 → dex_python_sdk-0.6.0}/pyproject.toml +1 -1
- dex_python_sdk-0.4.0/dex/dexpb/dex_pb2.py +0 -497
- {dex_python_sdk-0.4.0 → dex_python_sdk-0.6.0}/LEGACY_NOTICES.md +0 -0
- {dex_python_sdk-0.4.0 → dex_python_sdk-0.6.0}/LICENSE +0 -0
- {dex_python_sdk-0.4.0 → dex_python_sdk-0.6.0}/dex/_async_value_hydrator.py +0 -0
- {dex_python_sdk-0.4.0 → dex_python_sdk-0.6.0}/dex/_async_worker_dispatcher.py +0 -0
- {dex_python_sdk-0.4.0 → dex_python_sdk-0.6.0}/dex/_async_worker_service.py +0 -0
- {dex_python_sdk-0.4.0 → dex_python_sdk-0.6.0}/dex/_grpc_errors.py +0 -0
- {dex_python_sdk-0.4.0 → dex_python_sdk-0.6.0}/dex/_invocation_context.py +0 -0
- {dex_python_sdk-0.4.0 → dex_python_sdk-0.6.0}/dex/_native.pyi +0 -0
- {dex_python_sdk-0.4.0 → dex_python_sdk-0.6.0}/dex/_utils.py +0 -0
- {dex_python_sdk-0.4.0 → dex_python_sdk-0.6.0}/dex/_value_hydrator.py +0 -0
- {dex_python_sdk-0.4.0 → dex_python_sdk-0.6.0}/dex/_value_mapper.py +0 -0
- {dex_python_sdk-0.4.0 → dex_python_sdk-0.6.0}/dex/_worker_dispatcher.py +0 -0
- {dex_python_sdk-0.4.0 → dex_python_sdk-0.6.0}/dex/_worker_service.py +0 -0
- {dex_python_sdk-0.4.0 → dex_python_sdk-0.6.0}/dex/async_worker.py +0 -0
- {dex_python_sdk-0.4.0 → dex_python_sdk-0.6.0}/dex/attribute.py +0 -0
- {dex_python_sdk-0.4.0 → dex_python_sdk-0.6.0}/dex/attribute_match.py +0 -0
- {dex_python_sdk-0.4.0 → dex_python_sdk-0.6.0}/dex/blob_cache.py +0 -0
- {dex_python_sdk-0.4.0 → dex_python_sdk-0.6.0}/dex/channel.py +0 -0
- {dex_python_sdk-0.4.0 → dex_python_sdk-0.6.0}/dex/client_options.py +0 -0
- {dex_python_sdk-0.4.0 → dex_python_sdk-0.6.0}/dex/codec.py +0 -0
- {dex_python_sdk-0.4.0 → dex_python_sdk-0.6.0}/dex/condition.py +0 -0
- {dex_python_sdk-0.4.0 → dex_python_sdk-0.6.0}/dex/context.py +0 -0
- {dex_python_sdk-0.4.0 → dex_python_sdk-0.6.0}/dex/dexpb/__init__.py +0 -0
- {dex_python_sdk-0.4.0 → dex_python_sdk-0.6.0}/dex/flow.py +0 -0
- {dex_python_sdk-0.4.0 → dex_python_sdk-0.6.0}/dex/flow_config.py +0 -0
- {dex_python_sdk-0.4.0 → dex_python_sdk-0.6.0}/dex/flow_info.py +0 -0
- {dex_python_sdk-0.4.0 → dex_python_sdk-0.6.0}/dex/flow_options.py +0 -0
- {dex_python_sdk-0.4.0 → dex_python_sdk-0.6.0}/dex/flow_result.py +0 -0
- {dex_python_sdk-0.4.0 → dex_python_sdk-0.6.0}/dex/py.typed +0 -0
- {dex_python_sdk-0.4.0 → dex_python_sdk-0.6.0}/dex/runtime_errors.py +0 -0
- {dex_python_sdk-0.4.0 → dex_python_sdk-0.6.0}/dex/step.py +0 -0
- {dex_python_sdk-0.4.0 → dex_python_sdk-0.6.0}/dex/step_execution.py +0 -0
- {dex_python_sdk-0.4.0 → dex_python_sdk-0.6.0}/dex/subflow.py +0 -0
- {dex_python_sdk-0.4.0 → dex_python_sdk-0.6.0}/dex/timer.py +0 -0
- {dex_python_sdk-0.4.0 → dex_python_sdk-0.6.0}/dex/wait.py +0 -0
- {dex_python_sdk-0.4.0 → dex_python_sdk-0.6.0}/dex/worker.py +0 -0
- {dex_python_sdk-0.4.0 → dex_python_sdk-0.6.0}/dex/worker_options.py +0 -0
- {dex_python_sdk-0.4.0 → dex_python_sdk-0.6.0}/sdk-rust/Cargo.lock +0 -0
- {dex_python_sdk-0.4.0 → dex_python_sdk-0.6.0}/sdk-rust/Cargo.toml +0 -0
- {dex_python_sdk-0.4.0 → dex_python_sdk-0.6.0}/sdk-rust/crates/dex-blob-cache/Cargo.toml +0 -0
- {dex_python_sdk-0.4.0 → dex_python_sdk-0.6.0}/sdk-rust/crates/dex-blob-cache/LICENSE +0 -0
- {dex_python_sdk-0.4.0 → dex_python_sdk-0.6.0}/sdk-rust/crates/dex-blob-cache/src/config.rs +0 -0
- {dex_python_sdk-0.4.0 → dex_python_sdk-0.6.0}/sdk-rust/crates/dex-blob-cache/src/entry.rs +0 -0
- {dex_python_sdk-0.4.0 → dex_python_sdk-0.6.0}/sdk-rust/crates/dex-blob-cache/src/error.rs +0 -0
- {dex_python_sdk-0.4.0 → dex_python_sdk-0.6.0}/sdk-rust/crates/dex-blob-cache/src/format.rs +0 -0
- {dex_python_sdk-0.4.0 → dex_python_sdk-0.6.0}/sdk-rust/crates/dex-blob-cache/src/lib.rs +0 -0
- {dex_python_sdk-0.4.0 → dex_python_sdk-0.6.0}/sdk-rust/crates/dex-blob-cache/src/policy.rs +0 -0
- {dex_python_sdk-0.4.0 → dex_python_sdk-0.6.0}/sdk-rust/crates/dex-blob-cache/src/store.rs +0 -0
- {dex_python_sdk-0.4.0 → dex_python_sdk-0.6.0}/sdk-rust/crates/dex-blob-cache/tests/blob_cache_integration.rs +0 -0
- {dex_python_sdk-0.4.0 → dex_python_sdk-0.6.0}/sdk-rust/crates/dex-blob-cache-python/Cargo.toml +0 -0
- {dex_python_sdk-0.4.0 → dex_python_sdk-0.6.0}/sdk-rust/crates/dex-blob-cache-python/LICENSE +0 -0
- {dex_python_sdk-0.4.0 → dex_python_sdk-0.6.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.6.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
|
|
@@ -17,13 +17,12 @@ Project-URL: Repository, https://github.com/superdurable/dex
|
|
|
17
17
|
|
|
18
18
|
# Dex SDK for Python
|
|
19
19
|
|
|
20
|
-
##
|
|
20
|
+
## Flow state I/O
|
|
21
21
|
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
deletion.
|
|
22
|
+
Applications read and write Flow state through typed RPCs. Client and AsyncClient
|
|
23
|
+
do not expose direct Attribute reads or writes, Channel publication, or
|
|
24
|
+
pending-message mutation. This keeps each external state transition behind a
|
|
25
|
+
Flow-owned method.
|
|
27
26
|
|
|
28
27
|
RPC handlers can stage `channel.delete(context, message_id)`. Declare the RPC as
|
|
29
28
|
`@rpc(is_transactional=True)` when a missing message must abort its other writes.
|
|
@@ -279,6 +278,15 @@ message = client.read_stream(flow_id, progress)
|
|
|
279
278
|
print(message.source)
|
|
280
279
|
```
|
|
281
280
|
|
|
281
|
+
`Client.read_stream` and `AsyncClient.read_stream` move forward one message at
|
|
282
|
+
a time and can long-poll. Their `list_stream_messages` methods return one
|
|
283
|
+
non-blocking newest-first retained page. Pass the registered `Stream`, a
|
|
284
|
+
positive page size, and an empty token for the first page. Pass
|
|
285
|
+
`StreamMessagesPage.next_page_token` unchanged to read older messages until it
|
|
286
|
+
is empty. The server caps page size at 1000 by default. A trimmed anchor returns
|
|
287
|
+
an empty page, and newer concurrent writes do not enter an existing older-page
|
|
288
|
+
chain.
|
|
289
|
+
|
|
282
290
|
### Canceling Step executions
|
|
283
291
|
|
|
284
292
|
A successful Step can cancel queued or active executions while continuing with
|
|
@@ -392,14 +400,14 @@ SubFlow.
|
|
|
392
400
|
### Errors
|
|
393
401
|
|
|
394
402
|
Client calls raise concrete `DexServiceError` subclasses. Existing-Flow reads
|
|
395
|
-
(`
|
|
403
|
+
(`describe_flow`, `wait_for_flow`, and `time_travel`) raise
|
|
396
404
|
`FlowNotFoundError` when the Flow does not exist. Mutations, RPCs, timer/Step
|
|
397
405
|
waits, config updates, and continue-as-new triggers raise
|
|
398
406
|
`FlowNotActiveError` when no running Flow can accept the operation.
|
|
399
407
|
|
|
400
408
|
```python
|
|
401
409
|
try:
|
|
402
|
-
client.
|
|
410
|
+
client.invoke_rpc(orders.update_order, order_id, update)
|
|
403
411
|
except dex.FlowNotActiveError:
|
|
404
412
|
# The Flow is missing or already closed.
|
|
405
413
|
pass
|
|
@@ -1,13 +1,12 @@
|
|
|
1
1
|
|
|
2
2
|
# Dex SDK for Python
|
|
3
3
|
|
|
4
|
-
##
|
|
4
|
+
## Flow state I/O
|
|
5
5
|
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
deletion.
|
|
6
|
+
Applications read and write Flow state through typed RPCs. Client and AsyncClient
|
|
7
|
+
do not expose direct Attribute reads or writes, Channel publication, or
|
|
8
|
+
pending-message mutation. This keeps each external state transition behind a
|
|
9
|
+
Flow-owned method.
|
|
11
10
|
|
|
12
11
|
RPC handlers can stage `channel.delete(context, message_id)`. Declare the RPC as
|
|
13
12
|
`@rpc(is_transactional=True)` when a missing message must abort its other writes.
|
|
@@ -263,6 +262,15 @@ message = client.read_stream(flow_id, progress)
|
|
|
263
262
|
print(message.source)
|
|
264
263
|
```
|
|
265
264
|
|
|
265
|
+
`Client.read_stream` and `AsyncClient.read_stream` move forward one message at
|
|
266
|
+
a time and can long-poll. Their `list_stream_messages` methods return one
|
|
267
|
+
non-blocking newest-first retained page. Pass the registered `Stream`, a
|
|
268
|
+
positive page size, and an empty token for the first page. Pass
|
|
269
|
+
`StreamMessagesPage.next_page_token` unchanged to read older messages until it
|
|
270
|
+
is empty. The server caps page size at 1000 by default. A trimmed anchor returns
|
|
271
|
+
an empty page, and newer concurrent writes do not enter an existing older-page
|
|
272
|
+
chain.
|
|
273
|
+
|
|
266
274
|
### Canceling Step executions
|
|
267
275
|
|
|
268
276
|
A successful Step can cancel queued or active executions while continuing with
|
|
@@ -376,14 +384,14 @@ SubFlow.
|
|
|
376
384
|
### Errors
|
|
377
385
|
|
|
378
386
|
Client calls raise concrete `DexServiceError` subclasses. Existing-Flow reads
|
|
379
|
-
(`
|
|
387
|
+
(`describe_flow`, `wait_for_flow`, and `time_travel`) raise
|
|
380
388
|
`FlowNotFoundError` when the Flow does not exist. Mutations, RPCs, timer/Step
|
|
381
389
|
waits, config updates, and continue-as-new triggers raise
|
|
382
390
|
`FlowNotActiveError` when no running Flow can accept the operation.
|
|
383
391
|
|
|
384
392
|
```python
|
|
385
393
|
try:
|
|
386
|
-
client.
|
|
394
|
+
client.invoke_rpc(orders.update_order, order_id, update)
|
|
387
395
|
except dex.FlowNotActiveError:
|
|
388
396
|
# The Flow is missing or already closed.
|
|
389
397
|
pass
|
|
@@ -103,6 +103,7 @@ from dex.stream import (
|
|
|
103
103
|
BufferedTextStream,
|
|
104
104
|
Stream,
|
|
105
105
|
StreamMessage,
|
|
106
|
+
StreamMessagesPage,
|
|
106
107
|
)
|
|
107
108
|
from dex.subflow import SubFlow
|
|
108
109
|
from dex.timer import Timer
|
|
@@ -190,6 +191,7 @@ __all__ = [
|
|
|
190
191
|
"StepOptions",
|
|
191
192
|
"Stream",
|
|
192
193
|
"StreamMessage",
|
|
194
|
+
"StreamMessagesPage",
|
|
193
195
|
"StopFlowOptions",
|
|
194
196
|
"StopType",
|
|
195
197
|
"Timer",
|
|
@@ -25,7 +25,7 @@ from dex._worker_dispatcher import WorkerDispatcher
|
|
|
25
25
|
from dex.attribute import Attribute, AttributeMap, _apply_attribute_store_sync
|
|
26
26
|
from dex.attribute_match import AttributeMatch, _encode_attribute_match
|
|
27
27
|
from dex.blob_cache import BlobCache
|
|
28
|
-
from dex.channel import Channel, ChannelMap
|
|
28
|
+
from dex.channel import Channel, ChannelMap
|
|
29
29
|
from dex.client_options import ClientOptions
|
|
30
30
|
from dex.context import Context
|
|
31
31
|
from dex.dexpb import dex_pb2 as pb
|
|
@@ -48,7 +48,7 @@ from dex.flow_result import FlowResult, flow_result_from_proto
|
|
|
48
48
|
from dex.runtime_errors import FlowErrorType
|
|
49
49
|
from dex.step import RetryPolicy, StepDurability
|
|
50
50
|
from dex.step_execution import StepExecutionId, TimerId
|
|
51
|
-
from dex.stream import Stream, StreamMessage
|
|
51
|
+
from dex.stream import Stream, StreamMessage, StreamMessagesPage
|
|
52
52
|
|
|
53
53
|
InputT = TypeVar("InputT")
|
|
54
54
|
OutputT = TypeVar("OutputT")
|
|
@@ -307,223 +307,6 @@ class AsyncClient:
|
|
|
307
307
|
rpc.output_codec,
|
|
308
308
|
)
|
|
309
309
|
|
|
310
|
-
@overload
|
|
311
|
-
async def get_attribute(
|
|
312
|
-
self,
|
|
313
|
-
flow_id: str,
|
|
314
|
-
attribute: Attribute[ValueT],
|
|
315
|
-
*,
|
|
316
|
-
run_id: str = "",
|
|
317
|
-
) -> ValueT: ...
|
|
318
|
-
|
|
319
|
-
@overload
|
|
320
|
-
async def get_attribute(
|
|
321
|
-
self,
|
|
322
|
-
flow_id: str,
|
|
323
|
-
attribute: AttributeMap[ValueT],
|
|
324
|
-
instance: str,
|
|
325
|
-
*,
|
|
326
|
-
run_id: str = "",
|
|
327
|
-
) -> ValueT: ...
|
|
328
|
-
|
|
329
|
-
async def get_attribute(
|
|
330
|
-
self,
|
|
331
|
-
flow_id: str,
|
|
332
|
-
attribute: Attribute[Any] | AttributeMap[Any],
|
|
333
|
-
instance: str | None = None,
|
|
334
|
-
*,
|
|
335
|
-
run_id: str = "",
|
|
336
|
-
) -> Any:
|
|
337
|
-
"""Await one decoded Attribute or AttributeMap instance.
|
|
338
|
-
|
|
339
|
-
Args:
|
|
340
|
-
flow_id: The non-empty target Flow ID.
|
|
341
|
-
attribute: A typed singleton Attribute or AttributeMap definition.
|
|
342
|
-
instance: The map instance. Omit it for a singleton Attribute. Slash is prohibited because it is a reserved character.
|
|
343
|
-
run_id: Optional exact run; ``""`` targets the current run.
|
|
344
|
-
|
|
345
|
-
Returns:
|
|
346
|
-
The decoded value, or ``None`` when unset.
|
|
347
|
-
|
|
348
|
-
Raises:
|
|
349
|
-
TypeError: If singleton/map arguments do not match the definition.
|
|
350
|
-
ValueMappingError: If the stored value cannot be decoded.
|
|
351
|
-
FlowNotFoundError: If ``flow_id`` does not exist.
|
|
352
|
-
DexServiceError: If FlowService cannot perform the request.
|
|
353
|
-
"""
|
|
354
|
-
key = self._definition_name(attribute, instance)
|
|
355
|
-
response = cast(
|
|
356
|
-
pb.GetAttributesResponse,
|
|
357
|
-
await self._call(
|
|
358
|
-
self._service.GetAttributes,
|
|
359
|
-
pb.GetAttributesRequest(
|
|
360
|
-
flow_id=require_name(flow_id),
|
|
361
|
-
run_id=run_id,
|
|
362
|
-
keys=[key],
|
|
363
|
-
),
|
|
364
|
-
"get_attribute",
|
|
365
|
-
flow_id,
|
|
366
|
-
"existing",
|
|
367
|
-
),
|
|
368
|
-
)
|
|
369
|
-
if not response.attributes:
|
|
370
|
-
return None
|
|
371
|
-
value = await self._hydrator.hydrate(response.attributes[0].value)
|
|
372
|
-
return self._values.decode(value, self._values.codec(attribute.value_type))
|
|
373
|
-
|
|
374
|
-
@overload
|
|
375
|
-
async def set_attribute(
|
|
376
|
-
self,
|
|
377
|
-
flow_id: str,
|
|
378
|
-
attribute: Attribute[ValueT],
|
|
379
|
-
value: ValueT,
|
|
380
|
-
/,
|
|
381
|
-
*,
|
|
382
|
-
run_id: str = "",
|
|
383
|
-
) -> None: ...
|
|
384
|
-
|
|
385
|
-
@overload
|
|
386
|
-
async def set_attribute(
|
|
387
|
-
self,
|
|
388
|
-
flow_id: str,
|
|
389
|
-
attribute: AttributeMap[ValueT],
|
|
390
|
-
instance: str,
|
|
391
|
-
value: ValueT,
|
|
392
|
-
/,
|
|
393
|
-
*,
|
|
394
|
-
run_id: str = "",
|
|
395
|
-
) -> None: ...
|
|
396
|
-
|
|
397
|
-
async def set_attribute(
|
|
398
|
-
self,
|
|
399
|
-
flow_id: str,
|
|
400
|
-
attribute: Attribute[Any] | AttributeMap[Any],
|
|
401
|
-
/,
|
|
402
|
-
*args: object,
|
|
403
|
-
run_id: str = "",
|
|
404
|
-
) -> None:
|
|
405
|
-
"""Write one Attribute or AttributeMap instance on an active Flow.
|
|
406
|
-
|
|
407
|
-
Singleton form is ``set_attribute(flow_id, attribute, value)``; map form is
|
|
408
|
-
``set_attribute(flow_id, attribute_map, instance, value)``.
|
|
409
|
-
|
|
410
|
-
Args:
|
|
411
|
-
flow_id: The non-empty target Flow ID.
|
|
412
|
-
attribute: A typed singleton Attribute or AttributeMap definition.
|
|
413
|
-
*args: The value, or a map instance followed by its value.
|
|
414
|
-
run_id: Optional exact run; ``""`` targets the active run.
|
|
415
|
-
|
|
416
|
-
Raises:
|
|
417
|
-
TypeError: If arguments or value type are invalid.
|
|
418
|
-
ValueMappingError: If the value cannot be encoded.
|
|
419
|
-
FlowNotActiveError: If the selected Flow run is closed.
|
|
420
|
-
DexServiceError: If FlowService cannot apply the write.
|
|
421
|
-
"""
|
|
422
|
-
instance, value = self._definition_value(attribute, args)
|
|
423
|
-
write = pb.AttributeWrite(
|
|
424
|
-
key=self._definition_name(attribute, instance),
|
|
425
|
-
value=self._values.encode(
|
|
426
|
-
value,
|
|
427
|
-
self._values.codec(attribute.value_type),
|
|
428
|
-
),
|
|
429
|
-
)
|
|
430
|
-
index = self._values.index_config(
|
|
431
|
-
attribute.index,
|
|
432
|
-
isinstance(attribute, AttributeMap),
|
|
433
|
-
)
|
|
434
|
-
if index is not None:
|
|
435
|
-
write.index_config.CopyFrom(index)
|
|
436
|
-
_apply_attribute_store_sync(write, attribute)
|
|
437
|
-
await self._call(
|
|
438
|
-
self._service.SetAttributes,
|
|
439
|
-
pb.SetAttributesRequest(
|
|
440
|
-
flow_id=require_name(flow_id),
|
|
441
|
-
run_id=run_id,
|
|
442
|
-
attributes=[write],
|
|
443
|
-
request_id=str(uuid4()),
|
|
444
|
-
),
|
|
445
|
-
"set_attribute",
|
|
446
|
-
flow_id,
|
|
447
|
-
"active",
|
|
448
|
-
)
|
|
449
|
-
|
|
450
|
-
@overload
|
|
451
|
-
async def publish(
|
|
452
|
-
self,
|
|
453
|
-
flow_id: str,
|
|
454
|
-
channel: Channel[ValueT],
|
|
455
|
-
/,
|
|
456
|
-
*values: ValueT,
|
|
457
|
-
run_id: str = "",
|
|
458
|
-
) -> None: ...
|
|
459
|
-
|
|
460
|
-
@overload
|
|
461
|
-
async def publish(
|
|
462
|
-
self,
|
|
463
|
-
flow_id: str,
|
|
464
|
-
channel: ChannelMap[ValueT],
|
|
465
|
-
instance: str,
|
|
466
|
-
/,
|
|
467
|
-
*values: ValueT,
|
|
468
|
-
run_id: str = "",
|
|
469
|
-
) -> None: ...
|
|
470
|
-
|
|
471
|
-
async def publish(
|
|
472
|
-
self,
|
|
473
|
-
flow_id: str,
|
|
474
|
-
channel: Channel[Any] | ChannelMap[Any],
|
|
475
|
-
/,
|
|
476
|
-
*args: object,
|
|
477
|
-
run_id: str = "",
|
|
478
|
-
) -> None:
|
|
479
|
-
"""Append one or more typed values to a Channel.
|
|
480
|
-
|
|
481
|
-
Singleton form supplies values directly; ChannelMap form supplies an instance
|
|
482
|
-
followed by values. Dex preserves argument order within the request.
|
|
483
|
-
|
|
484
|
-
Args:
|
|
485
|
-
flow_id: The non-empty target Flow ID.
|
|
486
|
-
channel: A typed singleton Channel or ChannelMap definition.
|
|
487
|
-
*args: Values, or a map instance followed by one or more values.
|
|
488
|
-
run_id: Optional exact run; ``""`` targets the active run.
|
|
489
|
-
|
|
490
|
-
Raises:
|
|
491
|
-
ValueError: If no value is passed or a name is empty.
|
|
492
|
-
TypeError: If map arguments or value types are invalid.
|
|
493
|
-
ValueMappingError: If a value cannot be encoded.
|
|
494
|
-
FlowNotActiveError: If the selected Flow run is closed.
|
|
495
|
-
DexServiceError: If FlowService cannot publish the batch.
|
|
496
|
-
"""
|
|
497
|
-
if isinstance(channel, ChannelMap):
|
|
498
|
-
if len(args) < 2 or not isinstance(args[0], str):
|
|
499
|
-
raise TypeError("ChannelMap publish requires instance and values")
|
|
500
|
-
instance = args[0]
|
|
501
|
-
values = args[1:]
|
|
502
|
-
else:
|
|
503
|
-
instance = None
|
|
504
|
-
values = args
|
|
505
|
-
if not values:
|
|
506
|
-
raise ValueError("publish requires at least one value")
|
|
507
|
-
name = self._definition_name(channel, instance)
|
|
508
|
-
codec = self._values.codec(channel.value_type)
|
|
509
|
-
await self._call(
|
|
510
|
-
self._service.PublishToChannel,
|
|
511
|
-
pb.PublishToChannelRequest(
|
|
512
|
-
flow_id=require_name(flow_id),
|
|
513
|
-
run_id=run_id,
|
|
514
|
-
messages=[
|
|
515
|
-
pb.ChannelMessage(
|
|
516
|
-
channel_name=name,
|
|
517
|
-
value=self._values.encode(value, codec),
|
|
518
|
-
)
|
|
519
|
-
for value in values
|
|
520
|
-
],
|
|
521
|
-
),
|
|
522
|
-
"publish",
|
|
523
|
-
flow_id,
|
|
524
|
-
"active",
|
|
525
|
-
)
|
|
526
|
-
|
|
527
310
|
async def write_stream(
|
|
528
311
|
self,
|
|
529
312
|
flow_id: str,
|
|
@@ -565,148 +348,6 @@ class AsyncClient:
|
|
|
565
348
|
"none",
|
|
566
349
|
)
|
|
567
350
|
|
|
568
|
-
@overload
|
|
569
|
-
async def get_channel_messages(
|
|
570
|
-
self,
|
|
571
|
-
flow_id: str,
|
|
572
|
-
channel: Channel[ValueT],
|
|
573
|
-
/,
|
|
574
|
-
*,
|
|
575
|
-
run_id: str = "",
|
|
576
|
-
) -> tuple[ChannelMessage[ValueT], ...]: ...
|
|
577
|
-
|
|
578
|
-
@overload
|
|
579
|
-
async def get_channel_messages(
|
|
580
|
-
self,
|
|
581
|
-
flow_id: str,
|
|
582
|
-
channel: ChannelMap[ValueT],
|
|
583
|
-
instance: str,
|
|
584
|
-
/,
|
|
585
|
-
*,
|
|
586
|
-
run_id: str = "",
|
|
587
|
-
) -> tuple[ChannelMessage[ValueT], ...]: ...
|
|
588
|
-
|
|
589
|
-
async def get_channel_messages(
|
|
590
|
-
self,
|
|
591
|
-
flow_id: str,
|
|
592
|
-
channel: Channel[Any] | ChannelMap[Any],
|
|
593
|
-
instance: str | None = None,
|
|
594
|
-
/,
|
|
595
|
-
*,
|
|
596
|
-
run_id: str = "",
|
|
597
|
-
) -> tuple[ChannelMessage[Any], ...]:
|
|
598
|
-
"""Return every pending message for a Channel in FIFO order.
|
|
599
|
-
|
|
600
|
-
Args:
|
|
601
|
-
flow_id: The non-empty target Flow ID.
|
|
602
|
-
channel: A typed singleton Channel or ChannelMap definition.
|
|
603
|
-
instance: Required ChannelMap instance; omit for a singleton Channel.
|
|
604
|
-
run_id: Optional exact run; ``""`` targets the current run.
|
|
605
|
-
|
|
606
|
-
Returns:
|
|
607
|
-
Immutable typed message envelopes with server-assigned IDs.
|
|
608
|
-
|
|
609
|
-
Raises:
|
|
610
|
-
ValueMappingError: If a pending value cannot be decoded.
|
|
611
|
-
FlowNotFoundError: If the selected Flow run does not exist.
|
|
612
|
-
DexServiceError: If FlowService cannot read the queue.
|
|
613
|
-
"""
|
|
614
|
-
name = self._definition_name(channel, instance)
|
|
615
|
-
response = cast(
|
|
616
|
-
pb.GetChannelMessagesResponse,
|
|
617
|
-
await self._call(
|
|
618
|
-
self._service.GetChannelMessages,
|
|
619
|
-
pb.GetChannelMessagesRequest(
|
|
620
|
-
flow_id=require_name(flow_id),
|
|
621
|
-
run_id=run_id,
|
|
622
|
-
channel_name=name,
|
|
623
|
-
),
|
|
624
|
-
"get_channel_messages",
|
|
625
|
-
flow_id,
|
|
626
|
-
"existing",
|
|
627
|
-
),
|
|
628
|
-
)
|
|
629
|
-
codec = self._values.codec(channel.value_type)
|
|
630
|
-
messages: list[ChannelMessage[Any]] = []
|
|
631
|
-
for message in response.messages:
|
|
632
|
-
messages.append(
|
|
633
|
-
ChannelMessage(
|
|
634
|
-
message_id=message.message_id,
|
|
635
|
-
value=self._values.decode(
|
|
636
|
-
await self._hydrator.hydrate(message.value),
|
|
637
|
-
codec,
|
|
638
|
-
),
|
|
639
|
-
)
|
|
640
|
-
)
|
|
641
|
-
return tuple(messages)
|
|
642
|
-
|
|
643
|
-
@overload
|
|
644
|
-
async def delete_channel_message(
|
|
645
|
-
self,
|
|
646
|
-
flow_id: str,
|
|
647
|
-
channel: Channel[Any],
|
|
648
|
-
message_id: str,
|
|
649
|
-
/,
|
|
650
|
-
*,
|
|
651
|
-
run_id: str = "",
|
|
652
|
-
) -> None: ...
|
|
653
|
-
|
|
654
|
-
@overload
|
|
655
|
-
async def delete_channel_message(
|
|
656
|
-
self,
|
|
657
|
-
flow_id: str,
|
|
658
|
-
channel: ChannelMap[Any],
|
|
659
|
-
instance: str,
|
|
660
|
-
message_id: str,
|
|
661
|
-
/,
|
|
662
|
-
*,
|
|
663
|
-
run_id: str = "",
|
|
664
|
-
) -> None: ...
|
|
665
|
-
|
|
666
|
-
async def delete_channel_message(
|
|
667
|
-
self,
|
|
668
|
-
flow_id: str,
|
|
669
|
-
channel: Channel[Any] | ChannelMap[Any],
|
|
670
|
-
instance_or_message_id: str,
|
|
671
|
-
message_id: str | None = None,
|
|
672
|
-
/,
|
|
673
|
-
*,
|
|
674
|
-
run_id: str = "",
|
|
675
|
-
) -> None:
|
|
676
|
-
"""Delete one pending Channel message by its server-assigned ID.
|
|
677
|
-
|
|
678
|
-
Args:
|
|
679
|
-
flow_id: The non-empty target Flow ID.
|
|
680
|
-
channel: A typed singleton Channel or ChannelMap definition.
|
|
681
|
-
instance_or_message_id: Singleton message ID or ChannelMap instance.
|
|
682
|
-
message_id: ChannelMap message ID; omit for a singleton Channel.
|
|
683
|
-
run_id: Optional exact run; ``""`` targets the active run.
|
|
684
|
-
|
|
685
|
-
Raises:
|
|
686
|
-
ChannelMessageNotFoundError: If the message is no longer pending.
|
|
687
|
-
FlowNotActiveError: If the selected Flow run is closed.
|
|
688
|
-
DexServiceError: If FlowService cannot delete the message.
|
|
689
|
-
"""
|
|
690
|
-
instance = instance_or_message_id if isinstance(channel, ChannelMap) else None
|
|
691
|
-
resolved_message_id = (
|
|
692
|
-
message_id if instance is not None else instance_or_message_id
|
|
693
|
-
)
|
|
694
|
-
if resolved_message_id is None:
|
|
695
|
-
raise ValueError("ChannelMap message ID is required")
|
|
696
|
-
await self._call(
|
|
697
|
-
self._service.DeleteChannelMessage,
|
|
698
|
-
pb.DeleteChannelMessageRequest(
|
|
699
|
-
flow_id=require_name(flow_id),
|
|
700
|
-
run_id=run_id,
|
|
701
|
-
channel_name=self._definition_name(channel, instance),
|
|
702
|
-
message_id=require_name(resolved_message_id),
|
|
703
|
-
request_id=str(uuid4()),
|
|
704
|
-
),
|
|
705
|
-
"delete_channel_message",
|
|
706
|
-
flow_id,
|
|
707
|
-
"active",
|
|
708
|
-
)
|
|
709
|
-
|
|
710
351
|
async def read_stream(
|
|
711
352
|
self,
|
|
712
353
|
flow_id: str,
|
|
@@ -767,6 +408,73 @@ class AsyncClient:
|
|
|
767
408
|
response.message.source,
|
|
768
409
|
)
|
|
769
410
|
|
|
411
|
+
async def list_stream_messages(
|
|
412
|
+
self,
|
|
413
|
+
flow_id: str,
|
|
414
|
+
stream: Stream[ValueT],
|
|
415
|
+
page_size: int,
|
|
416
|
+
before_page_token: str = "",
|
|
417
|
+
) -> StreamMessagesPage[ValueT]:
|
|
418
|
+
"""Await one newest-first page of retained Stream messages without waiting for writes.
|
|
419
|
+
|
|
420
|
+
An empty token starts at the retained tail. Pass the returned page token
|
|
421
|
+
unchanged to read older messages. Trimming may remove messages between pages.
|
|
422
|
+
|
|
423
|
+
Args:
|
|
424
|
+
flow_id: Logical Flow instance ID used as the Stream instance key.
|
|
425
|
+
stream: Exact Stream object registered in one Flow schema.
|
|
426
|
+
page_size: Positive maximum message count within the server-configured limit.
|
|
427
|
+
before_page_token: Opaque token from the preceding page, or ``""`` first.
|
|
428
|
+
|
|
429
|
+
Returns:
|
|
430
|
+
Decoded messages in newest-first order and the next-page token.
|
|
431
|
+
|
|
432
|
+
Raises:
|
|
433
|
+
ValueError: If ``page_size`` is not positive.
|
|
434
|
+
FlowDefinitionError: If the Stream is not registered.
|
|
435
|
+
ValueMappingError: If a retained message cannot be decoded.
|
|
436
|
+
DexServiceError: If FlowService cannot list the Stream.
|
|
437
|
+
"""
|
|
438
|
+
if page_size < 1:
|
|
439
|
+
raise ValueError("Stream page size must be positive")
|
|
440
|
+
flow = self.registry._flow_for_stream(stream)
|
|
441
|
+
response = cast(
|
|
442
|
+
pb.ListStreamMessagesResponse,
|
|
443
|
+
await self._call(
|
|
444
|
+
self._service.ListStreamMessages,
|
|
445
|
+
pb.ListStreamMessagesRequest(
|
|
446
|
+
flow_id=require_name(flow_id),
|
|
447
|
+
flow_type=flow.name,
|
|
448
|
+
stream_name=stream.name,
|
|
449
|
+
page_size=page_size,
|
|
450
|
+
before_page_token=before_page_token,
|
|
451
|
+
),
|
|
452
|
+
"list_stream_messages",
|
|
453
|
+
flow_id,
|
|
454
|
+
"none",
|
|
455
|
+
),
|
|
456
|
+
)
|
|
457
|
+
messages: list[StreamMessage[ValueT]] = []
|
|
458
|
+
for message in response.messages:
|
|
459
|
+
if (
|
|
460
|
+
not message.HasField("value")
|
|
461
|
+
or not message.HasField("created_time")
|
|
462
|
+
or not message.resume_token
|
|
463
|
+
):
|
|
464
|
+
raise ValueError("Dex returned an incomplete Stream message")
|
|
465
|
+
messages.append(
|
|
466
|
+
StreamMessage(
|
|
467
|
+
self._values.decode(
|
|
468
|
+
message.value,
|
|
469
|
+
self._values.codec(stream.value_type),
|
|
470
|
+
),
|
|
471
|
+
message.resume_token,
|
|
472
|
+
message.created_time.ToDatetime(tzinfo=timezone.utc),
|
|
473
|
+
message.source,
|
|
474
|
+
)
|
|
475
|
+
)
|
|
476
|
+
return StreamMessagesPage(messages, response.next_page_token)
|
|
477
|
+
|
|
770
478
|
async def wait_for_flow(
|
|
771
479
|
self,
|
|
772
480
|
flow_id: str,
|
|
@@ -1395,21 +1103,6 @@ class AsyncClient:
|
|
|
1395
1103
|
raise ValueError("static definition cannot use an instance")
|
|
1396
1104
|
return definition.name
|
|
1397
1105
|
|
|
1398
|
-
@staticmethod
|
|
1399
|
-
def _definition_value(
|
|
1400
|
-
definition: Attribute[Any] | AttributeMap[Any],
|
|
1401
|
-
args: tuple[object, ...],
|
|
1402
|
-
) -> tuple[str | None, object]:
|
|
1403
|
-
if isinstance(definition, Attribute) and len(args) == 1:
|
|
1404
|
-
return None, args[0]
|
|
1405
|
-
if (
|
|
1406
|
-
isinstance(definition, AttributeMap)
|
|
1407
|
-
and len(args) == 2
|
|
1408
|
-
and isinstance(args[0], str)
|
|
1409
|
-
):
|
|
1410
|
-
return args[0], args[1]
|
|
1411
|
-
raise TypeError("set_attribute received invalid arguments")
|
|
1412
|
-
|
|
1413
1106
|
@staticmethod
|
|
1414
1107
|
def _attribute_wait_arguments(
|
|
1415
1108
|
definition: Attribute[Any] | AttributeMap[Any],
|