arpakitlib 1.8.254__py3-none-any.whl → 1.8.255__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.
@@ -1,8 +1,8 @@
1
1
  # arpakit
2
2
  import datetime as dt
3
- from typing import Any, Optional, get_type_hints
3
+ from typing import Any, Optional, get_type_hints, get_origin, Union, Annotated, get_args
4
4
 
5
- from pydantic import BaseModel, Field
5
+ from pydantic import BaseModel, Field, ConfigDict
6
6
  from sqlalchemy import inspect
7
7
  from sqlalchemy.orm import ColumnProperty
8
8
  from sqlalchemy.sql.sqltypes import (
@@ -27,7 +27,7 @@ _SQLA_TYPE_MAP = {
27
27
  Text: str,
28
28
  UnicodeText: str,
29
29
  LargeBinary: bytes,
30
- JSON: dict,
30
+ JSON: dict | list,
31
31
  DateTime: dt.datetime,
32
32
  Date: dt.date,
33
33
  Time: dt.time,
@@ -61,6 +61,38 @@ def _get_property_name_to_type_from_model_class(model_class: type) -> dict[str,
61
61
  return props
62
62
 
63
63
 
64
+ def _type_matches(*, type_: Any, allowed_types: list[type]) -> bool:
65
+ """
66
+ Возвращает True, если тип `tp` соответствует хоть одному из типов в `allowed`.
67
+ - поддерживает Union/Optional (перебирает аргументы),
68
+ - Annotated (смотрит на базовый тип),
69
+ - generics (List[int], Dict[str, Any]) — сравнивает по origin (list, dict, и т.п.).
70
+ """
71
+ if type_ is Any:
72
+ return True
73
+
74
+ origin = get_origin(type_)
75
+ if origin is Union: # Optional/Union
76
+ return any(_type_matches(type_=arg, allowed_types=allowed_types) for arg in get_args(type_))
77
+ if origin is Annotated:
78
+ return _type_matches(type_=get_args(type_)[0], allowed_types=allowed_types)
79
+
80
+ # если это generic, сравним по origin (например, list/dict)
81
+ type_check = origin or type_
82
+
83
+ for allowed_type in allowed_types:
84
+ # точное совпадение по объекту типа
85
+ if type_check is allowed_type:
86
+ return True
87
+ # безопасная проверка наследования
88
+ try:
89
+ if isinstance(type_check, type) and isinstance(allowed_type, type) and issubclass(type_check, allowed_type):
90
+ return True
91
+ except Exception:
92
+ pass
93
+ return False
94
+
95
+
64
96
  def pydantic_schema_from_sqlalchemy_model(
65
97
  sqlalchemy_model: type,
66
98
  *,
@@ -70,7 +102,9 @@ def pydantic_schema_from_sqlalchemy_model(
70
102
  exclude_column_names: list[str] | None = None,
71
103
  include_properties: bool = False,
72
104
  include_property_names: list[str] | None = None,
105
+ include_property_types: list[type] | None = None,
73
106
  exclude_property_names: list[str] | None = None,
107
+ exclude_property_types: list[type] | None = None,
74
108
  filter_property_prefixes: list[str] | None = None,
75
109
  remove_property_prefixes: list[str] | None = None,
76
110
  ) -> type[BaseModel]:
@@ -127,7 +161,22 @@ def pydantic_schema_from_sqlalchemy_model(
127
161
  if include_properties:
128
162
  property_name_to_type = _get_property_name_to_type_from_model_class(sqlalchemy_model)
129
163
 
130
- # фильтр по префиксам (если задан и не пуст)
164
+ # (НОВОЕ) фильтр по типам, если задан
165
+ if include_property_types:
166
+ property_name_to_type = {
167
+ k: v for k, v in property_name_to_type.items()
168
+ if _type_matches(type_=v, allowed_types=include_property_types)
169
+ }
170
+
171
+ # Затем исключающие типы (EXCLUDE)
172
+ if exclude_property_types:
173
+ property_name_to_type = {
174
+ k: v
175
+ for k, v in property_name_to_type.items()
176
+ if not _type_matches(type_=v, allowed_types=exclude_property_types)
177
+ }
178
+
179
+ # фильтр по префиксам
131
180
  if filter_property_prefixes:
132
181
  property_name_to_type = {
133
182
  property_name: property_type
@@ -151,7 +200,7 @@ def pydantic_schema_from_sqlalchemy_model(
151
200
  if property_name in exclude_property_names:
152
201
  property_name_to_type.pop(property_name, None)
153
202
 
154
- # удаляем префиксы
203
+ # удаление префиксов (без изменений)
155
204
  if remove_property_prefixes:
156
205
  renamed_property_name_to_type = {}
157
206
  for property_name, property_type in list(property_name_to_type.items()):
@@ -183,4 +232,8 @@ def pydantic_schema_from_sqlalchemy_model(
183
232
  annotations[property_name] = property_type
184
233
 
185
234
  attrs["__annotations__"] = annotations
235
+
236
+ if "model_config" not in attrs:
237
+ attrs["model_config"] = ConfigDict(extra="ignore", arbitrary_types_allowed=True, from_attributes=True)
238
+
186
239
  return type(model_name, (base_model,), attrs)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: arpakitlib
3
- Version: 1.8.254
3
+ Version: 1.8.255
4
4
  Summary: arpakitlib
5
5
  License: Apache-2.0
6
6
  Keywords: arpakitlib,arpakit,arpakit-company,arpakitcompany,arpakit_company
@@ -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=-uaJcr3GqledUXk_uSFKfUX00gxX6WVAQs4mfxmXTWg,7399
417
+ arpakitlib/ar_pydantic_schema_from_sqlalchemy_model.py,sha256=-cygl5zkbQuKQ1vp3RSbyLka7w9uackcGIsuCbq7jxU,9728
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.254.dist-info/LICENSE,sha256=GPEDQMam2r7FSTYqM1mm7aKnxLaWcBotH7UvQtea-ec,11355
434
- arpakitlib-1.8.254.dist-info/METADATA,sha256=pnFWXrz2lu5ZwiVcwwpwa3gYAUHv_AZC6RDFUm7hpiw,3919
435
- arpakitlib-1.8.254.dist-info/WHEEL,sha256=b4K_helf-jlQoXBBETfwnf4B04YC67LOev0jo4fX5m8,88
436
- arpakitlib-1.8.254.dist-info/entry_points.txt,sha256=36xqR3PJFT2kuwjkM_EqoIy0qFUDPKSm_mJaI7emewE,87
437
- arpakitlib-1.8.254.dist-info/RECORD,,
433
+ arpakitlib-1.8.255.dist-info/LICENSE,sha256=GPEDQMam2r7FSTYqM1mm7aKnxLaWcBotH7UvQtea-ec,11355
434
+ arpakitlib-1.8.255.dist-info/METADATA,sha256=UzSoTiAnAf8JvaX4DOOPyfHzUnH3fk4EwFfh4zvVMnA,3919
435
+ arpakitlib-1.8.255.dist-info/WHEEL,sha256=b4K_helf-jlQoXBBETfwnf4B04YC67LOev0jo4fX5m8,88
436
+ arpakitlib-1.8.255.dist-info/entry_points.txt,sha256=36xqR3PJFT2kuwjkM_EqoIy0qFUDPKSm_mJaI7emewE,87
437
+ arpakitlib-1.8.255.dist-info/RECORD,,