prefect-client 3.1.5__py3-none-any.whl → 3.1.6__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/__init__.py +3 -0
- prefect/_internal/compatibility/migration.py +1 -1
- prefect/_internal/concurrency/api.py +52 -52
- prefect/_internal/concurrency/calls.py +59 -35
- prefect/_internal/concurrency/cancellation.py +34 -18
- prefect/_internal/concurrency/event_loop.py +7 -6
- prefect/_internal/concurrency/threads.py +41 -33
- prefect/_internal/concurrency/waiters.py +28 -21
- prefect/_internal/pydantic/v1_schema.py +2 -2
- prefect/_internal/pydantic/v2_schema.py +10 -9
- prefect/_internal/schemas/bases.py +9 -7
- prefect/_internal/schemas/validators.py +2 -1
- prefect/_version.py +3 -3
- prefect/automations.py +53 -47
- prefect/blocks/abstract.py +12 -10
- prefect/blocks/core.py +4 -2
- prefect/cache_policies.py +11 -11
- prefect/client/__init__.py +3 -1
- prefect/client/base.py +36 -37
- prefect/client/cloud.py +26 -19
- prefect/client/collections.py +2 -2
- prefect/client/orchestration.py +342 -273
- prefect/client/schemas/__init__.py +24 -0
- prefect/client/schemas/actions.py +123 -116
- prefect/client/schemas/objects.py +110 -81
- prefect/client/schemas/responses.py +18 -18
- prefect/client/schemas/schedules.py +136 -93
- prefect/client/subscriptions.py +28 -14
- prefect/client/utilities.py +32 -36
- prefect/concurrency/asyncio.py +6 -9
- prefect/concurrency/sync.py +35 -5
- prefect/context.py +39 -31
- prefect/deployments/flow_runs.py +3 -5
- prefect/docker/__init__.py +1 -1
- prefect/events/schemas/events.py +25 -20
- prefect/events/utilities.py +1 -2
- prefect/filesystems.py +3 -3
- prefect/flow_engine.py +61 -21
- prefect/flow_runs.py +3 -3
- prefect/flows.py +214 -170
- prefect/logging/configuration.py +1 -1
- prefect/logging/highlighters.py +1 -2
- prefect/logging/loggers.py +30 -20
- prefect/main.py +17 -24
- prefect/runner/runner.py +43 -21
- prefect/runner/server.py +30 -32
- prefect/runner/submit.py +3 -6
- prefect/runner/utils.py +6 -6
- prefect/runtime/flow_run.py +7 -0
- prefect/settings/constants.py +2 -2
- prefect/settings/legacy.py +1 -1
- prefect/settings/models/server/events.py +10 -0
- prefect/task_engine.py +72 -19
- prefect/task_runners.py +2 -2
- prefect/tasks.py +46 -33
- prefect/telemetry/bootstrap.py +15 -2
- prefect/telemetry/run_telemetry.py +107 -0
- prefect/transactions.py +14 -14
- prefect/types/__init__.py +1 -4
- prefect/utilities/_engine.py +96 -0
- prefect/utilities/annotations.py +25 -18
- prefect/utilities/asyncutils.py +126 -140
- prefect/utilities/callables.py +87 -78
- prefect/utilities/collections.py +278 -117
- prefect/utilities/compat.py +13 -21
- prefect/utilities/context.py +6 -5
- prefect/utilities/dispatch.py +23 -12
- prefect/utilities/dockerutils.py +33 -32
- prefect/utilities/engine.py +126 -239
- prefect/utilities/filesystem.py +18 -15
- prefect/utilities/hashing.py +10 -11
- prefect/utilities/importtools.py +40 -27
- prefect/utilities/math.py +9 -5
- prefect/utilities/names.py +3 -3
- prefect/utilities/processutils.py +121 -57
- prefect/utilities/pydantic.py +41 -36
- prefect/utilities/render_swagger.py +22 -12
- prefect/utilities/schema_tools/__init__.py +2 -1
- prefect/utilities/schema_tools/hydration.py +50 -43
- prefect/utilities/schema_tools/validation.py +52 -42
- prefect/utilities/services.py +13 -12
- prefect/utilities/templating.py +45 -45
- prefect/utilities/text.py +2 -1
- prefect/utilities/timeout.py +4 -4
- prefect/utilities/urls.py +9 -4
- prefect/utilities/visualization.py +46 -24
- prefect/variables.py +9 -8
- prefect/workers/base.py +15 -8
- {prefect_client-3.1.5.dist-info → prefect_client-3.1.6.dist-info}/METADATA +4 -2
- {prefect_client-3.1.5.dist-info → prefect_client-3.1.6.dist-info}/RECORD +93 -91
- {prefect_client-3.1.5.dist-info → prefect_client-3.1.6.dist-info}/LICENSE +0 -0
- {prefect_client-3.1.5.dist-info → prefect_client-3.1.6.dist-info}/WHEEL +0 -0
- {prefect_client-3.1.5.dist-info → prefect_client-3.1.6.dist-info}/top_level.txt +0 -0
prefect/flow_engine.py
CHANGED
@@ -2,7 +2,7 @@ import asyncio
|
|
2
2
|
import logging
|
3
3
|
import os
|
4
4
|
import time
|
5
|
-
from contextlib import ExitStack, asynccontextmanager, contextmanager
|
5
|
+
from contextlib import ExitStack, asynccontextmanager, contextmanager, nullcontext
|
6
6
|
from dataclasses import dataclass, field
|
7
7
|
from typing import (
|
8
8
|
Any,
|
@@ -23,7 +23,7 @@ from typing import (
|
|
23
23
|
from uuid import UUID
|
24
24
|
|
25
25
|
from anyio import CancelScope
|
26
|
-
from opentelemetry import trace
|
26
|
+
from opentelemetry import propagate, trace
|
27
27
|
from opentelemetry.trace import Tracer, get_tracer
|
28
28
|
from typing_extensions import ParamSpec
|
29
29
|
|
@@ -72,6 +72,9 @@ from prefect.states import (
|
|
72
72
|
exception_to_failed_state,
|
73
73
|
return_value_to_state,
|
74
74
|
)
|
75
|
+
from prefect.telemetry.run_telemetry import OTELSetter
|
76
|
+
from prefect.types import KeyValueLabels
|
77
|
+
from prefect.utilities._engine import get_hook_name, resolve_custom_flow_run_name
|
75
78
|
from prefect.utilities.annotations import NotSet
|
76
79
|
from prefect.utilities.asyncutils import run_coro_as_sync
|
77
80
|
from prefect.utilities.callables import (
|
@@ -81,8 +84,6 @@ from prefect.utilities.callables import (
|
|
81
84
|
)
|
82
85
|
from prefect.utilities.collections import visit_collection
|
83
86
|
from prefect.utilities.engine import (
|
84
|
-
_get_hook_name,
|
85
|
-
_resolve_custom_flow_run_name,
|
86
87
|
capture_sigterm,
|
87
88
|
link_state_to_result,
|
88
89
|
propose_state,
|
@@ -94,6 +95,8 @@ from prefect.utilities.urls import url_for
|
|
94
95
|
|
95
96
|
P = ParamSpec("P")
|
96
97
|
R = TypeVar("R")
|
98
|
+
LABELS_TRACEPARENT_KEY = "__OTEL_TRACEPARENT"
|
99
|
+
TRACEPARENT_KEY = "traceparent"
|
97
100
|
|
98
101
|
|
99
102
|
class FlowRunTimeoutError(TimeoutError):
|
@@ -178,6 +181,37 @@ class BaseFlowRunEngine(Generic[P, R]):
|
|
178
181
|
if hasattr(self.flow.task_runner, "cancel_all"):
|
179
182
|
self.flow.task_runner.cancel_all() # type: ignore
|
180
183
|
|
184
|
+
def _update_otel_labels(
|
185
|
+
self, span: trace.Span, client: Union[SyncPrefectClient, PrefectClient]
|
186
|
+
):
|
187
|
+
parent_flow_run_ctx = FlowRunContext.get()
|
188
|
+
if parent_flow_run_ctx and parent_flow_run_ctx.flow_run:
|
189
|
+
if traceparent := parent_flow_run_ctx.flow_run.labels.get(
|
190
|
+
LABELS_TRACEPARENT_KEY
|
191
|
+
):
|
192
|
+
carrier: KeyValueLabels = {TRACEPARENT_KEY: traceparent}
|
193
|
+
propagate.get_global_textmap().inject(
|
194
|
+
carrier={TRACEPARENT_KEY: traceparent},
|
195
|
+
setter=OTELSetter(),
|
196
|
+
)
|
197
|
+
else:
|
198
|
+
carrier: KeyValueLabels = {}
|
199
|
+
propagate.get_global_textmap().inject(
|
200
|
+
carrier,
|
201
|
+
context=trace.set_span_in_context(span),
|
202
|
+
setter=OTELSetter(),
|
203
|
+
)
|
204
|
+
if carrier.get(TRACEPARENT_KEY):
|
205
|
+
if self.flow_run:
|
206
|
+
client.update_flow_run_labels(
|
207
|
+
flow_run_id=self.flow_run.id,
|
208
|
+
labels={LABELS_TRACEPARENT_KEY: carrier[TRACEPARENT_KEY]},
|
209
|
+
)
|
210
|
+
else:
|
211
|
+
self.logger.info(
|
212
|
+
f"Tried to set traceparent {carrier[TRACEPARENT_KEY]} for flow run, but None was found"
|
213
|
+
)
|
214
|
+
|
181
215
|
|
182
216
|
@dataclass
|
183
217
|
class FlowRunEngine(BaseFlowRunEngine[P, R]):
|
@@ -283,7 +317,7 @@ class FlowRunEngine(BaseFlowRunEngine[P, R]):
|
|
283
317
|
|
284
318
|
if self._span:
|
285
319
|
self._span.add_event(
|
286
|
-
state.name,
|
320
|
+
state.name or state.type,
|
287
321
|
{
|
288
322
|
"prefect.state.message": state.message or "",
|
289
323
|
"prefect.state.type": state.type,
|
@@ -402,7 +436,7 @@ class FlowRunEngine(BaseFlowRunEngine[P, R]):
|
|
402
436
|
self.set_state(state, force=True)
|
403
437
|
self._raised = exc
|
404
438
|
|
405
|
-
self._end_span_on_error(exc, state.message)
|
439
|
+
self._end_span_on_error(exc, state.message if state else "")
|
406
440
|
|
407
441
|
def load_subflow_run(
|
408
442
|
self,
|
@@ -537,7 +571,7 @@ class FlowRunEngine(BaseFlowRunEngine[P, R]):
|
|
537
571
|
hooks = None
|
538
572
|
|
539
573
|
for hook in hooks or []:
|
540
|
-
hook_name =
|
574
|
+
hook_name = get_hook_name(hook)
|
541
575
|
|
542
576
|
try:
|
543
577
|
self.logger.info(
|
@@ -600,7 +634,7 @@ class FlowRunEngine(BaseFlowRunEngine[P, R]):
|
|
600
634
|
|
601
635
|
# update the flow run name if necessary
|
602
636
|
if not self._flow_run_name_set and self.flow.flow_run_name:
|
603
|
-
flow_run_name =
|
637
|
+
flow_run_name = resolve_custom_flow_run_name(
|
604
638
|
flow=self.flow, parameters=self.parameters
|
605
639
|
)
|
606
640
|
self.client.set_flow_run_name(
|
@@ -647,7 +681,7 @@ class FlowRunEngine(BaseFlowRunEngine[P, R]):
|
|
647
681
|
empirical_policy=self.flow_run.empirical_policy,
|
648
682
|
)
|
649
683
|
|
650
|
-
|
684
|
+
span = self._tracer.start_span(
|
651
685
|
name=self.flow_run.name,
|
652
686
|
attributes={
|
653
687
|
**self.flow_run.labels,
|
@@ -657,6 +691,9 @@ class FlowRunEngine(BaseFlowRunEngine[P, R]):
|
|
657
691
|
"prefect.flow.name": self.flow.name,
|
658
692
|
},
|
659
693
|
)
|
694
|
+
self._update_otel_labels(span, self.client)
|
695
|
+
|
696
|
+
self._span = span
|
660
697
|
|
661
698
|
try:
|
662
699
|
yield self
|
@@ -698,12 +735,13 @@ class FlowRunEngine(BaseFlowRunEngine[P, R]):
|
|
698
735
|
|
699
736
|
@contextmanager
|
700
737
|
def start(self) -> Generator[None, None, None]:
|
701
|
-
with self.initialize_run()
|
702
|
-
self.
|
738
|
+
with self.initialize_run():
|
739
|
+
with trace.use_span(self._span) if self._span else nullcontext():
|
740
|
+
self.begin_run()
|
703
741
|
|
704
|
-
|
705
|
-
|
706
|
-
|
742
|
+
if self.state.is_running():
|
743
|
+
self.call_hooks()
|
744
|
+
yield
|
707
745
|
|
708
746
|
@contextmanager
|
709
747
|
def run_context(self):
|
@@ -856,7 +894,7 @@ class AsyncFlowRunEngine(BaseFlowRunEngine[P, R]):
|
|
856
894
|
|
857
895
|
if self._span:
|
858
896
|
self._span.add_event(
|
859
|
-
state.name,
|
897
|
+
state.name or state.type,
|
860
898
|
{
|
861
899
|
"prefect.state.message": state.message or "",
|
862
900
|
"prefect.state.type": state.type,
|
@@ -1107,7 +1145,7 @@ class AsyncFlowRunEngine(BaseFlowRunEngine[P, R]):
|
|
1107
1145
|
hooks = None
|
1108
1146
|
|
1109
1147
|
for hook in hooks or []:
|
1110
|
-
hook_name =
|
1148
|
+
hook_name = get_hook_name(hook)
|
1111
1149
|
|
1112
1150
|
try:
|
1113
1151
|
self.logger.info(
|
@@ -1170,7 +1208,7 @@ class AsyncFlowRunEngine(BaseFlowRunEngine[P, R]):
|
|
1170
1208
|
|
1171
1209
|
# update the flow run name if necessary
|
1172
1210
|
if not self._flow_run_name_set and self.flow.flow_run_name:
|
1173
|
-
flow_run_name =
|
1211
|
+
flow_run_name = resolve_custom_flow_run_name(
|
1174
1212
|
flow=self.flow, parameters=self.parameters
|
1175
1213
|
)
|
1176
1214
|
await self.client.set_flow_run_name(
|
@@ -1217,7 +1255,7 @@ class AsyncFlowRunEngine(BaseFlowRunEngine[P, R]):
|
|
1217
1255
|
empirical_policy=self.flow_run.empirical_policy,
|
1218
1256
|
)
|
1219
1257
|
|
1220
|
-
|
1258
|
+
span = self._tracer.start_span(
|
1221
1259
|
name=self.flow_run.name,
|
1222
1260
|
attributes={
|
1223
1261
|
**self.flow_run.labels,
|
@@ -1227,6 +1265,8 @@ class AsyncFlowRunEngine(BaseFlowRunEngine[P, R]):
|
|
1227
1265
|
"prefect.flow.name": self.flow.name,
|
1228
1266
|
},
|
1229
1267
|
)
|
1268
|
+
self._update_otel_labels(span, self.client)
|
1269
|
+
self._span = span
|
1230
1270
|
|
1231
1271
|
try:
|
1232
1272
|
yield self
|
@@ -1269,7 +1309,7 @@ class AsyncFlowRunEngine(BaseFlowRunEngine[P, R]):
|
|
1269
1309
|
@asynccontextmanager
|
1270
1310
|
async def start(self) -> AsyncGenerator[None, None]:
|
1271
1311
|
async with self.initialize_run():
|
1272
|
-
with trace.use_span(self._span):
|
1312
|
+
with trace.use_span(self._span) if self._span else nullcontext():
|
1273
1313
|
await self.begin_run()
|
1274
1314
|
|
1275
1315
|
if self.state.is_running():
|
@@ -1392,7 +1432,7 @@ async def run_generator_flow_async(
|
|
1392
1432
|
flow: Flow[P, R],
|
1393
1433
|
flow_run: Optional[FlowRun] = None,
|
1394
1434
|
parameters: Optional[Dict[str, Any]] = None,
|
1395
|
-
wait_for: Optional[Iterable[PrefectFuture]] = None,
|
1435
|
+
wait_for: Optional[Iterable[PrefectFuture[R]]] = None,
|
1396
1436
|
return_type: Literal["state", "result"] = "result",
|
1397
1437
|
) -> AsyncGenerator[R, None]:
|
1398
1438
|
if return_type != "result":
|
@@ -1430,7 +1470,7 @@ def run_flow(
|
|
1430
1470
|
flow: Flow[P, R],
|
1431
1471
|
flow_run: Optional[FlowRun] = None,
|
1432
1472
|
parameters: Optional[Dict[str, Any]] = None,
|
1433
|
-
wait_for: Optional[Iterable[PrefectFuture]] = None,
|
1473
|
+
wait_for: Optional[Iterable[PrefectFuture[R]]] = None,
|
1434
1474
|
return_type: Literal["state", "result"] = "result",
|
1435
1475
|
) -> Union[R, State, None]:
|
1436
1476
|
kwargs = dict(
|
prefect/flow_runs.py
CHANGED
@@ -307,7 +307,7 @@ async def suspend_flow_run(
|
|
307
307
|
flow_run_id: Optional[UUID] = None,
|
308
308
|
timeout: Optional[int] = 3600,
|
309
309
|
key: Optional[str] = None,
|
310
|
-
client: PrefectClient = None,
|
310
|
+
client: Optional[PrefectClient] = None,
|
311
311
|
) -> None:
|
312
312
|
...
|
313
313
|
|
@@ -318,7 +318,7 @@ async def suspend_flow_run(
|
|
318
318
|
flow_run_id: Optional[UUID] = None,
|
319
319
|
timeout: Optional[int] = 3600,
|
320
320
|
key: Optional[str] = None,
|
321
|
-
client: PrefectClient = None,
|
321
|
+
client: Optional[PrefectClient] = None,
|
322
322
|
) -> T:
|
323
323
|
...
|
324
324
|
|
@@ -330,7 +330,7 @@ async def suspend_flow_run(
|
|
330
330
|
flow_run_id: Optional[UUID] = None,
|
331
331
|
timeout: Optional[int] = 3600,
|
332
332
|
key: Optional[str] = None,
|
333
|
-
client: PrefectClient = None,
|
333
|
+
client: Optional[PrefectClient] = None,
|
334
334
|
) -> Optional[T]:
|
335
335
|
"""
|
336
336
|
Suspends a flow run by stopping code execution until resumed.
|