hatchet-sdk 1.2.6__py3-none-any.whl → 1.3.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.

Potentially problematic release.


This version of hatchet-sdk might be problematic. Click here for more details.

Files changed (60) hide show
  1. hatchet_sdk/__init__.py +7 -5
  2. hatchet_sdk/client.py +14 -6
  3. hatchet_sdk/clients/admin.py +57 -15
  4. hatchet_sdk/clients/dispatcher/action_listener.py +2 -2
  5. hatchet_sdk/clients/dispatcher/dispatcher.py +20 -7
  6. hatchet_sdk/clients/event_ts.py +25 -5
  7. hatchet_sdk/clients/listeners/durable_event_listener.py +125 -0
  8. hatchet_sdk/clients/listeners/pooled_listener.py +255 -0
  9. hatchet_sdk/clients/listeners/workflow_listener.py +62 -0
  10. hatchet_sdk/clients/rest/api/api_token_api.py +24 -24
  11. hatchet_sdk/clients/rest/api/default_api.py +64 -64
  12. hatchet_sdk/clients/rest/api/event_api.py +64 -64
  13. hatchet_sdk/clients/rest/api/github_api.py +8 -8
  14. hatchet_sdk/clients/rest/api/healthcheck_api.py +16 -16
  15. hatchet_sdk/clients/rest/api/log_api.py +16 -16
  16. hatchet_sdk/clients/rest/api/metadata_api.py +24 -24
  17. hatchet_sdk/clients/rest/api/rate_limits_api.py +8 -8
  18. hatchet_sdk/clients/rest/api/slack_api.py +16 -16
  19. hatchet_sdk/clients/rest/api/sns_api.py +24 -24
  20. hatchet_sdk/clients/rest/api/step_run_api.py +56 -56
  21. hatchet_sdk/clients/rest/api/task_api.py +56 -56
  22. hatchet_sdk/clients/rest/api/tenant_api.py +128 -128
  23. hatchet_sdk/clients/rest/api/user_api.py +96 -96
  24. hatchet_sdk/clients/rest/api/worker_api.py +24 -24
  25. hatchet_sdk/clients/rest/api/workflow_api.py +144 -144
  26. hatchet_sdk/clients/rest/api/workflow_run_api.py +48 -48
  27. hatchet_sdk/clients/rest/api/workflow_runs_api.py +40 -40
  28. hatchet_sdk/clients/rest/api_client.py +5 -8
  29. hatchet_sdk/clients/rest/configuration.py +7 -3
  30. hatchet_sdk/clients/rest/models/tenant_step_run_queue_metrics.py +2 -2
  31. hatchet_sdk/clients/rest/models/v1_task_summary.py +5 -0
  32. hatchet_sdk/clients/rest/models/v1_workflow_run.py +5 -0
  33. hatchet_sdk/clients/rest/rest.py +160 -111
  34. hatchet_sdk/clients/v1/api_client.py +2 -2
  35. hatchet_sdk/context/context.py +22 -21
  36. hatchet_sdk/features/cron.py +41 -40
  37. hatchet_sdk/features/logs.py +7 -6
  38. hatchet_sdk/features/metrics.py +19 -18
  39. hatchet_sdk/features/runs.py +88 -68
  40. hatchet_sdk/features/scheduled.py +42 -42
  41. hatchet_sdk/features/workers.py +17 -16
  42. hatchet_sdk/features/workflows.py +15 -14
  43. hatchet_sdk/hatchet.py +1 -1
  44. hatchet_sdk/runnables/standalone.py +12 -9
  45. hatchet_sdk/runnables/task.py +66 -2
  46. hatchet_sdk/runnables/types.py +8 -0
  47. hatchet_sdk/runnables/workflow.py +26 -125
  48. hatchet_sdk/waits.py +8 -8
  49. hatchet_sdk/worker/runner/run_loop_manager.py +4 -4
  50. hatchet_sdk/worker/runner/runner.py +22 -11
  51. hatchet_sdk/worker/worker.py +29 -25
  52. hatchet_sdk/workflow_run.py +58 -9
  53. {hatchet_sdk-1.2.6.dist-info → hatchet_sdk-1.3.1.dist-info}/METADATA +1 -1
  54. {hatchet_sdk-1.2.6.dist-info → hatchet_sdk-1.3.1.dist-info}/RECORD +57 -57
  55. hatchet_sdk/clients/durable_event_listener.py +0 -329
  56. hatchet_sdk/clients/workflow_listener.py +0 -288
  57. hatchet_sdk/utils/aio.py +0 -43
  58. /hatchet_sdk/clients/{run_event_listener.py → listeners/run_event_listener.py} +0 -0
  59. {hatchet_sdk-1.2.6.dist-info → hatchet_sdk-1.3.1.dist-info}/WHEEL +0 -0
  60. {hatchet_sdk-1.2.6.dist-info → hatchet_sdk-1.3.1.dist-info}/entry_points.txt +0 -0
