TypeDAL 3.17.3__tar.gz → 4.0.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.

Files changed (69) hide show
  1. {typedal-3.17.3 → typedal-4.0.0}/.github/workflows/su6.yml +3 -2
  2. {typedal-3.17.3 → typedal-4.0.0}/.readthedocs.yml +1 -1
  3. {typedal-3.17.3 → typedal-4.0.0}/CHANGELOG.md +25 -0
  4. {typedal-3.17.3 → typedal-4.0.0}/PKG-INFO +8 -7
  5. {typedal-3.17.3 → typedal-4.0.0}/pyproject.toml +14 -9
  6. {typedal-3.17.3 → typedal-4.0.0}/src/typedal/__about__.py +1 -1
  7. {typedal-3.17.3 → typedal-4.0.0}/src/typedal/__init__.py +9 -9
  8. {typedal-3.17.3 → typedal-4.0.0}/src/typedal/caching.py +36 -33
  9. {typedal-3.17.3 → typedal-4.0.0}/src/typedal/config.py +15 -16
  10. typedal-4.0.0/src/typedal/constants.py +25 -0
  11. typedal-4.0.0/src/typedal/core.py +460 -0
  12. typedal-4.0.0/src/typedal/define.py +188 -0
  13. typedal-4.0.0/src/typedal/fields.py +577 -0
  14. {typedal-3.17.3 → typedal-4.0.0}/src/typedal/for_web2py.py +1 -1
  15. typedal-4.0.0/src/typedal/helpers.py +622 -0
  16. {typedal-3.17.3 → typedal-4.0.0}/src/typedal/mixins.py +21 -25
  17. typedal-4.0.0/src/typedal/query_builder.py +1059 -0
  18. typedal-4.0.0/src/typedal/relationships.py +264 -0
  19. typedal-4.0.0/src/typedal/rows.py +524 -0
  20. {typedal-3.17.3 → typedal-4.0.0}/src/typedal/serializers/as_json.py +9 -10
  21. typedal-4.0.0/src/typedal/tables.py +1122 -0
  22. typedal-4.0.0/src/typedal/types.py +323 -0
  23. {typedal-3.17.3 → typedal-4.0.0}/src/typedal/web2py_py4web_shared.py +1 -1
  24. typedal-4.0.0/tests/py314_tests.py +146 -0
  25. {typedal-3.17.3 → typedal-4.0.0}/tests/test_helpers.py +32 -4
  26. {typedal-3.17.3 → typedal-4.0.0}/tests/test_main.py +43 -3
  27. {typedal-3.17.3 → typedal-4.0.0}/tests/test_mixins.py +0 -3
  28. {typedal-3.17.3 → typedal-4.0.0}/tests/test_mypy.py +13 -12
  29. {typedal-3.17.3 → typedal-4.0.0}/tests/test_orm.py +0 -26
  30. {typedal-3.17.3 → typedal-4.0.0}/tests/test_query_builder.py +1 -2
  31. {typedal-3.17.3 → typedal-4.0.0}/tests/test_relationships.py +60 -19
  32. typedal-3.17.3/src/typedal/core.py +0 -3452
  33. typedal-3.17.3/src/typedal/fields.py +0 -352
  34. typedal-3.17.3/src/typedal/helpers.py +0 -415
  35. typedal-3.17.3/src/typedal/types.py +0 -317
  36. {typedal-3.17.3 → typedal-4.0.0}/.gitignore +0 -0
  37. {typedal-3.17.3 → typedal-4.0.0}/README.md +0 -0
  38. {typedal-3.17.3 → typedal-4.0.0}/coverage.svg +0 -0
  39. {typedal-3.17.3 → typedal-4.0.0}/docs/1_getting_started.md +0 -0
  40. {typedal-3.17.3 → typedal-4.0.0}/docs/2_defining_tables.md +0 -0
  41. {typedal-3.17.3 → typedal-4.0.0}/docs/3_building_queries.md +0 -0
  42. {typedal-3.17.3 → typedal-4.0.0}/docs/4_relationships.md +0 -0
  43. {typedal-3.17.3 → typedal-4.0.0}/docs/5_py4web.md +0 -0
  44. {typedal-3.17.3 → typedal-4.0.0}/docs/6_migrations.md +0 -0
  45. {typedal-3.17.3 → typedal-4.0.0}/docs/7_mixins.md +0 -0
  46. {typedal-3.17.3 → typedal-4.0.0}/docs/css/code_blocks.css +0 -0
  47. {typedal-3.17.3 → typedal-4.0.0}/docs/index.md +0 -0
  48. {typedal-3.17.3 → typedal-4.0.0}/docs/requirements.txt +0 -0
  49. {typedal-3.17.3 → typedal-4.0.0}/example_new.py +0 -0
  50. {typedal-3.17.3 → typedal-4.0.0}/example_old.py +0 -0
  51. {typedal-3.17.3 → typedal-4.0.0}/mkdocs.yml +0 -0
  52. {typedal-3.17.3 → typedal-4.0.0}/src/typedal/cli.py +0 -0
  53. {typedal-3.17.3 → typedal-4.0.0}/src/typedal/for_py4web.py +0 -0
  54. {typedal-3.17.3 → typedal-4.0.0}/src/typedal/py.typed +0 -0
  55. {typedal-3.17.3 → typedal-4.0.0}/tests/__init__.py +0 -0
  56. {typedal-3.17.3 → typedal-4.0.0}/tests/configs/simple.toml +0 -0
  57. {typedal-3.17.3 → typedal-4.0.0}/tests/configs/valid.env +0 -0
  58. {typedal-3.17.3 → typedal-4.0.0}/tests/configs/valid.toml +0 -0
  59. {typedal-3.17.3 → typedal-4.0.0}/tests/test_cli.py +0 -0
  60. {typedal-3.17.3 → typedal-4.0.0}/tests/test_config.py +0 -0
  61. {typedal-3.17.3 → typedal-4.0.0}/tests/test_docs_examples.py +0 -0
  62. {typedal-3.17.3 → typedal-4.0.0}/tests/test_json.py +0 -0
  63. {typedal-3.17.3 → typedal-4.0.0}/tests/test_py4web.py +0 -0
  64. {typedal-3.17.3 → typedal-4.0.0}/tests/test_row.py +0 -0
  65. {typedal-3.17.3 → typedal-4.0.0}/tests/test_stats.py +0 -0
  66. {typedal-3.17.3 → typedal-4.0.0}/tests/test_table.py +0 -0
  67. {typedal-3.17.3 → typedal-4.0.0}/tests/test_web2py.py +0 -0
  68. {typedal-3.17.3 → typedal-4.0.0}/tests/test_xx_others.py +0 -0
  69. {typedal-3.17.3 → typedal-4.0.0}/tests/timings.py +0 -0
