TypeDAL 3.13.1__tar.gz → 3.14.0__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.
Potentially problematic release.
This version of TypeDAL might be problematic. Click here for more details.
- {typedal-3.13.1 → typedal-3.14.0}/CHANGELOG.md +6 -0
- {typedal-3.13.1 → typedal-3.14.0}/PKG-INFO +2 -2
- {typedal-3.13.1 → typedal-3.14.0}/src/typedal/__about__.py +1 -1
- {typedal-3.13.1 → typedal-3.14.0}/src/typedal/__init__.py +1 -1
- {typedal-3.13.1 → typedal-3.14.0}/src/typedal/cli.py +3 -2
- {typedal-3.13.1 → typedal-3.14.0}/src/typedal/core.py +27 -12
- {typedal-3.13.1 → typedal-3.14.0}/src/typedal/for_py4web.py +1 -2
- {typedal-3.13.1 → typedal-3.14.0}/src/typedal/helpers.py +5 -1
- {typedal-3.13.1 → typedal-3.14.0}/src/typedal/mixins.py +5 -1
- {typedal-3.13.1 → typedal-3.14.0}/src/typedal/serializers/as_json.py +1 -1
- {typedal-3.13.1 → typedal-3.14.0}/tests/test_main.py +5 -0
- {typedal-3.13.1 → typedal-3.14.0}/.github/workflows/su6.yml +0 -0
- {typedal-3.13.1 → typedal-3.14.0}/.gitignore +0 -0
- {typedal-3.13.1 → typedal-3.14.0}/.readthedocs.yml +0 -0
- {typedal-3.13.1 → typedal-3.14.0}/README.md +0 -0
- {typedal-3.13.1 → typedal-3.14.0}/coverage.svg +0 -0
- {typedal-3.13.1 → typedal-3.14.0}/docs/1_getting_started.md +0 -0
- {typedal-3.13.1 → typedal-3.14.0}/docs/2_defining_tables.md +0 -0
- {typedal-3.13.1 → typedal-3.14.0}/docs/3_building_queries.md +0 -0
- {typedal-3.13.1 → typedal-3.14.0}/docs/4_relationships.md +0 -0
- {typedal-3.13.1 → typedal-3.14.0}/docs/5_py4web.md +0 -0
- {typedal-3.13.1 → typedal-3.14.0}/docs/6_migrations.md +0 -0
- {typedal-3.13.1 → typedal-3.14.0}/docs/7_mixins.md +0 -0
- {typedal-3.13.1 → typedal-3.14.0}/docs/css/code_blocks.css +0 -0
- {typedal-3.13.1 → typedal-3.14.0}/docs/index.md +0 -0
- {typedal-3.13.1 → typedal-3.14.0}/docs/requirements.txt +0 -0
- {typedal-3.13.1 → typedal-3.14.0}/example_new.py +0 -0
- {typedal-3.13.1 → typedal-3.14.0}/example_old.py +0 -0
- {typedal-3.13.1 → typedal-3.14.0}/mkdocs.yml +0 -0
- {typedal-3.13.1 → typedal-3.14.0}/pyproject.toml +0 -0
- {typedal-3.13.1 → typedal-3.14.0}/src/typedal/caching.py +0 -0
- {typedal-3.13.1 → typedal-3.14.0}/src/typedal/config.py +0 -0
- {typedal-3.13.1 → typedal-3.14.0}/src/typedal/fields.py +0 -0
- {typedal-3.13.1 → typedal-3.14.0}/src/typedal/for_web2py.py +0 -0
- {typedal-3.13.1 → typedal-3.14.0}/src/typedal/py.typed +0 -0
- {typedal-3.13.1 → typedal-3.14.0}/src/typedal/types.py +0 -0
- {typedal-3.13.1 → typedal-3.14.0}/src/typedal/web2py_py4web_shared.py +0 -0
- {typedal-3.13.1 → typedal-3.14.0}/tests/__init__.py +0 -0
- {typedal-3.13.1 → typedal-3.14.0}/tests/configs/simple.toml +0 -0
- {typedal-3.13.1 → typedal-3.14.0}/tests/configs/valid.env +0 -0
- {typedal-3.13.1 → typedal-3.14.0}/tests/configs/valid.toml +0 -0
- {typedal-3.13.1 → typedal-3.14.0}/tests/test_cli.py +0 -0
- {typedal-3.13.1 → typedal-3.14.0}/tests/test_config.py +0 -0
- {typedal-3.13.1 → typedal-3.14.0}/tests/test_docs_examples.py +0 -0
- {typedal-3.13.1 → typedal-3.14.0}/tests/test_helpers.py +0 -0
- {typedal-3.13.1 → typedal-3.14.0}/tests/test_json.py +0 -0
- {typedal-3.13.1 → typedal-3.14.0}/tests/test_mixins.py +0 -0
- {typedal-3.13.1 → typedal-3.14.0}/tests/test_mypy.py +0 -0
- {typedal-3.13.1 → typedal-3.14.0}/tests/test_orm.py +0 -0
- {typedal-3.13.1 → typedal-3.14.0}/tests/test_py4web.py +0 -0
- {typedal-3.13.1 → typedal-3.14.0}/tests/test_query_builder.py +0 -0
- {typedal-3.13.1 → typedal-3.14.0}/tests/test_relationships.py +0 -0
- {typedal-3.13.1 → typedal-3.14.0}/tests/test_row.py +0 -0
- {typedal-3.13.1 → typedal-3.14.0}/tests/test_stats.py +0 -0
- {typedal-3.13.1 → typedal-3.14.0}/tests/test_table.py +0 -0
- {typedal-3.13.1 → typedal-3.14.0}/tests/test_web2py.py +0 -0
- {typedal-3.13.1 → typedal-3.14.0}/tests/test_xx_others.py +0 -0
- {typedal-3.13.1 → typedal-3.14.0}/tests/timings.py +0 -0
|
@@ -2,6 +2,12 @@
|
|
|
2
2
|
|
|
3
3
|
<!--next-version-placeholder-->
|
|
4
4
|
|
|
5
|
+
## v3.14.0 (2025-05-15)
|
|
6
|
+
|
|
7
|
+
### Feature
|
|
8
|
+
|
|
9
|
+
* `db.find_model` to get the registered TypedTable class for a specific 'table_name' ([`c645303`](https://github.com/trialandsuccess/TypeDAL/commit/c645303a85c96735f48eafaaeb20f867b977686f))
|
|
10
|
+
|
|
5
11
|
## v3.13.1 (2025-04-28)
|
|
6
12
|
|
|
7
13
|
### Fix
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
2
|
Name: TypeDAL
|
|
3
|
-
Version: 3.
|
|
3
|
+
Version: 3.14.0
|
|
4
4
|
Summary: Typing support for PyDAL
|
|
5
5
|
Project-URL: Documentation, https://typedal.readthedocs.io/
|
|
6
6
|
Project-URL: Issues, https://github.com/trialandsuccess/TypeDAL/issues
|
|
@@ -10,4 +10,4 @@ try:
|
|
|
10
10
|
except ImportError: # pragma: no cover
|
|
11
11
|
P4W_DAL = None # type: ignore
|
|
12
12
|
|
|
13
|
-
__all__ = ["
|
|
13
|
+
__all__ = ["Relationship", "TypeDAL", "TypedField", "TypedRows", "TypedTable", "fields", "relationship"]
|
|
@@ -185,7 +185,7 @@ def setup(
|
|
|
185
185
|
data.pop(prop, None)
|
|
186
186
|
continue
|
|
187
187
|
|
|
188
|
-
if minimal and getattr(config, prop, None) not in (None, "") or is_optional(annotation):
|
|
188
|
+
if (minimal and getattr(config, prop, None) not in (None, "")) or is_optional(annotation):
|
|
189
189
|
# property already present or not required, SKIP!
|
|
190
190
|
data[prop] = getattr(config, prop, None)
|
|
191
191
|
continue
|
|
@@ -392,7 +392,8 @@ def fake_migrations(
|
|
|
392
392
|
|
|
393
393
|
previously_migrated = (
|
|
394
394
|
db(
|
|
395
|
-
db.ewh_implemented_features.name.belongs(to_fake)
|
|
395
|
+
db.ewh_implemented_features.name.belongs(to_fake)
|
|
396
|
+
& (db.ewh_implemented_features.installed == True) # noqa E712
|
|
396
397
|
)
|
|
397
398
|
.select(db.ewh_implemented_features.name)
|
|
398
399
|
.column("name")
|
|
@@ -93,10 +93,8 @@ def is_typed_field(cls: Any) -> typing.TypeGuard["TypedField[Any]"]:
|
|
|
93
93
|
|
|
94
94
|
Deprecated
|
|
95
95
|
"""
|
|
96
|
-
return (
|
|
97
|
-
isinstance(cls, TypedField)
|
|
98
|
-
or isinstance(typing.get_origin(cls), type)
|
|
99
|
-
and issubclass(typing.get_origin(cls), TypedField)
|
|
96
|
+
return isinstance(cls, TypedField) or (
|
|
97
|
+
isinstance(typing.get_origin(cls), type) and issubclass(typing.get_origin(cls), TypedField)
|
|
100
98
|
)
|
|
101
99
|
|
|
102
100
|
|
|
@@ -698,11 +696,30 @@ class TypeDAL(pydal.DAL): # type: ignore
|
|
|
698
696
|
"""
|
|
699
697
|
Allows dynamically accessing a table by its name as a string.
|
|
700
698
|
|
|
699
|
+
If you need the TypedTable class instead of the pydal table, use find_model instead.
|
|
700
|
+
|
|
701
701
|
Example:
|
|
702
702
|
db['users'] -> user
|
|
703
703
|
"""
|
|
704
704
|
return typing.cast(Table, super().__getitem__(str(key)))
|
|
705
705
|
|
|
706
|
+
def find_model(self, table_name: str) -> Type["TypedTable"] | None:
|
|
707
|
+
"""
|
|
708
|
+
Retrieves a mapped table class by its name.
|
|
709
|
+
|
|
710
|
+
This method searches for a table class matching the given table name
|
|
711
|
+
in the defined class map dictionary. If a match is found, the corresponding
|
|
712
|
+
table class is returned; otherwise, None is returned, indicating that no
|
|
713
|
+
table class matches the input name.
|
|
714
|
+
|
|
715
|
+
Args:
|
|
716
|
+
table_name: The name of the table to retrieve the mapped class for.
|
|
717
|
+
|
|
718
|
+
Returns:
|
|
719
|
+
The mapped table class if it exists, otherwise None.
|
|
720
|
+
"""
|
|
721
|
+
return self._class_map.get(table_name, None)
|
|
722
|
+
|
|
706
723
|
@classmethod
|
|
707
724
|
def _build_field(cls, name: str, _type: str, **kw: Any) -> Field:
|
|
708
725
|
# return Field(name, _type, **{**cls.default_kwargs, **kw})
|
|
@@ -1024,7 +1041,6 @@ class TableMeta(type):
|
|
|
1024
1041
|
|
|
1025
1042
|
Shortcut for `.select(field).execute().column(field)`.
|
|
1026
1043
|
"""
|
|
1027
|
-
|
|
1028
1044
|
return QueryBuilder(self).select(field, **options).execute().column(field)
|
|
1029
1045
|
|
|
1030
1046
|
def paginate(self: Type[T_MetaInstance], limit: int, page: int = 1) -> "PaginatedRows[T_MetaInstance]":
|
|
@@ -2721,7 +2737,6 @@ class QueryBuilder(typing.Generic[T_MetaInstance]):
|
|
|
2721
2737
|
|
|
2722
2738
|
Shortcut for `.select(field).execute().column(field)`.
|
|
2723
2739
|
"""
|
|
2724
|
-
|
|
2725
2740
|
return self.select(field, **options).execute().column(field)
|
|
2726
2741
|
|
|
2727
2742
|
def _handle_relationships_pre_select(
|
|
@@ -2888,7 +2903,7 @@ class QueryBuilder(typing.Generic[T_MetaInstance]):
|
|
|
2888
2903
|
|
|
2889
2904
|
return _to(rows, self.model, records, metadata=metadata)
|
|
2890
2905
|
|
|
2891
|
-
def collect_or_fail(self, exception: Exception = None) -> "TypedRows[T_MetaInstance]":
|
|
2906
|
+
def collect_or_fail(self, exception: typing.Optional[Exception] = None) -> "TypedRows[T_MetaInstance]":
|
|
2892
2907
|
"""
|
|
2893
2908
|
Call .collect() and raise an error if nothing found.
|
|
2894
2909
|
|
|
@@ -2908,7 +2923,7 @@ class QueryBuilder(typing.Generic[T_MetaInstance]):
|
|
|
2908
2923
|
"""
|
|
2909
2924
|
yield from self.collect()
|
|
2910
2925
|
|
|
2911
|
-
def __count(self, db: TypeDAL, distinct: bool = None) -> Query:
|
|
2926
|
+
def __count(self, db: TypeDAL, distinct: typing.Optional[bool] = None) -> Query:
|
|
2912
2927
|
# internal, shared logic between .count and ._count
|
|
2913
2928
|
model = self.model
|
|
2914
2929
|
query = self.query
|
|
@@ -2924,7 +2939,7 @@ class QueryBuilder(typing.Generic[T_MetaInstance]):
|
|
|
2924
2939
|
|
|
2925
2940
|
return query
|
|
2926
2941
|
|
|
2927
|
-
def count(self, distinct: bool = None) -> int:
|
|
2942
|
+
def count(self, distinct: typing.Optional[bool] = None) -> int:
|
|
2928
2943
|
"""
|
|
2929
2944
|
Return the amount of rows matching the current query.
|
|
2930
2945
|
"""
|
|
@@ -2933,7 +2948,7 @@ class QueryBuilder(typing.Generic[T_MetaInstance]):
|
|
|
2933
2948
|
|
|
2934
2949
|
return db(query).count(distinct)
|
|
2935
2950
|
|
|
2936
|
-
def _count(self, distinct: bool = None) -> str:
|
|
2951
|
+
def _count(self, distinct: typing.Optional[bool] = None) -> str:
|
|
2937
2952
|
"""
|
|
2938
2953
|
Return the SQL for .count().
|
|
2939
2954
|
"""
|
|
@@ -3032,7 +3047,7 @@ class QueryBuilder(typing.Generic[T_MetaInstance]):
|
|
|
3032
3047
|
def _first(self) -> str:
|
|
3033
3048
|
return self._paginate(page=1, limit=1)
|
|
3034
3049
|
|
|
3035
|
-
def first_or_fail(self, exception: Exception = None, verbose: bool = False) -> T_MetaInstance:
|
|
3050
|
+
def first_or_fail(self, exception: typing.Optional[Exception] = None, verbose: bool = False) -> T_MetaInstance:
|
|
3036
3051
|
"""
|
|
3037
3052
|
Call .first() and raise an error if nothing found.
|
|
3038
3053
|
|
|
@@ -3120,7 +3135,7 @@ class TypedSet(pydal.objects.Set): # type: ignore # pragma: no cover
|
|
|
3120
3135
|
This class is not actually used, only 'cast' by TypeDAL.__call__
|
|
3121
3136
|
"""
|
|
3122
3137
|
|
|
3123
|
-
def count(self, distinct: bool = None, cache: AnyDict = None) -> int:
|
|
3138
|
+
def count(self, distinct: typing.Optional[bool] = None, cache: AnyDict = None) -> int:
|
|
3124
3139
|
"""
|
|
3125
3140
|
Count returns an int.
|
|
3126
3141
|
"""
|
|
@@ -5,7 +5,6 @@ ONLY USE IN COMBINATION WITH PY4WEB!
|
|
|
5
5
|
import typing
|
|
6
6
|
|
|
7
7
|
import threadsafevariable
|
|
8
|
-
from configuraptor.abs import AnyType
|
|
9
8
|
from py4web.core import ICECUBE
|
|
10
9
|
from py4web.core import Fixture as _Fixture
|
|
11
10
|
from pydal.base import MetaDAL, hashlib_md5
|
|
@@ -68,8 +67,8 @@ def setup_py4web_tables(db: TypeDAL) -> None:
|
|
|
68
67
|
|
|
69
68
|
|
|
70
69
|
__all__ = [
|
|
70
|
+
"DAL",
|
|
71
71
|
"AuthUser",
|
|
72
72
|
"Fixture",
|
|
73
|
-
"DAL",
|
|
74
73
|
"setup_py4web_tables",
|
|
75
74
|
]
|
|
@@ -55,7 +55,7 @@ def all_dict(cls: type) -> AnyDict:
|
|
|
55
55
|
return dict(ChainMap(*(c.__dict__ for c in reversed_mro(cls)))) # type: ignore
|
|
56
56
|
|
|
57
57
|
|
|
58
|
-
def all_annotations(cls: type, _except: typing.Iterable[str] = None) -> dict[str, type]:
|
|
58
|
+
def all_annotations(cls: type, _except: typing.Optional[typing.Iterable[str]] = None) -> dict[str, type]:
|
|
59
59
|
"""
|
|
60
60
|
Wrapper around `_all_annotations` that filters away any keys in _except.
|
|
61
61
|
|
|
@@ -306,6 +306,10 @@ def get_field(field: "TypedField[typing.Any] | Field") -> "Field":
|
|
|
306
306
|
|
|
307
307
|
|
|
308
308
|
class classproperty:
|
|
309
|
+
"""
|
|
310
|
+
Combination of @classmethod and @property.
|
|
311
|
+
"""
|
|
312
|
+
|
|
309
313
|
def __init__(self, fget: typing.Callable[..., typing.Any]) -> None:
|
|
310
314
|
"""
|
|
311
315
|
Initialize the classproperty.
|
|
@@ -163,7 +163,11 @@ class SlugMixin(Mixin):
|
|
|
163
163
|
) # set via init subclass
|
|
164
164
|
|
|
165
165
|
def __init_subclass__(
|
|
166
|
-
cls,
|
|
166
|
+
cls,
|
|
167
|
+
slug_field: typing.Optional[str] = None,
|
|
168
|
+
slug_suffix_length: int = 0,
|
|
169
|
+
slug_suffix: Optional[int] = None,
|
|
170
|
+
**kw: Any,
|
|
167
171
|
) -> None:
|
|
168
172
|
"""
|
|
169
173
|
Bind 'slug field' option to be used later (on_define).
|
|
@@ -68,7 +68,7 @@ class SerializedJson(ConfigurableJsonEncoder):
|
|
|
68
68
|
return _rules.get(_type, JSONRule(transform=self._default) if with_default else None)
|
|
69
69
|
|
|
70
70
|
|
|
71
|
-
def encode(something: Any, indent: int = None, **kw: Any) -> str:
|
|
71
|
+
def encode(something: Any, indent: typing.Optional[int] = None, **kw: Any) -> str:
|
|
72
72
|
"""
|
|
73
73
|
Encode anything to JSON with some improved defaults.
|
|
74
74
|
"""
|
|
@@ -166,6 +166,11 @@ def test_mixed_defines(capsys):
|
|
|
166
166
|
|
|
167
167
|
assert SecondNewSyntax(1).location == "Rotterdam"
|
|
168
168
|
|
|
169
|
+
# test find_model:
|
|
170
|
+
assert db.find_model("old_syntax") is None
|
|
171
|
+
assert db.find_model("first_new_syntax") is FirstNewSyntax
|
|
172
|
+
assert db.find_model("second_new_syntax") is SecondNewSyntax
|
|
173
|
+
|
|
169
174
|
|
|
170
175
|
def test_dont_allow_bool_in_query():
|
|
171
176
|
with pytest.raises(ValueError):
|
|
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
|
|
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
|
|
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
|