prefect-client 3.1.14__py3-none-any.whl → 3.2.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.
Files changed (98) hide show
  1. prefect/__main__.py +4 -0
  2. prefect/_experimental/lineage.py +40 -22
  3. prefect/_experimental/sla/objects.py +29 -1
  4. prefect/_internal/compatibility/deprecated.py +4 -4
  5. prefect/_internal/compatibility/migration.py +1 -1
  6. prefect/_internal/concurrency/calls.py +1 -2
  7. prefect/_internal/concurrency/cancellation.py +2 -4
  8. prefect/_internal/concurrency/services.py +1 -1
  9. prefect/_internal/concurrency/threads.py +3 -3
  10. prefect/_internal/schemas/bases.py +3 -11
  11. prefect/_internal/schemas/validators.py +36 -60
  12. prefect/_result_records.py +235 -0
  13. prefect/_version.py +3 -3
  14. prefect/agent.py +1 -0
  15. prefect/artifacts.py +408 -105
  16. prefect/automations.py +4 -8
  17. prefect/blocks/core.py +1 -1
  18. prefect/blocks/notifications.py +13 -8
  19. prefect/cache_policies.py +2 -0
  20. prefect/client/base.py +7 -8
  21. prefect/client/collections.py +3 -6
  22. prefect/client/orchestration/__init__.py +15 -263
  23. prefect/client/orchestration/_deployments/client.py +14 -6
  24. prefect/client/orchestration/_flow_runs/client.py +10 -6
  25. prefect/client/orchestration/_work_pools/__init__.py +0 -0
  26. prefect/client/orchestration/_work_pools/client.py +598 -0
  27. prefect/client/orchestration/base.py +9 -2
  28. prefect/client/schemas/actions.py +77 -3
  29. prefect/client/schemas/objects.py +22 -50
  30. prefect/client/schemas/schedules.py +11 -22
  31. prefect/client/types/flexible_schedule_list.py +2 -1
  32. prefect/context.py +2 -3
  33. prefect/deployments/base.py +13 -16
  34. prefect/deployments/flow_runs.py +1 -1
  35. prefect/deployments/runner.py +236 -47
  36. prefect/deployments/schedules.py +7 -1
  37. prefect/engine.py +4 -9
  38. prefect/events/clients.py +39 -0
  39. prefect/events/schemas/automations.py +4 -2
  40. prefect/events/utilities.py +15 -13
  41. prefect/exceptions.py +1 -1
  42. prefect/flow_engine.py +119 -0
  43. prefect/flow_runs.py +4 -8
  44. prefect/flows.py +282 -31
  45. prefect/infrastructure/__init__.py +1 -0
  46. prefect/infrastructure/base.py +1 -0
  47. prefect/infrastructure/provisioners/__init__.py +3 -6
  48. prefect/infrastructure/provisioners/coiled.py +3 -3
  49. prefect/infrastructure/provisioners/container_instance.py +1 -0
  50. prefect/infrastructure/provisioners/ecs.py +6 -6
  51. prefect/infrastructure/provisioners/modal.py +3 -3
  52. prefect/input/run_input.py +5 -7
  53. prefect/locking/filesystem.py +4 -3
  54. prefect/main.py +1 -1
  55. prefect/results.py +42 -249
  56. prefect/runner/runner.py +9 -4
  57. prefect/runner/server.py +5 -5
  58. prefect/runner/storage.py +12 -10
  59. prefect/runner/submit.py +2 -4
  60. prefect/runtime/task_run.py +37 -9
  61. prefect/schedules.py +231 -0
  62. prefect/serializers.py +5 -5
  63. prefect/settings/__init__.py +2 -1
  64. prefect/settings/base.py +3 -3
  65. prefect/settings/models/root.py +4 -0
  66. prefect/settings/models/server/services.py +50 -9
  67. prefect/settings/sources.py +4 -4
  68. prefect/states.py +42 -11
  69. prefect/task_engine.py +10 -10
  70. prefect/task_runners.py +11 -22
  71. prefect/task_worker.py +9 -9
  72. prefect/tasks.py +28 -45
  73. prefect/telemetry/bootstrap.py +4 -6
  74. prefect/telemetry/services.py +2 -4
  75. prefect/types/__init__.py +2 -1
  76. prefect/types/_datetime.py +28 -1
  77. prefect/utilities/_engine.py +0 -1
  78. prefect/utilities/asyncutils.py +4 -8
  79. prefect/utilities/collections.py +13 -22
  80. prefect/utilities/dispatch.py +2 -4
  81. prefect/utilities/dockerutils.py +6 -6
  82. prefect/utilities/importtools.py +1 -68
  83. prefect/utilities/names.py +1 -1
  84. prefect/utilities/processutils.py +3 -6
  85. prefect/utilities/pydantic.py +4 -6
  86. prefect/utilities/render_swagger.py +1 -1
  87. prefect/utilities/schema_tools/hydration.py +6 -5
  88. prefect/utilities/templating.py +21 -8
  89. prefect/utilities/visualization.py +2 -4
  90. prefect/workers/base.py +3 -3
  91. prefect/workers/block.py +1 -0
  92. prefect/workers/cloud.py +1 -0
  93. prefect/workers/process.py +1 -0
  94. {prefect_client-3.1.14.dist-info → prefect_client-3.2.0.dist-info}/METADATA +1 -1
  95. {prefect_client-3.1.14.dist-info → prefect_client-3.2.0.dist-info}/RECORD +98 -93
  96. {prefect_client-3.1.14.dist-info → prefect_client-3.2.0.dist-info}/LICENSE +0 -0
  97. {prefect_client-3.1.14.dist-info → prefect_client-3.2.0.dist-info}/WHEEL +0 -0
  98. {prefect_client-3.1.14.dist-info → prefect_client-3.2.0.dist-info}/top_level.txt +0 -0
