prefect-client 2.19.3__py3-none-any.whl → 3.0.0rc1__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 +8 -56
- prefect/_internal/compatibility/deprecated.py +6 -115
- prefect/_internal/compatibility/experimental.py +4 -79
- prefect/_internal/concurrency/api.py +0 -34
- prefect/_internal/concurrency/calls.py +0 -6
- prefect/_internal/concurrency/cancellation.py +0 -3
- prefect/_internal/concurrency/event_loop.py +0 -20
- prefect/_internal/concurrency/inspection.py +3 -3
- prefect/_internal/concurrency/threads.py +35 -0
- prefect/_internal/concurrency/waiters.py +0 -28
- prefect/_internal/pydantic/__init__.py +0 -45
- prefect/_internal/pydantic/v1_schema.py +21 -22
- prefect/_internal/pydantic/v2_schema.py +0 -2
- prefect/_internal/pydantic/v2_validated_func.py +18 -23
- prefect/_internal/schemas/bases.py +44 -177
- prefect/_internal/schemas/fields.py +1 -43
- prefect/_internal/schemas/validators.py +60 -158
- prefect/artifacts.py +161 -14
- prefect/automations.py +39 -4
- prefect/blocks/abstract.py +1 -1
- prefect/blocks/core.py +268 -148
- prefect/blocks/fields.py +2 -57
- prefect/blocks/kubernetes.py +8 -12
- prefect/blocks/notifications.py +40 -20
- prefect/blocks/system.py +22 -11
- prefect/blocks/webhook.py +2 -9
- prefect/client/base.py +4 -4
- prefect/client/cloud.py +8 -13
- prefect/client/orchestration.py +347 -341
- prefect/client/schemas/actions.py +92 -86
- prefect/client/schemas/filters.py +20 -40
- prefect/client/schemas/objects.py +147 -145
- prefect/client/schemas/responses.py +16 -24
- prefect/client/schemas/schedules.py +47 -35
- prefect/client/subscriptions.py +2 -2
- prefect/client/utilities.py +5 -2
- prefect/concurrency/asyncio.py +3 -1
- prefect/concurrency/events.py +1 -1
- prefect/concurrency/services.py +6 -3
- prefect/context.py +195 -27
- prefect/deployments/__init__.py +5 -6
- prefect/deployments/base.py +7 -5
- prefect/deployments/flow_runs.py +185 -0
- prefect/deployments/runner.py +50 -45
- prefect/deployments/schedules.py +28 -23
- prefect/deployments/steps/__init__.py +0 -1
- prefect/deployments/steps/core.py +1 -0
- prefect/deployments/steps/pull.py +7 -21
- prefect/engine.py +12 -2422
- prefect/events/actions.py +17 -23
- prefect/events/cli/automations.py +19 -6
- prefect/events/clients.py +14 -37
- prefect/events/filters.py +14 -18
- prefect/events/related.py +2 -2
- prefect/events/schemas/__init__.py +0 -5
- prefect/events/schemas/automations.py +55 -46
- prefect/events/schemas/deployment_triggers.py +7 -197
- prefect/events/schemas/events.py +34 -65
- prefect/events/schemas/labelling.py +10 -14
- prefect/events/utilities.py +2 -3
- prefect/events/worker.py +2 -3
- prefect/filesystems.py +6 -517
- prefect/{new_flow_engine.py → flow_engine.py} +313 -72
- prefect/flow_runs.py +377 -5
- prefect/flows.py +248 -165
- prefect/futures.py +186 -345
- prefect/infrastructure/__init__.py +0 -27
- prefect/infrastructure/provisioners/__init__.py +5 -3
- prefect/infrastructure/provisioners/cloud_run.py +11 -6
- prefect/infrastructure/provisioners/container_instance.py +11 -7
- prefect/infrastructure/provisioners/ecs.py +6 -4
- prefect/infrastructure/provisioners/modal.py +8 -5
- prefect/input/actions.py +2 -4
- prefect/input/run_input.py +5 -7
- prefect/logging/formatters.py +0 -2
- prefect/logging/handlers.py +3 -11
- prefect/logging/loggers.py +2 -2
- prefect/manifests.py +2 -1
- prefect/records/__init__.py +1 -0
- prefect/records/result_store.py +42 -0
- prefect/records/store.py +9 -0
- prefect/results.py +43 -39
- prefect/runner/runner.py +9 -9
- prefect/runner/server.py +6 -10
- prefect/runner/storage.py +3 -8
- prefect/runner/submit.py +2 -2
- prefect/runner/utils.py +2 -2
- prefect/serializers.py +24 -35
- prefect/server/api/collections_data/views/aggregate-worker-metadata.json +5 -14
- prefect/settings.py +70 -133
- prefect/states.py +17 -47
- prefect/task_engine.py +697 -58
- prefect/task_runners.py +269 -301
- prefect/task_server.py +53 -34
- prefect/tasks.py +327 -337
- prefect/transactions.py +220 -0
- prefect/types/__init__.py +61 -82
- prefect/utilities/asyncutils.py +195 -136
- prefect/utilities/callables.py +121 -41
- prefect/utilities/collections.py +23 -38
- prefect/utilities/dispatch.py +11 -3
- prefect/utilities/dockerutils.py +4 -0
- prefect/utilities/engine.py +140 -20
- prefect/utilities/importtools.py +26 -27
- prefect/utilities/pydantic.py +128 -38
- prefect/utilities/schema_tools/hydration.py +5 -1
- prefect/utilities/templating.py +12 -2
- prefect/variables.py +78 -61
- prefect/workers/__init__.py +0 -1
- prefect/workers/base.py +15 -17
- prefect/workers/process.py +3 -8
- prefect/workers/server.py +2 -2
- {prefect_client-2.19.3.dist-info → prefect_client-3.0.0rc1.dist-info}/METADATA +22 -21
- prefect_client-3.0.0rc1.dist-info/RECORD +176 -0
- prefect/_internal/pydantic/_base_model.py +0 -51
- prefect/_internal/pydantic/_compat.py +0 -82
- prefect/_internal/pydantic/_flags.py +0 -20
- prefect/_internal/pydantic/_types.py +0 -8
- prefect/_internal/pydantic/utilities/__init__.py +0 -0
- prefect/_internal/pydantic/utilities/config_dict.py +0 -72
- prefect/_internal/pydantic/utilities/field_validator.py +0 -150
- prefect/_internal/pydantic/utilities/model_construct.py +0 -56
- prefect/_internal/pydantic/utilities/model_copy.py +0 -55
- prefect/_internal/pydantic/utilities/model_dump.py +0 -136
- prefect/_internal/pydantic/utilities/model_dump_json.py +0 -112
- prefect/_internal/pydantic/utilities/model_fields.py +0 -50
- prefect/_internal/pydantic/utilities/model_fields_set.py +0 -29
- prefect/_internal/pydantic/utilities/model_json_schema.py +0 -82
- prefect/_internal/pydantic/utilities/model_rebuild.py +0 -80
- prefect/_internal/pydantic/utilities/model_validate.py +0 -75
- prefect/_internal/pydantic/utilities/model_validate_json.py +0 -68
- prefect/_internal/pydantic/utilities/model_validator.py +0 -87
- prefect/_internal/pydantic/utilities/type_adapter.py +0 -71
- prefect/_vendor/__init__.py +0 -0
- prefect/_vendor/fastapi/__init__.py +0 -25
- prefect/_vendor/fastapi/applications.py +0 -946
- prefect/_vendor/fastapi/background.py +0 -3
- prefect/_vendor/fastapi/concurrency.py +0 -44
- prefect/_vendor/fastapi/datastructures.py +0 -58
- prefect/_vendor/fastapi/dependencies/__init__.py +0 -0
- prefect/_vendor/fastapi/dependencies/models.py +0 -64
- prefect/_vendor/fastapi/dependencies/utils.py +0 -877
- prefect/_vendor/fastapi/encoders.py +0 -177
- prefect/_vendor/fastapi/exception_handlers.py +0 -40
- prefect/_vendor/fastapi/exceptions.py +0 -46
- prefect/_vendor/fastapi/logger.py +0 -3
- prefect/_vendor/fastapi/middleware/__init__.py +0 -1
- prefect/_vendor/fastapi/middleware/asyncexitstack.py +0 -25
- prefect/_vendor/fastapi/middleware/cors.py +0 -3
- prefect/_vendor/fastapi/middleware/gzip.py +0 -3
- prefect/_vendor/fastapi/middleware/httpsredirect.py +0 -3
- prefect/_vendor/fastapi/middleware/trustedhost.py +0 -3
- prefect/_vendor/fastapi/middleware/wsgi.py +0 -3
- prefect/_vendor/fastapi/openapi/__init__.py +0 -0
- prefect/_vendor/fastapi/openapi/constants.py +0 -2
- prefect/_vendor/fastapi/openapi/docs.py +0 -203
- prefect/_vendor/fastapi/openapi/models.py +0 -480
- prefect/_vendor/fastapi/openapi/utils.py +0 -485
- prefect/_vendor/fastapi/param_functions.py +0 -340
- prefect/_vendor/fastapi/params.py +0 -453
- prefect/_vendor/fastapi/requests.py +0 -4
- prefect/_vendor/fastapi/responses.py +0 -40
- prefect/_vendor/fastapi/routing.py +0 -1331
- prefect/_vendor/fastapi/security/__init__.py +0 -15
- prefect/_vendor/fastapi/security/api_key.py +0 -98
- prefect/_vendor/fastapi/security/base.py +0 -6
- prefect/_vendor/fastapi/security/http.py +0 -172
- prefect/_vendor/fastapi/security/oauth2.py +0 -227
- prefect/_vendor/fastapi/security/open_id_connect_url.py +0 -34
- prefect/_vendor/fastapi/security/utils.py +0 -10
- prefect/_vendor/fastapi/staticfiles.py +0 -1
- prefect/_vendor/fastapi/templating.py +0 -3
- prefect/_vendor/fastapi/testclient.py +0 -1
- prefect/_vendor/fastapi/types.py +0 -3
- prefect/_vendor/fastapi/utils.py +0 -235
- prefect/_vendor/fastapi/websockets.py +0 -7
- prefect/_vendor/starlette/__init__.py +0 -1
- prefect/_vendor/starlette/_compat.py +0 -28
- prefect/_vendor/starlette/_exception_handler.py +0 -80
- prefect/_vendor/starlette/_utils.py +0 -88
- prefect/_vendor/starlette/applications.py +0 -261
- prefect/_vendor/starlette/authentication.py +0 -159
- prefect/_vendor/starlette/background.py +0 -43
- prefect/_vendor/starlette/concurrency.py +0 -59
- prefect/_vendor/starlette/config.py +0 -151
- prefect/_vendor/starlette/convertors.py +0 -87
- prefect/_vendor/starlette/datastructures.py +0 -707
- prefect/_vendor/starlette/endpoints.py +0 -130
- prefect/_vendor/starlette/exceptions.py +0 -60
- prefect/_vendor/starlette/formparsers.py +0 -276
- prefect/_vendor/starlette/middleware/__init__.py +0 -17
- prefect/_vendor/starlette/middleware/authentication.py +0 -52
- prefect/_vendor/starlette/middleware/base.py +0 -220
- prefect/_vendor/starlette/middleware/cors.py +0 -176
- prefect/_vendor/starlette/middleware/errors.py +0 -265
- prefect/_vendor/starlette/middleware/exceptions.py +0 -74
- prefect/_vendor/starlette/middleware/gzip.py +0 -113
- prefect/_vendor/starlette/middleware/httpsredirect.py +0 -19
- prefect/_vendor/starlette/middleware/sessions.py +0 -82
- prefect/_vendor/starlette/middleware/trustedhost.py +0 -64
- prefect/_vendor/starlette/middleware/wsgi.py +0 -147
- prefect/_vendor/starlette/requests.py +0 -328
- prefect/_vendor/starlette/responses.py +0 -347
- prefect/_vendor/starlette/routing.py +0 -933
- prefect/_vendor/starlette/schemas.py +0 -154
- prefect/_vendor/starlette/staticfiles.py +0 -248
- prefect/_vendor/starlette/status.py +0 -199
- prefect/_vendor/starlette/templating.py +0 -231
- prefect/_vendor/starlette/testclient.py +0 -804
- prefect/_vendor/starlette/types.py +0 -30
- prefect/_vendor/starlette/websockets.py +0 -193
- prefect/agent.py +0 -698
- prefect/deployments/deployments.py +0 -1042
- prefect/deprecated/__init__.py +0 -0
- prefect/deprecated/data_documents.py +0 -350
- prefect/deprecated/packaging/__init__.py +0 -12
- prefect/deprecated/packaging/base.py +0 -96
- prefect/deprecated/packaging/docker.py +0 -146
- prefect/deprecated/packaging/file.py +0 -92
- prefect/deprecated/packaging/orion.py +0 -80
- prefect/deprecated/packaging/serializers.py +0 -171
- prefect/events/instrument.py +0 -135
- prefect/infrastructure/base.py +0 -323
- prefect/infrastructure/container.py +0 -818
- prefect/infrastructure/kubernetes.py +0 -920
- prefect/infrastructure/process.py +0 -289
- prefect/new_task_engine.py +0 -423
- prefect/pydantic/__init__.py +0 -76
- prefect/pydantic/main.py +0 -39
- prefect/software/__init__.py +0 -2
- prefect/software/base.py +0 -50
- prefect/software/conda.py +0 -199
- prefect/software/pip.py +0 -122
- prefect/software/python.py +0 -52
- prefect/workers/block.py +0 -218
- prefect_client-2.19.3.dist-info/RECORD +0 -292
- {prefect_client-2.19.3.dist-info → prefect_client-3.0.0rc1.dist-info}/LICENSE +0 -0
- {prefect_client-2.19.3.dist-info → prefect_client-3.0.0rc1.dist-info}/WHEEL +0 -0
- {prefect_client-2.19.3.dist-info → prefect_client-3.0.0rc1.dist-info}/top_level.txt +0 -0
prefect/utilities/pydantic.py
CHANGED
@@ -1,25 +1,38 @@
|
|
1
1
|
from functools import partial
|
2
|
-
from typing import
|
2
|
+
from typing import (
|
3
|
+
Any,
|
4
|
+
Callable,
|
5
|
+
Dict,
|
6
|
+
Generic,
|
7
|
+
Optional,
|
8
|
+
Type,
|
9
|
+
TypeVar,
|
10
|
+
cast,
|
11
|
+
get_origin,
|
12
|
+
overload,
|
13
|
+
)
|
3
14
|
|
4
15
|
from jsonpatch import JsonPatch as JsonPatchBase
|
5
|
-
from
|
6
|
-
|
16
|
+
from pydantic import (
|
17
|
+
BaseModel,
|
18
|
+
GetJsonSchemaHandler,
|
19
|
+
Secret,
|
20
|
+
TypeAdapter,
|
21
|
+
ValidationError,
|
22
|
+
)
|
23
|
+
from pydantic.json_schema import JsonSchemaValue
|
24
|
+
from pydantic_core import core_schema, to_jsonable_python
|
25
|
+
from typing_extensions import Literal
|
7
26
|
|
8
|
-
from prefect._internal.pydantic.utilities.model_dump import model_dump
|
9
|
-
from prefect.pydantic import HAS_PYDANTIC_V2
|
10
27
|
from prefect.utilities.dispatch import get_dispatch_key, lookup_type, register_base_type
|
11
28
|
from prefect.utilities.importtools import from_qualified_name, to_qualified_name
|
12
29
|
|
13
|
-
if HAS_PYDANTIC_V2:
|
14
|
-
import pydantic.v1 as pydantic_v1
|
15
|
-
else:
|
16
|
-
import pydantic as pydantic_v1
|
17
|
-
|
18
30
|
D = TypeVar("D", bound=Any)
|
19
|
-
M = TypeVar("M", bound=
|
31
|
+
M = TypeVar("M", bound=BaseModel)
|
32
|
+
T = TypeVar("T", bound=Any)
|
20
33
|
|
21
34
|
|
22
|
-
def _reduce_model(model:
|
35
|
+
def _reduce_model(model: BaseModel):
|
23
36
|
"""
|
24
37
|
Helper for serializing a cythonized model with cloudpickle.
|
25
38
|
|
@@ -30,7 +43,7 @@ def _reduce_model(model: pydantic_v1.BaseModel):
|
|
30
43
|
_unreduce_model,
|
31
44
|
(
|
32
45
|
to_qualified_name(type(model)),
|
33
|
-
model.
|
46
|
+
model.model_dump_json(**getattr(model, "__reduce_kwargs__", {})),
|
34
47
|
),
|
35
48
|
)
|
36
49
|
|
@@ -38,7 +51,7 @@ def _reduce_model(model: pydantic_v1.BaseModel):
|
|
38
51
|
def _unreduce_model(model_name, json):
|
39
52
|
"""Helper for restoring model after serialization"""
|
40
53
|
model = from_qualified_name(model_name)
|
41
|
-
return model.
|
54
|
+
return model.model_validate_json(json)
|
42
55
|
|
43
56
|
|
44
57
|
@overload
|
@@ -53,7 +66,7 @@ def add_cloudpickle_reduction(
|
|
53
66
|
...
|
54
67
|
|
55
68
|
|
56
|
-
def add_cloudpickle_reduction(__model_cls: Type[M] = None, **kwargs: Any):
|
69
|
+
def add_cloudpickle_reduction(__model_cls: Optional[Type[M]] = None, **kwargs: Any):
|
57
70
|
"""
|
58
71
|
Adds a `__reducer__` to the given class that ensures it is cloudpickle compatible.
|
59
72
|
|
@@ -83,7 +96,7 @@ def add_cloudpickle_reduction(__model_cls: Type[M] = None, **kwargs: Any):
|
|
83
96
|
)
|
84
97
|
|
85
98
|
|
86
|
-
def get_class_fields_only(model: Type[
|
99
|
+
def get_class_fields_only(model: Type[BaseModel]) -> set:
|
87
100
|
"""
|
88
101
|
Gets all the field names defined on the model class but not any parent classes.
|
89
102
|
Any fields that are on the parent but redefined on the subclass are included.
|
@@ -92,7 +105,7 @@ def get_class_fields_only(model: Type[pydantic_v1.BaseModel]) -> set:
|
|
92
105
|
parent_class_fields = set()
|
93
106
|
|
94
107
|
for base in model.__class__.__bases__:
|
95
|
-
if issubclass(base,
|
108
|
+
if issubclass(base, BaseModel):
|
96
109
|
parent_class_fields.update(base.__annotations__.keys())
|
97
110
|
|
98
111
|
return (subclass_class_fields - parent_class_fields) | (
|
@@ -125,7 +138,7 @@ def add_type_dispatch(model_cls: Type[M]) -> Type[M]:
|
|
125
138
|
model_cls, "__dispatch_key__"
|
126
139
|
) or "__dispatch_key__" in getattr(model_cls, "__annotations__", {})
|
127
140
|
|
128
|
-
defines_type_field = "type" in model_cls.
|
141
|
+
defines_type_field = "type" in model_cls.model_fields
|
129
142
|
|
130
143
|
if not defines_dispatch_key and not defines_type_field:
|
131
144
|
raise ValueError(
|
@@ -133,18 +146,8 @@ def add_type_dispatch(model_cls: Type[M]) -> Type[M]:
|
|
133
146
|
"or a type field. One of these is required for dispatch."
|
134
147
|
)
|
135
148
|
|
136
|
-
elif defines_dispatch_key and not defines_type_field:
|
137
|
-
# Add a type field to store the value of the dispatch key
|
138
|
-
model_cls.__fields__["type"] = pydantic_v1.fields.ModelField(
|
139
|
-
name="type",
|
140
|
-
type_=str,
|
141
|
-
required=True,
|
142
|
-
class_validators=None,
|
143
|
-
model_config=model_cls.__config__,
|
144
|
-
)
|
145
|
-
|
146
149
|
elif not defines_dispatch_key and defines_type_field:
|
147
|
-
field_type_annotation = model_cls.
|
150
|
+
field_type_annotation = model_cls.model_fields["type"].annotation
|
148
151
|
if field_type_annotation != str:
|
149
152
|
raise TypeError(
|
150
153
|
f"Model class {model_cls.__name__!r} defines a 'type' field with "
|
@@ -154,7 +157,7 @@ def add_type_dispatch(model_cls: Type[M]) -> Type[M]:
|
|
154
157
|
# Set the dispatch key to retrieve the value from the type field
|
155
158
|
@classmethod
|
156
159
|
def dispatch_key_from_type_field(cls):
|
157
|
-
return cls.
|
160
|
+
return cls.model_fields["type"].default
|
158
161
|
|
159
162
|
model_cls.__dispatch_key__ = dispatch_key_from_type_field
|
160
163
|
|
@@ -176,12 +179,12 @@ def add_type_dispatch(model_cls: Type[M]) -> Type[M]:
|
|
176
179
|
data.setdefault("type", type_string)
|
177
180
|
cls_init(__pydantic_self__, **data)
|
178
181
|
|
179
|
-
def __new__(cls: Type[
|
182
|
+
def __new__(cls: Type[M], **kwargs: Any) -> M:
|
180
183
|
if "type" in kwargs:
|
181
184
|
try:
|
182
185
|
subcls = lookup_type(cls, dispatch_key=kwargs["type"])
|
183
186
|
except KeyError as exc:
|
184
|
-
raise
|
187
|
+
raise ValidationError(errors=[exc], model=cls)
|
185
188
|
return cls_new(subcls)
|
186
189
|
else:
|
187
190
|
return cls_new(cls)
|
@@ -207,7 +210,7 @@ class PartialModel(Generic[M]):
|
|
207
210
|
a field already has a value.
|
208
211
|
|
209
212
|
Example:
|
210
|
-
>>> class MyModel(
|
213
|
+
>>> class MyModel(BaseModel):
|
211
214
|
>>> x: int
|
212
215
|
>>> y: str
|
213
216
|
>>> z: float
|
@@ -237,7 +240,7 @@ class PartialModel(Generic[M]):
|
|
237
240
|
raise ValueError(f"Field {name!r} has already been set.")
|
238
241
|
|
239
242
|
def raise_if_not_in_model(self, name):
|
240
|
-
if name not in self.model_cls.
|
243
|
+
if name not in self.model_cls.model_fields:
|
241
244
|
raise ValueError(f"Field {name!r} is not present in the model.")
|
242
245
|
|
243
246
|
def __setattr__(self, __name: str, __value: Any) -> None:
|
@@ -257,8 +260,22 @@ class PartialModel(Generic[M]):
|
|
257
260
|
|
258
261
|
class JsonPatch(JsonPatchBase):
|
259
262
|
@classmethod
|
260
|
-
def
|
261
|
-
|
263
|
+
def __get_pydantic_core_schema__(
|
264
|
+
cls, source_type: Any, handler: GetJsonSchemaHandler
|
265
|
+
) -> core_schema.CoreSchema:
|
266
|
+
return core_schema.typed_dict_schema(
|
267
|
+
{"patch": core_schema.typed_dict_field(core_schema.dict_schema())}
|
268
|
+
)
|
269
|
+
|
270
|
+
@classmethod
|
271
|
+
def __get_pydantic_json_schema__(
|
272
|
+
cls, core_schema: core_schema.CoreSchema, handler: GetJsonSchemaHandler
|
273
|
+
) -> JsonSchemaValue:
|
274
|
+
json_schema = handler(core_schema)
|
275
|
+
json_schema = handler.resolve_ref_schema(json_schema)
|
276
|
+
json_schema.pop("required", None)
|
277
|
+
json_schema.pop("properties", None)
|
278
|
+
json_schema.update(
|
262
279
|
{
|
263
280
|
"type": "array",
|
264
281
|
"format": "rfc6902",
|
@@ -268,6 +285,7 @@ class JsonPatch(JsonPatchBase):
|
|
268
285
|
},
|
269
286
|
}
|
270
287
|
)
|
288
|
+
return json_schema
|
271
289
|
|
272
290
|
|
273
291
|
def custom_pydantic_encoder(
|
@@ -282,7 +300,79 @@ def custom_pydantic_encoder(
|
|
282
300
|
|
283
301
|
return encoder(obj)
|
284
302
|
else: # We have exited the for loop without finding a suitable encoder
|
285
|
-
if isinstance(obj,
|
286
|
-
return model_dump(
|
303
|
+
if isinstance(obj, BaseModel):
|
304
|
+
return obj.model_dump(mode="json")
|
287
305
|
else:
|
288
306
|
return to_jsonable_python(obj)
|
307
|
+
|
308
|
+
|
309
|
+
def parse_obj_as(
|
310
|
+
type_: type[T],
|
311
|
+
data: Any,
|
312
|
+
mode: Literal["python", "json", "strings"] = "python",
|
313
|
+
) -> T:
|
314
|
+
"""Parse a given data structure as a Pydantic model via `TypeAdapter`.
|
315
|
+
|
316
|
+
Read more about `TypeAdapter` [here](https://docs.pydantic.dev/latest/concepts/type_adapter/).
|
317
|
+
|
318
|
+
Args:
|
319
|
+
type_: The type to parse the data as.
|
320
|
+
data: The data to be parsed.
|
321
|
+
mode: The mode to use for parsing, either `python`, `json`, or `strings`.
|
322
|
+
Defaults to `python`, where `data` should be a Python object (e.g. `dict`).
|
323
|
+
|
324
|
+
Returns:
|
325
|
+
The parsed `data` as the given `type_`.
|
326
|
+
|
327
|
+
|
328
|
+
Example:
|
329
|
+
Basic Usage of `parse_as`
|
330
|
+
```python
|
331
|
+
from prefect.utilities.pydantic import parse_as
|
332
|
+
from pydantic import BaseModel
|
333
|
+
|
334
|
+
class ExampleModel(BaseModel):
|
335
|
+
name: str
|
336
|
+
|
337
|
+
# parsing python objects
|
338
|
+
parsed = parse_as(ExampleModel, {"name": "Marvin"})
|
339
|
+
assert isinstance(parsed, ExampleModel)
|
340
|
+
assert parsed.name == "Marvin"
|
341
|
+
|
342
|
+
# parsing json strings
|
343
|
+
parsed = parse_as(
|
344
|
+
list[ExampleModel],
|
345
|
+
'[{"name": "Marvin"}, {"name": "Arthur"}]',
|
346
|
+
mode="json"
|
347
|
+
)
|
348
|
+
assert all(isinstance(item, ExampleModel) for item in parsed)
|
349
|
+
assert parsed[0].name == "Marvin"
|
350
|
+
assert parsed[1].name == "Arthur"
|
351
|
+
|
352
|
+
# parsing raw strings
|
353
|
+
parsed = parse_as(int, '123', mode="strings")
|
354
|
+
assert isinstance(parsed, int)
|
355
|
+
assert parsed == 123
|
356
|
+
```
|
357
|
+
|
358
|
+
"""
|
359
|
+
adapter = TypeAdapter(type_)
|
360
|
+
|
361
|
+
if get_origin(type_) is list and isinstance(data, dict):
|
362
|
+
data = next(iter(data.values()))
|
363
|
+
|
364
|
+
parser: Callable[[Any], T] = getattr(adapter, f"validate_{mode}")
|
365
|
+
|
366
|
+
return parser(data)
|
367
|
+
|
368
|
+
|
369
|
+
def handle_secret_render(value: object, context: dict[str, Any]) -> object:
|
370
|
+
if hasattr(value, "get_secret_value"):
|
371
|
+
return (
|
372
|
+
cast(Secret[object], value).get_secret_value()
|
373
|
+
if context.get("include_secrets", False)
|
374
|
+
else "**********"
|
375
|
+
)
|
376
|
+
elif isinstance(value, BaseModel):
|
377
|
+
return value.model_dump(context=context)
|
378
|
+
return value
|
@@ -11,10 +11,14 @@ from prefect.server.utilities.user_templates import (
|
|
11
11
|
render_user_template_sync,
|
12
12
|
validate_user_template,
|
13
13
|
)
|
14
|
+
from prefect.types import StrictVariableValue
|
14
15
|
|
15
16
|
|
16
17
|
class HydrationContext(BaseModel):
|
17
|
-
workspace_variables: Dict[
|
18
|
+
workspace_variables: Dict[
|
19
|
+
str,
|
20
|
+
StrictVariableValue,
|
21
|
+
] = Field(default_factory=dict)
|
18
22
|
render_workspace_variables: bool = Field(default=False)
|
19
23
|
raise_on_error: bool = Field(default=False)
|
20
24
|
render_jinja: bool = Field(default=False)
|
prefect/utilities/templating.py
CHANGED
@@ -1,7 +1,17 @@
|
|
1
1
|
import enum
|
2
2
|
import os
|
3
3
|
import re
|
4
|
-
from typing import
|
4
|
+
from typing import (
|
5
|
+
TYPE_CHECKING,
|
6
|
+
Any,
|
7
|
+
Dict,
|
8
|
+
NamedTuple,
|
9
|
+
Optional,
|
10
|
+
Set,
|
11
|
+
Type,
|
12
|
+
TypeVar,
|
13
|
+
Union,
|
14
|
+
)
|
5
15
|
|
6
16
|
from prefect.client.utilities import inject_client
|
7
17
|
from prefect.utilities.annotations import NotSet
|
@@ -301,7 +311,7 @@ async def resolve_block_document_references(
|
|
301
311
|
|
302
312
|
|
303
313
|
@inject_client
|
304
|
-
async def resolve_variables(template: T, client: "PrefectClient" = None):
|
314
|
+
async def resolve_variables(template: T, client: Optional["PrefectClient"] = None):
|
305
315
|
"""
|
306
316
|
Resolve variables in a template by replacing each variable placeholder with the
|
307
317
|
value of the variable.
|
prefect/variables.py
CHANGED
@@ -1,9 +1,11 @@
|
|
1
|
-
from typing import List, Optional
|
1
|
+
from typing import List, Optional, Union
|
2
2
|
|
3
|
-
from prefect._internal.compatibility.deprecated import deprecated_callable
|
4
3
|
from prefect.client.schemas.actions import VariableCreate as VariableRequest
|
5
4
|
from prefect.client.schemas.actions import VariableUpdate as VariableUpdateRequest
|
5
|
+
from prefect.client.schemas.objects import Variable as VariableResponse
|
6
6
|
from prefect.client.utilities import get_or_create_client
|
7
|
+
from prefect.exceptions import ObjectNotFound
|
8
|
+
from prefect.types import StrictVariableValue
|
7
9
|
from prefect.utilities.asyncutils import sync_compatible
|
8
10
|
|
9
11
|
|
@@ -23,92 +25,107 @@ class Variable(VariableRequest):
|
|
23
25
|
async def set(
|
24
26
|
cls,
|
25
27
|
name: str,
|
26
|
-
value:
|
28
|
+
value: StrictVariableValue,
|
27
29
|
tags: Optional[List[str]] = None,
|
28
30
|
overwrite: bool = False,
|
29
|
-
)
|
31
|
+
):
|
30
32
|
"""
|
31
33
|
Sets a new variable. If one exists with the same name, user must pass `overwrite=True`
|
32
|
-
```
|
33
|
-
from prefect.variables import Variable
|
34
34
|
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
35
|
+
Returns `True` if the variable was created or updated
|
36
|
+
|
37
|
+
Args:
|
38
|
+
- name: The name of the variable to set.
|
39
|
+
- value: The value of the variable to set.
|
40
|
+
- tags: An optional list of strings to associate with the variable.
|
41
|
+
- overwrite: Whether to overwrite the variable if it already exists.
|
42
|
+
|
43
|
+
Example:
|
44
|
+
Set a new variable and overwrite it if it already exists.
|
45
|
+
```
|
41
46
|
from prefect.variables import Variable
|
42
47
|
|
43
48
|
@flow
|
44
|
-
|
45
|
-
|
46
|
-
|
49
|
+
def my_flow():
|
50
|
+
Variable.set(name="my_var",value="test_value", tags=["hi", "there"], overwrite=True)
|
51
|
+
```
|
47
52
|
"""
|
48
53
|
client, _ = get_or_create_client()
|
49
54
|
variable = await client.read_variable_by_name(name)
|
50
|
-
var_dict = {"name": name, "value": value}
|
51
|
-
var_dict["tags"] = tags or []
|
55
|
+
var_dict = {"name": name, "value": value, "tags": tags or []}
|
52
56
|
if variable:
|
53
57
|
if not overwrite:
|
54
58
|
raise ValueError(
|
55
|
-
"You are attempting to
|
59
|
+
"You are attempting to set a variable with a name that is already in use. "
|
60
|
+
"If you would like to overwrite it, pass `overwrite=True`."
|
56
61
|
)
|
57
|
-
|
58
|
-
await client.update_variable(variable=var)
|
59
|
-
variable = await client.read_variable_by_name(name)
|
62
|
+
await client.update_variable(variable=VariableUpdateRequest(**var_dict))
|
60
63
|
else:
|
61
|
-
|
62
|
-
variable = await client.create_variable(variable=var)
|
63
|
-
|
64
|
-
return variable if variable else None
|
64
|
+
await client.create_variable(variable=VariableRequest(**var_dict))
|
65
65
|
|
66
66
|
@classmethod
|
67
67
|
@sync_compatible
|
68
|
-
async def get(
|
68
|
+
async def get(
|
69
|
+
cls,
|
70
|
+
name: str,
|
71
|
+
default: StrictVariableValue = None,
|
72
|
+
as_object: bool = False,
|
73
|
+
) -> Union[StrictVariableValue, VariableResponse]:
|
69
74
|
"""
|
70
|
-
Get a variable by name.
|
71
|
-
|
75
|
+
Get a variable's value by name.
|
76
|
+
|
77
|
+
If the variable does not exist, return the default value.
|
78
|
+
|
79
|
+
If `as_object=True`, return the full variable object. `default` is ignored in this case.
|
80
|
+
|
81
|
+
Args:
|
82
|
+
- name: The name of the variable to get.
|
83
|
+
- default: The default value to return if the variable does not exist.
|
84
|
+
- as_object: Whether to return the full variable object.
|
85
|
+
|
86
|
+
Example:
|
87
|
+
Get a variable's value by name.
|
88
|
+
```python
|
89
|
+
from prefect import flow
|
72
90
|
from prefect.variables import Variable
|
73
91
|
|
74
92
|
@flow
|
75
93
|
def my_flow():
|
76
94
|
var = Variable.get("my_var")
|
77
|
-
|
78
|
-
or
|
79
|
-
```
|
80
|
-
from prefect.variables import Variable
|
81
|
-
|
82
|
-
@flow
|
83
|
-
async def my_flow():
|
84
|
-
var = await Variable.get("my_var")
|
85
|
-
```
|
95
|
+
```
|
86
96
|
"""
|
87
97
|
client, _ = get_or_create_client()
|
88
98
|
variable = await client.read_variable_by_name(name)
|
89
|
-
|
99
|
+
if as_object:
|
100
|
+
return variable
|
90
101
|
|
102
|
+
return variable.value if variable else default
|
91
103
|
|
92
|
-
@
|
93
|
-
@sync_compatible
|
94
|
-
async def
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
104
|
+
@classmethod
|
105
|
+
@sync_compatible
|
106
|
+
async def unset(cls, name: str) -> bool:
|
107
|
+
"""
|
108
|
+
Unset a variable by name.
|
109
|
+
|
110
|
+
Args:
|
111
|
+
- name: The name of the variable to unset.
|
112
|
+
|
113
|
+
Returns `True` if the variable was deleted, `False` if the variable did not exist.
|
114
|
+
|
115
|
+
Example:
|
116
|
+
Unset a variable by name.
|
117
|
+
```python
|
118
|
+
from prefect import flow
|
119
|
+
from prefect.variables import Variable
|
120
|
+
|
121
|
+
@flow
|
122
|
+
def my_flow():
|
123
|
+
Variable.unset("my_var")
|
124
|
+
```
|
125
|
+
"""
|
126
|
+
client, _ = get_or_create_client()
|
127
|
+
try:
|
128
|
+
await client.delete_variable_by_name(name=name)
|
129
|
+
return True
|
130
|
+
except ObjectNotFound:
|
131
|
+
return False
|
prefect/workers/__init__.py
CHANGED
prefect/workers/base.py
CHANGED
@@ -7,14 +7,7 @@ from uuid import uuid4
|
|
7
7
|
import anyio
|
8
8
|
import anyio.abc
|
9
9
|
import pendulum
|
10
|
-
|
11
|
-
from prefect._internal.pydantic import HAS_PYDANTIC_V2
|
12
|
-
from prefect._internal.schemas.validators import return_v_or_none
|
13
|
-
|
14
|
-
if HAS_PYDANTIC_V2:
|
15
|
-
from pydantic.v1 import BaseModel, Field, PrivateAttr, validator
|
16
|
-
else:
|
17
|
-
from pydantic import BaseModel, Field, PrivateAttr, validator
|
10
|
+
from pydantic import BaseModel, Field, PrivateAttr, field_validator
|
18
11
|
|
19
12
|
import prefect
|
20
13
|
from prefect._internal.compatibility.experimental import (
|
@@ -22,6 +15,7 @@ from prefect._internal.compatibility.experimental import (
|
|
22
15
|
ExperimentalFeature,
|
23
16
|
experiment_enabled,
|
24
17
|
)
|
18
|
+
from prefect._internal.schemas.validators import return_v_or_none
|
25
19
|
from prefect.client.orchestration import PrefectClient, get_client
|
26
20
|
from prefect.client.schemas.actions import WorkPoolCreate, WorkPoolUpdate
|
27
21
|
from prefect.client.schemas.filters import (
|
@@ -37,7 +31,6 @@ from prefect.client.schemas.filters import (
|
|
37
31
|
)
|
38
32
|
from prefect.client.schemas.objects import StateType, WorkPool
|
39
33
|
from prefect.client.utilities import inject_client
|
40
|
-
from prefect.engine import propose_state
|
41
34
|
from prefect.events import Event, RelatedResource, emit_event
|
42
35
|
from prefect.events.related import object_as_related_resource, tags_as_related_resources
|
43
36
|
from prefect.exceptions import (
|
@@ -57,6 +50,7 @@ from prefect.settings import (
|
|
57
50
|
)
|
58
51
|
from prefect.states import Crashed, Pending, exception_to_failed_state
|
59
52
|
from prefect.utilities.dispatch import get_registry_for_type, register_base_type
|
53
|
+
from prefect.utilities.engine import propose_state
|
60
54
|
from prefect.utilities.slugify import slugify
|
61
55
|
from prefect.utilities.templating import (
|
62
56
|
apply_values,
|
@@ -107,7 +101,8 @@ class BaseJobConfiguration(BaseModel):
|
|
107
101
|
def is_using_a_runner(self):
|
108
102
|
return self.command is not None and "prefect flow-run execute" in self.command
|
109
103
|
|
110
|
-
@
|
104
|
+
@field_validator("command")
|
105
|
+
@classmethod
|
111
106
|
def _coerce_command(cls, v):
|
112
107
|
return return_v_or_none(v)
|
113
108
|
|
@@ -124,7 +119,10 @@ class BaseJobConfiguration(BaseModel):
|
|
124
119
|
@classmethod
|
125
120
|
@inject_client
|
126
121
|
async def from_template_and_values(
|
127
|
-
cls,
|
122
|
+
cls,
|
123
|
+
base_job_template: dict,
|
124
|
+
values: dict,
|
125
|
+
client: Optional["PrefectClient"] = None,
|
128
126
|
):
|
129
127
|
"""Creates a valid worker configuration object from the provided base
|
130
128
|
configuration and overrides.
|
@@ -161,7 +159,7 @@ class BaseJobConfiguration(BaseModel):
|
|
161
159
|
}
|
162
160
|
"""
|
163
161
|
configuration = {}
|
164
|
-
properties = cls.
|
162
|
+
properties = cls.model_json_schema()["properties"]
|
165
163
|
for k, v in properties.items():
|
166
164
|
if v.get("template"):
|
167
165
|
template = v["template"]
|
@@ -420,7 +418,7 @@ class BaseWorker(abc.ABC):
|
|
420
418
|
@classmethod
|
421
419
|
def get_default_base_job_template(cls) -> Dict:
|
422
420
|
if cls.job_configuration_variables is None:
|
423
|
-
schema = cls.job_configuration.
|
421
|
+
schema = cls.job_configuration.model_json_schema()
|
424
422
|
# remove "template" key from all dicts in schema['properties'] because it is not a
|
425
423
|
# relevant field
|
426
424
|
for key, value in schema["properties"].items():
|
@@ -428,7 +426,7 @@ class BaseWorker(abc.ABC):
|
|
428
426
|
schema["properties"][key].pop("template", None)
|
429
427
|
variables_schema = schema
|
430
428
|
else:
|
431
|
-
variables_schema = cls.job_configuration_variables.
|
429
|
+
variables_schema = cls.job_configuration_variables.model_json_schema()
|
432
430
|
variables_schema.pop("title", None)
|
433
431
|
return {
|
434
432
|
"job_configuration": cls.job_configuration.json_template(),
|
@@ -963,7 +961,7 @@ class BaseWorker(abc.ABC):
|
|
963
961
|
return {
|
964
962
|
"name": self.name,
|
965
963
|
"work_pool": (
|
966
|
-
self._work_pool.
|
964
|
+
self._work_pool.model_dump(mode="json")
|
967
965
|
if self._work_pool is not None
|
968
966
|
else None
|
969
967
|
),
|
@@ -1068,7 +1066,7 @@ class BaseWorker(abc.ABC):
|
|
1068
1066
|
state_updates = state_updates or {}
|
1069
1067
|
state_updates.setdefault("name", "Cancelled")
|
1070
1068
|
state_updates.setdefault("type", StateType.CANCELLED)
|
1071
|
-
state = flow_run.state.
|
1069
|
+
state = flow_run.state.model_copy(update=state_updates)
|
1072
1070
|
|
1073
1071
|
await self._client.set_flow_run_state(flow_run.id, state, force=True)
|
1074
1072
|
|
@@ -1155,7 +1153,7 @@ class BaseWorker(abc.ABC):
|
|
1155
1153
|
if include_self:
|
1156
1154
|
worker_resource = self._event_resource()
|
1157
1155
|
worker_resource["prefect.resource.role"] = "worker"
|
1158
|
-
related.append(RelatedResource.
|
1156
|
+
related.append(RelatedResource.model_validate(worker_resource))
|
1159
1157
|
|
1160
1158
|
return related
|
1161
1159
|
|
prefect/workers/process.py
CHANGED
@@ -26,13 +26,7 @@ from typing import TYPE_CHECKING, Dict, Optional, Tuple
|
|
26
26
|
|
27
27
|
import anyio
|
28
28
|
import anyio.abc
|
29
|
-
|
30
|
-
from prefect._internal.pydantic import HAS_PYDANTIC_V2
|
31
|
-
|
32
|
-
if HAS_PYDANTIC_V2:
|
33
|
-
from pydantic.v1 import Field, validator
|
34
|
-
else:
|
35
|
-
from pydantic import Field, validator
|
29
|
+
from pydantic import Field, field_validator
|
36
30
|
|
37
31
|
from prefect._internal.schemas.validators import validate_command
|
38
32
|
from prefect.client.schemas import FlowRun
|
@@ -68,7 +62,8 @@ class ProcessJobConfiguration(BaseJobConfiguration):
|
|
68
62
|
stream_output: bool = Field(default=True)
|
69
63
|
working_dir: Optional[Path] = Field(default=None)
|
70
64
|
|
71
|
-
@
|
65
|
+
@field_validator("working_dir")
|
66
|
+
@classmethod
|
72
67
|
def validate_command(cls, v):
|
73
68
|
return validate_command(v)
|
74
69
|
|
prefect/workers/server.py
CHANGED
@@ -1,8 +1,8 @@
|
|
1
1
|
from typing import Union
|
2
2
|
|
3
3
|
import uvicorn
|
4
|
-
from
|
5
|
-
from
|
4
|
+
from fastapi import APIRouter, FastAPI, status
|
5
|
+
from fastapi.responses import JSONResponse
|
6
6
|
|
7
7
|
from prefect.settings import (
|
8
8
|
PREFECT_WORKER_WEBSERVER_HOST,
|