TypeDAL 5.1.2__tar.gz → 5.1.4__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.2 → typedal-5.1.4}/PKG-INFO +2 -1
- {typedal-5.1.2 → typedal-5.1.4}/pyproject.toml +6 -2
- {typedal-5.1.2 → typedal-5.1.4}/pyproject.toml.orig +4 -2
- {typedal-5.1.2 → typedal-5.1.4}/src/typedal/cli.py +1 -1
- {typedal-5.1.2 → typedal-5.1.4}/src/typedal/core.py +13 -37
- {typedal-5.1.2 → typedal-5.1.4}/src/typedal/define.py +1 -1
- {typedal-5.1.2 → typedal-5.1.4}/src/typedal/fields.py +2 -2
- {typedal-5.1.2 → typedal-5.1.4}/src/typedal/helpers.py +1 -1
- {typedal-5.1.2 → typedal-5.1.4}/src/typedal/query_builder.py +9 -6
- {typedal-5.1.2 → typedal-5.1.4}/src/typedal/rows.py +20 -11
- {typedal-5.1.2 → typedal-5.1.4}/src/typedal/tables.py +10 -8
- {typedal-5.1.2 → typedal-5.1.4}/src/typedal/types.py +12 -72
- {typedal-5.1.2 → typedal-5.1.4}/README.md +0 -0
- {typedal-5.1.2 → typedal-5.1.4}/src/typedal/__about__.py +0 -0
- {typedal-5.1.2 → typedal-5.1.4}/src/typedal/__init__.py +0 -0
- {typedal-5.1.2 → typedal-5.1.4}/src/typedal/asynchronous.py +0 -0
- {typedal-5.1.2 → typedal-5.1.4}/src/typedal/caching.py +0 -0
- {typedal-5.1.2 → typedal-5.1.4}/src/typedal/config.py +0 -0
- {typedal-5.1.2 → typedal-5.1.4}/src/typedal/constants.py +0 -0
- {typedal-5.1.2 → typedal-5.1.4}/src/typedal/enum_helpers.py +0 -0
- {typedal-5.1.2 → typedal-5.1.4}/src/typedal/for_py4web.py +0 -0
- {typedal-5.1.2 → typedal-5.1.4}/src/typedal/for_web2py.py +0 -0
- {typedal-5.1.2 → typedal-5.1.4}/src/typedal/mixins.py +0 -0
- {typedal-5.1.2 → typedal-5.1.4}/src/typedal/py.typed +0 -0
- {typedal-5.1.2 → typedal-5.1.4}/src/typedal/relationships.py +0 -0
- {typedal-5.1.2 → typedal-5.1.4}/src/typedal/serializers/as_json.py +0 -0
- {typedal-5.1.2 → typedal-5.1.4}/src/typedal/serializers/typescript.py +0 -0
- {typedal-5.1.2 → typedal-5.1.4}/src/typedal/warnings.py +0 -0
- {typedal-5.1.2 → typedal-5.1.4}/src/typedal/web2py_py4web_shared.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.3
|
|
2
2
|
Name: TypeDAL
|
|
3
|
-
Version: 5.1.
|
|
3
|
+
Version: 5.1.4
|
|
4
4
|
Summary: Typing support for PyDAL
|
|
5
5
|
Keywords:
|
|
6
6
|
Author: Robin van der Noord
|
|
@@ -13,6 +13,7 @@ Classifier: Programming Language :: Python :: 3.14
|
|
|
13
13
|
Classifier: Programming Language :: Python :: Implementation :: CPython
|
|
14
14
|
Classifier: Programming Language :: Python :: Implementation :: PyPy
|
|
15
15
|
Requires-Dist: pydal>=20251012.3
|
|
16
|
+
Requires-Dist: pydal-stubs>=0.1.0
|
|
16
17
|
Requires-Dist: dill<1
|
|
17
18
|
Requires-Dist: configuraptor>=2.1.0,<3
|
|
18
19
|
Requires-Dist: configurable-json<2
|
|
@@ -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.4"
|
|
10
10
|
requires-python = ">=3.12"
|
|
11
11
|
license-expression = "MIT"
|
|
12
12
|
keywords = []
|
|
@@ -21,6 +21,7 @@ classifiers = [
|
|
|
21
21
|
]
|
|
22
22
|
dependencies = [
|
|
23
23
|
"pydal >= 20251012.3",
|
|
24
|
+
"pydal-stubs >= 0.1.0",
|
|
24
25
|
"dill < 1",
|
|
25
26
|
"configuraptor >= 2.1.0, < 3",
|
|
26
27
|
"Configurable-JSON < 2",
|
|
@@ -226,7 +227,10 @@ extend-ignore = [
|
|
|
226
227
|
"D212",
|
|
227
228
|
"D418",
|
|
228
229
|
]
|
|
229
|
-
ignore = [
|
|
230
|
+
ignore = [
|
|
231
|
+
"RUF012",
|
|
232
|
+
"RUF013",
|
|
233
|
+
]
|
|
230
234
|
|
|
231
235
|
[tool.ruff.lint.pydocstyle]
|
|
232
236
|
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.4"
|
|
10
10
|
requires-python = ">=3.12"
|
|
11
11
|
license-expression = "MIT"
|
|
12
12
|
keywords = []
|
|
@@ -24,6 +24,7 @@ classifiers = [
|
|
|
24
24
|
]
|
|
25
25
|
dependencies = [
|
|
26
26
|
"pydal >= 20251012.3", # core
|
|
27
|
+
"pydal-stubs >= 0.1.0", # improved typing for pydal
|
|
27
28
|
"dill < 1", # caching
|
|
28
29
|
"configuraptor >= 2.1.0, < 3", # config
|
|
29
30
|
"Configurable-JSON < 2", # json dumping
|
|
@@ -270,7 +271,8 @@ extend-ignore = [
|
|
|
270
271
|
]
|
|
271
272
|
|
|
272
273
|
ignore = [
|
|
273
|
-
"
|
|
274
|
+
"RUF012", # mutable class attributes
|
|
275
|
+
"RUF013", # implicit optional
|
|
274
276
|
]
|
|
275
277
|
|
|
276
278
|
|
|
@@ -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} # type: ignore
|
|
231
231
|
|
|
232
232
|
with toml_path.open("w") as f:
|
|
233
233
|
tomlkit.dump(old_contents, f)
|
|
@@ -46,7 +46,7 @@ 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, Rows,
|
|
49
|
+
from .types import AnyDict, DefineKwargs, Rows, T_Query, Table
|
|
50
50
|
|
|
51
51
|
|
|
52
52
|
def _expression_subclasses() -> t.Iterator[type[Expression]]:
|
|
@@ -200,36 +200,8 @@ def resolve_annotation(ftype: str, namespace: t.Mapping[str, type] | None = None
|
|
|
200
200
|
return resolve_annotation_314(ftype, namespace=namespace)
|
|
201
201
|
|
|
202
202
|
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
class _TypeDALBase:
|
|
206
|
-
# attributes accessed throughout the codebase
|
|
207
|
-
_adapter: t.Any
|
|
208
|
-
_migrate: t.Any
|
|
209
|
-
representers: t.Any
|
|
210
|
-
|
|
211
|
-
def __init__(self, *args: t.Any, **kwargs: t.Any) -> None: ...
|
|
212
|
-
|
|
213
|
-
def __call__(self, query: t.Any = None) -> "Set": ...
|
|
214
|
-
|
|
215
|
-
def commit(self) -> None: ...
|
|
216
|
-
|
|
217
|
-
def rollback(self) -> None: ...
|
|
218
|
-
|
|
219
|
-
def define_table(self, *args: t.Any, **kwargs: t.Any) -> "Table": ...
|
|
220
|
-
|
|
221
|
-
def has_representer(self, field_type: str) -> bool: ...
|
|
222
|
-
|
|
223
|
-
def represent(self, name: str, *args: t.Any, **kwargs: t.Any) -> str: ...
|
|
224
|
-
|
|
225
|
-
# pydal exposes dynamic table attributes like `db.my_table`.
|
|
226
|
-
# this keeps type checkers from flagging these as missing attributes.
|
|
227
|
-
def __getattr__(self, item: str) -> "Table": ...
|
|
228
|
-
|
|
229
|
-
else:
|
|
230
|
-
|
|
231
|
-
class _TypeDALBase(pydal.DAL):
|
|
232
|
-
pass
|
|
203
|
+
class _TypeDALBase(pydal.DAL):
|
|
204
|
+
pass
|
|
233
205
|
|
|
234
206
|
|
|
235
207
|
class TypeDAL(_TypeDALBase):
|
|
@@ -251,7 +223,7 @@ class TypeDAL(_TypeDALBase):
|
|
|
251
223
|
_async_workers: ConnectionWorkerPool
|
|
252
224
|
|
|
253
225
|
# pydal runs these around every statement; drop BlockingAccessHandler to disable the guard.
|
|
254
|
-
execution_handlers:
|
|
226
|
+
execution_handlers: list[type[ExecutionHandler]] = [
|
|
255
227
|
*pydal.DAL.execution_handlers,
|
|
256
228
|
BlockingAccessHandler,
|
|
257
229
|
]
|
|
@@ -419,7 +391,7 @@ class TypeDAL(_TypeDALBase):
|
|
|
419
391
|
self._async_workers.shutdown()
|
|
420
392
|
adapter = self._adapter
|
|
421
393
|
try:
|
|
422
|
-
super().close()
|
|
394
|
+
super().close()
|
|
423
395
|
finally:
|
|
424
396
|
for model in set(self._builder.class_map.values()):
|
|
425
397
|
model.unbind()
|
|
@@ -447,7 +419,9 @@ class TypeDAL(_TypeDALBase):
|
|
|
447
419
|
hooks.clear()
|
|
448
420
|
|
|
449
421
|
if hasattr(table, "_db"):
|
|
450
|
-
|
|
422
|
+
# outside pydal's contract: pydal only ever nulls a *field's*
|
|
423
|
+
# bindings, but the cycle has to be broken here too.
|
|
424
|
+
table._db = None # ty: ignore[invalid-assignment]
|
|
451
425
|
|
|
452
426
|
for field_name in getattr(table, "fields", ()):
|
|
453
427
|
field: Field | None = getattr(table, field_name, None)
|
|
@@ -561,7 +535,9 @@ class TypeDAL(_TypeDALBase):
|
|
|
561
535
|
db(query).select()
|
|
562
536
|
|
|
563
537
|
"""
|
|
564
|
-
|
|
538
|
+
# heterogeneous on purpose: this list is splatted across pydal's
|
|
539
|
+
# (query, ignore_common_filters) parameters.
|
|
540
|
+
args: list[t.Any] = list(_args)
|
|
565
541
|
if args:
|
|
566
542
|
cls = args[0]
|
|
567
543
|
if isinstance(cls, bool):
|
|
@@ -584,7 +560,7 @@ class TypeDAL(_TypeDALBase):
|
|
|
584
560
|
Example:
|
|
585
561
|
db['users'] -> user
|
|
586
562
|
"""
|
|
587
|
-
return
|
|
563
|
+
return super().__getitem__(str(key))
|
|
588
564
|
|
|
589
565
|
def find_model(self, table_name: str) -> t.Type["TypedTable"] | None:
|
|
590
566
|
"""
|
|
@@ -664,7 +640,7 @@ class TypeDAL(_TypeDALBase):
|
|
|
664
640
|
if SYSTEM_SUPPORTS_TEMPLATES and isinstance(query, Template): # pragma: no cover
|
|
665
641
|
query = sql_escape_template(self, query)
|
|
666
642
|
|
|
667
|
-
rows: list[t.Any] = super().executesql(
|
|
643
|
+
rows: list[t.Any] = super().executesql(
|
|
668
644
|
query,
|
|
669
645
|
placeholders=placeholders,
|
|
670
646
|
as_dict=as_dict,
|
|
@@ -133,7 +133,7 @@ class TableDefinitionBuilder:
|
|
|
133
133
|
|
|
134
134
|
table._after_insert.append(lambda _row, _id: remove_cache_for_table(tablename))
|
|
135
135
|
table._before_update.append(lambda s, _: _remove_cache(s, tablename))
|
|
136
|
-
table._before_delete.append(lambda s: _remove_cache(s, tablename))
|
|
136
|
+
table._before_delete.append(lambda s: _remove_cache(s, tablename))
|
|
137
137
|
|
|
138
138
|
return cls
|
|
139
139
|
|
|
@@ -268,7 +268,7 @@ class TypedField[T_Value](Expression): # pragma: no cover
|
|
|
268
268
|
if not self._field: # pragma: no cover
|
|
269
269
|
raise ValueError("Unbound Field can not be inverted!")
|
|
270
270
|
|
|
271
|
-
return
|
|
271
|
+
return ~self._field
|
|
272
272
|
|
|
273
273
|
def lower(self) -> Expression:
|
|
274
274
|
"""
|
|
@@ -277,7 +277,7 @@ class TypedField[T_Value](Expression): # pragma: no cover
|
|
|
277
277
|
if not self._field: # pragma: no cover
|
|
278
278
|
raise ValueError("Unbound Field can not be lowered!")
|
|
279
279
|
|
|
280
|
-
return
|
|
280
|
+
return self._field.lower()
|
|
281
281
|
|
|
282
282
|
|
|
283
283
|
def rname(field: TypedField[t.Any] | Field) -> str:
|
|
@@ -311,7 +311,7 @@ def get_table(table: "TypedTable | Table") -> "Table":
|
|
|
311
311
|
"""
|
|
312
312
|
Get the underlying pydal table for a typedal table.
|
|
313
313
|
"""
|
|
314
|
-
return t.cast("Table", table._table)
|
|
314
|
+
return t.cast("Table", table._table)
|
|
315
315
|
|
|
316
316
|
|
|
317
317
|
def get_field(field: "TypedField[t.Any] | Field") -> "Field":
|
|
@@ -111,7 +111,7 @@ class QueryBuilder[T_MetaInstance: _TypedTable](Select):
|
|
|
111
111
|
"""
|
|
112
112
|
self.model = model
|
|
113
113
|
table = self._ensure_table_defined()
|
|
114
|
-
default_query: Query =
|
|
114
|
+
default_query: Query = table.id > 0
|
|
115
115
|
self.query = add_query or default_query
|
|
116
116
|
self.select_args = select_args or []
|
|
117
117
|
self.select_kwargs = select_kwargs or {}
|
|
@@ -152,7 +152,7 @@ class QueryBuilder[T_MetaInstance: _TypedTable](Select):
|
|
|
152
152
|
Querybuilder is truthy if it has t.Any conditions.
|
|
153
153
|
"""
|
|
154
154
|
table = self._ensure_table_defined()
|
|
155
|
-
default_query: Query =
|
|
155
|
+
default_query: Query = table.id > 0
|
|
156
156
|
return any(
|
|
157
157
|
[
|
|
158
158
|
self.query != default_query,
|
|
@@ -330,13 +330,14 @@ class QueryBuilder[T_MetaInstance: _TypedTable](Select):
|
|
|
330
330
|
subquery |= t.cast(Query, query_part)
|
|
331
331
|
elif callable(query_part):
|
|
332
332
|
if result := query_part(self.model):
|
|
333
|
-
subquery |= result
|
|
333
|
+
subquery |= t.cast(Query, result)
|
|
334
334
|
elif isinstance(query_part, dict):
|
|
335
335
|
subsubquery = DummyQuery()
|
|
336
336
|
for field, value in query_part.items():
|
|
337
337
|
subsubquery &= table[field] == value
|
|
338
338
|
if subsubquery:
|
|
339
|
-
|
|
339
|
+
# DummyQuery is falsy, so reaching here means it became a Query.
|
|
340
|
+
subquery |= t.cast(Query, subsubquery)
|
|
340
341
|
else:
|
|
341
342
|
raise ValueError(f"Unexpected query type ({type(query_part)}).")
|
|
342
343
|
|
|
@@ -559,7 +560,9 @@ class QueryBuilder[T_MetaInstance: _TypedTable](Select):
|
|
|
559
560
|
db = self._get_db()
|
|
560
561
|
return str(db(self.query)._delete())
|
|
561
562
|
|
|
562
|
-
|
|
563
|
+
# QueryBuilder subclasses Select for its query-building surface but yields
|
|
564
|
+
# model instances rather than fields, so these two are not substitutable.
|
|
565
|
+
def update(self, **fields: t.Any) -> list[int]: # ty: ignore[invalid-method-override]
|
|
563
566
|
"""
|
|
564
567
|
Based on the current query, update `fields` and return a list of updated IDs.
|
|
565
568
|
"""
|
|
@@ -1262,7 +1265,7 @@ class QueryBuilder[T_MetaInstance: _TypedTable](Select):
|
|
|
1262
1265
|
"""
|
|
1263
1266
|
return self.collect() or throw(exception or ValueError("Nothing found!"))
|
|
1264
1267
|
|
|
1265
|
-
def __iter__(self) -> t.Generator[T_MetaInstance, None, None]:
|
|
1268
|
+
def __iter__(self) -> t.Generator[T_MetaInstance, None, None]: # ty: ignore[invalid-method-override]
|
|
1266
1269
|
"""
|
|
1267
1270
|
You can start iterating a Query Builder object before calling collect, for ease of use.
|
|
1268
1271
|
"""
|
|
@@ -106,7 +106,10 @@ class TypedRows(t.Collection[T_MetaInstance], Rows):
|
|
|
106
106
|
"""
|
|
107
107
|
return ind in self.records
|
|
108
108
|
|
|
109
|
-
|
|
109
|
+
# TypedRows deliberately re-types pydal's row container: its elements are
|
|
110
|
+
# _TypedTable instances, which are row-like but not pydal Rows. The overrides
|
|
111
|
+
# below therefore narrow Row to T_MetaInstance and are not Liskov-substitutable.
|
|
112
|
+
def first(self) -> T_MetaInstance | None: # ty: ignore[invalid-method-override]
|
|
110
113
|
"""
|
|
111
114
|
Get the row with the lowest id.
|
|
112
115
|
"""
|
|
@@ -115,7 +118,7 @@ class TypedRows(t.Collection[T_MetaInstance], Rows):
|
|
|
115
118
|
|
|
116
119
|
return next(iter(self))
|
|
117
120
|
|
|
118
|
-
def last(self) -> T_MetaInstance | None:
|
|
121
|
+
def last(self) -> T_MetaInstance | None: # ty: ignore[invalid-method-override]
|
|
119
122
|
"""
|
|
120
123
|
Get the row with the highest id.
|
|
121
124
|
"""
|
|
@@ -125,7 +128,7 @@ class TypedRows(t.Collection[T_MetaInstance], Rows):
|
|
|
125
128
|
max_id = max(self.records.keys())
|
|
126
129
|
return self[max_id]
|
|
127
130
|
|
|
128
|
-
def find(
|
|
131
|
+
def find( # ty: ignore[invalid-method-override]
|
|
129
132
|
self,
|
|
130
133
|
f: t.Callable[[T_MetaInstance], Query],
|
|
131
134
|
limitby: tuple[int, int] | None = None,
|
|
@@ -152,7 +155,9 @@ class TypedRows(t.Collection[T_MetaInstance], Rows):
|
|
|
152
155
|
|
|
153
156
|
return self.__class__(self, self.model, records)
|
|
154
157
|
|
|
155
|
-
def exclude(
|
|
158
|
+
def exclude( # ty: ignore[invalid-method-override]
|
|
159
|
+
self, f: t.Callable[[T_MetaInstance], Query]
|
|
160
|
+
) -> "TypedRows[T_MetaInstance]":
|
|
156
161
|
"""
|
|
157
162
|
Removes elements from the calling Rows object, filtered by the function `f`, \
|
|
158
163
|
and returns a new Rows object containing the removed elements.
|
|
@@ -175,7 +180,9 @@ class TypedRows(t.Collection[T_MetaInstance], Rows):
|
|
|
175
180
|
removed,
|
|
176
181
|
)
|
|
177
182
|
|
|
178
|
-
def sort(
|
|
183
|
+
def sort( # ty: ignore[invalid-method-override]
|
|
184
|
+
self, f: t.Callable[[T_MetaInstance], t.Any], reverse: bool = False
|
|
185
|
+
) -> list[T_MetaInstance]:
|
|
179
186
|
"""
|
|
180
187
|
Returns a list of sorted elements (not sorted in place).
|
|
181
188
|
"""
|
|
@@ -240,7 +247,7 @@ class TypedRows(t.Collection[T_MetaInstance], Rows):
|
|
|
240
247
|
"""
|
|
241
248
|
Dump the data to csv.
|
|
242
249
|
"""
|
|
243
|
-
return
|
|
250
|
+
return super().as_csv()
|
|
244
251
|
|
|
245
252
|
def as_dict(
|
|
246
253
|
self,
|
|
@@ -283,7 +290,7 @@ class TypedRows(t.Collection[T_MetaInstance], Rows):
|
|
|
283
290
|
|
|
284
291
|
def json(
|
|
285
292
|
self, default: t.Callable[[t.Any], t.Any] | None = None, indent: int | None = None, **kwargs: t.Any
|
|
286
|
-
) -> str:
|
|
293
|
+
) -> str:
|
|
287
294
|
"""
|
|
288
295
|
Turn the data into a dict and then dump to JSON.
|
|
289
296
|
"""
|
|
@@ -360,7 +367,7 @@ class TypedRows(t.Collection[T_MetaInstance], Rows):
|
|
|
360
367
|
"""
|
|
361
368
|
return await run_async(self.db, self.delete)
|
|
362
369
|
|
|
363
|
-
def join(
|
|
370
|
+
def join( # ty: ignore[invalid-method-override]
|
|
364
371
|
self,
|
|
365
372
|
field: "Field | TypedField[t.Any]",
|
|
366
373
|
name: str | None = None,
|
|
@@ -373,7 +380,9 @@ class TypedRows(t.Collection[T_MetaInstance], Rows):
|
|
|
373
380
|
|
|
374
381
|
Using the querybuilder's .join() method is prefered!
|
|
375
382
|
"""
|
|
376
|
-
|
|
383
|
+
# TypedField is an Expression, not a pydal Field, but carries the
|
|
384
|
+
# .name/.tablename attributes join() actually reads.
|
|
385
|
+
result = super().join(field, name, constraint, fields or [], orderby) # ty: ignore[invalid-argument-type]
|
|
377
386
|
return t.cast(T_MetaInstance, result)
|
|
378
387
|
|
|
379
388
|
def export_to_csv_file(
|
|
@@ -465,7 +474,7 @@ class TypedRows(t.Collection[T_MetaInstance], Rows):
|
|
|
465
474
|
) -> T_MetaInstance:
|
|
466
475
|
"""With an index, return one rendered row instance."""
|
|
467
476
|
|
|
468
|
-
def render(
|
|
477
|
+
def render( # ty: ignore[invalid-method-override]
|
|
469
478
|
self,
|
|
470
479
|
i: int | None = None,
|
|
471
480
|
fields: list[Field] | None = None,
|
|
@@ -569,7 +578,7 @@ class TypedSet(Set): # pragma: no cover
|
|
|
569
578
|
Count returns an int.
|
|
570
579
|
"""
|
|
571
580
|
result = super().count(distinct, cache)
|
|
572
|
-
return
|
|
581
|
+
return result
|
|
573
582
|
|
|
574
583
|
def select(self, *fields: t.Any, **attributes: t.Any) -> TypedRows[T_MetaInstance]:
|
|
575
584
|
"""
|
|
@@ -198,7 +198,7 @@ class TableMeta(type):
|
|
|
198
198
|
Allow dict notation to get a column of this table (-> Field instance).
|
|
199
199
|
"""
|
|
200
200
|
table = self._ensure_table_defined()
|
|
201
|
-
return
|
|
201
|
+
return table[item]
|
|
202
202
|
|
|
203
203
|
def __str__(self) -> str:
|
|
204
204
|
"""
|
|
@@ -766,7 +766,7 @@ class TableMeta(type):
|
|
|
766
766
|
http://web2py.com/books/default/chapter/29/06/the-database-abstraction-layer?search=export_to_csv_file#One-to-mt.Any-relation
|
|
767
767
|
"""
|
|
768
768
|
table = self._ensure_table_defined()
|
|
769
|
-
return
|
|
769
|
+
return table.on(query)
|
|
770
770
|
|
|
771
771
|
def with_alias(self: t.Type[T_MetaInstance], alias: str) -> t.Type[T_MetaInstance]:
|
|
772
772
|
"""
|
|
@@ -1321,7 +1321,7 @@ class TypedTable(_TypedTable, metaclass=TableMeta):
|
|
|
1321
1321
|
"""
|
|
1322
1322
|
table = cls._ensure_table_defined()
|
|
1323
1323
|
result = table.as_dict(flat, sanitize)
|
|
1324
|
-
return
|
|
1324
|
+
return result
|
|
1325
1325
|
|
|
1326
1326
|
@classmethod
|
|
1327
1327
|
def as_typeddict(
|
|
@@ -1441,7 +1441,7 @@ class TypedTable(_TypedTable, metaclass=TableMeta):
|
|
|
1441
1441
|
- dumps the row info if it's an instance (see _as_xml)
|
|
1442
1442
|
"""
|
|
1443
1443
|
table = cls._ensure_table_defined()
|
|
1444
|
-
return
|
|
1444
|
+
return table.as_xml(sanitize)
|
|
1445
1445
|
|
|
1446
1446
|
@classmethod
|
|
1447
1447
|
def as_yaml(cls, sanitize: bool = True) -> str:
|
|
@@ -1453,7 +1453,7 @@ class TypedTable(_TypedTable, metaclass=TableMeta):
|
|
|
1453
1453
|
- dumps the row info if it's an instance (see _as_yaml)
|
|
1454
1454
|
"""
|
|
1455
1455
|
table = cls._ensure_table_defined()
|
|
1456
|
-
return
|
|
1456
|
+
return table.as_yaml(sanitize)
|
|
1457
1457
|
|
|
1458
1458
|
def _as_dict(
|
|
1459
1459
|
self,
|
|
@@ -1483,7 +1483,7 @@ class TypedTable(_TypedTable, metaclass=TableMeta):
|
|
|
1483
1483
|
|
|
1484
1484
|
result[relationship] = data
|
|
1485
1485
|
|
|
1486
|
-
return
|
|
1486
|
+
return result
|
|
1487
1487
|
|
|
1488
1488
|
def _as_json(
|
|
1489
1489
|
self,
|
|
@@ -1494,9 +1494,11 @@ class TypedTable(_TypedTable, metaclass=TableMeta):
|
|
|
1494
1494
|
data = self._as_dict()
|
|
1495
1495
|
return as_json.encode(data, default=default, indent=indent, **kwargs)
|
|
1496
1496
|
|
|
1497
|
-
def _as_xml(self, sanitize: bool = True) -> str: # pragma: no cover
|
|
1497
|
+
def _as_xml(self, sanitize: bool = True) -> str: # noqa: ARG002 # pragma: no cover
|
|
1498
1498
|
row = self._ensure_matching_row()
|
|
1499
|
-
|
|
1499
|
+
# pydal's Row.as_xml has no sanitize flag (its first parameter is the
|
|
1500
|
+
# element name), so the argument is intentionally not forwarded.
|
|
1501
|
+
return row.as_xml()
|
|
1500
1502
|
|
|
1501
1503
|
# def _as_yaml(self, sanitize: bool = True) -> str:
|
|
1502
1504
|
# row = self._ensure_matching_row()
|
|
@@ -116,7 +116,7 @@ class TableProtocol(t.Protocol): # pragma: no cover
|
|
|
116
116
|
Tables have table[field] syntax.
|
|
117
117
|
"""
|
|
118
118
|
|
|
119
|
-
def on(self, query: "QueryLike") -> "Expression
|
|
119
|
+
def on(self, query: "QueryLike") -> "Expression":
|
|
120
120
|
"""
|
|
121
121
|
PyDAL `Table.on(query)` helper used in join callbacks.
|
|
122
122
|
"""
|
|
@@ -151,78 +151,18 @@ class FileSystemLike(t.Protocol): # pragma: no cover
|
|
|
151
151
|
# same for typing and runtime:
|
|
152
152
|
Row: t.TypeAlias = _Row
|
|
153
153
|
Validator: t.TypeAlias = _Validator
|
|
154
|
-
Table: t.TypeAlias = _Table
|
|
155
154
|
Reference: t.TypeAlias = _Reference
|
|
156
155
|
|
|
157
|
-
#
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
"""Pydal Set object. Makes mypy happy."""
|
|
168
|
-
|
|
169
|
-
class Select(_Select):
|
|
170
|
-
"""Pydal Select object. Makes mypy happy."""
|
|
171
|
-
|
|
172
|
-
class OpRow:
|
|
173
|
-
"""
|
|
174
|
-
Pydal OpRow object for typing (otherwise mypy thinks it's Any).
|
|
175
|
-
"""
|
|
176
|
-
|
|
177
|
-
def __getattr__(self, name: str) -> t.Any:
|
|
178
|
-
"""Dynamic attribute access (e.g. row.email)."""
|
|
179
|
-
|
|
180
|
-
def __getitem__(self, item: str) -> t.Any:
|
|
181
|
-
"""row.item syntax."""
|
|
182
|
-
|
|
183
|
-
def __setitem__(self, key: str, value: t.Any) -> None:
|
|
184
|
-
"""row.item = key syntax."""
|
|
185
|
-
|
|
186
|
-
def get(self, key: str, default: t.Any = None) -> t.Any:
|
|
187
|
-
"""Dictionary-like get used by update hooks."""
|
|
188
|
-
|
|
189
|
-
def keys(self) -> t.Iterable[str]:
|
|
190
|
-
"""Dictionary-like key access."""
|
|
191
|
-
|
|
192
|
-
def items(self) -> t.Iterable[tuple[str, t.Any]]:
|
|
193
|
-
"""Dictionary-like item iteration."""
|
|
194
|
-
|
|
195
|
-
def values(self) -> t.Iterable[t.Any]:
|
|
196
|
-
"""Dictionary-like value iteration."""
|
|
197
|
-
|
|
198
|
-
class Field(_Field):
|
|
199
|
-
"""Pydal Field object. Make mypy happy."""
|
|
200
|
-
|
|
201
|
-
_rname: str
|
|
202
|
-
|
|
203
|
-
def __eq__(self, other: t.Any) -> Query: # ty: ignore[invalid-method-override]
|
|
204
|
-
"""Comparing fields produces a PyDAL query."""
|
|
205
|
-
return t.cast(Query, super().__eq__(other))
|
|
206
|
-
|
|
207
|
-
def __ne__(self, other: t.Any) -> Query: # ty: ignore[invalid-method-override]
|
|
208
|
-
"""Comparing fields produces a PyDAL query."""
|
|
209
|
-
return t.cast(Query, super().__ne__(other))
|
|
210
|
-
|
|
211
|
-
def __hash__(self) -> int:
|
|
212
|
-
"""Keep fields hashable after overriding equality."""
|
|
213
|
-
return super().__hash__()
|
|
214
|
-
|
|
215
|
-
class Rows(_Rows):
|
|
216
|
-
def column(self, column: t.Any = None) -> list[t.Any]: ...
|
|
217
|
-
|
|
218
|
-
else:
|
|
219
|
-
Query: t.TypeAlias = _Query
|
|
220
|
-
Expression: t.TypeAlias = _Expression
|
|
221
|
-
Set: t.TypeAlias = _Set
|
|
222
|
-
Select: t.TypeAlias = _Select
|
|
223
|
-
Rows: t.TypeAlias = _Rows
|
|
224
|
-
OpRow: t.TypeAlias = _OpRow
|
|
225
|
-
Field: t.TypeAlias = _Field
|
|
156
|
+
# pydal ships PEP 561 stubs (pydal-stubs), so these need no type-checking-only
|
|
157
|
+
# subclass to carry extra declarations; plain aliases keep one name per concept.
|
|
158
|
+
Query: t.TypeAlias = _Query
|
|
159
|
+
Expression: t.TypeAlias = _Expression
|
|
160
|
+
Set: t.TypeAlias = _Set
|
|
161
|
+
Select: t.TypeAlias = _Select
|
|
162
|
+
Table: t.TypeAlias = _Table
|
|
163
|
+
Field: t.TypeAlias = _Field
|
|
164
|
+
Rows: t.TypeAlias = _Rows
|
|
165
|
+
OpRow: t.TypeAlias = _OpRow
|
|
226
166
|
|
|
227
167
|
|
|
228
168
|
# ---------------------------------------------------------------------------
|
|
@@ -414,7 +354,7 @@ type T_Field = t.Union["TypedField[t.Any]", "Table", t.Type["TypedTable"]]
|
|
|
414
354
|
# checked while its dynamic attribute fallback covers model-specific fields.
|
|
415
355
|
type P_Table = TableProtocol
|
|
416
356
|
|
|
417
|
-
type QueryLike = Query |
|
|
357
|
+
type QueryLike = Query | bool
|
|
418
358
|
|
|
419
359
|
type Condition = t.Callable[[type["TypedTable"], type["TypedTable"]], QueryLike] | None
|
|
420
360
|
|
|
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
|