prefect/task_engine.py CHANGED
@@ -28,7 +28,6 @@ from typing import (
28
28
  from uuid import UUID
29
29
 
30
30
  import anyio
31
- import pendulum
32
31
  from opentelemetry import trace
33
32
  from typing_extensions import ParamSpec, Self
34
33
 
@@ -80,6 +79,7 @@ from prefect.states import (
80
79
  )
81
80
  from prefect.telemetry.run_telemetry import RunTelemetry
82
81
  from prefect.transactions import IsolationLevel, Transaction, transaction
82
+ from prefect.types._datetime import DateTime, PendulumDuration
83
83
  from prefect.utilities._engine import get_hook_name
84
84
  from prefect.utilities.annotations import NotSet
85
85
  from prefect.utilities.asyncutils import run_coro_as_sync
@@ -249,7 +249,7 @@ class BaseTaskRunEngine(Generic[P, R]):
249
249
  display_state = repr(self.state) if PREFECT_DEBUG_MODE else str(self.state)
250
250
  level = logging.INFO if self.state.is_completed() else logging.ERROR
251
251
  msg = f"Finished in state {display_state}"
252
- if self.state.is_pending():
252
+ if self.state.is_pending() and self.state.name != "NotReady":
253
253
  msg += (
254
254
  "\nPlease wait for all submitted tasks to complete"
255
255
  " before exiting your flow by calling `.wait()` on the "
@@ -437,7 +437,7 @@ class SyncTaskRunEngine(BaseTaskRunEngine[P, R]):
437
437
  if last_state.timestamp == new_state.timestamp:
438
438
  # Ensure that the state timestamp is unique, or at least not equal to the last state.
439
439
  # This might occur especially on Windows where the timestamp resolution is limited.
440
- new_state.timestamp += pendulum.duration(microseconds=1)
440
+ new_state.timestamp += PendulumDuration(microseconds=1)
441
441
 
442
442
  # Ensure that the state_details are populated with the current run IDs
443
443
  new_state.state_details.task_run_id = self.task_run.id
@@ -486,7 +486,7 @@ class SyncTaskRunEngine(BaseTaskRunEngine[P, R]):
486
486
 
487
487
  def handle_success(self, result: R, transaction: Transaction) -> R:
488
488
  if self.task.cache_expiration is not None:
489
- expiration = pendulum.now("utc") + self.task.cache_expiration
489
+ expiration = DateTime.now("utc") + self.task.cache_expiration
490
490
  else:
491
491
  expiration = None
492
492
 
@@ -535,7 +535,7 @@ class SyncTaskRunEngine(BaseTaskRunEngine[P, R]):
535
535
  else self.task.retry_delay_seconds
536
536
  )
537
537
  new_state = AwaitingRetry(
538
- scheduled_time=pendulum.now("utc").add(seconds=delay)
538
+ scheduled_time=DateTime.now("utc").add(seconds=delay)
539
539
  )
540
540
  else:
541
541
  delay = None
@@ -728,7 +728,7 @@ class SyncTaskRunEngine(BaseTaskRunEngine[P, R]):
728
728
  async def wait_until_ready(self) -> None:
729
729
  """Waits until the scheduled time (if its the future), then enters Running."""
730
730
  if scheduled_time := self.state.state_details.scheduled_time:
731
- sleep_time = (scheduled_time - pendulum.now("utc")).total_seconds()
731
+ sleep_time = (scheduled_time - DateTime.now("utc")).total_seconds()
732
732
  await anyio.sleep(sleep_time if sleep_time > 0 else 0)
733
733
  new_state = Retrying() if self.state.name == "AwaitingRetry" else Running()
734
734
  self.set_state(
@@ -970,7 +970,7 @@ class AsyncTaskRunEngine(BaseTaskRunEngine[P, R]):
970
970
  if last_state.timestamp == new_state.timestamp:
971
971
  # Ensure that the state timestamp is unique, or at least not equal to the last state.
972
972
  # This might occur especially on Windows where the timestamp resolution is limited.
973
- new_state.timestamp += pendulum.duration(microseconds=1)
973
+ new_state.timestamp += PendulumDuration(microseconds=1)
974
974
 
975
975
  # Ensure that the state_details are populated with the current run IDs
976
976
  new_state.state_details.task_run_id = self.task_run.id
@@ -1020,7 +1020,7 @@ class AsyncTaskRunEngine(BaseTaskRunEngine[P, R]):
1020
1020
 
1021
1021
  async def handle_success(self, result: R, transaction: Transaction) -> R:
1022
1022
  if self.task.cache_expiration is not None:
1023
- expiration = pendulum.now("utc") + self.task.cache_expiration
1023
+ expiration = DateTime.now("utc") + self.task.cache_expiration
1024
1024
  else:
1025
1025
  expiration = None
1026
1026
 
@@ -1068,7 +1068,7 @@ class AsyncTaskRunEngine(BaseTaskRunEngine[P, R]):
1068
1068
  else self.task.retry_delay_seconds
1069
1069
  )
1070
1070
  new_state = AwaitingRetry(
1071
- scheduled_time=pendulum.now("utc").add(seconds=delay)
1071
+ scheduled_time=DateTime.now("utc").add(seconds=delay)
1072
1072
  )
1073
1073
  else:
1074
1074
  delay = None
@@ -1259,7 +1259,7 @@ class AsyncTaskRunEngine(BaseTaskRunEngine[P, R]):
1259
1259
  async def wait_until_ready(self) -> None:
1260
1260
  """Waits until the scheduled time (if its the future), then enters Running."""
1261
1261
  if scheduled_time := self.state.state_details.scheduled_time:
1262
- sleep_time = (scheduled_time - pendulum.now("utc")).total_seconds()
1262
+ sleep_time = (scheduled_time - DateTime.now("utc")).total_seconds()
1263
1263
  await anyio.sleep(sleep_time if sleep_time > 0 else 0)
1264
1264
  new_state = Retrying() if self.state.name == "AwaitingRetry" else Running()
1265
1265
  await self.set_state(
prefect/task_runners.py CHANGED
@@ -84,8 +84,7 @@ class TaskRunner(abc.ABC, Generic[F]):
84
84
  parameters: dict[str, Any],
85
85
  wait_for: Iterable[PrefectFuture[Any]] | None = None,
86
86
  dependencies: dict[str, set[TaskRunInput]] | None = None,
87
- ) -> F:
88
- ...
87
+ ) -> F: ...
89
88
 
