hatchet-sdk 1.14.2__py3-none-any.whl → 1.14.4__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.

hatchet_sdk/__init__.py CHANGED
@@ -11,9 +11,9 @@ from hatchet_sdk.clients.listeners.run_event_listener import (
11
11
  StepRunEventType,
12
12
  WorkflowRunEventType,
13
13
  )
14
- from hatchet_sdk.clients.rest.models.accept_invite_request import AcceptInviteRequest
15
14
 
16
15
  # import models into sdk package
16
+ from hatchet_sdk.clients.rest.models.accept_invite_request import AcceptInviteRequest
17
17
  from hatchet_sdk.clients.rest.models.api_error import APIError
18
18
  from hatchet_sdk.clients.rest.models.api_errors import APIErrors
19
19
  from hatchet_sdk.clients.rest.models.api_meta import APIMeta
@@ -166,6 +166,7 @@ from hatchet_sdk.runnables.types import (
166
166
  )
167
167
  from hatchet_sdk.runnables.workflow import TaskRunRef
168
168
  from hatchet_sdk.utils.opentelemetry import OTelAttribute
169
+ from hatchet_sdk.utils.serde import remove_null_unicode_character
169
170
  from hatchet_sdk.worker.worker import Worker, WorkerStartOptions, WorkerStatus
170
171
  from hatchet_sdk.workflow_run import WorkflowRunRef
171
172
 
@@ -290,5 +291,6 @@ __all__ = [
290
291
  "WorkflowVersionDefinition",
291
292
  "WorkflowVersionMeta",
292
293
  "or_",
294
+ "remove_null_unicode_character",
293
295
  "workflow",
294
296
  ]
@@ -108,3 +108,28 @@ class WorkflowsClient(BaseRestClient):
108
108
  :return: The workflow version.
109
109
  """
110
110
  return await asyncio.to_thread(self.get_version, workflow_id, version)
111
+
112
+ def delete(self, workflow_id: str) -> None:
113
+ """
114
+ Permanently delete a workflow.
115
+
116
+ **DANGEROUS: This will delete a workflow and all of its data**
117
+
118
+ :param workflow_id: The ID of the workflow to delete.
119
+ :return: None
120
+ """
121
+
122
+ with self.client() as client:
123
+ return self._wa(client).workflow_delete(workflow_id)
124
+
125
+ async def aio_delete(self, workflow_id: str) -> None:
126
+ """
127
+ Permanently delete a workflow.
128
+
129
+ **DANGEROUS: This will delete a workflow and all of its data**
130
+
131
+ :param workflow_id: The ID of the workflow to delete.
132
+ :return: None
133
+ """
134
+
135
+ return await asyncio.to_thread(self.delete, workflow_id)
@@ -509,6 +509,22 @@ class BaseWorkflow(Generic[TWorkflowInput]):
509
509
  priority=priority,
510
510
  )
511
511
 
512
+ def delete(self) -> None:
513
+ """
514
+ Permanently delete the workflow.
515
+
516
+ **DANGEROUS: This will delete a workflow and all of its data**
517
+ """
518
+ self.client.workflows.delete(self.id)
519
+
520
+ async def aio_delete(self) -> None:
521
+ """
522
+ Permanently delete the workflow.
523
+
524
+ **DANGEROUS: This will delete a workflow and all of its data**
525
+ """
526
+ await self.client.workflows.aio_delete(self.id)
527
+
512
528
 
513
529
  class Workflow(BaseWorkflow[TWorkflowInput]):
514
530
  """
