prefect-client 3.1.7__py3-none-any.whl → 3.1.9__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 +53 -59
- prefect/_internal/concurrency/services.py +6 -4
- prefect/_version.py +3 -3
- prefect/agent.py +3 -1
- prefect/client/cloud.py +0 -21
- prefect/client/orchestration.py +18 -0
- prefect/client/schemas/objects.py +11 -0
- prefect/client/utilities.py +1 -15
- prefect/deployments/deployments.py +4 -2
- prefect/deployments/runner.py +3 -1
- prefect/engine.py +2 -1
- prefect/events/filters.py +2 -8
- prefect/exceptions.py +31 -41
- prefect/filesystems.py +2 -2
- prefect/flow_engine.py +2 -2
- prefect/flows.py +228 -185
- prefect/infrastructure/__init__.py +3 -1
- prefect/infrastructure/base.py +3 -1
- prefect/results.py +76 -19
- prefect/runner/runner.py +131 -21
- prefect/settings/__init__.py +1 -0
- prefect/settings/base.py +3 -2
- prefect/settings/models/api.py +4 -0
- prefect/settings/models/runner.py +8 -0
- prefect/settings/models/server/api.py +7 -1
- prefect/states.py +22 -10
- prefect/task_engine.py +1 -1
- prefect/telemetry/instrumentation.py +9 -10
- prefect/telemetry/services.py +67 -0
- prefect/utilities/engine.py +15 -1
- prefect/utilities/importtools.py +28 -21
- prefect/variables.py +2 -2
- prefect/workers/base.py +6 -12
- prefect/workers/block.py +3 -1
- prefect/workers/cloud.py +3 -1
- {prefect_client-3.1.7.dist-info → prefect_client-3.1.9.dist-info}/METADATA +1 -1
- {prefect_client-3.1.7.dist-info → prefect_client-3.1.9.dist-info}/RECORD +40 -39
- {prefect_client-3.1.7.dist-info → prefect_client-3.1.9.dist-info}/LICENSE +0 -0
- {prefect_client-3.1.7.dist-info → prefect_client-3.1.9.dist-info}/WHEEL +0 -0
- {prefect_client-3.1.7.dist-info → prefect_client-3.1.9.dist-info}/top_level.txt +0 -0
prefect/__init__.py
CHANGED
@@ -2,29 +2,14 @@
|
|
2
2
|
|
3
3
|
# Setup version and path constants
|
4
4
|
|
5
|
+
import sys
|
5
6
|
from . import _version
|
6
7
|
import importlib
|
7
8
|
import pathlib
|
8
|
-
from typing import TYPE_CHECKING, Any
|
9
|
-
|
10
|
-
__version_info__ = _version.get_versions()
|
11
|
-
__version__ = __version_info__["version"]
|
12
|
-
|
13
|
-
# The absolute path to this module
|
14
|
-
__module_path__ = pathlib.Path(__file__).parent
|
15
|
-
# The absolute path to the root of the repository, only valid for use during development
|
16
|
-
__development_base_path__ = __module_path__.parents[1]
|
17
|
-
|
18
|
-
# The absolute path to the built UI within the Python module, used by
|
19
|
-
# `prefect server start` to serve a dynamic build of the UI
|
20
|
-
__ui_static_subpath__ = __module_path__ / "server" / "ui_build"
|
21
|
-
|
22
|
-
# The absolute path to the built UI within the Python module
|
23
|
-
__ui_static_path__ = __module_path__ / "server" / "ui"
|
24
|
-
|
25
|
-
del _version, pathlib
|
9
|
+
from typing import TYPE_CHECKING, Any, Optional, TypedDict, cast
|
26
10
|
|
27
11
|
if TYPE_CHECKING:
|
12
|
+
from importlib.machinery import ModuleSpec
|
28
13
|
from .main import (
|
29
14
|
allow_failure,
|
30
15
|
flow,
|
@@ -45,80 +30,89 @@ if TYPE_CHECKING:
|
|
45
30
|
suspend_flow_run,
|
46
31
|
)
|
47
32
|
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
"
|
53
|
-
|
54
|
-
|
55
|
-
|
33
|
+
__spec__: ModuleSpec
|
34
|
+
|
35
|
+
# Versioneer provides version information as dictionaries
|
36
|
+
# with these keys
|
37
|
+
class VersionInfo(TypedDict("_FullRevisionId", {"full-revisionid": str})):
|
38
|
+
version: str
|
39
|
+
dirty: Optional[bool]
|
40
|
+
error: Optional[str]
|
41
|
+
date: Optional[str]
|
56
42
|
|
57
|
-
|
43
|
+
|
44
|
+
__version_info__: "VersionInfo" = cast("VersionInfo", _version.get_versions())
|
45
|
+
__version__ = __version_info__["version"]
|
46
|
+
|
47
|
+
# The absolute path to this module
|
48
|
+
__module_path__: pathlib.Path = pathlib.Path(__file__).parent
|
49
|
+
# The absolute path to the root of the repository, only valid for use during development
|
50
|
+
__development_base_path__: pathlib.Path = __module_path__.parents[1]
|
51
|
+
|
52
|
+
# The absolute path to the built UI within the Python module, used by
|
53
|
+
# `prefect server start` to serve a dynamic build of the UI
|
54
|
+
__ui_static_subpath__: pathlib.Path = __module_path__ / "server" / "ui_build"
|
55
|
+
|
56
|
+
# The absolute path to the built UI within the Python module
|
57
|
+
__ui_static_path__: pathlib.Path = __module_path__ / "server" / "ui"
|
58
|
+
|
59
|
+
del _version, pathlib
|
60
|
+
|
61
|
+
_public_api: dict[str, tuple[Optional[str], str]] = {
|
58
62
|
"allow_failure": (__spec__.parent, ".main"),
|
63
|
+
"aserve": (__spec__.parent, ".main"),
|
64
|
+
"deploy": (__spec__.parent, ".main"),
|
59
65
|
"flow": (__spec__.parent, ".main"),
|
60
66
|
"Flow": (__spec__.parent, ".main"),
|
61
67
|
"get_client": (__spec__.parent, ".main"),
|
62
68
|
"get_run_logger": (__spec__.parent, ".main"),
|
69
|
+
"pause_flow_run": (__spec__.parent, ".main"),
|
70
|
+
"resume_flow_run": (__spec__.parent, ".main"),
|
71
|
+
"serve": (__spec__.parent, ".main"),
|
63
72
|
"State": (__spec__.parent, ".main"),
|
73
|
+
"suspend_flow_run": (__spec__.parent, ".main"),
|
64
74
|
"tags": (__spec__.parent, ".main"),
|
65
75
|
"task": (__spec__.parent, ".main"),
|
66
76
|
"Task": (__spec__.parent, ".main"),
|
67
77
|
"Transaction": (__spec__.parent, ".main"),
|
68
78
|
"unmapped": (__spec__.parent, ".main"),
|
69
|
-
"serve": (__spec__.parent, ".main"),
|
70
|
-
"aserve": (__spec__.parent, ".main"),
|
71
|
-
"deploy": (__spec__.parent, ".main"),
|
72
|
-
"pause_flow_run": (__spec__.parent, ".main"),
|
73
|
-
"resume_flow_run": (__spec__.parent, ".main"),
|
74
|
-
"suspend_flow_run": (__spec__.parent, ".main"),
|
75
79
|
}
|
76
80
|
|
77
81
|
# Declare API for type-checkers
|
78
82
|
__all__ = [
|
83
|
+
"__version__",
|
79
84
|
"allow_failure",
|
85
|
+
"aserve",
|
86
|
+
"deploy",
|
80
87
|
"flow",
|
81
88
|
"Flow",
|
82
89
|
"get_client",
|
83
90
|
"get_run_logger",
|
91
|
+
"pause_flow_run",
|
92
|
+
"resume_flow_run",
|
93
|
+
"serve",
|
84
94
|
"State",
|
95
|
+
"suspend_flow_run",
|
85
96
|
"tags",
|
86
97
|
"task",
|
87
98
|
"Task",
|
88
99
|
"Transaction",
|
89
100
|
"unmapped",
|
90
|
-
"serve",
|
91
|
-
"aserve",
|
92
|
-
"deploy",
|
93
|
-
"pause_flow_run",
|
94
|
-
"resume_flow_run",
|
95
|
-
"suspend_flow_run",
|
96
|
-
"__version_info__",
|
97
|
-
"__version__",
|
98
|
-
"__module_path__",
|
99
|
-
"__development_base_path__",
|
100
|
-
"__ui_static_subpath__",
|
101
|
-
"__ui_static_path__",
|
102
101
|
]
|
103
102
|
|
104
103
|
|
105
|
-
def __getattr__(attr_name: str) ->
|
106
|
-
if attr_name in _slots:
|
107
|
-
return _slots[attr_name]
|
104
|
+
def __getattr__(attr_name: str) -> Any:
|
108
105
|
try:
|
109
|
-
dynamic_attr
|
110
|
-
if dynamic_attr is None:
|
106
|
+
if (dynamic_attr := _public_api.get(attr_name)) is None:
|
111
107
|
return importlib.import_module(f".{attr_name}", package=__name__)
|
112
108
|
|
113
|
-
package,
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
if module_name == "__module__":
|
118
|
-
return import_module(f".{attr_name}", package=package)
|
109
|
+
package, mname = dynamic_attr
|
110
|
+
if mname == "__module__":
|
111
|
+
return importlib.import_module(f".{attr_name}", package=package)
|
119
112
|
else:
|
120
|
-
module = import_module(
|
113
|
+
module = importlib.import_module(mname, package=package)
|
121
114
|
return getattr(module, attr_name)
|
122
115
|
except ModuleNotFoundError as ex:
|
123
|
-
|
124
|
-
|
116
|
+
mname, _, attr = (ex.name or "").rpartition(".")
|
117
|
+
ctx = {"name": mname, "obj": attr} if sys.version_info >= (3, 10) else {}
|
118
|
+
raise AttributeError(f"module {mname} has no attribute {attr}", **ctx) from ex
|
@@ -225,7 +225,9 @@ class QueueService(abc.ABC, Generic[T]):
|
|
225
225
|
return future.result()
|
226
226
|
|
227
227
|
@classmethod
|
228
|
-
def drain_all(
|
228
|
+
def drain_all(
|
229
|
+
cls, timeout: Optional[float] = None, at_exit=True
|
230
|
+
) -> Union[Awaitable, None]:
|
229
231
|
"""
|
230
232
|
Stop all instances of the service and wait for all remaining work to be
|
231
233
|
completed.
|
@@ -237,7 +239,7 @@ class QueueService(abc.ABC, Generic[T]):
|
|
237
239
|
instances = tuple(cls._instances.values())
|
238
240
|
|
239
241
|
for instance in instances:
|
240
|
-
futures.append(instance._drain())
|
242
|
+
futures.append(instance._drain(at_exit=at_exit))
|
241
243
|
|
242
244
|
if get_running_loop() is not None:
|
243
245
|
return (
|
@@ -376,10 +378,10 @@ class BatchedQueueService(QueueService[T]):
|
|
376
378
|
@contextlib.contextmanager
|
377
379
|
def drain_on_exit(service: QueueService):
|
378
380
|
yield
|
379
|
-
service.drain_all()
|
381
|
+
service.drain_all(at_exit=True)
|
380
382
|
|
381
383
|
|
382
384
|
@contextlib.asynccontextmanager
|
383
385
|
async def drain_on_exit_async(service: QueueService):
|
384
386
|
yield
|
385
|
-
await service.drain_all()
|
387
|
+
await service.drain_all(at_exit=True)
|
prefect/_version.py
CHANGED
@@ -8,11 +8,11 @@ import json
|
|
8
8
|
|
9
9
|
version_json = '''
|
10
10
|
{
|
11
|
-
"date": "2024-12-
|
11
|
+
"date": "2024-12-20T16:33:15-0500",
|
12
12
|
"dirty": true,
|
13
13
|
"error": null,
|
14
|
-
"full-revisionid": "
|
15
|
-
"version": "3.1.
|
14
|
+
"full-revisionid": "e1fe79439b319ce5478aa5f8bd4e836ed4f8a0f5",
|
15
|
+
"version": "3.1.9"
|
16
16
|
}
|
17
17
|
''' # END VERSION_JSON
|
18
18
|
|
prefect/agent.py
CHANGED
@@ -1,6 +1,8 @@
|
|
1
1
|
"""
|
2
2
|
2024-06-27: This surfaces an actionable error message for moved or removed objects in Prefect 3.0 upgrade.
|
3
3
|
"""
|
4
|
+
from typing import Any, Callable
|
5
|
+
|
4
6
|
from prefect._internal.compatibility.migration import getattr_migration
|
5
7
|
|
6
|
-
__getattr__ = getattr_migration(__name__)
|
8
|
+
__getattr__: Callable[[str], Any] = getattr_migration(__name__)
|
prefect/client/cloud.py
CHANGED
@@ -1,6 +1,5 @@
|
|
1
1
|
import re
|
2
2
|
from typing import Any, NoReturn, Optional, cast
|
3
|
-
from uuid import UUID
|
4
3
|
|
5
4
|
import anyio
|
6
5
|
import httpx
|
@@ -23,7 +22,6 @@ from prefect.settings import (
|
|
23
22
|
PREFECT_CLOUD_API_URL,
|
24
23
|
PREFECT_TESTING_UNIT_TEST_MODE,
|
25
24
|
)
|
26
|
-
from prefect.types import KeyValueLabels
|
27
25
|
|
28
26
|
PARSE_API_URL_REGEX = re.compile(r"accounts/(.{36})/workspaces/(.{36})")
|
29
27
|
|
@@ -160,25 +158,6 @@ class CloudClient:
|
|
160
158
|
response = await self.get(f"{self.account_base_url}/ip_allowlist/my_access")
|
161
159
|
return IPAllowlistMyAccessResponse.model_validate(response)
|
162
160
|
|
163
|
-
async def update_flow_run_labels(
|
164
|
-
self, flow_run_id: UUID, labels: KeyValueLabels
|
165
|
-
) -> httpx.Response:
|
166
|
-
"""
|
167
|
-
Update the labels for a flow run.
|
168
|
-
|
169
|
-
Args:
|
170
|
-
flow_run_id: The identifier for the flow run to update.
|
171
|
-
labels: A dictionary of labels to update for the flow run.
|
172
|
-
|
173
|
-
Returns:
|
174
|
-
an `httpx.Response` object from the PATCH request
|
175
|
-
"""
|
176
|
-
|
177
|
-
return await self._client.patch(
|
178
|
-
f"{self.workspace_base_url}/flow_runs/{flow_run_id}/labels",
|
179
|
-
json=labels,
|
180
|
-
)
|
181
|
-
|
182
161
|
async def __aenter__(self) -> Self:
|
183
162
|
await self._client.__aenter__()
|
184
163
|
return self
|
prefect/client/orchestration.py
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
import asyncio
|
2
|
+
import base64
|
2
3
|
import datetime
|
3
4
|
import ssl
|
4
5
|
import warnings
|
@@ -114,6 +115,7 @@ from prefect.events import filters
|
|
114
115
|
from prefect.events.schemas.automations import Automation, AutomationCore
|
115
116
|
from prefect.logging import get_logger
|
116
117
|
from prefect.settings import (
|
118
|
+
PREFECT_API_AUTH_STRING,
|
117
119
|
PREFECT_API_DATABASE_CONNECTION_URL,
|
118
120
|
PREFECT_API_ENABLE_HTTP2,
|
119
121
|
PREFECT_API_KEY,
|
@@ -228,6 +230,7 @@ def get_client(
|
|
228
230
|
if sync_client:
|
229
231
|
return SyncPrefectClient(
|
230
232
|
api,
|
233
|
+
auth_string=PREFECT_API_AUTH_STRING.value(),
|
231
234
|
api_key=PREFECT_API_KEY.value(),
|
232
235
|
httpx_settings=httpx_settings,
|
233
236
|
server_type=server_type,
|
@@ -235,6 +238,7 @@ def get_client(
|
|
235
238
|
else:
|
236
239
|
return PrefectClient(
|
237
240
|
api,
|
241
|
+
auth_string=PREFECT_API_AUTH_STRING.value(),
|
238
242
|
api_key=PREFECT_API_KEY.value(),
|
239
243
|
httpx_settings=httpx_settings,
|
240
244
|
server_type=server_type,
|
@@ -271,6 +275,7 @@ class PrefectClient:
|
|
271
275
|
self,
|
272
276
|
api: Union[str, ASGIApp],
|
273
277
|
*,
|
278
|
+
auth_string: Optional[str] = None,
|
274
279
|
api_key: Optional[str] = None,
|
275
280
|
api_version: Optional[str] = None,
|
276
281
|
httpx_settings: Optional[dict[str, Any]] = None,
|
@@ -299,6 +304,10 @@ class PrefectClient:
|
|
299
304
|
if api_key:
|
300
305
|
httpx_settings["headers"].setdefault("Authorization", f"Bearer {api_key}")
|
301
306
|
|
307
|
+
if auth_string:
|
308
|
+
token = base64.b64encode(auth_string.encode("utf-8")).decode("utf-8")
|
309
|
+
httpx_settings["headers"].setdefault("Authorization", f"Basic {token}")
|
310
|
+
|
302
311
|
# Context management
|
303
312
|
self._context_stack: int = 0
|
304
313
|
self._exit_stack = AsyncExitStack()
|
@@ -3469,6 +3478,8 @@ class PrefectClient:
|
|
3469
3478
|
try:
|
3470
3479
|
api_version = await self.api_version()
|
3471
3480
|
except Exception as e:
|
3481
|
+
if "Unauthorized" in str(e):
|
3482
|
+
raise e
|
3472
3483
|
raise RuntimeError(f"Failed to reach API at {self.api_url}") from e
|
3473
3484
|
|
3474
3485
|
api_version = version.parse(api_version)
|
@@ -3590,6 +3601,7 @@ class SyncPrefectClient:
|
|
3590
3601
|
self,
|
3591
3602
|
api: Union[str, ASGIApp],
|
3592
3603
|
*,
|
3604
|
+
auth_string: Optional[str] = None,
|
3593
3605
|
api_key: Optional[str] = None,
|
3594
3606
|
api_version: Optional[str] = None,
|
3595
3607
|
httpx_settings: Optional[dict[str, Any]] = None,
|
@@ -3618,6 +3630,10 @@ class SyncPrefectClient:
|
|
3618
3630
|
if api_key:
|
3619
3631
|
httpx_settings["headers"].setdefault("Authorization", f"Bearer {api_key}")
|
3620
3632
|
|
3633
|
+
if auth_string:
|
3634
|
+
token = base64.b64encode(auth_string.encode("utf-8")).decode("utf-8")
|
3635
|
+
httpx_settings["headers"].setdefault("Authorization", f"Basic {token}")
|
3636
|
+
|
3621
3637
|
# Context management
|
3622
3638
|
self._context_stack: int = 0
|
3623
3639
|
self._ephemeral_app: Optional[ASGIApp] = None
|
@@ -3800,6 +3816,8 @@ class SyncPrefectClient:
|
|
3800
3816
|
try:
|
3801
3817
|
api_version = self.api_version()
|
3802
3818
|
except Exception as e:
|
3819
|
+
if "Unauthorized" in str(e):
|
3820
|
+
raise e
|
3803
3821
|
raise RuntimeError(f"Failed to reach API at {self.api_url}") from e
|
3804
3822
|
|
3805
3823
|
api_version = version.parse(api_version)
|
@@ -190,6 +190,8 @@ class StateDetails(PrefectBaseModel):
|
|
190
190
|
retriable: Optional[bool] = None
|
191
191
|
transition_id: Optional[UUID] = None
|
192
192
|
task_parameters_id: Optional[UUID] = None
|
193
|
+
# Captures the trace_id and span_id of the span where this state was created
|
194
|
+
traceparent: Optional[str] = None
|
193
195
|
|
194
196
|
|
195
197
|
def data_discriminator(x: Any) -> str:
|
@@ -237,6 +239,15 @@ class State(ObjectBaseModel, Generic[R]):
|
|
237
239
|
) -> Union[R, Exception]:
|
238
240
|
...
|
239
241
|
|
242
|
+
@overload
|
243
|
+
def result(
|
244
|
+
self: "State[R]",
|
245
|
+
raise_on_failure: bool = ...,
|
246
|
+
fetch: bool = ...,
|
247
|
+
retry_result_failure: bool = ...,
|
248
|
+
) -> Union[R, Exception]:
|
249
|
+
...
|
250
|
+
|
240
251
|
@deprecated.deprecated_parameter(
|
241
252
|
"fetch",
|
242
253
|
when=lambda fetch: fetch is not True,
|
prefect/client/utilities.py
CHANGED
@@ -7,7 +7,7 @@ Utilities for working with clients.
|
|
7
7
|
|
8
8
|
from collections.abc import Awaitable, Coroutine
|
9
9
|
from functools import wraps
|
10
|
-
from typing import TYPE_CHECKING, Any, Callable, Optional, Union
|
10
|
+
from typing import TYPE_CHECKING, Any, Callable, Optional, Union
|
11
11
|
|
12
12
|
from typing_extensions import Concatenate, ParamSpec, TypeGuard, TypeVar
|
13
13
|
|
@@ -71,23 +71,9 @@ def client_injector(
|
|
71
71
|
return wrapper
|
72
72
|
|
73
73
|
|
74
|
-
@overload
|
75
74
|
def inject_client(
|
76
75
|
fn: Callable[P, Coroutine[Any, Any, R]],
|
77
76
|
) -> Callable[P, Coroutine[Any, Any, R]]:
|
78
|
-
...
|
79
|
-
|
80
|
-
|
81
|
-
@overload
|
82
|
-
def inject_client(
|
83
|
-
fn: Callable[P, R],
|
84
|
-
) -> Callable[P, R]:
|
85
|
-
...
|
86
|
-
|
87
|
-
|
88
|
-
def inject_client(
|
89
|
-
fn: Callable[P, Union[Coroutine[Any, Any, R], R]],
|
90
|
-
) -> Callable[P, Union[Coroutine[Any, Any, R], R]]:
|
91
77
|
"""
|
92
78
|
Simple helper to provide a context managed client to an asynchronous function.
|
93
79
|
|
@@ -1,3 +1,5 @@
|
|
1
|
-
from
|
1
|
+
from typing import Any, Callable
|
2
2
|
|
3
|
-
|
3
|
+
from prefect._internal.compatibility.migration import getattr_migration
|
4
|
+
|
5
|
+
__getattr__: Callable[[str], Any] = getattr_migration(__name__)
|
prefect/deployments/runner.py
CHANGED
@@ -549,7 +549,9 @@ class RunnerDeployment(BaseModel):
|
|
549
549
|
module = importlib.import_module(mod_name)
|
550
550
|
flow_file = getattr(module, "__file__", None)
|
551
551
|
except ModuleNotFoundError as exc:
|
552
|
-
|
552
|
+
# 16458 adds an identifier to the module name, so checking
|
553
|
+
# for "__prefect_loader__" (2 underscores) will not match
|
554
|
+
if "__prefect_loader_" in str(exc):
|
553
555
|
raise ValueError(
|
554
556
|
"Cannot create a RunnerDeployment from a flow that has been"
|
555
557
|
" loaded from an entrypoint. To deploy a flow via"
|
prefect/engine.py
CHANGED
@@ -1,5 +1,6 @@
|
|
1
1
|
import os
|
2
2
|
import sys
|
3
|
+
from typing import Any, Callable
|
3
4
|
from uuid import UUID
|
4
5
|
|
5
6
|
from prefect._internal.compatibility.migration import getattr_migration
|
@@ -72,4 +73,4 @@ if __name__ == "__main__":
|
|
72
73
|
# Let the exit code be determined by the base exception type
|
73
74
|
raise
|
74
75
|
|
75
|
-
__getattr__ = getattr_migration(__name__)
|
76
|
+
__getattr__: Callable[[str], Any] = getattr_migration(__name__)
|
prefect/events/filters.py
CHANGED
@@ -2,7 +2,7 @@ from typing import List, Optional, Tuple, cast
|
|
2
2
|
from uuid import UUID
|
3
3
|
|
4
4
|
import pendulum
|
5
|
-
from pydantic import Field
|
5
|
+
from pydantic import Field
|
6
6
|
|
7
7
|
from prefect._internal.schemas.bases import PrefectBaseModel
|
8
8
|
from prefect.types import DateTime
|
@@ -41,18 +41,12 @@ class AutomationFilter(PrefectBaseModel):
|
|
41
41
|
class EventDataFilter(PrefectBaseModel, extra="forbid"): # type: ignore[call-arg]
|
42
42
|
"""A base class for filtering event data."""
|
43
43
|
|
44
|
-
_top_level_filter: Optional["EventFilter"] = PrivateAttr(None)
|
45
|
-
|
46
44
|
def get_filters(self) -> List["EventDataFilter"]:
|
47
45
|
filters: List["EventDataFilter"] = [
|
48
46
|
filter
|
49
|
-
for filter in [
|
50
|
-
getattr(self, name) for name, field in self.model_fields.items()
|
51
|
-
]
|
47
|
+
for filter in [getattr(self, name) for name in self.model_fields]
|
52
48
|
if isinstance(filter, EventDataFilter)
|
53
49
|
]
|
54
|
-
for filter in filters:
|
55
|
-
filter._top_level_filter = self._top_level_filter
|
56
50
|
return filters
|
57
51
|
|
58
52
|
def includes(self, event: Event) -> bool:
|
prefect/exceptions.py
CHANGED
@@ -4,19 +4,20 @@ Prefect-specific exceptions.
|
|
4
4
|
|
5
5
|
import inspect
|
6
6
|
import traceback
|
7
|
+
from collections.abc import Iterable
|
7
8
|
from types import ModuleType, TracebackType
|
8
|
-
from typing import Any, Callable,
|
9
|
+
from typing import TYPE_CHECKING, Any, Callable, Optional
|
9
10
|
|
10
11
|
from httpx._exceptions import HTTPStatusError
|
11
12
|
from pydantic import ValidationError
|
12
|
-
from rich.traceback import Traceback
|
13
13
|
from typing_extensions import Self
|
14
14
|
|
15
|
-
|
15
|
+
if TYPE_CHECKING:
|
16
|
+
from prefect.states import State
|
16
17
|
|
17
18
|
|
18
19
|
def _trim_traceback(
|
19
|
-
tb: TracebackType, remove_modules: Iterable[ModuleType]
|
20
|
+
tb: Optional[TracebackType], remove_modules: Iterable[ModuleType]
|
20
21
|
) -> Optional[TracebackType]:
|
21
22
|
"""
|
22
23
|
Utility to remove frames from specific modules from a traceback.
|
@@ -32,8 +33,9 @@ def _trim_traceback(
|
|
32
33
|
A traceback, or `None` if all traceback frames originate from an excluded module
|
33
34
|
|
34
35
|
"""
|
35
|
-
strip_paths = [
|
36
|
-
|
36
|
+
strip_paths = [
|
37
|
+
module.__file__ for module in remove_modules if module.__file__ is not None
|
38
|
+
]
|
37
39
|
while tb and any(
|
38
40
|
module_path in str(tb.tb_frame.f_globals.get("__file__", ""))
|
39
41
|
for module_path in strip_paths
|
@@ -91,7 +93,9 @@ class PausedRun(PrefectException):
|
|
91
93
|
Raised when the result from a paused run is retrieved.
|
92
94
|
"""
|
93
95
|
|
94
|
-
def __init__(
|
96
|
+
def __init__(
|
97
|
+
self, *args: Any, state: Optional["State[Any]"] = None, **kwargs: Any
|
98
|
+
) -> None:
|
95
99
|
super().__init__(*args, **kwargs)
|
96
100
|
self.state = state
|
97
101
|
|
@@ -133,6 +137,8 @@ class ScriptError(PrefectException):
|
|
133
137
|
user_exc: Exception,
|
134
138
|
path: str,
|
135
139
|
) -> None:
|
140
|
+
import prefect.utilities.importtools
|
141
|
+
|
136
142
|
message = f"Script at {str(path)!r} encountered an exception: {user_exc!r}"
|
137
143
|
super().__init__(message)
|
138
144
|
self.user_exc = user_exc
|
@@ -144,30 +150,6 @@ class ScriptError(PrefectException):
|
|
144
150
|
)
|
145
151
|
|
146
152
|
|
147
|
-
class FlowScriptError(PrefectException):
|
148
|
-
"""
|
149
|
-
Raised when a script errors during evaluation while attempting to load a flow.
|
150
|
-
"""
|
151
|
-
|
152
|
-
def __init__(
|
153
|
-
self,
|
154
|
-
user_exc: Exception,
|
155
|
-
script_path: str,
|
156
|
-
) -> None:
|
157
|
-
message = f"Flow script at {script_path!r} encountered an exception"
|
158
|
-
super().__init__(message)
|
159
|
-
|
160
|
-
self.user_exc = user_exc
|
161
|
-
|
162
|
-
def rich_user_traceback(self, **kwargs):
|
163
|
-
trace = Traceback.extract(
|
164
|
-
type(self.user_exc),
|
165
|
-
self.user_exc,
|
166
|
-
self.user_exc.__traceback__.tb_next.tb_next.tb_next.tb_next,
|
167
|
-
)
|
168
|
-
return Traceback(trace, **kwargs)
|
169
|
-
|
170
|
-
|
171
153
|
class ParameterTypeError(PrefectException):
|
172
154
|
"""
|
173
155
|
Raised when a parameter does not pass Pydantic type validation.
|
@@ -196,7 +178,11 @@ class ParameterBindError(TypeError, PrefectException):
|
|
196
178
|
|
197
179
|
@classmethod
|
198
180
|
def from_bind_failure(
|
199
|
-
cls,
|
181
|
+
cls,
|
182
|
+
fn: Callable[..., Any],
|
183
|
+
exc: TypeError,
|
184
|
+
call_args: tuple[Any, ...],
|
185
|
+
call_kwargs: dict[str, Any],
|
200
186
|
) -> Self:
|
201
187
|
fn_signature = str(inspect.signature(fn)).strip("()")
|
202
188
|
|
@@ -214,7 +200,9 @@ class SignatureMismatchError(PrefectException, TypeError):
|
|
214
200
|
super().__init__(msg)
|
215
201
|
|
216
202
|
@classmethod
|
217
|
-
def from_bad_params(
|
203
|
+
def from_bad_params(
|
204
|
+
cls, expected_params: list[str], provided_params: list[str]
|
205
|
+
) -> Self:
|
218
206
|
msg = (
|
219
207
|
f"Function expects parameters {expected_params} but was provided with"
|
220
208
|
f" parameters {provided_params}"
|
@@ -231,14 +219,14 @@ class ObjectNotFound(PrefectException):
|
|
231
219
|
self,
|
232
220
|
http_exc: Exception,
|
233
221
|
help_message: Optional[str] = None,
|
234
|
-
*args,
|
235
|
-
**kwargs,
|
236
|
-
):
|
222
|
+
*args: Any,
|
223
|
+
**kwargs: Any,
|
224
|
+
) -> None:
|
237
225
|
self.http_exc = http_exc
|
238
226
|
self.help_message = help_message
|
239
227
|
super().__init__(help_message, *args, **kwargs)
|
240
228
|
|
241
|
-
def __str__(self):
|
229
|
+
def __str__(self) -> str:
|
242
230
|
return self.help_message or super().__str__()
|
243
231
|
|
244
232
|
|
@@ -247,7 +235,7 @@ class ObjectAlreadyExists(PrefectException):
|
|
247
235
|
Raised when the client receives a 409 (conflict) from the API.
|
248
236
|
"""
|
249
237
|
|
250
|
-
def __init__(self, http_exc: Exception, *args, **kwargs):
|
238
|
+
def __init__(self, http_exc: Exception, *args: Any, **kwargs: Any) -> None:
|
251
239
|
self.http_exc = http_exc
|
252
240
|
super().__init__(*args, **kwargs)
|
253
241
|
|
@@ -304,7 +292,9 @@ class Pause(PrefectSignal):
|
|
304
292
|
Raised when a flow run is PAUSED and needs to exit for resubmission.
|
305
293
|
"""
|
306
294
|
|
307
|
-
def __init__(
|
295
|
+
def __init__(
|
296
|
+
self, *args: Any, state: Optional["State[Any]"] = None, **kwargs: Any
|
297
|
+
) -> None:
|
308
298
|
super().__init__(*args, **kwargs)
|
309
299
|
self.state = state
|
310
300
|
|
@@ -332,7 +322,7 @@ class PrefectHTTPStatusError(HTTPStatusError):
|
|
332
322
|
"""
|
333
323
|
|
334
324
|
@classmethod
|
335
|
-
def from_httpx_error(cls:
|
325
|
+
def from_httpx_error(cls: type[Self], httpx_error: HTTPStatusError) -> Self:
|
336
326
|
"""
|
337
327
|
Generate a `PrefectHTTPStatusError` from an `httpx.HTTPStatusError`.
|
338
328
|
"""
|
@@ -441,7 +431,7 @@ class ProfileSettingsValidationError(PrefectException):
|
|
441
431
|
Raised when a profile settings are invalid.
|
442
432
|
"""
|
443
433
|
|
444
|
-
def __init__(self, errors:
|
434
|
+
def __init__(self, errors: list[tuple[Any, ValidationError]]) -> None:
|
445
435
|
self.errors = errors
|
446
436
|
|
447
437
|
|
prefect/filesystems.py
CHANGED
@@ -2,7 +2,7 @@ import abc
|
|
2
2
|
import urllib.parse
|
3
3
|
from pathlib import Path
|
4
4
|
from shutil import copytree
|
5
|
-
from typing import Any, Dict, Optional
|
5
|
+
from typing import Any, Callable, Dict, Optional
|
6
6
|
|
7
7
|
import anyio
|
8
8
|
import fsspec
|
@@ -544,4 +544,4 @@ class NullFileSystem(BaseModel):
|
|
544
544
|
pass
|
545
545
|
|
546
546
|
|
547
|
-
__getattr__ = getattr_migration(__name__)
|
547
|
+
__getattr__: Callable[[str], Any] = getattr_migration(__name__)
|
prefect/flow_engine.py
CHANGED
@@ -221,7 +221,7 @@ class FlowRunEngine(BaseFlowRunEngine[P, R]):
|
|
221
221
|
return_data=True,
|
222
222
|
max_depth=-1,
|
223
223
|
remove_annotations=True,
|
224
|
-
context={},
|
224
|
+
context={"parameter_name": parameter},
|
225
225
|
)
|
226
226
|
except UpstreamTaskError:
|
227
227
|
raise
|
@@ -784,7 +784,7 @@ class AsyncFlowRunEngine(BaseFlowRunEngine[P, R]):
|
|
784
784
|
return_data=True,
|
785
785
|
max_depth=-1,
|
786
786
|
remove_annotations=True,
|
787
|
-
context={},
|
787
|
+
context={"parameter_name": parameter},
|
788
788
|
)
|
789
789
|
except UpstreamTaskError:
|
790
790
|
raise
|