prefect-client 3.1.10__py3-none-any.whl → 3.1.12__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 (141) hide show
  1. prefect/_experimental/lineage.py +7 -8
  2. prefect/_experimental/sla/__init__.py +0 -0
  3. prefect/_experimental/sla/client.py +66 -0
  4. prefect/_experimental/sla/objects.py +53 -0
  5. prefect/_internal/_logging.py +15 -3
  6. prefect/_internal/compatibility/async_dispatch.py +22 -16
  7. prefect/_internal/compatibility/deprecated.py +42 -18
  8. prefect/_internal/compatibility/migration.py +2 -2
  9. prefect/_internal/concurrency/inspection.py +12 -14
  10. prefect/_internal/concurrency/primitives.py +2 -2
  11. prefect/_internal/concurrency/services.py +154 -80
  12. prefect/_internal/concurrency/waiters.py +13 -9
  13. prefect/_internal/pydantic/annotations/pendulum.py +7 -7
  14. prefect/_internal/pytz.py +4 -3
  15. prefect/_internal/retries.py +10 -5
  16. prefect/_internal/schemas/bases.py +19 -10
  17. prefect/_internal/schemas/validators.py +227 -388
  18. prefect/_version.py +3 -3
  19. prefect/automations.py +236 -30
  20. prefect/blocks/__init__.py +3 -3
  21. prefect/blocks/abstract.py +53 -30
  22. prefect/blocks/core.py +183 -84
  23. prefect/blocks/notifications.py +133 -73
  24. prefect/blocks/redis.py +13 -9
  25. prefect/blocks/system.py +24 -11
  26. prefect/blocks/webhook.py +7 -5
  27. prefect/cache_policies.py +3 -2
  28. prefect/client/orchestration/__init__.py +1957 -0
  29. prefect/client/orchestration/_artifacts/__init__.py +0 -0
  30. prefect/client/orchestration/_artifacts/client.py +239 -0
  31. prefect/client/orchestration/_automations/__init__.py +0 -0
  32. prefect/client/orchestration/_automations/client.py +329 -0
  33. prefect/client/orchestration/_blocks_documents/__init__.py +0 -0
  34. prefect/client/orchestration/_blocks_documents/client.py +334 -0
  35. prefect/client/orchestration/_blocks_schemas/__init__.py +0 -0
  36. prefect/client/orchestration/_blocks_schemas/client.py +200 -0
  37. prefect/client/orchestration/_blocks_types/__init__.py +0 -0
  38. prefect/client/orchestration/_blocks_types/client.py +380 -0
  39. prefect/client/orchestration/_concurrency_limits/__init__.py +0 -0
  40. prefect/client/orchestration/_concurrency_limits/client.py +762 -0
  41. prefect/client/orchestration/_deployments/__init__.py +0 -0
  42. prefect/client/orchestration/_deployments/client.py +1128 -0
  43. prefect/client/orchestration/_flow_runs/__init__.py +0 -0
  44. prefect/client/orchestration/_flow_runs/client.py +903 -0
  45. prefect/client/orchestration/_flows/__init__.py +0 -0
  46. prefect/client/orchestration/_flows/client.py +343 -0
  47. prefect/client/orchestration/_logs/__init__.py +0 -0
  48. prefect/client/orchestration/_logs/client.py +97 -0
  49. prefect/client/orchestration/_variables/__init__.py +0 -0
  50. prefect/client/orchestration/_variables/client.py +157 -0
  51. prefect/client/orchestration/base.py +46 -0
  52. prefect/client/orchestration/routes.py +145 -0
  53. prefect/client/schemas/__init__.py +68 -28
  54. prefect/client/schemas/actions.py +2 -2
  55. prefect/client/schemas/filters.py +5 -0
  56. prefect/client/schemas/objects.py +8 -15
  57. prefect/client/schemas/schedules.py +22 -10
  58. prefect/concurrency/_asyncio.py +87 -0
  59. prefect/concurrency/{events.py → _events.py} +10 -10
  60. prefect/concurrency/asyncio.py +20 -104
  61. prefect/concurrency/context.py +6 -4
  62. prefect/concurrency/services.py +26 -74
  63. prefect/concurrency/sync.py +23 -44
  64. prefect/concurrency/v1/_asyncio.py +63 -0
  65. prefect/concurrency/v1/{events.py → _events.py} +13 -15
  66. prefect/concurrency/v1/asyncio.py +27 -80
  67. prefect/concurrency/v1/context.py +6 -4
  68. prefect/concurrency/v1/services.py +33 -79
  69. prefect/concurrency/v1/sync.py +18 -37
  70. prefect/context.py +66 -45
  71. prefect/deployments/base.py +10 -144
  72. prefect/deployments/flow_runs.py +12 -2
  73. prefect/deployments/runner.py +53 -4
  74. prefect/deployments/steps/pull.py +13 -0
  75. prefect/engine.py +17 -4
  76. prefect/events/clients.py +7 -1
  77. prefect/events/schemas/events.py +3 -2
  78. prefect/filesystems.py +6 -2
  79. prefect/flow_engine.py +101 -85
  80. prefect/flows.py +10 -1
  81. prefect/input/run_input.py +2 -1
  82. prefect/logging/logging.yml +1 -1
  83. prefect/main.py +1 -3
  84. prefect/results.py +2 -307
  85. prefect/runner/runner.py +4 -2
  86. prefect/runner/storage.py +87 -21
  87. prefect/serializers.py +32 -25
  88. prefect/settings/legacy.py +4 -4
  89. prefect/settings/models/api.py +3 -3
  90. prefect/settings/models/cli.py +3 -3
  91. prefect/settings/models/client.py +5 -3
  92. prefect/settings/models/cloud.py +8 -3
  93. prefect/settings/models/deployments.py +3 -3
  94. prefect/settings/models/experiments.py +4 -7
  95. prefect/settings/models/flows.py +3 -3
  96. prefect/settings/models/internal.py +4 -2
  97. prefect/settings/models/logging.py +4 -3
  98. prefect/settings/models/results.py +3 -3
  99. prefect/settings/models/root.py +3 -2
  100. prefect/settings/models/runner.py +4 -4
  101. prefect/settings/models/server/api.py +3 -3
  102. prefect/settings/models/server/database.py +11 -4
  103. prefect/settings/models/server/deployments.py +6 -2
  104. prefect/settings/models/server/ephemeral.py +4 -2
  105. prefect/settings/models/server/events.py +3 -2
  106. prefect/settings/models/server/flow_run_graph.py +6 -2
  107. prefect/settings/models/server/root.py +3 -3
  108. prefect/settings/models/server/services.py +26 -11
  109. prefect/settings/models/server/tasks.py +6 -3
  110. prefect/settings/models/server/ui.py +3 -3
  111. prefect/settings/models/tasks.py +5 -5
  112. prefect/settings/models/testing.py +3 -3
  113. prefect/settings/models/worker.py +5 -3
  114. prefect/settings/profiles.py +15 -2
  115. prefect/states.py +61 -45
  116. prefect/task_engine.py +54 -75
  117. prefect/task_runners.py +56 -55
  118. prefect/task_worker.py +2 -2
  119. prefect/tasks.py +90 -36
  120. prefect/telemetry/bootstrap.py +10 -9
  121. prefect/telemetry/run_telemetry.py +13 -8
  122. prefect/telemetry/services.py +4 -0
  123. prefect/transactions.py +4 -15
  124. prefect/utilities/_git.py +34 -0
  125. prefect/utilities/asyncutils.py +1 -1
  126. prefect/utilities/engine.py +3 -19
  127. prefect/utilities/generics.py +18 -0
  128. prefect/utilities/templating.py +25 -1
  129. prefect/workers/base.py +6 -3
  130. prefect/workers/process.py +1 -1
  131. {prefect_client-3.1.10.dist-info → prefect_client-3.1.12.dist-info}/METADATA +2 -2
  132. {prefect_client-3.1.10.dist-info → prefect_client-3.1.12.dist-info}/RECORD +135 -109
  133. prefect/client/orchestration.py +0 -4523
  134. prefect/records/__init__.py +0 -1
  135. prefect/records/base.py +0 -235
  136. prefect/records/filesystem.py +0 -213
  137. prefect/records/memory.py +0 -184
  138. prefect/records/result_store.py +0 -70
  139. {prefect_client-3.1.10.dist-info → prefect_client-3.1.12.dist-info}/LICENSE +0 -0
  140. {prefect_client-3.1.10.dist-info → prefect_client-3.1.12.dist-info}/WHEEL +0 -0
  141. {prefect_client-3.1.10.dist-info → prefect_client-3.1.12.dist-info}/top_level.txt +0 -0
