prefect-client 2.16.5__py3-none-any.whl → 2.16.7__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/_internal/pydantic/__init__.py +21 -1
- prefect/_internal/pydantic/_base_model.py +16 -0
- prefect/_internal/pydantic/_compat.py +352 -68
- prefect/_internal/pydantic/_flags.py +15 -0
- prefect/_internal/pydantic/v1_schema.py +48 -0
- prefect/_internal/pydantic/v2_schema.py +6 -2
- prefect/_internal/schemas/validators.py +582 -9
- prefect/artifacts.py +179 -70
- prefect/client/cloud.py +4 -1
- prefect/client/orchestration.py +1 -1
- prefect/client/schemas/actions.py +2 -2
- prefect/client/schemas/objects.py +13 -24
- prefect/client/schemas/schedules.py +18 -80
- prefect/deployments/deployments.py +22 -86
- prefect/deployments/runner.py +8 -11
- prefect/events/__init__.py +40 -1
- prefect/events/clients.py +17 -20
- prefect/events/filters.py +5 -6
- prefect/events/related.py +1 -1
- prefect/events/schemas/__init__.py +5 -0
- prefect/events/schemas/automations.py +303 -0
- prefect/events/{schemas.py → schemas/deployment_triggers.py} +146 -270
- prefect/events/schemas/events.py +285 -0
- prefect/events/schemas/labelling.py +106 -0
- prefect/events/utilities.py +2 -2
- prefect/events/worker.py +1 -1
- prefect/filesystems.py +8 -37
- prefect/flows.py +4 -4
- prefect/infrastructure/kubernetes.py +12 -56
- prefect/infrastructure/provisioners/__init__.py +1 -0
- prefect/pydantic/__init__.py +4 -0
- prefect/pydantic/main.py +15 -0
- prefect/runner/runner.py +2 -2
- prefect/runner/server.py +1 -1
- prefect/serializers.py +13 -61
- prefect/settings.py +35 -13
- prefect/task_server.py +21 -7
- prefect/utilities/asyncutils.py +1 -1
- prefect/utilities/callables.py +2 -2
- prefect/utilities/context.py +33 -1
- prefect/utilities/schema_tools/hydration.py +14 -6
- prefect/workers/base.py +1 -2
- prefect/workers/block.py +3 -7
- {prefect_client-2.16.5.dist-info → prefect_client-2.16.7.dist-info}/METADATA +2 -2
- {prefect_client-2.16.5.dist-info → prefect_client-2.16.7.dist-info}/RECORD +48 -40
- prefect/utilities/validation.py +0 -63
- {prefect_client-2.16.5.dist-info → prefect_client-2.16.7.dist-info}/LICENSE +0 -0
- {prefect_client-2.16.5.dist-info → prefect_client-2.16.7.dist-info}/WHEEL +0 -0
- {prefect_client-2.16.5.dist-info → prefect_client-2.16.7.dist-info}/top_level.txt +0 -0
@@ -10,4 +10,24 @@ from pydantic.version import VERSION as PYDANTIC_VERSION
|
|
10
10
|
|
11
11
|
HAS_PYDANTIC_V2 = PYDANTIC_VERSION.startswith("2.")
|
12
12
|
|
13
|
-
from ._compat import
|
13
|
+
from ._compat import (
|
14
|
+
model_dump,
|
15
|
+
model_json_schema,
|
16
|
+
model_validate,
|
17
|
+
IncEx,
|
18
|
+
model_dump_json,
|
19
|
+
model_copy,
|
20
|
+
model_validate_json,
|
21
|
+
validate_python,
|
22
|
+
)
|
23
|
+
|
24
|
+
__all__ = [
|
25
|
+
"model_dump",
|
26
|
+
"model_json_schema",
|
27
|
+
"model_validate",
|
28
|
+
"IncEx",
|
29
|
+
"model_dump_json",
|
30
|
+
"model_copy",
|
31
|
+
"model_validate_json",
|
32
|
+
"validate_python",
|
33
|
+
]
|
@@ -0,0 +1,16 @@
|
|
1
|
+
import typing
|
2
|
+
|
3
|
+
from prefect._internal.pydantic._flags import (
|
4
|
+
HAS_PYDANTIC_V2,
|
5
|
+
USE_PYDANTIC_V2,
|
6
|
+
)
|
7
|
+
|
8
|
+
if typing.TYPE_CHECKING:
|
9
|
+
from pydantic import BaseModel
|
10
|
+
|
11
|
+
if HAS_PYDANTIC_V2 and not USE_PYDANTIC_V2:
|
12
|
+
from pydantic.v1 import BaseModel
|
13
|
+
else:
|
14
|
+
from pydantic import BaseModel
|
15
|
+
|
16
|
+
__all__ = ["BaseModel"]
|
@@ -1,86 +1,145 @@
|
|
1
|
-
from typing import Any, Dict, Literal, Optional, Set, Type, Union
|
1
|
+
from typing import Any, Dict, Generic, Literal, Optional, Set, Type, TypeVar, Union
|
2
2
|
|
3
|
-
import
|
4
|
-
from pydantic import BaseModel
|
3
|
+
from typing_extensions import Self, TypeAlias
|
5
4
|
|
6
|
-
from prefect._internal.pydantic import
|
5
|
+
from prefect._internal.pydantic._flags import (
|
6
|
+
HAS_PYDANTIC_V2,
|
7
|
+
USE_PYDANTIC_V2,
|
8
|
+
)
|
7
9
|
from prefect.logging.loggers import get_logger
|
8
|
-
from prefect.settings import PREFECT_EXPERIMENTAL_ENABLE_PYDANTIC_V2_INTERNALS
|
9
10
|
|
10
|
-
|
11
|
-
"Union[Set[int], Set[str], Dict[int, Any], Dict[str, Any], None]"
|
12
|
-
)
|
11
|
+
from ._base_model import BaseModel as PydanticBaseModel
|
13
12
|
|
13
|
+
IncEx: TypeAlias = "Union[Set[int], Set[str], Dict[int, Any], Dict[str, Any], None]"
|
14
14
|
logger = get_logger("prefect._internal.pydantic")
|
15
15
|
|
16
|
+
T = TypeVar("T")
|
17
|
+
B = TypeVar("B", bound=PydanticBaseModel)
|
18
|
+
|
16
19
|
if HAS_PYDANTIC_V2:
|
17
|
-
from pydantic
|
20
|
+
from pydantic import (
|
21
|
+
TypeAdapter as BaseTypeAdapter,
|
22
|
+
)
|
23
|
+
from pydantic import (
|
24
|
+
parse_obj_as, # type: ignore
|
25
|
+
)
|
26
|
+
from pydantic.json_schema import GenerateJsonSchema # type: ignore
|
27
|
+
else:
|
28
|
+
from pydantic import parse_obj_as # type: ignore
|
18
29
|
|
30
|
+
if HAS_PYDANTIC_V2 and USE_PYDANTIC_V2:
|
31
|
+
TypeAdapter = BaseTypeAdapter # type: ignore
|
19
32
|
|
20
|
-
|
21
|
-
model_instance: Optional[BaseModel] = None, fn_name: Optional[str] = None
|
22
|
-
) -> bool:
|
23
|
-
"""
|
24
|
-
Determines if the current environment is compatible with Pydantic V2 features,
|
25
|
-
based on the presence of Pydantic V2 and a global setting that enables V2 functionalities.
|
26
|
-
|
27
|
-
This function primarily serves to facilitate conditional logic in code that needs to
|
28
|
-
operate differently depending on the availability of Pydantic V2 features. It checks
|
29
|
-
two conditions: whether Pydantic V2 is installed, and whether the use of V2 features
|
30
|
-
is explicitly enabled through a global setting (`PREFECT_EXPERIMENTAL_ENABLE_PYDANTIC_V2_INTERNALS`).
|
31
|
-
|
32
|
-
Parameters:
|
33
|
-
-----------
|
34
|
-
model_instance : Optional[BaseModel], optional
|
35
|
-
An instance of a Pydantic model. This parameter is used to perform a type check
|
36
|
-
to ensure the passed object is a Pydantic model instance. If not provided or if
|
37
|
-
the object is not a Pydantic model, a TypeError is raised. Defaults to None.
|
38
|
-
|
39
|
-
fn_name : Optional[str], optional
|
40
|
-
The name of the function or feature for which V2 compatibility is being checked.
|
41
|
-
This is used for logging purposes to provide more context in debug messages.
|
42
|
-
Defaults to None.
|
33
|
+
else:
|
43
34
|
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
True if the current environment supports Pydantic V2 features and if the global
|
48
|
-
setting for enabling V2 features is set to True. False otherwise.
|
35
|
+
class TypeAdapter(Generic[T]):
|
36
|
+
def __init__(self, type_: Union[T, Type[T]]) -> None:
|
37
|
+
self.type_ = type_
|
49
38
|
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
39
|
+
def validate_python(
|
40
|
+
self,
|
41
|
+
__object: Any,
|
42
|
+
/,
|
43
|
+
*,
|
44
|
+
strict: Optional[bool] = None,
|
45
|
+
from_attributes: Optional[bool] = None,
|
46
|
+
context: Optional[Dict[str, Any]] = None,
|
47
|
+
) -> Any:
|
48
|
+
return parse_obj_as(self.type_, __object) # type: ignore
|
49
|
+
|
50
|
+
|
51
|
+
# BaseModel methods and definitions
|
52
|
+
|
53
|
+
|
54
|
+
def model_copy(
|
55
|
+
model_instance: PydanticBaseModel,
|
56
|
+
*,
|
57
|
+
update: Optional[Dict[str, Any]] = None,
|
58
|
+
deep: bool = False,
|
59
|
+
) -> PydanticBaseModel:
|
60
|
+
"""Usage docs: https://docs.pydantic.dev/2.7/concepts/serialization/#model_copy
|
61
|
+
|
62
|
+
Returns a copy of the model.
|
63
|
+
|
64
|
+
Args:
|
65
|
+
update: Values to change/add in the new model. Note: the data is not validated
|
66
|
+
before creating the new model. You should trust this data.
|
67
|
+
deep: Set to `True` to make a deep copy of the model.
|
68
|
+
|
69
|
+
Returns:
|
70
|
+
New model instance.
|
54
71
|
"""
|
55
|
-
if model_instance and not
|
56
|
-
|
57
|
-
|
58
|
-
)
|
72
|
+
if not hasattr(model_instance, "copy") and not hasattr(
|
73
|
+
model_instance, "model_copy"
|
74
|
+
):
|
75
|
+
raise TypeError("Expected a Pydantic model instance")
|
59
76
|
|
60
|
-
|
61
|
-
|
62
|
-
)
|
77
|
+
if HAS_PYDANTIC_V2 and USE_PYDANTIC_V2:
|
78
|
+
return model_instance.model_copy(update=update, deep=deep)
|
63
79
|
|
64
|
-
|
65
|
-
logger.debug(
|
66
|
-
f"Using Pydantic v2 compatibility layer for `{fn_name}`. This will be removed in a future release."
|
67
|
-
)
|
80
|
+
return model_instance.copy(update=update, deep=deep) # type: ignore
|
68
81
|
|
69
|
-
return True
|
70
82
|
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
83
|
+
def model_dump_json(
|
84
|
+
model_instance: PydanticBaseModel,
|
85
|
+
*,
|
86
|
+
indent: Optional[int] = None,
|
87
|
+
include: IncEx = None,
|
88
|
+
exclude: IncEx = None,
|
89
|
+
by_alias: bool = False,
|
90
|
+
exclude_unset: bool = False,
|
91
|
+
exclude_defaults: bool = False,
|
92
|
+
exclude_none: bool = False,
|
93
|
+
round_trip: bool = False,
|
94
|
+
warnings: bool = True,
|
95
|
+
) -> str:
|
96
|
+
"""
|
97
|
+
Generate a JSON representation of the model, optionally specifying which fields to include or exclude.
|
75
98
|
|
76
|
-
|
77
|
-
|
99
|
+
Args:
|
100
|
+
indent: If provided, the number of spaces to indent the JSON output.
|
101
|
+
include: A list of fields to include in the output.
|
102
|
+
exclude: A list of fields to exclude from the output.
|
103
|
+
by_alias: Whether to use the field's alias in the dictionary key if defined.
|
104
|
+
exclude_unset: Whether to exclude fields that have not been explicitly set.
|
105
|
+
exclude_defaults: Whether to exclude fields that are set to their default value.
|
106
|
+
exclude_none: Whether to exclude fields that have a value of `None`.
|
107
|
+
round_trip: If True, dumped values should be valid as input for non-idempotent types such as Json[T].
|
108
|
+
warnings: Whether to log warnings when invalid fields are encountered.
|
78
109
|
|
79
|
-
|
110
|
+
Returns:
|
111
|
+
A JSON representation of the model.
|
112
|
+
"""
|
113
|
+
if not hasattr(model_instance, "json") and not hasattr(
|
114
|
+
model_instance, "model_dump_json"
|
115
|
+
):
|
116
|
+
raise TypeError("Expected a Pydantic model instance")
|
117
|
+
|
118
|
+
if HAS_PYDANTIC_V2 and USE_PYDANTIC_V2:
|
119
|
+
return model_instance.model_dump_json(
|
120
|
+
indent=indent,
|
121
|
+
include=include,
|
122
|
+
exclude=exclude,
|
123
|
+
by_alias=by_alias,
|
124
|
+
exclude_unset=exclude_unset,
|
125
|
+
exclude_defaults=exclude_defaults,
|
126
|
+
exclude_none=exclude_none,
|
127
|
+
round_trip=round_trip,
|
128
|
+
warnings=warnings,
|
129
|
+
)
|
130
|
+
|
131
|
+
return model_instance.json( # type: ignore
|
132
|
+
include=include,
|
133
|
+
exclude=exclude,
|
134
|
+
by_alias=by_alias,
|
135
|
+
exclude_unset=exclude_unset,
|
136
|
+
exclude_defaults=exclude_defaults,
|
137
|
+
exclude_none=exclude_none,
|
138
|
+
)
|
80
139
|
|
81
140
|
|
82
141
|
def model_dump(
|
83
|
-
model_instance:
|
142
|
+
model_instance: PydanticBaseModel,
|
84
143
|
*,
|
85
144
|
mode: Union[Literal["json", "python"], str] = "python",
|
86
145
|
include: IncEx = None,
|
@@ -111,7 +170,12 @@ def model_dump(
|
|
111
170
|
Returns:
|
112
171
|
A dictionary representation of the model.
|
113
172
|
"""
|
114
|
-
if
|
173
|
+
if not hasattr(model_instance, "dict") and not hasattr(
|
174
|
+
model_instance, "model_dump"
|
175
|
+
):
|
176
|
+
raise TypeError("Expected a Pydantic model instance")
|
177
|
+
|
178
|
+
if HAS_PYDANTIC_V2 and USE_PYDANTIC_V2:
|
115
179
|
return model_instance.model_dump(
|
116
180
|
mode=mode,
|
117
181
|
include=include,
|
@@ -124,7 +188,7 @@ def model_dump(
|
|
124
188
|
warnings=warnings,
|
125
189
|
)
|
126
190
|
|
127
|
-
return model_instance
|
191
|
+
return getattr(model_instance, "dict")(
|
128
192
|
include=include,
|
129
193
|
exclude=exclude,
|
130
194
|
by_alias=by_alias,
|
@@ -139,11 +203,11 @@ JsonSchemaMode = Literal["validation", "serialization"]
|
|
139
203
|
|
140
204
|
|
141
205
|
def model_json_schema(
|
142
|
-
model: Type[
|
206
|
+
model: Type[PydanticBaseModel],
|
143
207
|
*,
|
144
208
|
by_alias: bool = True,
|
145
209
|
ref_template: str = DEFAULT_REF_TEMPLATE,
|
146
|
-
schema_generator=None,
|
210
|
+
schema_generator: Any = None,
|
147
211
|
mode: JsonSchemaMode = "validation",
|
148
212
|
) -> Dict[str, Any]:
|
149
213
|
"""
|
@@ -165,8 +229,11 @@ def model_json_schema(
|
|
165
229
|
dict[str, Any]
|
166
230
|
The JSON schema for the given model class.
|
167
231
|
"""
|
168
|
-
if
|
169
|
-
|
232
|
+
if not hasattr(model, "schema") and not hasattr(model, "model_json_schema"):
|
233
|
+
raise TypeError("Expected a Pydantic model type")
|
234
|
+
|
235
|
+
if HAS_PYDANTIC_V2 and USE_PYDANTIC_V2:
|
236
|
+
schema_generator = GenerateJsonSchema # type: ignore
|
170
237
|
return model.model_json_schema(
|
171
238
|
by_alias=by_alias,
|
172
239
|
ref_template=ref_template,
|
@@ -174,7 +241,224 @@ def model_json_schema(
|
|
174
241
|
mode=mode,
|
175
242
|
)
|
176
243
|
|
177
|
-
return model.schema(
|
244
|
+
return model.schema( # type: ignore
|
178
245
|
by_alias=by_alias,
|
179
246
|
ref_template=ref_template,
|
180
247
|
)
|
248
|
+
|
249
|
+
|
250
|
+
def model_validate(
|
251
|
+
model: Type[B],
|
252
|
+
obj: Any,
|
253
|
+
*,
|
254
|
+
strict: Optional[bool] = False,
|
255
|
+
from_attributes: Optional[bool] = False,
|
256
|
+
context: Optional[Dict[str, Any]] = None,
|
257
|
+
) -> B:
|
258
|
+
"""Validate a pydantic model instance.
|
259
|
+
|
260
|
+
Args:
|
261
|
+
obj: The object to validate.
|
262
|
+
strict: Whether to enforce types strictly.
|
263
|
+
from_attributes: Whether to extract data from object attributes.
|
264
|
+
context: Additional context to pass to the validator.
|
265
|
+
|
266
|
+
Raises:
|
267
|
+
ValidationError: If the object could not be validated.
|
268
|
+
|
269
|
+
Returns:
|
270
|
+
The validated model instance.
|
271
|
+
"""
|
272
|
+
if not hasattr(model, "parse_obj") and not hasattr(model, "model_validate"):
|
273
|
+
raise TypeError("Expected a Pydantic model type")
|
274
|
+
|
275
|
+
if HAS_PYDANTIC_V2 and USE_PYDANTIC_V2:
|
276
|
+
return model.model_validate(
|
277
|
+
obj=obj,
|
278
|
+
strict=strict,
|
279
|
+
from_attributes=from_attributes,
|
280
|
+
context=context,
|
281
|
+
)
|
282
|
+
|
283
|
+
return getattr(model, "parse_obj")(obj)
|
284
|
+
|
285
|
+
|
286
|
+
def model_validate_json(
|
287
|
+
model: Type[B],
|
288
|
+
json_data: Union[str, bytes, bytearray],
|
289
|
+
*,
|
290
|
+
strict: Optional[bool] = False,
|
291
|
+
context: Optional[Dict[str, Any]] = None,
|
292
|
+
) -> B:
|
293
|
+
"""Validate the given JSON data against the Pydantic model.
|
294
|
+
|
295
|
+
Args:
|
296
|
+
json_data: The JSON data to validate.
|
297
|
+
strict: Whether to enforce types strictly.
|
298
|
+
context: Extra variables to pass to the validator.
|
299
|
+
|
300
|
+
Returns:
|
301
|
+
The validated Pydantic model.
|
302
|
+
|
303
|
+
Raises:
|
304
|
+
ValueError: If `json_data` is not a JSON string.
|
305
|
+
"""
|
306
|
+
if not hasattr(model, "parse_raw") and not hasattr(model, "model_validate_json"):
|
307
|
+
raise TypeError("Expected a Pydantic model type")
|
308
|
+
|
309
|
+
if HAS_PYDANTIC_V2 and USE_PYDANTIC_V2:
|
310
|
+
return model.model_validate_json(
|
311
|
+
json_data=json_data,
|
312
|
+
strict=strict,
|
313
|
+
context=context,
|
314
|
+
)
|
315
|
+
|
316
|
+
return getattr(model, "parse_raw")(json_data)
|
317
|
+
|
318
|
+
|
319
|
+
if HAS_PYDANTIC_V2 and USE_PYDANTIC_V2:
|
320
|
+
# In this case, there's no functionality to add, so we just alias the Pydantic v2 BaseModel
|
321
|
+
class BaseModel(PydanticBaseModel): # type: ignore
|
322
|
+
pass
|
323
|
+
|
324
|
+
else:
|
325
|
+
# In this case, we're working with a Pydantic v1 model, so we need to add Pydantic v2 functionality
|
326
|
+
class BaseModel(PydanticBaseModel):
|
327
|
+
def model_dump(
|
328
|
+
self: "BaseModel",
|
329
|
+
*,
|
330
|
+
mode: str = "python",
|
331
|
+
include: IncEx = None,
|
332
|
+
exclude: IncEx = None,
|
333
|
+
by_alias: bool = False,
|
334
|
+
exclude_unset: bool = False,
|
335
|
+
exclude_defaults: bool = False,
|
336
|
+
exclude_none: bool = False,
|
337
|
+
round_trip: bool = False,
|
338
|
+
warnings: bool = True,
|
339
|
+
) -> Dict[str, Any]:
|
340
|
+
return model_dump(
|
341
|
+
self,
|
342
|
+
mode=mode,
|
343
|
+
include=include,
|
344
|
+
exclude=exclude,
|
345
|
+
by_alias=by_alias,
|
346
|
+
exclude_unset=exclude_unset,
|
347
|
+
exclude_defaults=exclude_defaults,
|
348
|
+
exclude_none=exclude_none,
|
349
|
+
round_trip=round_trip,
|
350
|
+
warnings=warnings,
|
351
|
+
)
|
352
|
+
|
353
|
+
def model_dump_json(
|
354
|
+
self,
|
355
|
+
*,
|
356
|
+
indent: Optional[int] = None,
|
357
|
+
include: Optional[IncEx] = None,
|
358
|
+
exclude: Optional[IncEx] = None,
|
359
|
+
by_alias: bool = False,
|
360
|
+
exclude_unset: bool = False,
|
361
|
+
exclude_defaults: bool = False,
|
362
|
+
exclude_none: bool = False,
|
363
|
+
round_trip: bool = False,
|
364
|
+
warnings: bool = True,
|
365
|
+
) -> str:
|
366
|
+
return model_dump_json(
|
367
|
+
model_instance=self,
|
368
|
+
indent=indent,
|
369
|
+
include=include,
|
370
|
+
exclude=exclude,
|
371
|
+
by_alias=by_alias,
|
372
|
+
exclude_unset=exclude_unset,
|
373
|
+
exclude_defaults=exclude_defaults,
|
374
|
+
exclude_none=exclude_none,
|
375
|
+
round_trip=round_trip,
|
376
|
+
warnings=warnings,
|
377
|
+
)
|
378
|
+
|
379
|
+
def model_copy(
|
380
|
+
self: "Self",
|
381
|
+
*,
|
382
|
+
update: Optional[Dict[str, Any]] = None,
|
383
|
+
deep: bool = False,
|
384
|
+
) -> "Self":
|
385
|
+
return super().model_copy(update=update, deep=deep)
|
386
|
+
|
387
|
+
@classmethod
|
388
|
+
def model_json_schema(
|
389
|
+
cls,
|
390
|
+
by_alias: bool = True,
|
391
|
+
ref_template: str = DEFAULT_REF_TEMPLATE,
|
392
|
+
schema_generator: Any = None,
|
393
|
+
mode: JsonSchemaMode = "validation",
|
394
|
+
) -> Dict[str, Any]:
|
395
|
+
return model_json_schema(
|
396
|
+
cls,
|
397
|
+
by_alias=by_alias,
|
398
|
+
ref_template=ref_template,
|
399
|
+
schema_generator=schema_generator,
|
400
|
+
mode=mode,
|
401
|
+
)
|
402
|
+
|
403
|
+
@classmethod
|
404
|
+
def model_validate(
|
405
|
+
cls: Type["Self"],
|
406
|
+
obj: Any,
|
407
|
+
*,
|
408
|
+
strict: Optional[bool] = False,
|
409
|
+
from_attributes: Optional[bool] = False,
|
410
|
+
context: Optional[Dict[str, Any]] = None,
|
411
|
+
) -> "Self":
|
412
|
+
return model_validate(
|
413
|
+
cls,
|
414
|
+
obj,
|
415
|
+
strict=strict,
|
416
|
+
from_attributes=from_attributes,
|
417
|
+
context=context,
|
418
|
+
)
|
419
|
+
|
420
|
+
@classmethod
|
421
|
+
def model_validate_json(
|
422
|
+
cls: Type["Self"],
|
423
|
+
json_data: Union[str, bytes, bytearray],
|
424
|
+
*,
|
425
|
+
strict: Optional[bool] = False,
|
426
|
+
context: Optional[Dict[str, Any]] = None,
|
427
|
+
) -> "Self":
|
428
|
+
return model_validate_json(
|
429
|
+
cls,
|
430
|
+
json_data,
|
431
|
+
strict=strict,
|
432
|
+
context=context,
|
433
|
+
)
|
434
|
+
|
435
|
+
|
436
|
+
# TypeAdapter methods and definitions
|
437
|
+
|
438
|
+
|
439
|
+
def validate_python(
|
440
|
+
type_: Union[T, Type[T]],
|
441
|
+
__object: Any,
|
442
|
+
/,
|
443
|
+
*,
|
444
|
+
strict: Optional[bool] = None,
|
445
|
+
from_attributes: Optional[bool] = None,
|
446
|
+
context: Optional[Dict[str, Any]] = None,
|
447
|
+
) -> T:
|
448
|
+
"""Validate a Python object against the model.
|
449
|
+
|
450
|
+
Args:
|
451
|
+
type_: The type to validate against.
|
452
|
+
__object: The Python object to validate against the model.
|
453
|
+
strict: Whether to strictly check types.
|
454
|
+
from_attributes: Whether to extract data from object attributes.
|
455
|
+
context: Additional context to pass to the validator.
|
456
|
+
|
457
|
+
!!! note
|
458
|
+
When using `TypeAdapter` with a Pydantic `dataclass`, the use of the `from_attributes`
|
459
|
+
argument is not supported.
|
460
|
+
|
461
|
+
Returns:
|
462
|
+
The validated object.
|
463
|
+
"""
|
464
|
+
return TypeAdapter(type_).validate_python(__object)
|
@@ -0,0 +1,15 @@
|
|
1
|
+
import os
|
2
|
+
|
3
|
+
# Retrieve current version of Pydantic installed in environment
|
4
|
+
from pydantic.version import VERSION as PYDANTIC_VERSION
|
5
|
+
|
6
|
+
# Check if Pydantic version 2 is the installed version
|
7
|
+
HAS_PYDANTIC_V2 = PYDANTIC_VERSION.startswith("2.")
|
8
|
+
|
9
|
+
# Determine if Pydantic v2 internals should be used based on an environment variable.
|
10
|
+
USE_PYDANTIC_V2 = os.environ.get(
|
11
|
+
"PREFECT_EXPERIMENTAL_ENABLE_PYDANTIC_V2_INTERNALS", False
|
12
|
+
) in {"1", "true", "True"}
|
13
|
+
|
14
|
+
# Set to True if Pydantic v2 is present but not enabled, indicating deprecation warnings may occur.
|
15
|
+
EXPECT_DEPRECATION_WARNINGS = HAS_PYDANTIC_V2 and not USE_PYDANTIC_V2
|
@@ -0,0 +1,48 @@
|
|
1
|
+
import inspect
|
2
|
+
import typing
|
3
|
+
|
4
|
+
from prefect._internal.pydantic import HAS_PYDANTIC_V2
|
5
|
+
|
6
|
+
if HAS_PYDANTIC_V2:
|
7
|
+
from pydantic.v1 import BaseModel as V1BaseModel
|
8
|
+
else:
|
9
|
+
from pydantic import BaseModel as V1BaseModel
|
10
|
+
|
11
|
+
|
12
|
+
def is_v1_model(v) -> bool:
|
13
|
+
if isinstance(v, V1BaseModel):
|
14
|
+
return True
|
15
|
+
try:
|
16
|
+
if inspect.isclass(v) and issubclass(v, V1BaseModel):
|
17
|
+
return True
|
18
|
+
except TypeError:
|
19
|
+
pass
|
20
|
+
|
21
|
+
return False
|
22
|
+
|
23
|
+
|
24
|
+
def is_v1_type(v) -> bool:
|
25
|
+
if HAS_PYDANTIC_V2:
|
26
|
+
if is_v1_model(v):
|
27
|
+
return True
|
28
|
+
|
29
|
+
try:
|
30
|
+
return v.__module__.startswith("pydantic.v1.types")
|
31
|
+
except AttributeError:
|
32
|
+
return False
|
33
|
+
|
34
|
+
return True
|
35
|
+
|
36
|
+
|
37
|
+
def has_v1_type_as_param(signature: inspect.Signature) -> bool:
|
38
|
+
parameters = signature.parameters.values()
|
39
|
+
for p in parameters:
|
40
|
+
# check if this parameter is a v1 model
|
41
|
+
if is_v1_type(p.annotation):
|
42
|
+
return True
|
43
|
+
|
44
|
+
# check if this parameter is a collection of types
|
45
|
+
for v in typing.get_args(p.annotation):
|
46
|
+
if is_v1_type(v):
|
47
|
+
return True
|
48
|
+
return False
|
@@ -7,7 +7,7 @@ import typing as t
|
|
7
7
|
import pendulum
|
8
8
|
import pydantic
|
9
9
|
from pydantic import BaseModel as V2BaseModel
|
10
|
-
from pydantic import ConfigDict, create_model
|
10
|
+
from pydantic import ConfigDict, PydanticUndefinedAnnotation, create_model
|
11
11
|
from pydantic.type_adapter import TypeAdapter
|
12
12
|
|
13
13
|
from prefect._internal.pydantic.annotations.pendulum import (
|
@@ -106,7 +106,11 @@ def create_v2_schema(
|
|
106
106
|
model = create_model(
|
107
107
|
name_, __config__=model_cfg, __base__=model_base, **model_fields
|
108
108
|
)
|
109
|
-
|
109
|
+
try:
|
110
|
+
adapter = TypeAdapter(model)
|
111
|
+
except PydanticUndefinedAnnotation as exc:
|
112
|
+
# in v1 this raises a TypeError, which is handled by parameter_schema
|
113
|
+
raise TypeError(exc.message)
|
110
114
|
|
111
115
|
# root model references under #definitions
|
112
116
|
schema = adapter.json_schema(
|