TypeDAL 3.3.1__py3-none-any.whl → 3.5.0__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.
Potentially problematic release.
This version of TypeDAL might be problematic. Click here for more details.
- typedal/__about__.py +1 -1
- typedal/cli.py +3 -3
- typedal/core.py +90 -24
- typedal/types.py +37 -13
- {typedal-3.3.1.dist-info → typedal-3.5.0.dist-info}/METADATA +1 -1
- {typedal-3.3.1.dist-info → typedal-3.5.0.dist-info}/RECORD +8 -8
- {typedal-3.3.1.dist-info → typedal-3.5.0.dist-info}/WHEEL +0 -0
- {typedal-3.3.1.dist-info → typedal-3.5.0.dist-info}/entry_points.txt +0 -0
typedal/__about__.py
CHANGED
typedal/cli.py
CHANGED
|
@@ -122,7 +122,7 @@ def get_question(prop: str, annotation: typing.Type[T], default: T | None) -> Op
|
|
|
122
122
|
question["message"] = question.get("message", f"{prop}? ")
|
|
123
123
|
default = typing.cast(T, default or question.get("default") or "")
|
|
124
124
|
|
|
125
|
-
if annotation
|
|
125
|
+
if annotation is int:
|
|
126
126
|
default = typing.cast(T, str(default))
|
|
127
127
|
|
|
128
128
|
response = questionary.unsafe_prompt([question], default=default)[prop]
|
|
@@ -197,9 +197,9 @@ def setup(
|
|
|
197
197
|
if isinstance(answer, str):
|
|
198
198
|
answer = answer.strip()
|
|
199
199
|
|
|
200
|
-
if annotation
|
|
200
|
+
if annotation is bool:
|
|
201
201
|
answer = bool(answer)
|
|
202
|
-
elif annotation
|
|
202
|
+
elif annotation is int:
|
|
203
203
|
answer = int(answer)
|
|
204
204
|
|
|
205
205
|
config.update(**{prop: answer})
|
typedal/core.py
CHANGED
|
@@ -43,22 +43,19 @@ from .helpers import (
|
|
|
43
43
|
)
|
|
44
44
|
from .serializers import as_json
|
|
45
45
|
from .types import (
|
|
46
|
-
AfterDeleteCallable,
|
|
47
|
-
AfterInsertCallable,
|
|
48
|
-
AfterUpdateCallable,
|
|
49
46
|
AnyDict,
|
|
50
|
-
BeforeDeleteCallable,
|
|
51
|
-
BeforeInsertCallable,
|
|
52
|
-
BeforeUpdateCallable,
|
|
53
47
|
CacheMetadata,
|
|
54
48
|
Expression,
|
|
55
49
|
Field,
|
|
56
50
|
Metadata,
|
|
51
|
+
OpRow,
|
|
57
52
|
PaginateDict,
|
|
58
53
|
Pagination,
|
|
59
54
|
Query,
|
|
55
|
+
Reference,
|
|
60
56
|
Rows,
|
|
61
57
|
SelectKwargs,
|
|
58
|
+
Set,
|
|
62
59
|
Table,
|
|
63
60
|
Validator,
|
|
64
61
|
_Types,
|
|
@@ -286,7 +283,7 @@ def _generate_relationship_condition(
|
|
|
286
283
|
origin = typing.get_origin(field)
|
|
287
284
|
# else: generic
|
|
288
285
|
|
|
289
|
-
if origin
|
|
286
|
+
if origin is list:
|
|
290
287
|
# field = typing.get_args(field)[0] # actual field
|
|
291
288
|
# return lambda _self, _other: cls[key].contains(field)
|
|
292
289
|
|
|
@@ -337,7 +334,7 @@ def to_relationship(
|
|
|
337
334
|
warnings.warn(f"Invalid relationship for {cls.__name__}.{key}: {field}")
|
|
338
335
|
return None
|
|
339
336
|
|
|
340
|
-
join = "left" if optional or typing.get_origin(field)
|
|
337
|
+
join = "left" if optional or typing.get_origin(field) is list else "inner"
|
|
341
338
|
|
|
342
339
|
return Relationship(typing.cast(type[TypedTable], field), condition, typing.cast(JOIN_OPTIONS, join))
|
|
343
340
|
|
|
@@ -1139,7 +1136,63 @@ class TableMeta(type):
|
|
|
1139
1136
|
table = self._ensure_table_defined()
|
|
1140
1137
|
return typing.cast(Type[T_MetaInstance], table.with_alias(alias))
|
|
1141
1138
|
|
|
1142
|
-
#
|
|
1139
|
+
# hooks:
|
|
1140
|
+
def before_insert(
|
|
1141
|
+
cls: Type[T_MetaInstance],
|
|
1142
|
+
fn: typing.Callable[[T_MetaInstance], Optional[bool]] | typing.Callable[[OpRow], Optional[bool]],
|
|
1143
|
+
) -> Type[T_MetaInstance]:
|
|
1144
|
+
"""
|
|
1145
|
+
Add a before insert hook.
|
|
1146
|
+
"""
|
|
1147
|
+
cls._before_insert.append(fn) # type: ignore
|
|
1148
|
+
return cls
|
|
1149
|
+
|
|
1150
|
+
def after_insert(
|
|
1151
|
+
cls: Type[T_MetaInstance],
|
|
1152
|
+
fn: (
|
|
1153
|
+
typing.Callable[[T_MetaInstance, Reference], Optional[bool]]
|
|
1154
|
+
| typing.Callable[[OpRow, Reference], Optional[bool]]
|
|
1155
|
+
),
|
|
1156
|
+
) -> Type[T_MetaInstance]:
|
|
1157
|
+
"""
|
|
1158
|
+
Add an after insert hook.
|
|
1159
|
+
"""
|
|
1160
|
+
cls._after_insert.append(fn) # type: ignore
|
|
1161
|
+
return cls
|
|
1162
|
+
|
|
1163
|
+
def before_update(
|
|
1164
|
+
cls: Type[T_MetaInstance],
|
|
1165
|
+
fn: typing.Callable[[Set, T_MetaInstance], Optional[bool]] | typing.Callable[[Set, OpRow], Optional[bool]],
|
|
1166
|
+
) -> Type[T_MetaInstance]:
|
|
1167
|
+
"""
|
|
1168
|
+
Add a before update hook.
|
|
1169
|
+
"""
|
|
1170
|
+
cls._before_update.append(fn) # type: ignore
|
|
1171
|
+
return cls
|
|
1172
|
+
|
|
1173
|
+
def after_update(
|
|
1174
|
+
cls: Type[T_MetaInstance],
|
|
1175
|
+
fn: typing.Callable[[Set, T_MetaInstance], Optional[bool]] | typing.Callable[[Set, OpRow], Optional[bool]],
|
|
1176
|
+
) -> Type[T_MetaInstance]:
|
|
1177
|
+
"""
|
|
1178
|
+
Add an after update hook.
|
|
1179
|
+
"""
|
|
1180
|
+
cls._after_update.append(fn) # type: ignore
|
|
1181
|
+
return cls
|
|
1182
|
+
|
|
1183
|
+
def before_delete(cls: Type[T_MetaInstance], fn: typing.Callable[[Set], Optional[bool]]) -> Type[T_MetaInstance]:
|
|
1184
|
+
"""
|
|
1185
|
+
Add a before delete hook.
|
|
1186
|
+
"""
|
|
1187
|
+
cls._before_delete.append(fn)
|
|
1188
|
+
return cls
|
|
1189
|
+
|
|
1190
|
+
def after_delete(cls: Type[T_MetaInstance], fn: typing.Callable[[Set], Optional[bool]]) -> Type[T_MetaInstance]:
|
|
1191
|
+
"""
|
|
1192
|
+
Add an after delete hook.
|
|
1193
|
+
"""
|
|
1194
|
+
cls._after_delete.append(fn)
|
|
1195
|
+
return cls
|
|
1143
1196
|
|
|
1144
1197
|
|
|
1145
1198
|
class TypedField(Expression, typing.Generic[T_Value]): # pragma: no cover
|
|
@@ -1334,12 +1387,14 @@ class _TypedTable:
|
|
|
1334
1387
|
|
|
1335
1388
|
id: "TypedField[int]"
|
|
1336
1389
|
|
|
1337
|
-
_before_insert: list[
|
|
1338
|
-
_after_insert: list[
|
|
1339
|
-
|
|
1340
|
-
|
|
1341
|
-
|
|
1342
|
-
|
|
1390
|
+
_before_insert: list[typing.Callable[[Self], Optional[bool]] | typing.Callable[[OpRow], Optional[bool]]]
|
|
1391
|
+
_after_insert: list[
|
|
1392
|
+
typing.Callable[[Self, Reference], Optional[bool]] | typing.Callable[[OpRow, Reference], Optional[bool]]
|
|
1393
|
+
]
|
|
1394
|
+
_before_update: list[typing.Callable[[Set, Self], Optional[bool]] | typing.Callable[[Set, OpRow], Optional[bool]]]
|
|
1395
|
+
_after_update: list[typing.Callable[[Set, Self], Optional[bool]] | typing.Callable[[Set, OpRow], Optional[bool]]]
|
|
1396
|
+
_before_delete: list[typing.Callable[[Set], Optional[bool]]]
|
|
1397
|
+
_after_delete: list[typing.Callable[[Set], Optional[bool]]]
|
|
1343
1398
|
|
|
1344
1399
|
@classmethod
|
|
1345
1400
|
def __on_define__(cls, db: TypeDAL) -> None:
|
|
@@ -1841,15 +1896,6 @@ class TypedRows(typing.Collection[T_MetaInstance], Rows):
|
|
|
1841
1896
|
result = super().group_by_value(*fields, **kwargs)
|
|
1842
1897
|
return typing.cast(dict[T, list[T_MetaInstance]], result)
|
|
1843
1898
|
|
|
1844
|
-
def column(self, column: str = None) -> list[Any]:
|
|
1845
|
-
"""
|
|
1846
|
-
Get a list of all values in a specific column.
|
|
1847
|
-
|
|
1848
|
-
Example:
|
|
1849
|
-
rows.column('name') -> ['Name 1', 'Name 2', ...]
|
|
1850
|
-
"""
|
|
1851
|
-
return typing.cast(list[Any], super().column(column))
|
|
1852
|
-
|
|
1853
1899
|
def as_csv(self) -> str:
|
|
1854
1900
|
"""
|
|
1855
1901
|
Dump the data to csv.
|
|
@@ -2426,6 +2472,26 @@ class QueryBuilder(typing.Generic[T_MetaInstance]):
|
|
|
2426
2472
|
# only saves if requested in metadata:
|
|
2427
2473
|
return save_to_cache(typed_rows, rows)
|
|
2428
2474
|
|
|
2475
|
+
@typing.overload
|
|
2476
|
+
def column(self, field: TypedField[T]) -> list[T]:
|
|
2477
|
+
"""
|
|
2478
|
+
If a typedfield is passed, the output type can be safely determined.
|
|
2479
|
+
"""
|
|
2480
|
+
|
|
2481
|
+
@typing.overload
|
|
2482
|
+
def column(self, field: T) -> list[T]:
|
|
2483
|
+
"""
|
|
2484
|
+
Otherwise, the output type is loosely determined (assumes `field: type` or Any).
|
|
2485
|
+
"""
|
|
2486
|
+
|
|
2487
|
+
def column(self, field: TypedField[T] | T) -> list[T]:
|
|
2488
|
+
"""
|
|
2489
|
+
Get all values in a specific column.
|
|
2490
|
+
|
|
2491
|
+
Shortcut for `.select(field).execute().column(field)`.
|
|
2492
|
+
"""
|
|
2493
|
+
return self.select(field).execute().column(field)
|
|
2494
|
+
|
|
2429
2495
|
def _handle_relationships_pre_select(
|
|
2430
2496
|
self,
|
|
2431
2497
|
query: Query,
|
typedal/types.py
CHANGED
|
@@ -48,12 +48,35 @@ class Set(_Set): # type: ignore
|
|
|
48
48
|
"""
|
|
49
49
|
|
|
50
50
|
|
|
51
|
-
|
|
52
|
-
"""
|
|
53
|
-
Pydal OpRow object.
|
|
51
|
+
if typing.TYPE_CHECKING:
|
|
54
52
|
|
|
55
|
-
|
|
56
|
-
|
|
53
|
+
class OpRow:
|
|
54
|
+
"""
|
|
55
|
+
Pydal OpRow object for typing (otherwise mypy thinks it's Any).
|
|
56
|
+
|
|
57
|
+
Make mypy happy.
|
|
58
|
+
"""
|
|
59
|
+
|
|
60
|
+
def __getitem__(self, item: str) -> typing.Any:
|
|
61
|
+
"""
|
|
62
|
+
Dict [] get notation.
|
|
63
|
+
"""
|
|
64
|
+
|
|
65
|
+
def __setitem__(self, key: str, value: typing.Any) -> None:
|
|
66
|
+
"""
|
|
67
|
+
Dict [] set notation.
|
|
68
|
+
"""
|
|
69
|
+
|
|
70
|
+
# ... and more methods
|
|
71
|
+
|
|
72
|
+
else:
|
|
73
|
+
|
|
74
|
+
class OpRow(_OpRow): # type: ignore
|
|
75
|
+
"""
|
|
76
|
+
Pydal OpRow object at runtime just uses pydal's version.
|
|
77
|
+
|
|
78
|
+
Make mypy happy.
|
|
79
|
+
"""
|
|
57
80
|
|
|
58
81
|
|
|
59
82
|
class Reference(_Reference): # type: ignore
|
|
@@ -79,6 +102,15 @@ class Rows(_Rows): # type: ignore
|
|
|
79
102
|
Make mypy happy.
|
|
80
103
|
"""
|
|
81
104
|
|
|
105
|
+
def column(self, column: typing.Any = None) -> list[typing.Any]:
|
|
106
|
+
"""
|
|
107
|
+
Get a list of all values in a specific column.
|
|
108
|
+
|
|
109
|
+
Example:
|
|
110
|
+
rows.column('name') -> ['Name 1', 'Name 2', ...]
|
|
111
|
+
"""
|
|
112
|
+
return [r[str(column) if column else self.colnames[0]] for r in self]
|
|
113
|
+
|
|
82
114
|
|
|
83
115
|
class Validator(_Validator): # type: ignore
|
|
84
116
|
"""
|
|
@@ -96,14 +128,6 @@ class _Types:
|
|
|
96
128
|
NONETYPE = type(None)
|
|
97
129
|
|
|
98
130
|
|
|
99
|
-
BeforeInsertCallable: typing.TypeAlias = typing.Callable[[OpRow], Any]
|
|
100
|
-
AfterInsertCallable: typing.TypeAlias = typing.Callable[[OpRow, Reference], Any]
|
|
101
|
-
BeforeUpdateCallable: typing.TypeAlias = typing.Callable[[Set, OpRow], Any]
|
|
102
|
-
AfterUpdateCallable: typing.TypeAlias = typing.Callable[[Set, OpRow], Any]
|
|
103
|
-
BeforeDeleteCallable: typing.TypeAlias = typing.Callable[[Set], Any]
|
|
104
|
-
AfterDeleteCallable: typing.TypeAlias = typing.Callable[[Set], Any]
|
|
105
|
-
|
|
106
|
-
|
|
107
131
|
class Pagination(TypedDict):
|
|
108
132
|
"""
|
|
109
133
|
Pagination key of a paginate dict has these items.
|
|
@@ -1,19 +1,19 @@
|
|
|
1
|
-
typedal/__about__.py,sha256=
|
|
1
|
+
typedal/__about__.py,sha256=AjgocyPCjgkgwSg0cozJLLzDEJz3aZN-Ze0xcPDV5pc,206
|
|
2
2
|
typedal/__init__.py,sha256=QQpLiVl9w9hm2LBxey49Y_tCF_VB2bScVaS_mCjYy54,366
|
|
3
3
|
typedal/caching.py,sha256=SMcJsahLlZ79yykWCveERFx1ZJUNEKhA9SPmCTIuLp8,11798
|
|
4
|
-
typedal/cli.py,sha256=
|
|
4
|
+
typedal/cli.py,sha256=n2TKQGOryck91ByFEcLqwPgh6_kMtoBr3UBIDwU_8n8,18180
|
|
5
5
|
typedal/config.py,sha256=0qy1zrTUdtmXPM9jHzFnSR1DJsqGJqcdG6pvhzKQHe0,11625
|
|
6
|
-
typedal/core.py,sha256=
|
|
6
|
+
typedal/core.py,sha256=mbNFMv3NJ2QRDuohs03LCGhVVnffsxjsoe-m887U6c8,98367
|
|
7
7
|
typedal/fields.py,sha256=z2PD9vLWqBR_zXtiY0DthqTG4AeF3yxKoeuVfGXnSdg,5197
|
|
8
8
|
typedal/for_py4web.py,sha256=d07b8hL_PvNDUS26Z5fDH2OxWb-IETBuAFPSzrRwm04,1285
|
|
9
9
|
typedal/for_web2py.py,sha256=4RHgzGXgKIO_BYB-7adC5e35u52rX-p1t4tPEz-NK24,1867
|
|
10
10
|
typedal/helpers.py,sha256=KbgP4ZRW7KCroyHwTwdErPqylOX4dsqVnKJeZ5TtTFY,7363
|
|
11
11
|
typedal/mixins.py,sha256=OHhVYLBGTzPSJKgp1uovBs1Y6NJa0d-DxHTOk9LyOXA,5414
|
|
12
12
|
typedal/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
13
|
-
typedal/types.py,sha256=
|
|
13
|
+
typedal/types.py,sha256=W2zsmJSPYbIvhjb5Df_ZANH8riCIJhOOHjI8UCQINls,5239
|
|
14
14
|
typedal/web2py_py4web_shared.py,sha256=VK9T8P5UwVLvfNBsY4q79ANcABv-jX76YKADt1Zz_co,1539
|
|
15
15
|
typedal/serializers/as_json.py,sha256=ffo152W-sARYXym4BzwX709rrO2-QwKk2KunWY8RNl4,2229
|
|
16
|
-
typedal-3.
|
|
17
|
-
typedal-3.
|
|
18
|
-
typedal-3.
|
|
19
|
-
typedal-3.
|
|
16
|
+
typedal-3.5.0.dist-info/METADATA,sha256=pffl-arVDPP0CBg3EcVhlze5mxypyCH-Ds_iZ6sZY6s,9462
|
|
17
|
+
typedal-3.5.0.dist-info/WHEEL,sha256=KGYbc1zXlYddvwxnNty23BeaKzh7YuoSIvIMO4jEhvw,87
|
|
18
|
+
typedal-3.5.0.dist-info/entry_points.txt,sha256=m1wqcc_10rHWPdlQ71zEkmJDADUAnZtn7Jac_6mbyUc,44
|
|
19
|
+
typedal-3.5.0.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|