@@ -1,3 +1,4 @@
1
+ import asyncio
1
2
  import datetime
2
3
  from typing import Optional
3
4
 
@@ -22,7 +23,6 @@ from hatchet_sdk.clients.v1.api_client import (
22
23
  BaseRestClient,
23
24
  maybe_additional_metadata_to_kv,
24
25
  )
25
- from hatchet_sdk.utils.aio import run_async_from_sync
26
26
  from hatchet_sdk.utils.typing import JSONSerializableMapping
27
27
 
28
28
 
@@ -33,7 +33,7 @@ class ScheduledClient(BaseRestClient):
33
33
  def _wa(self, client: ApiClient) -> WorkflowApi:
34
34
  return WorkflowApi(client)
35
35
 
36
- async def aio_create(
36
+ def create(
37
37
  self,
38
38
  workflow_name: str,
39
39
  trigger_at: datetime.datetime,
@@ -52,8 +52,8 @@ class ScheduledClient(BaseRestClient):
52
52
  Returns:
53
53
  ScheduledWorkflows: The created scheduled workflow instance.
54
54
  """
55
- async with self.client() as client:
56
- return await self._wra(client).scheduled_workflow_run_create(
55
+ with self.client() as client:
56
+ return self._wra(client).scheduled_workflow_run_create(
57
57
  tenant=self.client_config.tenant_id,
58
58
  workflow=workflow_name,
59
59
  schedule_workflow_run_request=ScheduleWorkflowRunRequest(
@@ -63,7 +63,7 @@ class ScheduledClient(BaseRestClient):
63
63
  ),
64
64
  )
65
65
 
66
- def create(
66
+ async def aio_create(
67
67
  self,
68
68
  workflow_name: str,
69
69
  trigger_at: datetime.datetime,
@@ -83,29 +83,29 @@ class ScheduledClient(BaseRestClient):
83
83
  ScheduledWorkflows: The created scheduled workflow instance.
84
84
  """
85
85
 
86
- return run_async_from_sync(
87
- self.aio_create,
86
+ return await asyncio.to_thread(
87
+ self.create,
88
88
  workflow_name,
89
89
  trigger_at,
90
90
  input,
91
91
  additional_metadata,
92
92
  )
93
93
 
94
- async def aio_delete(self, scheduled_id: str) -> None:
94
+ def delete(self, scheduled_id: str) -> None:
95
95
  """
96
96
  Deletes a scheduled workflow run.
97
97
 
98
98
  Args:
99
99
  scheduled_id (str): The scheduled workflow trigger ID to delete.
100
100
  """
101
- async with self.client() as client:
102
- await self._wa(client).workflow_scheduled_delete(
101
+ with self.client() as client:
102
+ self._wa(client).workflow_scheduled_delete(
103
103
  tenant=self.client_config.tenant_id,
104
104
  scheduled_workflow_run=scheduled_id,
105
105
  )
106
106
 
107
- def delete(self, scheduled_id: str) -> None:
108
- run_async_from_sync(self.aio_delete, scheduled_id)
107
+ async def aio_delete(self, scheduled_id: str) -> None:
108
+ await asyncio.to_thread(self.delete, scheduled_id)
109
109
 
110
110
  async def aio_list(
111
111
  self,
@@ -134,20 +134,17 @@ class ScheduledClient(BaseRestClient):
134
134
  Returns:
135
135
  List[ScheduledWorkflows]: A list of scheduled workflows matching the criteria.
136
136
  """
137
- async with self.client() as client:
138
- return await self._wa(client).workflow_scheduled_list(
139
- tenant=self.client_config.tenant_id,
140
- offset=offset,
141
- limit=limit,
142
- order_by_field=order_by_field,
143
- order_by_direction=order_by_direction,
144
- workflow_id=workflow_id,
145
- additional_metadata=maybe_additional_metadata_to_kv(
146
- additional_metadata
147
- ),
148
- parent_workflow_run_id=parent_workflow_run_id,
149
- statuses=statuses,
150
- )
137
+ return await asyncio.to_thread(
138
+ self.list,
139
+ offset=offset,
140
+ limit=limit,
141
+ workflow_id=workflow_id,
142
+ additional_metadata=additional_metadata,
143
+ order_by_field=order_by_field,
144
+ order_by_direction=order_by_direction,
145
+ parent_workflow_run_id=parent_workflow_run_id,
146
+ statuses=statuses,
147
+ )
151
148
 
152
149
  def list(
153
150
  self,
@@ -176,19 +173,22 @@ class ScheduledClient(BaseRestClient):
176
173
  Returns:
177
174
  List[ScheduledWorkflows]: A list of scheduled workflows matching the criteria.
178
175
  """
179
- return run_async_from_sync(
180
- self.aio_list,
181
- offset=offset,
182
- limit=limit,
183
- workflow_id=workflow_id,
184
- additional_metadata=additional_metadata,
185
- order_by_field=order_by_field,
186
- order_by_direction=order_by_direction,
187
- parent_workflow_run_id=parent_workflow_run_id,
188
- statuses=statuses,
189
- )
176
+ with self.client() as client:
177
+ return self._wa(client).workflow_scheduled_list(
178
+ tenant=self.client_config.tenant_id,
179
+ offset=offset,
180
+ limit=limit,
181
+ order_by_field=order_by_field,
182
+ order_by_direction=order_by_direction,
183
+ workflow_id=workflow_id,
184
+ additional_metadata=maybe_additional_metadata_to_kv(
185
+ additional_metadata
186
+ ),
187
+ parent_workflow_run_id=parent_workflow_run_id,
188
+ statuses=statuses,
189
+ )
190
190
 
191
- async def aio_get(self, scheduled_id: str) -> ScheduledWorkflows:
191
+ def get(self, scheduled_id: str) -> ScheduledWorkflows:
192
192
  """
193
193
  Retrieves a specific scheduled workflow by scheduled run trigger ID.
194
194
 
@@ -199,13 +199,13 @@ class ScheduledClient(BaseRestClient):
199
199
  ScheduledWorkflows: The requested scheduled workflow instance.
200
200
  """
201
201
 
202
- async with self.client() as client:
203
- return await self._wa(client).workflow_scheduled_get(
202
+ with self.client() as client:
203
+ return self._wa(client).workflow_scheduled_get(
204
204
  tenant=self.client_config.tenant_id,
205
205
  scheduled_workflow_run=scheduled_id,
206
206
  )
207
207
 
208
- def get(self, scheduled_id: str) -> ScheduledWorkflows:
208
+ async def aio_get(self, scheduled_id: str) -> ScheduledWorkflows:
209
209
  """
210
210
  Retrieves a specific scheduled workflow by scheduled run trigger ID.
211
211
 
@@ -215,4 +215,4 @@ class ScheduledClient(BaseRestClient):
215
215
  Returns:
216
216
  ScheduledWorkflows: The requested scheduled workflow instance.
217
217
  """
218
- return run_async_from_sync(self.aio_get, scheduled_id)
218
+ return await asyncio.to_thread(self.get, scheduled_id)
@@ -1,42 +1,43 @@
1
+ import asyncio
2
+
1
3
  from hatchet_sdk.clients.rest.api.worker_api import WorkerApi
2
4
  from hatchet_sdk.clients.rest.api_client import ApiClient
3
5
  from hatchet_sdk.clients.rest.models.update_worker_request import UpdateWorkerRequest
4
6
  from hatchet_sdk.clients.rest.models.worker import Worker
5
7
  from hatchet_sdk.clients.rest.models.worker_list import WorkerList
6
8
  from hatchet_sdk.clients.v1.api_client import BaseRestClient
7
- from hatchet_sdk.utils.aio import run_async_from_sync
8
9
 
9
10
 
10
11
  class WorkersClient(BaseRestClient):
11
12
  def _wa(self, client: ApiClient) -> WorkerApi:
12
13
  return WorkerApi(client)
13
14
 
14
- async def aio_get(self, worker_id: str) -> Worker:
15
- async with self.client() as client:
16
- return await self._wa(client).worker_get(worker_id)
17
-
18
15
  def get(self, worker_id: str) -> Worker:
19
- return run_async_from_sync(self.aio_get, worker_id)
16
+ with self.client() as client:
17
+ return self._wa(client).worker_get(worker_id)
20
18
 
21
- async def aio_list(
19
+ async def aio_get(self, worker_id: str) -> Worker:
20
+ return await asyncio.to_thread(self.get, worker_id)
21
+
22
+ def list(
22
23
  self,
23
24
  ) -> WorkerList:
24
- async with self.client() as client:
25
- return await self._wa(client).worker_list(
25
+ with self.client() as client:
26
+ return self._wa(client).worker_list(
26
27
  tenant=self.client_config.tenant_id,
27
28
  )
28
29
 
29
- def list(
30
+ async def aio_list(
30
31
  self,
31
32
  ) -> WorkerList:
32
- return run_async_from_sync(self.aio_list)
33
+ return await asyncio.to_thread(self.list)
33
34
 
34
- async def aio_update(self, worker_id: str, opts: UpdateWorkerRequest) -> Worker:
35
- async with self.client() as client:
36
- return await self._wa(client).worker_update(
35
+ def update(self, worker_id: str, opts: UpdateWorkerRequest) -> Worker:
36
+ with self.client() as client:
37
+ return self._wa(client).worker_update(
37
38
  worker=worker_id,
38
39
  update_worker_request=opts,
39
40
  )
40
41
 
41
- def update(self, worker_id: str, opts: UpdateWorkerRequest) -> Worker:
42
- return run_async_from_sync(self.aio_update, worker_id, opts)
42
+ async def aio_update(self, worker_id: str, opts: UpdateWorkerRequest) -> Worker:
43
+ return await asyncio.to_thread(self.update, worker_id, opts)
@@ -1,3 +1,5 @@
1
+ import asyncio
2
+
1
3
  from hatchet_sdk.clients.rest.api.workflow_api import WorkflowApi
2
4
  from hatchet_sdk.clients.rest.api.workflow_run_api import WorkflowRunApi
3
5
  from hatchet_sdk.clients.rest.api_client import ApiClient
@@ -5,7 +7,6 @@ from hatchet_sdk.clients.rest.models.workflow import Workflow
5
7
  from hatchet_sdk.clients.rest.models.workflow_list import WorkflowList
6
8
  from hatchet_sdk.clients.rest.models.workflow_version import WorkflowVersion
7
9
  from hatchet_sdk.clients.v1.api_client import BaseRestClient
8
- from hatchet_sdk.utils.aio import run_async_from_sync
9
10
 
10
11
 
11
12
  class WorkflowsClient(BaseRestClient):
@@ -16,41 +17,41 @@ class WorkflowsClient(BaseRestClient):
16
17
  return WorkflowApi(client)
17
18
 
18
19
  async def aio_get(self, workflow_id: str) -> Workflow:
19
- async with self.client() as client:
20
- return await self._wa(client).workflow_get(workflow_id)
20
+ return await asyncio.to_thread(self.get, workflow_id)
21
21
 
22
22
  def get(self, workflow_id: str) -> Workflow:
23
- return run_async_from_sync(self.aio_get, workflow_id)
23
+ with self.client() as client:
24
+ return self._wa(client).workflow_get(workflow_id)
24
25
 
25
- async def aio_list(
26
+ def list(
26
27
  self,
27
28
  workflow_name: str | None = None,
28
29
  limit: int | None = None,
29
30
  offset: int | None = None,
30
31
  ) -> WorkflowList:
31
- async with self.client() as client:
32
- return await self._wa(client).workflow_list(
32
+ with self.client() as client:
33
+ return self._wa(client).workflow_list(
33
34
  tenant=self.client_config.tenant_id,
34
35
  limit=limit,
35
36
  offset=offset,
36
37
  name=workflow_name,
37
38
  )
38
39
 
39
- def list(
40
+ async def aio_list(
40
41
  self,
41
42
  workflow_name: str | None = None,
42
43
  limit: int | None = None,
43
44
  offset: int | None = None,
44
45
  ) -> WorkflowList:
45
- return run_async_from_sync(self.aio_list, workflow_name, limit, offset)
46
+ return await asyncio.to_thread(self.list, workflow_name, limit, offset)
46
47
 
47
- async def aio_get_version(
48
+ def get_version(
48
49
  self, workflow_id: str, version: str | None = None
49
50
  ) -> WorkflowVersion:
50
- async with self.client() as client:
51
- return await self._wa(client).workflow_version_get(workflow_id, version)
51
+ with self.client() as client:
52
+ return self._wa(client).workflow_version_get(workflow_id, version)
52
53
 
53
- def get_version(
54
+ async def aio_get_version(
54
55
  self, workflow_id: str, version: str | None = None
55
56
  ) -> WorkflowVersion:
56
- return run_async_from_sync(self.aio_get_version, workflow_id, version)
57
+ return await asyncio.to_thread(self.get_version, workflow_id, version)
hatchet_sdk/hatchet.py CHANGED
@@ -6,7 +6,7 @@ from hatchet_sdk import Context, DurableContext
6
6
  from hatchet_sdk.client import Client
7
7
  from hatchet_sdk.clients.dispatcher.dispatcher import DispatcherClient
8
8
  from hatchet_sdk.clients.events import EventClient
9
- from hatchet_sdk.clients.run_event_listener import RunEventListenerClient
9
+ from hatchet_sdk.clients.listeners.run_event_listener import RunEventListenerClient
10
10
  from hatchet_sdk.config import ClientConfig
11
11
  from hatchet_sdk.features.cron import CronClient
12
12
  from hatchet_sdk.features.logs import LogsClient
@@ -11,7 +11,6 @@ from hatchet_sdk.contracts.workflows_pb2 import WorkflowVersion
11
11
  from hatchet_sdk.runnables.task import Task
12
12
  from hatchet_sdk.runnables.types import EmptyModel, R, TWorkflowInput
13
13
  from hatchet_sdk.runnables.workflow import BaseWorkflow, Workflow
14
- from hatchet_sdk.utils.aio import run_async_from_sync
15
14
  from hatchet_sdk.utils.typing import JSONSerializableMapping, is_basemodel_subclass
16
15
  from hatchet_sdk.workflow_run import WorkflowRunRef
17
16
 
@@ -31,11 +30,15 @@ class TaskRunRef(Generic[TWorkflowInput, R]):
31
30
  return self.workflow_run_id
32
31
 
33
32
  async def aio_result(self) -> R:
34
- result = await self._wrr.workflow_listener.aio_result(self._wrr.workflow_run_id)
33
+ result = await self._wrr.workflow_run_listener.aio_result(
34
+ self._wrr.workflow_run_id
35
+ )
35
36
  return self._s._extract_result(result)
36
37
 
37
38
  def result(self) -> R:
38
- return run_async_from_sync(self.aio_result)
39
+ result = self._wrr.result()
40
+
41
+ return self._s._extract_result(result)
39
42
 
40
43
 
41
44
  class Standalone(BaseWorkflow[TWorkflowInput], Generic[TWorkflowInput, R]):
@@ -129,7 +132,7 @@ class Standalone(BaseWorkflow[TWorkflowInput], Generic[TWorkflowInput, R]):
129
132
  def schedule(
130
133
  self,
131
134
  run_at: datetime,
132
- input: TWorkflowInput | None = None,
135
+ input: TWorkflowInput = cast(TWorkflowInput, EmptyModel()),
133
136
  options: ScheduleTriggerWorkflowOptions = ScheduleTriggerWorkflowOptions(),
134
137
  ) -> WorkflowVersion:
135
138
  return self._workflow.schedule(
@@ -141,7 +144,7 @@ class Standalone(BaseWorkflow[TWorkflowInput], Generic[TWorkflowInput, R]):
141
144
  async def aio_schedule(
142
145
  self,
143
146
  run_at: datetime,
144
- input: TWorkflowInput,
147
+ input: TWorkflowInput = cast(TWorkflowInput, EmptyModel()),
145
148
  options: ScheduleTriggerWorkflowOptions = ScheduleTriggerWorkflowOptions(),
146
149
  ) -> WorkflowVersion:
147
150
  return await self._workflow.aio_schedule(
@@ -154,8 +157,8 @@ class Standalone(BaseWorkflow[TWorkflowInput], Generic[TWorkflowInput, R]):
154
157
  self,
155
158
  cron_name: str,
156
159
  expression: str,
157
- input: TWorkflowInput,
158
- additional_metadata: JSONSerializableMapping,
160
+ input: TWorkflowInput = cast(TWorkflowInput, EmptyModel()),
161
+ additional_metadata: JSONSerializableMapping = {},
159
162
  ) -> CronWorkflows:
160
163
  return self._workflow.create_cron(
161
164
  cron_name=cron_name,
@@ -168,8 +171,8 @@ class Standalone(BaseWorkflow[TWorkflowInput], Generic[TWorkflowInput, R]):
168
171
  self,
169
172
  cron_name: str,
170
173
  expression: str,
171
- input: TWorkflowInput,
172
- additional_metadata: JSONSerializableMapping,
174
+ input: TWorkflowInput = cast(TWorkflowInput, EmptyModel()),
175
+ additional_metadata: JSONSerializableMapping = {},
173
176
  ) -> CronWorkflows:
174
177
  return await self._workflow.aio_create_cron(
175
178
  cron_name=cron_name,
@@ -10,7 +10,9 @@ from typing import (
10
10
  )
11
11
 
12
12
  from hatchet_sdk.context.context import Context, DurableContext
13
+ from hatchet_sdk.contracts.v1.shared.condition_pb2 import TaskConditions
13
14
  from hatchet_sdk.contracts.v1.workflows_pb2 import (
15
+ CreateTaskOpts,
14
16
  CreateTaskRateLimit,
15
17
  DesiredWorkerLabels,
16
18
  )
@@ -25,8 +27,15 @@ from hatchet_sdk.runnables.types import (
25
27
  is_durable_sync_fn,
26
28
  is_sync_fn,
27
29
  )
28
- from hatchet_sdk.utils.timedelta_to_expression import Duration
29
- from hatchet_sdk.waits import Condition, OrGroup
30
+ from hatchet_sdk.utils.timedelta_to_expression import Duration, timedelta_to_expr
31
+ from hatchet_sdk.waits import (
32
+ Action,
33
+ Condition,
34
+ OrGroup,
35
+ ParentCondition,
36
+ SleepCondition,
37
+ UserEventCondition,
38
+ )
30
39
 
31
40
  if TYPE_CHECKING:
32
41
  from hatchet_sdk.runnables.workflow import Workflow
@@ -142,3 +151,58 @@ class Task(Generic[TWorkflowInput, R]):
142
151
  return await self.fn(workflow_input, cast(Context, ctx)) # type: ignore
143
152
 
144
153
  raise TypeError(f"{self.name} is not an async function. Use `call` instead.")
154
+
155
+ def to_proto(self, service_name: str) -> CreateTaskOpts:
156
+ return CreateTaskOpts(
157
+ readable_id=self.name,
158
+ action=service_name + ":" + self.name,
159
+ timeout=timedelta_to_expr(self.execution_timeout),
160
+ inputs="{}",
161
+ parents=[p.name for p in self.parents],
162
+ retries=self.retries,
163
+ rate_limits=self.rate_limits,
164
+ worker_labels=self.desired_worker_labels,
165
+ backoff_factor=self.backoff_factor,
166
+ backoff_max_seconds=self.backoff_max_seconds,
167
+ concurrency=[t.to_proto() for t in self.concurrency],
168
+ conditions=self._conditions_to_proto(),
169
+ schedule_timeout=timedelta_to_expr(self.schedule_timeout),
170
+ )
171
+
172
+ def _assign_action(self, condition: Condition, action: Action) -> Condition:
173
+ condition.base.action = action
174
+
175
+ return condition
176
+
177
+ def _conditions_to_proto(self) -> TaskConditions:
178
+ wait_for_conditions = [
179
+ self._assign_action(w, Action.QUEUE) for w in self.wait_for
180
+ ]
181
+
182
+ cancel_if_conditions = [
183
+ self._assign_action(c, Action.CANCEL) for c in self.cancel_if
184
+ ]
185
+ skip_if_conditions = [self._assign_action(s, Action.SKIP) for s in self.skip_if]
186
+
187
+ conditions = wait_for_conditions + cancel_if_conditions + skip_if_conditions
188
+
189
+ if len({c.base.readable_data_key for c in conditions}) != len(
190
+ [c.base.readable_data_key for c in conditions]
191
+ ):
192
+ raise ValueError("Conditions must have unique readable data keys.")
193
+
194
+ user_events = [
195
+ c.to_proto() for c in conditions if isinstance(c, UserEventCondition)
196
+ ]
197
+ parent_overrides = [
198
+ c.to_proto() for c in conditions if isinstance(c, ParentCondition)
199
+ ]
200
+ sleep_conditions = [
201
+ c.to_proto() for c in conditions if isinstance(c, SleepCondition)
202
+ ]
203
+
204
+ return TaskConditions(
205
+ parent_override_conditions=parent_overrides,
206
+ sleep_conditions=sleep_conditions,
207
+ user_event_conditions=user_events,
208
+ )
@@ -6,6 +6,7 @@ from typing import Any, Awaitable, Callable, ParamSpec, Type, TypeGuard, TypeVar
6
6
  from pydantic import BaseModel, ConfigDict, Field, StrictInt, model_validator
7
7
 
8
8
  from hatchet_sdk.context.context import Context, DurableContext
9
+ from hatchet_sdk.contracts.v1.workflows_pb2 import Concurrency
9
10
  from hatchet_sdk.utils.timedelta_to_expression import Duration
10
11
  from hatchet_sdk.utils.typing import JSONSerializableMapping
11
12
 
@@ -52,6 +53,13 @@ class ConcurrencyExpression(BaseModel):
52
53
  max_runs: int
53
54
  limit_strategy: ConcurrencyLimitStrategy
54
55
 
56
+ def to_proto(self) -> Concurrency:
57
+ return Concurrency(
58
+ expression=self.expression,
59
+ max_runs=self.max_runs,
60
+ limit_strategy=self.limit_strategy,
61
+ )
62
+
55
63
 
56
64
  TWorkflowInput = TypeVar("TWorkflowInput", bound=BaseModel)
57
65