prefect/flow_engine.py CHANGED
@@ -1,3 +1,5 @@
1
+ from __future__ import annotations
2
+
1
3
  import asyncio
2
4
  import logging
3
5
  import os
@@ -14,7 +16,6 @@ from typing import (
14
16
  Iterable,
15
17
  Literal,
16
18
  Optional,
17
- Tuple,
18
19
  Type,
19
20
  TypeVar,
20
21
  Union,
@@ -55,7 +56,6 @@ from prefect.logging.loggers import (
55
56
  patch_print,
56
57
  )
57
58
  from prefect.results import (
58
- BaseResult,
59
59
  ResultStore,
60
60
  get_result_store,
61
61
  should_persist_result,
@@ -104,13 +104,15 @@ class FlowRunTimeoutError(TimeoutError):
104
104
  """Raised when a flow run exceeds its defined timeout."""
105
105
 
106
106
 
107
- def load_flow_and_flow_run(flow_run_id: UUID) -> Tuple[FlowRun, Flow]:
108
- ## TODO: add error handling to update state and log tracebacks
109
- entrypoint = os.environ.get("PREFECT__FLOW_ENTRYPOINT")
107
+ def load_flow_run(flow_run_id: UUID) -> FlowRun:
108
+ client = get_client(sync_client=True)
109
+ flow_run = client.read_flow_run(flow_run_id)
110
+ return flow_run
110
111
 
111
- client = cast(SyncPrefectClient, get_client(sync_client=True))
112
112
 
113
- flow_run = client.read_flow_run(flow_run_id)
113
+ def load_flow(flow_run: FlowRun) -> Flow[..., Any]:
114
+ entrypoint = os.environ.get("PREFECT__FLOW_ENTRYPOINT")
115
+
114
116
  if entrypoint:
115
117
  # we should not accept a placeholder flow at runtime
116
118
  flow = load_flow_from_entrypoint(entrypoint, use_placeholder_flow=False)
@@ -118,7 +120,12 @@ def load_flow_and_flow_run(flow_run_id: UUID) -> Tuple[FlowRun, Flow]:
118
120
  flow = run_coro_as_sync(
119
121
  load_flow_from_flow_run(flow_run, use_placeholder_flow=False)
120
122
  )
123
+ return flow
121
124
 
125
+
126
+ def load_flow_and_flow_run(flow_run_id: UUID) -> tuple[FlowRun, Flow[..., Any]]:
127
+ flow_run = load_flow_run(flow_run_id)
128
+ flow = load_flow(flow_run)
122
129
  return flow_run, flow
123
130
 
124
131
 
@@ -129,7 +136,7 @@ class BaseFlowRunEngine(Generic[P, R]):
129
136
  flow_run: Optional[FlowRun] = None
130
137
  flow_run_id: Optional[UUID] = None
131
138
  logger: logging.Logger = field(default_factory=lambda: get_logger("engine"))
132
- wait_for: Optional[Iterable[PrefectFuture]] = None
139
+ wait_for: Optional[Iterable[PrefectFuture[Any]]] = None
133
140
  # holds the return value from the user code
134
141
  _return_value: Union[R, Type[NotSet]] = NotSet
135
142
  # holds the exception raised by the user code, if any
@@ -210,7 +217,7 @@ class FlowRunEngine(BaseFlowRunEngine[P, R]):
210
217
 
211
218
  def _resolve_parameters(self):
212
219
  if not self.parameters:
213
- return {}
220
+ return
214
221
 
215
222
  resolved_parameters = {}
216
223
  for parameter, value in self.parameters.items():
@@ -278,7 +285,6 @@ class FlowRunEngine(BaseFlowRunEngine[P, R]):
278
285
  ),
279
286
  )
