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.
Files changed (69) hide show
  1. {typedal-4.6.4 → typedal-4.7.0}/CHANGELOG.md +6 -0
  2. {typedal-4.6.4 → typedal-4.7.0}/PKG-INFO +1 -1
  3. {typedal-4.6.4 → typedal-4.7.0}/src/typedal/__about__.py +1 -1
  4. {typedal-4.6.4 → typedal-4.7.0}/src/typedal/define.py +26 -0
  5. {typedal-4.6.4 → typedal-4.7.0}/tests/test_main.py +40 -0
  6. {typedal-4.6.4 → typedal-4.7.0}/.github/workflows/su6.yml +0 -0
  7. {typedal-4.6.4 → typedal-4.7.0}/.gitignore +0 -0
  8. {typedal-4.6.4 → typedal-4.7.0}/.readthedocs.yml +0 -0
  9. {typedal-4.6.4 → typedal-4.7.0}/README.md +0 -0
  10. {typedal-4.6.4 → typedal-4.7.0}/coverage.svg +0 -0
  11. {typedal-4.6.4 → typedal-4.7.0}/docs/10_advanced_apis.md +0 -0
  12. {typedal-4.6.4 → typedal-4.7.0}/docs/1_getting_started.md +0 -0
  13. {typedal-4.6.4 → typedal-4.7.0}/docs/2_defining_tables.md +0 -0
  14. {typedal-4.6.4 → typedal-4.7.0}/docs/3_building_queries.md +0 -0
  15. {typedal-4.6.4 → typedal-4.7.0}/docs/4_relationships.md +0 -0
  16. {typedal-4.6.4 → typedal-4.7.0}/docs/5_py4web.md +0 -0
  17. {typedal-4.6.4 → typedal-4.7.0}/docs/6_migrations.md +0 -0
  18. {typedal-4.6.4 → typedal-4.7.0}/docs/7_configuration.md +0 -0
  19. {typedal-4.6.4 → typedal-4.7.0}/docs/8_mixins.md +0 -0
  20. {typedal-4.6.4 → typedal-4.7.0}/docs/9_memoization.md +0 -0
  21. {typedal-4.6.4 → typedal-4.7.0}/docs/css/code_blocks.css +0 -0
  22. {typedal-4.6.4 → typedal-4.7.0}/docs/index.md +0 -0
  23. {typedal-4.6.4 → typedal-4.7.0}/docs/requirements.txt +0 -0
  24. {typedal-4.6.4 → typedal-4.7.0}/example_new.py +0 -0
  25. {typedal-4.6.4 → typedal-4.7.0}/example_old.py +0 -0
  26. {typedal-4.6.4 → typedal-4.7.0}/mkdocs.yml +0 -0
  27. {typedal-4.6.4 → typedal-4.7.0}/pyproject.toml +0 -0
  28. {typedal-4.6.4 → typedal-4.7.0}/src/typedal/__init__.py +0 -0
  29. {typedal-4.6.4 → typedal-4.7.0}/src/typedal/caching.py +0 -0
  30. {typedal-4.6.4 → typedal-4.7.0}/src/typedal/cli.py +0 -0
  31. {typedal-4.6.4 → typedal-4.7.0}/src/typedal/config.py +0 -0
  32. {typedal-4.6.4 → typedal-4.7.0}/src/typedal/constants.py +0 -0
  33. {typedal-4.6.4 → typedal-4.7.0}/src/typedal/core.py +0 -0
  34. {typedal-4.6.4 → typedal-4.7.0}/src/typedal/fields.py +0 -0
  35. {typedal-4.6.4 → typedal-4.7.0}/src/typedal/for_py4web.py +0 -0
  36. {typedal-4.6.4 → typedal-4.7.0}/src/typedal/for_web2py.py +0 -0
  37. {typedal-4.6.4 → typedal-4.7.0}/src/typedal/helpers.py +0 -0
  38. {typedal-4.6.4 → typedal-4.7.0}/src/typedal/mixins.py +0 -0
  39. {typedal-4.6.4 → typedal-4.7.0}/src/typedal/py.typed +0 -0
  40. {typedal-4.6.4 → typedal-4.7.0}/src/typedal/query_builder.py +0 -0
  41. {typedal-4.6.4 → typedal-4.7.0}/src/typedal/relationships.py +0 -0
  42. {typedal-4.6.4 → typedal-4.7.0}/src/typedal/rows.py +0 -0
  43. {typedal-4.6.4 → typedal-4.7.0}/src/typedal/serializers/as_json.py +0 -0
  44. {typedal-4.6.4 → typedal-4.7.0}/src/typedal/tables.py +0 -0
  45. {typedal-4.6.4 → typedal-4.7.0}/src/typedal/types.py +0 -0
  46. {typedal-4.6.4 → typedal-4.7.0}/src/typedal/web2py_py4web_shared.py +0 -0
  47. {typedal-4.6.4 → typedal-4.7.0}/tasks.py +0 -0
  48. {typedal-4.6.4 → typedal-4.7.0}/tests/__init__.py +0 -0
  49. {typedal-4.6.4 → typedal-4.7.0}/tests/configs/simple.toml +0 -0
  50. {typedal-4.6.4 → typedal-4.7.0}/tests/configs/valid.env +0 -0
  51. {typedal-4.6.4 → typedal-4.7.0}/tests/configs/valid.toml +0 -0
  52. {typedal-4.6.4 → typedal-4.7.0}/tests/py314_tests.py +0 -0
  53. {typedal-4.6.4 → typedal-4.7.0}/tests/test_cli.py +0 -0
  54. {typedal-4.6.4 → typedal-4.7.0}/tests/test_config.py +0 -0
  55. {typedal-4.6.4 → typedal-4.7.0}/tests/test_docs_examples.py +0 -0
  56. {typedal-4.6.4 → typedal-4.7.0}/tests/test_helpers.py +0 -0
  57. {typedal-4.6.4 → typedal-4.7.0}/tests/test_json.py +0 -0
  58. {typedal-4.6.4 → typedal-4.7.0}/tests/test_mixins.py +0 -0
  59. {typedal-4.6.4 → typedal-4.7.0}/tests/test_mypy.py +0 -0
  60. {typedal-4.6.4 → typedal-4.7.0}/tests/test_orm.py +0 -0
  61. {typedal-4.6.4 → typedal-4.7.0}/tests/test_py4web.py +0 -0
  62. {typedal-4.6.4 → typedal-4.7.0}/tests/test_query_builder.py +0 -0
  63. {typedal-4.6.4 → typedal-4.7.0}/tests/test_relationships.py +0 -0
  64. {typedal-4.6.4 → typedal-4.7.0}/tests/test_row.py +0 -0
  65. {typedal-4.6.4 → typedal-4.7.0}/tests/test_stats.py +0 -0
  66. {typedal-4.6.4 → typedal-4.7.0}/tests/test_table.py +0 -0
  67. {typedal-4.6.4 → typedal-4.7.0}/tests/test_web2py.py +0 -0
  68. {typedal-4.6.4 → typedal-4.7.0}/tests/test_xx_others.py +0 -0
  69. {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
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: TypeDAL
3
- Version: 4.6.4
3
+ Version: 4.7.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
@@ -5,4 +5,4 @@ This file contains the Version info for this package.
5
5
  # SPDX-FileCopyrightText: 2023-present Robin van der Noord <robinvandernoord@gmail.com>
6
6
  #
7
7
  # SPDX-License-Identifier: MIT
8
- __version__ = "4.6.4"
8
+ __version__ = "4.7.0"
@@ -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