Coverage for pydantic/generics.py: 99.28%
176 statements
« prev ^ index » next coverage.py v7.6.1, created at 2024-08-15 13:26 +0000
« prev ^ index » next coverage.py v7.6.1, created at 2024-08-15 13:26 +0000
1import sys 1IJuvwxabcdefKLyzABghijklMCDmPQRSTUnNOEFGHopqrst
2import types 1IJuvwxabcdefKLyzABghijklMCDmPQRSTUnNOEFGHopqrst
3import typing 1IJuvwxabcdefKLyzABghijklMCDmPQRSTUnNOEFGHopqrst
4from typing import ( 1IJuvwxabcdefKLyzABghijklMCDmPQRSTUnNOEFGHopqrst
5 TYPE_CHECKING,
6 Any,
7 ClassVar,
8 Dict,
9 ForwardRef,
10 Generic,
11 Iterator,
12 List,
13 Mapping,
14 Optional,
15 Tuple,
16 Type,
17 TypeVar,
18 Union,
19 cast,
20)
21from weakref import WeakKeyDictionary, WeakValueDictionary 1IJuvwxabcdefKLyzABghijklMCDmPQRSTUnNOEFGHopqrst
23from typing_extensions import Annotated, Literal as ExtLiteral 1IJuvwxabcdefKLyzABghijklMCDmPQRSTUnNOEFGHopqrst
25from pydantic.class_validators import gather_all_validators 1IJuvwxabcdefKLyzABghijklMCDmPQRSTUnNOEFGHopqrst
26from pydantic.fields import DeferredType 1IJuvwxabcdefKLyzABghijklMCDmPQRSTUnNOEFGHopqrst
27from pydantic.main import BaseModel, create_model 1IJuvwxabcdefKLyzABghijklMCDmPQRSTUnNOEFGHopqrst
28from pydantic.types import JsonWrapper 1IJuvwxabcdefKLyzABghijklMCDmPQRSTUnNOEFGHopqrst
29from pydantic.typing import display_as_type, get_all_type_hints, get_args, get_origin, typing_base 1IJuvwxabcdefKLyzABghijklMCDmPQRSTUnNOEFGHopqrst
30from pydantic.utils import all_identical, lenient_issubclass 1IJuvwxabcdefKLyzABghijklMCDmPQRSTUnNOEFGHopqrst
32if sys.version_info >= (3, 10): 1IJuvwxabcdefKLyzABghijklMCDmPQRSTUnNOEFGHopqrst
33 from typing import _UnionGenericAlias 1abcdefghijklmPQRSTUnopqrst
34if sys.version_info >= (3, 8): 1IJuvwxabcdefKLyzABghijklMCDmPQRSTUnNOEFGHopqrst
35 from typing import Literal 1uvwxabcdefyzABghijklCDmPQRSTUnEFGHopqrst
37GenericModelT = TypeVar('GenericModelT', bound='GenericModel') 1IJuvwxabcdefKLyzABghijklMCDmPQRSTUnNOEFGHopqrst
38TypeVarType = Any # since mypy doesn't allow the use of TypeVar as a type 1IJuvwxabcdefKLyzABghijklMCDmPQRSTUnNOEFGHopqrst
40CacheKey = Tuple[Type[Any], Any, Tuple[Any, ...]] 1IJuvwxabcdefKLyzABghijklMCDmPQRSTUnNOEFGHopqrst
41Parametrization = Mapping[TypeVarType, Type[Any]] 1IJuvwxabcdefKLyzABghijklMCDmPQRSTUnNOEFGHopqrst
43# weak dictionaries allow the dynamically created parametrized versions of generic models to get collected
44# once they are no longer referenced by the caller.
45if sys.version_info >= (3, 9): # Typing for weak dictionaries available at 3.9 1IJuvwxabcdefKLyzABghijklMCDmPQRSTUnNOEFGHopqrst
46 GenericTypesCache = WeakValueDictionary[CacheKey, Type[BaseModel]] 1wxabcdefABghijklDmPQRSTUnGHopqrst
47 AssignedParameters = WeakKeyDictionary[Type[BaseModel], Parametrization] 1wxabcdefABghijklDmPQRSTUnGHopqrst
48else:
49 GenericTypesCache = WeakValueDictionary 1IJuvKLyzMCNOEF
50 AssignedParameters = WeakKeyDictionary 1IJuvKLyzMCNOEF
52# _generic_types_cache is a Mapping from __class_getitem__ arguments to the parametrized version of generic models.
53# This ensures multiple calls of e.g. A[B] return always the same class.
54_generic_types_cache = GenericTypesCache() 1IJuvwxabcdefKLyzABghijklMCDmPQRSTUnNOEFGHopqrst
56# _assigned_parameters is a Mapping from parametrized version of generic models to assigned types of parametrizations
57# as captured during construction of the class (not instances).
58# E.g., for generic model `Model[A, B]`, when parametrized model `Model[int, str]` is created,
59# `Model[int, str]`: {A: int, B: str}` will be stored in `_assigned_parameters`.
60# (This information is only otherwise available after creation from the class name string).
61_assigned_parameters = AssignedParameters() 1IJuvwxabcdefKLyzABghijklMCDmPQRSTUnNOEFGHopqrst
64class GenericModel(BaseModel): 1IJuvwxabcdefKLyzABghijklMCDmPQRSTUnNOEFGHopqrst
65 __slots__ = () 1IJuvwxabcdefKLyzABghijklMCDmPQRSTUnNOEFGHopqrst
66 __concrete__: ClassVar[bool] = False 1IJuvwxabcdefKLyzABghijklMCDmPQRSTUnNOEFGHopqrst
68 if TYPE_CHECKING: 1IJuvwxabcdefKLyzABghijklMCDmPQRSTUnNOEFGHopqrst
69 # Putting this in a TYPE_CHECKING block allows us to replace `if Generic not in cls.__bases__` with
70 # `not hasattr(cls, "__parameters__")`. This means we don't need to force non-concrete subclasses of
71 # `GenericModel` to also inherit from `Generic`, which would require changes to the use of `create_model` below.
72 __parameters__: ClassVar[Tuple[TypeVarType, ...]]
74 # Setting the return type as Type[Any] instead of Type[BaseModel] prevents PyCharm warnings
75 def __class_getitem__(cls: Type[GenericModelT], params: Union[Type[Any], Tuple[Type[Any], ...]]) -> Type[Any]: 1IJuvwxabcdefKLyzABghijklMCDmPQRSTUnNOEFGHopqrst
76 """Instantiates a new class from a generic class `cls` and type variables `params`.
78 :param params: Tuple of types the class . Given a generic class
79 `Model` with 2 type variables and a concrete model `Model[str, int]`,
80 the value `(str, int)` would be passed to `params`.
81 :return: New model class inheriting from `cls` with instantiated
82 types described by `params`. If no parameters are given, `cls` is
83 returned as is.
85 """
87 def _cache_key(_params: Any) -> CacheKey: 1IJuvwxabcdefKLyzABghijklMCDmPQRSTUnNOEFGHopqrst
88 args = get_args(_params) 1IJuvwxabcdefKLyzABghijklMCDmPQRSTUnNOEFGHopqrst
89 # python returns a list for Callables, which is not hashable
90 if len(args) == 2 and isinstance(args[0], list): 1IJuvwxabcdefKLyzABghijklMCDmPQRSTUnNOEFGHopqrst
91 args = (tuple(args[0]), args[1]) 1IJuvwxabcdefKLyzABghijklMCDmnNOEFGHopqrst
92 return cls, _params, args 1IJuvwxabcdefKLyzABghijklMCDmPQRSTUnNOEFGHopqrst
94 cached = _generic_types_cache.get(_cache_key(params)) 1IJuvwxabcdefKLyzABghijklMCDmPQRSTUnNOEFGHopqrst
95 if cached is not None: 1IJuvwxabcdefKLyzABghijklMCDmPQRSTUnNOEFGHopqrst
96 return cached 1IJuvwxabcdefKLyzABghijklMCDmnNOEFGHopqrst
97 if cls.__concrete__ and Generic not in cls.__bases__: 1IJuvwxabcdefKLyzABghijklMCDmPQRSTUnNOEFGHopqrst
98 raise TypeError('Cannot parameterize a concrete instantiation of a generic model') 1IJuvwxabcdefKLyzABghijklMCDmnNOEFGHopqrst
99 if not isinstance(params, tuple): 1IJuvwxabcdefKLyzABghijklMCDmPQRSTUnNOEFGHopqrst
100 params = (params,) 1IJuvwxabcdefKLyzABghijklMCDmPQRSTUnNOEFGHopqrst
101 if cls is GenericModel and any(isinstance(param, TypeVar) for param in params): 1IJuvwxabcdefKLyzABghijklMCDmPQRSTUnNOEFGHopqrst
102 raise TypeError('Type parameters should be placed on typing.Generic, not GenericModel') 1IJuvwxabcdefKLyzABghijklMCDmnNOEFGHopqrst
103 if not hasattr(cls, '__parameters__'): 1IJuvwxabcdefKLyzABghijklMCDmPQRSTUnNOEFGHopqrst
104 raise TypeError(f'Type {cls.__name__} must inherit from typing.Generic before being parameterized') 1IJuvwxabcdefKLyzABghijklMCDmnNOEFGHopqrst
106 check_parameters_count(cls, params) 1IJuvwxabcdefKLyzABghijklMCDmPQRSTUnNOEFGHopqrst
107 # Build map from generic typevars to passed params
108 typevars_map: Dict[TypeVarType, Type[Any]] = dict(zip(cls.__parameters__, params)) 1IJuvwxabcdefKLyzABghijklMCDmPQRSTUnNOEFGHopqrst
109 if all_identical(typevars_map.keys(), typevars_map.values()) and typevars_map: 1IJuvwxabcdefKLyzABghijklMCDmPQRSTUnNOEFGHopqrst
110 return cls # if arguments are equal to parameters it's the same object 1IJuvwxabcdefKLyzABghijklMCDmnNOEFGHopqrst
112 # Create new model with original model as parent inserting fields with DeferredType.
113 model_name = cls.__concrete_name__(params) 1IJuvwxabcdefKLyzABghijklMCDmPQRSTUnNOEFGHopqrst
114 validators = gather_all_validators(cls) 1IJuvwxabcdefKLyzABghijklMCDmPQRSTUnNOEFGHopqrst
116 type_hints = get_all_type_hints(cls).items() 1IJuvwxabcdefKLyzABghijklMCDmPQRSTUnNOEFGHopqrst
117 instance_type_hints = {k: v for k, v in type_hints if get_origin(v) is not ClassVar} 1IJuvwxabcdefKLyzABghijklMCDmPQRSTUnNOEFGHopqrst
119 fields = {k: (DeferredType(), cls.__fields__[k].field_info) for k in instance_type_hints if k in cls.__fields__} 1IJuvwxabcdefKLyzABghijklMCDmPQRSTUnNOEFGHopqrst
121 model_module, called_globally = get_caller_frame_info() 1IJuvwxabcdefKLyzABghijklMCDmPQRSTUnNOEFGHopqrst
122 created_model = cast( 1IJuvwxabcdefKLyzABghijklMCDmPQRSTUnNOEFGHopqrst
123 Type[GenericModel], # casting ensures mypy is aware of the __concrete__ and __parameters__ attributes
124 create_model(
125 model_name,
126 __module__=model_module or cls.__module__,
127 __base__=(cls,) + tuple(cls.__parameterized_bases__(typevars_map)),
128 __config__=None,
129 __validators__=validators,
130 __cls_kwargs__=None,
131 **fields,
132 ),
133 )
135 _assigned_parameters[created_model] = typevars_map 1IJuvwxabcdefKLyzABghijklMCDmPQRSTUnNOEFGHopqrst
137 if called_globally: # create global reference and therefore allow pickling 1IJuvwxabcdefKLyzABghijklMCDmPQRSTUnNOEFGHopqrst
138 object_by_reference = None 1IJuvwxabcdefKLyzABghijklMCDmPQRSTUnNOEFGHopqrst
139 reference_name = model_name 1IJuvwxabcdefKLyzABghijklMCDmPQRSTUnNOEFGHopqrst
140 reference_module_globals = sys.modules[created_model.__module__].__dict__ 1IJuvwxabcdefKLyzABghijklMCDmPQRSTUnNOEFGHopqrst
141 while object_by_reference is not created_model: 1IJuvwxabcdefKLyzABghijklMCDmPQRSTUnNOEFGHopqrst
142 object_by_reference = reference_module_globals.setdefault(reference_name, created_model) 1IJuvwxabcdefKLyzABghijklMCDmPQRSTUnNOEFGHopqrst
143 reference_name += '_' 1IJuvwxabcdefKLyzABghijklMCDmPQRSTUnNOEFGHopqrst
145 created_model.Config = cls.Config 1IJuvwxabcdefKLyzABghijklMCDmPQRSTUnNOEFGHopqrst
147 # Find any typevars that are still present in the model.
148 # If none are left, the model is fully "concrete", otherwise the new
149 # class is a generic class as well taking the found typevars as
150 # parameters.
151 new_params = tuple( 1IJuvwxabcdefKLyzABghijklMCDmPQRSTUnNOEFGHopqrst
152 {param: None for param in iter_contained_typevars(typevars_map.values())}
153 ) # use dict as ordered set
154 created_model.__concrete__ = not new_params 1IJuvwxabcdefKLyzABghijklMCDmPQRSTUnNOEFGHopqrst
155 if new_params: 1IJuvwxabcdefKLyzABghijklMCDmPQRSTUnNOEFGHopqrst
156 created_model.__parameters__ = new_params 1IJuvwxabcdefKLyzABghijklMCDmnNOEFGHopqrst
158 # Save created model in cache so we don't end up creating duplicate
159 # models that should be identical.
160 _generic_types_cache[_cache_key(params)] = created_model 1IJuvwxabcdefKLyzABghijklMCDmPQRSTUnNOEFGHopqrst
161 if len(params) == 1: 1IJuvwxabcdefKLyzABghijklMCDmPQRSTUnNOEFGHopqrst
162 _generic_types_cache[_cache_key(params[0])] = created_model 1IJuvwxabcdefKLyzABghijklMCDmPQRSTUnNOEFGHopqrst
164 # Recursively walk class type hints and replace generic typevars
165 # with concrete types that were passed.
166 _prepare_model_fields(created_model, fields, instance_type_hints, typevars_map) 1IJuvwxabcdefKLyzABghijklMCDmPQRSTUnNOEFGHopqrst
168 return created_model 1IJuvwxabcdefKLyzABghijklMCDmPQRSTUnNOEFGHopqrst
170 @classmethod 1IJuvwxabcdefKLyzABghijklMCDmPQRSTUnNOEFGHopqrst
171 def __concrete_name__(cls: Type[Any], params: Tuple[Type[Any], ...]) -> str: 1IJuvwxabcdefKLyzABghijklMCDmPQRSTUnNOEFGHopqrst
172 """Compute class name for child classes.
174 :param params: Tuple of types the class . Given a generic class
175 `Model` with 2 type variables and a concrete model `Model[str, int]`,
176 the value `(str, int)` would be passed to `params`.
177 :return: String representing a the new class where `params` are
178 passed to `cls` as type variables.
180 This method can be overridden to achieve a custom naming scheme for GenericModels.
181 """
182 param_names = [display_as_type(param) for param in params] 1IJuvwxabcdefKLyzABghijklMCDmPQRSTUnNOEFGHopqrst
183 params_component = ', '.join(param_names) 1IJuvwxabcdefKLyzABghijklMCDmPQRSTUnNOEFGHopqrst
184 return f'{cls.__name__}[{params_component}]' 1IJuvwxabcdefKLyzABghijklMCDmPQRSTUnNOEFGHopqrst
186 @classmethod 1IJuvwxabcdefKLyzABghijklMCDmPQRSTUnNOEFGHopqrst
187 def __parameterized_bases__(cls, typevars_map: Parametrization) -> Iterator[Type[Any]]: 1IJuvwxabcdefKLyzABghijklMCDmPQRSTUnNOEFGHopqrst
188 """
189 Returns unbound bases of cls parameterised to given type variables
191 :param typevars_map: Dictionary of type applications for binding subclasses.
192 Given a generic class `Model` with 2 type variables [S, T]
193 and a concrete model `Model[str, int]`,
194 the value `{S: str, T: int}` would be passed to `typevars_map`.
195 :return: an iterator of generic sub classes, parameterised by `typevars_map`
196 and other assigned parameters of `cls`
198 e.g.:
199 ```
200 class A(GenericModel, Generic[T]):
201 ...
203 class B(A[V], Generic[V]):
204 ...
206 assert A[int] in B.__parameterized_bases__({V: int})
207 ```
208 """
210 def build_base_model( 1uvwxabcdefyzABghijklCDmPQRSTUnEFGHopqrst
211 base_model: Type[GenericModel], mapped_types: Parametrization
212 ) -> Iterator[Type[GenericModel]]:
213 base_parameters = tuple(mapped_types[param] for param in base_model.__parameters__) 1IJuvwxabcdefKLyzABghijklMCDmnNOEFGHopqrst
214 parameterized_base = base_model.__class_getitem__(base_parameters) 1IJuvwxabcdefKLyzABghijklMCDmnNOEFGHopqrst
215 if parameterized_base is base_model or parameterized_base is cls: 1IJuvwxabcdefKLyzABghijklMCDmnNOEFGHopqrst
216 # Avoid duplication in MRO
217 return 1IJuvwxabcdefKLyzABghijklMCDmnNOEFGHopqrst
218 yield parameterized_base 1IJuvwxabcdefKLyzABghijklMCDmnNOEFGHopqrst
220 for base_model in cls.__bases__: 1IJuvwxabcdefKLyzABghijklMCDmPQRSTUnNOEFGHopqrst
221 if not issubclass(base_model, GenericModel): 1IJuvwxabcdefKLyzABghijklMCDmPQRSTUnNOEFGHopqrst
222 # not a class that can be meaningfully parameterized
223 continue 1IJuvwxabcdefKLyzABghijklMCDmPQRSTUnNOEFGHopqrst
224 elif not getattr(base_model, '__parameters__', None): 1IJuvwxabcdefKLyzABghijklMCDmPQRSTUnNOEFGHopqrst
225 # base_model is "GenericModel" (and has no __parameters__)
226 # or
227 # base_model is already concrete, and will be included transitively via cls.
228 continue 1IJuvwxabcdefKLyzABghijklMCDmPQRSTUnNOEFGHopqrst
229 elif cls in _assigned_parameters: 1IJuvwxabcdefKLyzABghijklMCDmnNOEFGHopqrst
230 if base_model in _assigned_parameters: 1IJuvwxabcdefKLyzABghijklMCDmnNOEFGHopqrst
231 # cls is partially parameterised but not from base_model
232 # e.g. cls = B[S], base_model = A[S]
233 # B[S][int] should subclass A[int], (and will be transitively via B[int])
234 # but it's not viable to consistently subclass types with arbitrary construction
235 # So don't attempt to include A[S][int]
236 continue 1IJuvwxabcdefKLyzABghijklMCDmnNOEFGHopqrst
237 else: # base_model not in _assigned_parameters:
238 # cls is partially parameterized, base_model is original generic
239 # e.g. cls = B[str, T], base_model = B[S, T]
240 # Need to determine the mapping for the base_model parameters
241 mapped_types: Parametrization = { 1IJuvwxabcdefKLyzABghijklMCDmnNOEFGHopqrst
242 key: typevars_map.get(value, value) for key, value in _assigned_parameters[cls].items()
243 }
244 yield from build_base_model(base_model, mapped_types) 1IJuvwxabcdefKLyzABghijklMCDmnNOEFGHopqrst
245 else:
246 # cls is base generic, so base_class has a distinct base
247 # can construct the Parameterised base model using typevars_map directly
248 yield from build_base_model(base_model, typevars_map) 1IJuvwxabcdefKLyzABghijklMCDmnNOEFGHopqrst
251def replace_types(type_: Any, type_map: Mapping[Any, Any]) -> Any: 1IJuvwxabcdefKLyzABghijklMCDmPQRSTUnNOEFGHopqrst
252 """Return type with all occurrences of `type_map` keys recursively replaced with their values.
254 :param type_: Any type, class or generic alias
255 :param type_map: Mapping from `TypeVar` instance to concrete types.
256 :return: New type representing the basic structure of `type_` with all
257 `typevar_map` keys recursively replaced.
259 >>> replace_types(Tuple[str, Union[List[str], float]], {str: int})
260 Tuple[int, Union[List[int], float]]
262 """
263 if not type_map: 1IJuvwxabcdefKLyzABghijklMCDmPQRSTUnNOEFGHopqrst
264 return type_ 1IJuvwxabcdefKLyzABghijklMCDmnNOEFGHopqrst
266 type_args = get_args(type_) 1IJuvwxabcdefKLyzABghijklMCDmPQRSTUnNOEFGHopqrst
267 origin_type = get_origin(type_) 1IJuvwxabcdefKLyzABghijklMCDmPQRSTUnNOEFGHopqrst
269 if origin_type is Annotated: 1IJuvwxabcdefKLyzABghijklMCDmPQRSTUnNOEFGHopqrst
270 annotated_type, *annotations = type_args 1IJuvwxabcdefKLyzABghijklMCDmnNOEFGHopqrst
271 return Annotated[replace_types(annotated_type, type_map), tuple(annotations)] 1IJuvwxabcdefKLyzABghijklMCDmnNOEFGHopqrst
273 if (origin_type is ExtLiteral) or (sys.version_info >= (3, 8) and origin_type is Literal): 1IJuvwxabcdefKLyzABghijklMCDmPQRSTUnNOEFGHopqrst
274 return type_map.get(type_, type_) 1IJuvwxabcdefKLyzABghijklMCDmnNOEFGHopqrst
275 # Having type args is a good indicator that this is a typing module
276 # class instantiation or a generic alias of some sort.
277 if type_args: 1IJuvwxabcdefKLyzABghijklMCDmPQRSTUnNOEFGHopqrst
278 resolved_type_args = tuple(replace_types(arg, type_map) for arg in type_args) 1IJuvwxabcdefKLyzABghijklMCDmPQRSTUnNOEFGHopqrst
279 if all_identical(type_args, resolved_type_args): 1IJuvwxabcdefKLyzABghijklMCDmPQRSTUnNOEFGHopqrst
280 # If all arguments are the same, there is no need to modify the
281 # type or create a new object at all
282 return type_ 1IJuvwxabcdefKLyzABghijklMCDmPQRSTUnNOEFGHopqrst
283 if ( 1uvwxyzABCDEFGH
284 origin_type is not None
285 and isinstance(type_, typing_base)
286 and not isinstance(origin_type, typing_base)
287 and getattr(type_, '_name', None) is not None
288 ):
289 # In python < 3.9 generic aliases don't exist so any of these like `list`,
290 # `type` or `collections.abc.Callable` need to be translated.
291 # See: https://www.python.org/dev/peps/pep-0585
292 origin_type = getattr(typing, type_._name) 1IJuvwxabcdefKLyzABghijklMCDmnNOEFGHopqrst
293 assert origin_type is not None 1IJuvwxabcdefKLyzABghijklMCDmnNOEFGHopqrst
294 # PEP-604 syntax (Ex.: list | str) is represented with a types.UnionType object that does not have __getitem__.
295 # We also cannot use isinstance() since we have to compare types.
296 if sys.version_info >= (3, 10) and origin_type is types.UnionType: # noqa: E721 1IJuvwxabcdefKLyzABghijklMCDmnNOEFGHopqrst
297 return _UnionGenericAlias(origin_type, resolved_type_args) 1abcdefghijklmnopqrst
298 return origin_type[resolved_type_args] 1IJuvwxabcdefKLyzABghijklMCDmnNOEFGHopqrst
300 # We handle pydantic generic models separately as they don't have the same
301 # semantics as "typing" classes or generic aliases
302 if not origin_type and lenient_issubclass(type_, GenericModel) and not type_.__concrete__: 1IJuvwxabcdefKLyzABghijklMCDmPQRSTUnNOEFGHopqrst
303 type_args = type_.__parameters__ 1IJuvwxabcdefKLyzABghijklMCDmnNOEFGHopqrst
304 resolved_type_args = tuple(replace_types(t, type_map) for t in type_args) 1IJuvwxabcdefKLyzABghijklMCDmnNOEFGHopqrst
305 if all_identical(type_args, resolved_type_args): 1IJuvwxabcdefKLyzABghijklMCDmnNOEFGHopqrst
306 return type_ 1IJuvwxabcdefKLyzABghijklMCDmnNOEFGHopqrst
307 return type_[resolved_type_args] 1IJuvwxabcdefKLyzABghijklMCDmnNOEFGHopqrst
309 # Handle special case for typehints that can have lists as arguments.
310 # `typing.Callable[[int, str], int]` is an example for this.
311 if isinstance(type_, (List, list)): 1IJuvwxabcdefKLyzABghijklMCDmPQRSTUnNOEFGHopqrst
312 resolved_list = list(replace_types(element, type_map) for element in type_) 1IJuvwxabcdefKLyzABghijklMCDmnNOEFGHopqrst
313 if all_identical(type_, resolved_list): 1IJuvwxabcdefKLyzABghijklMCDmnNOEFGHopqrst
314 return type_ 1IJuvwxabcdefKLyzABghijklMCDmnNOEFGHopqrst
315 return resolved_list 1IJuvwxabcdefKLyzABghijklMCDmnNOEFGHopqrst
317 # For JsonWrapperValue, need to handle its inner type to allow correct parsing
318 # of generic Json arguments like Json[T]
319 if not origin_type and lenient_issubclass(type_, JsonWrapper): 1IJuvwxabcdefKLyzABghijklMCDmPQRSTUnNOEFGHopqrst
320 type_.inner_type = replace_types(type_.inner_type, type_map) 1IJuvwxabcdefKLyzABghijklMCDmnNOEFGHopqrst
321 return type_ 1IJuvwxabcdefKLyzABghijklMCDmnNOEFGHopqrst
323 # If all else fails, we try to resolve the type directly and otherwise just
324 # return the input with no modifications.
325 new_type = type_map.get(type_, type_) 1IJuvwxabcdefKLyzABghijklMCDmPQRSTUnNOEFGHopqrst
326 # Convert string to ForwardRef
327 if isinstance(new_type, str): 327 ↛ 328line 327 didn't jump to line 328 because the condition on line 327 was never true1IJuvwxabcdefKLyzABghijklMCDmPQRSTUnNOEFGHopqrst
328 return ForwardRef(new_type)
329 else:
330 return new_type 1IJuvwxabcdefKLyzABghijklMCDmPQRSTUnNOEFGHopqrst
333def check_parameters_count(cls: Type[GenericModel], parameters: Tuple[Any, ...]) -> None: 1IJuvwxabcdefKLyzABghijklMCDmPQRSTUnNOEFGHopqrst
334 actual = len(parameters) 1IJuvwxabcdefKLyzABghijklMCDmPQRSTUnNOEFGHopqrst
335 expected = len(cls.__parameters__) 1IJuvwxabcdefKLyzABghijklMCDmPQRSTUnNOEFGHopqrst
336 if actual != expected: 1IJuvwxabcdefKLyzABghijklMCDmPQRSTUnNOEFGHopqrst
337 description = 'many' if actual > expected else 'few' 1IJuvwxabcdefKLyzABghijklMCDmnNOEFGHopqrst
338 raise TypeError(f'Too {description} parameters for {cls.__name__}; actual {actual}, expected {expected}') 1IJuvwxabcdefKLyzABghijklMCDmnNOEFGHopqrst
341DictValues: Type[Any] = {}.values().__class__ 1IJuvwxabcdefKLyzABghijklMCDmPQRSTUnNOEFGHopqrst
344def iter_contained_typevars(v: Any) -> Iterator[TypeVarType]: 1IJuvwxabcdefKLyzABghijklMCDmPQRSTUnNOEFGHopqrst
345 """Recursively iterate through all subtypes and type args of `v` and yield any typevars that are found."""
346 if isinstance(v, TypeVar): 1IJuvwxabcdefKLyzABghijklMCDmPQRSTUnNOEFGHopqrst
347 yield v 1IJuvwxabcdefKLyzABghijklMCDmnNOEFGHopqrst
348 elif hasattr(v, '__parameters__') and not get_origin(v) and lenient_issubclass(v, GenericModel): 1IJuvwxabcdefKLyzABghijklMCDmPQRSTUnNOEFGHopqrst
349 yield from v.__parameters__ 1IJuvwxabcdefKLyzABghijklMCDmnNOEFGHopqrst
350 elif isinstance(v, (DictValues, list)): 1IJuvwxabcdefKLyzABghijklMCDmPQRSTUnNOEFGHopqrst
351 for var in v: 1IJuvwxabcdefKLyzABghijklMCDmPQRSTUnNOEFGHopqrst
352 yield from iter_contained_typevars(var) 1IJuvwxabcdefKLyzABghijklMCDmPQRSTUnNOEFGHopqrst
353 else:
354 args = get_args(v) 1IJuvwxabcdefKLyzABghijklMCDmPQRSTUnNOEFGHopqrst
355 for arg in args: 1IJuvwxabcdefKLyzABghijklMCDmPQRSTUnNOEFGHopqrst
356 yield from iter_contained_typevars(arg) 1IJuvwxabcdefKLyzABghijklMCDmnNOEFGHopqrst
359def get_caller_frame_info() -> Tuple[Optional[str], bool]: 1IJuvwxabcdefKLyzABghijklMCDmPQRSTUnNOEFGHopqrst
360 """
361 Used inside a function to check whether it was called globally
363 Will only work against non-compiled code, therefore used only in pydantic.generics
365 :returns Tuple[module_name, called_globally]
366 """
367 try: 1IJuvwxabcdefKLyzABghijklMCDmPQRSTUnNOEFGHopqrst
368 previous_caller_frame = sys._getframe(2) 1IJuvwxabcdefKLyzABghijklMCDmPQRSTUnNOEFGHopqrst
369 except ValueError as e: 1IJuvwxabcdefKLyzABghijklMCDmnNOEFGHopqrst
370 raise RuntimeError('This function must be used inside another function') from e 1IJuvwxabcdefKLyzABghijklMCDmnNOEFGHopqrst
371 except AttributeError: # sys module does not have _getframe function, so there's nothing we can do about it 1IJuvwxabcdefKLyzABghijklMCDmnNOEFGHopqrst
372 return None, False 1IJuvwxabcdefKLyzABghijklMCDmnNOEFGHopqrst
373 frame_globals = previous_caller_frame.f_globals 1IJuvwxabcdefKLyzABghijklMCDmPQRSTUnNOEFGHopqrst
374 return frame_globals.get('__name__'), previous_caller_frame.f_locals is frame_globals 1IJuvwxabcdefKLyzABghijklMCDmPQRSTUnNOEFGHopqrst
377def _prepare_model_fields( 1uvwxabcdefyzABghijklCDmPQRSTUnEFGHopqrst
378 created_model: Type[GenericModel],
379 fields: Mapping[str, Any],
380 instance_type_hints: Mapping[str, type],
381 typevars_map: Mapping[Any, type],
382) -> None:
383 """
384 Replace DeferredType fields with concrete type hints and prepare them.
385 """
387 for key, field in created_model.__fields__.items(): 1IJuvwxabcdefKLyzABghijklMCDmPQRSTUnNOEFGHopqrst
388 if key not in fields: 1IJuvwxabcdefKLyzABghijklMCDmPQRSTUnNOEFGHopqrst
389 assert field.type_.__class__ is not DeferredType 1IJuvwxabcdefKLyzABghijklMCDmnNOEFGHopqrst
390 # https://github.com/nedbat/coveragepy/issues/198
391 continue # pragma: no cover 1abcdefghijklmnopqrst
393 assert field.type_.__class__ is DeferredType, field.type_.__class__ 1IJuvwxabcdefKLyzABghijklMCDmPQRSTUnNOEFGHopqrst
395 field_type_hint = instance_type_hints[key] 1IJuvwxabcdefKLyzABghijklMCDmPQRSTUnNOEFGHopqrst
396 concrete_type = replace_types(field_type_hint, typevars_map) 1IJuvwxabcdefKLyzABghijklMCDmPQRSTUnNOEFGHopqrst
397 field.type_ = concrete_type 1IJuvwxabcdefKLyzABghijklMCDmPQRSTUnNOEFGHopqrst
398 field.outer_type_ = concrete_type 1IJuvwxabcdefKLyzABghijklMCDmPQRSTUnNOEFGHopqrst
399 field.prepare() 1IJuvwxabcdefKLyzABghijklMCDmPQRSTUnNOEFGHopqrst
400 created_model.__annotations__[key] = concrete_type 1IJuvwxabcdefKLyzABghijklMCDmPQRSTUnNOEFGHopqrst