prefect-client 3.1.11__py3-none-any.whl → 3.1.13__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/sla/__init__.py +0 -0
- prefect/_experimental/sla/client.py +92 -0
- prefect/_experimental/sla/objects.py +61 -0
- prefect/_internal/concurrency/services.py +2 -2
- prefect/_internal/concurrency/threads.py +6 -0
- prefect/_internal/retries.py +6 -3
- prefect/_internal/schemas/validators.py +6 -4
- prefect/_version.py +3 -3
- prefect/artifacts.py +4 -1
- prefect/automations.py +236 -30
- prefect/blocks/__init__.py +3 -3
- prefect/blocks/abstract.py +57 -31
- prefect/blocks/core.py +181 -82
- prefect/blocks/notifications.py +134 -73
- prefect/blocks/redis.py +13 -9
- prefect/blocks/system.py +24 -11
- prefect/blocks/webhook.py +7 -5
- prefect/cache_policies.py +23 -22
- prefect/client/orchestration/__init__.py +103 -2006
- 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/_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/client.py +16 -14
- prefect/client/schemas/__init__.py +68 -28
- prefect/client/schemas/objects.py +5 -5
- prefect/client/utilities.py +3 -3
- prefect/context.py +15 -1
- prefect/deployments/base.py +13 -4
- prefect/deployments/flow_runs.py +5 -1
- prefect/deployments/runner.py +37 -1
- prefect/deployments/steps/core.py +1 -1
- prefect/deployments/steps/pull.py +8 -3
- prefect/deployments/steps/utility.py +2 -2
- prefect/docker/docker_image.py +13 -9
- prefect/engine.py +33 -11
- prefect/events/cli/automations.py +4 -4
- prefect/events/clients.py +17 -14
- prefect/events/schemas/automations.py +12 -8
- prefect/events/schemas/events.py +5 -1
- prefect/events/worker.py +1 -1
- prefect/filesystems.py +7 -3
- prefect/flow_engine.py +64 -47
- prefect/flows.py +128 -74
- prefect/futures.py +14 -7
- prefect/infrastructure/provisioners/__init__.py +2 -0
- prefect/infrastructure/provisioners/cloud_run.py +4 -4
- prefect/infrastructure/provisioners/coiled.py +249 -0
- prefect/infrastructure/provisioners/container_instance.py +4 -3
- prefect/infrastructure/provisioners/ecs.py +55 -43
- prefect/infrastructure/provisioners/modal.py +5 -4
- prefect/input/actions.py +5 -1
- prefect/input/run_input.py +157 -43
- prefect/logging/configuration.py +3 -3
- prefect/logging/filters.py +2 -2
- prefect/logging/formatters.py +15 -11
- prefect/logging/handlers.py +24 -14
- prefect/logging/highlighters.py +5 -5
- prefect/logging/loggers.py +28 -18
- prefect/logging/logging.yml +1 -1
- prefect/main.py +3 -1
- prefect/results.py +166 -86
- prefect/runner/runner.py +38 -29
- prefect/runner/server.py +3 -1
- prefect/runner/storage.py +18 -18
- prefect/runner/submit.py +19 -12
- prefect/runtime/deployment.py +15 -8
- prefect/runtime/flow_run.py +19 -6
- prefect/runtime/task_run.py +7 -3
- prefect/settings/base.py +17 -7
- prefect/settings/legacy.py +4 -4
- prefect/settings/models/api.py +4 -3
- prefect/settings/models/cli.py +4 -3
- prefect/settings/models/client.py +7 -4
- prefect/settings/models/cloud.py +9 -3
- prefect/settings/models/deployments.py +4 -3
- prefect/settings/models/experiments.py +4 -8
- prefect/settings/models/flows.py +4 -3
- prefect/settings/models/internal.py +4 -3
- prefect/settings/models/logging.py +8 -6
- prefect/settings/models/results.py +4 -3
- prefect/settings/models/root.py +11 -16
- prefect/settings/models/runner.py +8 -5
- prefect/settings/models/server/api.py +6 -3
- prefect/settings/models/server/database.py +120 -25
- prefect/settings/models/server/deployments.py +4 -3
- prefect/settings/models/server/ephemeral.py +7 -4
- prefect/settings/models/server/events.py +6 -3
- prefect/settings/models/server/flow_run_graph.py +4 -3
- prefect/settings/models/server/root.py +4 -3
- prefect/settings/models/server/services.py +15 -12
- prefect/settings/models/server/tasks.py +7 -4
- prefect/settings/models/server/ui.py +4 -3
- prefect/settings/models/tasks.py +10 -5
- prefect/settings/models/testing.py +4 -3
- prefect/settings/models/worker.py +7 -4
- prefect/settings/profiles.py +13 -12
- prefect/settings/sources.py +20 -19
- prefect/states.py +74 -51
- prefect/task_engine.py +43 -33
- prefect/task_runners.py +85 -72
- prefect/task_runs.py +20 -11
- prefect/task_worker.py +14 -9
- prefect/tasks.py +36 -28
- prefect/telemetry/bootstrap.py +13 -9
- prefect/telemetry/run_telemetry.py +15 -13
- prefect/telemetry/services.py +4 -0
- prefect/transactions.py +3 -3
- prefect/types/__init__.py +3 -1
- prefect/utilities/_deprecated.py +38 -0
- prefect/utilities/engine.py +11 -4
- prefect/utilities/filesystem.py +2 -2
- prefect/utilities/generics.py +1 -1
- prefect/utilities/pydantic.py +21 -36
- prefect/utilities/templating.py +25 -1
- prefect/workers/base.py +58 -33
- prefect/workers/process.py +20 -15
- prefect/workers/server.py +4 -5
- {prefect_client-3.1.11.dist-info → prefect_client-3.1.13.dist-info}/METADATA +3 -3
- {prefect_client-3.1.11.dist-info → prefect_client-3.1.13.dist-info}/RECORD +133 -114
- {prefect_client-3.1.11.dist-info → prefect_client-3.1.13.dist-info}/LICENSE +0 -0
- {prefect_client-3.1.11.dist-info → prefect_client-3.1.13.dist-info}/WHEEL +0 -0
- {prefect_client-3.1.11.dist-info → prefect_client-3.1.13.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,
|
@@ -103,13 +104,15 @@ class FlowRunTimeoutError(TimeoutError):
|
|
103
104
|
"""Raised when a flow run exceeds its defined timeout."""
|
104
105
|
|
105
106
|
|
106
|
-
def
|
107
|
-
|
108
|
-
|
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
|
109
111
|
|
110
|
-
client = cast(SyncPrefectClient, get_client(sync_client=True))
|
111
112
|
|
112
|
-
|
113
|
+
def load_flow(flow_run: FlowRun) -> Flow[..., Any]:
|
114
|
+
entrypoint = os.environ.get("PREFECT__FLOW_ENTRYPOINT")
|
115
|
+
|
113
116
|
if entrypoint:
|
114
117
|
# we should not accept a placeholder flow at runtime
|
115
118
|
flow = load_flow_from_entrypoint(entrypoint, use_placeholder_flow=False)
|
@@ -117,7 +120,12 @@ def load_flow_and_flow_run(flow_run_id: UUID) -> Tuple[FlowRun, Flow]:
|
|
117
120
|
flow = run_coro_as_sync(
|
118
121
|
load_flow_from_flow_run(flow_run, use_placeholder_flow=False)
|
119
122
|
)
|
123
|
+
return flow
|
120
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)
|
121
129
|
return flow_run, flow
|
122
130
|
|
123
131
|
|
@@ -128,7 +136,7 @@ class BaseFlowRunEngine(Generic[P, R]):
|
|
128
136
|
flow_run: Optional[FlowRun] = None
|
129
137
|
flow_run_id: Optional[UUID] = None
|
130
138
|
logger: logging.Logger = field(default_factory=lambda: get_logger("engine"))
|
131
|
-
wait_for: Optional[Iterable[PrefectFuture]] = None
|
139
|
+
wait_for: Optional[Iterable[PrefectFuture[Any]]] = None
|
132
140
|
# holds the return value from the user code
|
133
141
|
_return_value: Union[R, Type[NotSet]] = NotSet
|
134
142
|
# holds the exception raised by the user code, if any
|
@@ -138,7 +146,7 @@ class BaseFlowRunEngine(Generic[P, R]):
|
|
138
146
|
_flow_run_name_set: bool = False
|
139
147
|
_telemetry: RunTelemetry = field(default_factory=RunTelemetry)
|
140
148
|
|
141
|
-
def __post_init__(self):
|
149
|
+
def __post_init__(self) -> None:
|
142
150
|
if self.flow is None and self.flow_run_id is None:
|
143
151
|
raise ValueError("Either a flow or a flow_run_id must be provided.")
|
144
152
|
|
@@ -159,7 +167,7 @@ class BaseFlowRunEngine(Generic[P, R]):
|
|
159
167
|
return False # TODO: handle this differently?
|
160
168
|
return getattr(self, "flow_run").state.is_pending()
|
161
169
|
|
162
|
-
def cancel_all_tasks(self):
|
170
|
+
def cancel_all_tasks(self) -> None:
|
163
171
|
if hasattr(self.flow.task_runner, "cancel_all"):
|
164
172
|
self.flow.task_runner.cancel_all() # type: ignore
|
165
173
|
|
@@ -200,6 +208,8 @@ class BaseFlowRunEngine(Generic[P, R]):
|
|
200
208
|
@dataclass
|
201
209
|
class FlowRunEngine(BaseFlowRunEngine[P, R]):
|
202
210
|
_client: Optional[SyncPrefectClient] = None
|
211
|
+
flow_run: FlowRun | None = None
|
212
|
+
parameters: dict[str, Any] | None = None
|
203
213
|
|
204
214
|
@property
|
205
215
|
def client(self) -> SyncPrefectClient:
|
@@ -209,7 +219,7 @@ class FlowRunEngine(BaseFlowRunEngine[P, R]):
|
|
209
219
|
|
210
220
|
def _resolve_parameters(self):
|
211
221
|
if not self.parameters:
|
212
|
-
return
|
222
|
+
return
|
213
223
|
|
214
224
|
resolved_parameters = {}
|
215
225
|
for parameter, value in self.parameters.items():
|
@@ -277,7 +287,6 @@ class FlowRunEngine(BaseFlowRunEngine[P, R]):
|
|
277
287
|
),
|
278
288
|
)
|
279
289
|
self.short_circuit = True
|
280
|
-
self.call_hooks()
|
281
290
|
|
282
291
|
new_state = Running()
|
283
292
|
state = self.set_state(new_state)
|
@@ -300,6 +309,7 @@ class FlowRunEngine(BaseFlowRunEngine[P, R]):
|
|
300
309
|
self.flow_run.state_type = state.type # type: ignore
|
301
310
|
|
302
311
|
self._telemetry.update_state(state)
|
312
|
+
self.call_hooks(state)
|
303
313
|
return state
|
304
314
|
|
305
315
|
def result(self, raise_on_failure: bool = True) -> "Union[R, State, None]":
|
@@ -494,7 +504,7 @@ class FlowRunEngine(BaseFlowRunEngine[P, R]):
|
|
494
504
|
tags=TagsContext.get().current_tags,
|
495
505
|
)
|
496
506
|
|
497
|
-
def call_hooks(self, state: Optional[State] = None):
|
507
|
+
def call_hooks(self, state: Optional[State] = None) -> None:
|
498
508
|
if state is None:
|
499
509
|
state = self.state
|
500
510
|
flow = self.flow
|
@@ -592,7 +602,9 @@ class FlowRunEngine(BaseFlowRunEngine[P, R]):
|
|
592
602
|
|
593
603
|
# set the logger to the flow run logger
|
594
604
|
|
595
|
-
self.logger = flow_run_logger(
|
605
|
+
self.logger: "logging.Logger" = flow_run_logger(
|
606
|
+
flow_run=self.flow_run, flow=self.flow
|
607
|
+
) # type: ignore
|
596
608
|
|
597
609
|
# update the flow run name if necessary
|
598
610
|
if not self._flow_run_name_set and self.flow.flow_run_name:
|
@@ -711,8 +723,6 @@ class FlowRunEngine(BaseFlowRunEngine[P, R]):
|
|
711
723
|
):
|
712
724
|
self.begin_run()
|
713
725
|
|
714
|
-
if self.state.is_running():
|
715
|
-
self.call_hooks()
|
716
726
|
yield
|
717
727
|
|
718
728
|
@contextmanager
|
@@ -734,9 +744,6 @@ class FlowRunEngine(BaseFlowRunEngine[P, R]):
|
|
734
744
|
except Exception as exc:
|
735
745
|
self.logger.exception("Encountered exception during execution: %r", exc)
|
736
746
|
self.handle_exception(exc)
|
737
|
-
finally:
|
738
|
-
if self.state.is_final() or self.state.is_cancelling():
|
739
|
-
self.call_hooks()
|
740
747
|
|
741
748
|
def call_flow_fn(self) -> Union[R, Coroutine[Any, Any, R]]:
|
742
749
|
"""
|
@@ -765,6 +772,8 @@ class AsyncFlowRunEngine(BaseFlowRunEngine[P, R]):
|
|
765
772
|
"""
|
766
773
|
|
767
774
|
_client: Optional[PrefectClient] = None
|
775
|
+
parameters: dict[str, Any] | None = None
|
776
|
+
flow_run: FlowRun | None = None
|
768
777
|
|
769
778
|
@property
|
770
779
|
def client(self) -> PrefectClient:
|
@@ -774,7 +783,7 @@ class AsyncFlowRunEngine(BaseFlowRunEngine[P, R]):
|
|
774
783
|
|
775
784
|
def _resolve_parameters(self):
|
776
785
|
if not self.parameters:
|
777
|
-
return
|
786
|
+
return
|
778
787
|
|
779
788
|
resolved_parameters = {}
|
780
789
|
for parameter, value in self.parameters.items():
|
@@ -842,7 +851,6 @@ class AsyncFlowRunEngine(BaseFlowRunEngine[P, R]):
|
|
842
851
|
),
|
843
852
|
)
|
844
853
|
self.short_circuit = True
|
845
|
-
await self.call_hooks()
|
846
854
|
|
847
855
|
new_state = Running()
|
848
856
|
state = await self.set_state(new_state)
|
@@ -865,6 +873,7 @@ class AsyncFlowRunEngine(BaseFlowRunEngine[P, R]):
|
|
865
873
|
self.flow_run.state_type = state.type # type: ignore
|
866
874
|
|
867
875
|
self._telemetry.update_state(state)
|
876
|
+
await self.call_hooks(state)
|
868
877
|
return state
|
869
878
|
|
870
879
|
async def result(self, raise_on_failure: bool = True) -> "Union[R, State, None]":
|
@@ -1058,7 +1067,7 @@ class AsyncFlowRunEngine(BaseFlowRunEngine[P, R]):
|
|
1058
1067
|
tags=TagsContext.get().current_tags,
|
1059
1068
|
)
|
1060
1069
|
|
1061
|
-
async def call_hooks(self, state: Optional[State] = None):
|
1070
|
+
async def call_hooks(self, state: Optional[State] = None) -> None:
|
1062
1071
|
if state is None:
|
1063
1072
|
state = self.state
|
1064
1073
|
flow = self.flow
|
@@ -1155,7 +1164,9 @@ class AsyncFlowRunEngine(BaseFlowRunEngine[P, R]):
|
|
1155
1164
|
stack.enter_context(ConcurrencyContext())
|
1156
1165
|
|
1157
1166
|
# set the logger to the flow run logger
|
1158
|
-
self.logger = flow_run_logger(
|
1167
|
+
self.logger: "logging.Logger" = flow_run_logger(
|
1168
|
+
flow_run=self.flow_run, flow=self.flow
|
1169
|
+
)
|
1159
1170
|
|
1160
1171
|
# update the flow run name if necessary
|
1161
1172
|
|
@@ -1279,8 +1290,6 @@ class AsyncFlowRunEngine(BaseFlowRunEngine[P, R]):
|
|
1279
1290
|
):
|
1280
1291
|
await self.begin_run()
|
1281
1292
|
|
1282
|
-
if self.state.is_running():
|
1283
|
-
await self.call_hooks()
|
1284
1293
|
yield
|
1285
1294
|
|
1286
1295
|
@asynccontextmanager
|
@@ -1302,9 +1311,6 @@ class AsyncFlowRunEngine(BaseFlowRunEngine[P, R]):
|
|
1302
1311
|
except Exception as exc:
|
1303
1312
|
self.logger.exception("Encountered exception during execution: %r", exc)
|
1304
1313
|
await self.handle_exception(exc)
|
1305
|
-
finally:
|
1306
|
-
if self.state.is_final() or self.state.is_cancelling():
|
1307
|
-
await self.call_hooks()
|
1308
1314
|
|
1309
1315
|
async def call_flow_fn(self) -> Coroutine[Any, Any, R]:
|
1310
1316
|
"""
|
@@ -1322,7 +1328,7 @@ def run_flow_sync(
|
|
1322
1328
|
flow: Flow[P, R],
|
1323
1329
|
flow_run: Optional[FlowRun] = None,
|
1324
1330
|
parameters: Optional[Dict[str, Any]] = None,
|
1325
|
-
wait_for: Optional[Iterable[PrefectFuture]] = None,
|
1331
|
+
wait_for: Optional[Iterable[PrefectFuture[Any]]] = None,
|
1326
1332
|
return_type: Literal["state", "result"] = "result",
|
1327
1333
|
) -> Union[R, State, None]:
|
1328
1334
|
engine = FlowRunEngine[P, R](
|
@@ -1344,7 +1350,7 @@ async def run_flow_async(
|
|
1344
1350
|
flow: Flow[P, R],
|
1345
1351
|
flow_run: Optional[FlowRun] = None,
|
1346
1352
|
parameters: Optional[Dict[str, Any]] = None,
|
1347
|
-
wait_for: Optional[Iterable[PrefectFuture]] = None,
|
1353
|
+
wait_for: Optional[Iterable[PrefectFuture[Any]]] = None,
|
1348
1354
|
return_type: Literal["state", "result"] = "result",
|
1349
1355
|
) -> Union[R, State, None]:
|
1350
1356
|
engine = AsyncFlowRunEngine[P, R](
|
@@ -1363,7 +1369,7 @@ def run_generator_flow_sync(
|
|
1363
1369
|
flow: Flow[P, R],
|
1364
1370
|
flow_run: Optional[FlowRun] = None,
|
1365
1371
|
parameters: Optional[Dict[str, Any]] = None,
|
1366
|
-
wait_for: Optional[Iterable[PrefectFuture]] = None,
|
1372
|
+
wait_for: Optional[Iterable[PrefectFuture[Any]]] = None,
|
1367
1373
|
return_type: Literal["state", "result"] = "result",
|
1368
1374
|
) -> Generator[R, None, None]:
|
1369
1375
|
if return_type != "result":
|
@@ -1439,25 +1445,36 @@ def run_flow(
|
|
1439
1445
|
parameters: Optional[Dict[str, Any]] = None,
|
1440
1446
|
wait_for: Optional[Iterable[PrefectFuture[R]]] = None,
|
1441
1447
|
return_type: Literal["state", "result"] = "result",
|
1448
|
+
error_logger: Optional[logging.Logger] = None,
|
1442
1449
|
) -> Union[R, State, None]:
|
1443
|
-
|
1444
|
-
|
1445
|
-
|
1446
|
-
|
1447
|
-
flow=flow,
|
1448
|
-
|
1449
|
-
|
1450
|
-
|
1451
|
-
|
1450
|
+
ret_val: Union[R, State, None] = None
|
1451
|
+
|
1452
|
+
try:
|
1453
|
+
kwargs: dict[str, Any] = dict(
|
1454
|
+
flow=flow,
|
1455
|
+
flow_run=flow_run,
|
1456
|
+
parameters=_flow_parameters(
|
1457
|
+
flow=flow, flow_run=flow_run, parameters=parameters
|
1458
|
+
),
|
1459
|
+
wait_for=wait_for,
|
1460
|
+
return_type=return_type,
|
1461
|
+
)
|
1452
1462
|
|
1453
|
-
|
1454
|
-
|
1455
|
-
|
1456
|
-
|
1457
|
-
|
1458
|
-
|
1459
|
-
|
1460
|
-
|
1463
|
+
if flow.isasync and flow.isgenerator:
|
1464
|
+
ret_val = run_generator_flow_async(**kwargs)
|
1465
|
+
elif flow.isgenerator:
|
1466
|
+
ret_val = run_generator_flow_sync(**kwargs)
|
1467
|
+
elif flow.isasync:
|
1468
|
+
ret_val = run_flow_async(**kwargs)
|
1469
|
+
else:
|
1470
|
+
ret_val = run_flow_sync(**kwargs)
|
1471
|
+
except:
|
1472
|
+
if error_logger:
|
1473
|
+
error_logger.error(
|
1474
|
+
"Engine execution exited with unexpected exception", exc_info=True
|
1475
|
+
)
|
1476
|
+
raise
|
1477
|
+
return ret_val
|
1461
1478
|
|
1462
1479
|
|
1463
1480
|
def _flow_parameters(
|