durable-workflow 2.8.0__tar.gz → 2.9.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 (150) hide show
  1. {durable_workflow-2.8.0/src/durable_workflow.egg-info → durable_workflow-2.9.0}/PKG-INFO +1 -1
  2. {durable_workflow-2.8.0 → durable_workflow-2.9.0}/pyproject.toml +3 -3
  3. {durable_workflow-2.8.0 → durable_workflow-2.9.0}/src/durable_workflow/workflow.py +10 -0
  4. {durable_workflow-2.8.0 → durable_workflow-2.9.0/src/durable_workflow.egg-info}/PKG-INFO +1 -1
  5. {durable_workflow-2.8.0 → durable_workflow-2.9.0}/src/durable_workflow.egg-info/SOURCES.txt +1 -0
  6. {durable_workflow-2.8.0 → durable_workflow-2.9.0}/tests/test_replay_regression_corpus.py +5 -0
  7. durable_workflow-2.9.0/tests/test_workflow_identity.py +72 -0
  8. {durable_workflow-2.8.0 → durable_workflow-2.9.0}/LICENSE +0 -0
  9. {durable_workflow-2.8.0 → durable_workflow-2.9.0}/README.md +0 -0
  10. {durable_workflow-2.8.0 → durable_workflow-2.9.0}/setup.cfg +0 -0
  11. {durable_workflow-2.8.0 → durable_workflow-2.9.0}/src/durable_workflow/__init__.py +0 -0
  12. {durable_workflow-2.8.0 → durable_workflow-2.9.0}/src/durable_workflow/_activity_lease.py +0 -0
  13. {durable_workflow-2.8.0 → durable_workflow-2.9.0}/src/durable_workflow/_activity_process.py +0 -0
  14. {durable_workflow-2.8.0 → durable_workflow-2.9.0}/src/durable_workflow/_avro.py +0 -0
  15. {durable_workflow-2.8.0 → durable_workflow-2.9.0}/src/durable_workflow/_cancellation_scope.py +0 -0
  16. {durable_workflow-2.8.0 → durable_workflow-2.9.0}/src/durable_workflow/_cancellation_scope_history.py +0 -0
  17. {durable_workflow-2.8.0 → durable_workflow-2.9.0}/src/durable_workflow/_cooperative_cancellation.py +0 -0
  18. {durable_workflow-2.8.0 → durable_workflow-2.9.0}/src/durable_workflow/_prepared_local_activity.py +0 -0
  19. {durable_workflow-2.8.0 → durable_workflow-2.9.0}/src/durable_workflow/_query_task_authority.py +0 -0
  20. {durable_workflow-2.8.0 → durable_workflow-2.9.0}/src/durable_workflow/_sticky_workflow_cache.py +0 -0
  21. {durable_workflow-2.8.0 → durable_workflow-2.9.0}/src/durable_workflow/activity.py +0 -0
  22. {durable_workflow-2.8.0 → durable_workflow-2.9.0}/src/durable_workflow/auth_composition.py +0 -0
  23. {durable_workflow-2.8.0 → durable_workflow-2.9.0}/src/durable_workflow/cancellation.py +0 -0
  24. {durable_workflow-2.8.0 → durable_workflow-2.9.0}/src/durable_workflow/client.py +0 -0
  25. {durable_workflow-2.8.0 → durable_workflow-2.9.0}/src/durable_workflow/errors.py +0 -0
  26. {durable_workflow-2.8.0 → durable_workflow-2.9.0}/src/durable_workflow/external_storage.py +0 -0
  27. {durable_workflow-2.8.0 → durable_workflow-2.9.0}/src/durable_workflow/external_task_input.py +0 -0
  28. {durable_workflow-2.8.0 → durable_workflow-2.9.0}/src/durable_workflow/external_task_result.py +0 -0
  29. {durable_workflow-2.8.0 → durable_workflow-2.9.0}/src/durable_workflow/history_bundle_verify.py +0 -0
  30. {durable_workflow-2.8.0 → durable_workflow-2.9.0}/src/durable_workflow/interceptors.py +0 -0
  31. {durable_workflow-2.8.0 → durable_workflow-2.9.0}/src/durable_workflow/invocable.py +0 -0
  32. {durable_workflow-2.8.0 → durable_workflow-2.9.0}/src/durable_workflow/metrics.py +0 -0
  33. {durable_workflow-2.8.0 → durable_workflow-2.9.0}/src/durable_workflow/nexus.py +0 -0
  34. {durable_workflow-2.8.0 → durable_workflow-2.9.0}/src/durable_workflow/py.typed +0 -0
  35. {durable_workflow-2.8.0 → durable_workflow-2.9.0}/src/durable_workflow/python_conformance.py +0 -0
  36. {durable_workflow-2.8.0 → durable_workflow-2.9.0}/src/durable_workflow/replay_conformance.py +0 -0
  37. {durable_workflow-2.8.0 → durable_workflow-2.9.0}/src/durable_workflow/replay_verify.py +0 -0
  38. {durable_workflow-2.8.0 → durable_workflow-2.9.0}/src/durable_workflow/retry_policy.py +0 -0
  39. {durable_workflow-2.8.0 → durable_workflow-2.9.0}/src/durable_workflow/serializer.py +0 -0
  40. {durable_workflow-2.8.0 → durable_workflow-2.9.0}/src/durable_workflow/sync.py +0 -0
  41. {durable_workflow-2.8.0 → durable_workflow-2.9.0}/src/durable_workflow/telemetry.py +0 -0
  42. {durable_workflow-2.8.0 → durable_workflow-2.9.0}/src/durable_workflow/telemetry_carrier.py +0 -0
  43. {durable_workflow-2.8.0 → durable_workflow-2.9.0}/src/durable_workflow/testing.py +0 -0
  44. {durable_workflow-2.8.0 → durable_workflow-2.9.0}/src/durable_workflow/worker.py +0 -0
  45. {durable_workflow-2.8.0 → durable_workflow-2.9.0}/src/durable_workflow/worker_session.py +0 -0
  46. {durable_workflow-2.8.0 → durable_workflow-2.9.0}/src/durable_workflow/workflow_updates_conformance.py +0 -0
  47. {durable_workflow-2.8.0 → durable_workflow-2.9.0}/src/durable_workflow.egg-info/dependency_links.txt +0 -0
  48. {durable_workflow-2.8.0 → durable_workflow-2.9.0}/src/durable_workflow.egg-info/entry_points.txt +0 -0
  49. {durable_workflow-2.8.0 → durable_workflow-2.9.0}/src/durable_workflow.egg-info/requires.txt +0 -0
  50. {durable_workflow-2.8.0 → durable_workflow-2.9.0}/src/durable_workflow.egg-info/top_level.txt +0 -0
  51. {durable_workflow-2.8.0 → durable_workflow-2.9.0}/tests/test_activity_cancellation_policies.py +0 -0
  52. {durable_workflow-2.8.0 → durable_workflow-2.9.0}/tests/test_activity_context.py +0 -0
  53. {durable_workflow-2.8.0 → durable_workflow-2.9.0}/tests/test_activity_heartbeat_authority.py +0 -0
  54. {durable_workflow-2.8.0 → durable_workflow-2.9.0}/tests/test_activity_lease_authority.py +0 -0
  55. {durable_workflow-2.8.0 → durable_workflow-2.9.0}/tests/test_activity_lease_renewal.py +0 -0
  56. {durable_workflow-2.8.0 → durable_workflow-2.9.0}/tests/test_activity_lease_worker.py +0 -0
  57. {durable_workflow-2.8.0 → durable_workflow-2.9.0}/tests/test_activity_process.py +0 -0
  58. {durable_workflow-2.8.0 → durable_workflow-2.9.0}/tests/test_auth_composition.py +0 -0
  59. {durable_workflow-2.8.0 → durable_workflow-2.9.0}/tests/test_avro_value_benchmark.py +0 -0
  60. {durable_workflow-2.8.0 → durable_workflow-2.9.0}/tests/test_avro_value_protocol.py +0 -0
  61. {durable_workflow-2.8.0 → durable_workflow-2.9.0}/tests/test_cancellation_context.py +0 -0
  62. {durable_workflow-2.8.0 → durable_workflow-2.9.0}/tests/test_cancellation_remaining_time.py +0 -0
  63. {durable_workflow-2.8.0 → durable_workflow-2.9.0}/tests/test_cancellation_scope_admission.py +0 -0
  64. {durable_workflow-2.8.0 → durable_workflow-2.9.0}/tests/test_cancellation_scope_authoring.py +0 -0
  65. {durable_workflow-2.8.0 → durable_workflow-2.9.0}/tests/test_cancellation_scope_boundary.py +0 -0
  66. {durable_workflow-2.8.0 → durable_workflow-2.9.0}/tests/test_cancellation_scope_opening.py +0 -0
  67. {durable_workflow-2.8.0 → durable_workflow-2.9.0}/tests/test_child_workflow_policies.py +0 -0
  68. {durable_workflow-2.8.0 → durable_workflow-2.9.0}/tests/test_ci_checkout.py +0 -0
  69. {durable_workflow-2.8.0 → durable_workflow-2.9.0}/tests/test_ci_integration_endpoint.py +0 -0
  70. {durable_workflow-2.8.0 → durable_workflow-2.9.0}/tests/test_client.py +0 -0
  71. {durable_workflow-2.8.0 → durable_workflow-2.9.0}/tests/test_client_telemetry.py +0 -0
  72. {durable_workflow-2.8.0 → durable_workflow-2.9.0}/tests/test_client_timeouts.py +0 -0
  73. {durable_workflow-2.8.0 → durable_workflow-2.9.0}/tests/test_codec_regression_corpus.py +0 -0
  74. {durable_workflow-2.8.0 → durable_workflow-2.9.0}/tests/test_committed_cancellation_scope_descendants.py +0 -0
  75. {durable_workflow-2.8.0 → durable_workflow-2.9.0}/tests/test_committed_cancellation_scope_groups.py +0 -0
  76. {durable_workflow-2.8.0 → durable_workflow-2.9.0}/tests/test_committed_cancellation_scope_history.py +0 -0
  77. {durable_workflow-2.8.0 → durable_workflow-2.9.0}/tests/test_committed_cancellation_scope_replay.py +0 -0
  78. {durable_workflow-2.8.0 → durable_workflow-2.9.0}/tests/test_condition_replay_drift.py +0 -0
  79. {durable_workflow-2.8.0 → durable_workflow-2.9.0}/tests/test_control_plane_parity_fixtures.py +0 -0
  80. {durable_workflow-2.8.0 → durable_workflow-2.9.0}/tests/test_cooperative_cancellation.py +0 -0
  81. {durable_workflow-2.8.0 → durable_workflow-2.9.0}/tests/test_cooperative_cancellation_client.py +0 -0
  82. {durable_workflow-2.8.0 → durable_workflow-2.9.0}/tests/test_cooperative_cancellation_worker.py +0 -0
  83. {durable_workflow-2.8.0 → durable_workflow-2.9.0}/tests/test_cooperative_remote_worker.py +0 -0
  84. {durable_workflow-2.8.0 → durable_workflow-2.9.0}/tests/test_docstring_cross_references.py +0 -0
  85. {durable_workflow-2.8.0 → durable_workflow-2.9.0}/tests/test_durable_selection.py +0 -0
  86. {durable_workflow-2.8.0 → durable_workflow-2.9.0}/tests/test_errors.py +0 -0
  87. {durable_workflow-2.8.0 → durable_workflow-2.9.0}/tests/test_external_storage.py +0 -0
  88. {durable_workflow-2.8.0 → durable_workflow-2.9.0}/tests/test_external_task_input.py +0 -0
  89. {durable_workflow-2.8.0 → durable_workflow-2.9.0}/tests/test_external_task_result.py +0 -0
  90. {durable_workflow-2.8.0 → durable_workflow-2.9.0}/tests/test_golden_history_replay.py +0 -0
  91. {durable_workflow-2.8.0 → durable_workflow-2.9.0}/tests/test_history_bundle_verify.py +0 -0
  92. {durable_workflow-2.8.0 → durable_workflow-2.9.0}/tests/test_history_event_contract.py +0 -0
  93. {durable_workflow-2.8.0 → durable_workflow-2.9.0}/tests/test_invocable.py +0 -0
  94. {durable_workflow-2.8.0 → durable_workflow-2.9.0}/tests/test_message_streams.py +0 -0
  95. {durable_workflow-2.8.0 → durable_workflow-2.9.0}/tests/test_metrics.py +0 -0
  96. {durable_workflow-2.8.0 → durable_workflow-2.9.0}/tests/test_nexus_durable_wait.py +0 -0
  97. {durable_workflow-2.8.0 → durable_workflow-2.9.0}/tests/test_nexus_namespace.py +0 -0
  98. {durable_workflow-2.8.0 → durable_workflow-2.9.0}/tests/test_nexus_wire.py +0 -0
  99. {durable_workflow-2.8.0 → durable_workflow-2.9.0}/tests/test_order_processing_example.py +0 -0
  100. {durable_workflow-2.8.0 → durable_workflow-2.9.0}/tests/test_parallel_completion_order_replay.py +0 -0
  101. {durable_workflow-2.8.0 → durable_workflow-2.9.0}/tests/test_parallel_saga_authoring.py +0 -0
  102. {durable_workflow-2.8.0 → durable_workflow-2.9.0}/tests/test_patch_history.py +0 -0
  103. {durable_workflow-2.8.0 → durable_workflow-2.9.0}/tests/test_pending_operation_replay.py +0 -0
  104. {durable_workflow-2.8.0 → durable_workflow-2.9.0}/tests/test_prepared_local_activity_client.py +0 -0
  105. {durable_workflow-2.8.0 → durable_workflow-2.9.0}/tests/test_prepared_local_activity_groups.py +0 -0
  106. {durable_workflow-2.8.0 → durable_workflow-2.9.0}/tests/test_prepared_local_activity_policies.py +0 -0
  107. {durable_workflow-2.8.0 → durable_workflow-2.9.0}/tests/test_prepared_local_activity_worker.py +0 -0
  108. {durable_workflow-2.8.0 → durable_workflow-2.9.0}/tests/test_public_boundary_scanner.py +0 -0
  109. {durable_workflow-2.8.0 → durable_workflow-2.9.0}/tests/test_pypi_project_surface.py +0 -0
  110. {durable_workflow-2.8.0 → durable_workflow-2.9.0}/tests/test_python_conformance.py +0 -0
  111. {durable_workflow-2.8.0 → durable_workflow-2.9.0}/tests/test_queries.py +0 -0
  112. {durable_workflow-2.8.0 → durable_workflow-2.9.0}/tests/test_query_task_authority.py +0 -0
  113. {durable_workflow-2.8.0 → durable_workflow-2.9.0}/tests/test_query_timeout_retry.py +0 -0
  114. {durable_workflow-2.8.0 → durable_workflow-2.9.0}/tests/test_readme_quickstart.py +0 -0
  115. {durable_workflow-2.8.0 → durable_workflow-2.9.0}/tests/test_redrive_replay.py +0 -0
  116. {durable_workflow-2.8.0 → durable_workflow-2.9.0}/tests/test_registration_ambiguity.py +0 -0
  117. {durable_workflow-2.8.0 → durable_workflow-2.9.0}/tests/test_release_metadata.py +0 -0
  118. {durable_workflow-2.8.0 → durable_workflow-2.9.0}/tests/test_replay.py +0 -0
  119. {durable_workflow-2.8.0 → durable_workflow-2.9.0}/tests/test_replay_clock.py +0 -0
  120. {durable_workflow-2.8.0 → durable_workflow-2.9.0}/tests/test_replay_conformance.py +0 -0
  121. {durable_workflow-2.8.0 → durable_workflow-2.9.0}/tests/test_replay_verify.py +0 -0
  122. {durable_workflow-2.8.0 → durable_workflow-2.9.0}/tests/test_retry_policy.py +0 -0
  123. {durable_workflow-2.8.0 → durable_workflow-2.9.0}/tests/test_run_cancellation_scope_replay.py +0 -0
  124. {durable_workflow-2.8.0 → durable_workflow-2.9.0}/tests/test_runtime_external_payload_transport.py +0 -0
  125. {durable_workflow-2.8.0 → durable_workflow-2.9.0}/tests/test_schedules.py +0 -0
  126. {durable_workflow-2.8.0 → durable_workflow-2.9.0}/tests/test_scoped_run_cancellation_context.py +0 -0
  127. {durable_workflow-2.8.0 → durable_workflow-2.9.0}/tests/test_serializer.py +0 -0
  128. {durable_workflow-2.8.0 → durable_workflow-2.9.0}/tests/test_signals.py +0 -0
  129. {durable_workflow-2.8.0 → durable_workflow-2.9.0}/tests/test_sleep.py +0 -0
  130. {durable_workflow-2.8.0 → durable_workflow-2.9.0}/tests/test_standalone_activity_client.py +0 -0
  131. {durable_workflow-2.8.0 → durable_workflow-2.9.0}/tests/test_sticky_execution.py +0 -0
  132. {durable_workflow-2.8.0 → durable_workflow-2.9.0}/tests/test_storage_admission.py +0 -0
  133. {durable_workflow-2.8.0 → durable_workflow-2.9.0}/tests/test_sync.py +0 -0
  134. {durable_workflow-2.8.0 → durable_workflow-2.9.0}/tests/test_sync_activities.py +0 -0
  135. {durable_workflow-2.8.0 → durable_workflow-2.9.0}/tests/test_telemetry.py +0 -0
  136. {durable_workflow-2.8.0 → durable_workflow-2.9.0}/tests/test_telemetry_carrier.py +0 -0
  137. {durable_workflow-2.8.0 → durable_workflow-2.9.0}/tests/test_testing_harness.py +0 -0
  138. {durable_workflow-2.8.0 → durable_workflow-2.9.0}/tests/test_update_signal_condition_replay.py +0 -0
  139. {durable_workflow-2.8.0 → durable_workflow-2.9.0}/tests/test_updates.py +0 -0
  140. {durable_workflow-2.8.0 → durable_workflow-2.9.0}/tests/test_wait_condition.py +0 -0
  141. {durable_workflow-2.8.0 → durable_workflow-2.9.0}/tests/test_worker.py +0 -0
  142. {durable_workflow-2.8.0 → durable_workflow-2.9.0}/tests/test_worker_observation.py +0 -0
  143. {durable_workflow-2.8.0 → durable_workflow-2.9.0}/tests/test_worker_session.py +0 -0
  144. {durable_workflow-2.8.0 → durable_workflow-2.9.0}/tests/test_worker_telemetry_wire.py +0 -0
  145. {durable_workflow-2.8.0 → durable_workflow-2.9.0}/tests/test_workflow_entry_arguments.py +0 -0
  146. {durable_workflow-2.8.0 → durable_workflow-2.9.0}/tests/test_workflow_entrypoint_validation.py +0 -0
  147. {durable_workflow-2.8.0 → durable_workflow-2.9.0}/tests/test_workflow_handler_validation.py +0 -0
  148. {durable_workflow-2.8.0 → durable_workflow-2.9.0}/tests/test_workflow_result_timeout.py +0 -0
  149. {durable_workflow-2.8.0 → durable_workflow-2.9.0}/tests/test_workflow_streams.py +0 -0
  150. {durable_workflow-2.8.0 → durable_workflow-2.9.0}/tests/test_workflow_updates_conformance.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: durable-workflow
