TypeDAL 3.12.1__py3-none-any.whl → 4.2.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.
- typedal/__about__.py +1 -1
- typedal/__init__.py +21 -3
- typedal/caching.py +37 -34
- typedal/cli.py +1 -1
- typedal/config.py +18 -16
- typedal/constants.py +25 -0
- typedal/core.py +202 -2784
- typedal/define.py +188 -0
- typedal/fields.py +319 -30
- typedal/for_py4web.py +2 -3
- typedal/for_web2py.py +1 -1
- typedal/helpers.py +355 -38
- typedal/mixins.py +28 -24
- typedal/query_builder.py +1119 -0
- typedal/relationships.py +390 -0
- typedal/rows.py +524 -0
- typedal/serializers/as_json.py +9 -10
- typedal/tables.py +1131 -0
- typedal/types.py +187 -179
- typedal/web2py_py4web_shared.py +3 -3
- {typedal-3.12.1.dist-info → typedal-4.2.0.dist-info}/METADATA +9 -8
- typedal-4.2.0.dist-info/RECORD +25 -0
- {typedal-3.12.1.dist-info → typedal-4.2.0.dist-info}/WHEEL +1 -1
- typedal-3.12.1.dist-info/RECORD +0 -19
- {typedal-3.12.1.dist-info → typedal-4.2.0.dist-info}/entry_points.txt +0 -0
typedal/mixins.py
CHANGED
|
@@ -5,26 +5,22 @@ Mixins can add reusable fields and behavior (optimally both, otherwise it doesn'
|
|
|
5
5
|
"""
|
|
6
6
|
|
|
7
7
|
import base64
|
|
8
|
+
import datetime as dt
|
|
8
9
|
import os
|
|
9
|
-
import typing
|
|
10
|
+
import typing as t
|
|
10
11
|
import warnings
|
|
11
|
-
from datetime import datetime
|
|
12
|
-
from typing import Any, Optional
|
|
13
12
|
|
|
14
13
|
from pydal import DAL
|
|
15
14
|
from pydal.validators import IS_NOT_IN_DB, ValidationError
|
|
16
15
|
from slugify import slugify
|
|
17
16
|
|
|
18
|
-
from .core import
|
|
19
|
-
QueryBuilder,
|
|
20
|
-
T_MetaInstance,
|
|
21
|
-
TableMeta,
|
|
22
|
-
TypeDAL,
|
|
23
|
-
TypedTable,
|
|
24
|
-
_TypedTable,
|
|
25
|
-
)
|
|
17
|
+
from .core import TypeDAL
|
|
26
18
|
from .fields import DatetimeField, StringField
|
|
27
|
-
from .
|
|
19
|
+
from .tables import _TypedTable
|
|
20
|
+
from .types import OpRow, Set, T_MetaInstance
|
|
21
|
+
|
|
22
|
+
if t.TYPE_CHECKING:
|
|
23
|
+
from .tables import TypedTable # noqa: F401
|
|
28
24
|
|
|
29
25
|
|
|
30
26
|
class Mixin(_TypedTable):
|
|
@@ -38,9 +34,9 @@ class Mixin(_TypedTable):
|
|
|
38
34
|
('inconsistent method resolution' or 'metaclass conflicts')
|
|
39
35
|
"""
|
|
40
36
|
|
|
41
|
-
__settings__:
|
|
37
|
+
__settings__: t.ClassVar[dict[str, t.Any]]
|
|
42
38
|
|
|
43
|
-
def __init_subclass__(cls, **kwargs: Any):
|
|
39
|
+
def __init_subclass__(cls, **kwargs: t.Any):
|
|
44
40
|
"""
|
|
45
41
|
Ensures __settings__ exists for other mixins.
|
|
46
42
|
"""
|
|
@@ -52,8 +48,8 @@ class TimestampsMixin(Mixin):
|
|
|
52
48
|
A Mixin class for adding timestamp fields to a model.
|
|
53
49
|
"""
|
|
54
50
|
|
|
55
|
-
created_at = DatetimeField(default=datetime.now, writable=False)
|
|
56
|
-
updated_at = DatetimeField(default=datetime.now, writable=False)
|
|
51
|
+
created_at = DatetimeField(default=dt.datetime.now, writable=False)
|
|
52
|
+
updated_at = DatetimeField(default=dt.datetime.now, writable=False)
|
|
57
53
|
|
|
58
54
|
@classmethod
|
|
59
55
|
def __on_define__(cls, db: TypeDAL) -> None:
|
|
@@ -73,7 +69,7 @@ class TimestampsMixin(Mixin):
|
|
|
73
69
|
_: Set: Unused parameter.
|
|
74
70
|
row (OpRow): The row to update.
|
|
75
71
|
"""
|
|
76
|
-
row["updated_at"] = datetime.now()
|
|
72
|
+
row["updated_at"] = dt.datetime.now()
|
|
77
73
|
|
|
78
74
|
cls._before_update.append(set_updated_at)
|
|
79
75
|
|
|
@@ -89,7 +85,7 @@ def slug_random_suffix(length: int = 8) -> str:
|
|
|
89
85
|
return base64.urlsafe_b64encode(os.urandom(length)).rstrip(b"=").decode().strip("=")
|
|
90
86
|
|
|
91
87
|
|
|
92
|
-
T =
|
|
88
|
+
T = t.TypeVar("T")
|
|
93
89
|
|
|
94
90
|
|
|
95
91
|
# noinspection PyPep8Naming
|
|
@@ -112,7 +108,7 @@ class HAS_UNIQUE_SLUG(IS_NOT_IN_DB):
|
|
|
112
108
|
"""
|
|
113
109
|
super().__init__(db, field, error_message)
|
|
114
110
|
|
|
115
|
-
def validate(self, original: T, record_id: Optional[int] = None) -> T:
|
|
111
|
+
def validate(self, original: T, record_id: t.Optional[int] = None) -> T:
|
|
116
112
|
"""
|
|
117
113
|
Performs checks to see if the slug already exists for a different row.
|
|
118
114
|
"""
|
|
@@ -154,7 +150,7 @@ class SlugMixin(Mixin):
|
|
|
154
150
|
# pub:
|
|
155
151
|
slug = StringField(unique=True, writable=False)
|
|
156
152
|
# priv:
|
|
157
|
-
__settings__:
|
|
153
|
+
__settings__: t.TypedDict( # type: ignore
|
|
158
154
|
"SlugFieldSettings",
|
|
159
155
|
{
|
|
160
156
|
"slug_field": str,
|
|
@@ -163,7 +159,11 @@ class SlugMixin(Mixin):
|
|
|
163
159
|
) # set via init subclass
|
|
164
160
|
|
|
165
161
|
def __init_subclass__(
|
|
166
|
-
cls,
|
|
162
|
+
cls,
|
|
163
|
+
slug_field: t.Optional[str] = None,
|
|
164
|
+
slug_suffix_length: int = 0,
|
|
165
|
+
slug_suffix: t.Optional[int] = None,
|
|
166
|
+
**kw: t.Any,
|
|
167
167
|
) -> None:
|
|
168
168
|
"""
|
|
169
169
|
Bind 'slug field' option to be used later (on_define).
|
|
@@ -176,7 +176,7 @@ class SlugMixin(Mixin):
|
|
|
176
176
|
if slug_field is None:
|
|
177
177
|
raise ValueError(
|
|
178
178
|
"SlugMixin requires a valid slug_field setting: "
|
|
179
|
-
"e.g. `class MyClass(TypedTable, SlugMixin, slug_field='title'): ...`"
|
|
179
|
+
"e.g. `class MyClass(TypedTable, SlugMixin, slug_field='title'): ...`",
|
|
180
180
|
)
|
|
181
181
|
|
|
182
182
|
if slug_suffix:
|
|
@@ -193,6 +193,10 @@ class SlugMixin(Mixin):
|
|
|
193
193
|
|
|
194
194
|
@classmethod
|
|
195
195
|
def __generate_slug_before_insert(cls, row: OpRow) -> None:
|
|
196
|
+
if row.get("slug"): # type: ignore
|
|
197
|
+
# manually set -> skip
|
|
198
|
+
return None
|
|
199
|
+
|
|
196
200
|
settings = cls.__settings__
|
|
197
201
|
|
|
198
202
|
text_input = row[settings["slug_field"]]
|
|
@@ -227,7 +231,7 @@ class SlugMixin(Mixin):
|
|
|
227
231
|
slug_field.requires = current_requires
|
|
228
232
|
|
|
229
233
|
@classmethod
|
|
230
|
-
def from_slug(cls:
|
|
234
|
+
def from_slug(cls: t.Type[T_MetaInstance], slug: str, join: bool = True) -> t.Optional[T_MetaInstance]:
|
|
231
235
|
"""
|
|
232
236
|
Find a row by its slug.
|
|
233
237
|
"""
|
|
@@ -238,7 +242,7 @@ class SlugMixin(Mixin):
|
|
|
238
242
|
return builder.first()
|
|
239
243
|
|
|
240
244
|
@classmethod
|
|
241
|
-
def from_slug_or_fail(cls:
|
|
245
|
+
def from_slug_or_fail(cls: t.Type[T_MetaInstance], slug: str, join: bool = True) -> T_MetaInstance:
|
|
242
246
|
"""
|
|
243
247
|
Find a row by its slug, or raise an error if it doesn't exist.
|
|
244
248
|
"""
|