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