dex-python-sdk 0.5.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.
Files changed (62) hide show
  1. {dex_python_sdk-0.5.0 → dex_python_sdk-0.6.0}/PKG-INFO +17 -9
  2. {dex_python_sdk-0.5.0 → dex_python_sdk-0.6.0}/README.md +16 -8
  3. {dex_python_sdk-0.5.0 → dex_python_sdk-0.6.0}/dex/async_client.py +1 -375
  4. {dex_python_sdk-0.5.0 → dex_python_sdk-0.6.0}/dex/client.py +1 -374
  5. {dex_python_sdk-0.5.0 → dex_python_sdk-0.6.0}/pyproject.toml +1 -1
  6. {dex_python_sdk-0.5.0 → dex_python_sdk-0.6.0}/LEGACY_NOTICES.md +0 -0
  7. {dex_python_sdk-0.5.0 → dex_python_sdk-0.6.0}/LICENSE +0 -0
  8. {dex_python_sdk-0.5.0 → dex_python_sdk-0.6.0}/dex/__init__.py +0 -0
  9. {dex_python_sdk-0.5.0 → dex_python_sdk-0.6.0}/dex/_async_value_hydrator.py +0 -0
  10. {dex_python_sdk-0.5.0 → dex_python_sdk-0.6.0}/dex/_async_worker_dispatcher.py +0 -0
  11. {dex_python_sdk-0.5.0 → dex_python_sdk-0.6.0}/dex/_async_worker_service.py +0 -0
  12. {dex_python_sdk-0.5.0 → dex_python_sdk-0.6.0}/dex/_grpc_errors.py +0 -0
  13. {dex_python_sdk-0.5.0 → dex_python_sdk-0.6.0}/dex/_invocation_context.py +0 -0
  14. {dex_python_sdk-0.5.0 → dex_python_sdk-0.6.0}/dex/_native.pyi +0 -0
  15. {dex_python_sdk-0.5.0 → dex_python_sdk-0.6.0}/dex/_utils.py +0 -0
  16. {dex_python_sdk-0.5.0 → dex_python_sdk-0.6.0}/dex/_value_hydrator.py +0 -0
  17. {dex_python_sdk-0.5.0 → dex_python_sdk-0.6.0}/dex/_value_mapper.py +0 -0
  18. {dex_python_sdk-0.5.0 → dex_python_sdk-0.6.0}/dex/_worker_dispatcher.py +0 -0
  19. {dex_python_sdk-0.5.0 → dex_python_sdk-0.6.0}/dex/_worker_service.py +0 -0
  20. {dex_python_sdk-0.5.0 → dex_python_sdk-0.6.0}/dex/async_worker.py +0 -0
  21. {dex_python_sdk-0.5.0 → dex_python_sdk-0.6.0}/dex/attribute.py +0 -0
  22. {dex_python_sdk-0.5.0 → dex_python_sdk-0.6.0}/dex/attribute_match.py +0 -0
  23. {dex_python_sdk-0.5.0 → dex_python_sdk-0.6.0}/dex/blob_cache.py +0 -0
  24. {dex_python_sdk-0.5.0 → dex_python_sdk-0.6.0}/dex/channel.py +0 -0
  25. {dex_python_sdk-0.5.0 → dex_python_sdk-0.6.0}/dex/client_options.py +0 -0
  26. {dex_python_sdk-0.5.0 → dex_python_sdk-0.6.0}/dex/codec.py +0 -0
  27. {dex_python_sdk-0.5.0 → dex_python_sdk-0.6.0}/dex/condition.py +0 -0
  28. {dex_python_sdk-0.5.0 → dex_python_sdk-0.6.0}/dex/context.py +0 -0
  29. {dex_python_sdk-0.5.0 → dex_python_sdk-0.6.0}/dex/dexpb/__init__.py +0 -0
  30. {dex_python_sdk-0.5.0 → dex_python_sdk-0.6.0}/dex/dexpb/dex_pb2.py +0 -0
  31. {dex_python_sdk-0.5.0 → dex_python_sdk-0.6.0}/dex/dexpb/dex_pb2.pyi +0 -0
  32. {dex_python_sdk-0.5.0 → dex_python_sdk-0.6.0}/dex/dexpb/dex_pb2_grpc.py +0 -0
  33. {dex_python_sdk-0.5.0 → dex_python_sdk-0.6.0}/dex/flow.py +0 -0
  34. {dex_python_sdk-0.5.0 → dex_python_sdk-0.6.0}/dex/flow_config.py +0 -0
  35. {dex_python_sdk-0.5.0 → dex_python_sdk-0.6.0}/dex/flow_info.py +0 -0
  36. {dex_python_sdk-0.5.0 → dex_python_sdk-0.6.0}/dex/flow_options.py +0 -0
  37. {dex_python_sdk-0.5.0 → dex_python_sdk-0.6.0}/dex/flow_result.py +0 -0
  38. {dex_python_sdk-0.5.0 → dex_python_sdk-0.6.0}/dex/py.typed +0 -0
  39. {dex_python_sdk-0.5.0 → dex_python_sdk-0.6.0}/dex/runtime_errors.py +0 -0
  40. {dex_python_sdk-0.5.0 → dex_python_sdk-0.6.0}/dex/step.py +0 -0
  41. {dex_python_sdk-0.5.0 → dex_python_sdk-0.6.0}/dex/step_execution.py +0 -0
  42. {dex_python_sdk-0.5.0 → dex_python_sdk-0.6.0}/dex/stream.py +0 -0
  43. {dex_python_sdk-0.5.0 → dex_python_sdk-0.6.0}/dex/subflow.py +0 -0
  44. {dex_python_sdk-0.5.0 → dex_python_sdk-0.6.0}/dex/timer.py +0 -0
  45. {dex_python_sdk-0.5.0 → dex_python_sdk-0.6.0}/dex/wait.py +0 -0
  46. {dex_python_sdk-0.5.0 → dex_python_sdk-0.6.0}/dex/worker.py +0 -0
  47. {dex_python_sdk-0.5.0 → dex_python_sdk-0.6.0}/dex/worker_options.py +0 -0
  48. {dex_python_sdk-0.5.0 → dex_python_sdk-0.6.0}/sdk-rust/Cargo.lock +0 -0
  49. {dex_python_sdk-0.5.0 → dex_python_sdk-0.6.0}/sdk-rust/Cargo.toml +0 -0
  50. {dex_python_sdk-0.5.0 → dex_python_sdk-0.6.0}/sdk-rust/crates/dex-blob-cache/Cargo.toml +0 -0
  51. {dex_python_sdk-0.5.0 → dex_python_sdk-0.6.0}/sdk-rust/crates/dex-blob-cache/LICENSE +0 -0
  52. {dex_python_sdk-0.5.0 → dex_python_sdk-0.6.0}/sdk-rust/crates/dex-blob-cache/src/config.rs +0 -0
  53. {dex_python_sdk-0.5.0 → dex_python_sdk-0.6.0}/sdk-rust/crates/dex-blob-cache/src/entry.rs +0 -0
  54. {dex_python_sdk-0.5.0 → dex_python_sdk-0.6.0}/sdk-rust/crates/dex-blob-cache/src/error.rs +0 -0
  55. {dex_python_sdk-0.5.0 → dex_python_sdk-0.6.0}/sdk-rust/crates/dex-blob-cache/src/format.rs +0 -0
  56. {dex_python_sdk-0.5.0 → dex_python_sdk-0.6.0}/sdk-rust/crates/dex-blob-cache/src/lib.rs +0 -0
  57. {dex_python_sdk-0.5.0 → dex_python_sdk-0.6.0}/sdk-rust/crates/dex-blob-cache/src/policy.rs +0 -0
  58. {dex_python_sdk-0.5.0 → dex_python_sdk-0.6.0}/sdk-rust/crates/dex-blob-cache/src/store.rs +0 -0
  59. {dex_python_sdk-0.5.0 → dex_python_sdk-0.6.0}/sdk-rust/crates/dex-blob-cache/tests/blob_cache_integration.rs +0 -0
  60. {dex_python_sdk-0.5.0 → dex_python_sdk-0.6.0}/sdk-rust/crates/dex-blob-cache-python/Cargo.toml +0 -0
  61. {dex_python_sdk-0.5.0 → dex_python_sdk-0.6.0}/sdk-rust/crates/dex-blob-cache-python/LICENSE +0 -0
  62. {dex_python_sdk-0.5.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.5.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
- ## Pending Channel messages
20
+ ## Flow state I/O
21
21
 
22
- `Client.get_channel_messages(flow_id, channel)` returns typed `ChannelMessage`
23
- envelopes in FIFO order. Each envelope contains the decoded value and the UUIDv7
24
- assigned by Dex. `Client.delete_channel_message` deletes only a still-pending
25
- message and raises `ChannelMessageNotFoundError` after consumption or another
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
- (`get_attribute`, `describe_flow`, `wait_for_flow`, and `time_travel`) raise
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.publish(flow_id, orders.approved, order_id)
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
- ## Pending Channel messages
4
+ ## Flow state I/O
5
5
 
6
- `Client.get_channel_messages(flow_id, channel)` returns typed `ChannelMessage`
7
- envelopes in FIFO order. Each envelope contains the decoded value and the UUIDv7
8
- assigned by Dex. `Client.delete_channel_message` deletes only a still-pending
9
- message and raises `ChannelMessageNotFoundError` after consumption or another
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
- (`get_attribute`, `describe_flow`, `wait_for_flow`, and `time_travel`) raise
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.publish(flow_id, orders.approved, order_id)
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
@@ -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, ChannelMessage
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
@@ -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,
@@ -1462,21 +1103,6 @@ class AsyncClient:
1462
1103
  raise ValueError("static definition cannot use an instance")
1463
1104
  return definition.name
1464
1105
 
1465
- @staticmethod
1466
- def _definition_value(
1467
- definition: Attribute[Any] | AttributeMap[Any],
1468
- args: tuple[object, ...],
1469
- ) -> tuple[str | None, object]:
1470
- if isinstance(definition, Attribute) and len(args) == 1:
1471
- return None, args[0]
1472
- if (
1473
- isinstance(definition, AttributeMap)
1474
- and len(args) == 2
1475
- and isinstance(args[0], str)
1476
- ):
1477
- return args[0], args[1]
1478
- raise TypeError("set_attribute received invalid arguments")
1479
-
1480
1106
  @staticmethod
1481
1107
  def _attribute_wait_arguments(
1482
1108
  definition: Attribute[Any] | AttributeMap[Any],
@@ -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, ChannelMessage
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
@@ -307,224 +307,6 @@ class Client:
307
307
  rpc.output_codec,
308
308
  )
309
309
 
310
- @overload
311
- def get_attribute(
312
- self,
313
- flow_id: str,
314
- attribute: Attribute[ValueT],
315
- *,
316
- run_id: str = "",
317
- ) -> ValueT: ...
318
-
319
- @overload
320
- 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
- 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
- """Return 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 the Attribute is 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
- 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 = self._hydrator.hydrate(response.attributes[0].value)
372
- return self._values.decode(value, self._values.codec(attribute.value_type))
373
-
374
- @overload
375
- 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
- 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
- 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 do not match the definition or value type.
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
- 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
- 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
- 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
- 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 is ``publish(flow_id, channel, *values)``; map form is
482
- ``publish(flow_id, channel_map, instance, *values)``. Values are appended in
483
- argument order as one service request.
484
-
485
- Args:
486
- flow_id: The non-empty target Flow ID.
487
- channel: A typed singleton Channel or ChannelMap definition.
488
- *args: Values, or a map instance followed by one or more values.
489
- run_id: Optional exact run; ``""`` targets the active run.
490
-
491
- Raises:
492
- ValueError: If no value is passed or a required name is empty.
493
- TypeError: If map arguments or value types are invalid.
494
- ValueMappingError: If a value cannot be encoded.
495
- FlowNotActiveError: If the selected Flow run is closed.
496
- DexServiceError: If FlowService cannot publish the batch.
497
- """
498
- if isinstance(channel, ChannelMap):
499
- if len(args) < 2 or not isinstance(args[0], str):
500
- raise TypeError("ChannelMap publish requires instance and values")
501
- instance = args[0]
502
- values = args[1:]
503
- else:
504
- instance = None
505
- values = args
506
- if not values:
507
- raise ValueError("publish requires at least one value")
508
- name = self._definition_name(channel, instance)
509
- codec = self._values.codec(channel.value_type)
510
- self._call(
511
- self._service.PublishToChannel,
512
- pb.PublishToChannelRequest(
513
- flow_id=require_name(flow_id),
514
- run_id=run_id,
515
- messages=[
516
- pb.ChannelMessage(
517
- channel_name=name,
518
- value=self._values.encode(value, codec),
519
- )
520
- for value in values
521
- ],
522
- ),
523
- "publish",
524
- flow_id,
525
- "active",
526
- )
527
-
528
310
  def write_stream(
529
311
  self,
530
312
  flow_id: str,
@@ -566,146 +348,6 @@ class Client:
566
348
  "none",
567
349
  )
568
350
 
569
- @overload
570
- def get_channel_messages(
571
- self,
572
- flow_id: str,
573
- channel: Channel[ValueT],
574
- /,
575
- *,
576
- run_id: str = "",
577
- ) -> tuple[ChannelMessage[ValueT], ...]: ...
578
-
579
- @overload
580
- def get_channel_messages(
581
- self,
582
- flow_id: str,
583
- channel: ChannelMap[ValueT],
584
- instance: str,
585
- /,
586
- *,
587
- run_id: str = "",
588
- ) -> tuple[ChannelMessage[ValueT], ...]: ...
589
-
590
- def get_channel_messages(
591
- self,
592
- flow_id: str,
593
- channel: Channel[Any] | ChannelMap[Any],
594
- instance: str | None = None,
595
- /,
596
- *,
597
- run_id: str = "",
598
- ) -> tuple[ChannelMessage[Any], ...]:
599
- """Return every pending message for a Channel in FIFO order.
600
-
601
- Args:
602
- flow_id: The non-empty target Flow ID.
603
- channel: A typed singleton Channel or ChannelMap definition.
604
- instance: Required ChannelMap instance; omit for a singleton Channel.
605
- run_id: Optional exact run; ``""`` targets the current run.
606
-
607
- Returns:
608
- Immutable typed message envelopes with server-assigned IDs.
609
-
610
- Raises:
611
- ValueMappingError: If a pending value cannot be decoded.
612
- FlowNotFoundError: If the selected Flow run does not exist.
613
- DexServiceError: If FlowService cannot read the queue.
614
- """
615
- name = self._definition_name(channel, instance)
616
- response = cast(
617
- pb.GetChannelMessagesResponse,
618
- self._call(
619
- self._service.GetChannelMessages,
620
- pb.GetChannelMessagesRequest(
621
- flow_id=require_name(flow_id),
622
- run_id=run_id,
623
- channel_name=name,
624
- ),
625
- "get_channel_messages",
626
- flow_id,
627
- "existing",
628
- ),
629
- )
630
- codec = self._values.codec(channel.value_type)
631
- return tuple(
632
- ChannelMessage(
633
- message_id=message.message_id,
634
- value=self._values.decode(
635
- self._hydrator.hydrate(message.value),
636
- codec,
637
- ),
638
- )
639
- for message in response.messages
640
- )
641
-
642
- @overload
643
- def delete_channel_message(
644
- self,
645
- flow_id: str,
646
- channel: Channel[Any],
647
- message_id: str,
648
- /,
649
- *,
650
- run_id: str = "",
651
- ) -> None: ...
652
-
653
- @overload
654
- def delete_channel_message(
655
- self,
656
- flow_id: str,
657
- channel: ChannelMap[Any],
658
- instance: str,
659
- message_id: str,
660
- /,
661
- *,
662
- run_id: str = "",
663
- ) -> None: ...
664
-
665
- def delete_channel_message(
666
- self,
667
- flow_id: str,
668
- channel: Channel[Any] | ChannelMap[Any],
669
- instance_or_message_id: str,
670
- message_id: str | None = None,
671
- /,
672
- *,
673
- run_id: str = "",
674
- ) -> None:
675
- """Delete one pending Channel message by its server-assigned ID.
676
-
677
- Args:
678
- flow_id: The non-empty target Flow ID.
679
- channel: A typed singleton Channel or ChannelMap definition.
680
- instance_or_message_id: Singleton message ID or ChannelMap instance.
681
- message_id: ChannelMap message ID; omit for a singleton Channel.
682
- run_id: Optional exact run; ``""`` targets the active run.
683
-
684
- Raises:
685
- ChannelMessageNotFoundError: If the message is no longer pending.
686
- FlowNotActiveError: If the selected Flow run is closed.
687
- DexServiceError: If FlowService cannot delete the message.
688
- """
689
- instance = instance_or_message_id if isinstance(channel, ChannelMap) else None
690
- resolved_message_id = (
691
- message_id if instance is not None else instance_or_message_id
692
- )
693
- if resolved_message_id is None:
694
- raise ValueError("ChannelMap message ID is required")
695
- self._call(
696
- self._service.DeleteChannelMessage,
697
- pb.DeleteChannelMessageRequest(
698
- flow_id=require_name(flow_id),
699
- run_id=run_id,
700
- channel_name=self._definition_name(channel, instance),
701
- message_id=require_name(resolved_message_id),
702
- request_id=str(uuid4()),
703
- ),
704
- "delete_channel_message",
705
- flow_id,
706
- "active",
707
- )
708
-
709
351
  def read_stream(
710
352
  self,
711
353
  flow_id: str,
@@ -1459,21 +1101,6 @@ class Client:
1459
1101
  raise ValueError("static definition cannot use an instance")
1460
1102
  return definition.name
1461
1103
 
1462
- @staticmethod
1463
- def _definition_value(
1464
- definition: Attribute[Any] | AttributeMap[Any],
1465
- args: tuple[object, ...],
1466
- ) -> tuple[str | None, object]:
1467
- if isinstance(definition, Attribute) and len(args) == 1:
1468
- return None, args[0]
1469
- if (
1470
- isinstance(definition, AttributeMap)
1471
- and len(args) == 2
1472
- and isinstance(args[0], str)
1473
- ):
1474
- return args[0], args[1]
1475
- raise TypeError("set_attribute received invalid arguments")
1476
-
1477
1104
  @staticmethod
1478
1105
  def _attribute_wait_arguments(
1479
1106
  definition: Attribute[Any] | AttributeMap[Any],
@@ -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.5.0"
4
+ version = "0.6.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