cadwyn 5.4.6__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,338 @@
1
+ from collections.abc import Callable
2
+ from dataclasses import dataclass
3
+ from typing import TYPE_CHECKING, Any, Literal, Union, cast
4
+
5
+ from pydantic import AliasChoices, AliasPath, BaseModel, Field
6
+ from pydantic._internal._decorators import PydanticDescriptorProxy, unwrap_wrapped_function
7
+ from pydantic.fields import FieldInfo
8
+
9
+ from cadwyn._utils import (
10
+ DATACLASS_SLOTS,
11
+ Sentinel,
12
+ fully_unwrap_decorator,
13
+ get_name_of_function_wrapped_in_pydantic_validator,
14
+ lenient_issubclass,
15
+ )
16
+ from cadwyn.exceptions import CadwynStructureError
17
+
18
+ from .common import _HiddenAttributeMixin
19
+
20
+ if TYPE_CHECKING:
21
+ from pydantic.typing import AbstractSetIntStr, MappingIntStrAny
22
+
23
+
24
+ PossibleFieldAttributes = Literal[
25
+ "default",
26
+ "alias",
27
+ "alias_priority",
28
+ "default_factory",
29
+ "validation_alias",
30
+ "serialization_alias",
31
+ "title",
32
+ "field_title_generator",
33
+ "description",
34
+ "examples",
35
+ "exclude",
36
+ "const",
37
+ "deprecated",
38
+ "frozen",
39
+ "validate_default",
40
+ "repr",
41
+ "init",
42
+ "init_var",
43
+ "kw_only",
44
+ "fail_fast",
45
+ "gt",
46
+ "ge",
47
+ "lt",
48
+ "le",
49
+ "strict",
50
+ "coerce_numbers_to_str",
51
+ "multiple_of",
52
+ "allow_inf_nan",
53
+ "max_digits",
54
+ "decimal_places",
55
+ "min_length",
56
+ "max_length",
57
+ "union_mode",
58
+ "allow_mutation",
59
+ "pattern",
60
+ "discriminator",
61
+ ]
62
+
63
+
64
+ # TODO: Add json_schema_extra as a breaking change in a major version
65
+ @dataclass(**DATACLASS_SLOTS)
66
+ class FieldChanges:
67
+ default: Any
68
+ alias: Union[str, None]
69
+ default_factory: Any
70
+ alias_priority: Union[int, None]
71
+ validation_alias: Union[str, AliasPath, AliasChoices, None]
72
+ serialization_alias: Union[str, None]
73
+ title: Union[str, None]
74
+ field_title_generator: Union[Callable[[str, FieldInfo], str], None]
75
+ description: str
76
+ examples: Union[list[Any], None]
77
+ exclude: "AbstractSetIntStr | MappingIntStrAny | Any"
78
+ const: bool
79
+ deprecated: bool
80
+ frozen: Union[bool, None]
81
+ validate_default: Union[bool, None]
82
+ repr: bool
83
+ init: Union[bool, None]
84
+ init_var: Union[bool, None]
85
+ kw_only: Union[bool, None]
86
+ fail_fast: bool
87
+ gt: float
88
+ ge: float
89
+ lt: float
90
+ le: float
91
+ strict: bool
92
+ coerce_numbers_to_str: Union[bool, None]
93
+ multiple_of: float
94
+ allow_inf_nan: bool
95
+ max_digits: int
96
+ decimal_places: int
97
+ min_length: int
98
+ max_length: int
99
+ union_mode: Literal["smart", "left_to_right"]
100
+ allow_mutation: bool
101
+ pattern: str
102
+ discriminator: str
103
+
104
+
105
+ @dataclass(**DATACLASS_SLOTS)
106
+ class FieldHadInstruction(_HiddenAttributeMixin):
107
+ schema: type[BaseModel]
108
+ name: str
109
+ type: type
110
+ field_changes: FieldChanges
111
+ new_name: str
112
+
113
+
114
+ @dataclass(**DATACLASS_SLOTS)
115
+ class FieldDidntHaveInstruction(_HiddenAttributeMixin):
116
+ schema: type[BaseModel]
117
+ name: str
118
+ attributes: tuple[str, ...]
119
+
120
+
121
+ @dataclass(**DATACLASS_SLOTS)
122
+ class FieldDidntExistInstruction(_HiddenAttributeMixin):
123
+ schema: type[BaseModel]
124
+ name: str
125
+
126
+
127
+ @dataclass(**DATACLASS_SLOTS)
128
+ class FieldExistedAsInstruction(_HiddenAttributeMixin):
129
+ schema: type[BaseModel]
130
+ name: str
131
+ field: FieldInfo
132
+
133
+
134
+ # TODO (https://github.com/zmievsa/cadwyn/issues/112): Add an ability to add extras
135
+ @dataclass(**DATACLASS_SLOTS)
136
+ class AlterFieldInstructionFactory:
137
+ schema: type[BaseModel]
138
+ name: str
139
+
140
+ def had(
141
+ self,
142
+ *,
143
+ name: str = Sentinel,
144
+ type: Any = Sentinel,
145
+ default: Any = Sentinel,
146
+ alias: Union[str, None] = Sentinel,
147
+ default_factory: Callable = Sentinel,
148
+ alias_priority: Union[int, None] = Sentinel,
149
+ validation_alias: Union[str, AliasPath, AliasChoices, None] = Sentinel,
150
+ serialization_alias: Union[str, None] = Sentinel,
151
+ title: Union[str, None] = Sentinel,
152
+ field_title_generator: Union[Callable[[str, FieldInfo], str], None] = Sentinel,
153
+ description: str = Sentinel,
154
+ examples: Union[list[Any], None] = Sentinel,
155
+ exclude: "AbstractSetIntStr | MappingIntStrAny | Any" = Sentinel,
156
+ const: bool = Sentinel,
157
+ deprecated: bool = Sentinel,
158
+ frozen: Union[bool, None] = Sentinel,
159
+ validate_default: Union[bool, None] = Sentinel,
160
+ repr: bool = Sentinel,
161
+ init: bool = Sentinel,
162
+ init_var: bool = Sentinel,
163
+ kw_only: bool = Sentinel,
164
+ fail_fast: bool = Sentinel,
165
+ gt: float = Sentinel,
166
+ ge: float = Sentinel,
167
+ lt: float = Sentinel,
168
+ le: float = Sentinel,
169
+ strict: bool = Sentinel,
170
+ coerce_numbers_to_str: bool = Sentinel,
171
+ multiple_of: float = Sentinel,
172
+ allow_inf_nan: bool = Sentinel,
173
+ max_digits: int = Sentinel,
174
+ decimal_places: int = Sentinel,
175
+ min_length: int = Sentinel,
176
+ max_length: int = Sentinel,
177
+ union_mode: Literal["smart", "left_to_right"] = Sentinel,
178
+ allow_mutation: bool = Sentinel,
179
+ pattern: str = Sentinel,
180
+ discriminator: str = Sentinel,
181
+ ) -> FieldHadInstruction:
182
+ return FieldHadInstruction(
183
+ is_hidden_from_changelog=False,
184
+ schema=self.schema,
185
+ name=self.name,
186
+ type=type,
187
+ new_name=name,
188
+ field_changes=FieldChanges(
189
+ default=default,
190
+ default_factory=default_factory,
191
+ alias_priority=alias_priority,
192
+ alias=alias,
193
+ validation_alias=validation_alias,
194
+ serialization_alias=serialization_alias,
195
+ title=title,
196
+ field_title_generator=field_title_generator,
197
+ description=description,
198
+ examples=examples,
199
+ exclude=exclude,
200
+ const=const,
201
+ deprecated=deprecated,
202
+ frozen=frozen,
203
+ validate_default=validate_default,
204
+ repr=repr,
205
+ init=init,
206
+ init_var=init_var,
207
+ kw_only=kw_only,
208
+ fail_fast=fail_fast,
209
+ gt=gt,
210
+ ge=ge,
211
+ lt=lt,
212
+ le=le,
213
+ strict=strict,
214
+ coerce_numbers_to_str=coerce_numbers_to_str,
215
+ multiple_of=multiple_of,
216
+ allow_inf_nan=allow_inf_nan,
217
+ max_digits=max_digits,
218
+ decimal_places=decimal_places,
219
+ min_length=min_length,
220
+ max_length=max_length,
221
+ union_mode=union_mode,
222
+ allow_mutation=allow_mutation,
223
+ pattern=pattern,
224
+ discriminator=discriminator,
225
+ ),
226
+ )
227
+
228
+ def didnt_have(self, *attributes: PossibleFieldAttributes) -> FieldDidntHaveInstruction:
229
+ for attribute in attributes:
230
+ if attribute not in FieldChanges.__dataclass_fields__:
231
+ raise CadwynStructureError(
232
+ f"Unknown attribute {attribute!r}. Are you sure it's a valid field attribute?"
233
+ )
234
+ return FieldDidntHaveInstruction(
235
+ is_hidden_from_changelog=False, schema=self.schema, name=self.name, attributes=attributes
236
+ )
237
+
238
+ @property
239
+ def didnt_exist(self) -> FieldDidntExistInstruction:
240
+ return FieldDidntExistInstruction(is_hidden_from_changelog=False, schema=self.schema, name=self.name)
241
+
242
+ def existed_as(
243
+ self,
244
+ *,
245
+ type: Any,
246
+ info: Union[FieldInfo, Any, None] = None,
247
+ ) -> FieldExistedAsInstruction:
248
+ if info is None:
249
+ info = cast("FieldInfo", Field())
250
+ info.annotation = type
251
+ return FieldExistedAsInstruction(is_hidden_from_changelog=False, schema=self.schema, name=self.name, field=info)
252
+
253
+
254
+ def _get_model_decorators(model: type[BaseModel]):
255
+ return [
256
+ *model.__pydantic_decorators__.validators.values(),
257
+ *model.__pydantic_decorators__.field_validators.values(),
258
+ *model.__pydantic_decorators__.root_validators.values(),
259
+ *model.__pydantic_decorators__.field_serializers.values(),
260
+ *model.__pydantic_decorators__.model_serializers.values(),
261
+ *model.__pydantic_decorators__.model_validators.values(),
262
+ *model.__pydantic_decorators__.computed_fields.values(),
263
+ ]
264
+
265
+
266
+ @dataclass(**DATACLASS_SLOTS)
267
+ class ValidatorExistedInstruction:
268
+ schema: type[BaseModel]
269
+ validator: Union[Callable[..., Any], PydanticDescriptorProxy]
270
+
271
+
272
+ @dataclass(**DATACLASS_SLOTS)
273
+ class ValidatorDidntExistInstruction:
274
+ schema: type[BaseModel]
275
+ name: str
276
+
277
+
278
+ @dataclass(**DATACLASS_SLOTS)
279
+ class AlterValidatorInstructionFactory:
280
+ schema: type[BaseModel]
281
+ func: Union[Callable[..., Any], PydanticDescriptorProxy]
282
+
283
+ @property
284
+ def existed(self) -> ValidatorExistedInstruction:
285
+ return ValidatorExistedInstruction(self.schema, self.func)
286
+
287
+ @property
288
+ def didnt_exist(self) -> ValidatorDidntExistInstruction:
289
+ return ValidatorDidntExistInstruction(
290
+ self.schema, get_name_of_function_wrapped_in_pydantic_validator(self.func)
291
+ )
292
+
293
+
294
+ AlterSchemaSubInstruction = Union[
295
+ FieldHadInstruction,
296
+ FieldDidntHaveInstruction,
297
+ FieldDidntExistInstruction,
298
+ FieldExistedAsInstruction,
299
+ ValidatorExistedInstruction,
300
+ ValidatorDidntExistInstruction,
301
+ ]
302
+
303
+
304
+ @dataclass(**DATACLASS_SLOTS)
305
+ class SchemaHadInstruction(_HiddenAttributeMixin):
306
+ schema: type[BaseModel]
307
+ name: str
308
+
309
+
310
+ @dataclass(**DATACLASS_SLOTS)
311
+ class AlterSchemaInstructionFactory:
312
+ schema: type[BaseModel]
313
+
314
+ def field(self, name: str, /) -> AlterFieldInstructionFactory:
315
+ return AlterFieldInstructionFactory(self.schema, name)
316
+
317
+ def validator(
318
+ self, func: "Union[Callable[..., Any], classmethod[Any, Any, Any], PydanticDescriptorProxy]", /
319
+ ) -> AlterValidatorInstructionFactory:
320
+ func = cast("Union[Callable[..., Any], PydanticDescriptorProxy]", unwrap_wrapped_function(func))
321
+
322
+ if not isinstance(func, PydanticDescriptorProxy):
323
+ if hasattr(func, "__self__"):
324
+ owner = func.__self__
325
+ if lenient_issubclass(owner, BaseModel) and any( # pragma: no branch
326
+ fully_unwrap_decorator(decorator.func, decorator.shim) == func
327
+ for decorator in _get_model_decorators(owner)
328
+ ):
329
+ return AlterValidatorInstructionFactory(self.schema, func)
330
+ raise CadwynStructureError("The passed function must be a pydantic validator")
331
+ return AlterValidatorInstructionFactory(self.schema, func)
332
+
333
+ def had(self, *, name: str) -> SchemaHadInstruction:
334
+ return SchemaHadInstruction(is_hidden_from_changelog=False, schema=self.schema, name=name)
335
+
336
+
337
+ def schema(model: type[BaseModel], /) -> AlterSchemaInstructionFactory:
338
+ return AlterSchemaInstructionFactory(model)