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.
- prefect/_experimental/lineage.py +7 -8
- prefect/_experimental/sla/__init__.py +0 -0
- prefect/_experimental/sla/client.py +66 -0
- prefect/_experimental/sla/objects.py +53 -0
- prefect/_internal/_logging.py +15 -3
- prefect/_internal/compatibility/async_dispatch.py +22 -16
- prefect/_internal/compatibility/deprecated.py +42 -18
- prefect/_internal/compatibility/migration.py +2 -2
- prefect/_internal/concurrency/inspection.py +12 -14
- prefect/_internal/concurrency/primitives.py +2 -2
- prefect/_internal/concurrency/services.py +154 -80
- prefect/_internal/concurrency/waiters.py +13 -9
- prefect/_internal/pydantic/annotations/pendulum.py +7 -7
- prefect/_internal/pytz.py +4 -3
- prefect/_internal/retries.py +10 -5
- prefect/_internal/schemas/bases.py +19 -10
- prefect/_internal/schemas/validators.py +227 -388
- prefect/_version.py +3 -3
- prefect/automations.py +236 -30
- prefect/blocks/__init__.py +3 -3
- prefect/blocks/abstract.py +53 -30
- prefect/blocks/core.py +183 -84
- prefect/blocks/notifications.py +133 -73
- prefect/blocks/redis.py +13 -9
- prefect/blocks/system.py +24 -11
- prefect/blocks/webhook.py +7 -5
- prefect/cache_policies.py +3 -2
- prefect/client/orchestration/__init__.py +1957 -0
- prefect/client/orchestration/_artifacts/__init__.py +0 -0
- prefect/client/orchestration/_artifacts/client.py +239 -0
- prefect/client/orchestration/_automations/__init__.py +0 -0
- prefect/client/orchestration/_automations/client.py +329 -0
- prefect/client/orchestration/_blocks_documents/__init__.py +0 -0
- prefect/client/orchestration/_blocks_documents/client.py +334 -0
- prefect/client/orchestration/_blocks_schemas/__init__.py +0 -0
- prefect/client/orchestration/_blocks_schemas/client.py +200 -0
- prefect/client/orchestration/_blocks_types/__init__.py +0 -0
- prefect/client/orchestration/_blocks_types/client.py +380 -0
- prefect/client/orchestration/_concurrency_limits/__init__.py +0 -0
- prefect/client/orchestration/_concurrency_limits/client.py +762 -0
- prefect/client/orchestration/_deployments/__init__.py +0 -0
- prefect/client/orchestration/_deployments/client.py +1128 -0
- prefect/client/orchestration/_flow_runs/__init__.py +0 -0
- prefect/client/orchestration/_flow_runs/client.py +903 -0
- prefect/client/orchestration/_flows/__init__.py +0 -0
- prefect/client/orchestration/_flows/client.py +343 -0
- prefect/client/orchestration/_logs/__init__.py +0 -0
- prefect/client/orchestration/_logs/client.py +97 -0
- prefect/client/orchestration/_variables/__init__.py +0 -0
- prefect/client/orchestration/_variables/client.py +157 -0
- prefect/client/orchestration/base.py +46 -0
- prefect/client/orchestration/routes.py +145 -0
- prefect/client/schemas/__init__.py +68 -28
- prefect/client/schemas/actions.py +2 -2
- prefect/client/schemas/filters.py +5 -0
- prefect/client/schemas/objects.py +8 -15
- prefect/client/schemas/schedules.py +22 -10
- prefect/concurrency/_asyncio.py +87 -0
- prefect/concurrency/{events.py → _events.py} +10 -10
- prefect/concurrency/asyncio.py +20 -104
- prefect/concurrency/context.py +6 -4
- prefect/concurrency/services.py +26 -74
- prefect/concurrency/sync.py +23 -44
- prefect/concurrency/v1/_asyncio.py +63 -0
- prefect/concurrency/v1/{events.py → _events.py} +13 -15
- prefect/concurrency/v1/asyncio.py +27 -80
- prefect/concurrency/v1/context.py +6 -4
- prefect/concurrency/v1/services.py +33 -79
- prefect/concurrency/v1/sync.py +18 -37
- prefect/context.py +66 -45
- prefect/deployments/base.py +10 -144
- prefect/deployments/flow_runs.py +12 -2
- prefect/deployments/runner.py +53 -4
- prefect/deployments/steps/pull.py +13 -0
- prefect/engine.py +17 -4
- prefect/events/clients.py +7 -1
- prefect/events/schemas/events.py +3 -2
- prefect/filesystems.py +6 -2
- prefect/flow_engine.py +101 -85
- prefect/flows.py +10 -1
- prefect/input/run_input.py +2 -1
- prefect/logging/logging.yml +1 -1
- prefect/main.py +1 -3
- prefect/results.py +2 -307
- prefect/runner/runner.py +4 -2
- prefect/runner/storage.py +87 -21
- prefect/serializers.py +32 -25
- prefect/settings/legacy.py +4 -4
- prefect/settings/models/api.py +3 -3
- prefect/settings/models/cli.py +3 -3
- prefect/settings/models/client.py +5 -3
- prefect/settings/models/cloud.py +8 -3
- prefect/settings/models/deployments.py +3 -3
- prefect/settings/models/experiments.py +4 -7
- prefect/settings/models/flows.py +3 -3
- prefect/settings/models/internal.py +4 -2
- prefect/settings/models/logging.py +4 -3
- prefect/settings/models/results.py +3 -3
- prefect/settings/models/root.py +3 -2
- prefect/settings/models/runner.py +4 -4
- prefect/settings/models/server/api.py +3 -3
- prefect/settings/models/server/database.py +11 -4
- prefect/settings/models/server/deployments.py +6 -2
- prefect/settings/models/server/ephemeral.py +4 -2
- prefect/settings/models/server/events.py +3 -2
- prefect/settings/models/server/flow_run_graph.py +6 -2
- prefect/settings/models/server/root.py +3 -3
- prefect/settings/models/server/services.py +26 -11
- prefect/settings/models/server/tasks.py +6 -3
- prefect/settings/models/server/ui.py +3 -3
- prefect/settings/models/tasks.py +5 -5
- prefect/settings/models/testing.py +3 -3
- prefect/settings/models/worker.py +5 -3
- prefect/settings/profiles.py +15 -2
- prefect/states.py +61 -45
- prefect/task_engine.py +54 -75
- prefect/task_runners.py +56 -55
- prefect/task_worker.py +2 -2
- prefect/tasks.py +90 -36
- prefect/telemetry/bootstrap.py +10 -9
- prefect/telemetry/run_telemetry.py +13 -8
- prefect/telemetry/services.py +4 -0
- prefect/transactions.py +4 -15
- prefect/utilities/_git.py +34 -0
- prefect/utilities/asyncutils.py +1 -1
- prefect/utilities/engine.py +3 -19
- prefect/utilities/generics.py +18 -0
- prefect/utilities/templating.py +25 -1
- prefect/workers/base.py +6 -3
- prefect/workers/process.py +1 -1
- {prefect_client-3.1.10.dist-info → prefect_client-3.1.12.dist-info}/METADATA +2 -2
- {prefect_client-3.1.10.dist-info → prefect_client-3.1.12.dist-info}/RECORD +135 -109
- prefect/client/orchestration.py +0 -4523
- prefect/records/__init__.py +0 -1
- prefect/records/base.py +0 -235
- prefect/records/filesystem.py +0 -213
- prefect/records/memory.py +0 -184
- prefect/records/result_store.py +0 -70
- {prefect_client-3.1.10.dist-info → prefect_client-3.1.12.dist-info}/LICENSE +0 -0
- {prefect_client-3.1.10.dist-info → prefect_client-3.1.12.dist-info}/WHEEL +0 -0
- {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
|
108
|
-
|
109
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
709
|
-
self._telemetry.span
|
710
|
-
|
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
|
-
|
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
|
-
|
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
|
1271
|
-
self._telemetry.span
|
1272
|
-
|
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
|
-
|
1437
|
-
|
1438
|
-
|
1439
|
-
|
1440
|
-
flow=flow,
|
1441
|
-
|
1442
|
-
|
1443
|
-
|
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
|
-
|
1447
|
-
|
1448
|
-
|
1449
|
-
|
1450
|
-
|
1451
|
-
|
1452
|
-
|
1453
|
-
|
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
|
prefect/input/run_input.py
CHANGED
@@ -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()
|
prefect/logging/logging.yml
CHANGED
@@ -32,7 +32,7 @@ formatters:
|
|
32
32
|
# Define any custom filters to drops records containing
|
33
33
|
# sensitive information
|
34
34
|
# my_filter:
|
35
|
-
#
|
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
|
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)
|