90
89
  @overload
91
90
  @abc.abstractmethod
@@ -95,8 +94,7 @@ class TaskRunner(abc.ABC, Generic[F]):
95
94
  parameters: dict[str, Any],
96
95
  wait_for: Iterable[PrefectFuture[Any]] | None = None,
97
96
  dependencies: dict[str, set[TaskRunInput]] | None = None,
98
- ) -> F:
99
- ...
97
+ ) -> F: ...
100
98
 
101
99
  @abc.abstractmethod
102
100
  def submit(
@@ -105,8 +103,7 @@ class TaskRunner(abc.ABC, Generic[F]):
105
103
  parameters: dict[str, Any],
106
104
  wait_for: Iterable[PrefectFuture[Any]] | None = None,
107
105
  dependencies: dict[str, set[TaskRunInput]] | None = None,
108
- ) -> F:
109
- ...
106
+ ) -> F: ...
110
107
 
111
108
  def map(
112
109
  self,
@@ -251,8 +248,7 @@ class ThreadPoolTaskRunner(TaskRunner[PrefectConcurrentFuture[R]]):
251
248
  parameters: dict[str, Any],
252
249
  wait_for: Iterable[PrefectFuture[Any]] | None = None,
253
250
  dependencies: dict[str, set[TaskRunInput]] | None = None,
254
- ) -> PrefectConcurrentFuture[R]:
255
- ...
251
+ ) -> PrefectConcurrentFuture[R]: ...
256
252
 
257
253
  @overload