3
- Version: 2.8.0
3
+ Version: 2.9.0
4
4
  Summary: Python client and worker SDK for Durable Workflow Cloud and self-hosted Server
5
5
  Author: Durable Workflow Contributors
6
6
  License-Expression: MIT
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "durable-workflow"
7
- version = "2.8.0"
7
+ version = "2.9.0"
8
8
  description = "Python client and worker SDK for Durable Workflow Cloud and self-hosted Server"
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.10"
@@ -75,8 +75,8 @@ durable-workflow-replay-conformance = "durable_workflow.replay_conformance:main"
75
75
  durable-workflow-workflow-updates-conformance = "durable_workflow.workflow_updates_conformance:main"
76
76
 
77
77
  [tool.durable-workflow]
78
- product-train = "2.8.0"
79
- registry-version = "2.8.0"
78
+ product-train = "2.9.0"
79
+ registry-version = "2.9.0"
80
80
  supported-server-versions = "2.8.0"
81
81
  worker-protocol-version = "1.20"
82
82
  control-plane-version = "2"
@@ -2056,6 +2056,16 @@ class WorkflowContext:
2056
2056
  self._workflow_stream_command_counter = 0
2057
2057
  self.logger = _ReplayLogger(_REPLAY_LOGGER)
2058
2058
 