280
287
  self.short_circuit = True
281
- self.call_hooks()
282
288
 
283
289
  new_state = Running()
284
290
  state = self.set_state(new_state)
@@ -301,16 +307,14 @@ class FlowRunEngine(BaseFlowRunEngine[P, R]):
301
307
  self.flow_run.state_type = state.type # type: ignore
302
308
 
303
309
  self._telemetry.update_state(state)
310
+ self.call_hooks(state)
304
311
  return state
305
312
 
306
313
  def result(self, raise_on_failure: bool = True) -> "Union[R, State, None]":
307
314
  if self._return_value is not NotSet and not isinstance(
308
315
  self._return_value, State
309
316
  ):
310
- if isinstance(self._return_value, BaseResult):
311
- _result = self._return_value.get()
312
- else:
313
- _result = self._return_value
317
+ _result = self._return_value
314
318
 
315
319
  if asyncio.iscoroutine(_result):
316
320
  # getting the value for a BaseResult may return an awaitable
@@ -490,24 +494,13 @@ class FlowRunEngine(BaseFlowRunEngine[P, R]):
490
494
  ):
491
495
  return subflow_run
492
496
 
493
- flow_run = client.create_flow_run(
497
+ return client.create_flow_run(
494
498
  flow=self.flow,
495
499
  parameters=self.flow.serialize_parameters(parameters),
496
500
  state=Pending(),
497
501
  parent_task_run_id=getattr(parent_task_run, "id", None),
498
502
  tags=TagsContext.get().current_tags,
499
503
  )
500
- if flow_run_ctx:
501
- parent_logger = get_run_logger(flow_run_ctx)
502
- parent_logger.info(
503
- f"Created subflow run {flow_run.name!r} for flow {self.flow.name!r}"
504
- )
505
- else:
506
- self.logger.info(
507
- f"Created flow run {flow_run.name!r} for flow {self.flow.name!r}"
508
- )
509
-
510
- return flow_run
511
504
 
512
505
  def call_hooks(self, state: Optional[State] = None):
513
506
  if state is None:
@@ -606,6 +599,7 @@ class FlowRunEngine(BaseFlowRunEngine[P, R]):
606
599
  stack.enter_context(ConcurrencyContext())
607
600
 
608
601
  # set the logger to the flow run logger
602
+
609
603
  self.logger = flow_run_logger(flow_run=self.flow_run, flow=self.flow)
610
604
 
611
605
  # update the flow run name if necessary
@@ -616,12 +610,32 @@ class FlowRunEngine(BaseFlowRunEngine[P, R]):
616
610
  self.client.set_flow_run_name(
617
611
  flow_run_id=self.flow_run.id, name=flow_run_name
618
612
  )
613
+
619
614
  self.logger.extra["flow_run_name"] = flow_run_name
620
615
  self.logger.debug(
621
616
  f"Renamed flow run {self.flow_run.name!r} to {flow_run_name!r}"
622
617
  )
623
618
  self.flow_run.name = flow_run_name
624
619
  self._flow_run_name_set = True
620
+
621
+ self._telemetry.update_run_name(name=flow_run_name)
622
+
623
+ if self.flow_run.parent_task_run_id:
624
+ _logger = get_run_logger(FlowRunContext.get())
625
+ run_type = "subflow"
626
+ else:
627
+ _logger = self.logger
628
+ run_type = "flow"
629
+
630
+ _logger.info(
631
+ f"Beginning {run_type} run {self.flow_run.name!r} for flow {self.flow.name!r}"
632
+ )
633
+
634
+ if flow_run_url := url_for(self.flow_run):
635
+ self.logger.info(
636
+ f"View at {flow_run_url}", extra={"send_to_api": False}
637
+ )
638
+
625
639
  yield
626
640
 
627
641
  @contextmanager
@@ -635,12 +649,6 @@ class FlowRunEngine(BaseFlowRunEngine[P, R]):
635
649
 
636
650
  if not self.flow_run:
637
651
  self.flow_run = self.create_flow_run(self.client)
638
- flow_run_url = url_for(self.flow_run)
639
-
640
- if flow_run_url:
641
- self.logger.info(
642
- f"View at {flow_run_url}", extra={"send_to_api": False}
643
- )
644
652
  else:
645
653
  # Update the empirical policy to match the flow if it is not set
646
654
  if self.flow_run.empirical_policy.retry_delay is None:
@@ -658,7 +666,6 @@ class FlowRunEngine(BaseFlowRunEngine[P, R]):
658
666
  )