@@ -11,7 +11,7 @@ jobs:
11
11
  - uses: actions/checkout@v3
12
12
  - uses: actions/setup-python@v4
13
13
  with:
14
- python-version: '3.10'
14
+ python-version: '3.11'
15
15
  - uses: yezz123/setup-uv@v4
16
16
  with:
17
17
  uv-venv: ".venv"
@@ -25,7 +25,8 @@ jobs:
25
25
  - uses: actions/checkout@v3
26
26
  - uses: actions/setup-python@v4
27
27
  with:
28
- python-version: '3.13'
28
+ python-version: '3.14'
29
+ allow-prereleases: true
29
30
  - uses: yezz123/setup-uv@v4
30
31
  with:
31
32
  uv-venv: ".venv"
@@ -3,7 +3,7 @@ version: 2
3
3
  build:
4
4
  os: ubuntu-22.04
5
5
  tools:
6
- python: "3.10"
6
+ python: "3.11"
7
7
 
8
8
  mkdocs:
9
9
  configuration: mkdocs.yml
@@ -2,6 +2,31 @@
2
2
 
3
3
  <!--next-version-placeholder-->
4
4
 
5
+ ## v4.0.0 (2025-10-12)
6
+
7
+ ### Feature
8
+
9
+ * Continued work for nested joins like .join('relationship.with_relationship'), still some todo's for test coverage ([`2a57301`](https://github.com/trialandsuccess/TypeDAL/commit/2a57301bdb7f6e3075bd156a3e79f7f8c922382f))
10
+ * Support nested joins like .join('relationship.with_relationship') ([`6ac30d0`](https://github.com/trialandsuccess/TypeDAL/commit/6ac30d0ad8f0c4e2cb67de92852c917b3c8bb94e))
11
+ * T-string support for `sql_expression` and `executesql` in Python 3.14 ([`7d21200`](https://github.com/trialandsuccess/TypeDAL/commit/7d2120062021579b1dee4a46fde6e6da61b62671))
12
+ * Extend Expression functionality with Python 3.14 template strings (t-string) ([`b902005`](https://github.com/trialandsuccess/TypeDAL/commit/b902005f378f2fe7cfe89feb3a76bb6e079edc7b))
13
+
14
+ ### Fix
15
+
16
+ * Bump pydal to version that supports 3.14 ([`b4c836c`](https://github.com/trialandsuccess/TypeDAL/commit/b4c836c3a6a0363ac3e9f3c2018147b15b639016))
17
+ * Support .orderby as alias for .select(orderby= ([`e6d33e6`](https://github.com/trialandsuccess/TypeDAL/commit/e6d33e608c37d0e594881594b869063557b18758))
18
+ * Fix 3.14-related issues in tests and bump typer to specific version to prevent breaking changes (clirunner in test) ([`1c23954`](https://github.com/trialandsuccess/TypeDAL/commit/1c2395486d1a6d7990ccabaaf016e378e6aff5e0))
19
+ * Don't force slug if already manually set ([`f14962c`](https://github.com/trialandsuccess/TypeDAL/commit/f14962c1b1bb7b6f659071f97ec2bf3d8287e609))
20
+ * Support explicit `ForwardRef()` ([`74edf4c`](https://github.com/trialandsuccess/TypeDAL/commit/74edf4c32d93289098fb8b34bcf2e58b47a33bd9))
21
+ * Use custom patched pydal for python 3.14 ([`07040ad`](https://github.com/trialandsuccess/TypeDAL/commit/07040ade9ebf86d4c05a0519b4ceccfacd62195e))
22
+ * Better error for missing ForwardRef ([`b7df789`](https://github.com/trialandsuccess/TypeDAL/commit/b7df7895f7995b524c0571485068be98fcf7c39c))
23
+ * Upgrade to at least configuraptor 1.27.1 for python 3.14 ([`19cebd2`](https://github.com/trialandsuccess/TypeDAL/commit/19cebd26473fe7343d8a777274b4f5fa0b2d78e6))
24
+ * Prepare for python 3.14 which introduces annotationlib to parse (forward reference) annotations ([`75bb725`](https://github.com/trialandsuccess/TypeDAL/commit/75bb7256bf790a518803437096fec24739fc35c0))
25
+
26
+ ### Documentation
27
+
28
+ * Remove old annotation parsing comments that are irrelevant with annotationlib ([`8ff6d73`](https://github.com/trialandsuccess/TypeDAL/commit/8ff6d7382e2bec5a50b40308d76645d098cad973))
29
+
5
30
  ## v3.17.3 (2025-09-30)
6
31
 
7
32
  ### Fix
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: TypeDAL
3
- Version: 3.17.3
3
+ Version: 4.0.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
@@ -8,18 +8,19 @@ Project-URL: Source, https://github.com/trialandsuccess/TypeDAL
8
8
  Author-email: Robin van der Noord <contact@trialandsuccess.nl>
9
9
  Classifier: Development Status :: 4 - Beta
10
10
  Classifier: Programming Language :: Python
11
- Classifier: Programming Language :: Python :: 3.10
12
11
  Classifier: Programming Language :: Python :: 3.11
13
12
  Classifier: Programming Language :: Python :: 3.12
14
13
  Classifier: Programming Language :: Python :: 3.13
14
+ Classifier: Programming Language :: Python :: 3.14
15
15
  Classifier: Programming Language :: Python :: Implementation :: CPython
16
16
  Classifier: Programming Language :: Python :: Implementation :: PyPy
17
- Requires-Python: >=3.10
17
+ Requires-Python: >=3.11
18
18
  Requires-Dist: configurable-json<2
19
- Requires-Dist: configuraptor<2,>=1.26.2
19
+ Requires-Dist: configuraptor<2,>=1.27.1
20
20
  Requires-Dist: dill<1
21
21
  Requires-Dist: legacy-cgi; python_version >= '3.13'
22
- Requires-Dist: pydal<=20250228.1
22
+ Requires-Dist: pydal>=20251012.3
23
+ Requires-Dist: python-dateutil<3
23
24
  Requires-Dist: python-slugify<9
24
25
  Provides-Extra: all
25
26
  Requires-Dist: edwh-migrate[full]>=0.8.0; extra == 'all'
@@ -28,7 +29,7 @@ Requires-Dist: pydal2sql[all]>=1.2.0; extra == 'all'
28
29
  Requires-Dist: questionary; extra == 'all'
29
30
  Requires-Dist: tabulate; extra == 'all'
30
31
  Requires-Dist: tomlkit; extra == 'all'
31
- Requires-Dist: typer; extra == 'all'
32
+ Requires-Dist: typer<0.19,>=0.18; extra == 'all'
32
33
  Provides-Extra: dev
33
34
  Requires-Dist: contextlib-chdir; extra == 'dev'
34
35
  Requires-Dist: hatch; extra == 'dev'
@@ -48,7 +49,7 @@ Requires-Dist: pydal2sql>=1.2.0; extra == 'migrations'
48
49
  Requires-Dist: questionary; extra == 'migrations'
49
50
  Requires-Dist: tabulate; extra == 'migrations'
50
51
  Requires-Dist: tomlkit; extra == 'migrations'
51
- Requires-Dist: typer; extra == 'migrations'
52
+ Requires-Dist: typer<0.19,>=0.18; extra == 'migrations'
52
53
  Provides-Extra: py4web
53
54
  Requires-Dist: py4web; extra == 'py4web'
54
55
  Description-Content-Type: text/markdown
@@ -2,12 +2,15 @@
2
2
  requires = ["hatchling"]
3
3
  build-backend = "hatchling.build"
4
4
 
5
+ [tool.hatch.metadata]
6
+ allow-direct-references = true
7
+
5
8
  [project]
6
9
  name = "TypeDAL"
7
10
  dynamic = ["version"]
8
11
  description = 'Typing support for PyDAL'
9
12
  readme = "README.md"
10
- requires-python = ">=3.10"
13
+ requires-python = ">=3.11"
11
14
  license-expression = "MIT"
12
15
  keywords = []
13
16
  authors = [
@@ -16,20 +19,21 @@ authors = [
16
19
  classifiers = [
17
20
  "Development Status :: 4 - Beta",
18
21
  "Programming Language :: Python",
19
- "Programming Language :: Python :: 3.10",
20
22
  "Programming Language :: Python :: 3.11",
21
23
  "Programming Language :: Python :: 3.12",
22
24
  "Programming Language :: Python :: 3.13",
25
+ "Programming Language :: Python :: 3.14",
23
26
  "Programming Language :: Python :: Implementation :: CPython",
24
27
  "Programming Language :: Python :: Implementation :: PyPy",
25
28
  ]
26
29
  dependencies = [
27
- "pydal <= 20250228.1", # core
30
+ "pydal >= 20251012.3", # core
28
31
  "dill < 1", # caching
29
- "configuraptor >= 1.26.2, < 2", # config
32
+ "configuraptor >= 1.27.1, < 2", # config
30
33
  "Configurable-JSON < 2", # json dumping
31
34
  "python-slugify < 9",
32
- "legacy-cgi; python_version >= '3.13'"
35
+ "legacy-cgi; python_version >= '3.13'",
36
+ "python-dateutil < 3",
33
37
  ]
34
38
 
35
39
  [project.optional-dependencies]
@@ -38,7 +42,7 @@ py4web = [
38
42
  ]
39
43
 
40
44
  migrations = [
41
- "typer",
45
+ "typer >=0.18, <0.19",
42
46
  "tabulate",
43
47
  "pydal2sql>=1.2.0",
44
48
  "edwh-migrate>=0.8.0",
@@ -48,7 +52,7 @@ migrations = [
48
52
 
49
53
  all = [
50
54
  "py4web",
51
- "typer",
55
+ "typer >=0.18, <0.19",
52
56
  "tabulate",
53
57
  "pydal2sql[all]>=1.2.0",
54
58
  "edwh-migrate[full]>=0.8.0",
@@ -114,7 +118,7 @@ badge = true
114
118
  mypy = "--disable-error-code misc"
115
119
 
116
120
  [tool.black]
117
- target-version = ["py310"]
121
+ target-version = ["py313"]
118
122
  line-length = 120
119
123
  # 'extend-exclude' excludes files or directories in addition to the defaults
120
124
  extend-exclude = '''
@@ -130,6 +134,7 @@ extend-exclude = '''
130
134
  [tool.coverage.report]
131
135
  exclude_also = [
132
136
  "if TYPE_CHECKING:",
137
+ "if t.TYPE_CHECKING:",
133
138
  "if typing.TYPE_CHECKING:",
134
139
  "except ImportError as e:",
135
140
  "except ImportError:",
@@ -156,7 +161,7 @@ strict = true
156
161
  exclude = ["venv", ".bak"]
157
162
 
158
163
  [tool.ruff]
159
- target-version = "py310"
164
+ target-version = "py313"
160
165
  line-length = 120
161
166
 
162
167
  extend-exclude = ["*.bak/", "venv*/"]
@@ -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__ = "3.17.3"
8
+ __version__ = "4.0.0"
@@ -2,16 +2,15 @@
2
2
  TypeDAL Library.
3
3
  """
4
4
 
5
- from . import fields
6
- from .core import (
7
- Relationship,
8
- TypeDAL,
9
- TypedField,
10
- TypedRows,
11
- TypedTable,
12
- relationship,
13
- )
5
+ from .core import TypeDAL
6
+ from .fields import TypedField
14
7
  from .helpers import sql_expression
8
+ from .query_builder import QueryBuilder
9
+ from .relationships import Relationship, relationship
10
+ from .rows import TypedRows
11
+ from .tables import TypedTable
12
+
13
+ from . import fields # isort: skip
15
14
 
16
15
  try:
17
16
  from .for_py4web import DAL as P4W_DAL
@@ -19,6 +18,7 @@ except ImportError: # pragma: no cover
19
18
  P4W_DAL = None # type: ignore
20
19
 
21
20
  __all__ = [
21
+ "QueryBuilder",
22
22
  "Relationship",
23
23
  "TypeDAL",
24
24
  "TypedField",
@@ -3,27 +3,28 @@ Helpers to facilitate db-based caching.
3
3
  """
4
4
 
5
5
  import contextlib
6
+ import datetime as dt
6
7
  import hashlib
7
8
  import json
8
- import typing
9
- from datetime import datetime, timedelta, timezone
10
- from typing import Any, Iterable, Mapping, Optional, TypeVar
9
+ import typing as t
11
10
 
12
11
  import dill # nosec
13
12
  from pydal.objects import Field, Rows, Set
14
13
 
15
- from .core import TypedField, TypedRows, TypedTable
14
+ from .fields import TypedField
15
+ from .rows import TypedRows
16
+ from .tables import TypedTable
16
17
  from .types import Query
17
18
 
18
- if typing.TYPE_CHECKING:
19
+ if t.TYPE_CHECKING:
19
20
  from .core import TypeDAL
20
21
 
21
22
 
22
- def get_now(tz: timezone = timezone.utc) -> datetime:
23
+ def get_now(tz: dt.timezone = dt.timezone.utc) -> dt.datetime:
23
24
  """
24
25
  Get the default datetime, optionally in a specific timezone.
25
26
  """
26
- return datetime.now(tz)
27
+ return dt.datetime.now(tz)
27
28
 
28
29
 
29
30
  class _TypedalCache(TypedTable):
@@ -33,8 +34,8 @@ class _TypedalCache(TypedTable):
33
34
 
34
35
  key: TypedField[str]
35
36
  data: TypedField[bytes]
36
- cached_at = TypedField(datetime, default=get_now)
37
- expires_at: TypedField[datetime | None]
37
+ cached_at = TypedField(dt.datetime, default=get_now)
38
+ expires_at: TypedField[dt.datetime | None]
38
39
 
39
40
 
40
41
  class _TypedalCacheDependency(TypedTable):
@@ -47,7 +48,7 @@ class _TypedalCacheDependency(TypedTable):
47
48
  idx: TypedField[int]
48
49
 
49
50
 
50
- def prepare(field: Any) -> str:
51
+ def prepare(field: t.Any) -> str:
51
52
  """
52
53
  Prepare data to be used in a cache key.
53
54
 
@@ -56,10 +57,10 @@ def prepare(field: Any) -> str:
56
57
  """
57
58
  if isinstance(field, str):
58
59
  return field
59
- elif isinstance(field, (dict, Mapping)):
60
+ elif isinstance(field, (dict, t.Mapping)):
60
61
  data = {str(k): prepare(v) for k, v in field.items()}
61
62
  return json.dumps(data, sort_keys=True)
62
- elif isinstance(field, Iterable):
63
+ elif isinstance(field, t.Iterable):
63
64
  return ",".join(sorted([prepare(_) for _ in field]))
64
65
  elif isinstance(field, bool):
65
66
  return str(int(field))
@@ -67,7 +68,7 @@ def prepare(field: Any) -> str:
67
68
  return str(field)
68
69
 
69
70
 
70
- def create_cache_key(*fields: Any) -> str:
71
+ def create_cache_key(*fields: t.Any) -> str:
71
72
  """
72
73
  Turn any fields of data into a string.
73
74
  """
@@ -83,7 +84,7 @@ def hash_cache_key(cache_key: str | bytes) -> str:
83
84
  return h.hexdigest()
84
85
 
85
86
 
86
- def create_and_hash_cache_key(*fields: Any) -> tuple[str, str]:
87
+ def create_and_hash_cache_key(*fields: t.Any) -> tuple[str, str]:
87
88
  """
88
89
  Combine the input fields into one key and hash it with SHA 256.
89
90
  """
@@ -112,7 +113,7 @@ def _get_dependency_ids(rows: Rows, dependency_keys: list[tuple[Field, str]]) ->
112
113
  return dependencies
113
114
 
114
115
 
115
- def _determine_dependencies_auto(_: TypedRows[Any], rows: Rows) -> DependencyTupleSet:
116
+ def _determine_dependencies_auto(_: TypedRows[t.Any], rows: Rows) -> DependencyTupleSet:
116
117
  dependency_keys = []
117
118
  for field in rows.fields:
118
119
  if str(field).endswith(".id"):
@@ -123,7 +124,7 @@ def _determine_dependencies_auto(_: TypedRows[Any], rows: Rows) -> DependencyTup
123
124
  return _get_dependency_ids(rows, dependency_keys)
124
125
 
125
126
 
126
- def _determine_dependencies(instance: TypedRows[Any], rows: Rows, depends_on: list[Any]) -> DependencyTupleSet:
127
+ def _determine_dependencies(instance: TypedRows[t.Any], rows: Rows, depends_on: list[t.Any]) -> DependencyTupleSet:
127
128
  if not depends_on:
128
129
  return _determine_dependencies_auto(instance, rows)
129
130
 
@@ -144,11 +145,11 @@ def _determine_dependencies(instance: TypedRows[Any], rows: Rows, depends_on: li
144
145
  return _get_dependency_ids(rows, dependency_keys)
145
146
 
146
147
 
147
- def remove_cache(idx: int | Iterable[int], table: str) -> None:
148
+ def remove_cache(idx: int | t.Iterable[int], table: str) -> None:
148
149
  """
149
150
  Remove any cache entries that are dependant on one or multiple indices of a table.
150
151
  """
151
- if not isinstance(idx, Iterable):
152
+ if not isinstance(idx, t.Iterable):
152
153
  idx = [idx]
153
154
 
154
155
  related = (
@@ -184,12 +185,14 @@ def _remove_cache(s: Set, tablename: str) -> None:
184
185
  remove_cache(indeces, tablename)
185
186
 
186
187
 
187
- T_TypedTable = TypeVar("T_TypedTable", bound=TypedTable)
188
+ T_TypedTable = t.TypeVar("T_TypedTable", bound=TypedTable)
188
189
 
189
190
 
190
191
  def get_expire(
191
- expires_at: Optional[datetime] = None, ttl: Optional[int | timedelta] = None, now: Optional[datetime] = None
192
- ) -> datetime | None:
192
+ expires_at: t.Optional[dt.datetime] = None,
193
+ ttl: t.Optional[int | dt.timedelta] = None,
194
+ now: t.Optional[dt.datetime] = None,
195
+ ) -> dt.datetime | None:
193
196
  """
194
197
  Based on an expires_at date or a ttl (in seconds or a time delta), determine the expire date.
195
198
  """
@@ -197,10 +200,10 @@ def get_expire(
197
200
 
198
201
  if expires_at and ttl:
199
202
  raise ValueError("Please only supply an `expired at` date or a `ttl` in seconds!")
200
- elif isinstance(ttl, timedelta):
203
+ elif isinstance(ttl, dt.timedelta):
201
204
  return now + ttl
202
205
  elif ttl:
203
- return now + timedelta(seconds=ttl)
206
+ return now + dt.timedelta(seconds=ttl)
204
207
  elif expires_at:
205
208
  return expires_at
206
209
 
@@ -210,8 +213,8 @@ def get_expire(
210
213
  def save_to_cache(
211
214
  instance: TypedRows[T_TypedTable],
212
215
  rows: Rows,
213
- expires_at: Optional[datetime] = None,
214
- ttl: Optional[int | timedelta] = None,
216
+ expires_at: t.Optional[dt.datetime] = None,
217
+ ttl: t.Optional[int | dt.timedelta] = None,
215
218
  ) -> TypedRows[T_TypedTable]:
216
219
  """
217
220
  Save a typedrows result to the database, and save dependencies from rows.
@@ -237,13 +240,13 @@ def save_to_cache(
237
240
  return instance
238
241
 
239
242
 
240
- def _load_from_cache(key: str, db: "TypeDAL") -> Any | None:
243
+ def _load_from_cache(key: str, db: "TypeDAL") -> t.Any | None:
241
244
  if not (row := _TypedalCache.where(key=key).first()):
242
245
  return None
243
246
 
244
247
  now = get_now()
245
248
 
246
- expires = row.expires_at.replace(tzinfo=timezone.utc) if row.expires_at else None
249
+ expires = row.expires_at.replace(tzinfo=dt.timezone.utc) if row.expires_at else None
247
250
 
248
251
  if expires and now >= expires:
249
252
  row.delete_record()
@@ -261,7 +264,7 @@ def _load_from_cache(key: str, db: "TypeDAL") -> Any | None:
261
264
  return inst
262
265
 
263
266
 
264
- def load_from_cache(key: str, db: "TypeDAL") -> Any | None:
267
+ def load_from_cache(key: str, db: "TypeDAL") -> t.Any | None:
265
268
  """
266
269
  If 'key' matches a non-expired row in the database, try to load the dill.
267
270
 
@@ -302,10 +305,10 @@ def _expired_and_valid_query() -> tuple[str, str]:
302
305
  return expired_items, valid_items
303
306
 
304
307
 
305
- T = typing.TypeVar("T")
306
- Stats = typing.TypedDict("Stats", {"total": T, "valid": T, "expired": T})
308
+ T = t.TypeVar("T")
309
+ Stats = t.TypedDict("Stats", {"total": T, "valid": T, "expired": T})
307
310
 
308
- RowStats = typing.TypedDict(
311
+ RowStats = t.TypedDict(
309
312
  "RowStats",
310
313
  {
311
314
  "Dependent Cache Entries": int,
@@ -338,7 +341,7 @@ def row_stats(db: "TypeDAL", table: str, row_id: str) -> Stats[RowStats]:
338
341
  }
339
342
 
340
343
 
341
- TableStats = typing.TypedDict(
344
+ TableStats = t.TypedDict(
342
345
  "TableStats",
343
346
  {
344
347
  "Dependent Cache Entries": int,
@@ -371,7 +374,7 @@ def table_stats(db: "TypeDAL", table: str) -> Stats[TableStats]:
371
374
  }
372
375
 
373
376
 
374
- GenericStats = typing.TypedDict(
377
+ GenericStats = t.TypedDict(
375
378
  "GenericStats",
376
379
  {
377
380
  "entries": int,
@@ -4,11 +4,10 @@ TypeDAL can be configured by a combination of pyproject.toml (static), env (dyna
4
4
 
5
5
  import os
6
6
  import re
7
- import typing
7
+ import typing as t
8
8
  import warnings
9
9
  from collections import defaultdict
10
10
  from pathlib import Path
11
- from typing import Any, Optional
12
11
 
13
12
  import tomli
14
13
  from configuraptor import TypedConfig, alias
@@ -17,7 +16,7 @@ from dotenv import dotenv_values, find_dotenv
17
16
 
18
17
  from .types import AnyDict
19
18
 
20
- if typing.TYPE_CHECKING:
19
+ if t.TYPE_CHECKING:
21
20
  from edwh_migrate import Config as MigrateConfig
22
21
  from pydal2sql.typer_support import Config as P2SConfig
23
22
 
@@ -41,15 +40,15 @@ class TypeDALConfig(TypedConfig):
41
40
  output: str = ""
42
41
  noop: bool = False
43
42
  magic: bool = True
44
- tables: Optional[list[str]] = None
43
+ tables: t.Optional[list[str]] = None
45
44
  function: str = "define_tables"
46
45
 
47
46
  # edwh-migrate:
48
47
  # migrate uri = database
49
- database_to_restore: Optional[str]
50
- migrate_cat_command: Optional[str]
51
- schema_version: Optional[str]
52
- redis_host: Optional[str]
48
+ database_to_restore: t.Optional[str]
49
+ migrate_cat_command: t.Optional[str]
50
+ schema_version: t.Optional[str]
51
+ redis_host: t.Optional[str]
53
52
  migrate_table: str = "typedal_implemented_features"
54
53
  flag_location: str
55
54
  create_flag_location: bool = True
@@ -148,7 +147,7 @@ def _load_toml(path: str | bool | Path | None = True) -> tuple[str, AnyDict]:
148
147
  with open(toml_path, "rb") as f:
149
148
  data = tomli.load(f)
150
149
 
151
- return str(toml_path) or "", typing.cast(AnyDict, data["tool"]["typedal"])
150
+ return str(toml_path) or "", t.cast(AnyDict, data["tool"]["typedal"])
152
151
  except Exception as e:
153
152
  warnings.warn(f"Could not load typedal config toml: {e}", source=e)
154
153
  return str(toml_path) or "", {}
@@ -194,7 +193,7 @@ def get_db_for_alias(db_name: str) -> str:
194
193
  return DB_ALIASES.get(db_name, db_name)
195
194
 
196
195
 
197
- DEFAULTS: dict[str, Any | typing.Callable[[AnyDict], Any]] = {
196
+ DEFAULTS: dict[str, t.Any | t.Callable[[AnyDict], t.Any]] = {
198
197
  "database": lambda data: data.get("db_uri") or "sqlite:memory",
199
198
  "dialect": lambda data: (
200
199
  get_db_for_alias(data["database"].split(":")[0]) if ":" in data["database"] else data.get("db_type")
@@ -208,7 +207,7 @@ DEFAULTS: dict[str, Any | typing.Callable[[AnyDict], Any]] = {
208
207
  }
209
208
 
210
209
 
211
- def _fill_defaults(data: AnyDict, prop: str, fallback: Any = None) -> None:
210
+ def _fill_defaults(data: AnyDict, prop: str, fallback: t.Any = None) -> None:
212
211
  default = DEFAULTS.get(prop, fallback)
213
212
  if callable(default):
214
213
  default = default(data)
@@ -223,7 +222,7 @@ def fill_defaults(data: AnyDict, prop: str) -> None:
223
222
  _fill_defaults(data, prop)
224
223
 
225
224
 
226
- TRANSFORMS: dict[str, typing.Callable[[AnyDict], Any]] = {
225
+ TRANSFORMS: dict[str, t.Callable[[AnyDict], t.Any]] = {
227
226
  "database": lambda data: (
228
227
  data["database"]
229
228
  if (":" in data["database"] or not data.get("dialect"))
@@ -264,7 +263,7 @@ def expand_posix_vars(posix_expr: str, context: dict[str, str]) -> str:
264
263
  # Regular expression to match "${VAR:default}" pattern
265
264
  pattern = r"\$\{([^}]+)\}"
266
265
 
267
- def replace_var(match: re.Match[Any]) -> str:
266
+ def replace_var(match: re.Match[t.Any]) -> str:
268
267
  var_with_default = match.group(1)
269
268
  var_name, default_value = var_with_default.split(":") if ":" in var_with_default else (var_with_default, "")
270
269
  return env.get(var_name.lower(), default_value)
@@ -325,10 +324,10 @@ def expand_env_vars_into_toml_values(toml: AnyDict, env: AnyDict) -> None:
325
324
 
326
325
 
327
326
  def load_config(
328
- connection_name: Optional[str] = None,
327
+ connection_name: t.Optional[str] = None,
329
328
  _use_pyproject: bool | str | None = True,
330
329
  _use_env: bool | str | None = True,
331
- **fallback: Any,
330
+ **fallback: t.Any,
332
331
  ) -> TypeDALConfig:
333
332
  """
334
333
  Combines multiple sources of config into one config instance.
@@ -338,7 +337,7 @@ def load_config(
338
337
  # combine and fill with fallback values
339
338
  # load typedal config or fail
340
339
  toml_path, toml = _load_toml(_use_pyproject)
341
- dotenv_path, dotenv = _load_dotenv(_use_env)
340
+ _dotenv_path, dotenv = _load_dotenv(_use_env)
342
341
 
343
342
  expand_env_vars_into_toml_values(toml, dotenv)
344
343
 
@@ -0,0 +1,25 @@
1
+ """
2
+ Constants values.
3
+ """
4
+
5
+ import datetime as dt
6
+ import typing as t
7
+ from decimal import Decimal
8
+
9
+ from .types import T_annotation
10
+
11
+ JOIN_OPTIONS = t.Literal["left", "inner", None]
12
+ DEFAULT_JOIN_OPTION: JOIN_OPTIONS = "left"
13
+
14
+ BASIC_MAPPINGS: dict[T_annotation, str] = {
15
+ str: "string",
16
+ int: "integer",
17
+ bool: "boolean",
18
+ bytes: "blob",
19
+ float: "double",
20
+ object: "json",
21
+ Decimal: "decimal(10,2)",
22
+ dt.date: "date",
23
+ dt.time: "time",
24
+ dt.datetime: "datetime",
25
+ }