2059
+ @property
2060
+ def workflow_id(self) -> str:
2061
+ """Original workflow identity, retained across continue-as-new runs."""
2062
+ return self._workflow_id
2063
+
2064
+ @property
2065
+ def run_id(self) -> str:
2066
+ """Current run identity, stable on replay and new after continue-as-new."""
2067
+ return self._run_id
2068
+
2059
2069
  def cancellation_scope(
2060
2070
  self, body: Callable[[], Any], *, shield_parent: bool = False,
2061
2071
  ) -> Generator[Any, Any, Any]:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: durable-workflow
3
- Version: 2.8.0
3
+ Version: 2.9.0
4
4
  Summary: Python client and worker SDK for Durable Workflow Cloud and self-hosted Server
5
5
  Author: Durable Workflow Contributors
6
6
  License-Expression: MIT
@@ -142,6 +142,7 @@ tests/test_worker_telemetry_wire.py
142
142
  tests/test_workflow_entry_arguments.py
143
143
  tests/test_workflow_entrypoint_validation.py
144
144
  tests/test_workflow_handler_validation.py
145
+ tests/test_workflow_identity.py
145
146
  tests/test_workflow_result_timeout.py
146
147
  tests/test_workflow_streams.py
147
148
  tests/test_workflow_updates_conformance.py
