arpakitlib 1.8.200__py3-none-any.whl → 1.8.202__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,45 @@
1
+ from typing import Any, Type
2
+
3
+ from pydantic import BaseModel, create_model
4
+ from pydantic_core import PydanticUndefined
5
+
6
+
7
+ def clone_pydantic_model_fields(
8
+ *,
9
+ model_cls: Type[BaseModel],
10
+ fields_to_remove: set[str] | None = None,
11
+ new_class_name: str | None = None,
12
+ ) -> Type[BaseModel]:
13
+ if fields_to_remove is None:
14
+ fields_to_remove = set()
15
+ if new_class_name is None:
16
+ new_class_name = f"{model_cls.__name__}Cloned"
17
+
18
+ field_defs: dict[str, tuple[type[Any], Any]] = {}
19
+
20
+ for field_name, field_ in model_cls.model_fields.items():
21
+ if field_name in fields_to_remove:
22
+ continue
23
+
24
+ if field_.default_factory is not None and field_.default is PydanticUndefined:
25
+ default = field_
26
+ elif field_.default is not PydanticUndefined:
27
+ default = field_.default
28
+ else:
29
+ default = field_
30
+
31
+ field_defs[field_name] = ((field_.annotation or Any), default)
32
+
33
+ return create_model(
34
+ new_class_name,
35
+ __base__=BaseModel,
36
+ **field_defs,
37
+ )
38
+
39
+
40
+ def __example():
41
+ pass
42
+
43
+
44
+ if __name__ == '__main__':
45
+ __example()
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: arpakitlib
3
- Version: 1.8.200
3
+ Version: 1.8.202
4
4
  Summary: arpakitlib
5
5
  License: Apache-2.0
6
6
  Keywords: arpakitlib,arpakit,arpakit-company,arpakitcompany,arpakit_company
@@ -413,9 +413,9 @@ arpakitlib/ar_sqlalchemy_util.py,sha256=hiDh1GrFHmnqa6lJPMq4fb9m3_fs-eDKuRQzbFxI
413
413
  arpakitlib/ar_str_util.py,sha256=2lGpnXDf2h1cBZpVf5i1tX_HCv5iBd6IGnrCw4QWWlY,4350
414
414
  arpakitlib/ar_type_util.py,sha256=Cs_tef-Fc5xeyAF54KgISCsP11NHyzIsglm4S3Xx7iM,4049
415
415
  arpakitlib/ar_yookassa_api_client_util.py,sha256=VozuZeCJjmLd1zj2BdC9WfiAQ3XYOrIMsdpNK-AUlm0,5347
416
- arpakitlib/prune_model.py,sha256=GOW6BJGd40hQo8CxaQD0PDs8-nb67aDDEufDT_4BwX4,2745
417
- arpakitlib-1.8.200.dist-info/LICENSE,sha256=GPEDQMam2r7FSTYqM1mm7aKnxLaWcBotH7UvQtea-ec,11355
418
- arpakitlib-1.8.200.dist-info/METADATA,sha256=fcrNNEp3lekRKpBaKMDbcr_cokkXZYviLtaWpf74u6A,3741
419
- arpakitlib-1.8.200.dist-info/WHEEL,sha256=b4K_helf-jlQoXBBETfwnf4B04YC67LOev0jo4fX5m8,88
420
- arpakitlib-1.8.200.dist-info/entry_points.txt,sha256=36xqR3PJFT2kuwjkM_EqoIy0qFUDPKSm_mJaI7emewE,87
421
- arpakitlib-1.8.200.dist-info/RECORD,,
416
+ arpakitlib/clone_pydantic_model_fields.py,sha256=k3IrYAI-lEHVSHYJHmKWiz8FNVMGS5vwmStitCGHG4E,1152
417
+ arpakitlib-1.8.202.dist-info/LICENSE,sha256=GPEDQMam2r7FSTYqM1mm7aKnxLaWcBotH7UvQtea-ec,11355
418
+ arpakitlib-1.8.202.dist-info/METADATA,sha256=65x0MDlwddjab8wNPxBRB9_0nEGiWMI2KLVQ-j4pB3s,3741
419
+ arpakitlib-1.8.202.dist-info/WHEEL,sha256=b4K_helf-jlQoXBBETfwnf4B04YC67LOev0jo4fX5m8,88
420
+ arpakitlib-1.8.202.dist-info/entry_points.txt,sha256=36xqR3PJFT2kuwjkM_EqoIy0qFUDPKSm_mJaI7emewE,87
421
+ arpakitlib-1.8.202.dist-info/RECORD,,
arpakitlib/prune_model.py DELETED
@@ -1,79 +0,0 @@
1
- import copy
2
- from typing import Type
3
-
4
- from pydantic import BaseModel
5
- from pydantic.fields import FieldInfo, Field
6
-
7
-
8
- def prune_model(
9
- *,
10
- model_cls: Type[BaseModel],
11
- fields_to_remove: set[str],
12
- new_class_name: str,
13
- ) -> Type[BaseModel]:
14
- """
15
- Создаёт новый класс-модель (Pydantic v2), который:
16
- - наследуется от тех же баз, что и model_cls (в том же порядке);
17
- - содержит только поля, объявленные В САМОМ model_cls (а не у его баз),
18
- за вычетом fields_to_remove;
19
- - копирует каждое поле целиком через deepcopy(FieldInfo), сохраняя ВСЕ атрибуты
20
- (alias, constraints, repr, json_schema_extra и т.д.).
21
- - НЕ копирует валидаторы, конфиг, docstring и прочее — только поля.
22
-
23
- Наследованные от баз поля сохранятся за счёт наследования. Удалить наследуемое поле
24
- таким способом нельзя — нужно менять базовые классы / MRO.
25
- """
26
- if not (isinstance(model_cls, type) and issubclass(model_cls, BaseModel)):
27
- raise TypeError("model_cls должен быть подклассом pydantic.BaseModel (v2).")
28
-
29
- namespace: dict = {
30
- "__module__": getattr(model_cls, "__module__", "__main__"),
31
- "__annotations__": {},
32
- }
33
-
34
- for name, annotation in dict(getattr(model_cls, "__annotations__", {})).items():
35
- if name in fields_to_remove:
36
- continue
37
-
38
- field_info: FieldInfo | None = getattr(model_cls, "model_fields", {}).get(name)
39
-
40
- if isinstance(field_info, FieldInfo):
41
- namespace["__annotations__"][name] = annotation
42
- namespace[name] = copy.deepcopy(field_info)
43
-
44
- new_model = type(new_class_name, model_cls.__bases__, namespace)
45
-
46
- if not issubclass(new_model, BaseModel):
47
- raise RuntimeError("not issubclass(new_model, BaseModel)")
48
-
49
- return new_model
50
-
51
-
52
- def __example():
53
- from typing import Optional
54
- from pydantic import BaseModel
55
-
56
- class Timestamped(BaseModel):
57
- created_at: int = 1
58
- updated_at: int = 1
59
-
60
- class Names:
61
- arsen = "arse"
62
-
63
- class User(Timestamped):
64
- id: int = Field(default=1)
65
- email: str = "asasf"
66
- password_hash: str = "asasf"
67
- nickname: Optional[str] = None
68
-
69
- PublicUser = prune_model(
70
- model_cls=User,
71
- fields_to_remove={"id"},
72
- new_class_name="PublicUser",
73
- )
74
-
75
- print(PublicUser())
76
-
77
-
78
- if __name__ == '__main__':
79
- __example()