|
| 1 | +---- |
| 2 | +NOTE: I'm no longer working on this SDK. I will be refocusing my efforts on downstream tools. |
| 3 | +---- |
| 4 | + |
1 | 5 | # Unofficial Python SDK for the Temporal Workflow Engine |
2 | 6 |
|
3 | 7 | ## Status |
4 | 8 |
|
5 | 9 | This should be considered EXPERIMENTAL at the moment. At the moment, all I can say is that the [test cases](https://gist.github.com/firdaus/4ec442f2c626122ad0c8d379a7ffd8bc) currently pass. I have not tested this for any real world use cases yet. |
6 | 10 |
|
| 11 | +## Installation |
| 12 | + |
| 13 | +``` |
| 14 | +pip install temporal-python-sdk |
| 15 | +``` |
| 16 | +## Sample Code |
| 17 | + |
| 18 | +Sample code for using this library can be found in [Workflows in Python Using Temporal](https://onepointzero.app/workflows-in-python-using-temporal/). |
| 19 | + |
| 20 | +## Hello World |
| 21 | + |
| 22 | +```python |
| 23 | +import asyncio |
| 24 | +import logging |
| 25 | +from datetime import timedelta |
| 26 | + |
| 27 | +from temporal.activity_method import activity_method |
| 28 | +from temporal.workerfactory import WorkerFactory |
| 29 | +from temporal.workflow import workflow_method, Workflow, WorkflowClient |
| 30 | + |
| 31 | +logging.basicConfig(level=logging.INFO) |
| 32 | + |
| 33 | +TASK_QUEUE = "HelloActivity-python-tq" |
| 34 | +NAMESPACE = "default" |
| 35 | + |
| 36 | +# Activities Interface |
| 37 | +class GreetingActivities: |
| 38 | + @activity_method(task_queue=TASK_QUEUE, schedule_to_close_timeout=timedelta(seconds=1000)) |
| 39 | + async def compose_greeting(self, greeting: str, name: str) -> str: |
| 40 | + raise NotImplementedError |
| 41 | + |
| 42 | + |
| 43 | +# Activities Implementation |
| 44 | +class GreetingActivitiesImpl: |
| 45 | + async def compose_greeting(self, greeting: str, name: str): |
| 46 | + return greeting + " " + name + "!" |
| 47 | + |
| 48 | + |
| 49 | +# Workflow Interface |
| 50 | +class GreetingWorkflow: |
| 51 | + @workflow_method(task_queue=TASK_QUEUE) |
| 52 | + async def get_greeting(self, name: str) -> str: |
| 53 | + raise NotImplementedError |
| 54 | + |
| 55 | + |
| 56 | +# Workflow Implementation |
| 57 | +class GreetingWorkflowImpl(GreetingWorkflow): |
| 58 | + |
| 59 | + def __init__(self): |
| 60 | + self.greeting_activities: GreetingActivities = Workflow.new_activity_stub(GreetingActivities) |
| 61 | + pass |
| 62 | + |
| 63 | + async def get_greeting(self, name): |
| 64 | + return await self.greeting_activities.compose_greeting("Hello", name) |
| 65 | + |
| 66 | + |
| 67 | +async def client_main(): |
| 68 | + client = WorkflowClient.new_client(namespace=NAMESPACE) |
| 69 | + |
| 70 | + factory = WorkerFactory(client, NAMESPACE) |
| 71 | + worker = factory.new_worker(TASK_QUEUE) |
| 72 | + worker.register_activities_implementation(GreetingActivitiesImpl(), "GreetingActivities") |
| 73 | + worker.register_workflow_implementation_type(GreetingWorkflowImpl) |
| 74 | + factory.start() |
| 75 | + |
| 76 | + greeting_workflow: GreetingWorkflow = client.new_workflow_stub(GreetingWorkflow) |
| 77 | + result = await greeting_workflow.get_greeting("Python") |
| 78 | + print(result) |
| 79 | + print("Stopping workers.....") |
| 80 | + await worker.stop() |
| 81 | + print("Workers stopped......") |
| 82 | + |
| 83 | +if __name__ == '__main__': |
| 84 | + asyncio.run(client_main()) |
| 85 | +``` |
| 86 | + |
7 | 87 | ## Roadmap |
8 | 88 |
|
9 | 89 | 1.0 |
@@ -43,22 +123,26 @@ This should be considered EXPERIMENTAL at the moment. At the moment, all I can s |
43 | 123 |
|
44 | 124 | 1.1 |
45 | 125 | - [x] ActivityStub and Workflow.newUntypedActivityStub |
46 | | -- [ ] Classes as arguments and return values to/from activity and workflow methods (DataConverter) |
| 126 | +- [x] Remove threading, use coroutines for everything all concurrency |
| 127 | +- [x] Classes as arguments and return values to/from activity and workflow methods (DataConverter) |
| 128 | + - [x] Type hints for DataConverter |
| 129 | +- [x] Parallel activity execution (STATUS: there's a working but not finalized API). |
| 130 | + |
| 131 | +1.2 |
| 132 | +- [x] Timers |
| 133 | +- [x] Custom workflow ids through start() and new_workflow_stub() |
| 134 | + |
| 135 | + |
| 136 | +Other: |
47 | 137 | - [ ] WorkflowStub and WorkflowClient.newUntypedWorkflowStub |
48 | | -- [ ] Custom workflow ids through start() and new_workflow_stub() |
49 | 138 | - [ ] ContinueAsNew |
50 | | -- [ ] Parallel activity execution (STATUS: there's a working but not finalized API). |
51 | | -- [ ] Compatibility with Java client |
52 | | -- [ ] Compatibility with Golang client |
53 | | -- [ ] Remove threading, use coroutines for everything all concurrency |
54 | | - |
55 | | -2.0 |
56 | 139 | - [ ] Sticky workflows |
57 | | - |
58 | | -Post 2.0: |
| 140 | +- [ ] Child Workflows |
| 141 | +- [ ] Support for keyword arguments |
| 142 | +- [ ] Compatibility with Java client |
| 143 | +- [ ] Compatibility with Golang client |
| 144 | +- [ ] Upgrade python-betterproto |
59 | 145 | - [ ] sideEffect/mutableSideEffect |
60 | 146 | - [ ] Local activity |
61 | | -- [ ] Timers |
62 | 147 | - [ ] Cancellation Scopes |
63 | | -- [ ] Child Workflows |
64 | 148 | - [ ] Explicit activity ids for activity invocations |
0 commit comments