@@ -0,0 +1,52 @@
1
+ from typing import Any, TypeVar, cast, overload
2
+
3
+ T = TypeVar("T")
4
+ K = TypeVar("K")
5
+
6
+
7
+ @overload
8
+ def remove_null_unicode_character(data: str) -> str: ...
9
+
10
+
11
+ @overload
12
+ def remove_null_unicode_character(data: dict[K, T]) -> dict[K, T]: ...
13
+
14
+
15
+ @overload
16
+ def remove_null_unicode_character(data: list[T]) -> list[T]: ...
17
+
18
+
19
+ @overload
20
+ def remove_null_unicode_character(data: tuple[T, ...]) -> tuple[T, ...]: ...
21
+
22
+
23
+ def remove_null_unicode_character(
24
+ data: str | dict[K, T] | list[T] | tuple[T, ...],
25
+ ) -> str | dict[K, T] | list[T] | tuple[T, ...]:
26
+ """
27
+ Recursively traverse a dictionary (a task's output) and remove the unicode escape sequence \\u0000 which will cause unexpected behavior in Hatchet.
28
+
29
+ Needed as Hatchet does not support \\u0000 in task outputs
30
+
31
+ :param data: The task output (a JSON-serializable dictionary or mapping)
32
+ :return: The same dictionary with all \\u0000 characters removed from strings, and nested dictionaries/lists processed recursively.
33
+ :raises TypeError: If the input is not a string, dictionary, list, or tuple.
34
+ """
35
+ if isinstance(data, str):
36
+ return data.replace("\u0000", "")
37
+
38
+ if isinstance(data, dict):
39
+ return {
40
+ key: remove_null_unicode_character(cast(Any, value))
41
+ for key, value in data.items()
42
+ }
43
+
44
+ if isinstance(data, list):
45
+ return [remove_null_unicode_character(cast(Any, item)) for item in data]
46
+
47
+ if isinstance(data, tuple):
48
+ return tuple(remove_null_unicode_character(cast(Any, item)) for item in data)
49
+
50
+ raise TypeError(
51
+ f"Unsupported type {type(data)}. Expected str, dict, list, or tuple."
52
+ )
@@ -4,9 +4,9 @@ import functools
4
4
  import json
5
5
  from collections.abc import Callable
6
6
  from concurrent.futures import ThreadPoolExecutor
7
- from contextlib import suppress
8
7
  from enum import Enum
9
8
  from multiprocessing import Queue
9
+ from textwrap import dedent
10
10
  from threading import Thread, current_thread
11
11
  from typing import Any, Literal, cast, overload
12
12
 
@@ -49,6 +49,7 @@ from hatchet_sdk.runnables.contextvars import (
49
49
  )
50
50
  from hatchet_sdk.runnables.task import Task
51
51
  from hatchet_sdk.runnables.types import R, TWorkflowInput
52
+ from hatchet_sdk.utils.serde import remove_null_unicode_character
52
53
  from hatchet_sdk.worker.action_listener_process import ActionEvent
53
54
  from hatchet_sdk.worker.runner.utils.capture_logs import (
54
55
  AsyncLogSender,
@@ -410,7 +411,7 @@ class Runner:
410
411
  )
411
412
 
412
413
  ## IMPORTANT: Keep this method's signature in sync with the wrapper in the OTel instrumentor
413
- async def handle_start_step_run(self, action: Action) -> None:
414
+ async def handle_start_step_run(self, action: Action) -> Exception | None:
414
415
  action_name = action.action_id
415
416
 
416
417
  # Find the corresponding action function from the registry
@@ -444,8 +445,11 @@ class Runner:
444
445
 
445
446
  ## FIXME: Handle cancelled exceptions and other special exceptions
446
447
  ## that we don't want to suppress here
447
- with suppress(Exception):
448
+ try:
448
449
  await task
450
+ except Exception as e:
451
+ ## Used for the OTel instrumentor to capture exceptions
452
+ return e
449
453
 
450
454
  ## Once the step run completes, we need to remove the workflow spawn index
451
455
  ## so we don't leak memory
@@ -453,6 +457,8 @@ class Runner:
453
457
  async with spawn_index_lock:
454
458
  workflow_spawn_indices.pop(action.key)
455
459
 
460
+ return None
461
+
456
462
  ## IMPORTANT: Keep this method's signature in sync with the wrapper in the OTel instrumentor
457
463
  async def handle_start_group_key_run(self, action: Action) -> Exception | None:
458
464
  action_name = action.action_id
@@ -557,14 +563,30 @@ class Runner:
557
563
  f"Tasks must return either a dictionary or a Pydantic BaseModel which can be serialized to a JSON object. Got object of type {type(output)} instead."
558
564
  )
559
565
 
560
- if output is not None:
561
- try:
562
- return json.dumps(output, default=str)
563
- except Exception as e:
564
- logger.error(f"Could not serialize output: {e}")
565
- return str(output)
566
+ if output is None:
567
+ return ""
568
+
569
+ try:
570
+ serialized_output = json.dumps(output, default=str)
571
+ except Exception as e:
572
+ logger.error(f"Could not serialize output: {e}")
573
+ serialized_output = str(output)
574
+
575
+ if "\\u0000" in serialized_output:
576
+ raise IllegalTaskOutputError(
577
+ dedent(
578
+ f"""
579
+ Task outputs cannot contain the unicode null character \\u0000
580
+
581
+ Please see this Discord thread: https://discord.com/channels/1088927970518909068/1384324576166678710/1386714014565928992
582
+ Relevant Postgres documentation: https://www.postgresql.org/docs/current/datatype-json.html
583
+
584
+ Use `hatchet_sdk.{remove_null_unicode_character.__name__}` to sanitize your output if you'd like to remove the character.
585
+ """
586
+ )
587
+ )
566
588
 
