sqlmodel-ext 0.5.0__py3-none-any.whl → 0.5.2__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.
- sqlmodel_ext/__init__.py +4 -1
- sqlmodel_ext/_compat.py +4 -2
- sqlmodel_ext/_exceptions.py +1 -1
- sqlmodel_ext/_sa_type.py +20 -8
- sqlmodel_ext/_type_unwrap.py +10 -2
- sqlmodel_ext/base.py +267 -119
- sqlmodel_ext/check_derived.py +8 -8
- sqlmodel_ext/dependencies.py +178 -0
- sqlmodel_ext/field_types/__init__.py +27 -39
- sqlmodel_ext/field_types/_internal/path.py +22 -10
- sqlmodel_ext/field_types/dialects/postgresql/array.py +27 -13
- sqlmodel_ext/field_types/dialects/postgresql/jsonb_types.py +4 -5
- sqlmodel_ext/field_types/dialects/postgresql/numpy_vector.py +40 -24
- sqlmodel_ext/field_types/mixins/module_name_mixin.py +2 -2
- sqlmodel_ext/field_types/url.py +6 -6
- sqlmodel_ext/mixins/cached_table.py +239 -266
- sqlmodel_ext/mixins/migration_cache_invalidation.py +6 -6
- sqlmodel_ext/mixins/polymorphic.py +36 -23
- sqlmodel_ext/mixins/relation_preload.py +16 -16
- sqlmodel_ext/mixins/resource_quota.py +9 -6
- sqlmodel_ext/mixins/table.py +44 -28
- sqlmodel_ext/mixins/trgm_searchable.py +1 -1
- sqlmodel_ext/pagination.py +72 -39
- sqlmodel_ext/relation_load_checker.py +21 -15
- sqlmodel_ext/session.py +60 -33
- sqlmodel_ext/unset.py +1 -3
- {sqlmodel_ext-0.5.0.dist-info → sqlmodel_ext-0.5.2.dist-info}/METADATA +7 -6
- sqlmodel_ext-0.5.2.dist-info/RECORD +50 -0
- sqlmodel_ext-0.5.0.dist-info/RECORD +0 -49
- {sqlmodel_ext-0.5.0.dist-info → sqlmodel_ext-0.5.2.dist-info}/WHEEL +0 -0
- {sqlmodel_ext-0.5.0.dist-info → sqlmodel_ext-0.5.2.dist-info}/entry_points.txt +0 -0
- {sqlmodel_ext-0.5.0.dist-info → sqlmodel_ext-0.5.2.dist-info}/licenses/LICENSE +0 -0
sqlmodel_ext/__init__.py
CHANGED
|
@@ -20,7 +20,7 @@ Quick start::
|
|
|
20
20
|
user = await user.save(session)
|
|
21
21
|
users = await User.get(session, fetch_mode="all")
|
|
22
22
|
"""
|
|
23
|
-
__version__ = "0.5.
|
|
23
|
+
__version__ = "0.5.2"
|
|
24
24
|
|
|
25
25
|
# Every re-export below uses the redundant ``X as X`` form: the package ships
|
|
26
26
|
# ``py.typed``, and type checkers treat a plain ``from m import X`` in a typed
|
|
@@ -66,6 +66,9 @@ from sqlmodel_ext.pagination import (
|
|
|
66
66
|
TableViewRequest as TableViewRequest,
|
|
67
67
|
)
|
|
68
68
|
|
|
69
|
+
# FastAPI dependency for query-parameter DTOs (cross-field errors -> 422; requires the `fastapi` extra when called)
|
|
70
|
+
from sqlmodel_ext.dependencies import query_dependency as query_dependency
|
|
71
|
+
|
|
69
72
|
# Mixins
|
|
70
73
|
from sqlmodel_ext.mixins import (
|
|
71
74
|
# Table
|
sqlmodel_ext/_compat.py
CHANGED
|
@@ -9,7 +9,9 @@ Import this module for side effects before using SQLModelBase.
|
|
|
9
9
|
import sys
|
|
10
10
|
|
|
11
11
|
if sys.version_info >= (3, 14):
|
|
12
|
-
|
|
12
|
+
# The checker analyzes at pythonVersion 3.12 (the lowest supported version), where this
|
|
13
|
+
# version-gated block is statically unreachable; it does run on 3.14+.
|
|
14
|
+
import annotationlib # noqa: F401 # pyright: ignore[reportUnreachable]
|
|
13
15
|
import types
|
|
14
16
|
from enum import StrEnum
|
|
15
17
|
from typing import Literal, Union, get_args, get_origin
|
|
@@ -101,7 +103,7 @@ if sys.version_info >= (3, 14):
|
|
|
101
103
|
if non_none_args:
|
|
102
104
|
first_arg = non_none_args[0]
|
|
103
105
|
# Check for Annotated SA type metadata first (e.g. Array[T] | None).
|
|
104
|
-
# Array[T] desugars to Annotated[list[T],
|
|
106
|
+
# Array[T] desugars to Annotated[list[T], ArrayTypeHandler(T)];
|
|
105
107
|
# wrapping with | None produces Union[Annotated[...], None],
|
|
106
108
|
# so the SA type must be extracted from the inner Annotated.
|
|
107
109
|
first_arg_type_name = type(first_arg).__name__
|
sqlmodel_ext/_exceptions.py
CHANGED
sqlmodel_ext/_sa_type.py
CHANGED
|
@@ -2,15 +2,27 @@
|
|
|
2
2
|
Internal helpers for extracting SQLAlchemy types from annotations.
|
|
3
3
|
|
|
4
4
|
These are used by the metaclass to inject sa_type into Field definitions.
|
|
5
|
+
|
|
6
|
+
Internal protocol, not part of the public API: the functions carry public names
|
|
7
|
+
only because :mod:`sqlmodel_ext.base` (the metaclass) imports them across module
|
|
8
|
+
boundaries; the module itself stays private (``_sa_type``).
|
|
5
9
|
"""
|
|
6
10
|
import sys
|
|
7
11
|
import typing
|
|
8
|
-
from
|
|
12
|
+
from collections.abc import Mapping
|
|
13
|
+
from typing import Any, get_args, get_origin, get_type_hints
|
|
14
|
+
|
|
9
15
|
|
|
10
|
-
|
|
16
|
+
def _null_schema_handler(_source_type: Any) -> None:
|
|
17
|
+
"""
|
|
18
|
+
Stand-in for pydantic's ``GetCoreSchemaHandler`` when probing a type's
|
|
19
|
+
``__get_pydantic_core_schema__`` for ``metadata['sa_type']``: the probe
|
|
20
|
+
only reads the metadata and never needs the delegated inner schema.
|
|
21
|
+
"""
|
|
22
|
+
return None
|
|
11
23
|
|
|
12
24
|
|
|
13
|
-
def
|
|
25
|
+
def extract_sa_type_from_annotation(annotation: Any) -> Any | None:
|
|
14
26
|
"""
|
|
15
27
|
Extract SQLAlchemy type from a type annotation.
|
|
16
28
|
|
|
@@ -40,7 +52,7 @@ def _extract_sa_type_from_annotation(annotation: Any) -> Any | None:
|
|
|
40
52
|
try:
|
|
41
53
|
schema = item.__get_pydantic_core_schema__(
|
|
42
54
|
annotation,
|
|
43
|
-
|
|
55
|
+
_null_schema_handler,
|
|
44
56
|
)
|
|
45
57
|
if isinstance(schema, dict) and 'metadata' in schema:
|
|
46
58
|
sa_type = schema['metadata'].get('sa_type')
|
|
@@ -54,7 +66,7 @@ def _extract_sa_type_from_annotation(annotation: Any) -> Any | None:
|
|
|
54
66
|
try:
|
|
55
67
|
schema = annotation.__get_pydantic_core_schema__(
|
|
56
68
|
annotation,
|
|
57
|
-
|
|
69
|
+
_null_schema_handler,
|
|
58
70
|
)
|
|
59
71
|
if isinstance(schema, dict) and 'metadata' in schema:
|
|
60
72
|
sa_type = schema['metadata'].get('sa_type')
|
|
@@ -66,7 +78,7 @@ def _extract_sa_type_from_annotation(annotation: Any) -> Any | None:
|
|
|
66
78
|
return None
|
|
67
79
|
|
|
68
80
|
|
|
69
|
-
def
|
|
81
|
+
def resolve_annotations(attrs: dict[str, Any]) -> tuple[
|
|
70
82
|
dict[str, Any],
|
|
71
83
|
dict[str, str],
|
|
72
84
|
Mapping[str, Any],
|
|
@@ -112,7 +124,7 @@ def _resolve_annotations(attrs: dict[str, Any]) -> tuple[
|
|
|
112
124
|
return dict(evaluated), {}, module_globals, localns
|
|
113
125
|
|
|
114
126
|
|
|
115
|
-
def
|
|
127
|
+
def evaluate_annotation_from_string(
|
|
116
128
|
field_name: str,
|
|
117
129
|
annotation_strings: dict[str, str],
|
|
118
130
|
current_type: Any,
|
|
@@ -129,7 +141,7 @@ def _evaluate_annotation_from_string(
|
|
|
129
141
|
return current_type
|
|
130
142
|
|
|
131
143
|
expr = annotation_strings.get(field_name)
|
|
132
|
-
if not expr
|
|
144
|
+
if not expr:
|
|
133
145
|
return current_type
|
|
134
146
|
|
|
135
147
|
try:
|
sqlmodel_ext/_type_unwrap.py
CHANGED
|
@@ -17,7 +17,15 @@ from a ``response_model`` to its DTO / ORM classes).
|
|
|
17
17
|
"""
|
|
18
18
|
import types
|
|
19
19
|
import typing
|
|
20
|
-
from typing import Annotated, Any,
|
|
20
|
+
from typing import Annotated, Any, Final
|
|
21
|
+
|
|
22
|
+
# ``typing.Union`` as a runtime value: the ``get_origin()`` of ``Optional[X]`` /
|
|
23
|
+
# ``Union[X, Y]`` on Python < 3.14 (``X | Y`` has origin ``types.UnionType``).
|
|
24
|
+
# reportDeprecated targets spelling *annotations* with ``Union`` (use ``X | Y``);
|
|
25
|
+
# an identity-comparison target has no non-deprecated spelling, so the single
|
|
26
|
+
# reference lives here and every origin check in the package compares against
|
|
27
|
+
# this name (internal protocol, not part of the public API).
|
|
28
|
+
TYPING_UNION: Final = typing.Union # pyright: ignore[reportDeprecated]
|
|
21
29
|
|
|
22
30
|
|
|
23
31
|
def unwrap_to_class(hint: Any) -> type | None:
|
|
@@ -41,7 +49,7 @@ def unwrap_to_class(hint: Any) -> type | None:
|
|
|
41
49
|
return unwrap_to_class(args[0])
|
|
42
50
|
|
|
43
51
|
# X | None (UnionType) or Optional[X] (Union[X, None])
|
|
44
|
-
if origin is types.UnionType or origin is
|
|
52
|
+
if origin is types.UnionType or origin is TYPING_UNION:
|
|
45
53
|
args = typing.get_args(hint)
|
|
46
54
|
non_none = [a for a in args if a is not type(None)]
|
|
47
55
|
if len(non_none) == 1:
|