258
254
  def submit(
@@ -261,8 +257,7 @@ class ThreadPoolTaskRunner(TaskRunner[PrefectConcurrentFuture[R]]):
261
257
  parameters: dict[str, Any],
262
258
  wait_for: Iterable[PrefectFuture[Any]] | None = None,
263
259
  dependencies: dict[str, set[TaskRunInput]] | None = None,
264
- ) -> PrefectConcurrentFuture[R]:
265
- ...
260
+ ) -> PrefectConcurrentFuture[R]: ...
266
261
 
267
262
  def submit(
268
263
  self,
@@ -337,8 +332,7 @@ class ThreadPoolTaskRunner(TaskRunner[PrefectConcurrentFuture[R]]):
337
332
  task: "Task[P, Coroutine[Any, Any, R]]",
338
333
  parameters: dict[str, Any],
339
334
  wait_for: Iterable[PrefectFuture[Any]] | None = None,
340
- ) -> PrefectFutureList[PrefectConcurrentFuture[R]]:
341
- ...
335
+ ) -> PrefectFutureList[PrefectConcurrentFuture[R]]: ...
342
336
 
343
337
  @overload
344
338
  def map(
@@ -346,8 +340,7 @@ class ThreadPoolTaskRunner(TaskRunner[PrefectConcurrentFuture[R]]):
346
340
  task: "Task[Any, R]",
347
341
  parameters: dict[str, Any],
348
342
  wait_for: Iterable[PrefectFuture[Any]] | None = None,
349
- ) -> PrefectFutureList[PrefectConcurrentFuture[R]]:
350
- ...
343
+ ) -> PrefectFutureList[PrefectConcurrentFuture[R]]: ...
351
344
 
352
345
  def map(
353
346
  self,
@@ -402,8 +395,7 @@ class PrefectTaskRunner(TaskRunner[PrefectDistributedFuture[R]]):
402
395
  parameters: dict[str, Any],
403
396
  wait_for: Iterable[PrefectFuture[Any]] | None = None,
404
397
  dependencies: dict[str, set[TaskRunInput]] | None = None,
405
- ) -> PrefectDistributedFuture[R]:
406
- ...
398
+ ) -> PrefectDistributedFuture[R]: ...
407
399
 
408
400
  @overload
409
401
  def submit(
@@ -412,8 +404,7 @@ class PrefectTaskRunner(TaskRunner[PrefectDistributedFuture[R]]):
412
404
  parameters: dict[str, Any],
413
405
  wait_for: Iterable[PrefectFuture[Any]] | None = None,
414
406
  dependencies: dict[str, set[TaskRunInput]] | None = None,
415
- ) -> PrefectDistributedFuture[R]:
416
- ...
407
+ ) -> PrefectDistributedFuture[R]: ...
417
408
 
418
409
  def submit(
419
410
  self,
@@ -458,8 +449,7 @@ class PrefectTaskRunner(TaskRunner[PrefectDistributedFuture[R]]):
458
449
  task: "Task[P, Coroutine[Any, Any, R]]",
459
450
  parameters: dict[str, Any],
460
451
  wait_for: Iterable[PrefectFuture[Any]] | None = None,
461
- ) -> PrefectFutureList[PrefectDistributedFuture[R]]:
462
- ...
452
+ ) -> PrefectFutureList[PrefectDistributedFuture[R]]: ...
463
453
 
464
454
  @overload
465
455
  def map(
@@ -467,8 +457,7 @@ class PrefectTaskRunner(TaskRunner[PrefectDistributedFuture[R]]):
467
457
  task: "Task[Any, R]",
468
458
  parameters: dict[str, Any],
469
459
  wait_for: Iterable[PrefectFuture[Any]] | None = None,
470
- ) -> PrefectFutureList[PrefectDistributedFuture[R]]:
471
- ...
460
+ ) -> PrefectFutureList[PrefectDistributedFuture[R]]: ...
472
461
 
