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