@@ -46,6 +46,7 @@ from tests.test_update_signal_condition_replay import (
46
46
  UpdateSignalConditionTimerWorkflow,
47
47
  )
48
48
  from tests.test_worker import compatible_cluster_info
49
+ from tests.test_workflow_identity import IdentityAcrossReplay, IdentityContinueAsNew
49
50
 
50
51
  FIXTURE_SCHEMA = "durable-workflow.replay-regression/v1"
51
52
  FIXTURE_DIR = Path(__file__).parent / "fixtures" / "replay_regressions"
@@ -340,6 +341,8 @@ class NexusCooperativeDeliveryWorkflow:
340
341
 
341
342
 
342
343
  WORKFLOWS = [
344
+ IdentityAcrossReplay,
345
+ IdentityContinueAsNew,
343
346
  PersistedClockWorkflow,
344
347
  NexusCooperativeDeliveryWorkflow,
345
348
  NexusTerminalDeliveryWorkflow,
@@ -514,6 +517,8 @@ def _execute_fixture(fixture: dict[str, Any]) -> list[dict[str, Any]]:
514
517
  history,
515
518
  start_input,
516
519
  workflow_type=workflow_type,
520
+ workflow_id=workflow.get("workflow_id"),
521
+ run_id=workflow.get("run_id", ""),
517
522
  payload_codec=("json" if payload_codec is None else payload_codec),
518
523
  )
