prefect-client 3.0.4__py3-none-any.whl → 3.0.5__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/cache_policies.py +1 -1
- prefect/client/orchestration.py +30 -2
- prefect/client/schemas/objects.py +5 -1
- prefect/context.py +11 -19
- prefect/deployments/flow_runs.py +8 -0
- prefect/exceptions.py +22 -3
- prefect/flow_engine.py +10 -7
- prefect/flows.py +1 -1
- prefect/logging/configuration.py +4 -8
- prefect/logging/handlers.py +3 -4
- prefect/results.py +1 -1
- prefect/settings.py +1364 -1588
- prefect/transactions.py +7 -4
- prefect/types/__init__.py +51 -1
- prefect/utilities/pydantic.py +2 -1
- prefect/utilities/text.py +13 -1
- {prefect_client-3.0.4.dist-info → prefect_client-3.0.5.dist-info}/METADATA +1 -1
- {prefect_client-3.0.4.dist-info → prefect_client-3.0.5.dist-info}/RECORD +21 -22
- prefect/_internal/compatibility/experimental.py +0 -195
- {prefect_client-3.0.4.dist-info → prefect_client-3.0.5.dist-info}/LICENSE +0 -0
- {prefect_client-3.0.4.dist-info → prefect_client-3.0.5.dist-info}/WHEEL +0 -0
- {prefect_client-3.0.4.dist-info → prefect_client-3.0.5.dist-info}/top_level.txt +0 -0
prefect/cache_policies.py
CHANGED
@@ -219,7 +219,7 @@ class TaskSource(CachePolicy):
|
|
219
219
|
except TypeError:
|
220
220
|
lines = inspect.getsource(task_ctx.task.fn.__class__)
|
221
221
|
except OSError as exc:
|
222
|
-
if "
|
222
|
+
if "source code" in str(exc):
|
223
223
|
lines = task_ctx.task.fn.__code__.co_code
|
224
224
|
else:
|
225
225
|
raise
|
prefect/client/orchestration.py
CHANGED
@@ -1813,7 +1813,35 @@ class PrefectClient:
|
|
1813
1813
|
response = await self._client.get(f"/deployments/name/{name}")
|
1814
1814
|
except httpx.HTTPStatusError as e:
|
1815
1815
|
if e.response.status_code == status.HTTP_404_NOT_FOUND:
|
1816
|
-
|
1816
|
+
from prefect.utilities.text import fuzzy_match_string
|
1817
|
+
|
1818
|
+
deployments = await self.read_deployments()
|
1819
|
+
flow_name_map = {
|
1820
|
+
flow.id: flow.name
|
1821
|
+
for flow in await asyncio.gather(
|
1822
|
+
*[
|
1823
|
+
self.read_flow(flow_id)
|
1824
|
+
for flow_id in {d.flow_id for d in deployments}
|
1825
|
+
]
|
1826
|
+
)
|
1827
|
+
}
|
1828
|
+
|
1829
|
+
raise prefect.exceptions.ObjectNotFound(
|
1830
|
+
http_exc=e,
|
1831
|
+
help_message=(
|
1832
|
+
f"Deployment {name!r} not found; did you mean {fuzzy_match!r}?"
|
1833
|
+
if (
|
1834
|
+
fuzzy_match := fuzzy_match_string(
|
1835
|
+
name,
|
1836
|
+
[
|
1837
|
+
f"{flow_name_map[d.flow_id]}/{d.name}"
|
1838
|
+
for d in deployments
|
1839
|
+
],
|
1840
|
+
)
|
1841
|
+
)
|
1842
|
+
else f"Deployment {name!r} not found. Try `prefect deployment ls` to find available deployments."
|
1843
|
+
),
|
1844
|
+
) from e
|
1817
1845
|
else:
|
1818
1846
|
raise
|
1819
1847
|
|
@@ -2543,7 +2571,7 @@ class PrefectClient:
|
|
2543
2571
|
|
2544
2572
|
async def read_logs(
|
2545
2573
|
self,
|
2546
|
-
log_filter: LogFilter = None,
|
2574
|
+
log_filter: Optional[LogFilter] = None,
|
2547
2575
|
limit: Optional[int] = None,
|
2548
2576
|
offset: Optional[int] = None,
|
2549
2577
|
sort: LogSort = LogSort.TIMESTAMP_ASC,
|
@@ -327,7 +327,11 @@ class State(ObjectBaseModel, Generic[R]):
|
|
327
327
|
results should be sent to the API. Other data is only available locally.
|
328
328
|
"""
|
329
329
|
from prefect.client.schemas.actions import StateCreate
|
330
|
-
from prefect.results import
|
330
|
+
from prefect.results import (
|
331
|
+
BaseResult,
|
332
|
+
ResultRecord,
|
333
|
+
should_persist_result,
|
334
|
+
)
|
331
335
|
|
332
336
|
if isinstance(self.data, BaseResult):
|
333
337
|
data = self.data
|
prefect/context.py
CHANGED
@@ -11,7 +11,6 @@ import sys
|
|
11
11
|
import warnings
|
12
12
|
from contextlib import ExitStack, asynccontextmanager, contextmanager
|
13
13
|
from contextvars import ContextVar, Token
|
14
|
-
from pathlib import Path
|
15
14
|
from typing import (
|
16
15
|
TYPE_CHECKING,
|
17
16
|
Any,
|
@@ -40,7 +39,7 @@ from prefect.client.schemas import FlowRun, TaskRun
|
|
40
39
|
from prefect.events.worker import EventsWorker
|
41
40
|
from prefect.exceptions import MissingContextError
|
42
41
|
from prefect.results import ResultStore, get_default_persist_setting
|
43
|
-
from prefect.settings import
|
42
|
+
from prefect.settings import Profile, Settings
|
44
43
|
from prefect.states import State
|
45
44
|
from prefect.task_runners import TaskRunner
|
46
45
|
from prefect.utilities.services import start_client_metrics_server
|
@@ -166,11 +165,13 @@ class ContextModel(BaseModel):
|
|
166
165
|
new._token = None
|
167
166
|
return new
|
168
167
|
|
169
|
-
def serialize(self) -> Dict[str, Any]:
|
168
|
+
def serialize(self, include_secrets: bool = True) -> Dict[str, Any]:
|
170
169
|
"""
|
171
170
|
Serialize the context model to a dictionary that can be pickled with cloudpickle.
|
172
171
|
"""
|
173
|
-
return self.model_dump(
|
172
|
+
return self.model_dump(
|
173
|
+
exclude_unset=True, context={"include_secrets": include_secrets}
|
174
|
+
)
|
174
175
|
|
175
176
|
|
176
177
|
class SyncClientContext(ContextModel):
|
@@ -430,7 +431,7 @@ class TagsContext(ContextModel):
|
|
430
431
|
# Return an empty `TagsContext` instead of `None` if no context exists
|
431
432
|
return cls.__var__.get(TagsContext())
|
432
433
|
|
433
|
-
__var__ = ContextVar("tags")
|
434
|
+
__var__: ContextVar = ContextVar("tags")
|
434
435
|
|
435
436
|
|
436
437
|
class SettingsContext(ContextModel):
|
@@ -447,7 +448,7 @@ class SettingsContext(ContextModel):
|
|
447
448
|
profile: Profile
|
448
449
|
settings: Settings
|
449
450
|
|
450
|
-
__var__ = ContextVar("settings")
|
451
|
+
__var__: ContextVar = ContextVar("settings")
|
451
452
|
|
452
453
|
def __hash__(self) -> int:
|
453
454
|
return hash(self.settings)
|
@@ -459,14 +460,11 @@ class SettingsContext(ContextModel):
|
|
459
460
|
return_value = super().__enter__()
|
460
461
|
|
461
462
|
try:
|
462
|
-
prefect_home =
|
463
|
+
prefect_home = self.settings.home
|
463
464
|
prefect_home.mkdir(mode=0o0700, exist_ok=True)
|
464
465
|
except OSError:
|
465
466
|
warnings.warn(
|
466
|
-
(
|
467
|
-
"Failed to create the Prefect home directory at "
|
468
|
-
f"{self.settings.value_of(PREFECT_HOME)}"
|
469
|
-
),
|
467
|
+
(f"Failed to create the Prefect home directory at {prefect_home}"),
|
470
468
|
stacklevel=2,
|
471
469
|
)
|
472
470
|
|
@@ -609,12 +607,11 @@ def use_profile(
|
|
609
607
|
|
610
608
|
# Create a copy of the profiles settings as we will mutate it
|
611
609
|
profile_settings = profile.settings.copy()
|
612
|
-
|
613
610
|
existing_context = SettingsContext.get()
|
614
611
|
if existing_context and include_current_context:
|
615
612
|
settings = existing_context.settings
|
616
613
|
else:
|
617
|
-
settings =
|
614
|
+
settings = Settings()
|
618
615
|
|
619
616
|
if not override_environment_variables:
|
620
617
|
for key in os.environ:
|
@@ -662,12 +659,7 @@ def root_settings_context():
|
|
662
659
|
)
|
663
660
|
active_name = "ephemeral"
|
664
661
|
|
665
|
-
|
666
|
-
profiles[active_name],
|
667
|
-
# Override environment variables if the profile was set by the CLI
|
668
|
-
override_environment_variables=profile_source == "by command line argument",
|
669
|
-
) as settings_context:
|
670
|
-
return settings_context
|
662
|
+
return SettingsContext(profile=profiles[active_name], settings=Settings())
|
671
663
|
|
672
664
|
# Note the above context is exited and the global settings context is used by
|
673
665
|
# an override in the `SettingsContext.get` method.
|
prefect/deployments/flow_runs.py
CHANGED
@@ -5,10 +5,12 @@ from uuid import UUID
|
|
5
5
|
import anyio
|
6
6
|
import pendulum
|
7
7
|
|
8
|
+
import prefect
|
8
9
|
from prefect.client.schemas import FlowRun
|
9
10
|
from prefect.client.utilities import inject_client
|
10
11
|
from prefect.context import FlowRunContext, TaskRunContext
|
11
12
|
from prefect.logging import get_logger
|
13
|
+
from prefect.results import BaseResult, ResultRecordMetadata
|
12
14
|
from prefect.states import Pending, Scheduled
|
13
15
|
from prefect.tasks import Task
|
14
16
|
from prefect.utilities.asyncutils import sync_compatible
|
@@ -18,6 +20,12 @@ if TYPE_CHECKING:
|
|
18
20
|
from prefect.client.orchestration import PrefectClient
|
19
21
|
from prefect.client.schemas.objects import FlowRun
|
20
22
|
|
23
|
+
prefect.client.schemas.StateCreate.model_rebuild(
|
24
|
+
_types_namespace={
|
25
|
+
"BaseResult": BaseResult,
|
26
|
+
"ResultRecordMetadata": ResultRecordMetadata,
|
27
|
+
}
|
28
|
+
)
|
21
29
|
|
22
30
|
logger = get_logger(__name__)
|
23
31
|
|
prefect/exceptions.py
CHANGED
@@ -5,7 +5,7 @@ Prefect-specific exceptions.
|
|
5
5
|
import inspect
|
6
6
|
import traceback
|
7
7
|
from types import ModuleType, TracebackType
|
8
|
-
from typing import Callable, Dict, Iterable, List, Optional, Type
|
8
|
+
from typing import Any, Callable, Dict, Iterable, List, Optional, Tuple, Type
|
9
9
|
|
10
10
|
from httpx._exceptions import HTTPStatusError
|
11
11
|
from pydantic import ValidationError
|
@@ -227,9 +227,19 @@ class ObjectNotFound(PrefectException):
|
|
227
227
|
Raised when the client receives a 404 (not found) from the API.
|
228
228
|
"""
|
229
229
|
|
230
|
-
def __init__(
|
230
|
+
def __init__(
|
231
|
+
self,
|
232
|
+
http_exc: Exception,
|
233
|
+
help_message: Optional[str] = None,
|
234
|
+
*args,
|
235
|
+
**kwargs,
|
236
|
+
):
|
231
237
|
self.http_exc = http_exc
|
232
|
-
|
238
|
+
self.help_message = help_message
|
239
|
+
super().__init__(help_message, *args, **kwargs)
|
240
|
+
|
241
|
+
def __str__(self):
|
242
|
+
return self.help_message or super().__str__()
|
233
243
|
|
234
244
|
|
235
245
|
class ObjectAlreadyExists(PrefectException):
|
@@ -424,3 +434,12 @@ class ConfigurationError(PrefectException):
|
|
424
434
|
"""
|
425
435
|
Raised when a configuration is invalid.
|
426
436
|
"""
|
437
|
+
|
438
|
+
|
439
|
+
class ProfileSettingsValidationError(PrefectException):
|
440
|
+
"""
|
441
|
+
Raised when a profile settings are invalid.
|
442
|
+
"""
|
443
|
+
|
444
|
+
def __init__(self, errors: List[Tuple[Any, ValidationError]]) -> None:
|
445
|
+
self.errors = errors
|
prefect/flow_engine.py
CHANGED
@@ -290,13 +290,16 @@ class FlowRunEngine(Generic[P, R]):
|
|
290
290
|
result_store: Optional[ResultStore] = None,
|
291
291
|
) -> State:
|
292
292
|
context = FlowRunContext.get()
|
293
|
-
terminal_state =
|
294
|
-
|
295
|
-
|
296
|
-
|
297
|
-
|
298
|
-
|
299
|
-
|
293
|
+
terminal_state = cast(
|
294
|
+
State,
|
295
|
+
run_coro_as_sync(
|
296
|
+
exception_to_failed_state(
|
297
|
+
exc,
|
298
|
+
message=msg or "Flow run encountered an exception:",
|
299
|
+
result_store=result_store or getattr(context, "result_store", None),
|
300
|
+
write_result=True,
|
301
|
+
)
|
302
|
+
),
|
300
303
|
)
|
301
304
|
state = self.set_state(terminal_state)
|
302
305
|
if self.state.is_scheduled():
|
prefect/flows.py
CHANGED
@@ -593,7 +593,7 @@ class Flow(Generic[P, R]):
|
|
593
593
|
# Get the updated parameter dict with cast values from the model
|
594
594
|
cast_parameters = {
|
595
595
|
k: v
|
596
|
-
for k, v in
|
596
|
+
for k, v in model.__dict__.items()
|
597
597
|
if k in model.model_fields_set or model.model_fields[k].default_factory
|
598
598
|
}
|
599
599
|
return cast_parameters
|
prefect/logging/configuration.py
CHANGED
@@ -13,7 +13,7 @@ import yaml
|
|
13
13
|
from prefect.settings import (
|
14
14
|
PREFECT_LOGGING_EXTRA_LOGGERS,
|
15
15
|
PREFECT_LOGGING_SETTINGS_PATH,
|
16
|
-
|
16
|
+
get_current_settings,
|
17
17
|
)
|
18
18
|
from prefect.utilities.collections import dict_to_flatdict, flatdict_to_dict
|
19
19
|
|
@@ -31,18 +31,14 @@ def load_logging_config(path: Path) -> dict:
|
|
31
31
|
"""
|
32
32
|
Loads logging configuration from a path allowing override from the environment
|
33
33
|
"""
|
34
|
+
current_settings = get_current_settings()
|
34
35
|
template = string.Template(path.read_text())
|
36
|
+
|
35
37
|
with warnings.catch_warnings():
|
36
38
|
warnings.filterwarnings("ignore", category=DeprecationWarning)
|
37
39
|
config = yaml.safe_load(
|
38
40
|
# Substitute settings into the template in format $SETTING / ${SETTING}
|
39
|
-
template.substitute(
|
40
|
-
{
|
41
|
-
setting.name: str(setting.value())
|
42
|
-
for setting in SETTING_VARIABLES.values()
|
43
|
-
if setting.value() is not None
|
44
|
-
}
|
45
|
-
)
|
41
|
+
template.substitute(current_settings.to_environment_variables())
|
46
42
|
)
|
47
43
|
|
48
44
|
# Load overrides from the environment
|
prefect/logging/handlers.py
CHANGED
@@ -6,7 +6,7 @@ import traceback
|
|
6
6
|
import uuid
|
7
7
|
import warnings
|
8
8
|
from contextlib import asynccontextmanager
|
9
|
-
from typing import Any, Dict, List, Type, Union
|
9
|
+
from typing import Any, Dict, List, Optional, Type, Union
|
10
10
|
|
11
11
|
import pendulum
|
12
12
|
from rich.console import Console
|
@@ -30,7 +30,6 @@ from prefect.settings import (
|
|
30
30
|
PREFECT_LOGGING_MARKUP,
|
31
31
|
PREFECT_LOGGING_TO_API_BATCH_INTERVAL,
|
32
32
|
PREFECT_LOGGING_TO_API_BATCH_SIZE,
|
33
|
-
PREFECT_LOGGING_TO_API_ENABLED,
|
34
33
|
PREFECT_LOGGING_TO_API_MAX_LOG_SIZE,
|
35
34
|
PREFECT_LOGGING_TO_API_WHEN_MISSING_FLOW,
|
36
35
|
)
|
@@ -134,7 +133,7 @@ class APILogHandler(logging.Handler):
|
|
134
133
|
try:
|
135
134
|
profile = prefect.context.get_settings_context()
|
136
135
|
|
137
|
-
if not
|
136
|
+
if not profile.settings.logging_to_api_enabled:
|
138
137
|
return # Respect the global settings toggle
|
139
138
|
if not getattr(record, "send_to_api", True):
|
140
139
|
return # Do not send records that have opted out
|
@@ -242,7 +241,7 @@ class PrefectConsoleHandler(logging.StreamHandler):
|
|
242
241
|
self,
|
243
242
|
stream=None,
|
244
243
|
highlighter: Highlighter = PrefectConsoleHighlighter,
|
245
|
-
styles: Dict[str, str] = None,
|
244
|
+
styles: Optional[Dict[str, str]] = None,
|
246
245
|
level: Union[int, str] = logging.NOTSET,
|
247
246
|
):
|
248
247
|
"""
|
prefect/results.py
CHANGED
@@ -1155,7 +1155,7 @@ class BaseResult(BaseModel, abc.ABC, Generic[R]):
|
|
1155
1155
|
try:
|
1156
1156
|
subcls = lookup_type(cls, dispatch_key=kwargs["type"])
|
1157
1157
|
except KeyError as exc:
|
1158
|
-
raise
|
1158
|
+
raise ValueError(f"Invalid type: {kwargs['type']}") from exc
|
1159
1159
|
return super().__new__(subcls)
|
1160
1160
|
else:
|
1161
1161
|
return super().__new__(cls)
|