473
462
  def map(
474
463
  self,
prefect/task_worker.py CHANGED
@@ -14,7 +14,6 @@ from uuid import UUID
14
14
 
15
15
  import anyio
16
16
  import anyio.abc
17
- import pendulum
18
17
  import uvicorn
19
18
  from exceptiongroup import BaseExceptionGroup # novermin
20
19
  from fastapi import FastAPI
@@ -35,6 +34,7 @@ from prefect.settings import (
35
34
  )
36
35
  from prefect.states import Pending
37
36
  from prefect.task_engine import run_task_async, run_task_sync
37
+ from prefect.types._datetime import DateTime
38
38
  from prefect.utilities.annotations import NotSet
39
39
  from prefect.utilities.asyncutils import asyncnullcontext, sync_compatible
40
40
  from prefect.utilities.engine import emit_task_run_state_change_event
@@ -107,7 +107,7 @@ class TaskWorker:
107
107
 
108
108
  self.task_keys: set[str] = set(t.task_key for t in tasks if isinstance(t, Task)) # pyright: ignore[reportUnnecessaryIsInstance]
109
109
 
110
- self._started_at: Optional[pendulum.DateTime] = None
110
+ self._started_at: Optional[DateTime] = None
111
111
  self.stopping: bool = False
112
112
 
113
113
  self._client = get_client()
@@ -124,7 +124,7 @@ class TaskWorker:
124
124
  self._executor = ThreadPoolExecutor(max_workers=limit if limit else None)
125
125
  self._limiter = anyio.CapacityLimiter(limit) if limit else None
126
126
 
127
- self.in_flight_task_runs: dict[str, dict[UUID, pendulum.DateTime]] = {
127
+ self.in_flight_task_runs: dict[str, dict[UUID, DateTime]] = {
128
128
  task_key: {} for task_key in self.task_keys
129
129
  }
130
130
  self.finished_task_runs: dict[str, int] = {
@@ -136,7 +136,7 @@ class TaskWorker:
136
136
  return f"{socket.gethostname()}-{os.getpid()}"
137
137
 
138
138
  @property
139
- def started_at(self) -> Optional[pendulum.DateTime]:
139
+ def started_at(self) -> Optional[DateTime]:
140
140
  return self._started_at
141
141
 
142
142
  @property
@@ -248,15 +248,15 @@ class TaskWorker:
248
248
 
249
249
  token_acquired = await self._acquire_token(task_run.id)
250
250
  if token_acquired:
251
- assert (
252
- self._runs_task_group is not None
253
- ), "Task group was not initialized"
251
+ assert self._runs_task_group is not None, (
252
+ "Task group was not initialized"
253
+ )
254
254
  self._runs_task_group.start_soon(
255
255
  self._safe_submit_scheduled_task_run, task_run
256
256
  )
257
257
 
258
258
  async def _safe_submit_scheduled_task_run(self, task_run: TaskRun):
259
- self.in_flight_task_runs[task_run.task_key][task_run.id] = pendulum.now()
259
+ self.in_flight_task_runs[task_run.task_key][task_run.id] = DateTime.now()
260
260
  try:
261
261
  await self._submit_scheduled_task_run(task_run)
262
262
  except BaseException as exc:
@@ -379,7 +379,7 @@ class TaskWorker:
379
379
  await self._exit_stack.enter_async_context(self._runs_task_group)
380
380
  self._exit_stack.enter_context(self._executor)
381
381
 
382
- self._started_at = pendulum.now()
382
+ self._started_at = DateTime.now()
383
383
  return self
384
384
 
385
385
  async def __aexit__(self, *exc_info: Any) -> None:
prefect/tasks.py CHANGED
@@ -226,8 +226,7 @@ class TaskRunNameCallbackWithParameters(Protocol):
226
226
  sig = inspect.signature(callable)
227
227
  return "parameters" in sig.parameters
228
228
 
229
- def __call__(self, parameters: dict[str, Any]) -> str:
230
- ...
229
+ def __call__(self, parameters: dict[str, Any]) -> str: ...
231
230
 
232
231
 
233
232
  StateHookCallable: TypeAlias = Callable[
@@ -483,9 +482,9 @@ class Task(Generic[P, R]):
483
482
  f"Invalid `retry_delay_seconds` provided; must be an int, float, list or callable. Received type {type(retry_delay_seconds)}"
484
483
  )
485
484
  else:
486
- self.retry_delay_seconds: Union[
487
- float, int, list[float], None
488
- ] = retry_delay_seconds
485
+ self.retry_delay_seconds: Union[float, int, list[float], None] = (
486
+ retry_delay_seconds
487
+ )
489
488
 
490
489
  if isinstance(self.retry_delay_seconds, list) and (
491
490
  len(self.retry_delay_seconds) > 50
@@ -965,7 +964,7 @@ class Task(Generic[P, R]):
965
964
  def __call__(
966
965
  self: "Task[P, NoReturn]",
967
966
  *args: P.args,
968
- return_state: Literal[False],
967
+ return_state: Literal[False] = False,
969
968
  wait_for: Optional[OneOrManyFutureOrResult[Any]] = None,
970
969
  **kwargs: P.kwargs,
971
970
  ) -> None:
@@ -977,21 +976,21 @@ class Task(Generic[P, R]):
977
976
  def __call__(
978
977
  self: "Task[P, R]",
979
978
  *args: P.args,
980
- return_state: Literal[True],
981
- wait_for: Optional[OneOrManyFutureOrResult[Any]] = None,
982
979
  **kwargs: P.kwargs,
983
- ) -> State[R]:
984
- ...
980
+ ) -> R: ...
985
981
 
982
+ # Keyword parameters `return_state` and `wait_for` aren't allowed after the
983
+ # ParamSpec `*args` parameter, so we lose return type typing when either of
984
+ # those are provided.
985
+ # TODO: Find a way to expose this functionality without losing type information
986
986
  @overload
987
987
  def __call__(
988
988
  self: "Task[P, R]",
989
989
  *args: P.args,
990
- return_state: Literal[False],
990
+ return_state: Literal[True] = True,
991
991
  wait_for: Optional[OneOrManyFutureOrResult[Any]] = None,
992
992
  **kwargs: P.kwargs,
993
- ) -> R:
994
- ...
993
+ ) -> State[R]: ...
995
994
 
996
995
  @overload
997
996
  def __call__(
@@ -1000,8 +999,7 @@ class Task(Generic[P, R]):
1000
999
  return_state: Literal[False] = False,
1001
1000
  wait_for: Optional[OneOrManyFutureOrResult[Any]] = None,
1002
1001
  **kwargs: P.kwargs,
1003
- ) -> R:
1004
- ...
1002
+ ) -> R: ...
1005
1003
 
1006
1004
  def __call__(
1007
1005
  self: "Union[Task[P, R], Task[P, NoReturn]]",
@@ -1044,8 +1042,7 @@ class Task(Generic[P, R]):
1044
1042
  self: "Task[P, R]",
1045
1043
  *args: P.args,
1046
1044
  **kwargs: P.kwargs,
1047
- ) -> PrefectFuture[R]:
1048
- ...
1045
+ ) -> PrefectFuture[R]: ...
1049
1046
 