519
524
  commands = _command_documents(outcome.commands)
@@ -0,0 +1,72 @@
1
+ from __future__ import annotations
2
+
3
+ import pytest
4
+
5
+ from durable_workflow import serializer, workflow
6
+ from durable_workflow.workflow import (
7
+ CompleteWorkflow,
8
+ ContinueAsNew,
9
+ ScheduleActivity,
10
+ WorkflowContext,
11
+ replay,
12
+ )
13
+
14
+
15
+ @workflow.defn(name="identity-across-replay")
16
+ class IdentityAcrossReplay:
17
+ def run(self, ctx: WorkflowContext): # type: ignore[no-untyped-def]
18
+ before = [ctx.workflow_id, ctx.run_id]
19
+ value = yield ctx.schedule_activity("identity", before)
20
+ return {"before": before, "after": [ctx.workflow_id, ctx.run_id], "value": value}
21
+
22
+
23
+ @pytest.mark.parametrize("workflow_id", ["workflow-identity", "0", "17", "017"])
24
+ def test_identity_survives_activity_suspension_and_cold_replay(workflow_id: str) -> None:
25
+ run_id = "original-run"
26
+ first = replay(IdentityAcrossReplay, [], [], workflow_id=workflow_id, run_id=run_id)
27
+ assert len(first.commands) == 1
28
+ assert isinstance(first.commands[0], ScheduleActivity)
29
+ assert first.commands[0].arguments == [workflow_id, run_id]
30
+
31
+ history = [{"event_type": "ActivityCompleted", "payload": {
32
+ "result": serializer.envelope("done", codec=serializer.AVRO_CODEC),
33
+ }}]
34
+ resumed = replay(IdentityAcrossReplay, history, [], workflow_id=workflow_id, run_id=run_id)
35
+ assert len(resumed.commands) == 1
36
+ assert isinstance(resumed.commands[0], CompleteWorkflow)
37
+ assert resumed.commands[0].result == {
38
+ "before": [workflow_id, run_id], "after": [workflow_id, run_id], "value": "done",
39
+ }
40
+
41
+
42
+ @workflow.defn(name="identity-continue-as-new")
43
+ class IdentityContinueAsNew:
44
+ def run( # type: ignore[no-untyped-def]
45
+ self, ctx: WorkflowContext, again: bool,
46
+ prior_workflow_id: str | None = None, prior_run_id: str | None = None,
47
+ ):
48
+ if again:
49
+ return ctx.continue_as_new(False, ctx.workflow_id, ctx.run_id)
50
+ return {"current": [ctx.workflow_id, ctx.run_id], "prior": [prior_workflow_id, prior_run_id]}
51
+
52
+
53
+ def test_successor_context_has_same_workflow_and_new_run_identity() -> None:
54
+ original = replay(IdentityContinueAsNew, [], [True], workflow_id="chain", run_id="run-one")
55
+ assert len(original.commands) == 1
56
+ command = original.commands[0]
57
+ assert isinstance(command, ContinueAsNew)
58
+ assert command.arguments == [False, "chain", "run-one"]
59
+
60
+ successor = replay(
61
+ IdentityContinueAsNew, [], command.arguments, workflow_id="chain", run_id="run-two",
62
+ )
63
+ assert len(successor.commands) == 1
64
+ assert isinstance(successor.commands[0], CompleteWorkflow)
65
+ assert successor.commands[0].result == {"current": ["chain", "run-two"], "prior": ["chain", "run-one"]}
66
+
67
+
68
+ @pytest.mark.parametrize("attribute", ["workflow_id", "run_id"])
69
+ def test_workflow_identity_is_read_only(attribute: str) -> None:
70
+ ctx = WorkflowContext(workflow_id="workflow", run_id="run")
71
+ with pytest.raises(AttributeError):
72
+ setattr(ctx, attribute, "replacement")