arpakitlib 1.8.258__py3-none-any.whl → 1.8.260__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.
- arpakitlib/_arpakit_project_template_v_5/project/sqlalchemy_db_/sqlalchemy_model/user.py +2 -3
- arpakitlib/ar_pydantic_schema_from_sqlalchemy_model.py +46 -65
- {arpakitlib-1.8.258.dist-info → arpakitlib-1.8.260.dist-info}/METADATA +1 -1
- {arpakitlib-1.8.258.dist-info → arpakitlib-1.8.260.dist-info}/RECORD +7 -7
- {arpakitlib-1.8.258.dist-info → arpakitlib-1.8.260.dist-info}/LICENSE +0 -0
- {arpakitlib-1.8.258.dist-info → arpakitlib-1.8.260.dist-info}/WHEEL +0 -0
- {arpakitlib-1.8.258.dist-info → arpakitlib-1.8.260.dist-info}/entry_points.txt +0 -0
@@ -1,4 +1,3 @@
|
|
1
|
-
from __future__ import annotations
|
2
1
|
|
3
2
|
import datetime as dt
|
4
3
|
from typing import TYPE_CHECKING, Any
|
@@ -92,14 +91,14 @@ class UserDBM(SimpleDBM):
|
|
92
91
|
)
|
93
92
|
|
94
93
|
# many to one
|
95
|
-
user_tokens: Mapped[list[UserTokenDBM]] = relationship(
|
94
|
+
user_tokens: Mapped[list["UserTokenDBM"]] = relationship(
|
96
95
|
"UserTokenDBM",
|
97
96
|
uselist=True,
|
98
97
|
back_populates="user",
|
99
98
|
foreign_keys="UserTokenDBM.user_id",
|
100
99
|
cascade="all, delete-orphan"
|
101
100
|
)
|
102
|
-
verification_codes: Mapped[list[VerificationCodeDBM]] = relationship(
|
101
|
+
verification_codes: Mapped[list["VerificationCodeDBM"]] = relationship(
|
103
102
|
"VerificationCodeDBM",
|
104
103
|
uselist=True,
|
105
104
|
back_populates="user",
|
@@ -1,47 +1,30 @@
|
|
1
1
|
# arpakit
|
2
|
-
import
|
3
|
-
from typing import Any, Optional, get_type_hints, get_origin, Union, Annotated, get_args
|
2
|
+
from typing import Any, get_type_hints, get_origin, Union, Annotated, get_args
|
4
3
|
|
5
|
-
from pydantic import BaseModel,
|
4
|
+
from pydantic import BaseModel, ConfigDict
|
6
5
|
from sqlalchemy import inspect
|
7
|
-
from sqlalchemy.orm import ColumnProperty
|
8
|
-
|
9
|
-
|
10
|
-
String, Text, Unicode, UnicodeText,
|
11
|
-
DateTime, Date, Time,
|
12
|
-
Float, Numeric, DECIMAL, LargeBinary, JSON
|
13
|
-
)
|
6
|
+
from sqlalchemy.orm import ColumnProperty, Mapped
|
7
|
+
|
8
|
+
from project.sqlalchemy_db_.sqlalchemy_model import UserDBM
|
14
9
|
|
15
10
|
_ARPAKIT_LIB_MODULE_VERSION = "3.0"
|
16
11
|
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
Time: dt.time,
|
34
|
-
}
|
35
|
-
|
36
|
-
|
37
|
-
def _python_type_from_col(col) -> type | str:
|
38
|
-
try:
|
39
|
-
return col.type.python_type
|
40
|
-
except Exception:
|
41
|
-
for sa_t, py_t in _SQLA_TYPE_MAP.items():
|
42
|
-
if isinstance(col.type, sa_t):
|
43
|
-
return py_t
|
44
|
-
return Any
|
12
|
+
|
13
|
+
def _define_sqlalchemy_column_mapped_type(type_: Any) -> Any:
|
14
|
+
"""
|
15
|
+
Возвращает тип колонки ИСКЛЮЧИТЕЛЬНО из аннотации поля.
|
16
|
+
Разворачивает оболочки:
|
17
|
+
- Annotated[T, ...] -> T
|
18
|
+
- Mapped[T] -> T
|
19
|
+
Если аннотации нет — возвращает Any.
|
20
|
+
"""
|
21
|
+
|
22
|
+
origin = get_origin(type_)
|
23
|
+
|
24
|
+
if origin is Mapped:
|
25
|
+
return get_args(type_)[0] if get_args(type_) else Any
|
26
|
+
|
27
|
+
return type_
|
45
28
|
|
46
29
|
|
47
30
|
def _get_property_name_to_type_from_model_class(
|
@@ -64,8 +47,9 @@ def _get_property_name_to_type_from_model_class(
|
|
64
47
|
ret_type = hints.get("return", Any)
|
65
48
|
except Exception:
|
66
49
|
if skip_property_if_cannot_define_type:
|
67
|
-
|
68
|
-
|
50
|
+
ret_type = Any
|
51
|
+
else:
|
52
|
+
raise
|
69
53
|
if exclude_property_names:
|
70
54
|
if property_name in exclude_property_names:
|
71
55
|
continue
|
@@ -108,12 +92,22 @@ def _type_matches(*, type_: Any, allowed_types: list[type]) -> bool:
|
|
108
92
|
return False
|
109
93
|
|
110
94
|
|
95
|
+
def _get_sqlalchemy_mapped_types(sqlalchemy_model):
|
96
|
+
result = {}
|
97
|
+
for cls in reversed(sqlalchemy_model.__mro__):
|
98
|
+
annotations = getattr(cls, "__annotations__", {})
|
99
|
+
for field, annotation in annotations.items():
|
100
|
+
if get_origin(annotation) is Mapped:
|
101
|
+
result[field] = annotation
|
102
|
+
return result
|
103
|
+
|
104
|
+
|
111
105
|
def pydantic_schema_from_sqlalchemy_model(
|
112
106
|
sqlalchemy_model: type,
|
113
107
|
*,
|
114
108
|
model_name: str | None = None,
|
115
109
|
base_model: type[BaseModel] = BaseModel,
|
116
|
-
|
110
|
+
include_columns: bool = True,
|
117
111
|
exclude_column_names: list[str] | None = None,
|
118
112
|
include_properties: bool = False,
|
119
113
|
include_property_names: list[str] | None = None,
|
@@ -148,31 +142,15 @@ def pydantic_schema_from_sqlalchemy_model(
|
|
148
142
|
remove_property_prefixes = set(remove_property_prefixes or [])
|
149
143
|
|
150
144
|
# 1) Колонки
|
151
|
-
|
152
|
-
if not isinstance(prop, ColumnProperty):
|
153
|
-
continue
|
154
|
-
if prop.key in exclude_column_names:
|
155
|
-
continue
|
156
|
-
|
157
|
-
column = prop.columns[0]
|
158
|
-
column_type = _python_type_from_col(column)
|
159
|
-
|
160
|
-
# Аннотация типа
|
161
|
-
if column.nullable:
|
162
|
-
annotations[prop.key] = Optional[column_type] # type: ignore[name-defined]
|
163
|
-
else:
|
164
|
-
annotations[prop.key] = column_type
|
165
|
-
|
166
|
-
# Дефолты, если нужно
|
167
|
-
if include_column_defaults:
|
168
|
-
default_value = None
|
169
|
-
if column.default is not None and getattr(column.default, "is_scalar", False):
|
170
|
-
default_value = column.default.arg
|
171
|
-
elif column.server_default is not None and getattr(column.server_default.arg, "text", None):
|
172
|
-
default_value = column.server_default.arg.text
|
145
|
+
if include_columns:
|
173
146
|
|
174
|
-
|
175
|
-
|
147
|
+
for column_attr in mapper.column_attrs:
|
148
|
+
if not isinstance(column_attr, ColumnProperty):
|
149
|
+
continue
|
150
|
+
if column_attr.key in exclude_column_names:
|
151
|
+
continue
|
152
|
+
mapped_type = _get_sqlalchemy_mapped_types(sqlalchemy_model=sqlalchemy_model)[column_attr.key]
|
153
|
+
annotations[column_attr.key] = _define_sqlalchemy_column_mapped_type(type_=mapped_type)
|
176
154
|
|
177
155
|
# 2) Свойства (@property)
|
178
156
|
if include_properties:
|
@@ -260,3 +238,6 @@ def pydantic_schema_from_sqlalchemy_model(
|
|
260
238
|
attrs["model_config"] = ConfigDict(extra="ignore", arbitrary_types_allowed=True, from_attributes=True)
|
261
239
|
|
262
240
|
return type(model_name, (base_model,), attrs)
|
241
|
+
|
242
|
+
|
243
|
+
print(pydantic_schema_from_sqlalchemy_model(sqlalchemy_model=UserDBM))
|
@@ -275,7 +275,7 @@ arpakitlib/_arpakit_project_template_v_5/project/sqlalchemy_db_/sqlalchemy_model
|
|
275
275
|
arpakitlib/_arpakit_project_template_v_5/project/sqlalchemy_db_/sqlalchemy_model/common.py,sha256=NsZbGGJvsn1IgfUQ9J4_6qBQyNBADDmt2Q8waRePD0c,5851
|
276
276
|
arpakitlib/_arpakit_project_template_v_5/project/sqlalchemy_db_/sqlalchemy_model/operation.py,sha256=6mDtD20H0bQEoSwReLPzaqNp6vLHgOQ7D1DD7KC7zIU,7111
|
277
277
|
arpakitlib/_arpakit_project_template_v_5/project/sqlalchemy_db_/sqlalchemy_model/story_log.py,sha256=Xou8XvEGQfLuEHH5RKdq6pXCZWMhmtyshQvvohT-Go8,2507
|
278
|
-
arpakitlib/_arpakit_project_template_v_5/project/sqlalchemy_db_/sqlalchemy_model/user.py,sha256=
|
278
|
+
arpakitlib/_arpakit_project_template_v_5/project/sqlalchemy_db_/sqlalchemy_model/user.py,sha256=rLR4uWTS-tCX2SMVy8YrkMI-01b5kXEhaBHDbrLmmFI,7867
|
279
279
|
arpakitlib/_arpakit_project_template_v_5/project/sqlalchemy_db_/sqlalchemy_model/user_token.py,sha256=Yy4XZLHJqNEt_SlQOcVCDwHqxpuBwtOmyOfGKbYqKeo,1988
|
280
280
|
arpakitlib/_arpakit_project_template_v_5/project/sqlalchemy_db_/sqlalchemy_model/verification_code.py,sha256=xM5e9C8ELI1RJBAaSXZPn9Qpwl4DT2TgRvbYOxsKZsM,3137
|
281
281
|
arpakitlib/_arpakit_project_template_v_5/project/sqlalchemy_db_/util/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
@@ -414,7 +414,7 @@ arpakitlib/ar_need_type_util.py,sha256=XmY1kswz8j9oo5f9CxRu0_zgfvxWrXPYKOj6MM04s
|
|
414
414
|
arpakitlib/ar_openai_api_client_util.py,sha256=dWgsSPXtxNBxS5VRi_NharGQrUXF_YjIfhU3Bj5cW9M,5651
|
415
415
|
arpakitlib/ar_parse_command.py,sha256=1WTdQoWVshoDZ1jDaKeTzajfqaYHP3FNO0-REyo1aMY,3003
|
416
416
|
arpakitlib/ar_postgresql_util.py,sha256=1AuLjEaa1Lg4pzn-ukCVnDi35Eg1k91APRTqZhIJAdo,945
|
417
|
-
arpakitlib/ar_pydantic_schema_from_sqlalchemy_model.py,sha256=
|
417
|
+
arpakitlib/ar_pydantic_schema_from_sqlalchemy_model.py,sha256=0OXyyN0f08N5k5SwZOhqZnRnkU38ReCBDIDd3qDarlY,10403
|
418
418
|
arpakitlib/ar_raise_own_exception_if_exception.py,sha256=A6TuNSBk1pHaQ_qxnUmE2LgsNGA1IGqX26b1_HEA4Nc,5978
|
419
419
|
arpakitlib/ar_rat_func_util.py,sha256=Ca10o3RJwyx_DJLxjTxgHDO6NU3M6CWgUR4bif67OE4,2006
|
420
420
|
arpakitlib/ar_really_validate_email.py,sha256=HBfhyiDB3INI6Iq6hR2WOMKA5wVWWRl0Qun-x__OZ9o,1201
|
@@ -430,8 +430,8 @@ arpakitlib/ar_sqlalchemy_util.py,sha256=FDva9onjtCPrYZYIHHb93NMwD1WlmaORjiWgPRJQ
|
|
430
430
|
arpakitlib/ar_str_util.py,sha256=2lGpnXDf2h1cBZpVf5i1tX_HCv5iBd6IGnrCw4QWWlY,4350
|
431
431
|
arpakitlib/ar_type_util.py,sha256=Cs_tef-Fc5xeyAF54KgISCsP11NHyzIsglm4S3Xx7iM,4049
|
432
432
|
arpakitlib/ar_yookassa_api_client_util.py,sha256=VozuZeCJjmLd1zj2BdC9WfiAQ3XYOrIMsdpNK-AUlm0,5347
|
433
|
-
arpakitlib-1.8.
|
434
|
-
arpakitlib-1.8.
|
435
|
-
arpakitlib-1.8.
|
436
|
-
arpakitlib-1.8.
|
437
|
-
arpakitlib-1.8.
|
433
|
+
arpakitlib-1.8.260.dist-info/LICENSE,sha256=GPEDQMam2r7FSTYqM1mm7aKnxLaWcBotH7UvQtea-ec,11355
|
434
|
+
arpakitlib-1.8.260.dist-info/METADATA,sha256=8iFJMcmzoK7qqnHIMzadbyvpFOZIWiF6xdYSj9wuA2o,3919
|
435
|
+
arpakitlib-1.8.260.dist-info/WHEEL,sha256=b4K_helf-jlQoXBBETfwnf4B04YC67LOev0jo4fX5m8,88
|
436
|
+
arpakitlib-1.8.260.dist-info/entry_points.txt,sha256=36xqR3PJFT2kuwjkM_EqoIy0qFUDPKSm_mJaI7emewE,87
|
437
|
+
arpakitlib-1.8.260.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|