659
667
 
660
668
  self._telemetry.start_span(
661
- name=self.flow.name,
662
669
  run=self.flow_run,
663
670
  client=self.client,
664
671
  parameters=self.parameters,
@@ -705,13 +712,13 @@ class FlowRunEngine(BaseFlowRunEngine[P, R]):
705
712
  @contextmanager
706
713
  def start(self) -> Generator[None, None, None]:
707
714
  with self.initialize_run():
708
- with trace.use_span(
709
- self._telemetry.span
710
- ) if self._telemetry.span else nullcontext():
715
+ with (
716
+ trace.use_span(self._telemetry.span)
717
+ if self._telemetry.span
718
+ else nullcontext()
719
+ ):
711
720
  self.begin_run()
712
721
 
713
- if self.state.is_running():
714
- self.call_hooks()
715
722
  yield
716
723
 
717
724
  @contextmanager
@@ -733,9 +740,6 @@ class FlowRunEngine(BaseFlowRunEngine[P, R]):
733
740
  except Exception as exc:
734
741
  self.logger.exception("Encountered exception during execution: %r", exc)
735
742
  self.handle_exception(exc)
736
- finally:
737
- if self.state.is_final() or self.state.is_cancelling():
738
- self.call_hooks()
739
743
 
740
744
  def call_flow_fn(self) -> Union[R, Coroutine[Any, Any, R]]:
741
745
  """
@@ -773,7 +777,7 @@ class AsyncFlowRunEngine(BaseFlowRunEngine[P, R]):
773
777
 
774
778
  def _resolve_parameters(self):
775
779
  if not self.parameters:
776
- return {}
780
+ return
777
781
 
778
782
  resolved_parameters = {}
779
783
  for parameter, value in self.parameters.items():
@@ -841,7 +845,6 @@ class AsyncFlowRunEngine(BaseFlowRunEngine[P, R]):
841
845
  ),
842
846
  )
843
847
  self.short_circuit = True
844
- await self.call_hooks()
845
848
 
846
849
  new_state = Running()
847
850
  state = await self.set_state(new_state)
@@ -864,16 +867,14 @@ class AsyncFlowRunEngine(BaseFlowRunEngine[P, R]):
864
867
  self.flow_run.state_type = state.type # type: ignore
865
868
 
866
869
  self._telemetry.update_state(state)
870
+ await self.call_hooks(state)
867
871
  return state
868
872
 
869
873
  async def result(self, raise_on_failure: bool = True) -> "Union[R, State, None]":
870
874
  if self._return_value is not NotSet and not isinstance(
871
875
  self._return_value, State
872
876
  ):
873
- if isinstance(self._return_value, BaseResult):
874
- _result = self._return_value.get()
875
- else:
876
- _result = self._return_value
877
+ _result = self._return_value
877
878
 
878
879
  if asyncio.iscoroutine(_result):
879
880
  # getting the value for a BaseResult may return an awaitable
@@ -1052,24 +1053,13 @@ class AsyncFlowRunEngine(BaseFlowRunEngine[P, R]):
1052
1053
  ):
1053
1054
  return subflow_run
1054
1055
 
1055
- flow_run = await client.create_flow_run(
1056
+ return await client.create_flow_run(
1056
1057
  flow=self.flow,
1057
1058
  parameters=self.flow.serialize_parameters(parameters),
1058
1059
  state=Pending(),
1059
1060
  parent_task_run_id=getattr(parent_task_run, "id", None),
1060
1061
  tags=TagsContext.get().current_tags,
1061
1062
  )
1062
- if flow_run_ctx:
1063
- parent_logger = get_run_logger(flow_run_ctx)
1064
- parent_logger.info(
1065
- f"Created subflow run {flow_run.name!r} for flow {self.flow.name!r}"
1066
- )
1067
- else:
1068
- self.logger.info(
1069
- f"Created flow run {flow_run.name!r} for flow {self.flow.name!r}"
1070
- )
1071
-
1072
- return flow_run
1073
1063
 
1074
1064
  async def call_hooks(self, state: Optional[State] = None):
1075
1065
  if state is None:
@@ -1171,6 +1161,7 @@ class AsyncFlowRunEngine(BaseFlowRunEngine[P, R]):
1171
1161
  self.logger = flow_run_logger(flow_run=self.flow_run, flow=self.flow)
1172
1162
 
1173
1163
  # update the flow run name if necessary
1164
+
1174
1165
  if not self._flow_run_name_set and self.flow.flow_run_name:
1175
1166
  flow_run_name = resolve_custom_flow_run_name(
1176
1167
  flow=self.flow, parameters=self.parameters
@@ -1184,6 +1175,24 @@ class AsyncFlowRunEngine(BaseFlowRunEngine[P, R]):
1184
1175
  )
1185
1176
  self.flow_run.name = flow_run_name
1186
1177
  self._flow_run_name_set = True
1178
+
1179
+ self._telemetry.update_run_name(name=flow_run_name)
1180
+ if self.flow_run.parent_task_run_id:
1181
+ _logger = get_run_logger(FlowRunContext.get())
1182
+ run_type = "subflow"
1183
+ else:
1184
+ _logger = self.logger
1185
+ run_type = "flow"
1186
+
1187
+ _logger.info(
1188
+ f"Beginning {run_type} run {self.flow_run.name!r} for flow {self.flow.name!r}"
1189
+ )
1190
+
1191
+ if flow_run_url := url_for(self.flow_run):
1192
+ self.logger.info(
1193
+ f"View at {flow_run_url}", extra={"send_to_api": False}
1194
+ )
1195
+
1187
1196
  yield
1188
1197
 
1189
1198
  @asynccontextmanager
@@ -1220,7 +1229,6 @@ class AsyncFlowRunEngine(BaseFlowRunEngine[P, R]):
1220
1229
  )
1221
1230
 
1222
1231
  await self._telemetry.async_start_span(
1223
- name=self.flow.name,
1224
1232
  run=self.flow_run,
1225
1233
  client=self.client,
1226
1234
  parameters=self.parameters,
@@ -1267,13 +1275,13 @@ class AsyncFlowRunEngine(BaseFlowRunEngine[P, R]):
1267
1275
  @asynccontextmanager
1268
1276
  async def start(self) -> AsyncGenerator[None, None]:
1269
1277
  async with self.initialize_run():
1270
- with trace.use_span(
1271
- self._telemetry.span
1272
- ) if self._telemetry.span else nullcontext():
1278
+ with (
1279
+ trace.use_span(self._telemetry.span)
1280
+ if self._telemetry.span
1281
+ else nullcontext()
1282
+ ):
1273
1283
  await self.begin_run()
1274
1284
 
1275
- if self.state.is_running():
1276
- await self.call_hooks()
1277
1285
  yield
1278
1286
 
1279
1287
  @asynccontextmanager
@@ -1295,9 +1303,6 @@ class AsyncFlowRunEngine(BaseFlowRunEngine[P, R]):
1295
1303
  except Exception as exc:
1296
1304
  self.logger.exception("Encountered exception during execution: %r", exc)
1297
1305
  await self.handle_exception(exc)
1298
- finally:
1299
- if self.state.is_final() or self.state.is_cancelling():
1300
- await self.call_hooks()
1301
1306
 
1302
1307
  async def call_flow_fn(self) -> Coroutine[Any, Any, R]:
1303
1308
  """
@@ -1432,25 +1437,36 @@ def run_flow(
1432
1437
  parameters: Optional[Dict[str, Any]] = None,
1433
1438
  wait_for: Optional[Iterable[PrefectFuture[R]]] = None,
1434
1439
  return_type: Literal["state", "result"] = "result",
1440
+ error_logger: Optional[logging.Logger] = None,
1435
1441
  ) -> Union[R, State, None]:
1436
- kwargs = dict(
1437
- flow=flow,
1438
- flow_run=flow_run,
1439
- parameters=_flow_parameters(
1440
- flow=flow, flow_run=flow_run, parameters=parameters
1441
- ),
1442
- wait_for=wait_for,
1443
- return_type=return_type,
1444
- )
1442
+ ret_val: Union[R, State, None] = None
1443
+
1444
+ try:
1445
+ kwargs: dict[str, Any] = dict(
1446
+ flow=flow,
1447
+ flow_run=flow_run,
1448
+ parameters=_flow_parameters(
1449
+ flow=flow, flow_run=flow_run, parameters=parameters
1450
+ ),
1451
+ wait_for=wait_for,
1452
+ return_type=return_type,
1453
+ )
1445
1454
 
1446
- if flow.isasync and flow.isgenerator:
1447
- return run_generator_flow_async(**kwargs)
1448
- elif flow.isgenerator:
1449
- return run_generator_flow_sync(**kwargs)
1450
- elif flow.isasync:
1451
- return run_flow_async(**kwargs)
1452
- else:
1453
- return run_flow_sync(**kwargs)
1455
+ if flow.isasync and flow.isgenerator:
1456
+ ret_val = run_generator_flow_async(**kwargs)
1457
+ elif flow.isgenerator:
1458
+ ret_val = run_generator_flow_sync(**kwargs)
1459
+ elif flow.isasync:
1460
+ ret_val = run_flow_async(**kwargs)
1461
+ else:
1462
+ ret_val = run_flow_sync(**kwargs)
1463
+ except:
1464
+ if error_logger:
1465
+ error_logger.error(
1466
+ "Engine execution exited with unexpected exception", exc_info=True
1467
+ )
1468
+ raise
1469
+ return ret_val
1454
1470
 
1455
1471
 
1456
1472
  def _flow_parameters(
prefect/flows.py CHANGED
@@ -2,6 +2,8 @@
2
2
  Module containing the base workflow class and decorator - for most use cases, using the [`@flow` decorator][prefect.flows.flow] is preferred.
3
3
  """
4
4
 
5
+ from __future__ import annotations
6
+
5
7
  # This file requires type-checking with pyright because mypy does not yet support PEP612
6
8
  # See https://github.com/python/mypy/issues/8645
7
9
  import ast
@@ -43,6 +45,7 @@ from pydantic.v1.errors import ConfigError # TODO
43
45
  from rich.console import Console
44
46
  from typing_extensions import Literal, ParamSpec, TypeAlias
45
47
 
48
+ from prefect._experimental.sla.objects import SlaTypes
46
49
  from prefect._internal.concurrency.api import create_call, from_async
47
50
  from prefect.blocks.core import Block
48
51
  from prefect.client.schemas.actions import DeploymentScheduleCreate
@@ -651,6 +654,7 @@ class Flow(Generic[P, R]):
651
654
  work_queue_name: Optional[str] = None,
652
655
  job_variables: Optional[dict[str, Any]] = None,
653
656
  entrypoint_type: EntrypointType = EntrypointType.FILE_PATH,
657
+ _sla: Optional[Union[SlaTypes, list[SlaTypes]]] = None, # experimental
654
658
  ) -> "RunnerDeployment":
655
659
  """
656
660
  Creates a runner deployment object for this flow.
@@ -681,6 +685,7 @@ class Flow(Generic[P, R]):
681
685
  of the chosen work pool. Refer to the base job template of the chosen work pool for
682
686
  entrypoint_type: Type of entrypoint to use for the deployment. When using a module path
683
687
  entrypoint, ensure that the module will be importable in the execution environment.
688
+ _sla: (Experimental) SLA configuration for the deployment. May be removed or modified at any time. Currently only supported on Prefect Cloud.
684
689
 
685
690
  Examples:
686
691
  Prepare two deployments and serve them:
@@ -728,6 +733,7 @@ class Flow(Generic[P, R]):
728
733
  work_pool_name=work_pool_name,
729
734
  work_queue_name=work_queue_name,
730
735
  job_variables=job_variables,
736
+ _sla=_sla,
731
737
  ) # type: ignore # TODO: remove sync_compatible
732
738
  else:
733
739
  return RunnerDeployment.from_flow(
@@ -749,6 +755,7 @@ class Flow(Generic[P, R]):
749
755
  work_queue_name=work_queue_name,
750
756
  job_variables=job_variables,
751
757
  entrypoint_type=entrypoint_type,
758
+ _sla=_sla,
752
759
  )
753
760
 
754
761
  def on_completion(self, fn: StateHookCallable) -> StateHookCallable:
@@ -1061,6 +1068,7 @@ class Flow(Generic[P, R]):
1061
1068
  entrypoint_type: EntrypointType = EntrypointType.FILE_PATH,
1062
1069
  print_next_steps: bool = True,
1063
1070
  ignore_warnings: bool = False,
1071
+ _sla: Optional[Union[SlaTypes, list[SlaTypes]]] = None,
1064
1072
  ) -> UUID:
1065
1073
  """
1066
1074
  Deploys a flow to run on dynamic infrastructure via a work pool.
@@ -1112,7 +1120,7 @@ class Flow(Generic[P, R]):
1112
1120
  print_next_steps_message: Whether or not to print a message with next steps
1113
1121
  after deploying the deployments.
1114
1122
  ignore_warnings: Whether or not to ignore warnings about the work pool type.
1115
-
1123
+ _sla: (Experimental) SLA configuration for the deployment. May be removed or modified at any time. Currently only supported on Prefect Cloud.
1116
1124
  Returns:
1117
1125
  The ID of the created/updated deployment.
1118
1126
 
@@ -1190,6 +1198,7 @@ class Flow(Generic[P, R]):
1190
1198
  work_queue_name=work_queue_name,
1191
1199
  job_variables=job_variables,
1192
1200
  entrypoint_type=entrypoint_type,
1201
+ _sla=_sla,
1193
1202
  )
1194
1203
 
1195
1204
  from prefect.deployments.runner import deploy
@@ -64,6 +64,7 @@ from inspect import isclass
64
64
  from typing import (
65
65
  TYPE_CHECKING,
66
66
  Any,
67
+ ClassVar,
67
68
  Dict,
68
69
  Generic,
69
70
  Literal,
@@ -144,7 +145,7 @@ class RunInputMetadata(pydantic.BaseModel):
144
145
 
145
146
 
146
147
  class RunInput(pydantic.BaseModel):
147
- model_config = ConfigDict(extra="forbid")
148
+ model_config: ClassVar[ConfigDict] = ConfigDict(extra="forbid")
148
149
 
149
150
  _description: Optional[str] = pydantic.PrivateAttr(default=None)
150
151
  _metadata: RunInputMetadata = pydantic.PrivateAttr()
@@ -32,7 +32,7 @@ formatters:
32
32
  # Define any custom filters to drops records containing
33
33
  # sensitive information
34
34
  # my_filter:
35
- # class: your_module.FilterClass
35
+ # (): your_module.FilterClass
36
36
 
37
37
  handlers:
38
38
  # The handlers we define here will output all logs they receive by default
prefect/main.py CHANGED
@@ -1,6 +1,5 @@
1
1
  # Import user-facing API
2
2
  from typing import Any
3
-
4
3
  from prefect.deployments import deploy
5
4
  from prefect.states import State
6
5
  from prefect.logging import get_run_logger
@@ -9,7 +8,7 @@ from prefect.transactions import Transaction
9
8
  from prefect.tasks import task, Task
10
9
  from prefect.context import tags
11
10
  from prefect.utilities.annotations import unmapped, allow_failure
12
- from prefect.results import BaseResult, ResultRecordMetadata
11
+ from prefect.results import ResultRecordMetadata
13
12
  from prefect.flow_runs import pause_flow_run, resume_flow_run, suspend_flow_run
14
13
  from prefect.client.orchestration import get_client
15
14
  from prefect.client.cloud import get_cloud_client
@@ -30,7 +29,6 @@ import prefect.client.schemas
30
29
  _types: dict[str, Any] = dict(
31
30
  Task=Task,
32
31
  Flow=Flow,
33
- BaseResult=BaseResult,
34
32
  ResultRecordMetadata=ResultRecordMetadata,
35
33
  )
36
34
  prefect.context.FlowRunContext.model_rebuild(_types_namespace=_types)