TypeDAL 5.0.4__tar.gz → 5.0.6__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.0.4 → typedal-5.0.6}/PKG-INFO +1 -1
- {typedal-5.0.4 → typedal-5.0.6}/pyproject.toml +1 -1
- {typedal-5.0.4 → typedal-5.0.6}/pyproject.toml.orig +1 -1
- {typedal-5.0.4 → typedal-5.0.6}/src/typedal/caching.py +1 -2
- {typedal-5.0.4 → typedal-5.0.6}/src/typedal/core.py +5 -5
- {typedal-5.0.4 → typedal-5.0.6}/src/typedal/define.py +1 -2
- {typedal-5.0.4 → typedal-5.0.6}/src/typedal/fields.py +6 -5
- {typedal-5.0.4 → typedal-5.0.6}/src/typedal/query_builder.py +13 -12
- {typedal-5.0.4 → typedal-5.0.6}/src/typedal/relationships.py +3 -5
- {typedal-5.0.4 → typedal-5.0.6}/src/typedal/rows.py +30 -7
- {typedal-5.0.4 → typedal-5.0.6}/src/typedal/tables.py +20 -8
- {typedal-5.0.4 → typedal-5.0.6}/src/typedal/types.py +38 -54
- {typedal-5.0.4 → typedal-5.0.6}/README.md +0 -0
- {typedal-5.0.4 → typedal-5.0.6}/src/typedal/__about__.py +0 -0
- {typedal-5.0.4 → typedal-5.0.6}/src/typedal/__init__.py +0 -0
- {typedal-5.0.4 → typedal-5.0.6}/src/typedal/asynchronous.py +0 -0
- {typedal-5.0.4 → typedal-5.0.6}/src/typedal/cli.py +0 -0
- {typedal-5.0.4 → typedal-5.0.6}/src/typedal/config.py +0 -0
- {typedal-5.0.4 → typedal-5.0.6}/src/typedal/constants.py +0 -0
- {typedal-5.0.4 → typedal-5.0.6}/src/typedal/enum_helpers.py +0 -0
- {typedal-5.0.4 → typedal-5.0.6}/src/typedal/for_py4web.py +0 -0
- {typedal-5.0.4 → typedal-5.0.6}/src/typedal/for_web2py.py +0 -0
- {typedal-5.0.4 → typedal-5.0.6}/src/typedal/helpers.py +0 -0
- {typedal-5.0.4 → typedal-5.0.6}/src/typedal/mixins.py +0 -0
- {typedal-5.0.4 → typedal-5.0.6}/src/typedal/py.typed +0 -0
- {typedal-5.0.4 → typedal-5.0.6}/src/typedal/serializers/as_json.py +0 -0
- {typedal-5.0.4 → typedal-5.0.6}/src/typedal/serializers/typescript.py +0 -0
- {typedal-5.0.4 → typedal-5.0.6}/src/typedal/web2py_py4web_shared.py +0 -0
|
@@ -9,13 +9,12 @@ import json
|
|
|
9
9
|
import typing as t
|
|
10
10
|
|
|
11
11
|
import dill # nosec
|
|
12
|
-
from pydal.objects import Field, Rows, Set
|
|
13
12
|
|
|
14
13
|
from .fields import TypedField
|
|
15
14
|
from .helpers import throw
|
|
16
15
|
from .rows import TypedRows
|
|
17
16
|
from .tables import TypedTable
|
|
18
|
-
from .types import CacheStatus, Query
|
|
17
|
+
from .types import CacheStatus, Field, Query, Rows, Set
|
|
19
18
|
|
|
20
19
|
if t.TYPE_CHECKING:
|
|
21
20
|
from .core import TypeDAL
|
|
@@ -51,10 +51,10 @@ if t.TYPE_CHECKING:
|
|
|
51
51
|
|
|
52
52
|
def _expression_subclasses() -> t.Iterator[type]:
|
|
53
53
|
"""
|
|
54
|
-
Yield
|
|
54
|
+
Yield Expression and every (nested) subclass currently loaded, e.g. Field and TypedField.
|
|
55
55
|
"""
|
|
56
|
-
seen = {
|
|
57
|
-
stack = [
|
|
56
|
+
seen = {Expression}
|
|
57
|
+
stack = [Expression]
|
|
58
58
|
while stack:
|
|
59
59
|
for subclass in stack.pop().__subclasses__():
|
|
60
60
|
if subclass not in seen:
|
|
@@ -77,7 +77,7 @@ def _purge_dialect_expressions(adapter: t.Any) -> None:
|
|
|
77
77
|
`gc.collect()` will not free it, and with it the entire db (tables, fields, models)
|
|
78
78
|
it belongs to, for the lifetime of the process, unless explicitly undone here.
|
|
79
79
|
"""
|
|
80
|
-
expressions =
|
|
80
|
+
expressions = Expression._dialect_expressions_
|
|
81
81
|
stale = [
|
|
82
82
|
name
|
|
83
83
|
for name, wrapper in expressions.items()
|
|
@@ -544,7 +544,7 @@ class TypeDAL(_TypeDALBase):
|
|
|
544
544
|
|
|
545
545
|
return wrapper
|
|
546
546
|
|
|
547
|
-
def __call__(self, *_args: T_Query, **kwargs: t.Any) -> "TypedSet":
|
|
547
|
+
def __call__(self, *_args: T_Query, **kwargs: t.Any) -> "TypedSet":
|
|
548
548
|
"""
|
|
549
549
|
A db instance can be called directly to perform a query.
|
|
550
550
|
|
|
@@ -12,7 +12,6 @@ import types
|
|
|
12
12
|
import typing as t
|
|
13
13
|
import warnings
|
|
14
14
|
|
|
15
|
-
import pydal
|
|
16
15
|
from pydal.validators import IS_IN_SET, ValidationError, Validator
|
|
17
16
|
|
|
18
17
|
from .constants import BASIC_MAPPINGS
|
|
@@ -163,7 +162,7 @@ class TableDefinitionBuilder:
|
|
|
163
162
|
if mapping := BASIC_MAPPINGS.get(ftype):
|
|
164
163
|
# basi types
|
|
165
164
|
return mapping
|
|
166
|
-
elif isinstance(ftype,
|
|
165
|
+
elif isinstance(ftype, Table):
|
|
167
166
|
# db.table
|
|
168
167
|
return f"reference {ftype._tablename}"
|
|
169
168
|
elif issubclass(type(ftype), type) and issubclass(ftype, TypedTable):
|
|
@@ -14,7 +14,6 @@ import uuid
|
|
|
14
14
|
|
|
15
15
|
import pydal
|
|
16
16
|
from pydal.helpers.classes import SQLCustomType
|
|
17
|
-
from pydal.objects import Table
|
|
18
17
|
|
|
19
18
|
from .core import TypeDAL
|
|
20
19
|
from .types import (
|
|
@@ -26,6 +25,7 @@ from .types import (
|
|
|
26
25
|
Query,
|
|
27
26
|
T_annotation,
|
|
28
27
|
T_MetaInstance,
|
|
28
|
+
Table,
|
|
29
29
|
Validator,
|
|
30
30
|
)
|
|
31
31
|
|
|
@@ -79,7 +79,7 @@ class TypedField[T_Value](Expression): # pragma: no cover
|
|
|
79
79
|
authorize: AnyCallable | None
|
|
80
80
|
autodelete: bool
|
|
81
81
|
requires: Validator | t.Iterable[Validator]
|
|
82
|
-
represent: t.Callable[[T_Value,
|
|
82
|
+
represent: t.Callable[[T_Value, t.Any], t.Any] # second argument is the model class but we can't type that
|
|
83
83
|
compute: AnyCallable | None
|
|
84
84
|
custom_store: AnyCallable | None
|
|
85
85
|
custom_retrieve: AnyCallable | None
|
|
@@ -190,12 +190,12 @@ class TypedField[T_Value](Expression): # pragma: no cover
|
|
|
190
190
|
extra_kwargs,
|
|
191
191
|
)
|
|
192
192
|
|
|
193
|
-
def bind(self, field:
|
|
193
|
+
def bind(self, field: Field, table: Table) -> None:
|
|
194
194
|
"""
|
|
195
195
|
Bind the right db/table/field info to this class, so queries can be made using `Class.field == ...`.
|
|
196
196
|
"""
|
|
197
197
|
self._table = table
|
|
198
|
-
self._field =
|
|
198
|
+
self._field = field
|
|
199
199
|
|
|
200
200
|
def unbind(self) -> None:
|
|
201
201
|
"""Remove references to the pydal objects created during `bind`."""
|
|
@@ -280,7 +280,7 @@ class TypedField[T_Value](Expression): # pragma: no cover
|
|
|
280
280
|
return t.cast(Expression, self._field.lower())
|
|
281
281
|
|
|
282
282
|
|
|
283
|
-
def rname(field: TypedField[t.Any] | Field
|
|
283
|
+
def rname(field: TypedField[t.Any] | Field) -> str:
|
|
284
284
|
"""
|
|
285
285
|
Return the full rname (table and field).
|
|
286
286
|
"""
|
|
@@ -514,6 +514,7 @@ def BigintField(**kw: t.Unpack[FieldSettings]) -> TypedField[int]:
|
|
|
514
514
|
|
|
515
515
|
Bigint = BigintField
|
|
516
516
|
|
|
517
|
+
|
|
517
518
|
## Custom:
|
|
518
519
|
|
|
519
520
|
|
|
@@ -10,7 +10,7 @@ import time
|
|
|
10
10
|
import typing as t
|
|
11
11
|
from collections import defaultdict
|
|
12
12
|
|
|
13
|
-
|
|
13
|
+
from pydal.helpers.classes import SQLALL
|
|
14
14
|
|
|
15
15
|
from .asynchronous import run_async
|
|
16
16
|
from .constants import DEFAULT_JOIN_OPTION, JOIN_OPTIONS
|
|
@@ -38,6 +38,7 @@ from .types import (
|
|
|
38
38
|
Query,
|
|
39
39
|
Row,
|
|
40
40
|
Rows,
|
|
41
|
+
Select,
|
|
41
42
|
SelectKwargs,
|
|
42
43
|
T_MetaInstance,
|
|
43
44
|
Table,
|
|
@@ -46,7 +47,7 @@ from .types import (
|
|
|
46
47
|
)
|
|
47
48
|
|
|
48
49
|
|
|
49
|
-
class QueryBuilder[T_MetaInstance: _TypedTable](
|
|
50
|
+
class QueryBuilder[T_MetaInstance: _TypedTable](Select):
|
|
50
51
|
"""
|
|
51
52
|
Abstration on top of pydal's query system.
|
|
52
53
|
"""
|
|
@@ -290,9 +291,9 @@ class QueryBuilder[T_MetaInstance: _TypedTable](pydal.objects.Select):
|
|
|
290
291
|
|
|
291
292
|
subquery = t.cast(Query, DummyQuery())
|
|
292
293
|
for query_part in queries_or_lambdas:
|
|
293
|
-
if isinstance(query_part,
|
|
294
|
-
subquery |=
|
|
295
|
-
elif isinstance(query_part, (
|
|
294
|
+
if isinstance(query_part, Field) or is_typed_field(query_part):
|
|
295
|
+
subquery |= query_part != None
|
|
296
|
+
elif isinstance(query_part, (Query, Expression)):
|
|
296
297
|
subquery |= t.cast(Query, query_part)
|
|
297
298
|
elif callable(query_part):
|
|
298
299
|
if result := query_part(self.model): # ty: ignore[call-top-callable]
|
|
@@ -401,7 +402,7 @@ class QueryBuilder[T_MetaInstance: _TypedTable](pydal.objects.Select):
|
|
|
401
402
|
if len(fields) != 1:
|
|
402
403
|
raise ValueError("join(field, condition=...) can only be used with exactly one field!")
|
|
403
404
|
|
|
404
|
-
if isinstance(condition,
|
|
405
|
+
if isinstance(condition, Query):
|
|
405
406
|
condition = as_lambda(condition)
|
|
406
407
|
|
|
407
408
|
field = fields[0]
|
|
@@ -418,8 +419,8 @@ class QueryBuilder[T_MetaInstance: _TypedTable](pydal.objects.Select):
|
|
|
418
419
|
if len(fields) != 1:
|
|
419
420
|
raise ValueError("join(field, on=...) can only be used with exactly one field!")
|
|
420
421
|
|
|
421
|
-
if isinstance(on,
|
|
422
|
-
on =
|
|
422
|
+
if isinstance(on, Expression):
|
|
423
|
+
on = [on]
|
|
423
424
|
|
|
424
425
|
if isinstance(on, list):
|
|
425
426
|
on = t.cast(OnQuery, as_lambda(on))
|
|
@@ -856,7 +857,7 @@ class QueryBuilder[T_MetaInstance: _TypedTable](pydal.objects.Select):
|
|
|
856
857
|
expression_without_direction, _, direction = expression.rpartition(" ")
|
|
857
858
|
return [expression_without_direction if direction.upper() in {"ASC", "DESC"} else orderby]
|
|
858
859
|
|
|
859
|
-
if isinstance(orderby,
|
|
860
|
+
if isinstance(orderby, Field):
|
|
860
861
|
return t.cast(list[OrderBy], [orderby])
|
|
861
862
|
|
|
862
863
|
fields = []
|
|
@@ -968,8 +969,8 @@ class QueryBuilder[T_MetaInstance: _TypedTable](pydal.objects.Select):
|
|
|
968
969
|
if not isinstance(on, list):
|
|
969
970
|
on = [on]
|
|
970
971
|
|
|
971
|
-
on = [_ for _ in on if isinstance(_,
|
|
972
|
-
left_joins.extend(on)
|
|
972
|
+
on = [_ for _ in on if isinstance(_, Expression)]
|
|
973
|
+
left_joins.extend(on)
|
|
973
974
|
elif method == "left":
|
|
974
975
|
# Generate left join condition
|
|
975
976
|
if not is_self_reference:
|
|
@@ -1032,7 +1033,7 @@ class QueryBuilder[T_MetaInstance: _TypedTable](pydal.objects.Select):
|
|
|
1032
1033
|
if pre_alias != post_alias:
|
|
1033
1034
|
updated_args = []
|
|
1034
1035
|
for arg in select_args:
|
|
1035
|
-
if isinstance(arg,
|
|
1036
|
+
if isinstance(arg, SQLALL):
|
|
1036
1037
|
updated_args.extend(str(field).replace(f"{pre_alias}.", f"{post_alias}.") for field in arg._table)
|
|
1037
1038
|
else:
|
|
1038
1039
|
updated_args.append(str(arg).replace(f"{pre_alias}.", f"{post_alias}."))
|
|
@@ -6,14 +6,12 @@ import inspect
|
|
|
6
6
|
import typing as t
|
|
7
7
|
import warnings
|
|
8
8
|
|
|
9
|
-
import pydal.objects
|
|
10
|
-
|
|
11
9
|
from .config import LazyPolicy
|
|
12
10
|
from .constants import JOIN_OPTIONS
|
|
13
11
|
from .core import ForwardRef, TypeDAL, evaluate_forward_reference
|
|
14
12
|
from .fields import TypedField
|
|
15
13
|
from .helpers import extract_type_optional, looks_like, unwrap_type
|
|
16
|
-
from .types import Condition, OnQuery, T_Field
|
|
14
|
+
from .types import Condition, OnQuery, T_Field, Table
|
|
17
15
|
|
|
18
16
|
# default lazy policy is defined at the TypeDAL() instance settings level
|
|
19
17
|
|
|
@@ -199,7 +197,7 @@ class Relationship[To_Type]:
|
|
|
199
197
|
if isinstance(self.table, str):
|
|
200
198
|
return self.table
|
|
201
199
|
|
|
202
|
-
if isinstance(self.table,
|
|
200
|
+
if isinstance(self.table, Table):
|
|
203
201
|
return str(self.table)
|
|
204
202
|
|
|
205
203
|
# else: typed table
|
|
@@ -288,7 +286,7 @@ class Relationship[To_Type]:
|
|
|
288
286
|
resolved_table = self.get_table(instance._db)
|
|
289
287
|
|
|
290
288
|
builder = owner.where(id=instance.id).join(self.name)
|
|
291
|
-
if issubclass(resolved_table, TypedTable) or isinstance(resolved_table,
|
|
289
|
+
if issubclass(resolved_table, TypedTable) or isinstance(resolved_table, Table):
|
|
292
290
|
# is a table so we can select ALL and ignore non-required fields of parent row:
|
|
293
291
|
builder = builder.select(owner.id, resolved_table.ALL)
|
|
294
292
|
|
|
@@ -8,8 +8,6 @@ import csv
|
|
|
8
8
|
import json
|
|
9
9
|
import typing as t
|
|
10
10
|
|
|
11
|
-
import pydal.objects
|
|
12
|
-
|
|
13
11
|
from .asynchronous import run_async
|
|
14
12
|
from .core import TypeDAL
|
|
15
13
|
from .helpers import mktable
|
|
@@ -25,6 +23,7 @@ from .types import (
|
|
|
25
23
|
Query,
|
|
26
24
|
Row,
|
|
27
25
|
Rows,
|
|
26
|
+
Set,
|
|
28
27
|
T_MetaInstance,
|
|
29
28
|
)
|
|
30
29
|
|
|
@@ -199,18 +198,42 @@ class TypedRows(t.Collection[T_MetaInstance], Rows):
|
|
|
199
198
|
|
|
200
199
|
return mktable(data, headers)
|
|
201
200
|
|
|
202
|
-
|
|
201
|
+
@t.overload
|
|
202
|
+
def group_by_value[T: t.Any](
|
|
203
|
+
self,
|
|
204
|
+
*fields: "TypedField[T] | str | Field",
|
|
205
|
+
one_result: t.Literal[True],
|
|
206
|
+
**kwargs: t.Any,
|
|
207
|
+
) -> dict[T, T_MetaInstance]: ...
|
|
208
|
+
|
|
209
|
+
@t.overload
|
|
210
|
+
def group_by_value[T: t.Any](
|
|
211
|
+
self,
|
|
212
|
+
*fields: "TypedField[T] | str | Field",
|
|
213
|
+
one_result: t.Literal[False] = False,
|
|
214
|
+
**kwargs: t.Any,
|
|
215
|
+
) -> dict[T, list[T_MetaInstance]]: ...
|
|
216
|
+
|
|
217
|
+
@t.overload
|
|
218
|
+
def group_by_value[T: t.Any](
|
|
219
|
+
self,
|
|
220
|
+
*fields: "TypedField[T] | str | Field",
|
|
221
|
+
one_result: bool,
|
|
222
|
+
**kwargs: t.Any,
|
|
223
|
+
) -> dict[T, T_MetaInstance] | dict[T, list[T_MetaInstance]]: ...
|
|
224
|
+
|
|
225
|
+
def group_by_value[T: t.Any](
|
|
203
226
|
self,
|
|
204
|
-
*fields: "
|
|
227
|
+
*fields: "TypedField[T] | str | Field",
|
|
205
228
|
one_result: bool = False,
|
|
206
229
|
**kwargs: t.Any,
|
|
207
|
-
) -> dict[T, list[T_MetaInstance]]:
|
|
230
|
+
) -> dict[T, T_MetaInstance] | dict[T, list[T_MetaInstance]]:
|
|
208
231
|
"""
|
|
209
232
|
Group the rows by a specific field (which will be the dict key).
|
|
210
233
|
"""
|
|
211
234
|
kwargs["one_result"] = one_result
|
|
212
235
|
result = super().group_by_value(*fields, **kwargs)
|
|
213
|
-
return t.cast(dict[T, list[T_MetaInstance]], result)
|
|
236
|
+
return t.cast(dict[T, T_MetaInstance] | dict[T, list[T_MetaInstance]], result)
|
|
214
237
|
|
|
215
238
|
def as_csv(self) -> str:
|
|
216
239
|
"""
|
|
@@ -533,7 +556,7 @@ class PaginatedRows(TypedRows[T_MetaInstance]):
|
|
|
533
556
|
return {"data": super().as_dict(), "pagination": self.pagination}
|
|
534
557
|
|
|
535
558
|
|
|
536
|
-
class TypedSet(
|
|
559
|
+
class TypedSet(Set): # pragma: no cover
|
|
537
560
|
"""
|
|
538
561
|
Used to make pydal Set more typed.
|
|
539
562
|
|
|
@@ -13,9 +13,9 @@ import types
|
|
|
13
13
|
import typing as t
|
|
14
14
|
import uuid
|
|
15
15
|
|
|
16
|
-
import pydal
|
|
16
|
+
import pydal
|
|
17
17
|
from pydal._globals import DEFAULT
|
|
18
|
-
from pydal.helpers.classes import SQLCallableList
|
|
18
|
+
from pydal.helpers.classes import SQLALL, SQLCallableList
|
|
19
19
|
|
|
20
20
|
from .asynchronous import run_async
|
|
21
21
|
from .constants import JOIN_OPTIONS
|
|
@@ -50,7 +50,7 @@ if t.TYPE_CHECKING:
|
|
|
50
50
|
|
|
51
51
|
|
|
52
52
|
def reorder_fields(
|
|
53
|
-
table:
|
|
53
|
+
table: Table,
|
|
54
54
|
fields: t.Iterable[str | TypedField[t.Any] | Field],
|
|
55
55
|
keep_others: bool = True,
|
|
56
56
|
) -> None:
|
|
@@ -65,7 +65,7 @@ def reorder_fields(
|
|
|
65
65
|
- False: remove other fields (only keep what's specified).
|
|
66
66
|
"""
|
|
67
67
|
# Normalize input to field names
|
|
68
|
-
desired = [f.name if isinstance(f, (TypedField, Field
|
|
68
|
+
desired = [f.name if isinstance(f, (TypedField, Field)) else str(f) for f in fields]
|
|
69
69
|
|
|
70
70
|
new_order = [f for f in desired if f in table._fields]
|
|
71
71
|
|
|
@@ -105,6 +105,8 @@ class TableMeta(type):
|
|
|
105
105
|
_table: Table | None = None
|
|
106
106
|
_relationships: dict[str, Relationship[t.Any]] | None = None
|
|
107
107
|
_permissions: Permissions | None = None
|
|
108
|
+
_singular: str
|
|
109
|
+
_plural: str
|
|
108
110
|
|
|
109
111
|
#########################
|
|
110
112
|
# TypeDAL custom logic: #
|
|
@@ -149,6 +151,14 @@ class TableMeta(type):
|
|
|
149
151
|
|
|
150
152
|
return None
|
|
151
153
|
|
|
154
|
+
def __setattr__(self, name: str, value: t.Any) -> None:
|
|
155
|
+
"""Keep PyDAL's table label metadata in sync with its model class."""
|
|
156
|
+
if name.startswith("_") and self._table is not None:
|
|
157
|
+
# include base table for internal stuff such as _singular/_plural:
|
|
158
|
+
setattr(self._table, name, value)
|
|
159
|
+
|
|
160
|
+
super().__setattr__(name, value)
|
|
161
|
+
|
|
152
162
|
def _ensure_table_defined(self) -> Table:
|
|
153
163
|
if not self._table:
|
|
154
164
|
raise EnvironmentError("@define or db.define is not called on this class yet!")
|
|
@@ -182,7 +192,7 @@ class TableMeta(type):
|
|
|
182
192
|
else:
|
|
183
193
|
return f"<unbound table {self.__name__}>"
|
|
184
194
|
|
|
185
|
-
def from_row(self: t.Type[T_MetaInstance], row:
|
|
195
|
+
def from_row(self: t.Type[T_MetaInstance], row: Row) -> T_MetaInstance:
|
|
186
196
|
"""
|
|
187
197
|
Create a model instance from a pydal row.
|
|
188
198
|
"""
|
|
@@ -642,7 +652,7 @@ class TableMeta(type):
|
|
|
642
652
|
return await QueryBuilder(self).collect_into_async(into=into, verbose=verbose, init=init)
|
|
643
653
|
|
|
644
654
|
@property
|
|
645
|
-
def ALL(cls) ->
|
|
655
|
+
def ALL(cls) -> SQLALL:
|
|
646
656
|
"""
|
|
647
657
|
Select all fields for this table.
|
|
648
658
|
"""
|
|
@@ -931,6 +941,8 @@ class _TypedTable(metaclass=TableMeta):
|
|
|
931
941
|
_after_delete: list[t.Callable[[Set], t.Optional[bool]]]
|
|
932
942
|
_rows: tuple[Row, ...]
|
|
933
943
|
_with: list[str]
|
|
944
|
+
_singular: t.ClassVar[str]
|
|
945
|
+
_plural: t.ClassVar[str]
|
|
934
946
|
|
|
935
947
|
@classmethod
|
|
936
948
|
def __on_define__(cls, db: TypeDAL) -> None:
|
|
@@ -1131,7 +1143,7 @@ class TypedTable(_TypedTable, metaclass=TableMeta):
|
|
|
1131
1143
|
|
|
1132
1144
|
def __new__(
|
|
1133
1145
|
cls,
|
|
1134
|
-
row_or_id: t.Union[Row, Query,
|
|
1146
|
+
row_or_id: t.Union[Row, Query, Set, int, str, "TypedTable", None] = None,
|
|
1135
1147
|
**filters: t.Any,
|
|
1136
1148
|
) -> t.Self:
|
|
1137
1149
|
"""
|
|
@@ -1149,7 +1161,7 @@ class TypedTable(_TypedTable, metaclass=TableMeta):
|
|
|
1149
1161
|
# existing typed table instance!
|
|
1150
1162
|
return t.cast(t.Self, row_or_id)
|
|
1151
1163
|
|
|
1152
|
-
elif isinstance(row_or_id,
|
|
1164
|
+
elif isinstance(row_or_id, Row):
|
|
1153
1165
|
row = row_or_id
|
|
1154
1166
|
elif row_or_id is not None:
|
|
1155
1167
|
row = table(row_or_id, **filters)
|
|
@@ -20,6 +20,7 @@ from pydal.objects import Field as _Field
|
|
|
20
20
|
from pydal.objects import Query as _Query
|
|
21
21
|
from pydal.objects import Row as _Row
|
|
22
22
|
from pydal.objects import Rows as _Rows
|
|
23
|
+
from pydal.objects import Select as _Select
|
|
23
24
|
from pydal.objects import Set as _Set
|
|
24
25
|
from pydal.objects import Table as _Table
|
|
25
26
|
from pydal.validators import Validator as _Validator
|
|
@@ -147,20 +148,26 @@ class FileSystemLike(t.Protocol): # pragma: no cover
|
|
|
147
148
|
# pydal Wrappers (to help mypy understand these classes)
|
|
148
149
|
# ---------------------------------------------------------------------------
|
|
149
150
|
|
|
151
|
+
# same for typing and runtime:
|
|
152
|
+
Row: t.TypeAlias = _Row
|
|
153
|
+
Validator: t.TypeAlias = _Validator
|
|
154
|
+
Table: t.TypeAlias = _Table
|
|
155
|
+
Reference: t.TypeAlias = _Reference
|
|
150
156
|
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
class Expression(_Expression):
|
|
156
|
-
"""Pydal Expression object. Make mypy happy."""
|
|
157
|
+
# has to be (fake) subclass during type-checking:
|
|
158
|
+
if t.TYPE_CHECKING:
|
|
157
159
|
|
|
160
|
+
class Query(_Query):
|
|
161
|
+
"""Pydal Query object. Makes mypy happy."""
|
|
158
162
|
|
|
159
|
-
class
|
|
160
|
-
|
|
163
|
+
class Expression(_Expression):
|
|
164
|
+
"""Pydal Expression object. Makes mypy happy."""
|
|
161
165
|
|
|
166
|
+
class Set(_Set):
|
|
167
|
+
"""Pydal Set object. Makes mypy happy."""
|
|
162
168
|
|
|
163
|
-
|
|
169
|
+
class Select(_Select):
|
|
170
|
+
"""Pydal Select object. Makes mypy happy."""
|
|
164
171
|
|
|
165
172
|
class OpRow:
|
|
166
173
|
"""
|
|
@@ -188,57 +195,34 @@ if t.TYPE_CHECKING:
|
|
|
188
195
|
def values(self) -> t.Iterable[t.Any]:
|
|
189
196
|
"""Dictionary-like value iteration."""
|
|
190
197
|
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
class OpRow(_OpRow):
|
|
194
|
-
"""Runtime OpRow, using pydal's version."""
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
class Reference(_Reference):
|
|
198
|
-
"""Pydal Reference object. Make mypy happy."""
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
class Field(_Field):
|
|
202
|
-
"""Pydal Field object. Make mypy happy."""
|
|
203
|
-
|
|
204
|
-
_rname: str
|
|
198
|
+
class Field(_Field):
|
|
199
|
+
"""Pydal Field object. Make mypy happy."""
|
|
205
200
|
|
|
206
|
-
|
|
207
|
-
"""Comparing fields produces a PyDAL query."""
|
|
208
|
-
return t.cast(Query, super().__eq__(other))
|
|
201
|
+
_rname: str
|
|
209
202
|
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
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))
|
|
213
206
|
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
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))
|
|
217
210
|
|
|
211
|
+
def __hash__(self) -> int:
|
|
212
|
+
"""Keep fields hashable after overriding equality."""
|
|
213
|
+
return super().__hash__()
|
|
218
214
|
|
|
219
|
-
class Rows(_Rows):
|
|
220
|
-
|
|
215
|
+
class Rows(_Rows):
|
|
216
|
+
def column(self, column: t.Any = None) -> list[t.Any]: ...
|
|
221
217
|
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
class Row(_Row):
|
|
233
|
-
"""Pydal Row object. Make mypy happy."""
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
class Validator(_Validator):
|
|
237
|
-
"""Pydal Validator object. Make mypy happy."""
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
class Table(_Table):
|
|
241
|
-
"""Pydal Table object. Make mypy happy."""
|
|
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
|
|
242
226
|
|
|
243
227
|
|
|
244
228
|
# ---------------------------------------------------------------------------
|
|
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
|