prefect-client 3.1.12__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/client.py +53 -27
- prefect/_experimental/sla/objects.py +10 -2
- 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 +1 -1
- prefect/blocks/abstract.py +5 -2
- prefect/blocks/notifications.py +1 -0
- prefect/cache_policies.py +20 -20
- prefect/client/utilities.py +3 -3
- prefect/deployments/base.py +7 -4
- prefect/deployments/flow_runs.py +5 -1
- prefect/deployments/runner.py +6 -11
- 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 +19 -10
- 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 +1 -1
- prefect/flow_engine.py +17 -9
- prefect/flows.py +118 -73
- 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/main.py +3 -1
- prefect/results.py +166 -86
- prefect/runner/runner.py +34 -27
- 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 +4 -3
- prefect/settings/models/deployments.py +4 -3
- prefect/settings/models/experiments.py +4 -3
- 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 +17 -13
- prefect/task_engine.py +43 -33
- prefect/task_runners.py +35 -23
- prefect/task_runs.py +20 -11
- prefect/task_worker.py +12 -7
- prefect/tasks.py +30 -24
- prefect/telemetry/bootstrap.py +4 -1
- prefect/telemetry/run_telemetry.py +15 -13
- 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/workers/base.py +52 -30
- prefect/workers/process.py +20 -15
- prefect/workers/server.py +4 -5
- {prefect_client-3.1.12.dist-info → prefect_client-3.1.13.dist-info}/METADATA +2 -2
- {prefect_client-3.1.12.dist-info → prefect_client-3.1.13.dist-info}/RECORD +105 -103
- {prefect_client-3.1.12.dist-info → prefect_client-3.1.13.dist-info}/LICENSE +0 -0
- {prefect_client-3.1.12.dist-info → prefect_client-3.1.13.dist-info}/WHEEL +0 -0
- {prefect_client-3.1.12.dist-info → prefect_client-3.1.13.dist-info}/top_level.txt +0 -0
prefect/tasks.py
CHANGED
@@ -53,10 +53,7 @@ from prefect.results import (
|
|
53
53
|
ResultStore,
|
54
54
|
get_or_create_default_task_scheduling_storage,
|
55
55
|
)
|
56
|
-
from prefect.settings import
|
57
|
-
PREFECT_TASK_DEFAULT_RETRIES,
|
58
|
-
PREFECT_TASK_DEFAULT_RETRY_DELAY_SECONDS,
|
59
|
-
)
|
56
|
+
from prefect.settings.context import get_current_settings
|
60
57
|
from prefect.states import Pending, Scheduled, State
|
61
58
|
from prefect.utilities.annotations import NotSet
|
62
59
|
from prefect.utilities.asyncutils import run_coro_as_sync, sync_compatible
|
@@ -70,6 +67,8 @@ from prefect.utilities.importtools import to_qualified_name
|
|
70
67
|
from prefect.utilities.urls import url_for
|
71
68
|
|
72
69
|
if TYPE_CHECKING:
|
70
|
+
import logging
|
71
|
+
|
73
72
|
from prefect.client.orchestration import PrefectClient
|
74
73
|
from prefect.context import TaskRunContext
|
75
74
|
from prefect.transactions import Transaction
|
@@ -80,7 +79,7 @@ P = ParamSpec("P") # The parameters of the task
|
|
80
79
|
|
81
80
|
NUM_CHARS_DYNAMIC_KEY = 8
|
82
81
|
|
83
|
-
logger = get_logger("tasks")
|
82
|
+
logger: "logging.Logger" = get_logger("tasks")
|
84
83
|
|
85
84
|
FutureOrResult: TypeAlias = Union[PrefectFuture[T], T]
|
86
85
|
OneOrManyFutureOrResult: TypeAlias = Union[
|
@@ -383,19 +382,19 @@ class Task(Generic[P, R]):
|
|
383
382
|
if not callable(fn):
|
384
383
|
raise TypeError("'fn' must be callable")
|
385
384
|
|
386
|
-
self.description = description or inspect.getdoc(fn)
|
385
|
+
self.description: str | None = description or inspect.getdoc(fn)
|
387
386
|
update_wrapper(self, fn)
|
388
387
|
self.fn = fn
|
389
388
|
|
390
389
|
# the task is considered async if its function is async or an async
|
391
390
|
# generator
|
392
|
-
self.isasync = asyncio.iscoroutinefunction(
|
391
|
+
self.isasync: bool = asyncio.iscoroutinefunction(
|
393
392
|
self.fn
|
394
393
|
) or inspect.isasyncgenfunction(self.fn)
|
395
394
|
|
396
395
|
# the task is considered a generator if its function is a generator or
|
397
396
|
# an async generator
|
398
|
-
self.isgenerator = inspect.isgeneratorfunction(
|
397
|
+
self.isgenerator: bool = inspect.isgeneratorfunction(
|
399
398
|
self.fn
|
400
399
|
) or inspect.isasyncgenfunction(self.fn)
|
401
400
|
|
@@ -405,7 +404,7 @@ class Task(Generic[P, R]):
|
|
405
404
|
else:
|
406
405
|
self.name = self.fn.__name__
|
407
406
|
else:
|
408
|
-
self.name = name
|
407
|
+
self.name: str = name
|
409
408
|
|
410
409
|
if task_run_name is not None:
|
411
410
|
if not isinstance(task_run_name, str) and not callable(task_run_name):
|
@@ -420,9 +419,9 @@ class Task(Generic[P, R]):
|
|
420
419
|
|
421
420
|
raise_for_reserved_arguments(self.fn, ["return_state", "wait_for"])
|
422
421
|
|
423
|
-
self.tags = set(tags if tags else [])
|
422
|
+
self.tags: set[str] = set(tags if tags else [])
|
424
423
|
|
425
|
-
self.task_key = _generate_task_key(self.fn)
|
424
|
+
self.task_key: str = _generate_task_key(self.fn)
|
426
425
|
|
427
426
|
if cache_policy is not NotSet and cache_key_fn is not None:
|
428
427
|
logger.warning(
|
@@ -464,26 +463,29 @@ class Task(Generic[P, R]):
|
|
464
463
|
# TODO: handle this situation with double storage
|
465
464
|
self.cache_policy = None
|
466
465
|
else:
|
467
|
-
self.cache_policy = cache_policy
|
466
|
+
self.cache_policy: Union[CachePolicy, type[NotSet], None] = cache_policy
|
468
467
|
|
469
468
|
# TaskRunPolicy settings
|
470
469
|
# TODO: We can instantiate a `TaskRunPolicy` and add Pydantic bound checks to
|
471
470
|
# validate that the user passes positive numbers here
|
472
471
|
|
473
|
-
|
474
|
-
|
472
|
+
settings = get_current_settings()
|
473
|
+
self.retries: int = (
|
474
|
+
retries if retries is not None else settings.tasks.default_retries
|
475
475
|
)
|
476
476
|
if retry_delay_seconds is None:
|
477
|
-
retry_delay_seconds =
|
477
|
+
retry_delay_seconds = settings.tasks.default_retry_delay_seconds
|
478
478
|
|
479
479
|
if callable(retry_delay_seconds):
|
480
|
-
self.retry_delay_seconds = retry_delay_seconds(retries)
|
480
|
+
self.retry_delay_seconds = retry_delay_seconds(self.retries)
|
481
481
|
elif not isinstance(retry_delay_seconds, (list, int, float, type(None))):
|
482
482
|
raise TypeError(
|
483
483
|
f"Invalid `retry_delay_seconds` provided; must be an int, float, list or callable. Received type {type(retry_delay_seconds)}"
|
484
484
|
)
|
485
485
|
else:
|
486
|
-
self.retry_delay_seconds
|
486
|
+
self.retry_delay_seconds: Union[
|
487
|
+
float, int, list[float], None
|
488
|
+
] = retry_delay_seconds
|
487
489
|
|
488
490
|
if isinstance(self.retry_delay_seconds, list) and (
|
489
491
|
len(self.retry_delay_seconds) > 50
|
@@ -507,11 +509,15 @@ class Task(Generic[P, R]):
|
|
507
509
|
self.result_serializer = result_serializer
|
508
510
|
self.result_storage_key = result_storage_key
|
509
511
|
self.cache_result_in_memory = cache_result_in_memory
|
510
|
-
self.timeout_seconds
|
511
|
-
|
512
|
-
|
513
|
-
self.
|
514
|
-
|
512
|
+
self.timeout_seconds: Union[float, None] = (
|
513
|
+
float(timeout_seconds) if timeout_seconds else None
|
514
|
+
)
|
515
|
+
self.on_rollback_hooks: list[Callable[["Transaction"], None]] = (
|
516
|
+
on_rollback or []
|
517
|
+
)
|
518
|
+
self.on_commit_hooks: list[Callable[["Transaction"], None]] = on_commit or []
|
519
|
+
self.on_completion_hooks: list[StateHookCallable] = on_completion or []
|
520
|
+
self.on_failure_hooks: list[StateHookCallable] = on_failure or []
|
515
521
|
|
516
522
|
# retry_condition_fn must be a callable or None. If it is neither, raise a TypeError
|
517
523
|
if retry_condition_fn is not None and not (callable(retry_condition_fn)):
|
@@ -527,7 +533,7 @@ class Task(Generic[P, R]):
|
|
527
533
|
def ismethod(self) -> bool:
|
528
534
|
return hasattr(self.fn, "__prefect_self__")
|
529
535
|
|
530
|
-
def __get__(self, instance: Any, owner: Any):
|
536
|
+
def __get__(self, instance: Any, owner: Any) -> "Task[P, R]":
|
531
537
|
"""
|
532
538
|
Implement the descriptor protocol so that the task can be used as an instance method.
|
533
539
|
When an instance method is loaded, this method is called with the "self" instance as
|
@@ -582,7 +588,7 @@ class Task(Generic[P, R]):
|
|
582
588
|
Callable[["Task[..., Any]", TaskRun, State], bool]
|
583
589
|
] = None,
|
584
590
|
viz_return_value: Optional[Any] = None,
|
585
|
-
):
|
591
|
+
) -> "Task[P, R]":
|
586
592
|
"""
|
587
593
|
Create a new task from the current object, updating provided options.
|
588
594
|
|
prefect/telemetry/bootstrap.py
CHANGED
@@ -4,7 +4,10 @@ import prefect.settings
|
|
4
4
|
from prefect.client.base import ServerType, determine_server_type
|
5
5
|
from prefect.logging.loggers import get_logger
|
6
6
|
|
7
|
-
|
7
|
+
if TYPE_CHECKING:
|
8
|
+
import logging
|
9
|
+
|
10
|
+
logger: "logging.Logger" = get_logger(__name__)
|
8
11
|
|
9
12
|
if TYPE_CHECKING:
|
10
13
|
from opentelemetry.sdk._logs import LoggerProvider
|
@@ -1,6 +1,8 @@
|
|
1
|
+
from __future__ import annotations
|
2
|
+
|
1
3
|
import time
|
2
4
|
from dataclasses import dataclass, field
|
3
|
-
from typing import TYPE_CHECKING, Any,
|
5
|
+
from typing import TYPE_CHECKING, Any, Union
|
4
6
|
|
5
7
|
from opentelemetry import propagate, trace
|
6
8
|
from opentelemetry.context import Context
|
@@ -47,14 +49,14 @@ class RunTelemetry:
|
|
47
49
|
_tracer: "Tracer" = field(
|
48
50
|
default_factory=lambda: get_tracer("prefect", prefect.__version__)
|
49
51
|
)
|
50
|
-
span:
|
52
|
+
span: Span | None = None
|
51
53
|
|
52
54
|
async def async_start_span(
|
53
55
|
self,
|
54
56
|
run: FlowOrTaskRun,
|
55
57
|
client: PrefectClient,
|
56
|
-
parameters:
|
57
|
-
):
|
58
|
+
parameters: dict[str, Any] | None = None,
|
59
|
+
) -> Span:
|
58
60
|
traceparent, span = self._start_span(run, parameters)
|
59
61
|
|
60
62
|
if self._run_type(run) == "flow" and traceparent:
|
@@ -70,8 +72,8 @@ class RunTelemetry:
|
|
70
72
|
self,
|
71
73
|
run: FlowOrTaskRun,
|
72
74
|
client: SyncPrefectClient,
|
73
|
-
parameters:
|
74
|
-
):
|
75
|
+
parameters: dict[str, Any] | None = None,
|
76
|
+
) -> Span:
|
75
77
|
traceparent, span = self._start_span(run, parameters)
|
76
78
|
|
77
79
|
if self._run_type(run) == "flow" and traceparent:
|
@@ -84,8 +86,8 @@ class RunTelemetry:
|
|
84
86
|
def _start_span(
|
85
87
|
self,
|
86
88
|
run: FlowOrTaskRun,
|
87
|
-
parameters:
|
88
|
-
) -> tuple[
|
89
|
+
parameters: dict[str, Any] | None = None,
|
90
|
+
) -> tuple[str | None, Span]:
|
89
91
|
"""
|
90
92
|
Start a span for a run.
|
91
93
|
"""
|
@@ -139,8 +141,8 @@ class RunTelemetry:
|
|
139
141
|
return "task" if isinstance(run, TaskRun) else "flow"
|
140
142
|
|
141
143
|
def _trace_context_from_labels(
|
142
|
-
self, labels:
|
143
|
-
) ->
|
144
|
+
self, labels: KeyValueLabels | None
|
145
|
+
) -> Context | None:
|
144
146
|
"""Get trace context from run labels if it exists."""
|
145
147
|
if not labels or LABELS_TRACEPARENT_KEY not in labels:
|
146
148
|
return None
|
@@ -148,7 +150,7 @@ class RunTelemetry:
|
|
148
150
|
carrier = {TRACEPARENT_KEY: traceparent}
|
149
151
|
return propagate.extract(carrier)
|
150
152
|
|
151
|
-
def _traceparent_from_span(self, span: Span) ->
|
153
|
+
def _traceparent_from_span(self, span: Span) -> str | None:
|
152
154
|
carrier: dict[str, Any] = {}
|
153
155
|
propagate.inject(carrier, context=trace.set_span_in_context(span))
|
154
156
|
return carrier.get(TRACEPARENT_KEY)
|
@@ -162,7 +164,7 @@ class RunTelemetry:
|
|
162
164
|
self.span.end(time.time_ns())
|
163
165
|
self.span = None
|
164
166
|
|
165
|
-
def end_span_on_failure(self, terminal_message:
|
167
|
+
def end_span_on_failure(self, terminal_message: str | None = None) -> None:
|
166
168
|
"""
|
167
169
|
End a span for a run on failure.
|
168
170
|
"""
|
@@ -203,7 +205,7 @@ class RunTelemetry:
|
|
203
205
|
self.span.update_name(name=name)
|
204
206
|
self.span.set_attribute("prefect.run.name", name)
|
205
207
|
|
206
|
-
def _parent_run(self) ->
|
208
|
+
def _parent_run(self) -> FlowOrTaskRun | None:
|
207
209
|
"""
|
208
210
|
Identify the "parent run" for the current execution context.
|
209
211
|
|
prefect/transactions.py
CHANGED
@@ -173,7 +173,7 @@ class Transaction(ContextModel):
|
|
173
173
|
def is_active(self) -> bool:
|
174
174
|
return self.state == TransactionState.ACTIVE
|
175
175
|
|
176
|
-
def __enter__(self):
|
176
|
+
def __enter__(self) -> Self:
|
177
177
|
if self._token is not None:
|
178
178
|
raise RuntimeError(
|
179
179
|
"Context already entered. Context enter calls cannot be nested."
|
@@ -206,7 +206,7 @@ class Transaction(ContextModel):
|
|
206
206
|
self._token = self.__var__.set(self)
|
207
207
|
return self
|
208
208
|
|
209
|
-
def __exit__(self, *exc_info: Any):
|
209
|
+
def __exit__(self, *exc_info: Any) -> None:
|
210
210
|
exc_type, exc_val, _ = exc_info
|
211
211
|
if not self._token:
|
212
212
|
raise RuntimeError(
|
@@ -235,7 +235,7 @@ class Transaction(ContextModel):
|
|
235
235
|
|
236
236
|
self.reset()
|
237
237
|
|
238
|
-
def begin(self):
|
238
|
+
def begin(self) -> None:
|
239
239
|
if (
|
240
240
|
self.store
|
241
241
|
and self.key
|
prefect/types/__init__.py
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
from __future__ import annotations
|
2
|
+
|
1
3
|
from functools import partial
|
2
4
|
from typing import Annotated, Any, Dict, List, Optional, Set, TypeVar, Union
|
3
5
|
from typing_extensions import Literal, TypeAlias
|
@@ -114,7 +116,7 @@ class SecretDict(pydantic.Secret[Dict[str, Any]]):
|
|
114
116
|
|
115
117
|
|
116
118
|
def validate_set_T_from_delim_string(
|
117
|
-
value: Union[str, T, Set[T], None], type_, delim=None
|
119
|
+
value: Union[str, T, Set[T], None], type_: type[T], delim: str | None = None
|
118
120
|
) -> Set[T]:
|
119
121
|
"""
|
120
122
|
"no-info" before validator useful in scooping env vars
|
@@ -0,0 +1,38 @@
|
|
1
|
+
from typing import Any
|
2
|
+
|
3
|
+
from jsonpatch import ( # type: ignore # no typing stubs available, see https://github.com/stefankoegl/python-json-patch/issues/158
|
4
|
+
JsonPatch as JsonPatchBase,
|
5
|
+
)
|
6
|
+
from pydantic import GetJsonSchemaHandler
|
7
|
+
from pydantic.json_schema import JsonSchemaValue
|
8
|
+
from pydantic_core import core_schema
|
9
|
+
|
10
|
+
|
11
|
+
class JsonPatch(JsonPatchBase):
|
12
|
+
@classmethod
|
13
|
+
def __get_pydantic_core_schema__(
|
14
|
+
cls, source_type: Any, handler: GetJsonSchemaHandler
|
15
|
+
) -> core_schema.CoreSchema:
|
16
|
+
return core_schema.typed_dict_schema(
|
17
|
+
{"patch": core_schema.typed_dict_field(core_schema.dict_schema())}
|
18
|
+
)
|
19
|
+
|
20
|
+
@classmethod
|
21
|
+
def __get_pydantic_json_schema__(
|
22
|
+
cls, core_schema: core_schema.CoreSchema, handler: GetJsonSchemaHandler
|
23
|
+
) -> JsonSchemaValue:
|
24
|
+
json_schema = handler(core_schema)
|
25
|
+
json_schema = handler.resolve_ref_schema(json_schema)
|
26
|
+
json_schema.pop("required", None)
|
27
|
+
json_schema.pop("properties", None)
|
28
|
+
json_schema.update(
|
29
|
+
{
|
30
|
+
"type": "array",
|
31
|
+
"format": "rfc6902",
|
32
|
+
"items": {
|
33
|
+
"type": "object",
|
34
|
+
"additionalProperties": {"type": "string"},
|
35
|
+
},
|
36
|
+
}
|
37
|
+
)
|
38
|
+
return json_schema
|
prefect/utilities/engine.py
CHANGED
@@ -757,12 +757,19 @@ def resolve_to_final_result(expr: Any, context: dict[str, Any]) -> Any:
|
|
757
757
|
parameter_context = propagate.extract(
|
758
758
|
{"traceparent": state.state_details.traceparent}
|
759
759
|
)
|
760
|
-
|
761
|
-
|
762
|
-
|
760
|
+
attributes = {}
|
761
|
+
|
762
|
+
# If this future is being used as a parameter (as opposed to just a wait_for),
|
763
|
+
# add attributes to the span to indicate the parameter name and type
|
764
|
+
if "parameter_name" in context:
|
765
|
+
attributes = {
|
763
766
|
"prefect.input.name": context["parameter_name"],
|
764
767
|
"prefect.input.type": type(result).__name__,
|
765
|
-
}
|
768
|
+
}
|
769
|
+
|
770
|
+
trace.get_current_span().add_link(
|
771
|
+
context=trace.get_current_span(parameter_context).get_span_context(),
|
772
|
+
attributes=attributes,
|
766
773
|
)
|
767
774
|
|
768
775
|
return result
|
prefect/utilities/filesystem.py
CHANGED
@@ -8,7 +8,7 @@ import threading
|
|
8
8
|
from collections.abc import Iterable
|
9
9
|
from contextlib import contextmanager
|
10
10
|
from pathlib import Path, PureWindowsPath
|
11
|
-
from typing import AnyStr, Optional, Union, cast
|
11
|
+
from typing import Any, AnyStr, Optional, Union, cast
|
12
12
|
|
13
13
|
# fsspec has no stubs, see https://github.com/fsspec/filesystem_spec/issues/625
|
14
14
|
import fsspec # type: ignore
|
@@ -114,7 +114,7 @@ def filename(path: str) -> str:
|
|
114
114
|
return path.split(sep)[-1]
|
115
115
|
|
116
116
|
|
117
|
-
def is_local_path(path: Union[str, pathlib.Path,
|
117
|
+
def is_local_path(path: Union[str, pathlib.Path, Any]) -> bool:
|
118
118
|
"""Check if the given path points to a local or remote file system"""
|
119
119
|
if isinstance(path, str):
|
120
120
|
try:
|
prefect/utilities/generics.py
CHANGED
@@ -5,7 +5,7 @@ from pydantic_core import SchemaValidator, core_schema
|
|
5
5
|
|
6
6
|
T = TypeVar("T", bound=BaseModel)
|
7
7
|
|
8
|
-
ListValidator = SchemaValidator(
|
8
|
+
ListValidator: SchemaValidator = SchemaValidator(
|
9
9
|
schema=core_schema.list_schema(
|
10
10
|
items_schema=core_schema.dict_schema(
|
11
11
|
keys_schema=core_schema.str_schema(), values_schema=core_schema.any_schema()
|
prefect/utilities/pydantic.py
CHANGED
@@ -1,3 +1,4 @@
|
|
1
|
+
import warnings
|
1
2
|
from typing import (
|
2
3
|
Any,
|
3
4
|
Callable,
|
@@ -10,18 +11,13 @@ from typing import (
|
|
10
11
|
overload,
|
11
12
|
)
|
12
13
|
|
13
|
-
from jsonpatch import ( # type: ignore # no typing stubs available, see https://github.com/stefankoegl/python-json-patch/issues/158
|
14
|
-
JsonPatch as JsonPatchBase,
|
15
|
-
)
|
16
14
|
from pydantic import (
|
17
15
|
BaseModel,
|
18
|
-
GetJsonSchemaHandler,
|
19
16
|
Secret,
|
20
17
|
TypeAdapter,
|
21
18
|
ValidationError,
|
22
19
|
)
|
23
|
-
from
|
24
|
-
from pydantic_core import core_schema, to_jsonable_python
|
20
|
+
from pydantic_core import to_jsonable_python
|
25
21
|
from typing_extensions import Literal
|
26
22
|
|
27
23
|
from prefect.utilities.dispatch import get_dispatch_key, lookup_type, register_base_type
|
@@ -262,36 +258,6 @@ class PartialModel(Generic[M]):
|
|
262
258
|
return f"PartialModel(cls={self.model_cls.__name__}, {dsp_fields})"
|
263
259
|
|
264
260
|
|
265
|
-
class JsonPatch(JsonPatchBase):
|
266
|
-
@classmethod
|
267
|
-
def __get_pydantic_core_schema__(
|
268
|
-
cls, source_type: Any, handler: GetJsonSchemaHandler
|
269
|
-
) -> core_schema.CoreSchema:
|
270
|
-
return core_schema.typed_dict_schema(
|
271
|
-
{"patch": core_schema.typed_dict_field(core_schema.dict_schema())}
|
272
|
-
)
|
273
|
-
|
274
|
-
@classmethod
|
275
|
-
def __get_pydantic_json_schema__(
|
276
|
-
cls, core_schema: core_schema.CoreSchema, handler: GetJsonSchemaHandler
|
277
|
-
) -> JsonSchemaValue:
|
278
|
-
json_schema = handler(core_schema)
|
279
|
-
json_schema = handler.resolve_ref_schema(json_schema)
|
280
|
-
json_schema.pop("required", None)
|
281
|
-
json_schema.pop("properties", None)
|
282
|
-
json_schema.update(
|
283
|
-
{
|
284
|
-
"type": "array",
|
285
|
-
"format": "rfc6902",
|
286
|
-
"items": {
|
287
|
-
"type": "object",
|
288
|
-
"additionalProperties": {"type": "string"},
|
289
|
-
},
|
290
|
-
}
|
291
|
-
)
|
292
|
-
return json_schema
|
293
|
-
|
294
|
-
|
295
261
|
def custom_pydantic_encoder(
|
296
262
|
type_encoders: dict[Any, Callable[[type[Any]], Any]], obj: Any
|
297
263
|
) -> Any:
|
@@ -382,3 +348,22 @@ def handle_secret_render(value: object, context: dict[str, Any]) -> object:
|
|
382
348
|
elif isinstance(value, BaseModel):
|
383
349
|
return value.model_dump(context=context)
|
384
350
|
return value
|
351
|
+
|
352
|
+
|
353
|
+
def __getattr__(name: str) -> Any:
|
354
|
+
"""
|
355
|
+
Handles imports from this module that are deprecated.
|
356
|
+
"""
|
357
|
+
|
358
|
+
if name == "JsonPatch":
|
359
|
+
warnings.warn(
|
360
|
+
"JsonPatch is deprecated and will be removed after March 2025. "
|
361
|
+
"Please use `JsonPatch` from the `jsonpatch` package instead.",
|
362
|
+
DeprecationWarning,
|
363
|
+
stacklevel=2,
|
364
|
+
)
|
365
|
+
from ._deprecated import JsonPatch
|
366
|
+
|
367
|
+
return JsonPatch
|
368
|
+
else:
|
369
|
+
raise AttributeError(f"module '{__name__}' has no attribute '{name}'")
|