Coverage for pydantic/_internal/_generate_schema.py: 95.18%
1349 statements
« prev ^ index » next coverage.py v7.8.0, created at 2025-04-17 15:12 +0000
« prev ^ index » next coverage.py v7.8.0, created at 2025-04-17 15:12 +0000
1"""Convert python types to pydantic-core schema."""
3from __future__ import annotations as _annotations 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
5import collections.abc 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
6import dataclasses 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
7import datetime 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
8import inspect 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
9import os 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
10import pathlib 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
11import re 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
12import sys 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
13import typing 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
14import warnings 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
15from collections.abc import Generator, Iterable, Iterator, Mapping 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
16from contextlib import contextmanager 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
17from copy import copy 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
18from decimal import Decimal 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
19from enum import Enum 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
20from fractions import Fraction 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
21from functools import partial 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
22from inspect import Parameter, _ParameterKind, signature 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
23from ipaddress import IPv4Address, IPv4Interface, IPv4Network, IPv6Address, IPv6Interface, IPv6Network 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
24from itertools import chain 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
25from operator import attrgetter 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
26from types import FunctionType, GenericAlias, LambdaType, MethodType 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
27from typing import ( 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
28 TYPE_CHECKING,
29 Any,
30 Callable,
31 Final,
32 ForwardRef,
33 Literal,
34 TypeVar,
35 Union,
36 cast,
37 overload,
38)
39from uuid import UUID 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
40from warnings import warn 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
41from zoneinfo import ZoneInfo 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
43import typing_extensions 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
44from pydantic_core import ( 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
45 CoreSchema,
46 MultiHostUrl,
47 PydanticCustomError,
48 PydanticSerializationUnexpectedValue,
49 PydanticUndefined,
50 Url,
51 core_schema,
52 to_jsonable_python,
53)
54from typing_extensions import TypeAlias, TypeAliasType, TypedDict, get_args, get_origin, is_typeddict 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
55from typing_inspection import typing_objects 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
56from typing_inspection.introspection import AnnotationSource, get_literal_values, is_union_origin 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
58from ..aliases import AliasChoices, AliasGenerator, AliasPath 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
59from ..annotated_handlers import GetCoreSchemaHandler, GetJsonSchemaHandler 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
60from ..config import ConfigDict, JsonDict, JsonEncoder, JsonSchemaExtraCallable 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
61from ..errors import PydanticSchemaGenerationError, PydanticUndefinedAnnotation, PydanticUserError 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
62from ..functional_validators import AfterValidator, BeforeValidator, FieldValidatorModes, PlainValidator, WrapValidator 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
63from ..json_schema import JsonSchemaValue 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
64from ..version import version_short 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
65from ..warnings import PydanticDeprecatedSince20 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
66from . import _decorators, _discriminated_union, _known_annotated_metadata, _repr, _typing_extra 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
67from ._config import ConfigWrapper, ConfigWrapperStack 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
68from ._core_metadata import CoreMetadata, update_core_metadata 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
69from ._core_utils import ( 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
70 get_ref,
71 get_type_ref,
72 is_list_like_schema_with_items_schema,
73 validate_core_schema,
74)
75from ._decorators import ( 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
76 Decorator,
77 DecoratorInfos,
78 FieldSerializerDecoratorInfo,
79 FieldValidatorDecoratorInfo,
80 ModelSerializerDecoratorInfo,
81 ModelValidatorDecoratorInfo,
82 RootValidatorDecoratorInfo,
83 ValidatorDecoratorInfo,
84 get_attribute_from_bases,
85 inspect_field_serializer,
86 inspect_model_serializer,
87 inspect_validator,
88)
89from ._docs_extraction import extract_docstrings_from_cls 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
90from ._fields import collect_dataclass_fields, rebuild_model_fields, takes_validated_data_argument 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
91from ._forward_ref import PydanticRecursiveRef 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
92from ._generics import get_standard_typevars_map, replace_types 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
93from ._import_utils import import_cached_base_model, import_cached_field_info 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
94from ._mock_val_ser import MockCoreSchema 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
95from ._namespace_utils import NamespacesTuple, NsResolver 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
96from ._schema_gather import MissingDefinitionError, gather_schemas_for_cleaning 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
97from ._schema_generation_shared import CallbackGetCoreSchemaHandler 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
98from ._utils import lenient_issubclass, smart_deepcopy 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
100if TYPE_CHECKING: 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
101 from ..fields import ComputedFieldInfo, FieldInfo
102 from ..main import BaseModel
103 from ..types import Discriminator
104 from ._dataclasses import StandardDataclass
105 from ._schema_generation_shared import GetJsonSchemaFunction
107_SUPPORTS_TYPEDDICT = sys.version_info >= (3, 12) 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
109FieldDecoratorInfo = Union[ValidatorDecoratorInfo, FieldValidatorDecoratorInfo, FieldSerializerDecoratorInfo] 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
110FieldDecoratorInfoType = TypeVar('FieldDecoratorInfoType', bound=FieldDecoratorInfo) 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
111AnyFieldDecorator = Union[ 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
112 Decorator[ValidatorDecoratorInfo],
113 Decorator[FieldValidatorDecoratorInfo],
114 Decorator[FieldSerializerDecoratorInfo],
115]
117ModifyCoreSchemaWrapHandler: TypeAlias = GetCoreSchemaHandler 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
118GetCoreSchemaFunction: TypeAlias = Callable[[Any, ModifyCoreSchemaWrapHandler], core_schema.CoreSchema] 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
119ParametersCallback: TypeAlias = "Callable[[int, str, Any], Literal['skip'] | None]" 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
121TUPLE_TYPES: list[type] = [typing.Tuple, tuple] # noqa: UP006 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
122LIST_TYPES: list[type] = [typing.List, list, collections.abc.MutableSequence] # noqa: UP006 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
123SET_TYPES: list[type] = [typing.Set, set, collections.abc.MutableSet] # noqa: UP006 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
124FROZEN_SET_TYPES: list[type] = [typing.FrozenSet, frozenset, collections.abc.Set] # noqa: UP006 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
125DICT_TYPES: list[type] = [typing.Dict, dict] # noqa: UP006 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
126IP_TYPES: list[type] = [IPv4Address, IPv4Interface, IPv4Network, IPv6Address, IPv6Interface, IPv6Network] 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
127SEQUENCE_TYPES: list[type] = [typing.Sequence, collections.abc.Sequence] 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
128ITERABLE_TYPES: list[type] = [typing.Iterable, collections.abc.Iterable, typing.Generator, collections.abc.Generator] 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
129TYPE_TYPES: list[type] = [typing.Type, type] # noqa: UP006 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
130PATTERN_TYPES: list[type] = [typing.Pattern, re.Pattern] 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
131PATH_TYPES: list[type] = [ 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
132 os.PathLike,
133 pathlib.Path,
134 pathlib.PurePath,
135 pathlib.PosixPath,
136 pathlib.PurePosixPath,
137 pathlib.PureWindowsPath,
138]
139MAPPING_TYPES = [ 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
140 typing.Mapping,
141 typing.MutableMapping,
142 collections.abc.Mapping,
143 collections.abc.MutableMapping,
144 collections.OrderedDict,
145 typing_extensions.OrderedDict,
146 typing.DefaultDict, # noqa: UP006
147 collections.defaultdict,
148]
149COUNTER_TYPES = [collections.Counter, typing.Counter] 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
150DEQUE_TYPES: list[type] = [collections.deque, typing.Deque] # noqa: UP006 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
152# Note: This does not play very well with type checkers. For example,
153# `a: LambdaType = lambda x: x` will raise a type error by Pyright.
154ValidateCallSupportedTypes = Union[ 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
155 LambdaType,
156 FunctionType,
157 MethodType,
158 partial,
159]
161VALIDATE_CALL_SUPPORTED_TYPES = get_args(ValidateCallSupportedTypes) 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
163_mode_to_validator: dict[ 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
164 FieldValidatorModes, type[BeforeValidator | AfterValidator | PlainValidator | WrapValidator]
165] = {'before': BeforeValidator, 'after': AfterValidator, 'plain': PlainValidator, 'wrap': WrapValidator}
168def check_validator_fields_against_field_name( 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
169 info: FieldDecoratorInfo,
170 field: str,
171) -> bool:
172 """Check if field name is in validator fields.
174 Args:
175 info: The field info.
176 field: The field name to check.
178 Returns:
179 `True` if field name is in validator fields, `False` otherwise.
180 """
181 fields = info.fields 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
182 return '*' in fields or field in fields 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
185def check_decorator_fields_exist(decorators: Iterable[AnyFieldDecorator], fields: Iterable[str]) -> None: 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
186 """Check if the defined fields in decorators exist in `fields` param.
188 It ignores the check for a decorator if the decorator has `*` as field or `check_fields=False`.
190 Args:
191 decorators: An iterable of decorators.
192 fields: An iterable of fields name.
194 Raises:
195 PydanticUserError: If one of the field names does not exist in `fields` param.
196 """
197 fields = set(fields) 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
198 for dec in decorators: 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
199 if '*' in dec.info.fields: 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
200 continue 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
201 if dec.info.check_fields is False: 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
202 continue 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
203 for field in dec.info.fields: 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
204 if field not in fields: 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
205 raise PydanticUserError( 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
206 f'Decorators defined with incorrect fields: {dec.cls_ref}.{dec.cls_var_name}'
207 " (use check_fields=False if you're inheriting from the model and intended this)",
208 code='decorator-missing-field',
209 )
212def filter_field_decorator_info_by_field( 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
213 validator_functions: Iterable[Decorator[FieldDecoratorInfoType]], field: str
214) -> list[Decorator[FieldDecoratorInfoType]]:
215 return [dec for dec in validator_functions if check_validator_fields_against_field_name(dec.info, field)] 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
218def apply_each_item_validators( 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
219 schema: core_schema.CoreSchema,
220 each_item_validators: list[Decorator[ValidatorDecoratorInfo]],
221 field_name: str | None,
222) -> core_schema.CoreSchema:
223 # This V1 compatibility shim should eventually be removed
225 # fail early if each_item_validators is empty
226 if not each_item_validators: 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
227 return schema 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
229 # push down any `each_item=True` validators
230 # note that this won't work for any Annotated types that get wrapped by a function validator
231 # but that's okay because that didn't exist in V1
232 if schema['type'] == 'nullable': 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
233 schema['schema'] = apply_each_item_validators(schema['schema'], each_item_validators, field_name) 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
234 return schema 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
235 elif schema['type'] == 'tuple': 235 ↛ 236line 235 didn't jump to line 236 because the condition on line 235 was never true1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
236 if (variadic_item_index := schema.get('variadic_item_index')) is not None:
237 schema['items_schema'][variadic_item_index] = apply_validators(
238 schema['items_schema'][variadic_item_index],
239 each_item_validators,
240 field_name,
241 )
242 elif is_list_like_schema_with_items_schema(schema): 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
243 inner_schema = schema.get('items_schema', core_schema.any_schema()) 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
244 schema['items_schema'] = apply_validators(inner_schema, each_item_validators, field_name) 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
245 elif schema['type'] == 'dict': 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
246 inner_schema = schema.get('values_schema', core_schema.any_schema()) 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
247 schema['values_schema'] = apply_validators(inner_schema, each_item_validators, field_name) 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
248 else:
249 raise TypeError( 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
250 f'`@validator(..., each_item=True)` cannot be applied to fields with a schema of {schema["type"]}'
251 )
252 return schema 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
255def _extract_json_schema_info_from_field_info( 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
256 info: FieldInfo | ComputedFieldInfo,
257) -> tuple[JsonDict | None, JsonDict | JsonSchemaExtraCallable | None]:
258 json_schema_updates = { 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
259 'title': info.title,
260 'description': info.description,
261 'deprecated': bool(info.deprecated) or info.deprecated == '' or None,
262 'examples': to_jsonable_python(info.examples),
263 }
264 json_schema_updates = {k: v for k, v in json_schema_updates.items() if v is not None} 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
265 return (json_schema_updates or None, info.json_schema_extra) 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
268JsonEncoders = dict[type[Any], JsonEncoder] 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
271def _add_custom_serialization_from_json_encoders( 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
272 json_encoders: JsonEncoders | None, tp: Any, schema: CoreSchema
273) -> CoreSchema:
274 """Iterate over the json_encoders and add the first matching encoder to the schema.
276 Args:
277 json_encoders: A dictionary of types and their encoder functions.
278 tp: The type to check for a matching encoder.
279 schema: The schema to add the encoder to.
280 """
281 if not json_encoders: 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
282 return schema 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
283 if 'serialization' in schema: 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
284 return schema 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
285 # Check the class type and its superclasses for a matching encoder
286 # Decimal.__class__.__mro__ (and probably other cases) doesn't include Decimal itself
287 # if the type is a GenericAlias (e.g. from list[int]) we need to use __class__ instead of .__mro__
288 for base in (tp, *getattr(tp, '__mro__', tp.__class__.__mro__)[:-1]): 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
289 encoder = json_encoders.get(base) 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
290 if encoder is None: 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
291 continue 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
293 warnings.warn( 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
294 f'`json_encoders` is deprecated. See https://docs.pydantic.dev/{version_short()}/concepts/serialization/#custom-serializers for alternatives',
295 PydanticDeprecatedSince20,
296 )
298 # TODO: in theory we should check that the schema accepts a serialization key
299 schema['serialization'] = core_schema.plain_serializer_function_ser_schema(encoder, when_used='json') 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
300 return schema 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
302 return schema 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
305def _get_first_non_null(a: Any, b: Any) -> Any: 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
306 """Return the first argument if it is not None, otherwise return the second argument.
308 Use case: serialization_alias (argument a) and alias (argument b) are both defined, and serialization_alias is ''.
309 This function will return serialization_alias, which is the first argument, even though it is an empty string.
310 """
311 return a if a is not None else b 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
314class InvalidSchemaError(Exception): 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
315 """The core schema is invalid."""
318class GenerateSchema: 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
319 """Generate core schema for a Pydantic model, dataclass and types like `str`, `datetime`, ... ."""
321 __slots__ = ( 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
322 '_config_wrapper_stack',
323 '_ns_resolver',
324 '_typevars_map',
325 'field_name_stack',
326 'model_type_stack',
327 'defs',
328 )
330 def __init__( 1abdjoquwxCDghlmrsyzEFGOJKLMNPcifnptvABHI
331 self,
332 config_wrapper: ConfigWrapper,
333 ns_resolver: NsResolver | None = None,
334 typevars_map: Mapping[TypeVar, Any] | None = None,
335 ) -> None:
336 # we need a stack for recursing into nested models
337 self._config_wrapper_stack = ConfigWrapperStack(config_wrapper) 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
338 self._ns_resolver = ns_resolver or NsResolver() 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
339 self._typevars_map = typevars_map 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
340 self.field_name_stack = _FieldNameStack() 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
341 self.model_type_stack = _ModelTypeStack() 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
342 self.defs = _Definitions() 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
344 def __init_subclass__(cls) -> None: 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
345 super().__init_subclass__() 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
346 warnings.warn( 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
347 'Subclassing `GenerateSchema` is not supported. The API is highly subject to change in minor versions.',
348 UserWarning,
349 stacklevel=2,
350 )
352 @property 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
353 def _config_wrapper(self) -> ConfigWrapper: 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
354 return self._config_wrapper_stack.tail 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
356 @property 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
357 def _types_namespace(self) -> NamespacesTuple: 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
358 return self._ns_resolver.types_namespace 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
360 @property 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
361 def _arbitrary_types(self) -> bool: 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
362 return self._config_wrapper.arbitrary_types_allowed 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
364 # the following methods can be overridden but should be considered
365 # unstable / private APIs
366 def _list_schema(self, items_type: Any) -> CoreSchema: 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
367 return core_schema.list_schema(self.generate_schema(items_type)) 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
369 def _dict_schema(self, keys_type: Any, values_type: Any) -> CoreSchema: 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
370 return core_schema.dict_schema(self.generate_schema(keys_type), self.generate_schema(values_type)) 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
372 def _set_schema(self, items_type: Any) -> CoreSchema: 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
373 return core_schema.set_schema(self.generate_schema(items_type)) 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
375 def _frozenset_schema(self, items_type: Any) -> CoreSchema: 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
376 return core_schema.frozenset_schema(self.generate_schema(items_type)) 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
378 def _enum_schema(self, enum_type: type[Enum]) -> CoreSchema: 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
379 cases: list[Any] = list(enum_type.__members__.values()) 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
381 enum_ref = get_type_ref(enum_type) 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
382 description = None if not enum_type.__doc__ else inspect.cleandoc(enum_type.__doc__) 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
383 if ( 1abke
384 description == 'An enumeration.'
385 ): # This is the default value provided by enum.EnumMeta.__new__; don't use it
386 description = None 1abdjkeghlmcifn
387 js_updates = {'title': enum_type.__name__, 'description': description} 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
388 js_updates = {k: v for k, v in js_updates.items() if v is not None} 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
390 sub_type: Literal['str', 'int', 'float'] | None = None 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
391 if issubclass(enum_type, int): 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
392 sub_type = 'int' 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
393 value_ser_type: core_schema.SerSchema = core_schema.simple_ser_schema('int') 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
394 elif issubclass(enum_type, str): 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
395 # this handles `StrEnum` (3.11 only), and also `Foobar(str, Enum)`
396 sub_type = 'str' 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
397 value_ser_type = core_schema.simple_ser_schema('str') 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
398 elif issubclass(enum_type, float): 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
399 sub_type = 'float' 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
400 value_ser_type = core_schema.simple_ser_schema('float') 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
401 else:
402 # TODO this is an ugly hack, how do we trigger an Any schema for serialization?
403 value_ser_type = core_schema.plain_serializer_function_ser_schema(lambda x: x) 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
405 if cases: 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
407 def get_json_schema(schema: CoreSchema, handler: GetJsonSchemaHandler) -> JsonSchemaValue: 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
408 json_schema = handler(schema) 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
409 original_schema = handler.resolve_ref_schema(json_schema) 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
410 original_schema.update(js_updates) 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
411 return json_schema 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
413 # we don't want to add the missing to the schema if it's the default one
414 default_missing = getattr(enum_type._missing_, '__func__', None) is Enum._missing_.__func__ # pyright: ignore[reportFunctionMemberAccess] 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
415 enum_schema = core_schema.enum_schema( 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
416 enum_type,
417 cases,
418 sub_type=sub_type,
419 missing=None if default_missing else enum_type._missing_,
420 ref=enum_ref,
421 metadata={'pydantic_js_functions': [get_json_schema]},
422 )
424 if self._config_wrapper.use_enum_values: 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
425 enum_schema = core_schema.no_info_after_validator_function( 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
426 attrgetter('value'), enum_schema, serialization=value_ser_type
427 )
429 return enum_schema 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
431 else:
433 def get_json_schema_no_cases(_, handler: GetJsonSchemaHandler) -> JsonSchemaValue: 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
434 json_schema = handler(core_schema.enum_schema(enum_type, cases, sub_type=sub_type, ref=enum_ref)) 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
435 original_schema = handler.resolve_ref_schema(json_schema) 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
436 original_schema.update(js_updates) 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
437 return json_schema 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
439 # Use an isinstance check for enums with no cases.
440 # The most important use case for this is creating TypeVar bounds for generics that should
441 # be restricted to enums. This is more consistent than it might seem at first, since you can only
442 # subclass enum.Enum (or subclasses of enum.Enum) if all parent classes have no cases.
443 # We use the get_json_schema function when an Enum subclass has been declared with no cases
444 # so that we can still generate a valid json schema.
445 return core_schema.is_instance_schema( 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
446 enum_type,
447 metadata={'pydantic_js_functions': [get_json_schema_no_cases]},
448 )
450 def _ip_schema(self, tp: Any) -> CoreSchema: 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
451 from ._validators import IP_VALIDATOR_LOOKUP, IpType 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
453 ip_type_json_schema_format: dict[type[IpType], str] = { 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
454 IPv4Address: 'ipv4',
455 IPv4Network: 'ipv4network',
456 IPv4Interface: 'ipv4interface',
457 IPv6Address: 'ipv6',
458 IPv6Network: 'ipv6network',
459 IPv6Interface: 'ipv6interface',
460 }
462 def ser_ip(ip: Any, info: core_schema.SerializationInfo) -> str | IpType: 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
463 if not isinstance(ip, (tp, str)): 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
464 raise PydanticSerializationUnexpectedValue( 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
465 f"Expected `{tp}` but got `{type(ip)}` with value `'{ip}'` - serialized value may not be as expected."
466 )
467 if info.mode == 'python': 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
468 return ip 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
469 return str(ip) 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
471 return core_schema.lax_or_strict_schema( 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
472 lax_schema=core_schema.no_info_plain_validator_function(IP_VALIDATOR_LOOKUP[tp]),
473 strict_schema=core_schema.json_or_python_schema(
474 json_schema=core_schema.no_info_after_validator_function(tp, core_schema.str_schema()),
475 python_schema=core_schema.is_instance_schema(tp),
476 ),
477 serialization=core_schema.plain_serializer_function_ser_schema(ser_ip, info_arg=True, when_used='always'),
478 metadata={
479 'pydantic_js_functions': [lambda _1, _2: {'type': 'string', 'format': ip_type_json_schema_format[tp]}]
480 },
481 )
483 def _path_schema(self, tp: Any, path_type: Any) -> CoreSchema: 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
484 if tp is os.PathLike and (path_type not in {str, bytes} and not typing_objects.is_any(path_type)): 484 ↛ 485line 484 didn't jump to line 485 because the condition on line 484 was never true1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
485 raise PydanticUserError(
486 '`os.PathLike` can only be used with `str`, `bytes` or `Any`', code='schema-for-unknown-type'
487 )
489 path_constructor = pathlib.PurePath if tp is os.PathLike else tp 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
490 strict_inner_schema = ( 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
491 core_schema.bytes_schema(strict=True) if (path_type is bytes) else core_schema.str_schema(strict=True)
492 )
493 lax_inner_schema = core_schema.bytes_schema() if (path_type is bytes) else core_schema.str_schema() 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
495 def path_validator(input_value: str | bytes) -> os.PathLike[Any]: # type: ignore 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
496 try: 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
497 if path_type is bytes: 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
498 if isinstance(input_value, bytes): 498 ↛ 504line 498 didn't jump to line 504 because the condition on line 498 was always true1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
499 try: 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
500 input_value = input_value.decode() 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
501 except UnicodeDecodeError as e:
502 raise PydanticCustomError('bytes_type', 'Input must be valid bytes') from e
503 else:
504 raise PydanticCustomError('bytes_type', 'Input must be bytes')
505 elif not isinstance(input_value, str): 505 ↛ 506line 505 didn't jump to line 506 because the condition on line 505 was never true1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
506 raise PydanticCustomError('path_type', 'Input is not a valid path')
508 return path_constructor(input_value) # type: ignore 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
509 except TypeError as e:
510 raise PydanticCustomError('path_type', 'Input is not a valid path') from e
512 def ser_path(path: Any, info: core_schema.SerializationInfo) -> str | os.PathLike[Any]: 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
513 if not isinstance(path, (tp, str)): 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
514 raise PydanticSerializationUnexpectedValue( 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
515 f"Expected `{tp}` but got `{type(path)}` with value `'{path}'` - serialized value may not be as expected."
516 )
517 if info.mode == 'python': 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
518 return path 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
519 return str(path) 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
521 instance_schema = core_schema.json_or_python_schema( 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
522 json_schema=core_schema.no_info_after_validator_function(path_validator, lax_inner_schema),
523 python_schema=core_schema.is_instance_schema(tp),
524 )
526 schema = core_schema.lax_or_strict_schema( 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
527 lax_schema=core_schema.union_schema(
528 [
529 instance_schema,
530 core_schema.no_info_after_validator_function(path_validator, strict_inner_schema),
531 ],
532 custom_error_type='path_type',
533 custom_error_message=f'Input is not a valid path for {tp}',
534 ),
535 strict_schema=instance_schema,
536 serialization=core_schema.plain_serializer_function_ser_schema(ser_path, info_arg=True, when_used='always'),
537 metadata={'pydantic_js_functions': [lambda source, handler: {**handler(source), 'format': 'path'}]},
538 )
539 return schema 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
541 def _deque_schema(self, items_type: Any) -> CoreSchema: 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
542 from ._serializers import serialize_sequence_via_list 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
543 from ._validators import deque_validator 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
545 item_type_schema = self.generate_schema(items_type) 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
547 # we have to use a lax list schema here, because we need to validate the deque's
548 # items via a list schema, but it's ok if the deque itself is not a list
549 list_schema = core_schema.list_schema(item_type_schema, strict=False) 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
551 check_instance = core_schema.json_or_python_schema( 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
552 json_schema=list_schema,
553 python_schema=core_schema.is_instance_schema(collections.deque, cls_repr='Deque'),
554 )
556 lax_schema = core_schema.no_info_wrap_validator_function(deque_validator, list_schema) 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
558 return core_schema.lax_or_strict_schema( 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
559 lax_schema=lax_schema,
560 strict_schema=core_schema.chain_schema([check_instance, lax_schema]),
561 serialization=core_schema.wrap_serializer_function_ser_schema(
562 serialize_sequence_via_list, schema=item_type_schema, info_arg=True
563 ),
564 )
566 def _mapping_schema(self, tp: Any, keys_type: Any, values_type: Any) -> CoreSchema: 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
567 from ._validators import MAPPING_ORIGIN_MAP, defaultdict_validator, get_defaultdict_default_default_factory 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
569 mapped_origin = MAPPING_ORIGIN_MAP[tp] 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
570 keys_schema = self.generate_schema(keys_type) 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
571 values_schema = self.generate_schema(values_type) 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
572 dict_schema = core_schema.dict_schema(keys_schema, values_schema, strict=False) 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
574 if mapped_origin is dict: 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
575 schema = dict_schema 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
576 else:
577 check_instance = core_schema.json_or_python_schema( 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
578 json_schema=dict_schema,
579 python_schema=core_schema.is_instance_schema(mapped_origin),
580 )
582 if tp is collections.defaultdict: 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
583 default_default_factory = get_defaultdict_default_default_factory(values_type) 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
584 coerce_instance_wrap = partial( 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
585 core_schema.no_info_wrap_validator_function,
586 partial(defaultdict_validator, default_default_factory=default_default_factory),
587 )
588 else:
589 coerce_instance_wrap = partial(core_schema.no_info_after_validator_function, mapped_origin) 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
591 lax_schema = coerce_instance_wrap(dict_schema) 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
592 strict_schema = core_schema.chain_schema([check_instance, lax_schema]) 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
594 schema = core_schema.lax_or_strict_schema( 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
595 lax_schema=lax_schema,
596 strict_schema=strict_schema,
597 serialization=core_schema.wrap_serializer_function_ser_schema(
598 lambda v, h: h(v), schema=dict_schema, info_arg=False
599 ),
600 )
602 return schema 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
604 def _fraction_schema(self) -> CoreSchema: 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
605 """Support for [`fractions.Fraction`][fractions.Fraction]."""
606 from ._validators import fraction_validator 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
608 # TODO: note, this is a fairly common pattern, re lax / strict for attempted type coercion,
609 # can we use a helper function to reduce boilerplate?
610 return core_schema.lax_or_strict_schema( 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
611 lax_schema=core_schema.no_info_plain_validator_function(fraction_validator),
612 strict_schema=core_schema.json_or_python_schema(
613 json_schema=core_schema.no_info_plain_validator_function(fraction_validator),
614 python_schema=core_schema.is_instance_schema(Fraction),
615 ),
616 # use str serialization to guarantee round trip behavior
617 serialization=core_schema.to_string_ser_schema(when_used='always'),
618 metadata={'pydantic_js_functions': [lambda _1, _2: {'type': 'string', 'format': 'fraction'}]},
619 )
621 def _arbitrary_type_schema(self, tp: Any) -> CoreSchema: 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
622 if not isinstance(tp, type): 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
623 warn( 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
624 f'{tp!r} is not a Python type (it may be an instance of an object),'
625 ' Pydantic will allow any object with no validation since we cannot even'
626 ' enforce that the input is an instance of the given type.'
627 ' To get rid of this error wrap the type with `pydantic.SkipValidation`.',
628 UserWarning,
629 )
630 return core_schema.any_schema() 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
631 return core_schema.is_instance_schema(tp) 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
633 def _unknown_type_schema(self, obj: Any) -> CoreSchema: 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
634 raise PydanticSchemaGenerationError( 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
635 f'Unable to generate pydantic-core schema for {obj!r}. '
636 'Set `arbitrary_types_allowed=True` in the model_config to ignore this error'
637 ' or implement `__get_pydantic_core_schema__` on your type to fully support it.'
638 '\n\nIf you got this error by calling handler(<some type>) within'
639 ' `__get_pydantic_core_schema__` then you likely need to call'
640 ' `handler.generate_schema(<some type>)` since we do not call'
641 ' `__get_pydantic_core_schema__` on `<some type>` otherwise to avoid infinite recursion.'
642 )
644 def _apply_discriminator_to_union( 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
645 self, schema: CoreSchema, discriminator: str | Discriminator | None
646 ) -> CoreSchema:
647 if discriminator is None: 647 ↛ 648line 647 didn't jump to line 648 because the condition on line 647 was never true1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
648 return schema
649 try: 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
650 return _discriminated_union.apply_discriminator( 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
651 schema,
652 discriminator,
653 self.defs._definitions,
654 )
655 except _discriminated_union.MissingDefinitionForUnionRef: 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
656 # defer until defs are resolved
657 _discriminated_union.set_discriminator_in_metadata( 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
658 schema,
659 discriminator,
660 )
661 return schema 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
663 def clean_schema(self, schema: CoreSchema) -> CoreSchema: 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
664 schema = self.defs.finalize_schema(schema) 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
665 schema = validate_core_schema(schema) 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
666 return schema 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
668 def _add_js_function(self, metadata_schema: CoreSchema, js_function: Callable[..., Any]) -> None: 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
669 metadata = metadata_schema.get('metadata', {}) 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
670 pydantic_js_functions = metadata.setdefault('pydantic_js_functions', []) 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
671 # because of how we generate core schemas for nested generic models
672 # we can end up adding `BaseModel.__get_pydantic_json_schema__` multiple times
673 # this check may fail to catch duplicates if the function is a `functools.partial`
674 # or something like that, but if it does it'll fail by inserting the duplicate
675 if js_function not in pydantic_js_functions: 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
676 pydantic_js_functions.append(js_function) 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
677 metadata_schema['metadata'] = metadata 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
679 def generate_schema( 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
680 self,
681 obj: Any,
682 ) -> core_schema.CoreSchema:
683 """Generate core schema.
685 Args:
686 obj: The object to generate core schema for.
688 Returns:
689 The generated core schema.
691 Raises:
692 PydanticUndefinedAnnotation:
693 If it is not possible to evaluate forward reference.
694 PydanticSchemaGenerationError:
695 If it is not possible to generate pydantic-core schema.
696 TypeError:
697 - If `alias_generator` returns a disallowed type (must be str, AliasPath or AliasChoices).
698 - If V1 style validator with `each_item=True` applied on a wrong field.
699 PydanticUserError:
700 - If `typing.TypedDict` is used instead of `typing_extensions.TypedDict` on Python < 3.12.
701 - If `__modify_schema__` method is used instead of `__get_pydantic_json_schema__`.
702 """
703 schema = self._generate_schema_from_get_schema_method(obj, obj) 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
705 if schema is None: 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
706 schema = self._generate_schema_inner(obj) 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
708 metadata_js_function = _extract_get_pydantic_json_schema(obj) 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
709 if metadata_js_function is not None: 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
710 metadata_schema = resolve_original_schema(schema, self.defs) 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
711 if metadata_schema: 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
712 self._add_js_function(metadata_schema, metadata_js_function) 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
714 schema = _add_custom_serialization_from_json_encoders(self._config_wrapper.json_encoders, obj, schema) 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
716 return schema 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
718 def _model_schema(self, cls: type[BaseModel]) -> core_schema.CoreSchema: 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
719 """Generate schema for a Pydantic model."""
720 BaseModel_ = import_cached_base_model() 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
722 with self.defs.get_schema_or_ref(cls) as (model_ref, maybe_schema): 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
723 if maybe_schema is not None: 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
724 return maybe_schema 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
726 schema = cls.__dict__.get('__pydantic_core_schema__') 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
727 if schema is not None and not isinstance(schema, MockCoreSchema): 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
728 if schema['type'] == 'definitions': 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
729 schema = self.defs.unpack_definitions(schema) 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
730 ref = get_ref(schema) 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
731 if ref: 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
732 return self.defs.create_definition_reference_schema(schema) 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
733 else:
734 return schema 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
736 config_wrapper = ConfigWrapper(cls.model_config, check=False) 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
738 with self._config_wrapper_stack.push(config_wrapper), self._ns_resolver.push(cls): 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
739 core_config = self._config_wrapper.core_config(title=cls.__name__) 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
741 if cls.__pydantic_fields_complete__ or cls is BaseModel_: 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
742 fields = getattr(cls, '__pydantic_fields__', {}) 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
743 else:
744 try: 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
745 fields = rebuild_model_fields( 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
746 cls,
747 ns_resolver=self._ns_resolver,
748 typevars_map=self._typevars_map or {},
749 )
750 except NameError as e: 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
751 raise PydanticUndefinedAnnotation.from_name_error(e) from e 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
753 decorators = cls.__pydantic_decorators__ 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
754 computed_fields = decorators.computed_fields 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
755 check_decorator_fields_exist( 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
756 chain(
757 decorators.field_validators.values(),
758 decorators.field_serializers.values(),
759 decorators.validators.values(),
760 ),
761 {*fields.keys(), *computed_fields.keys()},
762 )
764 model_validators = decorators.model_validators.values() 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
766 extras_schema = None 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
767 extras_keys_schema = None 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
768 if core_config.get('extra_fields_behavior') == 'allow': 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
769 assert cls.__mro__[0] is cls 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
770 assert cls.__mro__[-1] is object 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
771 for candidate_cls in cls.__mro__[:-1]: 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
772 extras_annotation = getattr(candidate_cls, '__annotations__', {}).get( 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
773 '__pydantic_extra__', None
774 )
775 if extras_annotation is not None: 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
776 if isinstance(extras_annotation, str): 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
777 extras_annotation = _typing_extra.eval_type_backport( 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
778 _typing_extra._make_forward_ref(
779 extras_annotation, is_argument=False, is_class=True
780 ),
781 *self._types_namespace,
782 )
783 tp = get_origin(extras_annotation) 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
784 if tp not in DICT_TYPES: 784 ↛ 785line 784 didn't jump to line 785 because the condition on line 784 was never true1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
785 raise PydanticSchemaGenerationError(
786 'The type annotation for `__pydantic_extra__` must be `dict[str, ...]`'
787 )
788 extra_keys_type, extra_items_type = self._get_args_resolving_forward_refs( 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
789 extras_annotation,
790 required=True,
791 )
792 if extra_keys_type is not str: 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
793 extras_keys_schema = self.generate_schema(extra_keys_type) 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
794 if not typing_objects.is_any(extra_items_type): 794 ↛ 796line 794 didn't jump to line 796 because the condition on line 794 was always true1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
795 extras_schema = self.generate_schema(extra_items_type) 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
796 if extras_keys_schema is not None or extras_schema is not None: 796 ↛ 771line 796 didn't jump to line 771 because the condition on line 796 was always true1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
797 break 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
799 generic_origin: type[BaseModel] | None = getattr(cls, '__pydantic_generic_metadata__', {}).get('origin') 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
801 if cls.__pydantic_root_model__: 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
802 root_field = self._common_field_schema('root', fields['root'], decorators) 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
803 inner_schema = root_field['schema'] 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
804 inner_schema = apply_model_validators(inner_schema, model_validators, 'inner') 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
805 model_schema = core_schema.model_schema( 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
806 cls,
807 inner_schema,
808 generic_origin=generic_origin,
809 custom_init=getattr(cls, '__pydantic_custom_init__', None),
810 root_model=True,
811 post_init=getattr(cls, '__pydantic_post_init__', None),
812 config=core_config,
813 ref=model_ref,
814 )
815 else:
816 fields_schema: core_schema.CoreSchema = core_schema.model_fields_schema( 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
817 {k: self._generate_md_field_schema(k, v, decorators) for k, v in fields.items()},
818 computed_fields=[
819 self._computed_field_schema(d, decorators.field_serializers)
820 for d in computed_fields.values()
821 ],
822 extras_schema=extras_schema,
823 extras_keys_schema=extras_keys_schema,
824 model_name=cls.__name__,
825 )
826 inner_schema = apply_validators(fields_schema, decorators.root_validators.values(), None) 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
827 inner_schema = apply_model_validators(inner_schema, model_validators, 'inner') 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
829 model_schema = core_schema.model_schema( 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
830 cls,
831 inner_schema,
832 generic_origin=generic_origin,
833 custom_init=getattr(cls, '__pydantic_custom_init__', None),
834 root_model=False,
835 post_init=getattr(cls, '__pydantic_post_init__', None),
836 config=core_config,
837 ref=model_ref,
838 )
840 schema = self._apply_model_serializers(model_schema, decorators.model_serializers.values()) 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
841 schema = apply_model_validators(schema, model_validators, 'outer') 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
842 return self.defs.create_definition_reference_schema(schema) 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
844 def _resolve_self_type(self, obj: Any) -> Any: 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
845 obj = self.model_type_stack.get() 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
846 if obj is None: 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
847 raise PydanticUserError('`typing.Self` is invalid in this context', code='invalid-self-type') 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
848 return obj 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
850 def _generate_schema_from_get_schema_method(self, obj: Any, source: Any) -> core_schema.CoreSchema | None: 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
851 BaseModel_ = import_cached_base_model() 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
853 get_schema = getattr(obj, '__get_pydantic_core_schema__', None) 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
854 is_base_model_get_schema = ( 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
855 getattr(get_schema, '__func__', None) is BaseModel_.__get_pydantic_core_schema__.__func__ # pyright: ignore[reportFunctionMemberAccess]
856 )
858 if ( 1abkeghOci
859 get_schema is not None
860 # BaseModel.__get_pydantic_core_schema__ is defined for backwards compatibility,
861 # to allow existing code to call `super().__get_pydantic_core_schema__` in Pydantic
862 # model that overrides `__get_pydantic_core_schema__`. However, it raises a deprecation
863 # warning stating that the method will be removed, and during the core schema gen we actually
864 # don't call the method:
865 and not is_base_model_get_schema
866 ):
867 # Some referenceable types might have a `__get_pydantic_core_schema__` method
868 # defined on it by users (e.g. on a dataclass). This generally doesn't play well
869 # as these types are already recognized by the `GenerateSchema` class and isn't ideal
870 # as we might end up calling `get_schema_or_ref` (expensive) on types that are actually
871 # not referenceable:
872 with self.defs.get_schema_or_ref(obj) as (_, maybe_schema): 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
873 if maybe_schema is not None: 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
874 return maybe_schema 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
876 if obj is source: 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
877 ref_mode = 'unpack' 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
878 else:
879 ref_mode = 'to-def' 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
880 schema = get_schema( 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
881 source, CallbackGetCoreSchemaHandler(self._generate_schema_inner, self, ref_mode=ref_mode)
882 )
883 if schema['type'] == 'definitions': 883 ↛ 884line 883 didn't jump to line 884 because the condition on line 883 was never true1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
884 schema = self.defs.unpack_definitions(schema)
886 ref = get_ref(schema) 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
887 if ref: 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
888 return self.defs.create_definition_reference_schema(schema) 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
890 # Note: if schema is of type `'definition-ref'`, we might want to copy it as a
891 # safety measure (because these are inlined in place -- i.e. mutated directly)
892 return schema 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
894 if get_schema is None and (validators := getattr(obj, '__get_validators__', None)) is not None: 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
895 from pydantic.v1 import BaseModel as BaseModelV1 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
897 if issubclass(obj, BaseModelV1): 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
898 warn( 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
899 f'Mixing V1 models and V2 models (or constructs, like `TypeAdapter`) is not supported. Please upgrade `{obj.__name__}` to V2.',
900 UserWarning,
901 )
902 else:
903 warn( 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
904 '`__get_validators__` is deprecated and will be removed, use `__get_pydantic_core_schema__` instead.',
905 PydanticDeprecatedSince20,
906 )
907 return core_schema.chain_schema([core_schema.with_info_plain_validator_function(v) for v in validators()]) 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
909 def _resolve_forward_ref(self, obj: Any) -> Any: 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
910 # we assume that types_namespace has the target of forward references in its scope,
911 # but this could fail, for example, if calling Validator on an imported type which contains
912 # forward references to other types only defined in the module from which it was imported
913 # `Validator(SomeImportedTypeAliasWithAForwardReference)`
914 # or the equivalent for BaseModel
915 # class Model(BaseModel):
916 # x: SomeImportedTypeAliasWithAForwardReference
917 try: 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
918 obj = _typing_extra.eval_type_backport(obj, *self._types_namespace) 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
919 except NameError as e: 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
920 raise PydanticUndefinedAnnotation.from_name_error(e) from e 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
922 # if obj is still a ForwardRef, it means we can't evaluate it, raise PydanticUndefinedAnnotation
923 if isinstance(obj, ForwardRef): 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
924 raise PydanticUndefinedAnnotation(obj.__forward_arg__, f'Unable to evaluate forward reference {obj}') 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
926 if self._typevars_map: 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
927 obj = replace_types(obj, self._typevars_map) 1abdjkeghlmcifn
929 return obj 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
931 @overload 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
932 def _get_args_resolving_forward_refs(self, obj: Any, required: Literal[True]) -> tuple[Any, ...]: ... 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
934 @overload 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
935 def _get_args_resolving_forward_refs(self, obj: Any) -> tuple[Any, ...] | None: ... 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
937 def _get_args_resolving_forward_refs(self, obj: Any, required: bool = False) -> tuple[Any, ...] | None: 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
938 args = get_args(obj) 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
939 if args: 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
940 if isinstance(obj, GenericAlias): 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
941 # PEP 585 generic aliases don't convert args to ForwardRefs, unlike `typing.List/Dict` etc.
942 args = (_typing_extra._make_forward_ref(a) if isinstance(a, str) else a for a in args) 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
943 args = tuple(self._resolve_forward_ref(a) if isinstance(a, ForwardRef) else a for a in args) 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
944 elif required: # pragma: no cover 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
945 raise TypeError(f'Expected {obj} to have generic parameters but it had none')
946 return args 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
948 def _get_first_arg_or_any(self, obj: Any) -> Any: 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
949 args = self._get_args_resolving_forward_refs(obj) 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
950 if not args: 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
951 return Any 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
952 return args[0] 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
954 def _get_first_two_args_or_any(self, obj: Any) -> tuple[Any, Any]: 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
955 args = self._get_args_resolving_forward_refs(obj) 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
956 if not args: 956 ↛ 957line 956 didn't jump to line 957 because the condition on line 956 was never true1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
957 return (Any, Any)
958 if len(args) < 2: 958 ↛ 959line 958 didn't jump to line 959 because the condition on line 958 was never true1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
959 origin = get_origin(obj)
960 raise TypeError(f'Expected two type arguments for {origin}, got 1')
961 return args[0], args[1] 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
963 def _generate_schema_inner(self, obj: Any) -> core_schema.CoreSchema: 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
964 if typing_objects.is_self(obj): 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
965 obj = self._resolve_self_type(obj) 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
967 if typing_objects.is_annotated(get_origin(obj)): 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
968 return self._annotated_schema(obj) 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
970 if isinstance(obj, dict): 970 ↛ 972line 970 didn't jump to line 972 because the condition on line 970 was never true1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
971 # we assume this is already a valid schema
972 return obj # type: ignore[return-value]
974 if isinstance(obj, str): 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
975 obj = ForwardRef(obj) 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
977 if isinstance(obj, ForwardRef): 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
978 return self.generate_schema(self._resolve_forward_ref(obj)) 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
980 BaseModel = import_cached_base_model() 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
982 if lenient_issubclass(obj, BaseModel): 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
983 with self.model_type_stack.push(obj): 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
984 return self._model_schema(obj) 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
986 if isinstance(obj, PydanticRecursiveRef): 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
987 return core_schema.definition_reference_schema(schema_ref=obj.type_ref) 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
989 return self.match_type(obj) 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
991 def match_type(self, obj: Any) -> core_schema.CoreSchema: # noqa: C901 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
992 """Main mapping of types to schemas.
994 The general structure is a series of if statements starting with the simple cases
995 (non-generic primitive types) and then handling generics and other more complex cases.
997 Each case either generates a schema directly, calls into a public user-overridable method
998 (like `GenerateSchema.tuple_variable_schema`) or calls into a private method that handles some
999 boilerplate before calling into the user-facing method (e.g. `GenerateSchema._tuple_schema`).
1001 The idea is that we'll evolve this into adding more and more user facing methods over time
1002 as they get requested and we figure out what the right API for them is.
1003 """
1004 if obj is str: 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
1005 return core_schema.str_schema() 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
1006 elif obj is bytes: 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
1007 return core_schema.bytes_schema() 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
1008 elif obj is int: 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
1009 return core_schema.int_schema() 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
1010 elif obj is float: 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
1011 return core_schema.float_schema() 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
1012 elif obj is bool: 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
1013 return core_schema.bool_schema() 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
1014 elif obj is complex: 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
1015 return core_schema.complex_schema() 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
1016 elif typing_objects.is_any(obj) or obj is object: 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
1017 return core_schema.any_schema() 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
1018 elif obj is datetime.date: 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
1019 return core_schema.date_schema() 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
1020 elif obj is datetime.datetime: 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
1021 return core_schema.datetime_schema() 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
1022 elif obj is datetime.time: 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
1023 return core_schema.time_schema() 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
1024 elif obj is datetime.timedelta: 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
1025 return core_schema.timedelta_schema() 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
1026 elif obj is Decimal: 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
1027 return core_schema.decimal_schema() 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
1028 elif obj is UUID: 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
1029 return core_schema.uuid_schema() 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
1030 elif obj is Url: 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
1031 return core_schema.url_schema() 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
1032 elif obj is Fraction: 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
1033 return self._fraction_schema() 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
1034 elif obj is MultiHostUrl: 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
1035 return core_schema.multi_host_url_schema() 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
1036 elif obj is None or obj is _typing_extra.NoneType: 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
1037 return core_schema.none_schema() 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
1038 elif obj in IP_TYPES: 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
1039 return self._ip_schema(obj) 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
1040 elif obj in TUPLE_TYPES: 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
1041 return self._tuple_schema(obj) 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
1042 elif obj in LIST_TYPES: 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
1043 return self._list_schema(Any) 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
1044 elif obj in SET_TYPES: 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
1045 return self._set_schema(Any) 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
1046 elif obj in FROZEN_SET_TYPES: 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
1047 return self._frozenset_schema(Any) 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
1048 elif obj in SEQUENCE_TYPES: 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
1049 return self._sequence_schema(Any) 1adouxcfpvB
1050 elif obj in ITERABLE_TYPES: 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
1051 return self._iterable_schema(obj) 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
1052 elif obj in DICT_TYPES: 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
1053 return self._dict_schema(Any, Any) 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
1054 elif obj in PATH_TYPES: 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
1055 return self._path_schema(obj, Any) 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
1056 elif obj in DEQUE_TYPES: 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
1057 return self._deque_schema(Any) 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
1058 elif obj in MAPPING_TYPES: 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
1059 return self._mapping_schema(obj, Any, Any) 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
1060 elif obj in COUNTER_TYPES: 1060 ↛ 1061line 1060 didn't jump to line 1061 because the condition on line 1060 was never true1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
1061 return self._mapping_schema(obj, Any, int)
1062 elif typing_objects.is_typealiastype(obj): 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
1063 return self._type_alias_type_schema(obj) 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
1064 elif obj is type: 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
1065 return self._type_schema() 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
1066 elif _typing_extra.is_callable(obj): 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
1067 return core_schema.callable_schema() 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
1068 elif typing_objects.is_literal(get_origin(obj)): 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
1069 return self._literal_schema(obj) 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
1070 elif is_typeddict(obj): 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
1071 return self._typed_dict_schema(obj, None) 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
1072 elif _typing_extra.is_namedtuple(obj): 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
1073 return self._namedtuple_schema(obj, None) 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
1074 elif typing_objects.is_newtype(obj): 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
1075 # NewType, can't use isinstance because it fails <3.10
1076 return self.generate_schema(obj.__supertype__) 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
1077 elif obj in PATTERN_TYPES: 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
1078 return self._pattern_schema(obj) 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
1079 elif _typing_extra.is_hashable(obj): 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
1080 return self._hashable_schema() 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
1081 elif isinstance(obj, typing.TypeVar): 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
1082 return self._unsubstituted_typevar_schema(obj) 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
1083 elif _typing_extra.is_finalvar(obj): 1083 ↛ 1084line 1083 didn't jump to line 1084 because the condition on line 1083 was never true1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
1084 if obj is Final:
1085 return core_schema.any_schema()
1086 return self.generate_schema(
1087 self._get_first_arg_or_any(obj),
1088 )
1089 elif isinstance(obj, VALIDATE_CALL_SUPPORTED_TYPES): 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
1090 return self._call_schema(obj) 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
1091 elif inspect.isclass(obj) and issubclass(obj, Enum): 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
1092 return self._enum_schema(obj) 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
1093 elif obj is ZoneInfo: 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
1094 return self._zoneinfo_schema() 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
1096 # dataclasses.is_dataclass coerces dc instances to types, but we only handle
1097 # the case of a dc type here
1098 if dataclasses.is_dataclass(obj): 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
1099 return self._dataclass_schema(obj, None) # pyright: ignore[reportArgumentType] 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
1101 origin = get_origin(obj) 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
1102 if origin is not None: 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
1103 return self._match_generic_type(obj, origin) 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
1105 if self._arbitrary_types: 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
1106 return self._arbitrary_type_schema(obj) 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
1107 return self._unknown_type_schema(obj) 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
1109 def _match_generic_type(self, obj: Any, origin: Any) -> CoreSchema: # noqa: C901 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
1110 # Need to handle generic dataclasses before looking for the schema properties because attribute accesses
1111 # on _GenericAlias delegate to the origin type, so lose the information about the concrete parametrization
1112 # As a result, currently, there is no way to cache the schema for generic dataclasses. This may be possible
1113 # to resolve by modifying the value returned by `Generic.__class_getitem__`, but that is a dangerous game.
1114 if dataclasses.is_dataclass(origin): 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
1115 return self._dataclass_schema(obj, origin) # pyright: ignore[reportArgumentType] 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
1116 if _typing_extra.is_namedtuple(origin): 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
1117 return self._namedtuple_schema(obj, origin) 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
1119 schema = self._generate_schema_from_get_schema_method(origin, obj) 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
1120 if schema is not None: 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
1121 return schema 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
1123 if typing_objects.is_typealiastype(origin): 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
1124 return self._type_alias_type_schema(obj) 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
1125 elif is_union_origin(origin): 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
1126 return self._union_schema(obj) 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
1127 elif origin in TUPLE_TYPES: 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
1128 return self._tuple_schema(obj) 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
1129 elif origin in LIST_TYPES: 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
1130 return self._list_schema(self._get_first_arg_or_any(obj)) 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
1131 elif origin in SET_TYPES: 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
1132 return self._set_schema(self._get_first_arg_or_any(obj)) 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
1133 elif origin in FROZEN_SET_TYPES: 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
1134 return self._frozenset_schema(self._get_first_arg_or_any(obj)) 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
1135 elif origin in DICT_TYPES: 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
1136 return self._dict_schema(*self._get_first_two_args_or_any(obj)) 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
1137 elif origin in PATH_TYPES: 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
1138 return self._path_schema(origin, self._get_first_arg_or_any(obj)) 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
1139 elif origin in DEQUE_TYPES: 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
1140 return self._deque_schema(self._get_first_arg_or_any(obj)) 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
1141 elif origin in MAPPING_TYPES: 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
1142 return self._mapping_schema(origin, *self._get_first_two_args_or_any(obj)) 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
1143 elif origin in COUNTER_TYPES: 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
1144 return self._mapping_schema(origin, self._get_first_arg_or_any(obj), int) 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
1145 elif is_typeddict(origin): 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
1146 return self._typed_dict_schema(obj, origin) 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
1147 elif origin in TYPE_TYPES: 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
1148 return self._subclass_schema(obj) 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
1149 elif origin in SEQUENCE_TYPES: 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
1150 return self._sequence_schema(self._get_first_arg_or_any(obj)) 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
1151 elif origin in ITERABLE_TYPES: 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
1152 return self._iterable_schema(obj) 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
1153 elif origin in PATTERN_TYPES: 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
1154 return self._pattern_schema(obj) 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
1156 if self._arbitrary_types: 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
1157 return self._arbitrary_type_schema(origin) 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
1158 return self._unknown_type_schema(obj) 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
1160 def _generate_td_field_schema( 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
1161 self,
1162 name: str,
1163 field_info: FieldInfo,
1164 decorators: DecoratorInfos,
1165 *,
1166 required: bool = True,
1167 ) -> core_schema.TypedDictField:
1168 """Prepare a TypedDictField to represent a model or typeddict field."""
1169 common_field = self._common_field_schema(name, field_info, decorators) 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
1170 return core_schema.typed_dict_field( 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
1171 common_field['schema'],
1172 required=False if not field_info.is_required() else required,
1173 serialization_exclude=common_field['serialization_exclude'],
1174 validation_alias=common_field['validation_alias'],
1175 serialization_alias=common_field['serialization_alias'],
1176 metadata=common_field['metadata'],
1177 )
1179 def _generate_md_field_schema( 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
1180 self,
1181 name: str,
1182 field_info: FieldInfo,
1183 decorators: DecoratorInfos,
1184 ) -> core_schema.ModelField:
1185 """Prepare a ModelField to represent a model field."""
1186 common_field = self._common_field_schema(name, field_info, decorators) 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
1187 return core_schema.model_field( 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
1188 common_field['schema'],
1189 serialization_exclude=common_field['serialization_exclude'],
1190 validation_alias=common_field['validation_alias'],
1191 serialization_alias=common_field['serialization_alias'],
1192 frozen=common_field['frozen'],
1193 metadata=common_field['metadata'],
1194 )
1196 def _generate_dc_field_schema( 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
1197 self,
1198 name: str,
1199 field_info: FieldInfo,
1200 decorators: DecoratorInfos,
1201 ) -> core_schema.DataclassField:
1202 """Prepare a DataclassField to represent the parameter/field, of a dataclass."""
1203 common_field = self._common_field_schema(name, field_info, decorators) 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
1204 return core_schema.dataclass_field( 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
1205 name,
1206 common_field['schema'],
1207 init=field_info.init,
1208 init_only=field_info.init_var or None,
1209 kw_only=None if field_info.kw_only else False,
1210 serialization_exclude=common_field['serialization_exclude'],
1211 validation_alias=common_field['validation_alias'],
1212 serialization_alias=common_field['serialization_alias'],
1213 frozen=common_field['frozen'],
1214 metadata=common_field['metadata'],
1215 )
1217 @staticmethod 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
1218 def _apply_alias_generator_to_field_info( 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
1219 alias_generator: Callable[[str], str] | AliasGenerator, field_info: FieldInfo, field_name: str
1220 ) -> None:
1221 """Apply an alias_generator to aliases on a FieldInfo instance if appropriate.
1223 Args:
1224 alias_generator: A callable that takes a string and returns a string, or an AliasGenerator instance.
1225 field_info: The FieldInfo instance to which the alias_generator is (maybe) applied.
1226 field_name: The name of the field from which to generate the alias.
1227 """
1228 # Apply an alias_generator if
1229 # 1. An alias is not specified
1230 # 2. An alias is specified, but the priority is <= 1
1231 if ( 1abkeghci
1232 field_info.alias_priority is None
1233 or field_info.alias_priority <= 1
1234 or field_info.alias is None
1235 or field_info.validation_alias is None
1236 or field_info.serialization_alias is None
1237 ):
1238 alias, validation_alias, serialization_alias = None, None, None 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
1240 if isinstance(alias_generator, AliasGenerator): 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
1241 alias, validation_alias, serialization_alias = alias_generator.generate_aliases(field_name) 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
1242 elif isinstance(alias_generator, Callable): 1242 ↛ 1250line 1242 didn't jump to line 1250 because the condition on line 1242 was always true1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
1243 alias = alias_generator(field_name) 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
1244 if not isinstance(alias, str): 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
1245 raise TypeError(f'alias_generator {alias_generator} must return str, not {alias.__class__}') 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
1247 # if priority is not set, we set to 1
1248 # which supports the case where the alias_generator from a child class is used
1249 # to generate an alias for a field in a parent class
1250 if field_info.alias_priority is None or field_info.alias_priority <= 1: 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
1251 field_info.alias_priority = 1 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
1253 # if the priority is 1, then we set the aliases to the generated alias
1254 if field_info.alias_priority == 1: 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
1255 field_info.serialization_alias = _get_first_non_null(serialization_alias, alias) 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
1256 field_info.validation_alias = _get_first_non_null(validation_alias, alias) 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
1257 field_info.alias = alias 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
1259 # if any of the aliases are not set, then we set them to the corresponding generated alias
1260 if field_info.alias is None: 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
1261 field_info.alias = alias 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
1262 if field_info.serialization_alias is None: 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
1263 field_info.serialization_alias = _get_first_non_null(serialization_alias, alias) 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
1264 if field_info.validation_alias is None: 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
1265 field_info.validation_alias = _get_first_non_null(validation_alias, alias) 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
1267 @staticmethod 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
1268 def _apply_alias_generator_to_computed_field_info( 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
1269 alias_generator: Callable[[str], str] | AliasGenerator,
1270 computed_field_info: ComputedFieldInfo,
1271 computed_field_name: str,
1272 ):
1273 """Apply an alias_generator to alias on a ComputedFieldInfo instance if appropriate.
1275 Args:
1276 alias_generator: A callable that takes a string and returns a string, or an AliasGenerator instance.
1277 computed_field_info: The ComputedFieldInfo instance to which the alias_generator is (maybe) applied.
1278 computed_field_name: The name of the computed field from which to generate the alias.
1279 """
1280 # Apply an alias_generator if
1281 # 1. An alias is not specified
1282 # 2. An alias is specified, but the priority is <= 1
1284 if ( 1abke
1285 computed_field_info.alias_priority is None
1286 or computed_field_info.alias_priority <= 1
1287 or computed_field_info.alias is None
1288 ):
1289 alias, validation_alias, serialization_alias = None, None, None 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
1291 if isinstance(alias_generator, AliasGenerator): 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
1292 alias, validation_alias, serialization_alias = alias_generator.generate_aliases(computed_field_name) 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
1293 elif isinstance(alias_generator, Callable): 1293 ↛ 1301line 1293 didn't jump to line 1301 because the condition on line 1293 was always true1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
1294 alias = alias_generator(computed_field_name) 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
1295 if not isinstance(alias, str): 1295 ↛ 1296line 1295 didn't jump to line 1296 because the condition on line 1295 was never true1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
1296 raise TypeError(f'alias_generator {alias_generator} must return str, not {alias.__class__}')
1298 # if priority is not set, we set to 1
1299 # which supports the case where the alias_generator from a child class is used
1300 # to generate an alias for a field in a parent class
1301 if computed_field_info.alias_priority is None or computed_field_info.alias_priority <= 1: 1301 ↛ 1307line 1301 didn't jump to line 1307 because the condition on line 1301 was always true1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
1302 computed_field_info.alias_priority = 1 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
1304 # if the priority is 1, then we set the aliases to the generated alias
1305 # note that we use the serialization_alias with priority over alias, as computed_field
1306 # aliases are used for serialization only (not validation)
1307 if computed_field_info.alias_priority == 1: 1307 ↛ exitline 1307 didn't return from function '_apply_alias_generator_to_computed_field_info' because the condition on line 1307 was always true1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
1308 computed_field_info.alias = _get_first_non_null(serialization_alias, alias) 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
1310 @staticmethod 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
1311 def _apply_field_title_generator_to_field_info( 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
1312 config_wrapper: ConfigWrapper, field_info: FieldInfo | ComputedFieldInfo, field_name: str
1313 ) -> None:
1314 """Apply a field_title_generator on a FieldInfo or ComputedFieldInfo instance if appropriate
1315 Args:
1316 config_wrapper: The config of the model
1317 field_info: The FieldInfo or ComputedField instance to which the title_generator is (maybe) applied.
1318 field_name: The name of the field from which to generate the title.
1319 """
1320 field_title_generator = field_info.field_title_generator or config_wrapper.field_title_generator 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
1322 if field_title_generator is None: 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
1323 return 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
1325 if field_info.title is None: 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
1326 title = field_title_generator(field_name, field_info) # type: ignore 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
1327 if not isinstance(title, str): 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
1328 raise TypeError(f'field_title_generator {field_title_generator} must return str, not {title.__class__}') 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
1330 field_info.title = title 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
1332 def _common_field_schema( # C901 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
1333 self, name: str, field_info: FieldInfo, decorators: DecoratorInfos
1334 ) -> _CommonField:
1335 source_type, annotations = field_info.annotation, field_info.metadata 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
1337 def set_discriminator(schema: CoreSchema) -> CoreSchema: 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
1338 schema = self._apply_discriminator_to_union(schema, field_info.discriminator) 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
1339 return schema 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
1341 # Convert `@field_validator` decorators to `Before/After/Plain/WrapValidator` instances:
1342 validators_from_decorators = [] 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
1343 for decorator in filter_field_decorator_info_by_field(decorators.field_validators.values(), name): 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
1344 validators_from_decorators.append(_mode_to_validator[decorator.info.mode]._from_decorator(decorator)) 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
1346 with self.field_name_stack.push(name): 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
1347 if field_info.discriminator is not None: 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
1348 schema = self._apply_annotations( 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
1349 source_type, annotations + validators_from_decorators, transform_inner_schema=set_discriminator
1350 )
1351 else:
1352 schema = self._apply_annotations( 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
1353 source_type,
1354 annotations + validators_from_decorators,
1355 )
1357 # This V1 compatibility shim should eventually be removed
1358 # push down any `each_item=True` validators
1359 # note that this won't work for any Annotated types that get wrapped by a function validator
1360 # but that's okay because that didn't exist in V1
1361 this_field_validators = filter_field_decorator_info_by_field(decorators.validators.values(), name) 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
1362 if _validators_require_validate_default(this_field_validators): 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
1363 field_info.validate_default = True 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
1364 each_item_validators = [v for v in this_field_validators if v.info.each_item is True] 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
1365 this_field_validators = [v for v in this_field_validators if v not in each_item_validators] 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
1366 schema = apply_each_item_validators(schema, each_item_validators, name) 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
1368 schema = apply_validators(schema, this_field_validators, name) 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
1370 # the default validator needs to go outside of any other validators
1371 # so that it is the topmost validator for the field validator
1372 # which uses it to check if the field has a default value or not
1373 if not field_info.is_required(): 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
1374 schema = wrap_default(field_info, schema) 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
1376 schema = self._apply_field_serializers( 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
1377 schema, filter_field_decorator_info_by_field(decorators.field_serializers.values(), name)
1378 )
1379 self._apply_field_title_generator_to_field_info(self._config_wrapper, field_info, name) 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
1381 pydantic_js_updates, pydantic_js_extra = _extract_json_schema_info_from_field_info(field_info) 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
1382 core_metadata: dict[str, Any] = {} 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
1383 update_core_metadata( 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
1384 core_metadata, pydantic_js_updates=pydantic_js_updates, pydantic_js_extra=pydantic_js_extra
1385 )
1387 alias_generator = self._config_wrapper.alias_generator 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
1388 if alias_generator is not None: 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
1389 self._apply_alias_generator_to_field_info(alias_generator, field_info, name) 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
1391 if isinstance(field_info.validation_alias, (AliasChoices, AliasPath)): 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
1392 validation_alias = field_info.validation_alias.convert_to_aliases() 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
1393 else:
1394 validation_alias = field_info.validation_alias 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
1396 return _common_field( 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
1397 schema,
1398 serialization_exclude=True if field_info.exclude else None,
1399 validation_alias=validation_alias,
1400 serialization_alias=field_info.serialization_alias,
1401 frozen=field_info.frozen,
1402 metadata=core_metadata,
1403 )
1405 def _union_schema(self, union_type: Any) -> core_schema.CoreSchema: 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
1406 """Generate schema for a Union."""
1407 args = self._get_args_resolving_forward_refs(union_type, required=True) 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
1408 choices: list[CoreSchema] = [] 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
1409 nullable = False 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
1410 for arg in args: 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
1411 if arg is None or arg is _typing_extra.NoneType: 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
1412 nullable = True 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
1413 else:
1414 choices.append(self.generate_schema(arg)) 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
1416 if len(choices) == 1: 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
1417 s = choices[0] 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
1418 else:
1419 choices_with_tags: list[CoreSchema | tuple[CoreSchema, str]] = [] 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
1420 for choice in choices: 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
1421 tag = cast(CoreMetadata, choice.get('metadata', {})).get('pydantic_internal_union_tag_key') 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
1422 if tag is not None: 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
1423 choices_with_tags.append((choice, tag)) 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
1424 else:
1425 choices_with_tags.append(choice) 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
1426 s = core_schema.union_schema(choices_with_tags) 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
1428 if nullable: 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
1429 s = core_schema.nullable_schema(s) 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
1430 return s 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
1432 def _type_alias_type_schema(self, obj: TypeAliasType) -> CoreSchema: 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
1433 with self.defs.get_schema_or_ref(obj) as (ref, maybe_schema): 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
1434 if maybe_schema is not None: 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
1435 return maybe_schema 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
1437 origin: TypeAliasType = get_origin(obj) or obj 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
1438 typevars_map = get_standard_typevars_map(obj) 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
1440 with self._ns_resolver.push(origin): 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
1441 try: 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
1442 annotation = _typing_extra.eval_type(origin.__value__, *self._types_namespace) 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
1443 except NameError as e:
1444 raise PydanticUndefinedAnnotation.from_name_error(e) from e
1445 annotation = replace_types(annotation, typevars_map) 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
1446 schema = self.generate_schema(annotation) 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
1447 assert schema['type'] != 'definitions' 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
1448 schema['ref'] = ref # type: ignore 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
1449 return self.defs.create_definition_reference_schema(schema) 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
1451 def _literal_schema(self, literal_type: Any) -> CoreSchema: 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
1452 """Generate schema for a Literal."""
1453 expected = list(get_literal_values(literal_type, type_check=False, unpack_type_aliases='eager')) 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
1454 assert expected, f'literal "expected" cannot be empty, obj={literal_type}' 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
1455 schema = core_schema.literal_schema(expected) 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
1457 if self._config_wrapper.use_enum_values and any(isinstance(v, Enum) for v in expected): 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
1458 schema = core_schema.no_info_after_validator_function( 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
1459 lambda v: v.value if isinstance(v, Enum) else v, schema
1460 )
1462 return schema 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
1464 def _typed_dict_schema(self, typed_dict_cls: Any, origin: Any) -> core_schema.CoreSchema: 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
1465 """Generate a core schema for a `TypedDict` class.
1467 To be able to build a `DecoratorInfos` instance for the `TypedDict` class (which will include
1468 validators, serializers, etc.), we need to have access to the original bases of the class
1469 (see https://docs.python.org/3/library/types.html#types.get_original_bases).
1470 However, the `__orig_bases__` attribute was only added in 3.12 (https://github.com/python/cpython/pull/103698).
1472 For this reason, we require Python 3.12 (or using the `typing_extensions` backport).
1473 """
1474 FieldInfo = import_cached_field_info() 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
1476 with ( 1abdjoqkeghlmrscifnpt
1477 self.model_type_stack.push(typed_dict_cls),
1478 self.defs.get_schema_or_ref(typed_dict_cls) as (
1479 typed_dict_ref,
1480 maybe_schema,
1481 ),
1482 ):
1483 if maybe_schema is not None: 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
1484 return maybe_schema 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
1486 typevars_map = get_standard_typevars_map(typed_dict_cls) 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
1487 if origin is not None: 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
1488 typed_dict_cls = origin 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
1490 if not _SUPPORTS_TYPEDDICT and type(typed_dict_cls).__module__ == 'typing': 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
1491 raise PydanticUserError( 1abdjoqkeghlmrscifnpt
1492 'Please use `typing_extensions.TypedDict` instead of `typing.TypedDict` on Python < 3.12.',
1493 code='typed-dict-version',
1494 )
1496 try: 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
1497 # if a typed dictionary class doesn't have config, we use the parent's config, hence a default of `None`
1498 # see https://github.com/pydantic/pydantic/issues/10917
1499 config: ConfigDict | None = get_attribute_from_bases(typed_dict_cls, '__pydantic_config__') 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
1500 except AttributeError: 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
1501 config = None 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
1503 with self._config_wrapper_stack.push(config): 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
1504 core_config = self._config_wrapper.core_config(title=typed_dict_cls.__name__) 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
1506 required_keys: frozenset[str] = typed_dict_cls.__required_keys__ 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
1508 fields: dict[str, core_schema.TypedDictField] = {} 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
1510 decorators = DecoratorInfos.build(typed_dict_cls) 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
1512 if self._config_wrapper.use_attribute_docstrings: 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
1513 field_docstrings = extract_docstrings_from_cls(typed_dict_cls, use_inspect=True) 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
1514 else:
1515 field_docstrings = None 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
1517 try: 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
1518 annotations = _typing_extra.get_cls_type_hints(typed_dict_cls, ns_resolver=self._ns_resolver) 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
1519 except NameError as e:
1520 raise PydanticUndefinedAnnotation.from_name_error(e) from e
1522 readonly_fields: list[str] = [] 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
1524 for field_name, annotation in annotations.items(): 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
1525 field_info = FieldInfo.from_annotation(annotation, _source=AnnotationSource.TYPED_DICT) 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
1526 field_info.annotation = replace_types(field_info.annotation, typevars_map) 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
1528 required = ( 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
1529 field_name in required_keys or 'required' in field_info._qualifiers
1530 ) and 'not_required' not in field_info._qualifiers
1531 if 'read_only' in field_info._qualifiers: 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
1532 readonly_fields.append(field_name) 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
1534 if ( 1abkeghci
1535 field_docstrings is not None
1536 and field_info.description is None
1537 and field_name in field_docstrings
1538 ):
1539 field_info.description = field_docstrings[field_name] 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
1540 self._apply_field_title_generator_to_field_info(self._config_wrapper, field_info, field_name) 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
1541 fields[field_name] = self._generate_td_field_schema( 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
1542 field_name, field_info, decorators, required=required
1543 )
1545 if readonly_fields: 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
1546 fields_repr = ', '.join(repr(f) for f in readonly_fields) 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
1547 plural = len(readonly_fields) >= 2 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
1548 warnings.warn( 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
1549 f'Item{"s" if plural else ""} {fields_repr} on TypedDict class {typed_dict_cls.__name__!r} '
1550 f'{"are" if plural else "is"} using the `ReadOnly` qualifier. Pydantic will not protect items '
1551 'from any mutation on dictionary instances.',
1552 UserWarning,
1553 )
1555 td_schema = core_schema.typed_dict_schema( 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
1556 fields,
1557 cls=typed_dict_cls,
1558 computed_fields=[
1559 self._computed_field_schema(d, decorators.field_serializers)
1560 for d in decorators.computed_fields.values()
1561 ],
1562 ref=typed_dict_ref,
1563 config=core_config,
1564 )
1566 schema = self._apply_model_serializers(td_schema, decorators.model_serializers.values()) 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
1567 schema = apply_model_validators(schema, decorators.model_validators.values(), 'all') 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
1568 return self.defs.create_definition_reference_schema(schema) 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
1570 def _namedtuple_schema(self, namedtuple_cls: Any, origin: Any) -> core_schema.CoreSchema: 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
1571 """Generate schema for a NamedTuple."""
1572 with ( 1abdjoqkeghlmrscifnpt
1573 self.model_type_stack.push(namedtuple_cls),
1574 self.defs.get_schema_or_ref(namedtuple_cls) as (
1575 namedtuple_ref,
1576 maybe_schema,
1577 ),
1578 ):
1579 if maybe_schema is not None: 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
1580 return maybe_schema 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
1581 typevars_map = get_standard_typevars_map(namedtuple_cls) 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
1582 if origin is not None: 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
1583 namedtuple_cls = origin 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
1585 try: 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
1586 annotations = _typing_extra.get_cls_type_hints(namedtuple_cls, ns_resolver=self._ns_resolver) 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
1587 except NameError as e:
1588 raise PydanticUndefinedAnnotation.from_name_error(e) from e
1589 if not annotations: 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
1590 # annotations is empty, happens if namedtuple_cls defined via collections.namedtuple(...)
1591 annotations: dict[str, Any] = {k: Any for k in namedtuple_cls._fields} 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
1593 if typevars_map: 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
1594 annotations = { 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
1595 field_name: replace_types(annotation, typevars_map)
1596 for field_name, annotation in annotations.items()
1597 }
1599 arguments_schema = core_schema.arguments_schema( 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
1600 [
1601 self._generate_parameter_schema(
1602 field_name,
1603 annotation,
1604 source=AnnotationSource.NAMED_TUPLE,
1605 default=namedtuple_cls._field_defaults.get(field_name, Parameter.empty),
1606 )
1607 for field_name, annotation in annotations.items()
1608 ],
1609 metadata={'pydantic_js_prefer_positional_arguments': True},
1610 )
1611 schema = core_schema.call_schema(arguments_schema, namedtuple_cls, ref=namedtuple_ref) 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
1612 return self.defs.create_definition_reference_schema(schema) 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
1614 def _generate_parameter_schema( 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
1615 self,
1616 name: str,
1617 annotation: type[Any],
1618 source: AnnotationSource,
1619 default: Any = Parameter.empty,
1620 mode: Literal['positional_only', 'positional_or_keyword', 'keyword_only'] | None = None,
1621 ) -> core_schema.ArgumentsParameter:
1622 """Generate the definition of a field in a namedtuple or a parameter in a function signature.
1624 This definition is meant to be used for the `'arguments'` core schema, which will be replaced
1625 in V3 by the `'arguments-v3`'.
1626 """
1627 FieldInfo = import_cached_field_info() 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
1629 if default is Parameter.empty: 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
1630 field = FieldInfo.from_annotation(annotation, _source=source) 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
1631 else:
1632 field = FieldInfo.from_annotated_attribute(annotation, default, _source=source) 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
1633 assert field.annotation is not None, 'field.annotation should not be None when generating a schema' 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
1634 with self.field_name_stack.push(name): 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
1635 schema = self._apply_annotations(field.annotation, [field]) 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
1637 if not field.is_required(): 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
1638 schema = wrap_default(field, schema) 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
1640 parameter_schema = core_schema.arguments_parameter(name, schema) 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
1641 if mode is not None: 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
1642 parameter_schema['mode'] = mode 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
1643 if field.alias is not None: 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
1644 parameter_schema['alias'] = field.alias 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
1645 else:
1646 alias_generator = self._config_wrapper.alias_generator 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
1647 if isinstance(alias_generator, AliasGenerator) and alias_generator.alias is not None: 1647 ↛ 1648line 1647 didn't jump to line 1648 because the condition on line 1647 was never true1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
1648 parameter_schema['alias'] = alias_generator.alias(name)
1649 elif callable(alias_generator): 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
1650 parameter_schema['alias'] = alias_generator(name) 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
1651 return parameter_schema 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
1653 def _generate_parameter_v3_schema( 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
1654 self,
1655 name: str,
1656 annotation: Any,
1657 source: AnnotationSource,
1658 mode: Literal[
1659 'positional_only',
1660 'positional_or_keyword',
1661 'keyword_only',
1662 'var_args',
1663 'var_kwargs_uniform',
1664 'var_kwargs_unpacked_typed_dict',
1665 ],
1666 default: Any = Parameter.empty,
1667 ) -> core_schema.ArgumentsV3Parameter:
1668 """Generate the definition of a parameter in a function signature.
1670 This definition is meant to be used for the `'arguments-v3'` core schema, which will replace
1671 the `'arguments`' schema in V3.
1672 """
1673 FieldInfo = import_cached_field_info() 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
1675 if default is Parameter.empty: 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
1676 field = FieldInfo.from_annotation(annotation, _source=source) 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
1677 else:
1678 field = FieldInfo.from_annotated_attribute(annotation, default, _source=source) 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
1680 with self.field_name_stack.push(name): 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
1681 schema = self._apply_annotations(field.annotation, [field]) 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
1683 if not field.is_required(): 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
1684 schema = wrap_default(field, schema) 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
1686 parameter_schema = core_schema.arguments_v3_parameter( 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
1687 name=name,
1688 schema=schema,
1689 mode=mode,
1690 )
1691 if field.alias is not None: 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
1692 parameter_schema['alias'] = field.alias 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
1693 else:
1694 alias_generator = self._config_wrapper.alias_generator 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
1695 if isinstance(alias_generator, AliasGenerator) and alias_generator.alias is not None: 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
1696 parameter_schema['alias'] = alias_generator.alias(name) 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
1697 elif callable(alias_generator): 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
1698 parameter_schema['alias'] = alias_generator(name) 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
1700 return parameter_schema 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
1702 def _tuple_schema(self, tuple_type: Any) -> core_schema.CoreSchema: 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
1703 """Generate schema for a Tuple, e.g. `tuple[int, str]` or `tuple[int, ...]`."""
1704 # TODO: do we really need to resolve type vars here?
1705 typevars_map = get_standard_typevars_map(tuple_type) 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
1706 params = self._get_args_resolving_forward_refs(tuple_type) 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
1708 if typevars_map and params: 1708 ↛ 1709line 1708 didn't jump to line 1709 because the condition on line 1708 was never true1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
1709 params = tuple(replace_types(param, typevars_map) for param in params)
1711 # NOTE: subtle difference: `tuple[()]` gives `params=()`, whereas `typing.Tuple[()]` gives `params=((),)`
1712 # This is only true for <3.11, on Python 3.11+ `typing.Tuple[()]` gives `params=()`
1713 if not params: 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
1714 if tuple_type in TUPLE_TYPES: 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
1715 return core_schema.tuple_schema([core_schema.any_schema()], variadic_item_index=0) 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
1716 else:
1717 # special case for `tuple[()]` which means `tuple[]` - an empty tuple
1718 return core_schema.tuple_schema([]) 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
1719 elif params[-1] is Ellipsis: 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
1720 if len(params) == 2: 1720 ↛ 1724line 1720 didn't jump to line 1724 because the condition on line 1720 was always true1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
1721 return core_schema.tuple_schema([self.generate_schema(params[0])], variadic_item_index=0) 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
1722 else:
1723 # TODO: something like https://github.com/pydantic/pydantic/issues/5952
1724 raise ValueError('Variable tuples can only have one type')
1725 elif len(params) == 1 and params[0] == (): 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
1726 # special case for `tuple[()]` which means `tuple[]` - an empty tuple
1727 # NOTE: This conditional can be removed when we drop support for Python 3.10.
1728 return core_schema.tuple_schema([]) 1abdjkeghlmcifn
1729 else:
1730 return core_schema.tuple_schema([self.generate_schema(param) for param in params]) 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
1732 def _type_schema(self) -> core_schema.CoreSchema: 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
1733 return core_schema.custom_error_schema( 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
1734 core_schema.is_instance_schema(type),
1735 custom_error_type='is_type',
1736 custom_error_message='Input should be a type',
1737 )
1739 def _zoneinfo_schema(self) -> core_schema.CoreSchema: 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
1740 """Generate schema for a zone_info.ZoneInfo object"""
1741 from ._validators import validate_str_is_valid_iana_tz 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
1743 metadata = {'pydantic_js_functions': [lambda _1, _2: {'type': 'string', 'format': 'zoneinfo'}]} 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
1744 return core_schema.no_info_plain_validator_function( 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
1745 validate_str_is_valid_iana_tz,
1746 serialization=core_schema.to_string_ser_schema(),
1747 metadata=metadata,
1748 )
1750 def _union_is_subclass_schema(self, union_type: Any) -> core_schema.CoreSchema: 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
1751 """Generate schema for `type[Union[X, ...]]`."""
1752 args = self._get_args_resolving_forward_refs(union_type, required=True) 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
1753 return core_schema.union_schema([self.generate_schema(type[args]) for args in args]) 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
1755 def _subclass_schema(self, type_: Any) -> core_schema.CoreSchema: 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
1756 """Generate schema for a type, e.g. `type[int]`."""
1757 type_param = self._get_first_arg_or_any(type_) 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
1759 # Assume `type[Annotated[<typ>, ...]]` is equivalent to `type[<typ>]`:
1760 type_param = _typing_extra.annotated_type(type_param) or type_param 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
1762 if typing_objects.is_any(type_param): 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
1763 return self._type_schema() 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
1764 elif typing_objects.is_typealiastype(type_param): 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
1765 return self.generate_schema(type[type_param.__value__]) 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
1766 elif typing_objects.is_typevar(type_param): 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
1767 if type_param.__bound__: 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
1768 if is_union_origin(get_origin(type_param.__bound__)): 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
1769 return self._union_is_subclass_schema(type_param.__bound__) 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
1770 return core_schema.is_subclass_schema(type_param.__bound__) 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
1771 elif type_param.__constraints__: 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
1772 return core_schema.union_schema([self.generate_schema(type[c]) for c in type_param.__constraints__]) 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
1773 else:
1774 return self._type_schema() 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
1775 elif is_union_origin(get_origin(type_param)): 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
1776 return self._union_is_subclass_schema(type_param) 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
1777 else:
1778 if typing_objects.is_self(type_param): 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
1779 type_param = self._resolve_self_type(type_param) 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
1780 if _typing_extra.is_generic_alias(type_param): 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
1781 raise PydanticUserError( 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
1782 'Subscripting `type[]` with an already parametrized type is not supported. '
1783 f'Instead of using type[{type_param!r}], use type[{_repr.display_as_type(get_origin(type_param))}].',
1784 code=None,
1785 )
1786 if not inspect.isclass(type_param): 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
1787 # when using type[None], this doesn't type convert to type[NoneType], and None isn't a class
1788 # so we handle it manually here
1789 if type_param is None: 1789 ↛ 1791line 1789 didn't jump to line 1791 because the condition on line 1789 was always true1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
1790 return core_schema.is_subclass_schema(_typing_extra.NoneType) 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
1791 raise TypeError(f'Expected a class, got {type_param!r}')
1792 return core_schema.is_subclass_schema(type_param) 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
1794 def _sequence_schema(self, items_type: Any) -> core_schema.CoreSchema: 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
1795 """Generate schema for a Sequence, e.g. `Sequence[int]`."""
1796 from ._serializers import serialize_sequence_via_list 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
1798 item_type_schema = self.generate_schema(items_type) 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
1799 list_schema = core_schema.list_schema(item_type_schema) 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
1801 json_schema = smart_deepcopy(list_schema) 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
1802 python_schema = core_schema.is_instance_schema(typing.Sequence, cls_repr='Sequence') 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
1803 if not typing_objects.is_any(items_type): 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
1804 from ._validators import sequence_validator 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
1806 python_schema = core_schema.chain_schema( 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
1807 [python_schema, core_schema.no_info_wrap_validator_function(sequence_validator, list_schema)],
1808 )
1810 serialization = core_schema.wrap_serializer_function_ser_schema( 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
1811 serialize_sequence_via_list, schema=item_type_schema, info_arg=True
1812 )
1813 return core_schema.json_or_python_schema( 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
1814 json_schema=json_schema, python_schema=python_schema, serialization=serialization
1815 )
1817 def _iterable_schema(self, type_: Any) -> core_schema.GeneratorSchema: 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
1818 """Generate a schema for an `Iterable`."""
1819 item_type = self._get_first_arg_or_any(type_) 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
1821 return core_schema.generator_schema(self.generate_schema(item_type)) 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
1823 def _pattern_schema(self, pattern_type: Any) -> core_schema.CoreSchema: 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
1824 from . import _validators 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
1826 metadata = {'pydantic_js_functions': [lambda _1, _2: {'type': 'string', 'format': 'regex'}]} 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
1827 ser = core_schema.plain_serializer_function_ser_schema( 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
1828 attrgetter('pattern'), when_used='json', return_schema=core_schema.str_schema()
1829 )
1830 if pattern_type is typing.Pattern or pattern_type is re.Pattern: 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
1831 # bare type
1832 return core_schema.no_info_plain_validator_function( 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
1833 _validators.pattern_either_validator, serialization=ser, metadata=metadata
1834 )
1836 param = self._get_args_resolving_forward_refs( 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
1837 pattern_type,
1838 required=True,
1839 )[0]
1840 if param is str: 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
1841 return core_schema.no_info_plain_validator_function( 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
1842 _validators.pattern_str_validator, serialization=ser, metadata=metadata
1843 )
1844 elif param is bytes: 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
1845 return core_schema.no_info_plain_validator_function( 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
1846 _validators.pattern_bytes_validator, serialization=ser, metadata=metadata
1847 )
1848 else:
1849 raise PydanticSchemaGenerationError(f'Unable to generate pydantic-core schema for {pattern_type!r}.') 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
1851 def _hashable_schema(self) -> core_schema.CoreSchema: 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
1852 return core_schema.custom_error_schema( 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
1853 schema=core_schema.json_or_python_schema(
1854 json_schema=core_schema.chain_schema(
1855 [core_schema.any_schema(), core_schema.is_instance_schema(collections.abc.Hashable)]
1856 ),
1857 python_schema=core_schema.is_instance_schema(collections.abc.Hashable),
1858 ),
1859 custom_error_type='is_hashable',
1860 custom_error_message='Input should be hashable',
1861 )
1863 def _dataclass_schema( 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
1864 self, dataclass: type[StandardDataclass], origin: type[StandardDataclass] | None
1865 ) -> core_schema.CoreSchema:
1866 """Generate schema for a dataclass."""
1867 with ( 1abdjoqkeghlmrsOJKLMNcifnpt
1868 self.model_type_stack.push(dataclass),
1869 self.defs.get_schema_or_ref(dataclass) as (
1870 dataclass_ref,
1871 maybe_schema,
1872 ),
1873 ):
1874 if maybe_schema is not None: 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
1875 return maybe_schema 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
1877 schema = dataclass.__dict__.get('__pydantic_core_schema__') 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
1878 if schema is not None and not isinstance(schema, MockCoreSchema): 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
1879 if schema['type'] == 'definitions': 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
1880 schema = self.defs.unpack_definitions(schema) 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
1881 ref = get_ref(schema) 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
1882 if ref: 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
1883 return self.defs.create_definition_reference_schema(schema) 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
1884 else:
1885 return schema 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
1887 typevars_map = get_standard_typevars_map(dataclass) 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
1888 if origin is not None: 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
1889 dataclass = origin 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
1891 # if (plain) dataclass doesn't have config, we use the parent's config, hence a default of `None`
1892 # (Pydantic dataclasses have an empty dict config by default).
1893 # see https://github.com/pydantic/pydantic/issues/10917
1894 config = getattr(dataclass, '__pydantic_config__', None) 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
1896 from ..dataclasses import is_pydantic_dataclass 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
1898 with self._ns_resolver.push(dataclass), self._config_wrapper_stack.push(config): 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
1899 if is_pydantic_dataclass(dataclass): 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
1900 # Copy the field info instances to avoid mutating the `FieldInfo` instances
1901 # of the generic dataclass generic origin (e.g. `apply_typevars_map` below).
1902 # Note that we don't apply `deepcopy` on `__pydantic_fields__` because we
1903 # don't want to copy the `FieldInfo` attributes:
1904 fields = {f_name: copy(field_info) for f_name, field_info in dataclass.__pydantic_fields__.items()} 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
1905 if typevars_map: 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
1906 for field in fields.values(): 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
1907 field.apply_typevars_map(typevars_map, *self._types_namespace) 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
1908 else:
1909 fields = collect_dataclass_fields( 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
1910 dataclass,
1911 typevars_map=typevars_map,
1912 config_wrapper=self._config_wrapper,
1913 )
1915 if self._config_wrapper.extra == 'allow': 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
1916 # disallow combination of init=False on a dataclass field and extra='allow' on a dataclass
1917 for field_name, field in fields.items(): 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
1918 if field.init is False: 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
1919 raise PydanticUserError( 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
1920 f'Field {field_name} has `init=False` and dataclass has config setting `extra="allow"`. '
1921 f'This combination is not allowed.',
1922 code='dataclass-init-false-extra-allow',
1923 )
1925 decorators = dataclass.__dict__.get('__pydantic_decorators__') or DecoratorInfos.build(dataclass) 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
1926 # Move kw_only=False args to the start of the list, as this is how vanilla dataclasses work.
1927 # Note that when kw_only is missing or None, it is treated as equivalent to kw_only=True
1928 args = sorted( 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
1929 (self._generate_dc_field_schema(k, v, decorators) for k, v in fields.items()),
1930 key=lambda a: a.get('kw_only') is not False,
1931 )
1932 has_post_init = hasattr(dataclass, '__post_init__') 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
1933 has_slots = hasattr(dataclass, '__slots__') 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
1935 args_schema = core_schema.dataclass_args_schema( 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
1936 dataclass.__name__,
1937 args,
1938 computed_fields=[
1939 self._computed_field_schema(d, decorators.field_serializers)
1940 for d in decorators.computed_fields.values()
1941 ],
1942 collect_init_only=has_post_init,
1943 )
1945 inner_schema = apply_validators(args_schema, decorators.root_validators.values(), None) 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
1947 model_validators = decorators.model_validators.values() 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
1948 inner_schema = apply_model_validators(inner_schema, model_validators, 'inner') 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
1950 core_config = self._config_wrapper.core_config(title=dataclass.__name__) 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
1952 dc_schema = core_schema.dataclass_schema( 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
1953 dataclass,
1954 inner_schema,
1955 generic_origin=origin,
1956 post_init=has_post_init,
1957 ref=dataclass_ref,
1958 fields=[field.name for field in dataclasses.fields(dataclass)],
1959 slots=has_slots,
1960 config=core_config,
1961 # we don't use a custom __setattr__ for dataclasses, so we must
1962 # pass along the frozen config setting to the pydantic-core schema
1963 frozen=self._config_wrapper_stack.tail.frozen,
1964 )
1965 schema = self._apply_model_serializers(dc_schema, decorators.model_serializers.values()) 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
1966 schema = apply_model_validators(schema, model_validators, 'outer') 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
1967 return self.defs.create_definition_reference_schema(schema) 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
1969 def _call_schema(self, function: ValidateCallSupportedTypes) -> core_schema.CallSchema: 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
1970 """Generate schema for a Callable.
1972 TODO support functional validators once we support them in Config
1973 """
1974 arguments_schema = self._arguments_schema(function) 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
1976 return_schema: core_schema.CoreSchema | None = None 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
1977 config_wrapper = self._config_wrapper 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
1978 if config_wrapper.validate_return: 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
1979 sig = signature(function) 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
1980 return_hint = sig.return_annotation 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
1981 if return_hint is not sig.empty: 1981 ↛ 1988line 1981 didn't jump to line 1988 because the condition on line 1981 was always true1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
1982 globalns, localns = self._types_namespace 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
1983 type_hints = _typing_extra.get_function_type_hints( 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
1984 function, globalns=globalns, localns=localns, include_keys={'return'}
1985 )
1986 return_schema = self.generate_schema(type_hints['return']) 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
1988 return core_schema.call_schema( 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
1989 arguments_schema,
1990 function,
1991 return_schema=return_schema,
1992 )
1994 def _arguments_schema( 1abdjoquwxCDghlmrsyzEFGOJKLMNPcifnptvABHI
1995 self, function: ValidateCallSupportedTypes, parameters_callback: ParametersCallback | None = None
1996 ) -> core_schema.ArgumentsSchema:
1997 """Generate schema for a Signature."""
1998 mode_lookup: dict[_ParameterKind, Literal['positional_only', 'positional_or_keyword', 'keyword_only']] = { 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
1999 Parameter.POSITIONAL_ONLY: 'positional_only',
2000 Parameter.POSITIONAL_OR_KEYWORD: 'positional_or_keyword',
2001 Parameter.KEYWORD_ONLY: 'keyword_only',
2002 }
2004 sig = signature(function) 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
2005 globalns, localns = self._types_namespace 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
2006 type_hints = _typing_extra.get_function_type_hints(function, globalns=globalns, localns=localns) 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
2008 arguments_list: list[core_schema.ArgumentsParameter] = [] 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
2009 var_args_schema: core_schema.CoreSchema | None = None 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
2010 var_kwargs_schema: core_schema.CoreSchema | None = None 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
2011 var_kwargs_mode: core_schema.VarKwargsMode | None = None 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
2013 for i, (name, p) in enumerate(sig.parameters.items()): 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
2014 if p.annotation is sig.empty: 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
2015 annotation = typing.cast(Any, Any) 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
2016 else:
2017 annotation = type_hints[name] 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
2019 if parameters_callback is not None: 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
2020 result = parameters_callback(i, name, annotation) 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
2021 if result == 'skip': 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
2022 continue 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
2024 parameter_mode = mode_lookup.get(p.kind) 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
2025 if parameter_mode is not None: 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
2026 arg_schema = self._generate_parameter_schema( 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
2027 name, annotation, AnnotationSource.FUNCTION, p.default, parameter_mode
2028 )
2029 arguments_list.append(arg_schema) 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
2030 elif p.kind == Parameter.VAR_POSITIONAL: 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
2031 var_args_schema = self.generate_schema(annotation) 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
2032 else:
2033 assert p.kind == Parameter.VAR_KEYWORD, p.kind 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
2035 unpack_type = _typing_extra.unpack_type(annotation) 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
2036 if unpack_type is not None: 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
2037 origin = get_origin(unpack_type) or unpack_type 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
2038 if not is_typeddict(origin): 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
2039 raise PydanticUserError( 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
2040 f'Expected a `TypedDict` class inside `Unpack[...]`, got {unpack_type!r}',
2041 code='unpack-typed-dict',
2042 )
2043 non_pos_only_param_names = { 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
2044 name for name, p in sig.parameters.items() if p.kind != Parameter.POSITIONAL_ONLY
2045 }
2046 overlapping_params = non_pos_only_param_names.intersection(origin.__annotations__) 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
2047 if overlapping_params: 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
2048 raise PydanticUserError( 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
2049 f'Typed dictionary {origin.__name__!r} overlaps with parameter'
2050 f'{"s" if len(overlapping_params) >= 2 else ""} '
2051 f'{", ".join(repr(p) for p in sorted(overlapping_params))}',
2052 code='overlapping-unpack-typed-dict',
2053 )
2055 var_kwargs_mode = 'unpacked-typed-dict' 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
2056 var_kwargs_schema = self._typed_dict_schema(unpack_type, get_origin(unpack_type)) 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
2057 else:
2058 var_kwargs_mode = 'uniform' 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
2059 var_kwargs_schema = self.generate_schema(annotation) 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
2061 return core_schema.arguments_schema( 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
2062 arguments_list,
2063 var_args_schema=var_args_schema,
2064 var_kwargs_mode=var_kwargs_mode,
2065 var_kwargs_schema=var_kwargs_schema,
2066 validate_by_name=self._config_wrapper.validate_by_name,
2067 )
2069 def _arguments_v3_schema( 1abdjoquwxCDghlmrsyzEFGOJKLMNPcifnptvABHI
2070 self, function: ValidateCallSupportedTypes, parameters_callback: ParametersCallback | None = None
2071 ) -> core_schema.ArgumentsV3Schema:
2072 mode_lookup: dict[ 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
2073 _ParameterKind, Literal['positional_only', 'positional_or_keyword', 'var_args', 'keyword_only']
2074 ] = {
2075 Parameter.POSITIONAL_ONLY: 'positional_only',
2076 Parameter.POSITIONAL_OR_KEYWORD: 'positional_or_keyword',
2077 Parameter.VAR_POSITIONAL: 'var_args',
2078 Parameter.KEYWORD_ONLY: 'keyword_only',
2079 }
2081 sig = signature(function) 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
2082 globalns, localns = self._types_namespace 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
2083 type_hints = _typing_extra.get_function_type_hints(function, globalns=globalns, localns=localns) 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
2085 parameters_list: list[core_schema.ArgumentsV3Parameter] = [] 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
2087 for i, (name, p) in enumerate(sig.parameters.items()): 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
2088 if parameters_callback is not None: 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
2089 result = parameters_callback(i, name, p.annotation) 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
2090 if result == 'skip': 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
2091 continue 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
2093 if p.annotation is Parameter.empty: 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
2094 annotation = typing.cast(Any, Any) 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
2095 else:
2096 annotation = type_hints[name] 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
2098 parameter_mode = mode_lookup.get(p.kind) 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
2099 if parameter_mode is None: 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
2100 assert p.kind == Parameter.VAR_KEYWORD, p.kind 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
2102 unpack_type = _typing_extra.unpack_type(annotation) 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
2103 if unpack_type is not None: 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
2104 origin = get_origin(unpack_type) or unpack_type 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
2105 if not is_typeddict(origin): 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
2106 raise PydanticUserError( 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
2107 f'Expected a `TypedDict` class inside `Unpack[...]`, got {unpack_type!r}',
2108 code='unpack-typed-dict',
2109 )
2110 non_pos_only_param_names = { 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
2111 name for name, p in sig.parameters.items() if p.kind != Parameter.POSITIONAL_ONLY
2112 }
2113 overlapping_params = non_pos_only_param_names.intersection(origin.__annotations__) 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
2114 if overlapping_params: 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
2115 raise PydanticUserError( 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
2116 f'Typed dictionary {origin.__name__!r} overlaps with parameter'
2117 f'{"s" if len(overlapping_params) >= 2 else ""} '
2118 f'{", ".join(repr(p) for p in sorted(overlapping_params))}',
2119 code='overlapping-unpack-typed-dict',
2120 )
2121 parameter_mode = 'var_kwargs_unpacked_typed_dict' 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
2122 annotation = unpack_type 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
2123 else:
2124 parameter_mode = 'var_kwargs_uniform' 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
2126 parameters_list.append( 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
2127 self._generate_parameter_v3_schema(
2128 name, annotation, AnnotationSource.FUNCTION, parameter_mode, default=p.default
2129 )
2130 )
2132 return core_schema.arguments_v3_schema( 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
2133 parameters_list,
2134 validate_by_name=self._config_wrapper.validate_by_name,
2135 )
2137 def _unsubstituted_typevar_schema(self, typevar: typing.TypeVar) -> core_schema.CoreSchema: 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
2138 try: 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
2139 has_default = typevar.has_default() 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
2140 except AttributeError: 1abdjoquwkeghlmrsyzOJKLMNcifnptvA
2141 # Happens if using `typing.TypeVar` (and not `typing_extensions`) on Python < 3.13
2142 pass 1abdjoquwkeghlmrsyzOJKLMNcifnptvA
2143 else:
2144 if has_default: 1abdjoquwxCDkeghlmrsyzEFGPcifnptvABHI
2145 return self.generate_schema(typevar.__default__) 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
2147 if constraints := typevar.__constraints__: 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
2148 return self._union_schema(typing.Union[constraints]) 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
2150 if bound := typevar.__bound__: 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
2151 schema = self.generate_schema(bound) 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
2152 schema['serialization'] = core_schema.wrap_serializer_function_ser_schema( 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
2153 lambda x, h: h(x),
2154 schema=core_schema.any_schema(),
2155 )
2156 return schema 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
2158 return core_schema.any_schema() 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
2160 def _computed_field_schema( 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
2161 self,
2162 d: Decorator[ComputedFieldInfo],
2163 field_serializers: dict[str, Decorator[FieldSerializerDecoratorInfo]],
2164 ) -> core_schema.ComputedField:
2165 if d.info.return_type is not PydanticUndefined: 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
2166 return_type = d.info.return_type 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
2167 else:
2168 try: 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
2169 # Do not pass in globals as the function could be defined in a different module.
2170 # Instead, let `get_callable_return_type` infer the globals to use, but still pass
2171 # in locals that may contain a parent/rebuild namespace:
2172 return_type = _decorators.get_callable_return_type(d.func, localns=self._types_namespace.locals) 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
2173 except NameError as e: 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
2174 raise PydanticUndefinedAnnotation.from_name_error(e) from e 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
2175 if return_type is PydanticUndefined: 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
2176 raise PydanticUserError( 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
2177 'Computed field is missing return type annotation or specifying `return_type`'
2178 ' to the `@computed_field` decorator (e.g. `@computed_field(return_type=int | str)`)',
2179 code='model-field-missing-annotation',
2180 )
2182 return_type = replace_types(return_type, self._typevars_map) 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
2183 # Create a new ComputedFieldInfo so that different type parametrizations of the same
2184 # generic model's computed field can have different return types.
2185 d.info = dataclasses.replace(d.info, return_type=return_type) 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
2186 return_type_schema = self.generate_schema(return_type) 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
2187 # Apply serializers to computed field if there exist
2188 return_type_schema = self._apply_field_serializers( 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
2189 return_type_schema,
2190 filter_field_decorator_info_by_field(field_serializers.values(), d.cls_var_name),
2191 )
2193 alias_generator = self._config_wrapper.alias_generator 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
2194 if alias_generator is not None: 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
2195 self._apply_alias_generator_to_computed_field_info( 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
2196 alias_generator=alias_generator, computed_field_info=d.info, computed_field_name=d.cls_var_name
2197 )
2198 self._apply_field_title_generator_to_field_info(self._config_wrapper, d.info, d.cls_var_name) 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
2200 pydantic_js_updates, pydantic_js_extra = _extract_json_schema_info_from_field_info(d.info) 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
2201 core_metadata: dict[str, Any] = {} 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
2202 update_core_metadata( 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
2203 core_metadata,
2204 pydantic_js_updates={'readOnly': True, **(pydantic_js_updates if pydantic_js_updates else {})},
2205 pydantic_js_extra=pydantic_js_extra,
2206 )
2207 return core_schema.computed_field( 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
2208 d.cls_var_name, return_schema=return_type_schema, alias=d.info.alias, metadata=core_metadata
2209 )
2211 def _annotated_schema(self, annotated_type: Any) -> core_schema.CoreSchema: 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
2212 """Generate schema for an Annotated type, e.g. `Annotated[int, Field(...)]` or `Annotated[int, Gt(0)]`."""
2213 FieldInfo = import_cached_field_info() 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
2214 source_type, *annotations = self._get_args_resolving_forward_refs( 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
2215 annotated_type,
2216 required=True,
2217 )
2218 schema = self._apply_annotations(source_type, annotations) 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
2219 # put the default validator last so that TypeAdapter.get_default_value() works
2220 # even if there are function validators involved
2221 for annotation in annotations: 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
2222 if isinstance(annotation, FieldInfo): 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
2223 schema = wrap_default(annotation, schema) 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
2224 return schema 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
2226 def _apply_annotations( 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
2227 self,
2228 source_type: Any,
2229 annotations: list[Any],
2230 transform_inner_schema: Callable[[CoreSchema], CoreSchema] = lambda x: x,
2231 ) -> CoreSchema:
2232 """Apply arguments from `Annotated` or from `FieldInfo` to a schema.
2234 This gets called by `GenerateSchema._annotated_schema` but differs from it in that it does
2235 not expect `source_type` to be an `Annotated` object, it expects it to be the first argument of that
2236 (in other words, `GenerateSchema._annotated_schema` just unpacks `Annotated`, this process it).
2237 """
2238 annotations = list(_known_annotated_metadata.expand_grouped_metadata(annotations)) 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
2240 pydantic_js_annotation_functions: list[GetJsonSchemaFunction] = [] 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
2242 def inner_handler(obj: Any) -> CoreSchema: 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
2243 schema = self._generate_schema_from_get_schema_method(obj, source_type) 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
2245 if schema is None: 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
2246 schema = self._generate_schema_inner(obj) 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
2248 metadata_js_function = _extract_get_pydantic_json_schema(obj) 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
2249 if metadata_js_function is not None: 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
2250 metadata_schema = resolve_original_schema(schema, self.defs) 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
2251 if metadata_schema is not None: 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
2252 self._add_js_function(metadata_schema, metadata_js_function) 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
2253 return transform_inner_schema(schema) 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
2255 get_inner_schema = CallbackGetCoreSchemaHandler(inner_handler, self) 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
2257 for annotation in annotations: 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
2258 if annotation is None: 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
2259 continue 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
2260 get_inner_schema = self._get_wrapped_inner_schema( 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
2261 get_inner_schema, annotation, pydantic_js_annotation_functions
2262 )
2264 schema = get_inner_schema(source_type) 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
2265 if pydantic_js_annotation_functions: 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
2266 core_metadata = schema.setdefault('metadata', {}) 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
2267 update_core_metadata(core_metadata, pydantic_js_annotation_functions=pydantic_js_annotation_functions) 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
2268 return _add_custom_serialization_from_json_encoders(self._config_wrapper.json_encoders, source_type, schema) 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
2270 def _apply_single_annotation(self, schema: core_schema.CoreSchema, metadata: Any) -> core_schema.CoreSchema: 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
2271 FieldInfo = import_cached_field_info() 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
2273 if isinstance(metadata, FieldInfo): 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
2274 for field_metadata in metadata.metadata: 2274 ↛ 2275line 2274 didn't jump to line 2275 because the loop on line 2274 never started1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
2275 schema = self._apply_single_annotation(schema, field_metadata)
2277 if metadata.discriminator is not None: 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
2278 schema = self._apply_discriminator_to_union(schema, metadata.discriminator) 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
2279 return schema 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
2281 if schema['type'] == 'nullable': 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
2282 # for nullable schemas, metadata is automatically applied to the inner schema
2283 inner = schema.get('schema', core_schema.any_schema()) 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
2284 inner = self._apply_single_annotation(inner, metadata) 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
2285 if inner: 2285 ↛ 2287line 2285 didn't jump to line 2287 because the condition on line 2285 was always true1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
2286 schema['schema'] = inner 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
2287 return schema 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
2289 original_schema = schema 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
2290 ref = schema.get('ref') 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
2291 if ref is not None: 2291 ↛ 2292line 2291 didn't jump to line 2292 because the condition on line 2291 was never true1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
2292 schema = schema.copy()
2293 new_ref = ref + f'_{repr(metadata)}'
2294 if (existing := self.defs.get_schema_from_ref(new_ref)) is not None:
2295 return existing
2296 schema['ref'] = new_ref # pyright: ignore[reportGeneralTypeIssues]
2297 elif schema['type'] == 'definition-ref': 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
2298 ref = schema['schema_ref'] 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
2299 if (referenced_schema := self.defs.get_schema_from_ref(ref)) is not None: 2299 ↛ 2306line 2299 didn't jump to line 2306 because the condition on line 2299 was always true1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
2300 schema = referenced_schema.copy() 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
2301 new_ref = ref + f'_{repr(metadata)}' 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
2302 if (existing := self.defs.get_schema_from_ref(new_ref)) is not None: 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
2303 return existing 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
2304 schema['ref'] = new_ref # pyright: ignore[reportGeneralTypeIssues] 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
2306 maybe_updated_schema = _known_annotated_metadata.apply_known_metadata(metadata, schema) 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
2308 if maybe_updated_schema is not None: 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
2309 return maybe_updated_schema 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
2310 return original_schema 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
2312 def _apply_single_annotation_json_schema( 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
2313 self, schema: core_schema.CoreSchema, metadata: Any
2314 ) -> core_schema.CoreSchema:
2315 FieldInfo = import_cached_field_info() 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
2317 if isinstance(metadata, FieldInfo): 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
2318 for field_metadata in metadata.metadata: 2318 ↛ 2319line 2318 didn't jump to line 2319 because the loop on line 2318 never started1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
2319 schema = self._apply_single_annotation_json_schema(schema, field_metadata)
2321 pydantic_js_updates, pydantic_js_extra = _extract_json_schema_info_from_field_info(metadata) 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
2322 core_metadata = schema.setdefault('metadata', {}) 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
2323 update_core_metadata( 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
2324 core_metadata, pydantic_js_updates=pydantic_js_updates, pydantic_js_extra=pydantic_js_extra
2325 )
2326 return schema 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
2328 def _get_wrapped_inner_schema( 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
2329 self,
2330 get_inner_schema: GetCoreSchemaHandler,
2331 annotation: Any,
2332 pydantic_js_annotation_functions: list[GetJsonSchemaFunction],
2333 ) -> CallbackGetCoreSchemaHandler:
2334 annotation_get_schema: GetCoreSchemaFunction | None = getattr(annotation, '__get_pydantic_core_schema__', None) 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
2336 def new_handler(source: Any) -> core_schema.CoreSchema: 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
2337 if annotation_get_schema is not None: 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
2338 schema = annotation_get_schema(source, get_inner_schema) 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
2339 else:
2340 schema = get_inner_schema(source) 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
2341 schema = self._apply_single_annotation(schema, annotation) 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
2342 schema = self._apply_single_annotation_json_schema(schema, annotation) 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
2344 metadata_js_function = _extract_get_pydantic_json_schema(annotation) 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
2345 if metadata_js_function is not None: 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
2346 pydantic_js_annotation_functions.append(metadata_js_function) 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
2347 return schema 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
2349 return CallbackGetCoreSchemaHandler(new_handler, self) 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
2351 def _apply_field_serializers( 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
2352 self,
2353 schema: core_schema.CoreSchema,
2354 serializers: list[Decorator[FieldSerializerDecoratorInfo]],
2355 ) -> core_schema.CoreSchema:
2356 """Apply field serializers to a schema."""
2357 if serializers: 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
2358 schema = copy(schema) 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
2359 if schema['type'] == 'definitions': 2359 ↛ 2360line 2359 didn't jump to line 2360 because the condition on line 2359 was never true1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
2360 inner_schema = schema['schema']
2361 schema['schema'] = self._apply_field_serializers(inner_schema, serializers)
2362 return schema
2363 elif 'ref' in schema: 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
2364 schema = self.defs.create_definition_reference_schema(schema) 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
2366 # use the last serializer to make it easy to override a serializer set on a parent model
2367 serializer = serializers[-1] 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
2368 is_field_serializer, info_arg = inspect_field_serializer(serializer.func, serializer.info.mode) 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
2370 if serializer.info.return_type is not PydanticUndefined: 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
2371 return_type = serializer.info.return_type 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
2372 else:
2373 try: 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
2374 # Do not pass in globals as the function could be defined in a different module.
2375 # Instead, let `get_callable_return_type` infer the globals to use, but still pass
2376 # in locals that may contain a parent/rebuild namespace:
2377 return_type = _decorators.get_callable_return_type( 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
2378 serializer.func, localns=self._types_namespace.locals
2379 )
2380 except NameError as e: 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
2381 raise PydanticUndefinedAnnotation.from_name_error(e) from e 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
2383 if return_type is PydanticUndefined: 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
2384 return_schema = None 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
2385 else:
2386 return_schema = self.generate_schema(return_type) 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
2388 if serializer.info.mode == 'wrap': 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
2389 schema['serialization'] = core_schema.wrap_serializer_function_ser_schema( 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
2390 serializer.func,
2391 is_field_serializer=is_field_serializer,
2392 info_arg=info_arg,
2393 return_schema=return_schema,
2394 when_used=serializer.info.when_used,
2395 )
2396 else:
2397 assert serializer.info.mode == 'plain' 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
2398 schema['serialization'] = core_schema.plain_serializer_function_ser_schema( 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
2399 serializer.func,
2400 is_field_serializer=is_field_serializer,
2401 info_arg=info_arg,
2402 return_schema=return_schema,
2403 when_used=serializer.info.when_used,
2404 )
2405 return schema 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
2407 def _apply_model_serializers( 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
2408 self, schema: core_schema.CoreSchema, serializers: Iterable[Decorator[ModelSerializerDecoratorInfo]]
2409 ) -> core_schema.CoreSchema:
2410 """Apply model serializers to a schema."""
2411 ref: str | None = schema.pop('ref', None) # type: ignore 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
2412 if serializers: 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
2413 serializer = list(serializers)[-1] 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
2414 info_arg = inspect_model_serializer(serializer.func, serializer.info.mode) 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
2416 if serializer.info.return_type is not PydanticUndefined: 2416 ↛ 2417line 2416 didn't jump to line 2417 because the condition on line 2416 was never true1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
2417 return_type = serializer.info.return_type
2418 else:
2419 try: 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
2420 # Do not pass in globals as the function could be defined in a different module.
2421 # Instead, let `get_callable_return_type` infer the globals to use, but still pass
2422 # in locals that may contain a parent/rebuild namespace:
2423 return_type = _decorators.get_callable_return_type( 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
2424 serializer.func, localns=self._types_namespace.locals
2425 )
2426 except NameError as e:
2427 raise PydanticUndefinedAnnotation.from_name_error(e) from e
2429 if return_type is PydanticUndefined: 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
2430 return_schema = None 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
2431 else:
2432 return_schema = self.generate_schema(return_type) 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
2434 if serializer.info.mode == 'wrap': 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
2435 ser_schema: core_schema.SerSchema = core_schema.wrap_serializer_function_ser_schema( 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
2436 serializer.func,
2437 info_arg=info_arg,
2438 return_schema=return_schema,
2439 when_used=serializer.info.when_used,
2440 )
2441 else:
2442 # plain
2443 ser_schema = core_schema.plain_serializer_function_ser_schema( 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
2444 serializer.func,
2445 info_arg=info_arg,
2446 return_schema=return_schema,
2447 when_used=serializer.info.when_used,
2448 )
2449 schema['serialization'] = ser_schema 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
2450 if ref: 2450 ↛ 2452line 2450 didn't jump to line 2452 because the condition on line 2450 was always true1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
2451 schema['ref'] = ref # type: ignore 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
2452 return schema 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
2455_VALIDATOR_F_MATCH: Mapping[ 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
2456 tuple[FieldValidatorModes, Literal['no-info', 'with-info']],
2457 Callable[[Callable[..., Any], core_schema.CoreSchema, str | None], core_schema.CoreSchema],
2458] = {
2459 ('before', 'no-info'): lambda f, schema, _: core_schema.no_info_before_validator_function(f, schema),
2460 ('after', 'no-info'): lambda f, schema, _: core_schema.no_info_after_validator_function(f, schema),
2461 ('plain', 'no-info'): lambda f, _1, _2: core_schema.no_info_plain_validator_function(f),
2462 ('wrap', 'no-info'): lambda f, schema, _: core_schema.no_info_wrap_validator_function(f, schema),
2463 ('before', 'with-info'): lambda f, schema, field_name: core_schema.with_info_before_validator_function(
2464 f, schema, field_name=field_name
2465 ),
2466 ('after', 'with-info'): lambda f, schema, field_name: core_schema.with_info_after_validator_function(
2467 f, schema, field_name=field_name
2468 ),
2469 ('plain', 'with-info'): lambda f, _, field_name: core_schema.with_info_plain_validator_function(
2470 f, field_name=field_name
2471 ),
2472 ('wrap', 'with-info'): lambda f, schema, field_name: core_schema.with_info_wrap_validator_function(
2473 f, schema, field_name=field_name
2474 ),
2475}
2478# TODO V3: this function is only used for deprecated decorators. It should
2479# be removed once we drop support for those.
2480def apply_validators( 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
2481 schema: core_schema.CoreSchema,
2482 validators: Iterable[Decorator[RootValidatorDecoratorInfo]]
2483 | Iterable[Decorator[ValidatorDecoratorInfo]]
2484 | Iterable[Decorator[FieldValidatorDecoratorInfo]],
2485 field_name: str | None,
2486) -> core_schema.CoreSchema:
2487 """Apply validators to a schema.
2489 Args:
2490 schema: The schema to apply validators on.
2491 validators: An iterable of validators.
2492 field_name: The name of the field if validators are being applied to a model field.
2494 Returns:
2495 The updated schema.
2496 """
2497 for validator in validators: 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
2498 info_arg = inspect_validator(validator.func, validator.info.mode) 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
2499 val_type = 'with-info' if info_arg else 'no-info' 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
2501 schema = _VALIDATOR_F_MATCH[(validator.info.mode, val_type)](validator.func, schema, field_name) 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
2502 return schema 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
2505def _validators_require_validate_default(validators: Iterable[Decorator[ValidatorDecoratorInfo]]) -> bool: 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
2506 """In v1, if any of the validators for a field had `always=True`, the default value would be validated.
2508 This serves as an auxiliary function for re-implementing that logic, by looping over a provided
2509 collection of (v1-style) ValidatorDecoratorInfo's and checking if any of them have `always=True`.
2511 We should be able to drop this function and the associated logic calling it once we drop support
2512 for v1-style validator decorators. (Or we can extend it and keep it if we add something equivalent
2513 to the v1-validator `always` kwarg to `field_validator`.)
2514 """
2515 for validator in validators: 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
2516 if validator.info.always: 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
2517 return True 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
2518 return False 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
2521def apply_model_validators( 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
2522 schema: core_schema.CoreSchema,
2523 validators: Iterable[Decorator[ModelValidatorDecoratorInfo]],
2524 mode: Literal['inner', 'outer', 'all'],
2525) -> core_schema.CoreSchema:
2526 """Apply model validators to a schema.
2528 If mode == 'inner', only "before" validators are applied
2529 If mode == 'outer', validators other than "before" are applied
2530 If mode == 'all', all validators are applied
2532 Args:
2533 schema: The schema to apply validators on.
2534 validators: An iterable of validators.
2535 mode: The validator mode.
2537 Returns:
2538 The updated schema.
2539 """
2540 ref: str | None = schema.pop('ref', None) # type: ignore 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
2541 for validator in validators: 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
2542 if mode == 'inner' and validator.info.mode != 'before': 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
2543 continue 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
2544 if mode == 'outer' and validator.info.mode == 'before': 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
2545 continue 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
2546 info_arg = inspect_validator(validator.func, validator.info.mode) 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
2547 if validator.info.mode == 'wrap': 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
2548 if info_arg: 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
2549 schema = core_schema.with_info_wrap_validator_function(function=validator.func, schema=schema) 1uwxCDyzEFGvABHI
2550 else:
2551 schema = core_schema.no_info_wrap_validator_function(function=validator.func, schema=schema) 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
2552 elif validator.info.mode == 'before': 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
2553 if info_arg: 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
2554 schema = core_schema.with_info_before_validator_function(function=validator.func, schema=schema) 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
2555 else:
2556 schema = core_schema.no_info_before_validator_function(function=validator.func, schema=schema) 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
2557 else:
2558 assert validator.info.mode == 'after' 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
2559 if info_arg: 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
2560 schema = core_schema.with_info_after_validator_function(function=validator.func, schema=schema) 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
2561 else:
2562 schema = core_schema.no_info_after_validator_function(function=validator.func, schema=schema) 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
2563 if ref: 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
2564 schema['ref'] = ref # type: ignore 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
2565 return schema 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
2568def wrap_default(field_info: FieldInfo, schema: core_schema.CoreSchema) -> core_schema.CoreSchema: 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
2569 """Wrap schema with default schema if default value or `default_factory` are available.
2571 Args:
2572 field_info: The field info object.
2573 schema: The schema to apply default on.
2575 Returns:
2576 Updated schema by default value or `default_factory`.
2577 """
2578 if field_info.default_factory: 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
2579 return core_schema.with_default_schema( 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
2580 schema,
2581 default_factory=field_info.default_factory,
2582 default_factory_takes_data=takes_validated_data_argument(field_info.default_factory),
2583 validate_default=field_info.validate_default,
2584 )
2585 elif field_info.default is not PydanticUndefined: 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
2586 return core_schema.with_default_schema( 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
2587 schema, default=field_info.default, validate_default=field_info.validate_default
2588 )
2589 else:
2590 return schema 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
2593def _extract_get_pydantic_json_schema(tp: Any) -> GetJsonSchemaFunction | None: 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
2594 """Extract `__get_pydantic_json_schema__` from a type, handling the deprecated `__modify_schema__`."""
2595 js_modify_function = getattr(tp, '__get_pydantic_json_schema__', None) 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
2597 if hasattr(tp, '__modify_schema__'): 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
2598 BaseModel = import_cached_base_model() 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
2600 has_custom_v2_modify_js_func = ( 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
2601 js_modify_function is not None
2602 and BaseModel.__get_pydantic_json_schema__.__func__ # type: ignore
2603 not in (js_modify_function, getattr(js_modify_function, '__func__', None))
2604 )
2606 if not has_custom_v2_modify_js_func: 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
2607 cls_name = getattr(tp, '__name__', None) 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
2608 raise PydanticUserError( 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
2609 f'The `__modify_schema__` method is not supported in Pydantic v2. '
2610 f'Use `__get_pydantic_json_schema__` instead{f" in class `{cls_name}`" if cls_name else ""}.',
2611 code='custom-json-schema',
2612 )
2614 if (origin := get_origin(tp)) is not None: 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
2615 # Generic aliases proxy attribute access to the origin, *except* dunder attributes,
2616 # such as `__get_pydantic_json_schema__`, hence the explicit check.
2617 return _extract_get_pydantic_json_schema(origin) 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
2619 if js_modify_function is None: 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
2620 return None 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
2622 return js_modify_function 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
2625class _CommonField(TypedDict): 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
2626 schema: core_schema.CoreSchema 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
2627 validation_alias: str | list[str | int] | list[list[str | int]] | None 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
2628 serialization_alias: str | None 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
2629 serialization_exclude: bool | None 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
2630 frozen: bool | None 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
2631 metadata: dict[str, Any] 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
2634def _common_field( 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
2635 schema: core_schema.CoreSchema,
2636 *,
2637 validation_alias: str | list[str | int] | list[list[str | int]] | None = None,
2638 serialization_alias: str | None = None,
2639 serialization_exclude: bool | None = None,
2640 frozen: bool | None = None,
2641 metadata: Any = None,
2642) -> _CommonField:
2643 return { 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
2644 'schema': schema,
2645 'validation_alias': validation_alias,
2646 'serialization_alias': serialization_alias,
2647 'serialization_exclude': serialization_exclude,
2648 'frozen': frozen,
2649 'metadata': metadata,
2650 }
2653def resolve_original_schema(schema: CoreSchema, definitions: _Definitions) -> CoreSchema | None: 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
2654 if schema['type'] == 'definition-ref': 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
2655 return definitions.get_schema_from_ref(schema['schema_ref']) 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
2656 elif schema['type'] == 'definitions': 2656 ↛ 2657line 2656 didn't jump to line 2657 because the condition on line 2656 was never true1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
2657 return schema['schema']
2658 else:
2659 return schema 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
2662def _inlining_behavior( 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
2663 def_ref: core_schema.DefinitionReferenceSchema,
2664) -> Literal['inline', 'keep', 'preserve_metadata']:
2665 """Determine the inlining behavior of the `'definition-ref'` schema.
2667 - If no `'serialization'` schema and no metadata is attached, the schema can safely be inlined.
2668 - If it has metadata but only related to the deferred discriminator application, it can be inlined
2669 provided that such metadata is kept.
2670 - Otherwise, the schema should not be inlined. Doing so would remove the `'serialization'` schema or metadata.
2671 """
2672 if 'serialization' in def_ref: 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
2673 return 'keep' 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
2674 metadata = def_ref.get('metadata') 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
2675 if not metadata: 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
2676 return 'inline' 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
2677 if len(metadata) == 1 and 'pydantic_internal_union_discriminator' in metadata: 2677 ↛ 2678line 2677 didn't jump to line 2678 because the condition on line 2677 was never true1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
2678 return 'preserve_metadata'
2679 return 'keep' 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
2682class _Definitions: 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
2683 """Keeps track of references and definitions."""
2685 _recursively_seen: set[str] 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
2686 """A set of recursively seen references. 1djoquwxCDelmrsyzEFGJKLMNPfnptvABHI
2688 When a referenceable type is encountered, the `get_schema_or_ref` context manager is
2689 entered to compute the reference. If the type references itself by some way (e.g. for
2690 a dataclass a Pydantic model, the class can be referenced as a field annotation),
2691 entering the context manager again will yield a `'definition-ref'` schema that should
2692 short-circuit the normal generation process, as the reference was already in this set.
2693 """
2695 _definitions: dict[str, core_schema.CoreSchema] 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
2696 """A mapping of references to their corresponding schema. 1djoquwxCDelmrsyzEFGJKLMNPfnptvABHI
2698 When a schema for a referenceable type is generated, it is stored in this mapping. If the
2699 same type is encountered again, the reference is yielded by the `get_schema_or_ref` context
2700 manager.
2701 """
2703 def __init__(self) -> None: 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
2704 self._recursively_seen = set() 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
2705 self._definitions = {} 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
2707 @contextmanager 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
2708 def get_schema_or_ref(self, tp: Any, /) -> Generator[tuple[str, core_schema.DefinitionReferenceSchema | None]]: 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
2709 """Get a definition for `tp` if one exists.
2711 If a definition exists, a tuple of `(ref_string, CoreSchema)` is returned.
2712 If no definition exists yet, a tuple of `(ref_string, None)` is returned.
2714 Note that the returned `CoreSchema` will always be a `DefinitionReferenceSchema`,
2715 not the actual definition itself.
2717 This should be called for any type that can be identified by reference.
2718 This includes any recursive types.
2720 At present the following types can be named/recursive:
2722 - Pydantic model
2723 - Pydantic and stdlib dataclasses
2724 - Typed dictionaries
2725 - Named tuples
2726 - `TypeAliasType` instances
2727 - Enums
2728 """
2729 ref = get_type_ref(tp) 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
2730 # return the reference if we're either (1) in a cycle or (2) it the reference was already encountered:
2731 if ref in self._recursively_seen or ref in self._definitions: 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
2732 yield (ref, core_schema.definition_reference_schema(ref)) 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
2733 else:
2734 self._recursively_seen.add(ref) 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
2735 try: 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
2736 yield (ref, None) 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
2737 finally:
2738 self._recursively_seen.discard(ref) 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
2740 def get_schema_from_ref(self, ref: str) -> CoreSchema | None: 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
2741 """Resolve the schema from the given reference."""
2742 return self._definitions.get(ref) 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
2744 def create_definition_reference_schema(self, schema: CoreSchema) -> core_schema.DefinitionReferenceSchema: 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
2745 """Store the schema as a definition and return a `'definition-reference'` schema pointing to it.
2747 The schema must have a reference attached to it.
2748 """
2749 ref = schema['ref'] # pyright: ignore 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
2750 self._definitions[ref] = schema 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
2751 return core_schema.definition_reference_schema(ref) 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
2753 def unpack_definitions(self, schema: core_schema.DefinitionsSchema) -> CoreSchema: 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
2754 """Store the definitions of the `'definitions'` core schema and return the inner core schema."""
2755 for def_schema in schema['definitions']: 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
2756 self._definitions[def_schema['ref']] = def_schema # pyright: ignore 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
2757 return schema['schema'] 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
2759 def finalize_schema(self, schema: CoreSchema) -> CoreSchema: 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
2760 """Finalize the core schema.
2762 This traverses the core schema and referenced definitions, replaces `'definition-ref'` schemas
2763 by the referenced definition if possible, and applies deferred discriminators.
2764 """
2765 definitions = self._definitions 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
2766 try: 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
2767 gather_result = gather_schemas_for_cleaning( 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
2768 schema,
2769 definitions=definitions,
2770 )
2771 except MissingDefinitionError as e: 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
2772 raise InvalidSchemaError from e 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
2774 remaining_defs: dict[str, CoreSchema] = {} 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
2776 # Note: this logic doesn't play well when core schemas with deferred discriminator metadata
2777 # and references are encountered. See the `test_deferred_discriminated_union_and_references()` test.
2778 for ref, inlinable_def_ref in gather_result['collected_references'].items(): 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
2779 if inlinable_def_ref is not None and (inlining_behavior := _inlining_behavior(inlinable_def_ref)) != 'keep': 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
2780 if inlining_behavior == 'inline': 2780 ↛ 2787line 2780 didn't jump to line 2787 because the condition on line 2780 was always true1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
2781 # `ref` was encountered, and only once:
2782 # - `inlinable_def_ref` is a `'definition-ref'` schema and is guaranteed to be
2783 # the only one. Transform it into the definition it points to.
2784 # - Do not store the definition in the `remaining_defs`.
2785 inlinable_def_ref.clear() # pyright: ignore[reportAttributeAccessIssue] 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
2786 inlinable_def_ref.update(self._resolve_definition(ref, definitions)) # pyright: ignore 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
2787 elif inlining_behavior == 'preserve_metadata':
2788 # `ref` was encountered, and only once, but contains discriminator metadata.
2789 # We will do the same thing as if `inlining_behavior` was `'inline'`, but make
2790 # sure to keep the metadata for the deferred discriminator application logic below.
2791 meta = inlinable_def_ref.pop('metadata')
2792 inlinable_def_ref.clear() # pyright: ignore[reportAttributeAccessIssue]
2793 inlinable_def_ref.update(self._resolve_definition(ref, definitions)) # pyright: ignore
2794 inlinable_def_ref['metadata'] = meta
2795 else:
2796 # `ref` was encountered, at least two times (or only once, but with metadata or a serialization schema):
2797 # - Do not inline the `'definition-ref'` schemas (they are not provided in the gather result anyway).
2798 # - Store the the definition in the `remaining_defs`
2799 remaining_defs[ref] = self._resolve_definition(ref, definitions) 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
2801 for cs in gather_result['deferred_discriminator_schemas']: 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
2802 discriminator: str | None = cs['metadata'].pop('pydantic_internal_union_discriminator', None) # pyright: ignore[reportTypedDictNotRequiredAccess] 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
2803 if discriminator is None: 2803 ↛ 2807line 2803 didn't jump to line 2807 because the condition on line 2803 was never true1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
2804 # This can happen in rare scenarios, when a deferred schema is present multiple times in the
2805 # gather result (e.g. when using the `Sequence` type -- see `test_sequence_discriminated_union()`).
2806 # In this case, a previous loop iteration applied the discriminator and so we can just skip it here.
2807 continue
2808 applied = _discriminated_union.apply_discriminator(cs.copy(), discriminator, remaining_defs) 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
2809 # Mutate the schema directly to have the discriminator applied
2810 cs.clear() # pyright: ignore[reportAttributeAccessIssue] 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
2811 cs.update(applied) # pyright: ignore 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
2813 if remaining_defs: 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
2814 schema = core_schema.definitions_schema(schema=schema, definitions=[*remaining_defs.values()]) 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
2815 return schema 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
2817 def _resolve_definition(self, ref: str, definitions: dict[str, CoreSchema]) -> CoreSchema: 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
2818 definition = definitions[ref] 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
2819 if definition['type'] != 'definition-ref': 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
2820 return definition 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
2822 # Some `'definition-ref'` schemas might act as "intermediate" references (e.g. when using
2823 # a PEP 695 type alias (which is referenceable) that references another PEP 695 type alias):
2824 visited: set[str] = set() 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
2825 while definition['type'] == 'definition-ref' and _inlining_behavior(definition) == 'inline': 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
2826 schema_ref = definition['schema_ref'] 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
2827 if schema_ref in visited: 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
2828 raise PydanticUserError( 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
2829 f'{ref} contains a circular reference to itself.', code='circular-reference-schema'
2830 )
2831 visited.add(schema_ref) 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
2832 definition = definitions[schema_ref] 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
2833 return {**definition, 'ref': ref} # pyright: ignore[reportReturnType] 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
2836class _FieldNameStack: 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
2837 __slots__ = ('_stack',) 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
2839 def __init__(self) -> None: 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
2840 self._stack: list[str] = [] 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
2842 @contextmanager 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
2843 def push(self, field_name: str) -> Iterator[None]: 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
2844 self._stack.append(field_name) 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
2845 yield 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
2846 self._stack.pop() 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
2848 def get(self) -> str | None: 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
2849 if self._stack: 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
2850 return self._stack[-1] 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
2851 else:
2852 return None 1adouxcfpvB
2855class _ModelTypeStack: 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
2856 __slots__ = ('_stack',) 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
2858 def __init__(self) -> None: 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
2859 self._stack: list[type] = [] 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
2861 @contextmanager 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
2862 def push(self, type_obj: type) -> Iterator[None]: 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
2863 self._stack.append(type_obj) 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
2864 yield 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
2865 self._stack.pop() 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
2867 def get(self) -> type | None: 1abdjoquwxCDkeghlmrsyzEFGOJKLMNPcifnptvABHI
2868 if self._stack: 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
2869 return self._stack[-1] 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI
2870 else:
2871 return None 1abdjoquwxCDkeghlmrsyzEFGcifnptvABHI