TypeDAL 5.1.1__tar.gz → 5.1.3__tar.gz
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.
- {typedal-5.1.1 → typedal-5.1.3}/PKG-INFO +1 -1
- {typedal-5.1.1 → typedal-5.1.3}/pyproject.toml +5 -2
- {typedal-5.1.1 → typedal-5.1.3}/pyproject.toml.orig +3 -2
- {typedal-5.1.1 → typedal-5.1.3}/src/typedal/cli.py +1 -1
- {typedal-5.1.1 → typedal-5.1.3}/src/typedal/core.py +27 -21
- {typedal-5.1.1 → typedal-5.1.3}/src/typedal/query_builder.py +11 -7
- {typedal-5.1.1 → typedal-5.1.3}/src/typedal/relationships.py +4 -2
- {typedal-5.1.1 → typedal-5.1.3}/src/typedal/rows.py +2 -3
- {typedal-5.1.1 → typedal-5.1.3}/src/typedal/serializers/typescript.py +1 -1
- {typedal-5.1.1 → typedal-5.1.3}/src/typedal/tables.py +1 -1
- {typedal-5.1.1 → typedal-5.1.3}/README.md +0 -0
- {typedal-5.1.1 → typedal-5.1.3}/src/typedal/__about__.py +0 -0
- {typedal-5.1.1 → typedal-5.1.3}/src/typedal/__init__.py +0 -0
- {typedal-5.1.1 → typedal-5.1.3}/src/typedal/asynchronous.py +0 -0
- {typedal-5.1.1 → typedal-5.1.3}/src/typedal/caching.py +0 -0
- {typedal-5.1.1 → typedal-5.1.3}/src/typedal/config.py +0 -0
- {typedal-5.1.1 → typedal-5.1.3}/src/typedal/constants.py +0 -0
- {typedal-5.1.1 → typedal-5.1.3}/src/typedal/define.py +0 -0
- {typedal-5.1.1 → typedal-5.1.3}/src/typedal/enum_helpers.py +0 -0
- {typedal-5.1.1 → typedal-5.1.3}/src/typedal/fields.py +0 -0
- {typedal-5.1.1 → typedal-5.1.3}/src/typedal/for_py4web.py +0 -0
- {typedal-5.1.1 → typedal-5.1.3}/src/typedal/for_web2py.py +0 -0
- {typedal-5.1.1 → typedal-5.1.3}/src/typedal/helpers.py +0 -0
- {typedal-5.1.1 → typedal-5.1.3}/src/typedal/mixins.py +0 -0
- {typedal-5.1.1 → typedal-5.1.3}/src/typedal/py.typed +0 -0
- {typedal-5.1.1 → typedal-5.1.3}/src/typedal/serializers/as_json.py +0 -0
- {typedal-5.1.1 → typedal-5.1.3}/src/typedal/types.py +0 -0
- {typedal-5.1.1 → typedal-5.1.3}/src/typedal/warnings.py +0 -0
- {typedal-5.1.1 → typedal-5.1.3}/src/typedal/web2py_py4web_shared.py +0 -0
|
@@ -6,7 +6,7 @@ build-backend = "uv_build"
|
|
|
6
6
|
name = "TypeDAL"
|
|
7
7
|
description = "Typing support for PyDAL"
|
|
8
8
|
readme = "README.md"
|
|
9
|
-
version = "5.1.
|
|
9
|
+
version = "5.1.3"
|
|
10
10
|
requires-python = ">=3.12"
|
|
11
11
|
license-expression = "MIT"
|
|
12
12
|
keywords = []
|
|
@@ -226,7 +226,10 @@ extend-ignore = [
|
|
|
226
226
|
"D212",
|
|
227
227
|
"D418",
|
|
228
228
|
]
|
|
229
|
-
ignore = [
|
|
229
|
+
ignore = [
|
|
230
|
+
"RUF012",
|
|
231
|
+
"RUF013",
|
|
232
|
+
]
|
|
230
233
|
|
|
231
234
|
[tool.ruff.lint.pydocstyle]
|
|
232
235
|
convention = "google"
|
|
@@ -6,7 +6,7 @@ build-backend = "uv_build"
|
|
|
6
6
|
name = "TypeDAL"
|
|
7
7
|
description = 'Typing support for PyDAL'
|
|
8
8
|
readme = "README.md"
|
|
9
|
-
version = "5.1.
|
|
9
|
+
version = "5.1.3"
|
|
10
10
|
requires-python = ">=3.12"
|
|
11
11
|
license-expression = "MIT"
|
|
12
12
|
keywords = []
|
|
@@ -270,7 +270,8 @@ extend-ignore = [
|
|
|
270
270
|
]
|
|
271
271
|
|
|
272
272
|
ignore = [
|
|
273
|
-
"
|
|
273
|
+
"RUF012", # mutable class attributes
|
|
274
|
+
"RUF013", # implicit optional
|
|
274
275
|
]
|
|
275
276
|
|
|
276
277
|
|
|
@@ -227,7 +227,7 @@ def setup(
|
|
|
227
227
|
data.pop("connection", None)
|
|
228
228
|
|
|
229
229
|
# ignore any None:
|
|
230
|
-
old_contents["tool"]["typedal"] = {k: v for k, v in data.items() if v is not None}
|
|
230
|
+
old_contents["tool"]["typedal"] = {k: v for k, v in data.items() if v is not None}
|
|
231
231
|
|
|
232
232
|
with toml_path.open("w") as f:
|
|
233
233
|
tomlkit.dump(old_contents, f)
|
|
@@ -34,7 +34,7 @@ from .helpers import (
|
|
|
34
34
|
from .serializers.typescript import TypedDictRegistry
|
|
35
35
|
|
|
36
36
|
# noinspection PyUnusedImports
|
|
37
|
-
from .types import CacheStatus, Field, Template
|
|
37
|
+
from .types import CacheStatus, Expression, Field, Template
|
|
38
38
|
|
|
39
39
|
try:
|
|
40
40
|
# python 3.14+
|
|
@@ -46,10 +46,10 @@ except ImportError: # pragma: no cover
|
|
|
46
46
|
if t.TYPE_CHECKING:
|
|
47
47
|
from .fields import TypedField
|
|
48
48
|
from .query_builder import QueryBuilder
|
|
49
|
-
from .types import AnyDict, DefineKwargs,
|
|
49
|
+
from .types import AnyDict, DefineKwargs, Rows, Set, T_Query, Table
|
|
50
50
|
|
|
51
51
|
|
|
52
|
-
def _expression_subclasses() -> t.Iterator[type]:
|
|
52
|
+
def _expression_subclasses() -> t.Iterator[type[Expression]]:
|
|
53
53
|
"""
|
|
54
54
|
Yield Expression and every (nested) subclass currently loaded, e.g. Field and TypedField.
|
|
55
55
|
"""
|
|
@@ -100,7 +100,7 @@ def _purge_dialect_expressions(adapter: t.Any) -> None:
|
|
|
100
100
|
# because then they will have different globals and it breaks!
|
|
101
101
|
|
|
102
102
|
|
|
103
|
-
def evaluate_forward_reference_312(fw_ref: ForwardRef, namespace:
|
|
103
|
+
def evaluate_forward_reference_312(fw_ref: ForwardRef, namespace: t.Mapping[str, type]) -> type: # pragma: no cover
|
|
104
104
|
"""
|
|
105
105
|
Extract the original type from a forward reference string.
|
|
106
106
|
|
|
@@ -110,13 +110,13 @@ def evaluate_forward_reference_312(fw_ref: ForwardRef, namespace: dict[str, type
|
|
|
110
110
|
type,
|
|
111
111
|
fw_ref._evaluate( # ty: ignore[deprecated]
|
|
112
112
|
localns=locals(),
|
|
113
|
-
globalns=globals() | namespace,
|
|
113
|
+
globalns=globals() | dict(namespace),
|
|
114
114
|
recursive_guard=frozenset(),
|
|
115
115
|
),
|
|
116
116
|
)
|
|
117
117
|
|
|
118
118
|
|
|
119
|
-
def evaluate_forward_reference_313(fw_ref: ForwardRef, namespace:
|
|
119
|
+
def evaluate_forward_reference_313(fw_ref: ForwardRef, namespace: t.Mapping[str, type]) -> type: # pragma: no cover
|
|
120
120
|
"""
|
|
121
121
|
Extract the original type from a forward reference string.
|
|
122
122
|
|
|
@@ -126,14 +126,14 @@ def evaluate_forward_reference_313(fw_ref: ForwardRef, namespace: dict[str, type
|
|
|
126
126
|
type,
|
|
127
127
|
fw_ref._evaluate( # ty: ignore[deprecated]
|
|
128
128
|
localns=locals(),
|
|
129
|
-
globalns=globals() | namespace,
|
|
129
|
+
globalns=globals() | dict(namespace),
|
|
130
130
|
recursive_guard=frozenset(),
|
|
131
131
|
type_params=(), # suggested since 3.13 (warning) and not supported before. Mandatory after 1.15!
|
|
132
132
|
),
|
|
133
133
|
)
|
|
134
134
|
|
|
135
135
|
|
|
136
|
-
def evaluate_forward_reference_314(fw_ref: ForwardRef, namespace:
|
|
136
|
+
def evaluate_forward_reference_314(fw_ref: ForwardRef, namespace: t.Mapping[str, type]) -> type: # pragma: no cover
|
|
137
137
|
"""
|
|
138
138
|
Extract the original type from a forward reference string.
|
|
139
139
|
|
|
@@ -143,7 +143,7 @@ def evaluate_forward_reference_314(fw_ref: ForwardRef, namespace: dict[str, type
|
|
|
143
143
|
type,
|
|
144
144
|
fw_ref.evaluate(
|
|
145
145
|
locals=locals(),
|
|
146
|
-
globals=globals() | namespace,
|
|
146
|
+
globals=globals() | dict(namespace),
|
|
147
147
|
type_params=(),
|
|
148
148
|
),
|
|
149
149
|
)
|
|
@@ -151,7 +151,7 @@ def evaluate_forward_reference_314(fw_ref: ForwardRef, namespace: dict[str, type
|
|
|
151
151
|
|
|
152
152
|
def evaluate_forward_reference(
|
|
153
153
|
fw_ref: ForwardRef,
|
|
154
|
-
namespace:
|
|
154
|
+
namespace: t.Mapping[str, type] | None = None,
|
|
155
155
|
) -> type: # pragma: no cover
|
|
156
156
|
"""
|
|
157
157
|
Extract the original type from a forward reference string.
|
|
@@ -166,7 +166,7 @@ def evaluate_forward_reference(
|
|
|
166
166
|
return evaluate_forward_reference_314(fw_ref, namespace=namespace or {})
|
|
167
167
|
|
|
168
168
|
|
|
169
|
-
def resolve_annotation_313(ftype: str, namespace:
|
|
169
|
+
def resolve_annotation_313(ftype: str, namespace: t.Mapping[str, type] | None = None) -> type: # pragma: no cover
|
|
170
170
|
"""
|
|
171
171
|
Resolve an annotation that's in string representation.
|
|
172
172
|
|
|
@@ -176,7 +176,7 @@ def resolve_annotation_313(ftype: str, namespace: dict[str, type] | None = None)
|
|
|
176
176
|
return evaluate_forward_reference(fw_ref, namespace=namespace)
|
|
177
177
|
|
|
178
178
|
|
|
179
|
-
def resolve_annotation_314(ftype: str, namespace:
|
|
179
|
+
def resolve_annotation_314(ftype: str, namespace: t.Mapping[str, type] | None = None) -> type: # pragma: no cover
|
|
180
180
|
"""
|
|
181
181
|
Resolve an annotation that's in string representation.
|
|
182
182
|
|
|
@@ -186,7 +186,7 @@ def resolve_annotation_314(ftype: str, namespace: dict[str, type] | None = None)
|
|
|
186
186
|
return evaluate_forward_reference(fw_ref, namespace=namespace)
|
|
187
187
|
|
|
188
188
|
|
|
189
|
-
def resolve_annotation(ftype: str, namespace:
|
|
189
|
+
def resolve_annotation(ftype: str, namespace: t.Mapping[str, type] | None = None) -> type: # pragma: no cover
|
|
190
190
|
"""
|
|
191
191
|
Resolve an annotation that's in string representation.
|
|
192
192
|
|
|
@@ -202,15 +202,17 @@ def resolve_annotation(ftype: str, namespace: dict[str, type] | None = None) ->
|
|
|
202
202
|
|
|
203
203
|
if t.TYPE_CHECKING:
|
|
204
204
|
|
|
205
|
-
class _TypeDALBase:
|
|
205
|
+
class _TypeDALBase(pydal.DAL):
|
|
206
206
|
# attributes accessed throughout the codebase
|
|
207
207
|
_adapter: t.Any
|
|
208
208
|
_migrate: t.Any
|
|
209
209
|
representers: t.Any
|
|
210
210
|
|
|
211
|
+
def __new__(cls, *args: t.Any, **kwargs: t.Any) -> t.Self: ...
|
|
212
|
+
|
|
211
213
|
def __init__(self, *args: t.Any, **kwargs: t.Any) -> None: ...
|
|
212
214
|
|
|
213
|
-
def __call__(self, query: t.Any = None) -> "Set": ...
|
|
215
|
+
def __call__(self, query: t.Any = None, ignore_common_filters: t.Any = None) -> "Set": ...
|
|
214
216
|
|
|
215
217
|
def commit(self) -> None: ...
|
|
216
218
|
|
|
@@ -218,11 +220,15 @@ if t.TYPE_CHECKING:
|
|
|
218
220
|
|
|
219
221
|
def define_table(self, *args: t.Any, **kwargs: t.Any) -> "Table": ...
|
|
220
222
|
|
|
221
|
-
|
|
223
|
+
# pydal ships no py.typed, so without this declaration the result would be Any for mypy users.
|
|
224
|
+
# pyright infers `TypeIs[...]` from pydal's `return callable(...)`, which `bool` can't restate.
|
|
225
|
+
def has_representer(self, name: str) -> bool: ... # pyright: ignore[reportIncompatibleMethodOverride]
|
|
226
|
+
|
|
227
|
+
def represent(self, name: str, *args: t.Any, **kwargs: t.Any) -> str: ...
|
|
222
228
|
|
|
223
229
|
# pydal exposes dynamic table attributes like `db.my_table`.
|
|
224
230
|
# this keeps type checkers from flagging these as missing attributes.
|
|
225
|
-
def __getattr__(self,
|
|
231
|
+
def __getattr__(self, key: str) -> "Table": ...
|
|
226
232
|
|
|
227
233
|
else:
|
|
228
234
|
|
|
@@ -249,7 +255,7 @@ class TypeDAL(_TypeDALBase):
|
|
|
249
255
|
_async_workers: ConnectionWorkerPool
|
|
250
256
|
|
|
251
257
|
# pydal runs these around every statement; drop BlockingAccessHandler to disable the guard.
|
|
252
|
-
execution_handlers:
|
|
258
|
+
execution_handlers: list[type[ExecutionHandler]] = [
|
|
253
259
|
*pydal.DAL.execution_handlers,
|
|
254
260
|
BlockingAccessHandler,
|
|
255
261
|
]
|
|
@@ -417,7 +423,7 @@ class TypeDAL(_TypeDALBase):
|
|
|
417
423
|
self._async_workers.shutdown()
|
|
418
424
|
adapter = self._adapter
|
|
419
425
|
try:
|
|
420
|
-
super().close()
|
|
426
|
+
super().close()
|
|
421
427
|
finally:
|
|
422
428
|
for model in set(self._builder.class_map.values()):
|
|
423
429
|
model.unbind()
|
|
@@ -582,7 +588,7 @@ class TypeDAL(_TypeDALBase):
|
|
|
582
588
|
Example:
|
|
583
589
|
db['users'] -> user
|
|
584
590
|
"""
|
|
585
|
-
return t.cast(Table, super().__getitem__(str(key)))
|
|
591
|
+
return t.cast(Table, super().__getitem__(str(key)))
|
|
586
592
|
|
|
587
593
|
def find_model(self, table_name: str) -> t.Type["TypedTable"] | None:
|
|
588
594
|
"""
|
|
@@ -662,7 +668,7 @@ class TypeDAL(_TypeDALBase):
|
|
|
662
668
|
if SYSTEM_SUPPORTS_TEMPLATES and isinstance(query, Template): # pragma: no cover
|
|
663
669
|
query = sql_escape_template(self, query)
|
|
664
670
|
|
|
665
|
-
rows: list[t.Any] = super().executesql(
|
|
671
|
+
rows: list[t.Any] = super().executesql(
|
|
666
672
|
query,
|
|
667
673
|
placeholders=placeholders,
|
|
668
674
|
as_dict=as_dict,
|
|
@@ -187,7 +187,7 @@ class QueryBuilder[T_MetaInstance: _TypedTable](Select):
|
|
|
187
187
|
"""
|
|
188
188
|
Return a clone of this builder with permission overrides merged in.
|
|
189
189
|
"""
|
|
190
|
-
if not permissions and self:
|
|
190
|
+
if not permissions and self: # ty: ignore[redundant-condition]
|
|
191
191
|
warn_noop("permissions")
|
|
192
192
|
return self
|
|
193
193
|
|
|
@@ -1299,7 +1299,8 @@ class QueryBuilder[T_MetaInstance: _TypedTable](Select):
|
|
|
1299
1299
|
def __count(
|
|
1300
1300
|
self,
|
|
1301
1301
|
db: TypeDAL,
|
|
1302
|
-
distinct: t.
|
|
1302
|
+
distinct: bool | Field | TypedField[t.Any] = False,
|
|
1303
|
+
*,
|
|
1303
1304
|
include_left_for_distinct: bool = True,
|
|
1304
1305
|
) -> Query:
|
|
1305
1306
|
# internal, shared logic between .count and ._count
|
|
@@ -1323,9 +1324,11 @@ class QueryBuilder[T_MetaInstance: _TypedTable](Select):
|
|
|
1323
1324
|
|
|
1324
1325
|
return query
|
|
1325
1326
|
|
|
1326
|
-
def count(self, distinct: t.
|
|
1327
|
+
def count(self, distinct: bool | Field | TypedField[t.Any] = False) -> int:
|
|
1327
1328
|
"""
|
|
1328
1329
|
Return the amount of rows matching the current query.
|
|
1330
|
+
|
|
1331
|
+
Passing a field counts its distinct values.
|
|
1329
1332
|
"""
|
|
1330
1333
|
require_permission(self._permissions, "read")
|
|
1331
1334
|
db = self._get_db()
|
|
@@ -1333,7 +1336,7 @@ class QueryBuilder[T_MetaInstance: _TypedTable](Select):
|
|
|
1333
1336
|
|
|
1334
1337
|
return db(query).count(distinct)
|
|
1335
1338
|
|
|
1336
|
-
def _count(self, distinct: t.
|
|
1339
|
+
def _count(self, distinct: bool | Field | TypedField[t.Any] = False) -> str:
|
|
1337
1340
|
"""
|
|
1338
1341
|
Return the SQL for .count().
|
|
1339
1342
|
"""
|
|
@@ -1359,8 +1362,9 @@ class QueryBuilder[T_MetaInstance: _TypedTable](Select):
|
|
|
1359
1362
|
return self.count()
|
|
1360
1363
|
|
|
1361
1364
|
db = self._get_db()
|
|
1362
|
-
|
|
1363
|
-
|
|
1365
|
+
distinct = t.cast(TypedField[int], self.model.id)
|
|
1366
|
+
query = self.__count(db, distinct=distinct, include_left_for_distinct=False)
|
|
1367
|
+
return db(query).count(distinct)
|
|
1364
1368
|
|
|
1365
1369
|
def __paginate(
|
|
1366
1370
|
self,
|
|
@@ -1554,7 +1558,7 @@ class QueryBuilder[T_MetaInstance: _TypedTable](Select):
|
|
|
1554
1558
|
column = t.cast(t.Callable[..., list[T]], self.column)
|
|
1555
1559
|
return await run_async(self._get_db(), column, field, **options)
|
|
1556
1560
|
|
|
1557
|
-
async def count_async(self, distinct: t.
|
|
1561
|
+
async def count_async(self, distinct: bool | Field | TypedField[t.Any] = False) -> int:
|
|
1558
1562
|
"""
|
|
1559
1563
|
Async twin of `count()`.
|
|
1560
1564
|
"""
|
|
@@ -253,10 +253,12 @@ class Relationship[To_Type]:
|
|
|
253
253
|
# relationship queried on class, that's allowed
|
|
254
254
|
return self
|
|
255
255
|
|
|
256
|
+
db = instance._db
|
|
257
|
+
|
|
256
258
|
# instance: TypedTable instance
|
|
257
259
|
# owner: TypedTable class
|
|
258
260
|
|
|
259
|
-
if not self.name: # pragma: no cover
|
|
261
|
+
if not (self.name and db): # pragma: no cover
|
|
260
262
|
raise ValueError("Relationship does not seem to be connected to a table field.")
|
|
261
263
|
|
|
262
264
|
# Handle different lazy policies
|
|
@@ -284,7 +286,7 @@ class Relationship[To_Type]:
|
|
|
284
286
|
|
|
285
287
|
# For "tolerate" and "allow", we fetch the data
|
|
286
288
|
try:
|
|
287
|
-
resolved_table = self.get_table(
|
|
289
|
+
resolved_table = self.get_table(db)
|
|
288
290
|
|
|
289
291
|
builder = owner.where(id=instance.id).join(self.name)
|
|
290
292
|
if issubclass(resolved_table, TypedTable) or isinstance(resolved_table, Table):
|
|
@@ -10,6 +10,7 @@ import typing as t
|
|
|
10
10
|
|
|
11
11
|
from .asynchronous import run_async
|
|
12
12
|
from .core import TypeDAL
|
|
13
|
+
from .fields import TypedField
|
|
13
14
|
from .helpers import mktable
|
|
14
15
|
from .query_builder import QueryBuilder
|
|
15
16
|
from .serializers import as_json
|
|
@@ -563,7 +564,7 @@ class TypedSet(Set): # pragma: no cover
|
|
|
563
564
|
This class is not actually used, only 'cast' by TypeDAL.__call__
|
|
564
565
|
"""
|
|
565
566
|
|
|
566
|
-
def count(self, distinct: bool |
|
|
567
|
+
def count(self, distinct: bool | Field | TypedField[t.Any] = False, cache: AnyDict | None = None) -> int:
|
|
567
568
|
"""
|
|
568
569
|
Count returns an int.
|
|
569
570
|
"""
|
|
@@ -585,5 +586,3 @@ class TypedSet(Set): # pragma: no cover
|
|
|
585
586
|
|
|
586
587
|
|
|
587
588
|
# note: these imports exist at the bottom of this file to prevent circular import issues:
|
|
588
|
-
|
|
589
|
-
from .fields import TypedField # noqa: E402
|
|
@@ -31,7 +31,7 @@ class TypedDictRegistry(Singleton):
|
|
|
31
31
|
def __init__(self) -> None:
|
|
32
32
|
"""Initialize the singleton registry and optional shared typtyp world."""
|
|
33
33
|
self._types: dict[type, type[dict[str, t.Any]]] = {}
|
|
34
|
-
self._world = typtyp.World() if typtyp else None #
|
|
34
|
+
self._world = typtyp.World() if typtyp else None # ty: ignore[redundant-condition]
|
|
35
35
|
self._names: set[str] = set()
|
|
36
36
|
|
|
37
37
|
@property
|
|
@@ -1152,7 +1152,7 @@ class TypedTable(_TypedTable, metaclass=TableMeta):
|
|
|
1152
1152
|
"after_delete": cls._after_delete,
|
|
1153
1153
|
}
|
|
1154
1154
|
|
|
1155
|
-
def _setup_instance_methods(self) -> None:
|
|
1155
|
+
def _setup_instance_methods(self: t.Self | type[t.Self]) -> None:
|
|
1156
1156
|
# use setattr instead of self.x = y to make the typecheckers happier
|
|
1157
1157
|
setattr(self, "as_dict", self._as_dict)
|
|
1158
1158
|
setattr(self, "__json__", self._as_json)
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|