1050
1047
  @overload
1051
1048
  def submit(
@@ -1054,8 +1051,7 @@ class Task(Generic[P, R]):
1054
1051
  return_state: Literal[False],
1055
1052
  wait_for: Optional[OneOrManyFutureOrResult[Any]] = None,
1056
1053
  **kwargs: P.kwargs,
1057
- ) -> PrefectFuture[R]:
1058
- ...
1054
+ ) -> PrefectFuture[R]: ...
1059
1055
 
1060
1056
  @overload
1061
1057
  def submit(
@@ -1064,8 +1060,7 @@ class Task(Generic[P, R]):
1064
1060
  return_state: Literal[False],
1065
1061
  wait_for: Optional[OneOrManyFutureOrResult[Any]] = None,
1066
1062
  **kwargs: P.kwargs,
1067
- ) -> PrefectFuture[R]:
1068
- ...
1063
+ ) -> PrefectFuture[R]: ...
1069
1064
 
1070
1065
  @overload
1071
1066
  def submit(
@@ -1074,8 +1069,7 @@ class Task(Generic[P, R]):
1074
1069
  return_state: Literal[True],
1075
1070
  wait_for: Optional[OneOrManyFutureOrResult[Any]] = None,
1076
1071
  **kwargs: P.kwargs,
1077
- ) -> State[R]:
1078
- ...
1072
+ ) -> State[R]: ...
1079
1073
 
1080
1074
  @overload
1081
1075
  def submit(
@@ -1084,8 +1078,7 @@ class Task(Generic[P, R]):
1084
1078
  return_state: Literal[True],
1085
1079
  wait_for: Optional[OneOrManyFutureOrResult[Any]] = None,
1086
1080
  **kwargs: P.kwargs,
1087
- ) -> State[R]:
1088
- ...
1081
+ ) -> State[R]: ...
1089
1082
 
1090
1083
  def submit(
1091
1084
  self: "Union[Task[P, R], Task[P, Coroutine[Any, Any, R]]]",
@@ -1219,8 +1212,7 @@ class Task(Generic[P, R]):
1219
1212
  wait_for: Optional[Iterable[Union[PrefectFuture[R], R]]] = ...,
1220
1213
  deferred: bool = ...,
1221
1214
  **kwargs: Any,
1222
- ) -> list[State[R]]:
1223
- ...
1215
+ ) -> list[State[R]]: ...
1224
1216
 
1225
1217
  @overload
1226
1218
  def map(
@@ -1229,8 +1221,7 @@ class Task(Generic[P, R]):
1229
1221
  wait_for: Optional[Iterable[Union[PrefectFuture[R], R]]] = ...,
1230
1222
  deferred: bool = ...,
1231
1223
  **kwargs: Any,
1232
- ) -> PrefectFutureList[R]:
1233
- ...
1224
+ ) -> PrefectFutureList[R]: ...
1234
1225
 
1235
1226
  @overload
