TypeDAL 4.6.4__tar.gz → 4.7.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.
- {typedal-4.6.4 → typedal-4.7.0}/CHANGELOG.md +6 -0
- {typedal-4.6.4 → typedal-4.7.0}/PKG-INFO +1 -1
- {typedal-4.6.4 → typedal-4.7.0}/src/typedal/__about__.py +1 -1
- {typedal-4.6.4 → typedal-4.7.0}/src/typedal/define.py +26 -0
- {typedal-4.6.4 → typedal-4.7.0}/tests/test_main.py +40 -0
- {typedal-4.6.4 → typedal-4.7.0}/.github/workflows/su6.yml +0 -0
- {typedal-4.6.4 → typedal-4.7.0}/.gitignore +0 -0
- {typedal-4.6.4 → typedal-4.7.0}/.readthedocs.yml +0 -0
- {typedal-4.6.4 → typedal-4.7.0}/README.md +0 -0
- {typedal-4.6.4 → typedal-4.7.0}/coverage.svg +0 -0
- {typedal-4.6.4 → typedal-4.7.0}/docs/10_advanced_apis.md +0 -0
- {typedal-4.6.4 → typedal-4.7.0}/docs/1_getting_started.md +0 -0
- {typedal-4.6.4 → typedal-4.7.0}/docs/2_defining_tables.md +0 -0
- {typedal-4.6.4 → typedal-4.7.0}/docs/3_building_queries.md +0 -0
- {typedal-4.6.4 → typedal-4.7.0}/docs/4_relationships.md +0 -0
- {typedal-4.6.4 → typedal-4.7.0}/docs/5_py4web.md +0 -0
- {typedal-4.6.4 → typedal-4.7.0}/docs/6_migrations.md +0 -0
- {typedal-4.6.4 → typedal-4.7.0}/docs/7_configuration.md +0 -0
- {typedal-4.6.4 → typedal-4.7.0}/docs/8_mixins.md +0 -0
- {typedal-4.6.4 → typedal-4.7.0}/docs/9_memoization.md +0 -0
- {typedal-4.6.4 → typedal-4.7.0}/docs/css/code_blocks.css +0 -0
- {typedal-4.6.4 → typedal-4.7.0}/docs/index.md +0 -0
- {typedal-4.6.4 → typedal-4.7.0}/docs/requirements.txt +0 -0
- {typedal-4.6.4 → typedal-4.7.0}/example_new.py +0 -0
- {typedal-4.6.4 → typedal-4.7.0}/example_old.py +0 -0
- {typedal-4.6.4 → typedal-4.7.0}/mkdocs.yml +0 -0
- {typedal-4.6.4 → typedal-4.7.0}/pyproject.toml +0 -0
- {typedal-4.6.4 → typedal-4.7.0}/src/typedal/__init__.py +0 -0
- {typedal-4.6.4 → typedal-4.7.0}/src/typedal/caching.py +0 -0
- {typedal-4.6.4 → typedal-4.7.0}/src/typedal/cli.py +0 -0
- {typedal-4.6.4 → typedal-4.7.0}/src/typedal/config.py +0 -0
- {typedal-4.6.4 → typedal-4.7.0}/src/typedal/constants.py +0 -0
- {typedal-4.6.4 → typedal-4.7.0}/src/typedal/core.py +0 -0
- {typedal-4.6.4 → typedal-4.7.0}/src/typedal/fields.py +0 -0
- {typedal-4.6.4 → typedal-4.7.0}/src/typedal/for_py4web.py +0 -0
- {typedal-4.6.4 → typedal-4.7.0}/src/typedal/for_web2py.py +0 -0
- {typedal-4.6.4 → typedal-4.7.0}/src/typedal/helpers.py +0 -0
- {typedal-4.6.4 → typedal-4.7.0}/src/typedal/mixins.py +0 -0
- {typedal-4.6.4 → typedal-4.7.0}/src/typedal/py.typed +0 -0
- {typedal-4.6.4 → typedal-4.7.0}/src/typedal/query_builder.py +0 -0
- {typedal-4.6.4 → typedal-4.7.0}/src/typedal/relationships.py +0 -0
- {typedal-4.6.4 → typedal-4.7.0}/src/typedal/rows.py +0 -0
- {typedal-4.6.4 → typedal-4.7.0}/src/typedal/serializers/as_json.py +0 -0
- {typedal-4.6.4 → typedal-4.7.0}/src/typedal/tables.py +0 -0
- {typedal-4.6.4 → typedal-4.7.0}/src/typedal/types.py +0 -0
- {typedal-4.6.4 → typedal-4.7.0}/src/typedal/web2py_py4web_shared.py +0 -0
- {typedal-4.6.4 → typedal-4.7.0}/tasks.py +0 -0
- {typedal-4.6.4 → typedal-4.7.0}/tests/__init__.py +0 -0
- {typedal-4.6.4 → typedal-4.7.0}/tests/configs/simple.toml +0 -0
- {typedal-4.6.4 → typedal-4.7.0}/tests/configs/valid.env +0 -0
- {typedal-4.6.4 → typedal-4.7.0}/tests/configs/valid.toml +0 -0
- {typedal-4.6.4 → typedal-4.7.0}/tests/py314_tests.py +0 -0
- {typedal-4.6.4 → typedal-4.7.0}/tests/test_cli.py +0 -0
- {typedal-4.6.4 → typedal-4.7.0}/tests/test_config.py +0 -0
- {typedal-4.6.4 → typedal-4.7.0}/tests/test_docs_examples.py +0 -0
- {typedal-4.6.4 → typedal-4.7.0}/tests/test_helpers.py +0 -0
- {typedal-4.6.4 → typedal-4.7.0}/tests/test_json.py +0 -0
- {typedal-4.6.4 → typedal-4.7.0}/tests/test_mixins.py +0 -0
- {typedal-4.6.4 → typedal-4.7.0}/tests/test_mypy.py +0 -0
- {typedal-4.6.4 → typedal-4.7.0}/tests/test_orm.py +0 -0
- {typedal-4.6.4 → typedal-4.7.0}/tests/test_py4web.py +0 -0
- {typedal-4.6.4 → typedal-4.7.0}/tests/test_query_builder.py +0 -0
- {typedal-4.6.4 → typedal-4.7.0}/tests/test_relationships.py +0 -0
- {typedal-4.6.4 → typedal-4.7.0}/tests/test_row.py +0 -0
- {typedal-4.6.4 → typedal-4.7.0}/tests/test_stats.py +0 -0
- {typedal-4.6.4 → typedal-4.7.0}/tests/test_table.py +0 -0
- {typedal-4.6.4 → typedal-4.7.0}/tests/test_web2py.py +0 -0
- {typedal-4.6.4 → typedal-4.7.0}/tests/test_xx_others.py +0 -0
- {typedal-4.6.4 → typedal-4.7.0}/tests/timings.py +0 -0
|
@@ -2,6 +2,12 @@
|
|
|
2
2
|
|
|
3
3
|
<!--next-version-placeholder-->
|
|
4
4
|
|
|
5
|
+
## v4.7.0 (2026-04-20)
|
|
6
|
+
|
|
7
|
+
### Feature
|
|
8
|
+
|
|
9
|
+
* Support typing.Literal and Enum as field type with IS_IN_SET-based default 'requires' ([`221f60c`](https://github.com/trialandsuccess/TypeDAL/commit/221f60cf6db5cad5c12b5e8308ff00324583a6cb))
|
|
10
|
+
|
|
5
11
|
## v4.6.4 (2026-03-30)
|
|
6
12
|
|
|
7
13
|
### Fix
|
|
@@ -7,11 +7,13 @@ Since otherwise helper methods would clutter up the TypeDAl class.
|
|
|
7
7
|
from __future__ import annotations
|
|
8
8
|
|
|
9
9
|
import copy
|
|
10
|
+
import enum
|
|
10
11
|
import types
|
|
11
12
|
import typing as t
|
|
12
13
|
import warnings
|
|
13
14
|
|
|
14
15
|
import pydal
|
|
16
|
+
from pydal.validators import IS_IN_SET, ValidationError, Validator
|
|
15
17
|
|
|
16
18
|
from .constants import BASIC_MAPPINGS
|
|
17
19
|
from .core import TypeDAL, evaluate_forward_reference, resolve_annotation
|
|
@@ -42,6 +44,20 @@ except ImportError: # pragma: no cover
|
|
|
42
44
|
from typing import ForwardRef
|
|
43
45
|
|
|
44
46
|
|
|
47
|
+
class IS_IN_ENUM(Validator):
|
|
48
|
+
def __init__(self, etype: type[enum.Enum], error_message: str = "value not allowed"):
|
|
49
|
+
super().__init__()
|
|
50
|
+
self.etype = etype
|
|
51
|
+
self.error_message = error_message
|
|
52
|
+
|
|
53
|
+
def validate(self, value: t.Any, _record_id: int | None = None) -> t.Any:
|
|
54
|
+
if value not in self.etype:
|
|
55
|
+
raise ValidationError(self.translator(self.error_message))
|
|
56
|
+
|
|
57
|
+
# normalize value:
|
|
58
|
+
return self.etype(value).value
|
|
59
|
+
|
|
60
|
+
|
|
45
61
|
class TableDefinitionBuilder:
|
|
46
62
|
"""Handles the conversion of TypedTable classes to pydal tables."""
|
|
47
63
|
|
|
@@ -157,6 +173,16 @@ class TableDefinitionBuilder:
|
|
|
157
173
|
elif origin_is_subclass(ftype, TypedField):
|
|
158
174
|
# TypedField[int]
|
|
159
175
|
return self.annotation_to_pydal_fieldtype(t.get_args(ftype)[0], mut_kw)
|
|
176
|
+
elif t.get_origin(ftype) is t.Literal:
|
|
177
|
+
mut_kw.setdefault("requires", [IS_IN_SET(t.get_args(ftype))])
|
|
178
|
+
_child_type = type(t.get_args(ftype)[0])
|
|
179
|
+
return self.annotation_to_pydal_fieldtype(_child_type, mut_kw)
|
|
180
|
+
elif isinstance(ftype, type) and issubclass(ftype, enum.Enum):
|
|
181
|
+
_values = [v.value for v in ftype]
|
|
182
|
+
_child_type = type(_values[0])
|
|
183
|
+
# mut_kw.setdefault("requires", [IS_IN_SET(_values)])
|
|
184
|
+
mut_kw.setdefault("requires", [IS_IN_ENUM(ftype)])
|
|
185
|
+
return self.annotation_to_pydal_fieldtype(_child_type, mut_kw)
|
|
160
186
|
elif isinstance(ftype, types.GenericAlias) and t.get_origin(ftype) in (list, TypedField):
|
|
161
187
|
# list[str] -> str -> string -> list:string
|
|
162
188
|
_child_type = t.get_args(ftype)[0]
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import enum
|
|
1
2
|
import re
|
|
2
3
|
import sys
|
|
3
4
|
import typing
|
|
@@ -639,3 +640,42 @@ def test_reorder_fields():
|
|
|
639
640
|
# 'name' should be dropped:
|
|
640
641
|
Sub.reorder_fields(Sub.id, Sub.gid, keep_others=False)
|
|
641
642
|
assert list(Sub) == [Sub.id, Sub.gid]
|
|
643
|
+
|
|
644
|
+
|
|
645
|
+
def test_literal_enum_fields():
|
|
646
|
+
class TestEnum(enum.Enum):
|
|
647
|
+
FIRST = "first"
|
|
648
|
+
SECOND = 2
|
|
649
|
+
|
|
650
|
+
@db.define()
|
|
651
|
+
class LiteralTable(TypedTable):
|
|
652
|
+
lit_one: t.Literal["first", "second"]
|
|
653
|
+
lit_two = TypedField(t.Literal["first", "second"])
|
|
654
|
+
|
|
655
|
+
enum_one: TestEnum
|
|
656
|
+
enum_two = TypedField(TestEnum)
|
|
657
|
+
|
|
658
|
+
# should be ok
|
|
659
|
+
row, err = LiteralTable.validate_and_insert(
|
|
660
|
+
lit_one="first",
|
|
661
|
+
lit_two="second",
|
|
662
|
+
enum_one=TestEnum.FIRST,
|
|
663
|
+
enum_two=2,
|
|
664
|
+
)
|
|
665
|
+
assert not err, "unexpected error"
|
|
666
|
+
assert row, "expected row"
|
|
667
|
+
|
|
668
|
+
# should error on lit_one
|
|
669
|
+
row, err = LiteralTable.validate_and_insert(
|
|
670
|
+
lit_one="wrong",
|
|
671
|
+
lit_two="wronger",
|
|
672
|
+
enum_one=1,
|
|
673
|
+
enum_two="two",
|
|
674
|
+
)
|
|
675
|
+
assert not row, "unexpected row"
|
|
676
|
+
assert err, "expected err"
|
|
677
|
+
|
|
678
|
+
assert "lit_one" in err
|
|
679
|
+
assert "lit_two" in err
|
|
680
|
+
assert "enum_one" in err
|
|
681
|
+
assert "enum_two" in err
|
|
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
|
|
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
|