567
- return ""
589
+ return serialized_output
568
590
 
569
591
  async def wait_for_tasks(self) -> None:
570
592
  running = len(self.tasks.keys())
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: hatchet-sdk
3
- Version: 1.14.2
3
+ Version: 1.14.4
4
4
  Summary:
5
5
  License: MIT
6
6
  Author: Alexander Belanger
@@ -1,4 +1,4 @@
1
- hatchet_sdk/__init__.py,sha256=3iVKyZ4OnGxZWU0YtXQG9imlljPNBdPARqqCm6Ft03o,10640
1
+ hatchet_sdk/__init__.py,sha256=LdT8xJ7-95gwksRZuCzuKDM5bfLx8uW8gXGPL7VMqwc,10743
2
2
  hatchet_sdk/client.py,sha256=OXb2hOJ5p7pY5QMlM4cydb4aGyf6bDdbyWQjPMVCe64,2413
3
3
  hatchet_sdk/clients/admin.py,sha256=t8GXhjMiFp9iL0ofISNxSOKlfwaOTX2iQbZfz1G0pHU,16936
4
4
  hatchet_sdk/clients/dispatcher/action_listener.py,sha256=tFknXH9iSP0OFYYVcKeDZVrcDNIz00ZQVTxSbHpbKhI,13863
@@ -264,7 +264,7 @@ hatchet_sdk/features/runs.py,sha256=8geS5l1CU3GCLudFORmCvXyjVVcgNKsNAPV9mLcI8sU,
264
264
  hatchet_sdk/features/scheduled.py,sha256=t7YA9CoJrzBhH82ChTSFWaTF_dyoC9i1O_wf9ywsphc,8939
265
265
  hatchet_sdk/features/tenant.py,sha256=xkhh5mRKCWbunk_S1iBmGR-DYR-F4mjxk8jLyYUyzNE,886
266
266
  hatchet_sdk/features/workers.py,sha256=DVdno28RmtlfhMJUkaPcOMHNKXCPV0RFrXtLqV6zWyE,2600
267
- hatchet_sdk/features/workflows.py,sha256=a_0UwX_Y-6DX8TcQ7yuiugWHvKzQmMqafKanq4HEiSg,4052
267
+ hatchet_sdk/features/workflows.py,sha256=WTt58imAFRrEEB3M5hEEIBwNtrzdWbITFpgtsIqJNSM,4770
268
268
  hatchet_sdk/hatchet.py,sha256=rOuE7YPqu4setE_zGbmgvb2WN-q8HNXTDFYcp9N0Wj8,25759
269
269
  hatchet_sdk/labels.py,sha256=nATgxWE3lFxRTnfISEpoIRLGbMfAZsHF4lZTuG4Mfic,182
270
270
  hatchet_sdk/logger.py,sha256=5uOr52T4mImSQm1QvWT8HvZFK5WfPNh3Y1cBQZRFgUQ,333
@@ -276,13 +276,14 @@ hatchet_sdk/runnables/action.py,sha256=zrVHpyzIQ9XZgWwY69b_6uhZd53An4trRoLd9b3os
276
276
  hatchet_sdk/runnables/contextvars.py,sha256=T2LWiXhcSyQYJY_-pfqMjDNjf6PdtDwyXyCZ6zIyWK0,929
277
277
  hatchet_sdk/runnables/task.py,sha256=VEYabAl38U9L_igSDgZSzUL7-c-sX6YFRP0wsqGTadU,6714
278
278
  hatchet_sdk/runnables/types.py,sha256=QFayOJ_Oi8tOYI6Sjl9bwjftM96QZh9XIlfFnSNgEXI,4359
279
- hatchet_sdk/runnables/workflow.py,sha256=SxxNhv1SAMh4Rw68_fyQJh3Su-e_zscPmILo3ghzzaU,49225
279
+ hatchet_sdk/runnables/workflow.py,sha256=9Vq4T0goR4dG_bzarEog9ui-8mef9YmvPICk0CRHf3I,49673
280
280
  hatchet_sdk/token.py,sha256=KjIiInwG5Kqd_FO4BSW1x_5Uc7PFbnzIVJqr50-ZldE,779
