cadence-python-client 0.1.0__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.
- cadence/__init__.py +18 -0
- cadence/_internal/__init__.py +8 -0
- cadence/_internal/activity/__init__.py +5 -0
- cadence/_internal/activity/_activity_executor.py +113 -0
- cadence/_internal/activity/_context.py +58 -0
- cadence/_internal/rpc/__init__.py +0 -0
- cadence/_internal/rpc/error.py +148 -0
- cadence/_internal/rpc/retry.py +104 -0
- cadence/_internal/rpc/yarpc.py +42 -0
- cadence/_internal/workflow/__init__.py +0 -0
- cadence/_internal/workflow/context.py +121 -0
- cadence/_internal/workflow/decision_events_iterator.py +161 -0
- cadence/_internal/workflow/decisions_helper.py +312 -0
- cadence/_internal/workflow/deterministic_event_loop.py +498 -0
- cadence/_internal/workflow/history_event_iterator.py +58 -0
- cadence/_internal/workflow/statemachine/__init__.py +0 -0
- cadence/_internal/workflow/statemachine/activity_state_machine.py +106 -0
- cadence/_internal/workflow/statemachine/decision_manager.py +157 -0
- cadence/_internal/workflow/statemachine/decision_state_machine.py +87 -0
- cadence/_internal/workflow/statemachine/event_dispatcher.py +76 -0
- cadence/_internal/workflow/statemachine/timer_state_machine.py +73 -0
- cadence/_internal/workflow/workflow_engine.py +245 -0
- cadence/_internal/workflow/workflow_intance.py +44 -0
- cadence/activity.py +255 -0
- cadence/api/v1/__init__.py +92 -0
- cadence/api/v1/common_pb2.py +90 -0
- cadence/api/v1/common_pb2.pyi +200 -0
- cadence/api/v1/common_pb2_grpc.py +24 -0
- cadence/api/v1/decision_pb2.py +67 -0
- cadence/api/v1/decision_pb2.pyi +225 -0
- cadence/api/v1/decision_pb2_grpc.py +24 -0
- cadence/api/v1/domain_pb2.py +68 -0
- cadence/api/v1/domain_pb2.pyi +145 -0
- cadence/api/v1/domain_pb2_grpc.py +24 -0
- cadence/api/v1/error_pb2.py +59 -0
- cadence/api/v1/error_pb2.pyi +82 -0
- cadence/api/v1/error_pb2_grpc.py +24 -0
- cadence/api/v1/history_pb2.py +134 -0
- cadence/api/v1/history_pb2.pyi +780 -0
- cadence/api/v1/history_pb2_grpc.py +24 -0
- cadence/api/v1/query_pb2.py +49 -0
- cadence/api/v1/query_pb2.pyi +59 -0
- cadence/api/v1/query_pb2_grpc.py +24 -0
- cadence/api/v1/service_domain_pb2.py +76 -0
- cadence/api/v1/service_domain_pb2.pyi +164 -0
- cadence/api/v1/service_domain_pb2_grpc.py +327 -0
- cadence/api/v1/service_meta_pb2.py +41 -0
- cadence/api/v1/service_meta_pb2.pyi +17 -0
- cadence/api/v1/service_meta_pb2_grpc.py +97 -0
- cadence/api/v1/service_visibility_pb2.py +71 -0
- cadence/api/v1/service_visibility_pb2.pyi +149 -0
- cadence/api/v1/service_visibility_pb2_grpc.py +362 -0
- cadence/api/v1/service_worker_pb2.py +116 -0
- cadence/api/v1/service_worker_pb2.pyi +350 -0
- cadence/api/v1/service_worker_pb2_grpc.py +743 -0
- cadence/api/v1/service_workflow_pb2.py +126 -0
- cadence/api/v1/service_workflow_pb2.pyi +395 -0
- cadence/api/v1/service_workflow_pb2_grpc.py +861 -0
- cadence/api/v1/tasklist_pb2.py +78 -0
- cadence/api/v1/tasklist_pb2.pyi +147 -0
- cadence/api/v1/tasklist_pb2_grpc.py +24 -0
- cadence/api/v1/visibility_pb2.py +47 -0
- cadence/api/v1/visibility_pb2.pyi +53 -0
- cadence/api/v1/visibility_pb2_grpc.py +24 -0
- cadence/api/v1/workflow_pb2.py +89 -0
- cadence/api/v1/workflow_pb2.pyi +365 -0
- cadence/api/v1/workflow_pb2_grpc.py +24 -0
- cadence/client.py +382 -0
- cadence/data_converter.py +78 -0
- cadence/error.py +111 -0
- cadence/metrics/__init__.py +12 -0
- cadence/metrics/constants.py +136 -0
- cadence/metrics/metrics.py +56 -0
- cadence/metrics/prometheus.py +165 -0
- cadence/sample/__init__.py +1 -0
- cadence/sample/client_example.py +15 -0
- cadence/sample/grpc_usage_example.py +230 -0
- cadence/sample/simple_usage_example.py +155 -0
- cadence/signal.py +174 -0
- cadence/worker/__init__.py +13 -0
- cadence/worker/_activity.py +60 -0
- cadence/worker/_base_task_handler.py +71 -0
- cadence/worker/_decision.py +62 -0
- cadence/worker/_decision_task_handler.py +285 -0
- cadence/worker/_poller.py +64 -0
- cadence/worker/_registry.py +245 -0
- cadence/worker/_types.py +26 -0
- cadence/worker/_worker.py +56 -0
- cadence/workflow.py +271 -0
- cadence_python_client-0.1.0.dist-info/METADATA +180 -0
- cadence_python_client-0.1.0.dist-info/RECORD +95 -0
- cadence_python_client-0.1.0.dist-info/WHEEL +5 -0
- cadence_python_client-0.1.0.dist-info/licenses/LICENSE +201 -0
- cadence_python_client-0.1.0.dist-info/licenses/NOTICE +19 -0
- cadence_python_client-0.1.0.dist-info/top_level.txt +1 -0
cadence/workflow.py
ADDED
|
@@ -0,0 +1,271 @@
|
|
|
1
|
+
from abc import ABC, abstractmethod
|
|
2
|
+
from contextlib import contextmanager
|
|
3
|
+
from contextvars import ContextVar
|
|
4
|
+
from dataclasses import dataclass
|
|
5
|
+
from datetime import timedelta
|
|
6
|
+
from typing import (
|
|
7
|
+
Iterator,
|
|
8
|
+
Callable,
|
|
9
|
+
TypeVar,
|
|
10
|
+
TypedDict,
|
|
11
|
+
Type,
|
|
12
|
+
cast,
|
|
13
|
+
Any,
|
|
14
|
+
Optional,
|
|
15
|
+
Union,
|
|
16
|
+
Unpack,
|
|
17
|
+
Generic,
|
|
18
|
+
)
|
|
19
|
+
import inspect
|
|
20
|
+
|
|
21
|
+
from cadence.data_converter import DataConverter
|
|
22
|
+
from cadence.signal import SignalDefinition, SignalDefinitionOptions
|
|
23
|
+
|
|
24
|
+
ResultType = TypeVar("ResultType")
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
class ActivityOptions(TypedDict, total=False):
|
|
28
|
+
task_list: str
|
|
29
|
+
schedule_to_close_timeout: timedelta
|
|
30
|
+
schedule_to_start_timeout: timedelta
|
|
31
|
+
start_to_close_timeout: timedelta
|
|
32
|
+
heartbeat_timeout: timedelta
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
async def execute_activity(
|
|
36
|
+
activity: str,
|
|
37
|
+
result_type: Type[ResultType],
|
|
38
|
+
*args: Any,
|
|
39
|
+
**kwargs: Unpack[ActivityOptions],
|
|
40
|
+
) -> ResultType:
|
|
41
|
+
return await WorkflowContext.get().execute_activity(
|
|
42
|
+
activity, result_type, *args, **kwargs
|
|
43
|
+
)
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
T = TypeVar("T", bound=Callable[..., Any])
|
|
47
|
+
C = TypeVar("C")
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
class WorkflowDefinitionOptions(TypedDict, total=False):
|
|
51
|
+
"""Options for defining a workflow."""
|
|
52
|
+
|
|
53
|
+
name: str
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
class WorkflowDefinition(Generic[C]):
|
|
57
|
+
"""
|
|
58
|
+
Definition of a workflow class with metadata.
|
|
59
|
+
|
|
60
|
+
Similar to ActivityDefinition but for workflow classes.
|
|
61
|
+
Provides type safety and metadata for workflow classes.
|
|
62
|
+
"""
|
|
63
|
+
|
|
64
|
+
def __init__(
|
|
65
|
+
self,
|
|
66
|
+
cls: Type[C],
|
|
67
|
+
name: str,
|
|
68
|
+
run_method_name: str,
|
|
69
|
+
signals: dict[str, SignalDefinition[..., Any]],
|
|
70
|
+
):
|
|
71
|
+
self._cls: Type[C] = cls
|
|
72
|
+
self._name = name
|
|
73
|
+
self._run_method_name = run_method_name
|
|
74
|
+
self._signals = signals
|
|
75
|
+
|
|
76
|
+
@property
|
|
77
|
+
def signals(self) -> dict[str, SignalDefinition[..., Any]]:
|
|
78
|
+
"""Get the signal definitions."""
|
|
79
|
+
return self._signals
|
|
80
|
+
|
|
81
|
+
@property
|
|
82
|
+
def name(self) -> str:
|
|
83
|
+
"""Get the workflow name."""
|
|
84
|
+
return self._name
|
|
85
|
+
|
|
86
|
+
@property
|
|
87
|
+
def cls(self) -> Type[C]:
|
|
88
|
+
"""Get the workflow class."""
|
|
89
|
+
return self._cls
|
|
90
|
+
|
|
91
|
+
def get_run_method(self, instance: Any) -> Callable:
|
|
92
|
+
"""Get the workflow run method from an instance of the workflow class."""
|
|
93
|
+
return cast(Callable, getattr(instance, self._run_method_name))
|
|
94
|
+
|
|
95
|
+
@staticmethod
|
|
96
|
+
def wrap(cls: Type, opts: WorkflowDefinitionOptions) -> "WorkflowDefinition":
|
|
97
|
+
"""
|
|
98
|
+
Wrap a class as a WorkflowDefinition.
|
|
99
|
+
|
|
100
|
+
Args:
|
|
101
|
+
cls: The workflow class to wrap
|
|
102
|
+
opts: Options for the workflow definition
|
|
103
|
+
|
|
104
|
+
Returns:
|
|
105
|
+
A WorkflowDefinition instance
|
|
106
|
+
|
|
107
|
+
Raises:
|
|
108
|
+
ValueError: If no run method is found or multiple run methods exist
|
|
109
|
+
"""
|
|
110
|
+
name = cls.__name__
|
|
111
|
+
if "name" in opts and opts["name"]:
|
|
112
|
+
name = opts["name"]
|
|
113
|
+
|
|
114
|
+
# Validate that the class has exactly one run method and find it
|
|
115
|
+
# Also validate that class does not have multiple signal methods with the same name
|
|
116
|
+
signals: dict[str, SignalDefinition[..., Any]] = {}
|
|
117
|
+
signal_names: dict[
|
|
118
|
+
str, str
|
|
119
|
+
] = {} # Map signal name to method name for duplicate detection
|
|
120
|
+
run_method_name = None
|
|
121
|
+
for attr_name in dir(cls):
|
|
122
|
+
if attr_name.startswith("_"):
|
|
123
|
+
continue
|
|
124
|
+
|
|
125
|
+
attr = getattr(cls, attr_name)
|
|
126
|
+
if not callable(attr):
|
|
127
|
+
continue
|
|
128
|
+
|
|
129
|
+
# Check for workflow run method
|
|
130
|
+
if hasattr(attr, "_workflow_run"):
|
|
131
|
+
if run_method_name is not None:
|
|
132
|
+
raise ValueError(
|
|
133
|
+
f"Multiple @workflow.run methods found in class {cls.__name__}"
|
|
134
|
+
)
|
|
135
|
+
run_method_name = attr_name
|
|
136
|
+
|
|
137
|
+
if hasattr(attr, "_workflow_signal"):
|
|
138
|
+
signal_name = getattr(attr, "_workflow_signal")
|
|
139
|
+
if signal_name in signal_names:
|
|
140
|
+
raise ValueError(
|
|
141
|
+
f"Multiple @workflow.signal methods found in class {cls.__name__} "
|
|
142
|
+
f"with signal name '{signal_name}': '{attr_name}' and '{signal_names[signal_name]}'"
|
|
143
|
+
)
|
|
144
|
+
# Create SignalDefinition from the decorated method
|
|
145
|
+
signal_def = SignalDefinition.wrap(
|
|
146
|
+
attr, SignalDefinitionOptions(name=signal_name)
|
|
147
|
+
)
|
|
148
|
+
signals[signal_name] = signal_def
|
|
149
|
+
signal_names[signal_name] = attr_name
|
|
150
|
+
|
|
151
|
+
if run_method_name is None:
|
|
152
|
+
raise ValueError(f"No @workflow.run method found in class {cls.__name__}")
|
|
153
|
+
|
|
154
|
+
return WorkflowDefinition(cls, name, run_method_name, signals)
|
|
155
|
+
|
|
156
|
+
|
|
157
|
+
def run(func: Optional[T] = None) -> Union[T, Callable[[T], T]]:
|
|
158
|
+
"""
|
|
159
|
+
Decorator to mark a method as the main workflow run method.
|
|
160
|
+
|
|
161
|
+
Can be used with or without parentheses:
|
|
162
|
+
@workflow.run
|
|
163
|
+
async def my_workflow(self):
|
|
164
|
+
...
|
|
165
|
+
|
|
166
|
+
@workflow.run()
|
|
167
|
+
async def my_workflow(self):
|
|
168
|
+
...
|
|
169
|
+
|
|
170
|
+
Args:
|
|
171
|
+
func: The method to mark as the workflow run method
|
|
172
|
+
|
|
173
|
+
Returns:
|
|
174
|
+
The decorated method with workflow run metadata
|
|
175
|
+
|
|
176
|
+
Raises:
|
|
177
|
+
ValueError: If the function is not async
|
|
178
|
+
"""
|
|
179
|
+
|
|
180
|
+
def decorator(f: T) -> T:
|
|
181
|
+
# Validate that the function is async
|
|
182
|
+
if not inspect.iscoroutinefunction(f):
|
|
183
|
+
raise ValueError(f"Workflow run method '{f.__name__}' must be async")
|
|
184
|
+
|
|
185
|
+
# Attach metadata to the function
|
|
186
|
+
setattr(f, "_workflow_run", None)
|
|
187
|
+
return f
|
|
188
|
+
|
|
189
|
+
# Support both @workflow.run and @workflow.run()
|
|
190
|
+
if func is None:
|
|
191
|
+
# Called with parentheses: @workflow.run()
|
|
192
|
+
return decorator
|
|
193
|
+
else:
|
|
194
|
+
# Called without parentheses: @workflow.run
|
|
195
|
+
return decorator(func)
|
|
196
|
+
|
|
197
|
+
|
|
198
|
+
def signal(name: str | None = None) -> Callable[[T], T]:
|
|
199
|
+
"""
|
|
200
|
+
Decorator to mark a method as a workflow signal handler.
|
|
201
|
+
|
|
202
|
+
Example:
|
|
203
|
+
@workflow.signal(name="approval_channel")
|
|
204
|
+
async def approve(self, approved: bool):
|
|
205
|
+
self.approved = approved
|
|
206
|
+
|
|
207
|
+
Args:
|
|
208
|
+
name: The name of the signal
|
|
209
|
+
|
|
210
|
+
Returns:
|
|
211
|
+
The decorated method with workflow signal metadata
|
|
212
|
+
|
|
213
|
+
Raises:
|
|
214
|
+
ValueError: If name is not provided
|
|
215
|
+
|
|
216
|
+
"""
|
|
217
|
+
if name is None:
|
|
218
|
+
raise ValueError("name is required")
|
|
219
|
+
|
|
220
|
+
def decorator(f: T) -> T:
|
|
221
|
+
f._workflow_signal = name # type: ignore
|
|
222
|
+
return f
|
|
223
|
+
|
|
224
|
+
# Only allow @workflow.signal(name), require name to be explicitly provided
|
|
225
|
+
return decorator
|
|
226
|
+
|
|
227
|
+
|
|
228
|
+
@dataclass(frozen=True)
|
|
229
|
+
class WorkflowInfo:
|
|
230
|
+
workflow_type: str
|
|
231
|
+
workflow_domain: str
|
|
232
|
+
workflow_id: str
|
|
233
|
+
workflow_run_id: str
|
|
234
|
+
workflow_task_list: str
|
|
235
|
+
data_converter: DataConverter
|
|
236
|
+
|
|
237
|
+
|
|
238
|
+
class WorkflowContext(ABC):
|
|
239
|
+
_var: ContextVar["WorkflowContext"] = ContextVar("workflow")
|
|
240
|
+
|
|
241
|
+
@abstractmethod
|
|
242
|
+
def info(self) -> WorkflowInfo: ...
|
|
243
|
+
|
|
244
|
+
@abstractmethod
|
|
245
|
+
def data_converter(self) -> DataConverter: ...
|
|
246
|
+
|
|
247
|
+
@abstractmethod
|
|
248
|
+
async def execute_activity(
|
|
249
|
+
self,
|
|
250
|
+
activity: str,
|
|
251
|
+
result_type: Type[ResultType],
|
|
252
|
+
*args: Any,
|
|
253
|
+
**kwargs: Unpack[ActivityOptions],
|
|
254
|
+
) -> ResultType: ...
|
|
255
|
+
|
|
256
|
+
@contextmanager
|
|
257
|
+
def _activate(self) -> Iterator["WorkflowContext"]:
|
|
258
|
+
token = WorkflowContext._var.set(self)
|
|
259
|
+
yield self
|
|
260
|
+
WorkflowContext._var.reset(token)
|
|
261
|
+
|
|
262
|
+
@staticmethod
|
|
263
|
+
def is_set() -> bool:
|
|
264
|
+
return WorkflowContext._var.get(None) is not None
|
|
265
|
+
|
|
266
|
+
@staticmethod
|
|
267
|
+
def get() -> "WorkflowContext":
|
|
268
|
+
res = WorkflowContext._var.get(None)
|
|
269
|
+
if res is None:
|
|
270
|
+
raise RuntimeError("Workflow function used outside of workflow context")
|
|
271
|
+
return res
|
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: cadence-python-client
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Python framework for authoring Cadence workflows and activities
|
|
5
|
+
Author: Cadence
|
|
6
|
+
License: Apache-2.0
|
|
7
|
+
Project-URL: Homepage, https://cadenceworkflow.io/
|
|
8
|
+
Project-URL: Documentation, https://cadenceworkflow.io/docs/get-started
|
|
9
|
+
Project-URL: Repository, https://github.com/cadence-workflow/cadence-python-client
|
|
10
|
+
Project-URL: Bug Tracker, https://github.com/cadence-workflow/cadence-python-client/issues
|
|
11
|
+
Keywords: workflow,orchestration,distributed,async,cadence
|
|
12
|
+
Classifier: Development Status :: 3 - Alpha
|
|
13
|
+
Classifier: Intended Audience :: Developers
|
|
14
|
+
Classifier: License :: OSI Approved :: Apache Software License
|
|
15
|
+
Classifier: Operating System :: OS Independent
|
|
16
|
+
Classifier: Programming Language :: Python :: 3
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
20
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
21
|
+
Classifier: Topic :: System :: Distributed Computing
|
|
22
|
+
Requires-Python: <3.14,>=3.11
|
|
23
|
+
Description-Content-Type: text/markdown
|
|
24
|
+
License-File: LICENSE
|
|
25
|
+
License-File: NOTICE
|
|
26
|
+
Requires-Dist: grpcio==1.71.2
|
|
27
|
+
Requires-Dist: grpcio-status>=1.71.2
|
|
28
|
+
Requires-Dist: msgspec>=0.19.0
|
|
29
|
+
Requires-Dist: protobuf==5.29.1
|
|
30
|
+
Requires-Dist: typing-extensions>=4.0.0
|
|
31
|
+
Requires-Dist: prometheus-client>=0.21.0
|
|
32
|
+
Provides-Extra: dev
|
|
33
|
+
Requires-Dist: grpcio-tools==1.71.2; extra == "dev"
|
|
34
|
+
Requires-Dist: pytest>=8.4.1; extra == "dev"
|
|
35
|
+
Requires-Dist: pytest-cov>=4.0.0; extra == "dev"
|
|
36
|
+
Requires-Dist: pytest-asyncio>=0.21.0; extra == "dev"
|
|
37
|
+
Requires-Dist: black>=23.0.0; extra == "dev"
|
|
38
|
+
Requires-Dist: isort>=5.12.0; extra == "dev"
|
|
39
|
+
Requires-Dist: flake8>=6.0.0; extra == "dev"
|
|
40
|
+
Requires-Dist: mypy>=1.0.0; extra == "dev"
|
|
41
|
+
Requires-Dist: pre-commit>=3.0.0; extra == "dev"
|
|
42
|
+
Requires-Dist: pytest-docker>=3.2.3; extra == "dev"
|
|
43
|
+
Provides-Extra: docs
|
|
44
|
+
Requires-Dist: sphinx>=6.0.0; extra == "docs"
|
|
45
|
+
Requires-Dist: sphinx-rtd-theme>=1.2.0; extra == "docs"
|
|
46
|
+
Requires-Dist: myst-parser>=1.0.0; extra == "docs"
|
|
47
|
+
Provides-Extra: examples
|
|
48
|
+
Requires-Dist: requests>=2.28.0; extra == "examples"
|
|
49
|
+
Requires-Dist: aiohttp>=3.8.0; extra == "examples"
|
|
50
|
+
Dynamic: license-file
|
|
51
|
+
|
|
52
|
+
# Python framework for Cadence
|
|
53
|
+
|
|
54
|
+
[Cadence](https://github.com/uber/cadence) is a distributed, scalable, durable, and highly available orchestration engine we developed at Uber Engineering to execute asynchronous long-running business logic in a scalable and resilient way.
|
|
55
|
+
|
|
56
|
+
If you'd like to propose a new feature, first join the [CNCF Slack workspace](https://communityinviter.com/apps/cloud-native/cncf) in the **#cadence-users** channel to start a discussion.
|
|
57
|
+
|
|
58
|
+
`cadence-python-client` is the Python framework for authoring workflows and activities.
|
|
59
|
+
|
|
60
|
+
## Disclaimer
|
|
61
|
+
**This SDK is currently an early work-in-progress (WIP) and is NOT ready for production use.**
|
|
62
|
+
|
|
63
|
+
- This project is still in active development
|
|
64
|
+
- It has not been published to any package repository (PyPI, etc.)
|
|
65
|
+
- APIs and interfaces are subject to change without notice
|
|
66
|
+
|
|
67
|
+
## Installation
|
|
68
|
+
|
|
69
|
+
```bash
|
|
70
|
+
git clone https://github.com/cadence-workflow/cadence-python-client.git
|
|
71
|
+
cd cadence-python-client
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
## Development
|
|
75
|
+
|
|
76
|
+
### Setup
|
|
77
|
+
|
|
78
|
+
1. **Install protobuf (required):**
|
|
79
|
+
```bash
|
|
80
|
+
# macOS
|
|
81
|
+
brew install protobuf@29
|
|
82
|
+
|
|
83
|
+
# Linux/Other
|
|
84
|
+
# Install protobuf 29.x via your package manager
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
2. **Install uv (recommended):**
|
|
88
|
+
```bash
|
|
89
|
+
# macOS
|
|
90
|
+
brew install uv
|
|
91
|
+
|
|
92
|
+
# Linux/Other
|
|
93
|
+
curl -LsSf https://astral.sh/uv/install.sh | sh
|
|
94
|
+
source $HOME/.local/bin/env # Add to your shell profile for persistence
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
3. **Create virtual environment and install dependencies:**
|
|
98
|
+
```bash
|
|
99
|
+
uv venv
|
|
100
|
+
uv pip install -e ".[dev]"
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
Or if you prefer traditional pip:
|
|
104
|
+
```bash
|
|
105
|
+
python3.11 -m venv venv
|
|
106
|
+
source venv/bin/activate # Windows: venv\Scripts\activate
|
|
107
|
+
pip install -e ".[dev]"
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
### Generate Protobuf and gRPC Files
|
|
111
|
+
|
|
112
|
+
Run the generation script:
|
|
113
|
+
```bash
|
|
114
|
+
# Using uv (recommended)
|
|
115
|
+
uv sync --extra dev
|
|
116
|
+
uv run python scripts/generate_proto.py
|
|
117
|
+
|
|
118
|
+
# Or using traditional Python
|
|
119
|
+
python scripts/generate_proto.py
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
This will:
|
|
123
|
+
- Download protoc 29.1 binary
|
|
124
|
+
- Install grpcio-tools if needed
|
|
125
|
+
- Generate Python protobuf files in `cadence/api/v1/`
|
|
126
|
+
- Generate gRPC service files in `cadence/api/v1/`
|
|
127
|
+
- Create proper package structure with both protobuf and gRPC imports
|
|
128
|
+
|
|
129
|
+
### Test
|
|
130
|
+
|
|
131
|
+
Verify the generated files work:
|
|
132
|
+
```bash
|
|
133
|
+
# Using uv (recommended)
|
|
134
|
+
uv run python cadence/sample/simple_usage_example.py
|
|
135
|
+
uv run python cadence/sample/grpc_usage_example.py
|
|
136
|
+
|
|
137
|
+
# Or using traditional Python
|
|
138
|
+
python cadence/sample/simple_usage_example.py
|
|
139
|
+
python test_grpc_with_examples.py
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
### Development Script
|
|
143
|
+
|
|
144
|
+
The project includes a development script that provides convenient commands for common tasks:
|
|
145
|
+
|
|
146
|
+
```bash
|
|
147
|
+
# Generate protobuf files
|
|
148
|
+
uv run python scripts/dev.py protobuf
|
|
149
|
+
|
|
150
|
+
# Run tests
|
|
151
|
+
uv run python scripts/dev.py test
|
|
152
|
+
|
|
153
|
+
# Run tests with coverage
|
|
154
|
+
uv run python scripts/dev.py test-cov
|
|
155
|
+
|
|
156
|
+
# Run linting
|
|
157
|
+
uv run python scripts/dev.py lint
|
|
158
|
+
|
|
159
|
+
# Format code
|
|
160
|
+
uv run python scripts/dev.py format
|
|
161
|
+
|
|
162
|
+
# Install in development mode
|
|
163
|
+
uv run python scripts/dev.py install
|
|
164
|
+
|
|
165
|
+
# Install with dev dependencies
|
|
166
|
+
uv run python scripts/dev.py install-dev
|
|
167
|
+
|
|
168
|
+
# Build package
|
|
169
|
+
uv run python scripts/dev.py build
|
|
170
|
+
|
|
171
|
+
# Clean build artifacts
|
|
172
|
+
uv run python scripts/dev.py clean
|
|
173
|
+
|
|
174
|
+
# Run all checks (lint + test)
|
|
175
|
+
uv run python scripts/dev.py check
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
## License
|
|
179
|
+
|
|
180
|
+
Apache 2.0 License, please see [LICENSE](LICENSE) for details.
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
cadence/__init__.py,sha256=XOIsExuXANww36y5qXaDdelG_xQGlCmhvh6hZe3yBf0,301
|
|
2
|
+
cadence/activity.py,sha256=f6xjg5qJUN2eCYdC-vCigOcoXhSZKNUBczZbFougd5g,7060
|
|
3
|
+
cadence/client.py,sha256=5n-Pjhx-KfkETNKw15f42Y60sNtl9hAETATq85e9720,13011
|
|
4
|
+
cadence/data_converter.py,sha256=BWzq1eKos7GolFJ5S-j3zqTsIDYEin-auaPHXRytqhM,2559
|
|
5
|
+
cadence/error.py,sha256=K-iT6RHvKAY7QEEgLcTd10uu944A5Xeig2m8k5c7Yr8,3030
|
|
6
|
+
cadence/signal.py,sha256=dlRJR9cjfHlOb3ZwRQW0PkVr4ETJqotyVqIPcEl-NKo,4572
|
|
7
|
+
cadence/workflow.py,sha256=b2jf-0oKCgRS1GNbKiQHM93_I-bfIxMYQrB0EzFKIW0,7663
|
|
8
|
+
cadence/_internal/__init__.py,sha256=CHRVMb61lNtf042rNlPEE0Ubg5CYK6klk9WrHy07Vc8,307
|
|
9
|
+
cadence/_internal/activity/__init__.py,sha256=jnyPV8aJFzpoR830m5UCHsvq5h8RfleOmyu2mu1pj2Q,88
|
|
10
|
+
cadence/_internal/activity/_activity_executor.py,sha256=zUVJT1gXK05sv4tFfLWXn3z2TDvGjAtN5c8jZ7Je0EY,4188
|
|
11
|
+
cadence/_internal/activity/_context.py,sha256=FpSiNCk3dJ1He1p04WhEt4Zzuleq0Vf86KB5lgMeIW4,1780
|
|
12
|
+
cadence/_internal/rpc/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
13
|
+
cadence/_internal/rpc/error.py,sha256=RLcOqeTTusDKASxcxdVyrtoOuPWyiXWZgd-wlgJENJU,5795
|
|
14
|
+
cadence/_internal/rpc/retry.py,sha256=3UGafXASwKDInBSE4bjSZJh_SAImsU7nLCmQra05k_U,3445
|
|
15
|
+
cadence/_internal/rpc/yarpc.py,sha256=ijP_JkjhfbPHa5tJcE-u_JPQBPYsPm3_0kXOQDyf0i0,1351
|
|
16
|
+
cadence/_internal/workflow/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
17
|
+
cadence/_internal/workflow/context.py,sha256=AKQr9OR7Lf66NFWvB9WiyIHlBxTDTQwVX4FmTskSEdw,4643
|
|
18
|
+
cadence/_internal/workflow/decision_events_iterator.py,sha256=i6ZH5xyGQe_vLoJhuf5AzC_ArFQ3XzWhgi_eUoEmqEU,6263
|
|
19
|
+
cadence/_internal/workflow/decisions_helper.py,sha256=jqTeQdw026w6bOT8O0M8lQ00sNnGpeOSMxJNuPBa150,10337
|
|
20
|
+
cadence/_internal/workflow/deterministic_event_loop.py,sha256=pGWonKnN-itqmqhXdbOgcOTFwZwAqkABwwEx-XMR33M,16973
|
|
21
|
+
cadence/_internal/workflow/history_event_iterator.py,sha256=AOeIS6bguGfxc6l6KoPMGkhMSdPaFgHedDupgPZK21k,1860
|
|
22
|
+
cadence/_internal/workflow/workflow_engine.py,sha256=FDpwzOX6gfglPLFOfBjIeD1Jg69SbEd3dhrCE4H3LqQ,10091
|
|
23
|
+
cadence/_internal/workflow/workflow_intance.py,sha256=uSSHvk_2KTTCjUj8_GD4Zc7qncrvGHDhG5cEcd_zQvc,1791
|
|
24
|
+
cadence/_internal/workflow/statemachine/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
25
|
+
cadence/_internal/workflow/statemachine/activity_state_machine.py,sha256=iQF84fKnDbP4Nn33a9TOP4GYl0zzmfE_Xm-AOUxjS_c,3876
|
|
26
|
+
cadence/_internal/workflow/statemachine/decision_manager.py,sha256=5nH43XZRrENhTY2Cu7PpK1iZSlYERVC4vBrAslLNQEQ,5880
|
|
27
|
+
cadence/_internal/workflow/statemachine/decision_state_machine.py,sha256=8wCFo0ptgvebKcsLECngSKx9dzWsw85cmnPq8OOPA_0,2200
|
|
28
|
+
cadence/_internal/workflow/statemachine/event_dispatcher.py,sha256=qRhvdTNwpzj7FyCAZ0D2UL4SdGl-yrr8sgupIx_gP38,2609
|
|
29
|
+
cadence/_internal/workflow/statemachine/timer_state_machine.py,sha256=qWkp3eqA5BvLjbSCBxcBa2c2J85dyU41pz3zo7ozoDM,2725
|
|
30
|
+
cadence/api/v1/__init__.py,sha256=7XJR08QwFhK1YRDxjlDLTttFu0mkdOOykFwo-WJ5wm4,2533
|
|
31
|
+
cadence/api/v1/common_pb2.py,sha256=eD4n0QMNLxK5Vo88jCgZkU_xti2gJ4ToQo4WbLPhPEU,8450
|
|
32
|
+
cadence/api/v1/common_pb2.pyi,sha256=-qu2GQ_GTnIZ_MxfkR7NxrOH7bl8-2F8CW1pmheXQTA,9789
|
|
33
|
+
cadence/api/v1/common_pb2_grpc.py,sha256=0hGhK6q2Ry2BbE9LlNuZtfeY3g5fKi3xfkImlc2O0ns,902
|
|
34
|
+
cadence/api/v1/decision_pb2.py,sha256=THh9mtLjZlOVmCtPh-uwRGnanwK2YFeoUmoP96SGYDY,11607
|
|
35
|
+
cadence/api/v1/decision_pb2.pyi,sha256=gYP6vhVxNWIz9-oPgn_ztSxiXa1IYNp6nxBFTLL66i4,17952
|
|
36
|
+
cadence/api/v1/decision_pb2_grpc.py,sha256=Eb0_udT9oqyck80jkMtT-ziWe3CCEtSchUYCvjdxflI,904
|
|
37
|
+
cadence/api/v1/domain_pb2.py,sha256=CfrbfO8Dy5u8ePH5MRoyiWfpqNBUaBWWSNsnN7RLi0E,6868
|
|
38
|
+
cadence/api/v1/domain_pb2.pyi,sha256=v7EW4V2D8_Mv_11nRkplbWsWzY0Glr57faL1zUK1PC4,8401
|
|
39
|
+
cadence/api/v1/domain_pb2_grpc.py,sha256=bNl0u4U_EOlo8O_LSXpll_EeK9eMywnTJQGps7cutQc,902
|
|
40
|
+
cadence/api/v1/error_pb2.py,sha256=6f39Am_w8NCB5fJn94Vz5icJ5TeX6zuVsVH8l9HNHq0,4030
|
|
41
|
+
cadence/api/v1/error_pb2.pyi,sha256=etMm0dtM29lMwts3YjA_PJNye-9Hqy1Cc5i1PGPqBYA,3393
|
|
42
|
+
cadence/api/v1/error_pb2_grpc.py,sha256=U88D7uhJrHeghv9gJiaGcb1ysUQjGokxIAkKuO0oVzo,901
|
|
43
|
+
cadence/api/v1/history_pb2.py,sha256=b0jGNa_Oo3nK9n5PmGXTURYtiahbyBYh8ECuDC5PoYA,33834
|
|
44
|
+
cadence/api/v1/history_pb2.pyi,sha256=3pYDdm2OmWZH-tE_ojj46dCUBgoUEabPMpGXUjzHLTo,59861
|
|
45
|
+
cadence/api/v1/history_pb2_grpc.py,sha256=iUMgBKd0qg-Y2KaTLMEu3Oz0wGH4890ASIpmSf050IA,903
|
|
46
|
+
cadence/api/v1/query_pb2.py,sha256=EmRdeRnApxle27ZhANQmhW0OrHYUdK-V6w01lW_PisU,3399
|
|
47
|
+
cadence/api/v1/query_pb2.pyi,sha256=QhdhrEbevQ64Jn8cTOD0udWxGcd2R96i28LywFx4zb0,2989
|
|
48
|
+
cadence/api/v1/query_pb2_grpc.py,sha256=Jw2vm8KArbjKygLW5u3hazZ0XRgtp0q1NV8ku_Bz-ec,901
|
|
49
|
+
cadence/api/v1/service_domain_pb2.py,sha256=jYXBceRDEsBwDhmnhKePJiM2hmBZW1L1ihgcfrxsSAY,8573
|
|
50
|
+
cadence/api/v1/service_domain_pb2.pyi,sha256=9AAj19DT81yAz2bAgdRIH-jOngDRbxbGtvOvu-tNEzA,9363
|
|
51
|
+
cadence/api/v1/service_domain_pb2_grpc.py,sha256=avu-UjidG49tdw0W4Hr91HL1_qcSrGfHH7-kQkBIFEE,14452
|
|
52
|
+
cadence/api/v1/service_meta_pb2.py,sha256=u5PCzKiMMBsiiWdjIcvjcSGTN_nftSb-7fD8Hi37Ytg,1999
|
|
53
|
+
cadence/api/v1/service_meta_pb2.pyi,sha256=_cCUN2Vd74Z8amoRhP0zqxYS7hhmQ8lppjGXuEI6nt0,566
|
|
54
|
+
cadence/api/v1/service_meta_pb2_grpc.py,sha256=i-USldukY-hLzturEE0S1NgZ9yBsWEmIIkBDmo1sOe4,3670
|
|
55
|
+
cadence/api/v1/service_visibility_pb2.py,sha256=HkrQItKcIRUOuwX4CYRIhqeQh0T_yGPxAx5wHhLcSR0,8320
|
|
56
|
+
cadence/api/v1/service_visibility_pb2.pyi,sha256=HrSR6mJ_4fza4Kv4aGph2STEzc8V6_Y33skyk7CO52g,8219
|
|
57
|
+
cadence/api/v1/service_visibility_pb2_grpc.py,sha256=LxcvfuOme4e7z2HZIVJt6p2Pcizb4wrFU6WfH7o7dZ0,17205
|
|
58
|
+
cadence/api/v1/service_worker_pb2.py,sha256=Y4p-SuMdm7SsVIcBr1xw16mnxPT0f6gozI8_yt_SHXo,18403
|
|
59
|
+
cadence/api/v1/service_worker_pb2.pyi,sha256=Sz1UmRur2ZTwPHhlQtwzMk0BPww7GeQZIQQW6WuM9Xs,20340
|
|
60
|
+
cadence/api/v1/service_worker_pb2_grpc.py,sha256=vnuma-HeqIyqjl32BxIEcpyEknRi0Y9PNkWkk7Vj4ok,39514
|
|
61
|
+
cadence/api/v1/service_workflow_pb2.py,sha256=JrHeigR5meNl6JaRt8rcjzeelgQ7UfjTNgL0KVm9lUI,20638
|
|
62
|
+
cadence/api/v1/service_workflow_pb2.pyi,sha256=SpX5dYMZRcReSSBclsTvJioRVjOS6fvfILdkPtg67l4,23738
|
|
63
|
+
cadence/api/v1/service_workflow_pb2_grpc.py,sha256=wphlh9PJtTALVripgnsxXEQ1ascYoryA6gakSIbnHJI,42018
|
|
64
|
+
cadence/api/v1/tasklist_pb2.py,sha256=5pGTZ4ypy7i3ybk8kVbBNjSCrkCJMATOkB5DxpYlPIY,7365
|
|
65
|
+
cadence/api/v1/tasklist_pb2.pyi,sha256=oxIV5uUbm2wK3gRa5NvJXUUsE7VmdcgkdifbeNi9xZ8,7507
|
|
66
|
+
cadence/api/v1/tasklist_pb2_grpc.py,sha256=g1S_5zrmA_wEkhlYT9QEh8mc5oP--Mke8uiVHxV1Glw,904
|
|
67
|
+
cadence/api/v1/visibility_pb2.py,sha256=625nIES4-X3J28S6-BqmrJD3wU8GeX-yGs-vgieTAH8,3107
|
|
68
|
+
cadence/api/v1/visibility_pb2.pyi,sha256=e8gmFeLPikvEs9vi1TF8g80g3UqAzJxw6ghR8w1k9nM,2489
|
|
69
|
+
cadence/api/v1/visibility_pb2_grpc.py,sha256=VfMwcli_WeE47ea1WD9UHAP89w5FRDN5ZX1xpp9E-T8,906
|
|
70
|
+
cadence/api/v1/workflow_pb2.py,sha256=dmnTk4d9x_9RFuQok1n5jxZCjkKKyzVqlYlsvqIDm5E,14986
|
|
71
|
+
cadence/api/v1/workflow_pb2.pyi,sha256=3FjLcUGH7tN9tNxyrEiubmlrh7FeBF6MZcDuEKdOe6c,24949
|
|
72
|
+
cadence/api/v1/workflow_pb2_grpc.py,sha256=eVYUW0AotPWNLKPL9tkcpvjpLz0k9SZB6WlaPj9TFQo,904
|
|
73
|
+
cadence/metrics/__init__.py,sha256=ETEkUqTnZAcAlDg7ahszbnQQXjA4FgenLM51rVoVFlc,315
|
|
74
|
+
cadence/metrics/constants.py,sha256=59y2wflfI-GqjVLsriddlz1tgJ7PfXsqBmAa_iN5Sxo,6796
|
|
75
|
+
cadence/metrics/metrics.py,sha256=yZcy7ZzAwXM7V8VaNUIiFJ9lgvAslqhHkO4eQaBJoT4,1351
|
|
76
|
+
cadence/metrics/prometheus.py,sha256=8mIA_vYbXeARG9Tc4w3nIQxQKwnmxgCJMDb-6fLYFNo,5418
|
|
77
|
+
cadence/sample/__init__.py,sha256=h12Cl5Qq2xA1Zz8tNbxklrg1TxerMNZq1EQDS8QhoXo,53
|
|
78
|
+
cadence/sample/client_example.py,sha256=1dwYJrYDp4Gwn1pFMuMQNgGkIlFBRaHxvpzoK0iZEzI,324
|
|
79
|
+
cadence/sample/grpc_usage_example.py,sha256=szLl5GwzRtx2D48Shn7s7ko4iTWH-CdmHo6I92WzWqQ,6947
|
|
80
|
+
cadence/sample/simple_usage_example.py,sha256=Pt8lR3-sKvje042i9PVhbSF34NOlCZXa3bdNckkk9oM,4881
|
|
81
|
+
cadence/worker/__init__.py,sha256=y8234sZQmWDysUTa70ZFK2bvz4xBqFBT9jearbbScDg,211
|
|
82
|
+
cadence/worker/_activity.py,sha256=4MehD6Jsqmme_OB2OUOFV5ved6bDlP47jpIbpXnauN8,2117
|
|
83
|
+
cadence/worker/_base_task_handler.py,sha256=RUKuGGCOr232Pz12qHUPPR7to8RXzcncwGA3EczNcCQ,1962
|
|
84
|
+
cadence/worker/_decision.py,sha256=KiXUbd5Irsi4So5BeeduNtgWds48_DQTEwu8SSCpNoM,2262
|
|
85
|
+
cadence/worker/_decision_task_handler.py,sha256=Ilp9s_OH2Kmib0Y3s-PM7tMqajlXOebwTot3kmFt42M,10724
|
|
86
|
+
cadence/worker/_poller.py,sha256=QxjHcoOZ2VAulfnVRG8jx5WHrfIrnTrvoAm4wWdRjiI,1947
|
|
87
|
+
cadence/worker/_registry.py,sha256=2j2wK5hKOI2FzMxWIANPOWmxisOnmF_80uvsLoRinmg,7233
|
|
88
|
+
cadence/worker/_types.py,sha256=eiUtWeEwmisq5Z8Qgx2dHv4og3m3LPFovgVzNyWq-rE,813
|
|
89
|
+
cadence/worker/_worker.py,sha256=HhfAn2rCe26oDVOvTz7VL6WnOzkqbdHaykdfEs5junk,1770
|
|
90
|
+
cadence_python_client-0.1.0.dist-info/licenses/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
|
|
91
|
+
cadence_python_client-0.1.0.dist-info/licenses/NOTICE,sha256=U9hvT-wujG3BXy5FLfqvyxGjCrzwa6ZlrijAz2OSLQo,1081
|
|
92
|
+
cadence_python_client-0.1.0.dist-info/METADATA,sha256=YbaqxfnmvDbfl2YM181VfCUILv7l4Wkb9ziqqhvBuGE,5452
|
|
93
|
+
cadence_python_client-0.1.0.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
94
|
+
cadence_python_client-0.1.0.dist-info/top_level.txt,sha256=KnUsgihoRao9Q9nvZm7RPS5IPIxoL7ItRElWmn9ZOMo,8
|
|
95
|
+
cadence_python_client-0.1.0.dist-info/RECORD,,
|