dex-python-sdk 0.0.1__py3-none-any.whl

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 (93) hide show
  1. dex/__init__.py +14 -0
  2. dex/client.py +568 -0
  3. dex/client_options.py +34 -0
  4. dex/command_request.py +130 -0
  5. dex/command_results.py +116 -0
  6. dex/communication.py +141 -0
  7. dex/communication_schema.py +68 -0
  8. dex/data_attributes.py +75 -0
  9. dex/dexpb/__init__.py +1 -0
  10. dex/dexpb/dex_pb2.py +305 -0
  11. dex/dexpb/dex_pb2.pyi +1273 -0
  12. dex/dexpb/dex_pb2_grpc.py +1126 -0
  13. dex/errors.py +132 -0
  14. dex/object_encoder.py +818 -0
  15. dex/persistence.py +94 -0
  16. dex/persistence_options.py +24 -0
  17. dex/persistence_schema.py +58 -0
  18. dex/py.typed +1 -0
  19. dex/registry.py +209 -0
  20. dex/reset_workflow_type_and_options.py +77 -0
  21. dex/rpc.py +100 -0
  22. dex/search_attributes.py +189 -0
  23. dex/state_decision.py +161 -0
  24. dex/state_execution_locals.py +71 -0
  25. dex/state_movement.py +123 -0
  26. dex/state_schema.py +54 -0
  27. dex/stop_workflow_options.py +23 -0
  28. dex/tests/__init__.py +84 -0
  29. dex/tests/dex-service-env/.env +7 -0
  30. dex/tests/dex-service-env/docker-compose-init.sh +44 -0
  31. dex/tests/dex-service-env/docker-compose.yml +87 -0
  32. dex/tests/dex-service-env/dynamicconfig/README.md +39 -0
  33. dex/tests/dex-service-env/dynamicconfig/development-sql.yaml +6 -0
  34. dex/tests/dex-service-env/dynamicconfig/docker.yaml +0 -0
  35. dex/tests/test_abnormal_exit_workflow.py +48 -0
  36. dex/tests/test_basic_workflow.py +75 -0
  37. dex/tests/test_conditional_complete.py +56 -0
  38. dex/tests/test_describe_workflow.py +45 -0
  39. dex/tests/test_empty_data_decodes_properly.py +79 -0
  40. dex/tests/test_internal_channel.py +33 -0
  41. dex/tests/test_internal_channel_with_no_prefix_channel.py +46 -0
  42. dex/tests/test_persistence_data_attributes.py +67 -0
  43. dex/tests/test_persistence_search_attributes.py +132 -0
  44. dex/tests/test_persistence_state_execution_locals.py +43 -0
  45. dex/tests/test_rpc.py +69 -0
  46. dex/tests/test_rpc_with_memo.py +200 -0
  47. dex/tests/test_rpc_with_memo_duplicate_java_tests.py +122 -0
  48. dex/tests/test_signal.py +56 -0
  49. dex/tests/test_skip_wait_until.py +85 -0
  50. dex/tests/test_state_failure_recovery.py +33 -0
  51. dex/tests/test_timer.py +40 -0
  52. dex/tests/test_wait_for_state_execution_completion.py +58 -0
  53. dex/tests/test_workflow_errors.py +92 -0
  54. dex/tests/test_workflow_state_options.py +123 -0
  55. dex/tests/test_workflow_state_options_override.py +49 -0
  56. dex/tests/worker_server.py +74 -0
  57. dex/tests/workflows/abnormal_exit_workflow.py +48 -0
  58. dex/tests/workflows/basic_workflow.py +69 -0
  59. dex/tests/workflows/conditional_complete_workflow.py +101 -0
  60. dex/tests/workflows/describe_workflow.py +52 -0
  61. dex/tests/workflows/empty_data_workflow.py +51 -0
  62. dex/tests/workflows/internal_channel_workflow.py +137 -0
  63. dex/tests/workflows/internal_channel_workflow_with_no_prefix_channel.py +108 -0
  64. dex/tests/workflows/java_duplicate_rpc_memo_workflow.py +285 -0
  65. dex/tests/workflows/persistence_data_attributes_workflow.py +104 -0
  66. dex/tests/workflows/persistence_search_attributes_workflow.py +167 -0
  67. dex/tests/workflows/persistence_state_execution_local_workflow.py +69 -0
  68. dex/tests/workflows/recovery_workflow.py +90 -0
  69. dex/tests/workflows/rpc_memo_workflow.py +238 -0
  70. dex/tests/workflows/rpc_workflow.py +125 -0
  71. dex/tests/workflows/state_options_override_workflow.py +100 -0
  72. dex/tests/workflows/state_options_workflow.py +92 -0
  73. dex/tests/workflows/timer_workflow.py +52 -0
  74. dex/tests/workflows/wait_for_state_with_state_execution_id_workflow.py +77 -0
  75. dex/tests/workflows/wait_for_state_with_wait_for_key_workflow.py +78 -0
  76. dex/tests/workflows/wait_internal_channel_workflow.py +53 -0
  77. dex/tests/workflows/wait_signal_workflow.py +154 -0
  78. dex/type_store.py +105 -0
  79. dex/unregistered_client.py +595 -0
  80. dex/utils/__init__.py +14 -0
  81. dex/utils/dex_typing.py +31 -0
  82. dex/utils/persistence_utils.py +37 -0
  83. dex/worker_service.py +441 -0
  84. dex/workflow.py +86 -0
  85. dex/workflow_context.py +50 -0
  86. dex/workflow_info.py +21 -0
  87. dex/workflow_options.py +79 -0
  88. dex/workflow_state.py +134 -0
  89. dex/workflow_state_options.py +160 -0
  90. dex_python_sdk-0.0.1.dist-info/METADATA +140 -0
  91. dex_python_sdk-0.0.1.dist-info/RECORD +93 -0
  92. dex_python_sdk-0.0.1.dist-info/WHEEL +4 -0
  93. dex_python_sdk-0.0.1.dist-info/licenses/LICENSE +201 -0