281
281
  hatchet_sdk/utils/aio.py,sha256=cu1rD_UZkShtfzi7iXMYwBBaCRdxJQTdUC0_mf8nU2E,499
282
282
  hatchet_sdk/utils/backoff.py,sha256=6B5Rb5nLKw_TqqgpJMYjIBV1PTTtbOMRZCveisVhg_I,353
283
283
  hatchet_sdk/utils/datetimes.py,sha256=vIZNEX8tt-bknaIuTmoLEmKVt18dBjClH3urYtCJAys,775
284
284
  hatchet_sdk/utils/opentelemetry.py,sha256=64TVwCLrUzEmcL2BUNPV_QubfiR5jajOZtVeGYLnEEA,1226
285
285
  hatchet_sdk/utils/proto_enums.py,sha256=v2gp_ZmIhPxURVXwz5lscllXwZXDl5XGXeL6gezw3o0,1241
286
+ hatchet_sdk/utils/serde.py,sha256=d2iypdK2UQCPA19NgYa0Tr7CTbk25KPbaCMqcqN3CYk,1645
286
287
  hatchet_sdk/utils/timedelta_to_expression.py,sha256=YujnBnGn7lxtkUdKIeqmOiN_ZCGBpRPjCCSzcD3jxzA,644
287
288
  hatchet_sdk/utils/typing.py,sha256=FgYnZyJSoRjNVFodxlI9gn0X8ST1KFed7xfUynIxa2U,978
288
289
  hatchet_sdk/v0/__init__.py,sha256=r3Q7l2RsLgdIkK2jjiz7-JJpD1T_Zy--Oa9MN5n_yEs,9654
@@ -509,11 +510,11 @@ hatchet_sdk/v0/workflow_run.py,sha256=jsEZprXshrSV7i_TtL5uoCL03D18zQ3NeJCq7mp97D
509
510
  hatchet_sdk/worker/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
510
511
  hatchet_sdk/worker/action_listener_process.py,sha256=Xzzn1dDFJrqnC9HBsh3fYI8lfpOD4Ecze47qmm_XUWE,12923
511
512
  hatchet_sdk/worker/runner/run_loop_manager.py,sha256=GeILClNXaDbsjXCQb0bBdgeyAwZGem2JdaH0t6wz__I,4053
512
- hatchet_sdk/worker/runner/runner.py,sha256=rTD0OrPMyFY0k4DDcKpuz67K1YpHdZUZSd1o2L_QlYs,20781
513
+ hatchet_sdk/worker/runner/runner.py,sha256=Btz7wd0DQ-5aPEZLN3T5X5__8DjuxN6H4yQEVX0eZiI,21678
513
514
  hatchet_sdk/worker/runner/utils/capture_logs.py,sha256=DKw6boqVsSCM1XvBWYuc833MZxCdSpMxg3l4aAqKPyw,3465
514
515
  hatchet_sdk/worker/worker.py,sha256=nDuRo_LishRuOCTnDonc7G7qeOoW93nRHGd-fQOE_bs,16541
515
516
  hatchet_sdk/workflow_run.py,sha256=KcylcqRwKADtnzOTjoiVr1vdr7qTZFtDeD5aRS6A4Y8,2823
516
- hatchet_sdk-1.14.2.dist-info/METADATA,sha256=Z5hZyudaXspH-TNuGTWoEtVcGtrV5UGeImzNo3ePanI,3636
517
- hatchet_sdk-1.14.2.dist-info/WHEEL,sha256=FMvqSimYX_P7y0a7UY-_Mc83r5zkBZsCYPm7Lr0Bsq4,88
518
- hatchet_sdk-1.14.2.dist-info/entry_points.txt,sha256=Un_76pcLse-ZGBlwebhQpnTPyQrripeHW8J7qmEpGOk,1400
519
- hatchet_sdk-1.14.2.dist-info/RECORD,,
517
+ hatchet_sdk-1.14.4.dist-info/METADATA,sha256=RnI_R_0aYYdHdr5BJjxCRAlkdDyhHZjG5PU_eYx8xBs,3636
518
+ hatchet_sdk-1.14.4.dist-info/WHEEL,sha256=FMvqSimYX_P7y0a7UY-_Mc83r5zkBZsCYPm7Lr0Bsq4,88
519
+ hatchet_sdk-1.14.4.dist-info/entry_points.txt,sha256=Un_76pcLse-ZGBlwebhQpnTPyQrripeHW8J7qmEpGOk,1400
520
+ hatchet_sdk-1.14.4.dist-info/RECORD,,