1236
1227
  def map(
@@ -1240,8 +1231,7 @@ class Task(Generic[P, R]):
1240
1231
  wait_for: Optional[Iterable[Union[PrefectFuture[R], R]]] = ...,
1241
1232
  deferred: bool = ...,
1242
1233
  **kwargs: Any,
1243
- ) -> list[State[R]]:
1244
- ...
1234
+ ) -> list[State[R]]: ...
1245
1235
 
1246
1236
  @overload
1247
1237
  def map(
@@ -1250,8 +1240,7 @@ class Task(Generic[P, R]):
1250
1240
  wait_for: Optional[Iterable[Union[PrefectFuture[R], R]]] = ...,
1251
1241
  deferred: bool = ...,
1252
1242
  **kwargs: Any,
1253
- ) -> PrefectFutureList[R]:
1254
- ...
1243
+ ) -> PrefectFutureList[R]: ...
1255
1244
 
1256
1245
  @overload
1257
1246
  def map(
@@ -1261,8 +1250,7 @@ class Task(Generic[P, R]):
1261
1250
  wait_for: Optional[Iterable[Union[PrefectFuture[R], R]]] = ...,
1262
1251
  deferred: bool = ...,
1263
1252
  **kwargs: Any,
1264
- ) -> list[State[R]]:
1265
- ...
1253
+ ) -> list[State[R]]: ...
1266
1254
 
1267
1255
  @overload
1268
1256
  def map(
@@ -1272,8 +1260,7 @@ class Task(Generic[P, R]):
1272
1260
  wait_for: Optional[Iterable[Union[PrefectFuture[R], R]]] = ...,
1273
1261
  deferred: bool = ...,
1274
1262
  **kwargs: Any,
1275
- ) -> PrefectFutureList[R]:
1276
- ...
1263
+ ) -> PrefectFutureList[R]: ...
1277
1264
 
1278
1265
  def map(
1279
1266
  self,
@@ -1608,8 +1595,7 @@ class Task(Generic[P, R]):
1608
1595
 
1609
1596
 
1610
1597
  @overload
1611
- def task(__fn: Callable[P, R]) -> Task[P, R]:
1612
- ...
1598
+ def task(__fn: Callable[P, R]) -> Task[P, R]: ...
1613
1599
 
1614
1600
 
1615
1601
  # see https://github.com/PrefectHQ/prefect/issues/16380
@@ -1644,8 +1630,7 @@ def task(
1644
1630
  on_failure: Optional[list[StateHookCallable]] = None,
1645
1631
  retry_condition_fn: Literal[None] = None,
1646
1632
  viz_return_value: Any = None,
1647
- ) -> Callable[[Callable[P, R]], Task[P, R]]:
1648
- ...
1633
+ ) -> Callable[[Callable[P, R]], Task[P, R]]: ...
1649
1634
 
1650
1635
 
1651
1636
  # see https://github.com/PrefectHQ/prefect/issues/16380
@@ -1680,8 +1665,7 @@ def task(
1680
1665
  on_failure: Optional[list[StateHookCallable]] = None,
1681
1666
  retry_condition_fn: Optional[Callable[[Task[P, R], TaskRun, State], bool]] = None,
1682
1667
  viz_return_value: Any = None,
1683
- ) -> Callable[[Callable[P, R]], Task[P, R]]:
1684
- ...
1668
+ ) -> Callable[[Callable[P, R]], Task[P, R]]: ...
1685
1669
 
1686
1670
 
1687
1671
  @overload # TODO: do we need this overload?
@@ -1717,8 +1701,7 @@ def task(
1717
1701
  on_failure: Optional[list[StateHookCallable]] = None,
1718
1702
  retry_condition_fn: Optional[Callable[[Task[P, Any], TaskRun, State], bool]] = None,
1719
1703
  viz_return_value: Any = None,
1720
- ) -> Callable[[Callable[P, R]], Task[P, R]]:
1721
- ...
1704
+ ) -> Callable[[Callable[P, R]], Task[P, R]]: ...
1722
1705
 
1723
1706
 
