arpakitlib 1.8.249__py3-none-any.whl → 1.8.251__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/api/raise_own_exception_if_exception_in_api_router.py +1 -1
- arpakitlib/_arpakit_project_template_v_5/project/sandbox/sandbox_3.py +1 -1
- arpakitlib/ar_pydantic_schema_from_sqlalchemy_model.py +149 -0
- arpakitlib/ar_really_validate_url.py +47 -0
- arpakitlib/ar_sqlalchemy_util.py +1 -1
- {arpakitlib-1.8.249.dist-info → arpakitlib-1.8.251.dist-info}/METADATA +1 -1
- {arpakitlib-1.8.249.dist-info → arpakitlib-1.8.251.dist-info}/RECORD +15 -14
- arpakitlib/pydantic_schema_from_sqlalchemy_model.py +0 -93
- /arpakitlib/{clone_pydantic_model_fields.py → ar_clone_pydantic_model_fields.py} +0 -0
- /arpakitlib/{ensure_sqlalchemy_check_constraints.py → ar_ensure_sqlalchemy_check_constraints.py} +0 -0
- /arpakitlib/{generate_simple_code.py → ar_generate_simple_code.py} +0 -0
- /arpakitlib/{raise_own_exception_if_exception.py → ar_raise_own_exception_if_exception.py} +0 -0
- /arpakitlib/{really_validate_email.py → ar_really_validate_email.py} +0 -0
- {arpakitlib-1.8.249.dist-info → arpakitlib-1.8.251.dist-info}/LICENSE +0 -0
- {arpakitlib-1.8.249.dist-info → arpakitlib-1.8.251.dist-info}/WHEEL +0 -0
- {arpakitlib-1.8.249.dist-info → arpakitlib-1.8.251.dist-info}/entry_points.txt +0 -0
@@ -1,7 +1,7 @@
|
|
1
1
|
from typing import Any
|
2
2
|
|
3
3
|
import fastapi
|
4
|
-
from arpakitlib.
|
4
|
+
from arpakitlib.ar_raise_own_exception_if_exception import raise_own_exception_if_exception
|
5
5
|
|
6
6
|
from project.api.api_exception import APIException
|
7
7
|
from project.api.schema.out.common.error import ErrorCommonSO
|
@@ -1,6 +1,6 @@
|
|
1
1
|
import asyncio
|
2
2
|
|
3
|
-
from arpakitlib.
|
3
|
+
from arpakitlib.ar_pydantic_schema_from_sqlalchemy_model import pydantic_schema_from_sqlalchemy_model
|
4
4
|
from project.sqlalchemy_db_.sqlalchemy_model import UserDBM
|
5
5
|
|
6
6
|
|
@@ -0,0 +1,149 @@
|
|
1
|
+
# arpakit
|
2
|
+
import datetime as dt
|
3
|
+
from typing import Any, Optional, get_type_hints
|
4
|
+
|
5
|
+
from pydantic import BaseModel, Field
|
6
|
+
from sqlalchemy import inspect
|
7
|
+
from sqlalchemy.orm import ColumnProperty
|
8
|
+
from sqlalchemy.sql.sqltypes import (
|
9
|
+
Boolean, Integer, BigInteger, SmallInteger,
|
10
|
+
String, Text, Unicode, UnicodeText,
|
11
|
+
DateTime, Date, Time,
|
12
|
+
Float, Numeric, DECIMAL, LargeBinary, JSON
|
13
|
+
)
|
14
|
+
|
15
|
+
_ARPAKIT_LIB_MODULE_VERSION = "3.0"
|
16
|
+
|
17
|
+
_SQLA_TYPE_MAP = {
|
18
|
+
Boolean: bool,
|
19
|
+
Integer: int,
|
20
|
+
BigInteger: int,
|
21
|
+
SmallInteger: int,
|
22
|
+
Float: float,
|
23
|
+
Numeric: float,
|
24
|
+
DECIMAL: float,
|
25
|
+
String: str,
|
26
|
+
Unicode: str,
|
27
|
+
Text: str,
|
28
|
+
UnicodeText: str,
|
29
|
+
LargeBinary: bytes,
|
30
|
+
JSON: dict,
|
31
|
+
DateTime: dt.datetime,
|
32
|
+
Date: dt.date,
|
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
|
45
|
+
|
46
|
+
|
47
|
+
def _collect_properties_with_types(model_class: type) -> dict[str, Any]:
|
48
|
+
"""
|
49
|
+
Находит все @property в классе и вытаскивает их возвращаемый тип.
|
50
|
+
Если тип не удаётся получить — подставляем Any.
|
51
|
+
"""
|
52
|
+
props: dict[str, Any] = {}
|
53
|
+
for name, attr in vars(model_class).items():
|
54
|
+
if isinstance(attr, property):
|
55
|
+
try:
|
56
|
+
hints = get_type_hints(attr.fget) if attr.fget else {}
|
57
|
+
ret_type = hints.get("return", Any)
|
58
|
+
except Exception:
|
59
|
+
ret_type = Any
|
60
|
+
props[name] = ret_type
|
61
|
+
return props
|
62
|
+
|
63
|
+
|
64
|
+
def pydantic_schema_from_sqlalchemy_model(
|
65
|
+
sqlalchemy_model: type,
|
66
|
+
*,
|
67
|
+
name: str | None = None,
|
68
|
+
base_model: type[BaseModel] = BaseModel,
|
69
|
+
include_column_defaults: bool = False,
|
70
|
+
exclude_column_names: list[str] | None = None,
|
71
|
+
include_properties: bool = False,
|
72
|
+
include_property_names: list[str] | None = None,
|
73
|
+
exclude_property_names: list[str] | None = None,
|
74
|
+
) -> type[BaseModel]:
|
75
|
+
"""
|
76
|
+
Генерирует Pydantic-модель из колонок SQLAlchemy-модели и (опционально) из @property.
|
77
|
+
|
78
|
+
- include_column_defaults: добавлять ли default/server_default у колонок.
|
79
|
+
- exclude_column_names: список имён колонок, которые нужно пропустить.
|
80
|
+
|
81
|
+
- include_properties: включать ли свойства (@property). По умолчанию False.
|
82
|
+
- include_property_names: whitelist имён свойств (если задан, берём только их).
|
83
|
+
- exclude_property_names: blacklist имён свойств (исключаются после whitelist'а).
|
84
|
+
"""
|
85
|
+
mapper = inspect(sqlalchemy_model).mapper
|
86
|
+
model_name = name or f"{sqlalchemy_model.__name__}Schema"
|
87
|
+
|
88
|
+
annotations: dict[str, Any] = {}
|
89
|
+
attrs: dict[str, Any] = {}
|
90
|
+
|
91
|
+
exclude_column_names = set(exclude_column_names or [])
|
92
|
+
include_property_names = set(include_property_names or [])
|
93
|
+
exclude_property_names = set(exclude_property_names or [])
|
94
|
+
|
95
|
+
# 1) Колонки
|
96
|
+
for prop in mapper.attrs:
|
97
|
+
if not isinstance(prop, ColumnProperty):
|
98
|
+
continue
|
99
|
+
if prop.key in exclude_column_names:
|
100
|
+
continue
|
101
|
+
|
102
|
+
column = prop.columns[0]
|
103
|
+
column_type = _python_type_from_col(column)
|
104
|
+
|
105
|
+
# Аннотация типа
|
106
|
+
if column.nullable:
|
107
|
+
annotations[prop.key] = Optional[column_type] # type: ignore[name-defined]
|
108
|
+
else:
|
109
|
+
annotations[prop.key] = column_type
|
110
|
+
|
111
|
+
# Дефолты, если нужно
|
112
|
+
if include_column_defaults:
|
113
|
+
default_value = None
|
114
|
+
if column.default is not None and getattr(column.default, "is_scalar", False):
|
115
|
+
default_value = column.default.arg
|
116
|
+
elif column.server_default is not None and getattr(column.server_default.arg, "text", None):
|
117
|
+
default_value = column.server_default.arg.text
|
118
|
+
|
119
|
+
if default_value is not None:
|
120
|
+
attrs[prop.key] = Field(default=default_value)
|
121
|
+
|
122
|
+
# 2) Свойства (@property)
|
123
|
+
if include_properties:
|
124
|
+
property_name_to_type = _collect_properties_with_types(sqlalchemy_model)
|
125
|
+
|
126
|
+
# whitelist (если задан)
|
127
|
+
if include_property_names:
|
128
|
+
property_name_to_type = {
|
129
|
+
k: v
|
130
|
+
for k, v in property_name_to_type.items()
|
131
|
+
if k in include_property_names
|
132
|
+
}
|
133
|
+
else:
|
134
|
+
property_name_to_type = dict(property_name_to_type)
|
135
|
+
|
136
|
+
# blacklist
|
137
|
+
if exclude_property_names:
|
138
|
+
for property_name in list(property_name_to_type.keys()):
|
139
|
+
if property_name in exclude_property_names:
|
140
|
+
property_name_to_type.pop(name, None)
|
141
|
+
|
142
|
+
# Добавляем аннотации свойств (колонки имеют приоритет)
|
143
|
+
for property_name, property_type in property_name_to_type.items():
|
144
|
+
if property_name in annotations:
|
145
|
+
continue
|
146
|
+
annotations[property_name] = property_type
|
147
|
+
|
148
|
+
attrs["__annotations__"] = annotations
|
149
|
+
return type(model_name, (base_model,), attrs)
|
@@ -0,0 +1,47 @@
|
|
1
|
+
from urllib.parse import urlparse
|
2
|
+
|
3
|
+
|
4
|
+
class ReallyValidateUrlException(Exception):
|
5
|
+
def __init__(self, url: str, error_message: str):
|
6
|
+
self.url = url
|
7
|
+
self.error_message = error_message
|
8
|
+
|
9
|
+
def __str__(self) -> str:
|
10
|
+
return f"{self.__class__.__name__}, {self.url=}, {self.error_message}"
|
11
|
+
|
12
|
+
def __repr__(self) -> str:
|
13
|
+
return f"{self.__class__.__name__}, {self.url=}, {self.error_message}"
|
14
|
+
|
15
|
+
|
16
|
+
def really_validate_url(url: str) -> None:
|
17
|
+
result = urlparse(url)
|
18
|
+
|
19
|
+
if not result.scheme:
|
20
|
+
raise ReallyValidateUrlException(
|
21
|
+
url=url,
|
22
|
+
error_message="URL must include a scheme (e.g., http/https)."
|
23
|
+
)
|
24
|
+
|
25
|
+
if not result.netloc:
|
26
|
+
raise ReallyValidateUrlException(
|
27
|
+
url=url,
|
28
|
+
error_message="URL must include a domain or host."
|
29
|
+
)
|
30
|
+
|
31
|
+
# Optional: restrict allowed schemes
|
32
|
+
if result.scheme not in ("http", "https", "ftp"):
|
33
|
+
raise ReallyValidateUrlException(
|
34
|
+
url=url,
|
35
|
+
error_message=f"Unsupported scheme: {result.scheme}"
|
36
|
+
)
|
37
|
+
|
38
|
+
# If everything is fine — return None (no errors)
|
39
|
+
return None
|
40
|
+
|
41
|
+
|
42
|
+
def is_really_url_valid(email: str) -> bool:
|
43
|
+
try:
|
44
|
+
really_validate_url(url=email)
|
45
|
+
except ReallyValidateUrlException:
|
46
|
+
return False
|
47
|
+
return True
|
arpakitlib/ar_sqlalchemy_util.py
CHANGED
@@ -299,7 +299,7 @@ class SQLAlchemyDb:
|
|
299
299
|
self._logger.info("alembic tables data were removed")
|
300
300
|
|
301
301
|
def ensure_check_constraints(self):
|
302
|
-
from arpakitlib.
|
302
|
+
from arpakitlib.ar_ensure_sqlalchemy_check_constraints import ensure_sqlalchemy_check_constraints
|
303
303
|
ensure_sqlalchemy_check_constraints(base_=self.base_dbm, engine=self.engine)
|
304
304
|
|
305
305
|
def init(self, ensure_check_constraints: bool = True):
|
@@ -101,7 +101,7 @@ arpakitlib/_arpakit_project_template_v_5/project/api/middleware/__init__.py,sha2
|
|
101
101
|
arpakitlib/_arpakit_project_template_v_5/project/api/middleware/add_api_middlewares.py,sha256=TrWn0yPDCn0yTlHqLf19ypGtRumNjDxm0sM60yVsqXE,468
|
102
102
|
arpakitlib/_arpakit_project_template_v_5/project/api/middleware/limit_content_length.py,sha256=cEtGcJSh3e2EyuQCFqKzRcrl3qS6oIvpSv5UEbYsvR4,1622
|
103
103
|
arpakitlib/_arpakit_project_template_v_5/project/api/openapi_ui.py,sha256=7yg9ZNu6BjTAregnfbRFpwvqa-gTIY6o6NCz5pmsbeo,976
|
104
|
-
arpakitlib/_arpakit_project_template_v_5/project/api/raise_own_exception_if_exception_in_api_router.py,sha256=
|
104
|
+
arpakitlib/_arpakit_project_template_v_5/project/api/raise_own_exception_if_exception_in_api_router.py,sha256=7zssLmFEfZ5WvC-ZW1bPyn_HrYNPjvK_Q9Ln1-xH3O4,1413
|
105
105
|
arpakitlib/_arpakit_project_template_v_5/project/api/response.py,sha256=xZMymP2BuQaRNVWLeIp3UgUUo-MFN8MJnsn9Al4vOb8,1028
|
106
106
|
arpakitlib/_arpakit_project_template_v_5/project/api/router/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
107
107
|
arpakitlib/_arpakit_project_template_v_5/project/api/router/admin/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
@@ -237,7 +237,7 @@ arpakitlib/_arpakit_project_template_v_5/project/resource/templates/simple_email
|
|
237
237
|
arpakitlib/_arpakit_project_template_v_5/project/sandbox/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
238
238
|
arpakitlib/_arpakit_project_template_v_5/project/sandbox/sandbox_1.py,sha256=xKSp7tIBu3Ffp_kgJkwVtdam3BcoFZ44JPVHoRRaP0E,163
|
239
239
|
arpakitlib/_arpakit_project_template_v_5/project/sandbox/sandbox_2.py,sha256=xKSp7tIBu3Ffp_kgJkwVtdam3BcoFZ44JPVHoRRaP0E,163
|
240
|
-
arpakitlib/_arpakit_project_template_v_5/project/sandbox/sandbox_3.py,sha256=
|
240
|
+
arpakitlib/_arpakit_project_template_v_5/project/sandbox/sandbox_3.py,sha256=CIv4vQfBLhlIh92fiLhmyTXSZXjDovxTFZtUBDnWyFY,427
|
241
241
|
arpakitlib/_arpakit_project_template_v_5/project/sandbox/sandbox_4.py,sha256=xKSp7tIBu3Ffp_kgJkwVtdam3BcoFZ44JPVHoRRaP0E,163
|
242
242
|
arpakitlib/_arpakit_project_template_v_5/project/sandbox/sandbox_5.py,sha256=xKSp7tIBu3Ffp_kgJkwVtdam3BcoFZ44JPVHoRRaP0E,163
|
243
243
|
arpakitlib/_arpakit_project_template_v_5/project/sandbox/sandbox_6.py,sha256=xKSp7tIBu3Ffp_kgJkwVtdam3BcoFZ44JPVHoRRaP0E,163
|
@@ -388,15 +388,18 @@ arpakitlib/ar_base_worker_util.py,sha256=e-Vj9w1D-59KN3Zz7TQlOB2lW4fZphJlsPpFkmX
|
|
388
388
|
arpakitlib/ar_blank_util.py,sha256=qFUdY8usL_pRYamz8Rw1fW3fzNIgrLmpdYP8q-_PQvw,2281
|
389
389
|
arpakitlib/ar_cache_file_util.py,sha256=Fo2pH-Zqm966KWFBHG_pbiySGZvhIFCYqy7k1weRfJ0,3476
|
390
390
|
arpakitlib/ar_class_util.py,sha256=i76pQW_7k_S2m_DlQh6xNjtggv9Col3WSx9W_bwk98E,722
|
391
|
+
arpakitlib/ar_clone_pydantic_model_fields.py,sha256=xxLwtvJzDf8EWMvBE4psWIj8c-cyeCxLRX76oCY_4zk,1214
|
391
392
|
arpakitlib/ar_datetime_util.py,sha256=Xe1NiT9oPQzNSG7RVRkhukhbg4i-hhS5ImmV7sPUc8o,971
|
392
393
|
arpakitlib/ar_dict_util.py,sha256=oet-9AJEjQZfG_EI82BuYW0jdW2NQxKjPXol_nfTXjw,447
|
393
394
|
arpakitlib/ar_dream_ai_api_client_util.py,sha256=Z1oii_XSsgunYx17SdcHl54S4KPQti7-MJs0xXZ8vL0,2830
|
394
395
|
arpakitlib/ar_encrypt_decrypt_util.py,sha256=GhWnp7HHkbhwFVVCzO1H07m-5gryr4yjWsXjOaNQm1Y,520
|
396
|
+
arpakitlib/ar_ensure_sqlalchemy_check_constraints.py,sha256=JJbgaUiLT8D8oDVevP25wlMz1BTtx0JMasJ_ILyIJ3o,5328
|
395
397
|
arpakitlib/ar_enumeration_util.py,sha256=XoFInWtGzbIr6fJq0un5nettaDfOLAyY84ovwj7n_7g,3030
|
396
398
|
arpakitlib/ar_exception_util.py,sha256=3hZKsj34TZVdmd4JAQz7w515smWqB8o3gTwAEjuMdnI,408
|
397
399
|
arpakitlib/ar_file_storage_in_dir_util.py,sha256=Zh922S6-aIy0p_Fen8GTTrGpixpPQ6c-wFLukiSK4Ck,4091
|
398
400
|
arpakitlib/ar_file_util.py,sha256=GUdJYm1tUZnYpY-SIPRHAZBHGra8NKy1eYEI0D5AfhY,489
|
399
401
|
arpakitlib/ar_func_util.py,sha256=lG0bx_DtxWN4skbUim0liRZ6WUyLVV8Qfk6iZNtCZOs,1042
|
402
|
+
arpakitlib/ar_generate_simple_code.py,sha256=EkrebrTi7sArSRAuxvN5BPm_A0-dFSCZgdoJhx5kPhk,344
|
400
403
|
arpakitlib/ar_hash_util.py,sha256=Iqy6KBAOLBQMFLWv676boI5sV7atT2B-fb7aCdHOmIQ,340
|
401
404
|
arpakitlib/ar_http_request_util.py,sha256=PCUtGOQIvNScrLqD_9Z8LqT-7a-lP2y-Y-CH5vGdn7Q,7663
|
402
405
|
arpakitlib/ar_ip_util.py,sha256=aEAa1Hvobh9DWX7cmBAPLqnXSTiKe2hRk-WJaiKMaI8,1009
|
@@ -411,7 +414,11 @@ arpakitlib/ar_need_type_util.py,sha256=XmY1kswz8j9oo5f9CxRu0_zgfvxWrXPYKOj6MM04s
|
|
411
414
|
arpakitlib/ar_openai_api_client_util.py,sha256=dWgsSPXtxNBxS5VRi_NharGQrUXF_YjIfhU3Bj5cW9M,5651
|
412
415
|
arpakitlib/ar_parse_command.py,sha256=1WTdQoWVshoDZ1jDaKeTzajfqaYHP3FNO0-REyo1aMY,3003
|
413
416
|
arpakitlib/ar_postgresql_util.py,sha256=1AuLjEaa1Lg4pzn-ukCVnDi35Eg1k91APRTqZhIJAdo,945
|
417
|
+
arpakitlib/ar_pydantic_schema_from_sqlalchemy_model.py,sha256=NuvydQe7Cih6dW5H53GB6BsG2oFKgf27F3iJxuPO2J0,5364
|
418
|
+
arpakitlib/ar_raise_own_exception_if_exception.py,sha256=A6TuNSBk1pHaQ_qxnUmE2LgsNGA1IGqX26b1_HEA4Nc,5978
|
414
419
|
arpakitlib/ar_rat_func_util.py,sha256=Ca10o3RJwyx_DJLxjTxgHDO6NU3M6CWgUR4bif67OE4,2006
|
420
|
+
arpakitlib/ar_really_validate_email.py,sha256=HBfhyiDB3INI6Iq6hR2WOMKA5wVWWRl0Qun-x__OZ9o,1201
|
421
|
+
arpakitlib/ar_really_validate_url.py,sha256=aaSPVMbz2DSqlC2yk2g44-kTIiHlITfJwIG97L-Y93U,1309
|
415
422
|
arpakitlib/ar_retry_func_util.py,sha256=LB4FJRsu2cssnPw6X8bCEcaGpQsXhkLkgeU37w1t9fU,2250
|
416
423
|
arpakitlib/ar_run_cmd_util.py,sha256=D_rPavKMmWkQtwvZFz-Io5Ak8eSODHkcFeLPzNVC68g,1072
|
417
424
|
arpakitlib/ar_safe_func.py,sha256=c2P1hzB8uQn3l8cAr2nttfHbrM-4QrxgDejk_jM1OVE,2321
|
@@ -419,18 +426,12 @@ arpakitlib/ar_schedule_uust_api_client_util.py,sha256=rXI2_3OTaIBgR-GixM1Ti-Ue1f
|
|
419
426
|
arpakitlib/ar_settings_util.py,sha256=Y5wi_cmsjDjfJpM0VJHjbo0NoVPKfypKaD1USowwDtQ,1327
|
420
427
|
arpakitlib/ar_sleep_util.py,sha256=ggaj7ML6QK_ADsHMcyu6GUmUpQ_9B9n-SKYH17h-9lM,1045
|
421
428
|
arpakitlib/ar_sqladmin_util.py,sha256=SEoaowAPF3lhxPsNjwmOymNJ55Ty9rmzvsDm7gD5Ceo,861
|
422
|
-
arpakitlib/ar_sqlalchemy_util.py,sha256=
|
429
|
+
arpakitlib/ar_sqlalchemy_util.py,sha256=5I7KsKCzJc9hxpn2_0r__RcbqcKpTs_PDw_f5_0P7Xw,16050
|
423
430
|
arpakitlib/ar_str_util.py,sha256=2lGpnXDf2h1cBZpVf5i1tX_HCv5iBd6IGnrCw4QWWlY,4350
|
424
431
|
arpakitlib/ar_type_util.py,sha256=Cs_tef-Fc5xeyAF54KgISCsP11NHyzIsglm4S3Xx7iM,4049
|
425
432
|
arpakitlib/ar_yookassa_api_client_util.py,sha256=VozuZeCJjmLd1zj2BdC9WfiAQ3XYOrIMsdpNK-AUlm0,5347
|
426
|
-
arpakitlib/
|
427
|
-
arpakitlib/
|
428
|
-
arpakitlib/
|
429
|
-
arpakitlib/
|
430
|
-
arpakitlib/
|
431
|
-
arpakitlib/really_validate_email.py,sha256=HBfhyiDB3INI6Iq6hR2WOMKA5wVWWRl0Qun-x__OZ9o,1201
|
432
|
-
arpakitlib-1.8.249.dist-info/LICENSE,sha256=GPEDQMam2r7FSTYqM1mm7aKnxLaWcBotH7UvQtea-ec,11355
|
433
|
-
arpakitlib-1.8.249.dist-info/METADATA,sha256=Cg-pyrGVi2RHXny_fIxg3kprdoJHO2OBqYa7Dggujn0,3919
|
434
|
-
arpakitlib-1.8.249.dist-info/WHEEL,sha256=b4K_helf-jlQoXBBETfwnf4B04YC67LOev0jo4fX5m8,88
|
435
|
-
arpakitlib-1.8.249.dist-info/entry_points.txt,sha256=36xqR3PJFT2kuwjkM_EqoIy0qFUDPKSm_mJaI7emewE,87
|
436
|
-
arpakitlib-1.8.249.dist-info/RECORD,,
|
433
|
+
arpakitlib-1.8.251.dist-info/LICENSE,sha256=GPEDQMam2r7FSTYqM1mm7aKnxLaWcBotH7UvQtea-ec,11355
|
434
|
+
arpakitlib-1.8.251.dist-info/METADATA,sha256=qCRaVdN1qqbRnIqYG7bYL2J3i6_sDOIpxqO7SG1BLNA,3919
|
435
|
+
arpakitlib-1.8.251.dist-info/WHEEL,sha256=b4K_helf-jlQoXBBETfwnf4B04YC67LOev0jo4fX5m8,88
|
436
|
+
arpakitlib-1.8.251.dist-info/entry_points.txt,sha256=36xqR3PJFT2kuwjkM_EqoIy0qFUDPKSm_mJaI7emewE,87
|
437
|
+
arpakitlib-1.8.251.dist-info/RECORD,,
|
@@ -1,93 +0,0 @@
|
|
1
|
-
# arpakit
|
2
|
-
import datetime as dt
|
3
|
-
from typing import Any, Optional
|
4
|
-
|
5
|
-
from pydantic import BaseModel, Field
|
6
|
-
from sqlalchemy import inspect
|
7
|
-
from sqlalchemy.orm import ColumnProperty
|
8
|
-
from sqlalchemy.sql.sqltypes import (
|
9
|
-
Boolean, Integer, BigInteger, SmallInteger,
|
10
|
-
String, Text, Unicode, UnicodeText,
|
11
|
-
DateTime, Date, Time,
|
12
|
-
Float, Numeric, DECIMAL, LargeBinary, JSON
|
13
|
-
)
|
14
|
-
_ARPAKIT_LIB_MODULE_VERSION = "3.0"
|
15
|
-
|
16
|
-
_SQLA_TYPE_MAP = {
|
17
|
-
Boolean: bool,
|
18
|
-
Integer: int,
|
19
|
-
BigInteger: int,
|
20
|
-
SmallInteger: int,
|
21
|
-
Float: float,
|
22
|
-
Numeric: float,
|
23
|
-
DECIMAL: float,
|
24
|
-
String: str,
|
25
|
-
Unicode: str,
|
26
|
-
Text: str,
|
27
|
-
UnicodeText: str,
|
28
|
-
LargeBinary: bytes,
|
29
|
-
JSON: dict,
|
30
|
-
DateTime: dt.datetime,
|
31
|
-
Date: dt.date,
|
32
|
-
Time: dt.time,
|
33
|
-
}
|
34
|
-
|
35
|
-
|
36
|
-
def _python_type_from_col(col) -> type | str:
|
37
|
-
try:
|
38
|
-
return col.type.python_type
|
39
|
-
except Exception:
|
40
|
-
for sa_t, py_t in _SQLA_TYPE_MAP.items():
|
41
|
-
if isinstance(col.type, sa_t):
|
42
|
-
return py_t
|
43
|
-
return Any
|
44
|
-
|
45
|
-
|
46
|
-
def pydantic_schema_from_sqlalchemy_model(
|
47
|
-
sqlalchemy_model: type,
|
48
|
-
*,
|
49
|
-
name: str | None = None,
|
50
|
-
base_model: type[BaseModel] = BaseModel,
|
51
|
-
include_defaults: bool = False,
|
52
|
-
exclude_column_names: list[str] | None = None,
|
53
|
-
) -> type[BaseModel]:
|
54
|
-
"""
|
55
|
-
Генерирует Pydantic-модель только из колонок SQLAlchemy-модели.
|
56
|
-
- include_defaults: добавлять ли default/server_default.
|
57
|
-
- exclude_column_names: список имён колонок, которые нужно пропустить.
|
58
|
-
"""
|
59
|
-
mapper = inspect(sqlalchemy_model).mapper
|
60
|
-
model_name = name or f"{sqlalchemy_model.__name__}Schema"
|
61
|
-
|
62
|
-
annotations: dict[str, Any] = {}
|
63
|
-
attrs: dict[str, Any] = {}
|
64
|
-
exclude_column_names = set(exclude_column_names or [])
|
65
|
-
|
66
|
-
for prop in mapper.attrs:
|
67
|
-
if not isinstance(prop, ColumnProperty):
|
68
|
-
continue
|
69
|
-
if prop.key in exclude_column_names:
|
70
|
-
continue
|
71
|
-
|
72
|
-
col = prop.columns[0]
|
73
|
-
py_t = _python_type_from_col(col)
|
74
|
-
|
75
|
-
# Аннотация типа
|
76
|
-
if col.nullable:
|
77
|
-
annotations[prop.key] = Optional[py_t] # type: ignore[name-defined]
|
78
|
-
else:
|
79
|
-
annotations[prop.key] = py_t
|
80
|
-
|
81
|
-
# Если нужно — добавляем дефолт
|
82
|
-
if include_defaults:
|
83
|
-
default_value = None
|
84
|
-
if col.default is not None and col.default.is_scalar:
|
85
|
-
default_value = col.default.arg
|
86
|
-
elif col.server_default is not None and getattr(col.server_default.arg, "text", None):
|
87
|
-
default_value = col.server_default.arg.text
|
88
|
-
|
89
|
-
if default_value is not None:
|
90
|
-
attrs[prop.key] = Field(default=default_value)
|
91
|
-
|
92
|
-
attrs["__annotations__"] = annotations
|
93
|
-
return type(model_name, (base_model,), attrs)
|
File without changes
|
/arpakitlib/{ensure_sqlalchemy_check_constraints.py → ar_ensure_sqlalchemy_check_constraints.py}
RENAMED
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|