Coverage for pydantic/_internal/_mock_val_ser.py: 84.48%
82 statements
« prev ^ index » next coverage.py v7.5.4, created at 2024-07-03 19:29 +0000
« prev ^ index » next coverage.py v7.5.4, created at 2024-07-03 19:29 +0000
1from __future__ import annotations 1abcdefghijklKLmnopqrstuvwxMNOPQRSTUVyzABCDEFGHIJ
3from typing import TYPE_CHECKING, Any, Callable, Generic, Iterator, Mapping, TypeVar 1abcdefghijklKLmnopqrstuvwxMNOPQRSTUVyzABCDEFGHIJ
5from pydantic_core import CoreSchema, SchemaSerializer, SchemaValidator 1abcdefghijklKLmnopqrstuvwxMNOPQRSTUVyzABCDEFGHIJ
6from typing_extensions import Literal 1abcdefghijklKLmnopqrstuvwxMNOPQRSTUVyzABCDEFGHIJ
8from ..errors import PydanticErrorCodes, PydanticUserError 1abcdefghijklKLmnopqrstuvwxMNOPQRSTUVyzABCDEFGHIJ
10if TYPE_CHECKING: 1abcdefghijklKLmnopqrstuvwxMNOPQRSTUVyzABCDEFGHIJ
11 from ..dataclasses import PydanticDataclass
12 from ..main import BaseModel
15ValSer = TypeVar('ValSer', SchemaValidator, SchemaSerializer) 1abcdefghijklKLmnopqrstuvwxMNOPQRSTUVyzABCDEFGHIJ
16T = TypeVar('T') 1abcdefghijklKLmnopqrstuvwxMNOPQRSTUVyzABCDEFGHIJ
19class MockCoreSchema(Mapping[str, Any]): 1abcdefghijklKLmnopqrstuvwxMNOPQRSTUVyzABCDEFGHIJ
20 """Mocker for `pydantic_core.CoreSchema` which optionally attempts to
21 rebuild the thing it's mocking when one of its methods is accessed and raises an error if that fails.
22 """
24 __slots__ = '_error_message', '_code', '_attempt_rebuild', '_built_memo' 1abcdefghijklKLmnopqrstuvwxMNOPQRSTUVyzABCDEFGHIJ
26 def __init__( 1abcdefghijklKLmnopqrstuvwxMNOPQRSTUVyzABCDEFGHIJ
27 self,
28 error_message: str,
29 *,
30 code: PydanticErrorCodes,
31 attempt_rebuild: Callable[[], CoreSchema | None] | None = None,
32 ) -> None:
33 self._error_message = error_message 1abcdefghijklKLmnopqrstuvwxMNOPQRSTUVyzABCDEFGHIJ
34 self._code: PydanticErrorCodes = code 1abcdefghijklKLmnopqrstuvwxMNOPQRSTUVyzABCDEFGHIJ
35 self._attempt_rebuild = attempt_rebuild 1abcdefghijklKLmnopqrstuvwxMNOPQRSTUVyzABCDEFGHIJ
36 self._built_memo: CoreSchema | None = None 1abcdefghijklKLmnopqrstuvwxMNOPQRSTUVyzABCDEFGHIJ
38 def __getitem__(self, key: str) -> Any: 1abcdefghijklKLmnopqrstuvwxMNOPQRSTUVyzABCDEFGHIJ
39 return self._get_built().__getitem__(key) 1abcdefghijklKLmnopqrstuvwxyzABCDEFGHIJ
41 def __len__(self) -> int: 1abcdefghijklKLmnopqrstuvwxMNOPQRSTUVyzABCDEFGHIJ
42 return self._get_built().__len__()
44 def __iter__(self) -> Iterator[str]: 1abcdefghijklKLmnopqrstuvwxMNOPQRSTUVyzABCDEFGHIJ
45 return self._get_built().__iter__()
47 def _get_built(self) -> CoreSchema: 1abcdefghijklKLmnopqrstuvwxMNOPQRSTUVyzABCDEFGHIJ
48 if self._built_memo is not None: 48 ↛ 49line 48 didn't jump to line 49 because the condition on line 48 was never true1abcdefghijklKLmnopqrstuvwxyzABCDEFGHIJ
49 return self._built_memo
51 if self._attempt_rebuild: 51 ↛ 56line 51 didn't jump to line 56 because the condition on line 51 was always true1abcdefghijklKLmnopqrstuvwxyzABCDEFGHIJ
52 schema = self._attempt_rebuild() 1abcdefghijklKLmnopqrstuvwxyzABCDEFGHIJ
53 if schema is not None: 1abcdefghijklKLmnopqrstuvwxyzABCDEFGHIJ
54 self._built_memo = schema 1abcdefghijklKLmnopqrstuvwxyzABCDEFGHIJ
55 return schema 1abcdefghijklKLmnopqrstuvwxyzABCDEFGHIJ
56 raise PydanticUserError(self._error_message, code=self._code) 1abcdefghijklKLmnopqrstuvwxyzABCDEFGHIJ
58 def rebuild(self) -> CoreSchema | None: 1abcdefghijklKLmnopqrstuvwxMNOPQRSTUVyzABCDEFGHIJ
59 self._built_memo = None 1abcdefghijklKLmnopqrstuvwxyzABCDEFGHIJ
60 if self._attempt_rebuild: 60 ↛ 66line 60 didn't jump to line 66 because the condition on line 60 was always true1abcdefghijklKLmnopqrstuvwxyzABCDEFGHIJ
61 val_ser = self._attempt_rebuild() 1abcdefghijklKLmnopqrstuvwxyzABCDEFGHIJ
62 if val_ser is not None: 1abcdefghijklKLmnopqrstuvwxyzABCDEFGHIJ
63 return val_ser 1abcdefghijklKLmnopqrstuvwxyzABCDEFGHIJ
64 else:
65 raise PydanticUserError(self._error_message, code=self._code) 1abcdefghijklKLmnopqrstuvwxyzABCDEFGHIJ
66 return None
69class MockValSer(Generic[ValSer]): 1abcdefghijklKLmnopqrstuvwxMNOPQRSTUVyzABCDEFGHIJ
70 """Mocker for `pydantic_core.SchemaValidator` or `pydantic_core.SchemaSerializer` which optionally attempts to
71 rebuild the thing it's mocking when one of its methods is accessed and raises an error if that fails.
72 """
74 __slots__ = '_error_message', '_code', '_val_or_ser', '_attempt_rebuild' 1abcdefghijklKLmnopqrstuvwxMNOPQRSTUVyzABCDEFGHIJ
76 def __init__( 1abcdefghijklKLmnopqrstuvwxMNOPQRSTUVyzABCDEFGHIJ
77 self,
78 error_message: str,
79 *,
80 code: PydanticErrorCodes,
81 val_or_ser: Literal['validator', 'serializer'],
82 attempt_rebuild: Callable[[], ValSer | None] | None = None,
83 ) -> None:
84 self._error_message = error_message 1abcdefghijklKLmnopqrstuvwxMNOPQRSTUVyzABCDEFGHIJ
85 self._val_or_ser = SchemaValidator if val_or_ser == 'validator' else SchemaSerializer 1abcdefghijklKLmnopqrstuvwxMNOPQRSTUVyzABCDEFGHIJ
86 self._code: PydanticErrorCodes = code 1abcdefghijklKLmnopqrstuvwxMNOPQRSTUVyzABCDEFGHIJ
87 self._attempt_rebuild = attempt_rebuild 1abcdefghijklKLmnopqrstuvwxMNOPQRSTUVyzABCDEFGHIJ
89 def __getattr__(self, item: str) -> None: 1abcdefghijklKLmnopqrstuvwxMNOPQRSTUVyzABCDEFGHIJ
90 __tracebackhide__ = True 1abcdefghijklKLmnopqrstuvwxMNOPQRSTUVyzABCDEFGHIJ
91 if self._attempt_rebuild: 1abcdefghijklKLmnopqrstuvwxMNOPQRSTUVyzABCDEFGHIJ
92 val_ser = self._attempt_rebuild() 1abcdefghijklKLmnopqrstuvwxyzABCDEFGHIJ
93 if val_ser is not None: 1abcdefghijklKLmnopqrstuvwxyzABCDEFGHIJ
94 return getattr(val_ser, item) 1abcdefghijklKLmnopqrstuvwxyzABCDEFGHIJ
96 # raise an AttributeError if `item` doesn't exist
97 getattr(self._val_or_ser, item) 1abcdefghijklKLmnopqrstuvwxMNOPQRSTUVyzABCDEFGHIJ
98 raise PydanticUserError(self._error_message, code=self._code) 1abcdefghijklKLmnopqrstuvwxyzABCDEFGHIJ
100 def rebuild(self) -> ValSer | None: 1abcdefghijklKLmnopqrstuvwxMNOPQRSTUVyzABCDEFGHIJ
101 if self._attempt_rebuild:
102 val_ser = self._attempt_rebuild()
103 if val_ser is not None:
104 return val_ser
105 else:
106 raise PydanticUserError(self._error_message, code=self._code)
107 return None
110def set_model_mocks(cls: type[BaseModel], cls_name: str, undefined_name: str = 'all referenced types') -> None: 1abcdefghijklKLmnopqrstuvwxMNOPQRSTUVyzABCDEFGHIJ
111 """Set `__pydantic_validator__` and `__pydantic_serializer__` to `MockValSer`s on a model.
113 Args:
114 cls: The model class to set the mocks on
115 cls_name: Name of the model class, used in error messages
116 undefined_name: Name of the undefined thing, used in error messages
117 """
118 undefined_type_error_message = ( 1abcdefghijklKLmnopqrstuvwxMNOPQRSTUVyzABCDEFGHIJ
119 f'`{cls_name}` is not fully defined; you should define {undefined_name},'
120 f' then call `{cls_name}.model_rebuild()`.'
121 )
123 def attempt_rebuild_fn(attr_fn: Callable[[type[BaseModel]], T]) -> Callable[[], T | None]: 1abcdefghijklKLmnopqrstuvwxMNOPQRSTUVyzABCDEFGHIJ
124 def handler() -> T | None: 1abcdefghijklKLmnopqrstuvwxMNOPQRSTUVyzABCDEFGHIJ
125 if cls.model_rebuild(raise_errors=False, _parent_namespace_depth=5) is not False: 1abcdefghijklKLmnopqrstuvwxyzABCDEFGHIJ
126 return attr_fn(cls) 1abcdefghijklKLmnopqrstuvwxyzABCDEFGHIJ
127 else:
128 return None 1abcdefghijklKLmnopqrstuvwxyzABCDEFGHIJ
130 return handler 1abcdefghijklKLmnopqrstuvwxMNOPQRSTUVyzABCDEFGHIJ
132 cls.__pydantic_core_schema__ = MockCoreSchema( # type: ignore[assignment] 1abcdefghijklKLmnopqrstuvwxMNOPQRSTUVyzABCDEFGHIJ
133 undefined_type_error_message,
134 code='class-not-fully-defined',
135 attempt_rebuild=attempt_rebuild_fn(lambda c: c.__pydantic_core_schema__),
136 )
137 cls.__pydantic_validator__ = MockValSer( # type: ignore[assignment] 1abcdefghijklKLmnopqrstuvwxMNOPQRSTUVyzABCDEFGHIJ
138 undefined_type_error_message,
139 code='class-not-fully-defined',
140 val_or_ser='validator',
141 attempt_rebuild=attempt_rebuild_fn(lambda c: c.__pydantic_validator__),
142 )
143 cls.__pydantic_serializer__ = MockValSer( # type: ignore[assignment] 1abcdefghijklKLmnopqrstuvwxMNOPQRSTUVyzABCDEFGHIJ
144 undefined_type_error_message,
145 code='class-not-fully-defined',
146 val_or_ser='serializer',
147 attempt_rebuild=attempt_rebuild_fn(lambda c: c.__pydantic_serializer__),
148 )
151def set_dataclass_mocks( 1abcdefghijklmnopqrstuvwxMNOPQRSTUVyzABCDEFGHIJ
152 cls: type[PydanticDataclass], cls_name: str, undefined_name: str = 'all referenced types'
153) -> None:
154 """Set `__pydantic_validator__` and `__pydantic_serializer__` to `MockValSer`s on a dataclass.
156 Args:
157 cls: The model class to set the mocks on
158 cls_name: Name of the model class, used in error messages
159 undefined_name: Name of the undefined thing, used in error messages
160 """
161 from ..dataclasses import rebuild_dataclass 1abcdefghijklKLmnopqrstuvwxyzABCDEFGHIJ
163 undefined_type_error_message = ( 1abcdefghijklKLmnopqrstuvwxyzABCDEFGHIJ
164 f'`{cls_name}` is not fully defined; you should define {undefined_name},'
165 f' then call `pydantic.dataclasses.rebuild_dataclass({cls_name})`.'
166 )
168 def attempt_rebuild_fn(attr_fn: Callable[[type[PydanticDataclass]], T]) -> Callable[[], T | None]: 1abcdefghijklKLmnopqrstuvwxyzABCDEFGHIJ
169 def handler() -> T | None: 1abcdefghijklKLmnopqrstuvwxyzABCDEFGHIJ
170 if rebuild_dataclass(cls, raise_errors=False, _parent_namespace_depth=5) is not False: 1abcdefghijklKLmnopqrstuvwxyzABCDEFGHIJ
171 return attr_fn(cls) 1abcdefghijklKLmnopqrstuvwxyzABCDEFGHIJ
172 else:
173 return None 1abcdefghijklKLmnopqrstuvwxyzABCDEFGHIJ
175 return handler 1abcdefghijklKLmnopqrstuvwxyzABCDEFGHIJ
177 cls.__pydantic_core_schema__ = MockCoreSchema( # type: ignore[assignment] 1abcdefghijklKLmnopqrstuvwxyzABCDEFGHIJ
178 undefined_type_error_message,
179 code='class-not-fully-defined',
180 attempt_rebuild=attempt_rebuild_fn(lambda c: c.__pydantic_core_schema__),
181 )
182 cls.__pydantic_validator__ = MockValSer( # type: ignore[assignment] 1abcdefghijklKLmnopqrstuvwxyzABCDEFGHIJ
183 undefined_type_error_message,
184 code='class-not-fully-defined',
185 val_or_ser='validator',
186 attempt_rebuild=attempt_rebuild_fn(lambda c: c.__pydantic_validator__),
187 )
188 cls.__pydantic_serializer__ = MockValSer( # type: ignore[assignment] 188 ↛ exitline 188 didn't jump to the function exit1abcdefghijklKLmnopqrstuvwxyzABCDEFGHIJ
189 undefined_type_error_message,
190 code='class-not-fully-defined',
191 val_or_ser='validator',
192 attempt_rebuild=attempt_rebuild_fn(lambda c: c.__pydantic_serializer__),
193 )