1724
1707
  def task(
@@ -15,12 +15,10 @@ if TYPE_CHECKING:
15
15
  from opentelemetry.sdk.trace import TracerProvider
16
16
 
17
17
 
18
- def setup_telemetry() -> (
19
- Union[
20
- tuple["TracerProvider", "MeterProvider", "LoggerProvider"],
21
- tuple[None, None, None],
22
- ]
23
- ):
18
+ def setup_telemetry() -> Union[
19
+ tuple["TracerProvider", "MeterProvider", "LoggerProvider"],
20
+ tuple[None, None, None],
21
+ ]:
24
22
  settings = prefect.settings.get_current_settings()
25
23
 
26
24
  server_type = determine_server_type()
@@ -15,11 +15,9 @@ T_contra = TypeVar("T_contra", contravariant=True)
15
15
 
16
16
 
17
17
  class OTLPExporter(Protocol[T_contra]):
18
- def export(self, __items: Sequence[T_contra]) -> Any:
19
- ...
18
+ def export(self, __items: Sequence[T_contra]) -> Any: ...
20
19
 
21
- def shutdown(self) -> Any:
22
- ...
20
+ def shutdown(self) -> Any: ...
23
21
 
24
22
 
25
23
  class BaseQueueingExporter(BatchedQueueService[BatchItem]):
prefect/types/__init__.py CHANGED
@@ -106,7 +106,8 @@ KeyValueLabels = Annotated[
106
106
 
107
107
 
108
108
  ListOfNonEmptyStrings = Annotated[
109
- List[str], BeforeValidator(lambda x: [s for s in x if s.strip()])
109
+ List[str],
110
+ BeforeValidator(lambda x: [str(s) for s in x if str(s).strip()]),
110
111
  ]
111
112
 
112
113
 
@@ -1,10 +1,14 @@
1
1
  from __future__ import annotations
2
2
 
3
+ from typing import Any
4
+
3
5
  import pendulum
6
+ import pendulum.tz
4
7
  from pendulum.date import Date as PendulumDate
5
8
  from pendulum.datetime import DateTime as PendulumDateTime
6
9
  from pendulum.duration import Duration as PendulumDuration
7
10
  from pendulum.time import Time as PendulumTime
11
+ from pendulum.tz.timezone import FixedTimezone, Timezone
8
12
  from pydantic_extra_types.pendulum_dt import Date as PydanticDate
9
13
  from pydantic_extra_types.pendulum_dt import DateTime as PydanticDateTime
10
14
  from typing_extensions import TypeAlias
@@ -15,5 +19,28 @@ Date: TypeAlias = PydanticDate
15
19
 
16
20
  def parse_datetime(
17
21
  value: str,
22
+ **options: Any,
18
23
  ) -> PendulumDateTime | PendulumDate | PendulumTime | PendulumDuration:
19
- return pendulum.parse(value)
24
+ return pendulum.parse(value, **options)
25
+
26
+
27
+ def format_diff(
28
+ diff: PendulumDuration,
29
+ is_now: bool = True,
30
+ absolute: bool = False,
31
+ locale: str | None = None,
32
+ ) -> str:
33
+ return pendulum.format_diff(diff, is_now, absolute, locale)
34
+
35
+
36
+ def local_timezone() -> Timezone | FixedTimezone:
37
+ return pendulum.tz.local_timezone()
38
+
39
+
40
+ def from_format(
41
+ value: str,
42
+ fmt: str,
43
+ tz: str | Timezone = pendulum.tz.UTC,
44
+ locale: str | None = None,
45
+ ) -> DateTime:
46
+ return DateTime.instance(pendulum.from_format(value, fmt, tz, locale))
@@ -1,6 +1,5 @@
1
1
  """Internal engine utilities"""
2
2
 
3
-
4
3
  from collections.abc import Callable
5
4
  from functools import partial
6
5
  from typing import TYPE_CHECKING, Any, Union
@@ -129,8 +129,7 @@ def run_coro_as_sync(
129
129
  *,
130
130
  force_new_thread: bool = ...,
131
131
  wait_for_result: Literal[True] = ...,
132
- ) -> R:
133
- ...
132
+ ) -> R: ...
134
133
 
135
134
 
136
135
  @overload
@@ -139,8 +138,7 @@ def run_coro_as_sync(
139
138
  *,
140
139
  force_new_thread: bool = ...,
141
140
  wait_for_result: Literal[False] = False,
142
- ) -> R:
143
- ...
141
+ ) -> R: ...
144
142
 
145
143
 
146
144
  def run_coro_as_sync(
@@ -366,15 +364,13 @@ def sync_compatible(
366
364
  @overload
367
365
  def asyncnullcontext(
368
366
  value: None = None, *args: Any, **kwargs: Any
369
- ) -> AbstractAsyncContextManager[None, None]:
370
- ...
367
+ ) -> AbstractAsyncContextManager[None, None]: ...
371
368
 
372
369
 
373
370
  @overload
374
371
  def asyncnullcontext(
375
372
  value: R, *args: Any, **kwargs: Any
376
- ) -> AbstractAsyncContextManager[R, None]:
377
- ...
373
+ ) -> AbstractAsyncContextManager[R, None]: ...
378
374
 
379
375
 
380
376
  @asynccontextmanager