dex/workflow_state.py ADDED
@@ -0,0 +1,134 @@
1
+ # Copyright (c) 2022-2026 Super Durable, Inc.
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+ from abc import ABC
16
+ from typing import Generic, TypeVar, get_args
17
+
18
+ from dex.command_request import CommandRequest
19
+ from dex.command_results import CommandResults
20
+ from dex.communication import Communication
21
+ from dex.persistence import Persistence
22
+ from dex.state_decision import StateDecision
23
+ from dex.workflow_context import WorkflowContext
24
+ from dex.workflow_state_options import WorkflowStateOptions
25
+
26
+ T = TypeVar("T")
27
+
28
+
29
+ not_implemented_error_msg = "This implementation shouldn't be invoked"
30
+
31
+
32
+ class WorkflowState(ABC, Generic[T]):
33
+ """WorkflowState is the interface to define a workflow state."""
34
+
35
+ def wait_until(
36
+ self,
37
+ ctx: WorkflowContext,
38
+ input: T,
39
+ persistence: Persistence,
40
+ communication: Communication,
41
+ ) -> CommandRequest:
42
+ """
43
+ WaitUntil is the method to set up commands set up to wait for, before `execute` API is invoked.
44
+ It's optional -- execute will be invoked instead if this is not implemented.
45
+
46
+ Args:
47
+ ctx: the context info of this API invocation, like workflow start time, workflowId, etc
48
+ input: input: the state input
49
+ persistence: the API for
50
+ 1) data attributes: defined by ObjectWorkflow interface
51
+ 2) search attributes: defined by ObjectWorkflow interface
52
+ 3) stateExecutionLocals: for passing data within the state execution
53
+ 4) recordEvent: for storing some tracking info(e.g. RPC call input/output) when executing the API.
54
+ Note that any write API will be recorded to server after the whole waitUntil API response is accepted
55
+ communication: the API right now only for publishing value to internalChannel
56
+ Note that any write API will be recorded to server after the whole waitUntil API response is accepted.
57
+
58
+ Returns: the requested command
59
+ """
60
+ raise NotImplementedError(not_implemented_error_msg)
61
+
62
+ def execute(
63
+ self,
64
+ ctx: WorkflowContext,
65
+ input: T,
66
+ command_results: CommandResults,
67
+ persistence: Persistence,
68
+ communication: Communication,
69
+ ) -> StateDecision:
70
+ """
71
+ Execute is the method to execute and decide what to do next. Invoke after commands from WaitUntil are completed, or there is WaitUntil is not implemented for the state.
72
+
73
+ Args:
74
+ ctx: the context info of this API invocation, like workflow start time, workflowId, etc
75
+ input: the state input
76
+ command_results: the results of the command that executed by WaitUntil
77
+ persistence: the API for
78
+ 1) data attributes: defined by ObjectWorkflow interface
79
+ 2) search attributes: defined by ObjectWorkflow interface
80
+ 3) stateExecutionLocals: for passing data within the state execution
81
+ 4) recordEvent: for storing some tracking info(e.g. RPC call input/output) when executing the API.
82
+ Note that any write API will be recorded to server after the whole waitUntil API response is accepted
83
+ communication: the API right now only for publishing value to internalChannel.
84
+ Note that any write API will be recorded to server after the whole execute API response is accepted.
85
+
86
+ Returns: the decision of what to do next(e.g. transition to next states or closing workflow)
87
+ """
88
+ raise NotImplementedError(not_implemented_error_msg)
89
+
90
+ def get_state_options(self) -> WorkflowStateOptions:
91
+ """GetStateOptions can just return nil to use the default Options
92
+ StateOptions is optional configuration to adjust the state behaviors. Default values:
93
+ StateId: name of the implementation class
94
+ waitUntilApiFailurePolicy: FAIL_WORKFLOW_ON_FAILURE
95
+ PersistenceLoadingPolicy for dataAttributes/searchAttributes: LOAD_ALL_WITHOUT_LOCKING
96
+ waitUntil/execute API:
97
+ timeout: 30s
98
+ retryPolicy:
99
+ InitialIntervalSeconds: 1
100
+ MaxInternalSeconds:100
101
+ MaximumAttempts: 0
102
+ BackoffCoefficient: 2
103
+ Returns: WorkflowStateOptions
104
+ """
105
+ return WorkflowStateOptions()
106
+
107
+
108
+ def get_state_id(state: WorkflowState) -> str:
109
+ options = state.get_state_options()
110
+ if options is None or options.state_id is None:
111
+ return state.__class__.__name__
112
+ return options.state_id
113
+
114
+
115
+ def get_state_id_by_class(state: type[WorkflowState]) -> str:
116
+ return state.__name__
117
+
118
+
119
+ def should_skip_wait_until(state: WorkflowState) -> bool:
120
+ func_name = state.wait_until.__name__
121
+ parent_method = getattr(super(type(state), state), func_name)
122
+ return parent_method == state.wait_until
123
+
124
+
125
+ def get_input_type(state):
126
+ bases = state.__orig_bases__
127
+ for b in bases:
128
+ if b.__origin__ == WorkflowState:
129
+ return get_args(b)[0]
130
+ return None
131
+
132
+
133
+ def get_state_execution_id(state: type[WorkflowState], number: int):
134
+ return f"{get_state_id_by_class(state)}-{number}"
@@ -0,0 +1,160 @@
1
+ # Copyright (c) 2022-2026 Super Durable, Inc.
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+ from dataclasses import dataclass
16
+ from typing import Any, Optional
17
+
18
+ from dex.errors import WorkflowDefinitionError
19
+ from dex.dex_api.models import (
20
+ ExecuteApiFailurePolicy,
21
+ PersistenceLoadingPolicy,
22
+ RetryPolicy,
23
+ WaitUntilApiFailurePolicy,
24
+ WorkflowStateOptions as IdlWorkflowStateOptions,
25
+ )
26
+ from dex.dex_api.types import Unset
27
+
28
+
29
+ @dataclass
30
+ class WorkflowStateOptions:
31
+ state_id: Optional[str] = None
32
+ # apply for both waitUntil and execute API
33
+ data_attributes_loading_policy: Optional[PersistenceLoadingPolicy] = None
34
+ search_attributes_loading_policy: Optional[PersistenceLoadingPolicy] = None
35
+ # below are wait_until API specific options:
36
+ wait_until_api_timeout_seconds: Optional[int] = None
37
+ wait_until_api_retry_policy: Optional[RetryPolicy] = None
38
+ """
39
+ By default, workflow would fail after waitUntil API retry exhausted.
40
+ This policy to allow proceeding to the execute API after waitUntil API exhausted all retries.
41
+ This is useful for some advanced use cases like SAGA pattern.
42
+ RetryPolicy is required to be set with maximumAttempts or maximumAttemptsDurationSeconds for waitUntil API.
43
+ NOTE: execute API will use commandResults to check whether the waitUntil has succeeded or not.
44
+ See more in <a href="https://github.com/superdurable/dex/wiki/WorkflowStateOptions">wiki</a>
45
+ """
46
+ proceed_to_execute_when_wait_until_retry_exhausted: Optional[
47
+ WaitUntilApiFailurePolicy
48
+ ] = None
49
+ wait_until_api_data_attributes_loading_policy: Optional[
50
+ PersistenceLoadingPolicy
51
+ ] = None
52
+ wait_until_api_search_attributes_loading_policy: Optional[
53
+ PersistenceLoadingPolicy
54
+ ] = None
55
+ # below are execute API specific options:
56
+ execute_api_timeout_seconds: Optional[int] = None
57
+ execute_api_retry_policy: Optional[RetryPolicy] = None
58
+ """
59
+ By default, workflow would fail after execute API retry exhausted.
60
+ Set the state to proceed to the specified state after the execute API exhausted all retries
61
+ This is useful for some advanced use cases like SAGA pattern.
62
+ RetryPolicy is required to be set with maximumAttempts or maximumAttemptsDurationSeconds for execute API.
63
+ Note that the failure handling state will take the same input as the failed from state.
64
+ TODO the type should be the type is Optional[type[WorkflowState]] but -- there is an issue with circular import...
65
+ """
66
+ proceed_to_state_when_execute_retry_exhausted: Optional[type] = None
67
+ execute_api_data_attributes_loading_policy: Optional[PersistenceLoadingPolicy] = (
68
+ None
69
+ )
70
+ execute_api_search_attributes_loading_policy: Optional[PersistenceLoadingPolicy] = (
71
+ None
72
+ )
73
+
74
+
75
+ def _to_idl_state_options(
76
+ skip_wait_until: bool,
77
+ options: Any, # TODO this type was Optional[WorkflowStateOptions],
78
+ # however, type hint is not working with recursive call...
79
+ state_store: dict[str, Any], # TODO this type should be dict[str, WorkflowState]
80
+ ) -> IdlWorkflowStateOptions:
81
+ res = IdlWorkflowStateOptions()
82
+ if skip_wait_until:
83
+ res.skip_wait_until = True
84
+
85
+ if options is None:
86
+ return res
87
+ assert isinstance(options, WorkflowStateOptions)
88
+
89
+ if options.wait_until_api_search_attributes_loading_policy is not None:
90
+ res.wait_until_api_search_attributes_loading_policy = (
91
+ options.wait_until_api_search_attributes_loading_policy
92
+ )
93
+ if options.execute_api_search_attributes_loading_policy is not None:
94
+ res.execute_api_search_attributes_loading_policy = (
95
+ options.execute_api_search_attributes_loading_policy
96
+ )
97
+ if options.search_attributes_loading_policy is not None:
98
+ res.search_attributes_loading_policy = options.search_attributes_loading_policy
99
+ if options.wait_until_api_data_attributes_loading_policy is not None:
100
+ res.wait_until_api_data_attributes_loading_policy = (
101
+ options.wait_until_api_data_attributes_loading_policy
102
+ )
103
+ if options.execute_api_data_attributes_loading_policy is not None:
104
+ res.execute_api_data_attributes_loading_policy = (
105
+ options.execute_api_data_attributes_loading_policy
106
+ )
107
+ if options.data_attributes_loading_policy is not None:
108
+ res.data_attributes_loading_policy = options.data_attributes_loading_policy
109
+ if options.proceed_to_execute_when_wait_until_retry_exhausted is not None:
110
+ res.wait_until_api_failure_policy = (
111
+ options.proceed_to_execute_when_wait_until_retry_exhausted
112
+ )
113
+ if options.wait_until_api_retry_policy is None:
114
+ raise WorkflowDefinitionError("wait_until API retry policy must be set")
115
+ if isinstance(
116
+ options.wait_until_api_retry_policy.maximum_attempts, Unset
117
+ ) and isinstance(
118
+ options.wait_until_api_retry_policy.maximum_attempts_duration_seconds, Unset
119
+ ):
120
+ raise WorkflowDefinitionError(
121
+ "wait_until API retry policy must be set with maximum_attempts or maximum_attempts_duration_seconds"
122
+ )
123
+ if options.wait_until_api_retry_policy is not None:
124
+ res.wait_until_api_retry_policy = options.wait_until_api_retry_policy
125
+ if options.wait_until_api_timeout_seconds is not None:
126
+ res.wait_until_api_timeout_seconds = options.wait_until_api_timeout_seconds
127
+ if options.execute_api_retry_policy is not None:
128
+ res.execute_api_retry_policy = options.execute_api_retry_policy
129
+ if options.execute_api_timeout_seconds is not None:
130
+ res.execute_api_timeout_seconds = options.execute_api_timeout_seconds
131
+ if options.proceed_to_state_when_execute_retry_exhausted is not None:
132
+ res.execute_api_failure_policy = (
133
+ ExecuteApiFailurePolicy.PROCEED_TO_CONFIGURED_STATE
134
+ )
135
+ if options.execute_api_retry_policy is None:
136
+ raise WorkflowDefinitionError("execute API retry policy must be set")
137
+ if isinstance(
138
+ options.execute_api_retry_policy.maximum_attempts, Unset
139
+ ) and isinstance(
140
+ options.execute_api_retry_policy.maximum_attempts_duration_seconds, Unset
141
+ ):
142
+ raise WorkflowDefinitionError(
143
+ "execute API retry policy must be set with maximum_attempts or maximum_attempts_duration_seconds"
144
+ )
145
+
146
+ from dex.workflow_state import get_state_id_by_class
147
+
148
+ res.execute_api_failure_proceed_state_id = get_state_id_by_class(
149
+ options.proceed_to_state_when_execute_retry_exhausted
150
+ )
151
+ state = state_store[res.execute_api_failure_proceed_state_id]
152
+ proceed_state_options = state.get_state_options()
153
+
154
+ from dex.workflow_state import should_skip_wait_until
155
+
156
+ proceed_state_idl_options = _to_idl_state_options(
157
+ should_skip_wait_until(state), proceed_state_options, state_store
158
+ )
159
+ res.execute_api_failure_proceed_state_options = proceed_state_idl_options
160
+ return res
@@ -0,0 +1,140 @@
1
+ Metadata-Version: 2.4
2
+ Name: dex-python-sdk
3
+ Version: 0.0.1
4
+ Summary: Python SDK for the Dex workflow engine
5
+ License-File: LICENSE
6
+ Author: Super Durable
7
+ Requires-Python: >=3.9,<4.0
8
+ Classifier: Programming Language :: Python :: 3
9
+ Classifier: Programming Language :: Python :: 3.9
10
+ Classifier: Programming Language :: Python :: 3.10
11
+ Classifier: Programming Language :: Python :: 3.11
12
+ Classifier: Programming Language :: Python :: 3.12
13
+ Classifier: Programming Language :: Python :: 3.13
14
+ Classifier: Programming Language :: Python :: 3.14
15
+ Requires-Dist: grpcio (>=1.60)
16
+ Requires-Dist: httpx (==0.28.1)
17
+ Requires-Dist: protobuf (>=4.25)
18
+ Requires-Dist: python-dateutil (>=2.8.2,<3.0.0) ; python_version < "3.11"
19
+ Project-URL: Homepage, https://github.com/superdurable/dex/tree/main/sdk-python
20
+ Project-URL: Repository, https://github.com/superdurable/dex
21
+ Description-Content-Type: text/markdown
22
+
23
+
24
+ # dex-python-sdk
25
+
26
+ Python SDK for [Dex workflow engine](https://github.com/superdurable/dex)
27
+
28
+ ```
29
+ pip install dex-python-sdk==0.0.1
30
+ ```
31
+
32
+ See [samples](../examples/python) for use case examples.
33
+
34
+ ## Requirements
35
+
36
+ - Python 3.9+
37
+ - [Dex server](https://github.com/superdurable/dex#how-to-use)
38
+
39
+ ## Concepts
40
+
41
+ To implement a workflow, the two most core interfaces are
42
+
43
+ * [Workflow interface](https://github.com/superdurable/dex/blob/main/sdk-python/dex/workflow.py)
44
+ defines the workflow definition
45
+
46
+ * [WorkflowState interface](https://github.com/superdurable/dex/blob/main/sdk-python/dex/workflow_state.py)
47
+ defines the workflow states for workflow definitions
48
+
49
+ A workflow can contain any number of WorkflowStates.
50
+
51
+ See more in https://github.com/superdurable/dex#what-is-dex
52
+
53
+
54
+ # Development Plan
55
+
56
+ ## 1.0 -- the basic and most frequently needed features
57
+ - [x] Start workflow API
58
+ - [x] Executing `wait_until`/`execute` APIs and completing workflow
59
+ - [x] Parallel execution of multiple states
60
+ - [x] GetWorkflowResultsWithWait API
61
+ - [x] StateOption: WaitUntil(optional)/Execute API timeout and retry policy
62
+ - [x] Get workflow with wait API
63
+ - [x] Timer command
64
+ - [x] AnyCommandCompleted and AllCommandCompleted waitingType
65
+ - [x] InternalChannel command
66
+ - [x] DataAttribute
67
+ - [x] Stop workflow API
68
+ - [x] Improve workflow uncompleted error return(canceled, failed, timeout, terminated)
69
+ - [x] Support execute API failure policy
70
+ - [x] Support workflow RPC
71
+ - [x] Signal command
72
+ - [x] Reset workflow API
73
+ - [x] Skip timer API for testing/operation
74
+
75
+ ### Running dex-server locally
76
+
77
+ #### Option 1: use docker compose
78
+ See [dex README](https://github.com/superdurable/dex#using-docker-image--docker-compose)
79
+
80
+ #### Option 2: VSCode Dev Container
81
+
82
+ Dev Container is an easy way to get dex-server running locally. Follow these steps to launch a dev container:
83
+ - Install Docker, VSCode, and [VSCode Dev Container plugin](https://marketplace.visualstudio.com/items?itemName=ms-vscode-remote.remote-containers).
84
+ - Open the project in VSCode.
85
+ ```bash
86
+ cd dex-python-sdk
87
+ code .
88
+ ```
89
+ - Launch the Remote-Containers: Reopen in Container command from Command Palette (Ctrl + Shift + P). You can also click in the bottom left corner to access the remote container menu.
90
+ - Once the dev container starts, dex-server will be listening on port 8801.
91
+
92
+ ## How To Contribute
93
+
94
+ This project uses [Poetry](https://python-poetry.org/) as a dependency manager. Check out Poetry's [documentation on how to install it](https://python-poetry.org/docs/#installing-with-the-official-installer) on your system before proceeding.
95
+
96
+ > ❗Note: If you use Conda or Pyenv as your environment / package manager, avoid dependency conflicts by doing the following first:
97
+ 1. Before installing Poetry, create and activate a new Conda env (e.g. conda create -n langchain python=3.9)
98
+ 2. Install Poetry (see above)
99
+ 3. Tell Poetry to use the virtualenv python environment (poetry config virtualenvs.prefer-active-python true)
100
+ 4. Continue with the following steps.
101
+
102
+ To install requirements:
103
+
104
+ ```bash
105
+ poetry install
106
+ ```
107
+
108
+ #### Update IDL
109
+
110
+ Edit [`protos/dex.proto`](../protos/dex.proto). Rename catalog: [`docs/design/idl-renames.md`](../docs/design/idl-renames.md).
111
+
112
+ #### Generate stubs from IDL
113
+
114
+ ```bash
115
+ make -C ../protos proto
116
+ ```
117
+
118
+ Checked-in Python stubs land in `dex/dexpb/`.
119
+ #### Linting
120
+
121
+ To run linting for this project:
122
+
123
+ ```bash
124
+ poetry run pre-commit run --show-diff-on-failure --color=always --all-files
125
+ ```
126
+
127
+ ## Code of Conduct
128
+ This project is governed by the [Contributor Covenant v 1.4.1](CODE_OF_CONDUCT.md). (Review the Code of Conduct and remove this sentence before publishing your project.)
129
+
130
+ ## Publishing to PyPI
131
+
132
+ 1. Bump `version` in `pyproject.toml` (and the `pip install` line above).
133
+ 2. Create a GitHub Release with tag `sdk-python-vX.Y.Z` (for example `sdk-python-v0.0.1`), or run the **Publish Python SDK to PyPI** workflow manually.
134
+ 3. CI runs `poetry publish --build` using the `PYPI_TOKEN` repository secret.
135
+
136
+ See [CONTRIBUTING.md](../CONTRIBUTING.md#releases-monorepo-tags) for monorepo tag conventions.
137
+
138
+ ## License
139
+ This project uses the [Apache 2.0](LICENSE) license. (Update this and the LICENSE file if your project uses a different license.)
140
+
@@ -0,0 +1,93 @@
1
+ dex/__init__.py,sha256=JSqLdxV-BbOchWw40dm6Q_gTFs7Dxw0Um_covA_zvAI,593
2
+ dex/client.py,sha256=2sxUocj4Wtv4wWwG8w3FA2Q1nVfkFFBmuk14aknDuwA,22122
3
+ dex/client_options.py,sha256=s8rBPSTRyWxtrTXFsSq8sXMc8hjbtD53h9uYw2e5rmo,1089
4
+ dex/command_request.py,sha256=0mB5mDXune0Foogu4uZldlNnWZHl_st-Cpg4JHWkG60,4412
5
+ dex/command_results.py,sha256=V9X87kkopRJUDp0KU7uKDKlNjakS2t27_sQVZoLYLI0,3892
6
+ dex/communication.py,sha256=YaIOzTFxIB5Mgh9GTB9oi2Vw8iUn5IxCl4zPK_7CKcs,5524
7
+ dex/communication_schema.py,sha256=AxY6Uis8HvH9NoSIKTPl_auyettus9akvxQ49RkrULs,2095
8
+ dex/data_attributes.py,sha256=QDaTKB8JSxKWdz14DMi_qaPfW0JORb9lgxipy6VziKg,2827
9
+ dex/dexpb/__init__.py,sha256=yuJqMfBdU6TScp7CLIEeOWNEBFrfL2pcqsGzRawW-A0,44
10
+ dex/dexpb/dex_pb2.py,sha256=-Q4dieYhO55Z-HLE_Q-Xu4psNmYp0-_dZoHZxG3s6BQ,46361
11
+ dex/dexpb/dex_pb2.pyi,sha256=smmH3kPj1cYhZmu260hE1Bi2_baR9VCalkNnQ6-5aP0,70023
12
+ dex/dexpb/dex_pb2_grpc.py,sha256=H5YdOefAzW5cc01phqtHWsEi1yPWuyKxvhMmHis8y-E,45638
13
+ dex/errors.py,sha256=UkS3SKIEfuDnJPH65P3ggzuIjnOzf2F8a49NmaNqIoA,3613
14
+ dex/object_encoder.py,sha256=m6I7uCE8TA8Btk_se-bzzAJc39joMiPC7kGdFpcTEHI,27411
15
+ dex/persistence.py,sha256=LomP7lfCiNspDbdcI-OEkX4cwJRyk-Y3hBTizJRSVtA,4064
16
+ dex/persistence_options.py,sha256=ZWt4nY6RYX08j8wVT35A55Qh3DMtL27c4l_8shwPQws,776
17
+ dex/persistence_schema.py,sha256=sJgw5nNTP7DRGFFaIc9TpiDJMBpPORchaBnTScWuumI,1861
18
+ dex/py.typed,sha256=8PjyZ1aVoQpRVvt71muvuq5qE-jTFZkK-GLHkhdebmc,26
19
+ dex/registry.py,sha256=Z_Z9O0Hn1Ax5-FTTdQodADZA75qR3LcaOEqdI4TZ71Q,8813
20
+ dex/reset_workflow_type_and_options.py,sha256=V1bL6B0XHMnlTIZKiviYmx2Doxyq_Pzpp3ChfpCNvA0,2280
21
+ dex/rpc.py,sha256=K8EwgpvDMHxXT-IuA_IGIPHZ2Jhw4HtyerS8oJPTiFA,3553
22
+ dex/search_attributes.py,sha256=CSNNzDkNi7Yq_5wZ0NnPo_DA-dwSHZ4QTLfUh2MmA8Y,8550
23
+ dex/state_decision.py,sha256=P3kWpmqpTYd82k1zo1_-f8RcFZydvhNzEjRaOZFEGng,6501
24
+ dex/state_execution_locals.py,sha256=ON6CDJe4gi-RoUQL1wGRWUNjbbA3QWuop6vblG-v4hY,2889
25
+ dex/state_movement.py,sha256=CAxlxeijWo9LML2dSKGYEuhyPcsV1o7DdetfD-naPOY,4050
26
+ dex/state_schema.py,sha256=jimTJD6uNmTJBDxfICsIieo36tCKmJjZea1rnJQPbbY,1734
27
+ dex/stop_workflow_options.py,sha256=Cd_Hp4xpjwW-R0ouEqesYxfyuOLckekD6UFRkeQ-ojY,773
28
+ dex/tests/__init__.py,sha256=traifsy3IF7s41O3D9ywZ2I2F5UF7qgdItYeq2nLDIw,3687
29
+ dex/tests/dex-service-env/.env,sha256=43l3DVR4gBlAA179GXotv7ilxsYCJBCrTzqL3YVKRKs,200
30
+ dex/tests/dex-service-env/docker-compose-init.sh,sha256=Zv25Gb85j-VXzO8Jl-H2L9btLk0IF2T9DaMK4cjGZW8,1737
31
+ dex/tests/dex-service-env/docker-compose.yml,sha256=-JOqORirlaX3YYpGP9rSNjSKMwU-Cr6OUuR1fOVk-xc,2519
32
+ dex/tests/dex-service-env/dynamicconfig/README.md,sha256=33FXQSiJAt7gvxWG7pUL9EddwYgPLpsLZaOUMIL70P4,1132
33
+ dex/tests/dex-service-env/dynamicconfig/development-sql.yaml,sha256=NcBfj7uKr2_Is3I32eKkTNI_gG2xuIUdrtm7vJy-uCo,189
34
+ dex/tests/dex-service-env/dynamicconfig/docker.yaml,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
35
+ dex/tests/test_abnormal_exit_workflow.py,sha256=Iu7TQKAgbVW6_jKdknq2-yZl7p-xMDbe0xPRRQ0n9Mw,1897
36
+ dex/tests/test_basic_workflow.py,sha256=eurJwEKaM4T-zYbB6eQYCmtoCrLJF1o1IB3SfF8gdj4,2597
37
+ dex/tests/test_conditional_complete.py,sha256=W26OPknuXETBvDX8xD5LUHGVgwBVUAju6iDXxPsyois,1965
38
+ dex/tests/test_describe_workflow.py,sha256=oUv6ZmQcYNmUZrEWLxkXc6w1emYxYceZhgbEC5VCWYY,1629
39
+ dex/tests/test_empty_data_decodes_properly.py,sha256=GjoIDZ404E3LhN3edXalsCjqMzVy8Tb7eOKh_tHpB2c,2813
40
+ dex/tests/test_internal_channel.py,sha256=9EhrXxtp9FeWxub6vGFvJKe7HTMgKVO-DbRq-SDatTQ,1190
41
+ dex/tests/test_internal_channel_with_no_prefix_channel.py,sha256=VOD0CTH_w7zb0dFrIOudRqRjV_QuK_ITFABBCCunn8E,1687
42
+ dex/tests/test_persistence_data_attributes.py,sha256=AQC6Fsyctq3RRpw4maqJuzefag8eLgUgnOWQ5c3m1Co,2222
43
+ dex/tests/test_persistence_search_attributes.py,sha256=sXX44F302umG18EzC8cC5OwvuKxwRi889IXVuG_IKIc,5212
44
+ dex/tests/test_persistence_state_execution_locals.py,sha256=MlD9rlWPGn9tLVyYDCa629mMVbSWb18w9edyzOX2dIQ,1597
45
+ dex/tests/test_rpc.py,sha256=d4R_G_xaoW2siML83i24MqG80EDLHFFqTmAS6IVSpUg,2576
46
+ dex/tests/test_rpc_with_memo.py,sha256=s1mZpZPdJrJEc-uqpYLFEtRGIUA4IhaDndSjxdjyX00,7881
47
+ dex/tests/test_rpc_with_memo_duplicate_java_tests.py,sha256=406yuj_hf8MMStTjsGhU0OyY-dEh1E429_IJvqDSzis,4371
48
+ dex/tests/test_signal.py,sha256=K71A0Lt3KLkYhpTEww-alz_ZA_Tss30dW3gtRPnuIm8,2068
49
+ dex/tests/test_skip_wait_until.py,sha256=amkRcZePE3fadyXwzq84UM_8Z3lvLIJjLnJ_dERqRRA,2584
50
+ dex/tests/test_state_failure_recovery.py,sha256=GsjWlHbMml5xO3Lsy94wv-tzDA682nGwMdLVi4e3PdE,1173
51
+ dex/tests/test_timer.py,sha256=T_PV1df4JvVE4aUbdarwnMbpFkzNP-NRQVZAmUmsKAU,1439
52
+ dex/tests/test_wait_for_state_execution_completion.py,sha256=HLA45OeVeq89TaxhbZoueloss-BHpGFKaShMdbZn2uY,2139
53
+ dex/tests/test_workflow_errors.py,sha256=uv57RK_u6wpQ1UvsUa_gZe2t5h9F0BrqKJm37OD1pkI,3684
54
+ dex/tests/test_workflow_state_options.py,sha256=_R9c5cvrIBi2wya5BKz43q2_kcVkyj-pJKrR7Na_3iQ,4777
55
+ dex/tests/test_workflow_state_options_override.py,sha256=-D5bzf247tlosVcOvD5e6KDEIV51kMZa2ETp2q2Y44k,1609
56
+ dex/tests/worker_server.py,sha256=piNxQVD5gFTUjtRgoPmuvhME9tdzDuhEsYeHo7NXCEY,2382
57
+ dex/tests/workflows/abnormal_exit_workflow.py,sha256=Qj-MSjAihdK-Zwyy2RR6vTNVZZYHusvg664RQbf1KO8,1741
58
+ dex/tests/workflows/basic_workflow.py,sha256=jJmFaGcheETabPI-Nm4ZmT5eZxZ4KQQWcrmCE2faRmk,2277
59
+ dex/tests/workflows/conditional_complete_workflow.py,sha256=XQCQB_vb526iDJHQM5nCdSyI6nVtlBpOmZgPOYRhs24,3574
60
+ dex/tests/workflows/describe_workflow.py,sha256=gecikkSYgYqFnuRBYSm2fVutKs1B3DsYHY-inNCrsZo,1763
61
+ dex/tests/workflows/empty_data_workflow.py,sha256=xA2Wc_AKU1HHEl_iKgZCoA4Ou1pC8etFWu9sw7WxfxI,1822
62
+ dex/tests/workflows/internal_channel_workflow.py,sha256=g0YGQGe7cK8KxrdRJituP47-OjOyv56rpbwf02wp0l0,5033
63
+ dex/tests/workflows/internal_channel_workflow_with_no_prefix_channel.py,sha256=HovlMxQic4V2gdDz0y2j3Y4zAimYRY9wmnyluEmK284,3949
64
+ dex/tests/workflows/java_duplicate_rpc_memo_workflow.py,sha256=dXYNXXxpLyGaW6d9A5dyUgjVMoJ4VPvp0D2pQ4M393A,9993
65
+ dex/tests/workflows/persistence_data_attributes_workflow.py,sha256=dkHWhDQs1fNHyMNWqjpiGdcK3VMJ6LJNxc6X-nmw7tI,3914
66
+ dex/tests/workflows/persistence_search_attributes_workflow.py,sha256=b6I-s82WJ6rWa9PjY5rUTRI-N6Ven2A_9e5VT1VO7Aw,6073
67
+ dex/tests/workflows/persistence_state_execution_local_workflow.py,sha256=KlCrbKoGdLqvDiB_99fyyK_4XAk5yR1SZfTcQACOnNQ,2601
68
+ dex/tests/workflows/recovery_workflow.py,sha256=0gKl6gRE0NMb8CGzOyrEAABzhjSbgI8_48YSNJwza8o,3135
69
+ dex/tests/workflows/rpc_memo_workflow.py,sha256=7_q_2X6N6SC7RXS-TQ1ve_ibdypz2n8-bwsHy6_7slk,8500
70
+ dex/tests/workflows/rpc_workflow.py,sha256=KfnLaejPNA8yPN1w7cDvfNdamemriT2SYWNia157C0I,4081
71
+ dex/tests/workflows/state_options_override_workflow.py,sha256=i6XLw_e0gDafOi7xZUjl7-XEXbSro4jb4G0cJTlBp8w,3512
72
+ dex/tests/workflows/state_options_workflow.py,sha256=sjPRdA9qCY8mlrzgowfCKB2OYp-KqGdvDT4Fexn4J1E,3195
73
+ dex/tests/workflows/timer_workflow.py,sha256=I8bIUcPyBKp9lKc3OZsRdfyOE-hCrYfaTUfc-iz5fUY,1814
74
+ dex/tests/workflows/wait_for_state_with_state_execution_id_workflow.py,sha256=lqtvsjxmdWBER-vjVk8QkhkgjA9VsgpujvrxqeY2iqo,2579
75
+ dex/tests/workflows/wait_for_state_with_wait_for_key_workflow.py,sha256=1WaDpViPmfGZndJnJ3ZWjR_z_L3k-La-jlFhsK89brk,2575
76
+ dex/tests/workflows/wait_internal_channel_workflow.py,sha256=10oAJDszGbwZGp9QTO0q0wSrtXQwqfOMN70-5d8ywXI,1837
77
+ dex/tests/workflows/wait_signal_workflow.py,sha256=TrkrN7qqJKy5Jw5pjOwLOk7mOt1bQULdtd7HYHXzeao,5515
78
+ dex/type_store.py,sha256=DRfCSgHLY-DzBP_5IEJg5hlMZA46jUAstdk312e6nnI,3506
79
+ dex/unregistered_client.py,sha256=vX6TDNEuBfV3UAM5uURA8CqU9eEXxkuDLmW18RkUNh0,22210
80
+ dex/utils/__init__.py,sha256=JSqLdxV-BbOchWw40dm6Q_gTFs7Dxw0Um_covA_zvAI,593
81
+ dex/utils/dex_typing.py,sha256=aOlVmpBJqIHMbUt-0xOWJgnG2n7YAlS5gAOgrhRKudc,984
82
+ dex/utils/persistence_utils.py,sha256=8L8aa3Fn-f_7kuwn7BYFSdX42NMQZY_TUsEoQOSFtDc,1568
83
+ dex/worker_service.py,sha256=CT6m-ukPCFj78rblIHqnj335rIQveTcWOStGpkwD1Ag,16451
84
+ dex/workflow.py,sha256=rGOReD_OljAZgjngJJbTt-DnAW4FlWRNjGCEk245SD4,3769
85
+ dex/workflow_context.py,sha256=j8URlU56x2a6_i-LKOVhLfuMdU1pg8azttMrqVMxETE,1810
86
+ dex/workflow_info.py,sha256=0QCvmPpD9moWyDYOn7OsaP6YNfI8F74pB7EQ18BG9Ls,758
87
+ dex/workflow_options.py,sha256=zbUZGbmIANX6owNskCkMRUdKGW7oyWts-_zEV2Ohfe4,3096
88
+ dex/workflow_state.py,sha256=Dlhs11-v9L8lV9m6LKILLw2H_V73hBfJFPkMNy8NiDc,5715
89
+ dex/workflow_state_options.py,sha256=o8I5p_qSch8WdSrChhVWbxhRyxq07_R5ZV_EJO-VqsU,7606
90
+ dex_python_sdk-0.0.1.dist-info/METADATA,sha256=kDsZCd_ank2JRvFX18Kb1K317K_P_jM_pRDipn2iLxc,5103
91
+ dex_python_sdk-0.0.1.dist-info/WHEEL,sha256=EGEvSphFYqXKs23-kQBeyNoJP1nrT8ZJKQoi5p5DYL8,88
92
+ dex_python_sdk-0.0.1.dist-info/licenses/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
93
+ dex_python_sdk-0.0.1.dist-info/RECORD,,
@@ -0,0 +1,4 @@
1
+ Wheel-Version: 1.0
2
+ Generator: poetry-core 2.4.0
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any