TypeDAL 4.4.3__tar.gz → 4.4.5__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.4.3 → typedal-4.4.5}/.crush/crush.db-shm +0 -0
- typedal-4.4.5/.crush/crush.db-wal +0 -0
- typedal-4.4.5/.crush/logs/crush.log +37 -0
- {typedal-4.4.3 → typedal-4.4.5}/CHANGELOG.md +13 -0
- {typedal-4.4.3 → typedal-4.4.5}/PKG-INFO +1 -1
- {typedal-4.4.3 → typedal-4.4.5}/src/typedal/__about__.py +1 -1
- {typedal-4.4.3 → typedal-4.4.5}/src/typedal/caching.py +1 -1
- {typedal-4.4.3 → typedal-4.4.5}/src/typedal/config.py +1 -3
- {typedal-4.4.3 → typedal-4.4.5}/src/typedal/core.py +7 -7
- {typedal-4.4.3 → typedal-4.4.5}/src/typedal/define.py +3 -3
- {typedal-4.4.3 → typedal-4.4.5}/src/typedal/mixins.py +1 -1
- {typedal-4.4.3 → typedal-4.4.5}/src/typedal/query_builder.py +1 -1
- {typedal-4.4.3 → typedal-4.4.5}/src/typedal/relationships.py +36 -6
- {typedal-4.4.3 → typedal-4.4.5}/tests/test_relationships.py +8 -4
- typedal-4.4.3/.crush/crush.db-wal +0 -0
- typedal-4.4.3/.crush/logs/crush.log +0 -34
- {typedal-4.4.3 → typedal-4.4.5}/.crush/.gitignore +0 -0
- {typedal-4.4.3 → typedal-4.4.5}/.crush/init +0 -0
- {typedal-4.4.3 → typedal-4.4.5}/.github/workflows/su6.yml +0 -0
- {typedal-4.4.3 → typedal-4.4.5}/.gitignore +0 -0
- {typedal-4.4.3 → typedal-4.4.5}/.readthedocs.yml +0 -0
- {typedal-4.4.3 → typedal-4.4.5}/README.md +0 -0
- {typedal-4.4.3 → typedal-4.4.5}/coverage.svg +0 -0
- {typedal-4.4.3 → typedal-4.4.5}/docs/1_getting_started.md +0 -0
- {typedal-4.4.3 → typedal-4.4.5}/docs/2_defining_tables.md +0 -0
- {typedal-4.4.3 → typedal-4.4.5}/docs/3_building_queries.md +0 -0
- {typedal-4.4.3 → typedal-4.4.5}/docs/4_relationships.md +0 -0
- {typedal-4.4.3 → typedal-4.4.5}/docs/5_py4web.md +0 -0
- {typedal-4.4.3 → typedal-4.4.5}/docs/6_migrations.md +0 -0
- {typedal-4.4.3 → typedal-4.4.5}/docs/7_configuration.md +0 -0
- {typedal-4.4.3 → typedal-4.4.5}/docs/8_mixins.md +0 -0
- {typedal-4.4.3 → typedal-4.4.5}/docs/9_memoization.md +0 -0
- {typedal-4.4.3 → typedal-4.4.5}/docs/css/code_blocks.css +0 -0
- {typedal-4.4.3 → typedal-4.4.5}/docs/index.md +0 -0
- {typedal-4.4.3 → typedal-4.4.5}/docs/requirements.txt +0 -0
- {typedal-4.4.3 → typedal-4.4.5}/example_new.py +0 -0
- {typedal-4.4.3 → typedal-4.4.5}/example_old.py +0 -0
- {typedal-4.4.3 → typedal-4.4.5}/mkdocs.yml +0 -0
- {typedal-4.4.3 → typedal-4.4.5}/pyproject.toml +0 -0
- {typedal-4.4.3 → typedal-4.4.5}/src/typedal/__init__.py +0 -0
- {typedal-4.4.3 → typedal-4.4.5}/src/typedal/cli.py +0 -0
- {typedal-4.4.3 → typedal-4.4.5}/src/typedal/constants.py +0 -0
- {typedal-4.4.3 → typedal-4.4.5}/src/typedal/fields.py +0 -0
- {typedal-4.4.3 → typedal-4.4.5}/src/typedal/for_py4web.py +0 -0
- {typedal-4.4.3 → typedal-4.4.5}/src/typedal/for_web2py.py +0 -0
- {typedal-4.4.3 → typedal-4.4.5}/src/typedal/helpers.py +0 -0
- {typedal-4.4.3 → typedal-4.4.5}/src/typedal/py.typed +0 -0
- {typedal-4.4.3 → typedal-4.4.5}/src/typedal/rows.py +0 -0
- {typedal-4.4.3 → typedal-4.4.5}/src/typedal/serializers/as_json.py +0 -0
- {typedal-4.4.3 → typedal-4.4.5}/src/typedal/tables.py +0 -0
- {typedal-4.4.3 → typedal-4.4.5}/src/typedal/types.py +0 -0
- {typedal-4.4.3 → typedal-4.4.5}/src/typedal/web2py_py4web_shared.py +0 -0
- {typedal-4.4.3 → typedal-4.4.5}/tasks.py +0 -0
- {typedal-4.4.3 → typedal-4.4.5}/tests/__init__.py +0 -0
- {typedal-4.4.3 → typedal-4.4.5}/tests/configs/simple.toml +0 -0
- {typedal-4.4.3 → typedal-4.4.5}/tests/configs/valid.env +0 -0
- {typedal-4.4.3 → typedal-4.4.5}/tests/configs/valid.toml +0 -0
- {typedal-4.4.3 → typedal-4.4.5}/tests/py314_tests.py +0 -0
- {typedal-4.4.3 → typedal-4.4.5}/tests/test_cli.py +0 -0
- {typedal-4.4.3 → typedal-4.4.5}/tests/test_config.py +0 -0
- {typedal-4.4.3 → typedal-4.4.5}/tests/test_docs_examples.py +0 -0
- {typedal-4.4.3 → typedal-4.4.5}/tests/test_helpers.py +0 -0
- {typedal-4.4.3 → typedal-4.4.5}/tests/test_json.py +0 -0
- {typedal-4.4.3 → typedal-4.4.5}/tests/test_main.py +0 -0
- {typedal-4.4.3 → typedal-4.4.5}/tests/test_mixins.py +0 -0
- {typedal-4.4.3 → typedal-4.4.5}/tests/test_mypy.py +0 -0
- {typedal-4.4.3 → typedal-4.4.5}/tests/test_orm.py +0 -0
- {typedal-4.4.3 → typedal-4.4.5}/tests/test_py4web.py +0 -0
- {typedal-4.4.3 → typedal-4.4.5}/tests/test_query_builder.py +0 -0
- {typedal-4.4.3 → typedal-4.4.5}/tests/test_row.py +0 -0
- {typedal-4.4.3 → typedal-4.4.5}/tests/test_stats.py +0 -0
- {typedal-4.4.3 → typedal-4.4.5}/tests/test_table.py +0 -0
- {typedal-4.4.3 → typedal-4.4.5}/tests/test_web2py.py +0 -0
- {typedal-4.4.3 → typedal-4.4.5}/tests/test_xx_others.py +0 -0
- {typedal-4.4.3 → typedal-4.4.5}/tests/timings.py +0 -0
|
Binary file
|
|
Binary file
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
{"time":"2026-01-20T14:19:21.359487106+01:00","level":"INFO","source":{"function":"github.com/charmbracelet/crush/internal/config.(*catwalkSync).Get.func1","file":"github.com/charmbracelet/crush/internal/config/catwalk.go","line":55},"msg":"Fetching providers from Catwalk"}
|
|
2
|
+
{"time":"2026-01-20T14:19:21.518115889+01:00","level":"INFO","source":{"function":"github.com/charmbracelet/crush/internal/config.(*catwalkSync).Get.func1","file":"github.com/charmbracelet/crush/internal/config/catwalk.go","line":63},"msg":"Catwalk providers not modified"}
|
|
3
|
+
{"time":"2026-01-20T14:19:21.52626179+01:00","level":"INFO","msg":"OK 20250424200609_initial.sql (1.52ms)"}
|
|
4
|
+
{"time":"2026-01-20T14:19:21.526651475+01:00","level":"INFO","msg":"OK 20250515105448_add_summary_message_id.sql (330.71µs)"}
|
|
5
|
+
{"time":"2026-01-20T14:19:21.526995425+01:00","level":"INFO","msg":"OK 20250624000000_add_created_at_indexes.sql (325.29µs)"}
|
|
6
|
+
{"time":"2026-01-20T14:19:21.527303588+01:00","level":"INFO","msg":"OK 20250627000000_add_provider_to_messages.sql (293.15µs)"}
|
|
7
|
+
{"time":"2026-01-20T14:19:21.52790648+01:00","level":"INFO","msg":"OK 20250810000000_add_is_summary_message.sql (495.71µs)"}
|
|
8
|
+
{"time":"2026-01-20T14:19:21.528316924+01:00","level":"INFO","msg":"OK 20250812000000_add_todos_to_sessions.sql (389.38µs)"}
|
|
9
|
+
{"time":"2026-01-20T14:19:21.528324939+01:00","level":"INFO","msg":"goose: successfully migrated database to version: 20250812000000"}
|
|
10
|
+
{"time":"2026-01-20T14:19:21.528356959+01:00","level":"INFO","source":{"function":"github.com/charmbracelet/crush/internal/app.(*App).initLSPClients","file":"github.com/charmbracelet/crush/internal/app/lsp.go","line":21},"msg":"LSP clients initialization started in background"}
|
|
11
|
+
{"time":"2026-01-20T14:19:21.52843831+01:00","level":"INFO","source":{"function":"github.com/charmbracelet/crush/internal/app.New.func1","file":"github.com/charmbracelet/crush/internal/app/app.go","line":102},"msg":"Initializing MCP clients"}
|
|
12
|
+
{"time":"2026-01-20T14:21:06.413595152+01:00","level":"INFO","source":{"function":"github.com/charmbracelet/crush/internal/agent.(*sessionAgent).generateTitle","file":"github.com/charmbracelet/crush/internal/agent/agent.go","line":788},"msg":"generated title with small model"}
|
|
13
|
+
{"time":"2026-01-20T14:21:14.539289381+01:00","level":"INFO","source":{"function":"github.com/charmbracelet/crush/internal/agent.(*sessionAgent).generateTitle","file":"github.com/charmbracelet/crush/internal/agent/agent.go","line":788},"msg":"generated title with small model"}
|
|
14
|
+
{"time":"2026-01-20T14:21:15.710688424+01:00","level":"WARN","source":{"function":"github.com/charmbracelet/crush/internal/agent/tools.init.func1","file":"github.com/charmbracelet/crush/internal/agent/tools/rg.go","line":18},"msg":"Ripgrep (rg) not found in $PATH. Some grep features might be limited or slower."}
|
|
15
|
+
{"time":"2026-01-20T14:21:17.08089755+01:00","level":"INFO","source":{"function":"github.com/charmbracelet/crush/internal/agent.(*sessionAgent).generateTitle","file":"github.com/charmbracelet/crush/internal/agent/agent.go","line":788},"msg":"generated title with small model"}
|
|
16
|
+
{"time":"2026-01-20T14:21:17.151106375+01:00","level":"INFO","source":{"function":"github.com/charmbracelet/crush/internal/agent.(*sessionAgent).generateTitle","file":"github.com/charmbracelet/crush/internal/agent/agent.go","line":788},"msg":"generated title with small model"}
|
|
17
|
+
{"time":"2026-01-20T14:22:05.503761296+01:00","level":"INFO","source":{"function":"github.com/charmbracelet/crush/internal/agent.(*sessionAgent).generateTitle","file":"github.com/charmbracelet/crush/internal/agent/agent.go","line":788},"msg":"generated title with small model"}
|
|
18
|
+
{"time":"2026-01-20T14:26:05.030425805+01:00","level":"INFO","source":{"function":"github.com/charmbracelet/crush/internal/agent.(*sessionAgent).generateTitle","file":"github.com/charmbracelet/crush/internal/agent/agent.go","line":788},"msg":"generated title with small model"}
|
|
19
|
+
{"time":"2026-01-20T14:36:26.778665189+01:00","level":"INFO","source":{"function":"github.com/charmbracelet/crush/internal/agent.(*sessionAgent).generateTitle","file":"github.com/charmbracelet/crush/internal/agent/agent.go","line":788},"msg":"generated title with small model"}
|
|
20
|
+
{"time":"2026-01-20T14:38:51.314473736+01:00","level":"INFO","source":{"function":"github.com/charmbracelet/crush/internal/agent.(*sessionAgent).generateTitle","file":"github.com/charmbracelet/crush/internal/agent/agent.go","line":788},"msg":"generated title with small model"}
|
|
21
|
+
{"time":"2026-01-20T15:02:22.602405814+01:00","level":"INFO","source":{"function":"github.com/charmbracelet/crush/internal/app.(*App).Shutdown.func1","file":"github.com/charmbracelet/crush/internal/app/app.go","line":403},"msg":"Shutdown took 6.62949ms"}
|
|
22
|
+
{"time":"2026-01-20T15:02:23.719585648+01:00","level":"INFO","source":{"function":"github.com/charmbracelet/crush/internal/config.(*catwalkSync).Get.func1","file":"github.com/charmbracelet/crush/internal/config/catwalk.go","line":55},"msg":"Fetching providers from Catwalk"}
|
|
23
|
+
{"time":"2026-01-20T15:02:23.881789126+01:00","level":"INFO","source":{"function":"github.com/charmbracelet/crush/internal/config.(*catwalkSync).Get.func1","file":"github.com/charmbracelet/crush/internal/config/catwalk.go","line":63},"msg":"Catwalk providers not modified"}
|
|
24
|
+
{"time":"2026-01-20T15:02:23.884044691+01:00","level":"INFO","msg":"goose: no migrations to run. current version: 20250812000000"}
|
|
25
|
+
{"time":"2026-01-20T15:02:23.884082792+01:00","level":"INFO","source":{"function":"github.com/charmbracelet/crush/internal/app.(*App).initLSPClients","file":"github.com/charmbracelet/crush/internal/app/lsp.go","line":21},"msg":"LSP clients initialization started in background"}
|
|
26
|
+
{"time":"2026-01-20T15:02:23.884273487+01:00","level":"INFO","source":{"function":"github.com/charmbracelet/crush/internal/app.New.func1","file":"github.com/charmbracelet/crush/internal/app/app.go","line":102},"msg":"Initializing MCP clients"}
|
|
27
|
+
{"time":"2026-01-20T15:04:13.024457515+01:00","level":"INFO","source":{"function":"github.com/charmbracelet/crush/internal/agent.(*sessionAgent).generateTitle","file":"github.com/charmbracelet/crush/internal/agent/agent.go","line":788},"msg":"generated title with small model"}
|
|
28
|
+
{"time":"2026-01-20T15:04:14.232072885+01:00","level":"WARN","source":{"function":"github.com/charmbracelet/crush/internal/agent/tools.init.func1","file":"github.com/charmbracelet/crush/internal/agent/tools/rg.go","line":18},"msg":"Ripgrep (rg) not found in $PATH. Some grep features might be limited or slower."}
|
|
29
|
+
{"time":"2026-01-20T15:11:24.612161916+01:00","level":"INFO","source":{"function":"github.com/charmbracelet/crush/internal/app.(*App).Shutdown.func1","file":"github.com/charmbracelet/crush/internal/app/app.go","line":403},"msg":"Shutdown took 9.537141ms"}
|
|
30
|
+
{"time":"2026-01-20T15:11:25.263960575+01:00","level":"INFO","source":{"function":"github.com/charmbracelet/crush/internal/config.(*catwalkSync).Get.func1","file":"github.com/charmbracelet/crush/internal/config/catwalk.go","line":55},"msg":"Fetching providers from Catwalk"}
|
|
31
|
+
{"time":"2026-01-20T15:11:25.431990051+01:00","level":"INFO","source":{"function":"github.com/charmbracelet/crush/internal/config.(*catwalkSync).Get.func1","file":"github.com/charmbracelet/crush/internal/config/catwalk.go","line":63},"msg":"Catwalk providers not modified"}
|
|
32
|
+
{"time":"2026-01-20T15:11:25.434282035+01:00","level":"INFO","msg":"goose: no migrations to run. current version: 20250812000000"}
|
|
33
|
+
{"time":"2026-01-20T15:11:25.434366662+01:00","level":"INFO","source":{"function":"github.com/charmbracelet/crush/internal/app.(*App).initLSPClients","file":"github.com/charmbracelet/crush/internal/app/lsp.go","line":21},"msg":"LSP clients initialization started in background"}
|
|
34
|
+
{"time":"2026-01-20T15:11:25.434579879+01:00","level":"INFO","source":{"function":"github.com/charmbracelet/crush/internal/app.New.func1","file":"github.com/charmbracelet/crush/internal/app/app.go","line":102},"msg":"Initializing MCP clients"}
|
|
35
|
+
{"time":"2026-01-20T15:24:40.456010578+01:00","level":"INFO","source":{"function":"github.com/charmbracelet/crush/internal/agent.(*sessionAgent).generateTitle","file":"github.com/charmbracelet/crush/internal/agent/agent.go","line":788},"msg":"generated title with small model"}
|
|
36
|
+
{"time":"2026-01-20T15:24:51.673808433+01:00","level":"WARN","source":{"function":"github.com/charmbracelet/crush/internal/agent/tools.init.func1","file":"github.com/charmbracelet/crush/internal/agent/tools/rg.go","line":18},"msg":"Ripgrep (rg) not found in $PATH. Some grep features might be limited or slower."}
|
|
37
|
+
{"time":"2026-01-20T15:26:03.868420566+01:00","level":"INFO","source":{"function":"github.com/charmbracelet/crush/internal/agent.(*sessionAgent).Cancel","file":"github.com/charmbracelet/crush/internal/agent/agent.go","line":907},"msg":"Request cancellation initiated","session_id":"4c2d1684-8db2-4ffd-83bb-9c08fe850f29"}
|
|
@@ -2,6 +2,19 @@
|
|
|
2
2
|
|
|
3
3
|
<!--next-version-placeholder-->
|
|
4
4
|
|
|
5
|
+
## v4.4.5 (2026-02-27)
|
|
6
|
+
|
|
7
|
+
### Fix
|
|
8
|
+
|
|
9
|
+
* Add `Ref` type so you can do forward references in types, ([`3240a74`](https://github.com/trialandsuccess/TypeDAL/commit/3240a747a4dd63a887464c0a748c68907d38d7d0))
|
|
10
|
+
* Pass known classes as namespace so `col: "ForwardRef"` works in 3.13 too ([`b655da8`](https://github.com/trialandsuccess/TypeDAL/commit/b655da812d7ea014b95adf73974ca301a6c42ca2))
|
|
11
|
+
|
|
12
|
+
## v4.4.4 (2026-02-25)
|
|
13
|
+
|
|
14
|
+
### Fix
|
|
15
|
+
|
|
16
|
+
* **relationship:** Ensure get_db() also works with forward references by looking at other table (owner) as fallback ([`17dd7b4`](https://github.com/trialandsuccess/TypeDAL/commit/17dd7b4273819f2edf6d427264ee1a81622ef597))
|
|
17
|
+
|
|
5
18
|
## v4.4.3 (2026-02-11)
|
|
6
19
|
|
|
7
20
|
### Fix
|
|
@@ -577,7 +577,7 @@ def memoize(
|
|
|
577
577
|
return cached, "cached"
|
|
578
578
|
# Cache miss - compute result
|
|
579
579
|
|
|
580
|
-
def track_execute(_qb: "QueryBuilder[t.Any]", raw: Rows):
|
|
580
|
+
def track_execute(_qb: "QueryBuilder[t.Any]", raw: Rows) -> None:
|
|
581
581
|
# find dependant table+id combinations, includes relationships:
|
|
582
582
|
deps.update(_determine_dependencies_auto(raw))
|
|
583
583
|
|
|
@@ -9,13 +9,11 @@ from pathlib import Path
|
|
|
9
9
|
|
|
10
10
|
import tomli
|
|
11
11
|
from configuraptor import TypedConfig, alias
|
|
12
|
-
from configuraptor.helpers import find_pyproject_toml
|
|
12
|
+
from configuraptor.helpers import expand_env_vars_into_toml_values, find_pyproject_toml
|
|
13
13
|
from dotenv import dotenv_values, find_dotenv
|
|
14
14
|
|
|
15
15
|
from .types import AnyDict
|
|
16
16
|
|
|
17
|
-
from configuraptor.helpers import expand_env_vars_into_toml_values
|
|
18
|
-
|
|
19
17
|
if t.TYPE_CHECKING:
|
|
20
18
|
from edwh_migrate import Config as MigrateConfig
|
|
21
19
|
from pydal2sql.typer_support import Config as P2SConfig
|
|
@@ -106,27 +106,27 @@ def evaluate_forward_reference(
|
|
|
106
106
|
return evaluate_forward_reference_314(fw_ref, namespace=namespace or {})
|
|
107
107
|
|
|
108
108
|
|
|
109
|
-
def resolve_annotation_313(ftype: str) -> type: # pragma: no cover
|
|
109
|
+
def resolve_annotation_313(ftype: str, namespace: dict[str, type] | None = None) -> type: # pragma: no cover
|
|
110
110
|
"""
|
|
111
111
|
Resolve an annotation that's in string representation.
|
|
112
112
|
|
|
113
113
|
Variant for Python 3.13
|
|
114
114
|
"""
|
|
115
115
|
fw_ref: ForwardRef = t.get_args(t.Type[ftype])[0]
|
|
116
|
-
return evaluate_forward_reference(fw_ref)
|
|
116
|
+
return evaluate_forward_reference(fw_ref, namespace=namespace)
|
|
117
117
|
|
|
118
118
|
|
|
119
|
-
def resolve_annotation_314(ftype: str) -> type: # pragma: no cover
|
|
119
|
+
def resolve_annotation_314(ftype: str, namespace: dict[str, type] | None = None) -> type: # pragma: no cover
|
|
120
120
|
"""
|
|
121
121
|
Resolve an annotation that's in string representation.
|
|
122
122
|
|
|
123
123
|
Variant for Python 3.14 + using annotationlib
|
|
124
124
|
"""
|
|
125
125
|
fw_ref = ForwardRef(ftype)
|
|
126
|
-
return evaluate_forward_reference(fw_ref)
|
|
126
|
+
return evaluate_forward_reference(fw_ref, namespace=namespace)
|
|
127
127
|
|
|
128
128
|
|
|
129
|
-
def resolve_annotation(ftype: str) -> type: # pragma: no cover
|
|
129
|
+
def resolve_annotation(ftype: str, namespace: dict[str, type] | None = None) -> type: # pragma: no cover
|
|
130
130
|
"""
|
|
131
131
|
Resolve an annotation that's in string representation.
|
|
132
132
|
|
|
@@ -135,9 +135,9 @@ def resolve_annotation(ftype: str) -> type: # pragma: no cover
|
|
|
135
135
|
if sys.version_info.major != 3:
|
|
136
136
|
raise EnvironmentError("Only python 3 is supported.")
|
|
137
137
|
elif sys.version_info.minor <= 13:
|
|
138
|
-
return resolve_annotation_313(ftype)
|
|
138
|
+
return resolve_annotation_313(ftype, namespace=namespace)
|
|
139
139
|
else:
|
|
140
|
-
return resolve_annotation_314(ftype)
|
|
140
|
+
return resolve_annotation_314(ftype, namespace=namespace)
|
|
141
141
|
|
|
142
142
|
|
|
143
143
|
class TypeDAL(pydal.DAL):
|
|
@@ -133,13 +133,13 @@ class TableDefinitionBuilder:
|
|
|
133
133
|
"""Convert Python type annotation to pydal field type string."""
|
|
134
134
|
ftype = t.cast(type, ftype_annotation) # cast from Type to type to make mypy happy)
|
|
135
135
|
|
|
136
|
+
known_classes = {table.__name__: table for table in self.class_map.values()}
|
|
137
|
+
|
|
136
138
|
if isinstance(ftype, str):
|
|
137
139
|
# extract type from string
|
|
138
|
-
ftype = resolve_annotation(ftype)
|
|
140
|
+
ftype = resolve_annotation(ftype, namespace=known_classes)
|
|
139
141
|
|
|
140
142
|
if isinstance(ftype, ForwardRef):
|
|
141
|
-
known_classes = {table.__name__: table for table in self.class_map.values()}
|
|
142
|
-
|
|
143
143
|
ftype = evaluate_forward_reference(ftype, namespace=known_classes)
|
|
144
144
|
|
|
145
145
|
if mapping := BASIC_MAPPINGS.get(ftype):
|
|
@@ -116,7 +116,7 @@ class HAS_UNIQUE_SLUG(IS_NOT_IN_DB):
|
|
|
116
116
|
if not value.strip():
|
|
117
117
|
raise ValidationError(self.translator(self.error_message))
|
|
118
118
|
|
|
119
|
-
|
|
119
|
+
tablename, fieldname = str(self.field).split(".")
|
|
120
120
|
table = self.dbset.db[tablename]
|
|
121
121
|
field = table[fieldname]
|
|
122
122
|
query = field == value
|
|
@@ -555,7 +555,7 @@ class QueryBuilder(t.Generic[T_MetaInstance]):
|
|
|
555
555
|
for fn_before in db._before_execute:
|
|
556
556
|
fn_before(self)
|
|
557
557
|
|
|
558
|
-
rows = db(query).select(*select_args, **select_kwargs)
|
|
558
|
+
rows: Rows = db(query).select(*select_args, **select_kwargs)
|
|
559
559
|
|
|
560
560
|
for fn_after in db._after_execute:
|
|
561
561
|
fn_after(self, rows)
|
|
@@ -5,17 +5,18 @@ Contains base functionality related to Relationships.
|
|
|
5
5
|
import inspect
|
|
6
6
|
import typing as t
|
|
7
7
|
import warnings
|
|
8
|
+
from typing import ForwardRef
|
|
8
9
|
|
|
9
10
|
import pydal.objects
|
|
10
11
|
|
|
11
12
|
from .config import LazyPolicy
|
|
12
13
|
from .constants import JOIN_OPTIONS
|
|
13
|
-
from .core import TypeDAL
|
|
14
|
+
from .core import TypeDAL, evaluate_forward_reference
|
|
14
15
|
from .fields import TypedField
|
|
15
16
|
from .helpers import extract_type_optional, looks_like, unwrap_type
|
|
16
17
|
from .types import Condition, OnQuery, T_Field
|
|
17
18
|
|
|
18
|
-
To_Type = t.TypeVar("To_Type")
|
|
19
|
+
To_Type = t.TypeVar("To_Type", bound="TypedTable")
|
|
19
20
|
|
|
20
21
|
|
|
21
22
|
# default lazy policy is defined at the TypeDAL() instance settings level
|
|
@@ -37,6 +38,7 @@ class Relationship(t.Generic[To_Type]):
|
|
|
37
38
|
nested: dict[str, t.Self]
|
|
38
39
|
explicit: bool
|
|
39
40
|
name: str | None = None # set by __set_name__
|
|
41
|
+
_owner: t.Type["TypedTable"] | None = None
|
|
40
42
|
|
|
41
43
|
def __init__(
|
|
42
44
|
self,
|
|
@@ -62,6 +64,10 @@ class Relationship(t.Generic[To_Type]):
|
|
|
62
64
|
self.condition_and = condition_and
|
|
63
65
|
self._lazy = lazy
|
|
64
66
|
|
|
67
|
+
if t.get_origin(_type) == Ref:
|
|
68
|
+
# unwrap Ref["City"] to ForwardRef("City") to be evaluated/stringified later on:
|
|
69
|
+
_type = t.get_args(_type)[0]
|
|
70
|
+
|
|
65
71
|
if args := t.get_args(_type):
|
|
66
72
|
self.table = unwrap_type(args[0])
|
|
67
73
|
self.multiple = True
|
|
@@ -69,6 +75,12 @@ class Relationship(t.Generic[To_Type]):
|
|
|
69
75
|
self.table = t.cast(type[TypedTable], _type)
|
|
70
76
|
self.multiple = False
|
|
71
77
|
|
|
78
|
+
if isinstance(self.table, ForwardRef):
|
|
79
|
+
try:
|
|
80
|
+
self.table = evaluate_forward_reference(self.table)
|
|
81
|
+
except Exception:
|
|
82
|
+
self.table = self.table.__forward_arg__
|
|
83
|
+
|
|
72
84
|
if isinstance(self.table, str):
|
|
73
85
|
self.table = TypeDAL.to_snake(self.table)
|
|
74
86
|
|
|
@@ -120,6 +132,7 @@ class Relationship(t.Generic[To_Type]):
|
|
|
120
132
|
|
|
121
133
|
def __set_name__(self, owner: t.Type["TypedTable"], name: str) -> None:
|
|
122
134
|
"""Called automatically when assigned to a class attribute."""
|
|
135
|
+
self._owner = owner
|
|
123
136
|
self.name = name
|
|
124
137
|
|
|
125
138
|
def get_table(self, db: "TypeDAL") -> t.Type["TypedTable"]:
|
|
@@ -145,7 +158,12 @@ class Relationship(t.Generic[To_Type]):
|
|
|
145
158
|
Returns:
|
|
146
159
|
TypeDAL | None: The database instance if it exists, or None otherwise.
|
|
147
160
|
"""
|
|
148
|
-
|
|
161
|
+
target = self.table
|
|
162
|
+
|
|
163
|
+
if isinstance(target, str) and (owner := self._owner):
|
|
164
|
+
target = owner
|
|
165
|
+
|
|
166
|
+
return getattr(target, "_db", None)
|
|
149
167
|
|
|
150
168
|
@property
|
|
151
169
|
def lazy(self) -> LazyPolicy:
|
|
@@ -257,6 +275,18 @@ class Relationship(t.Generic[To_Type]):
|
|
|
257
275
|
return fallback_value
|
|
258
276
|
|
|
259
277
|
|
|
278
|
+
class Ref(t.Generic[To_Type]):
|
|
279
|
+
"""
|
|
280
|
+
Type-level forward reference wrapper.
|
|
281
|
+
|
|
282
|
+
Allows writing:
|
|
283
|
+
|
|
284
|
+
relationship(Ref["User"])
|
|
285
|
+
|
|
286
|
+
so that type checkers resolve the inner type correctly.
|
|
287
|
+
"""
|
|
288
|
+
|
|
289
|
+
|
|
260
290
|
@t.overload
|
|
261
291
|
def relationship(
|
|
262
292
|
_type: type[list[To_Type]],
|
|
@@ -279,7 +309,7 @@ def relationship(
|
|
|
279
309
|
|
|
280
310
|
@t.overload
|
|
281
311
|
def relationship(
|
|
282
|
-
_type: t.Type[To_Type] | str,
|
|
312
|
+
_type: t.Type[To_Type] | str | t.Type[Ref[To_Type]],
|
|
283
313
|
condition: Condition = None,
|
|
284
314
|
*,
|
|
285
315
|
join: t.Literal["inner"],
|
|
@@ -301,7 +331,7 @@ def relationship(
|
|
|
301
331
|
|
|
302
332
|
@t.overload
|
|
303
333
|
def relationship(
|
|
304
|
-
_type: t.Type[To_Type] | str,
|
|
334
|
+
_type: t.Type[To_Type] | str | t.Type[Ref[To_Type]],
|
|
305
335
|
condition: Condition = None,
|
|
306
336
|
join: JOIN_OPTIONS = None,
|
|
307
337
|
on: OnQuery = None,
|
|
@@ -320,7 +350,7 @@ def relationship(
|
|
|
320
350
|
|
|
321
351
|
|
|
322
352
|
def relationship(
|
|
323
|
-
_type: type[list[To_Type]] | t.Type[To_Type] | str,
|
|
353
|
+
_type: type[list[To_Type]] | t.Type[To_Type] | str | t.Type[Ref[To_Type]],
|
|
324
354
|
condition: Condition = None,
|
|
325
355
|
join: JOIN_OPTIONS = None,
|
|
326
356
|
on: OnQuery = None,
|
|
@@ -8,7 +8,7 @@ from uuid import uuid4
|
|
|
8
8
|
|
|
9
9
|
import pytest
|
|
10
10
|
|
|
11
|
-
from src.typedal import Relationship, TypeDAL, TypedField, TypedTable, relationship
|
|
11
|
+
from src.typedal import Relationship, TypeDAL, TypedField, TypedRows, TypedTable, relationship
|
|
12
12
|
from src.typedal.caching import (
|
|
13
13
|
_TypedalCache,
|
|
14
14
|
_TypedalCacheDependency,
|
|
@@ -16,10 +16,10 @@ from src.typedal.caching import (
|
|
|
16
16
|
clear_expired,
|
|
17
17
|
remove_cache,
|
|
18
18
|
)
|
|
19
|
+
from src.typedal.relationships import Ref
|
|
19
20
|
from src.typedal.serializers import as_json
|
|
20
|
-
from typedal import TypedRows
|
|
21
21
|
|
|
22
|
-
db = TypeDAL("sqlite:memory")
|
|
22
|
+
db = TypeDAL("sqlite:memory", lazy_policy="warn")
|
|
23
23
|
|
|
24
24
|
|
|
25
25
|
class TaggableMixin:
|
|
@@ -336,6 +336,7 @@ def test_reprs():
|
|
|
336
336
|
empty = Relationship("article")
|
|
337
337
|
|
|
338
338
|
assert empty.get_table(db) == Article
|
|
339
|
+
assert empty.get_db() is None
|
|
339
340
|
|
|
340
341
|
db.define_table("new")
|
|
341
342
|
empty = Relationship("new")
|
|
@@ -345,8 +346,10 @@ def test_reprs():
|
|
|
345
346
|
|
|
346
347
|
empty = Relationship(db.new)
|
|
347
348
|
assert empty.get_table(db) == db.new
|
|
349
|
+
assert empty.get_db() == db
|
|
348
350
|
|
|
349
351
|
assert empty.get_table_name() == "new"
|
|
352
|
+
assert User.bestie.get_db() == db
|
|
350
353
|
|
|
351
354
|
relation = Article.join("author").relationships["author"]
|
|
352
355
|
|
|
@@ -967,7 +970,8 @@ class Office(TypedTable):
|
|
|
967
970
|
city_id: City
|
|
968
971
|
company: "Company"
|
|
969
972
|
|
|
970
|
-
|
|
973
|
+
city = relationship(City, lambda office, city: office.city_id == city.id)
|
|
974
|
+
city_alternative = relationship(Ref["City"], lambda office, city: office.city_id == city.id)
|
|
971
975
|
|
|
972
976
|
|
|
973
977
|
class Company(TypedTable):
|
|
Binary file
|
|
@@ -1,34 +0,0 @@
|
|
|
1
|
-
{"time":"2026-01-26T17:01:48.91963488+01:00","level":"INFO","source":{"function":"github.com/charmbracelet/crush/internal/config.(*catwalkSync).Get.func1","file":"github.com/charmbracelet/crush/internal/config/catwalk.go","line":55},"msg":"Fetching providers from Catwalk"}
|
|
2
|
-
{"time":"2026-01-26T17:01:49.11634171+01:00","level":"INFO","source":{"function":"github.com/charmbracelet/crush/internal/config.(*catwalkSync).Get.func1","file":"github.com/charmbracelet/crush/internal/config/catwalk.go","line":63},"msg":"Catwalk providers not modified"}
|
|
3
|
-
{"time":"2026-01-26T17:01:49.116589785+01:00","level":"WARN","source":{"function":"github.com/charmbracelet/crush/internal/config.(*Config).configureProviders","file":"github.com/charmbracelet/crush/internal/config/load.go","line":259},"msg":"Skipping provider due to missing API key","provider":"anthropic"}
|
|
4
|
-
{"time":"2026-01-26T17:01:49.128053484+01:00","level":"INFO","msg":"OK 20250424200609_initial.sql (1.26ms)"}
|
|
5
|
-
{"time":"2026-01-26T17:01:49.128338994+01:00","level":"INFO","msg":"OK 20250515105448_add_summary_message_id.sql (263.8µs)"}
|
|
6
|
-
{"time":"2026-01-26T17:01:49.128678839+01:00","level":"INFO","msg":"OK 20250624000000_add_created_at_indexes.sql (325.2µs)"}
|
|
7
|
-
{"time":"2026-01-26T17:01:49.128984204+01:00","level":"INFO","msg":"OK 20250627000000_add_provider_to_messages.sql (291.73µs)"}
|
|
8
|
-
{"time":"2026-01-26T17:01:49.12929983+01:00","level":"INFO","msg":"OK 20250810000000_add_is_summary_message.sql (265.62µs)"}
|
|
9
|
-
{"time":"2026-01-26T17:01:49.129580779+01:00","level":"INFO","msg":"OK 20250812000000_add_todos_to_sessions.sql (268.09µs)"}
|
|
10
|
-
{"time":"2026-01-26T17:01:49.129585964+01:00","level":"INFO","msg":"goose: successfully migrated database to version: 20250812000000"}
|
|
11
|
-
{"time":"2026-01-26T17:01:49.129633405+01:00","level":"INFO","source":{"function":"github.com/charmbracelet/crush/internal/app.(*App).initLSPClients","file":"github.com/charmbracelet/crush/internal/app/lsp.go","line":21},"msg":"LSP clients initialization started in background"}
|
|
12
|
-
{"time":"2026-01-26T17:01:49.129745943+01:00","level":"INFO","source":{"function":"github.com/charmbracelet/crush/internal/app.New.func1","file":"github.com/charmbracelet/crush/internal/app/app.go","line":110},"msg":"Initializing MCP clients"}
|
|
13
|
-
{"time":"2026-01-26T17:01:49.73470854+01:00","level":"INFO","source":{"function":"github.com/charmbracelet/crush/internal/app.(*App).createAndStartLSPClient","file":"github.com/charmbracelet/crush/internal/app/lsp.go","line":76},"msg":"LSP client initialized","name":"python"}
|
|
14
|
-
{"time":"2026-01-26T17:02:52.962674187+01:00","level":"INFO","source":{"function":"github.com/charmbracelet/crush/internal/agent.(*sessionAgent).generateTitle","file":"github.com/charmbracelet/crush/internal/agent/agent.go","line":788},"msg":"generated title with small model"}
|
|
15
|
-
{"time":"2026-01-26T17:02:57.3247847+01:00","level":"WARN","source":{"function":"github.com/charmbracelet/crush/internal/agent/tools.init.func1","file":"github.com/charmbracelet/crush/internal/agent/tools/rg.go","line":18},"msg":"Ripgrep (rg) not found in $PATH. Some grep features might be limited or slower."}
|
|
16
|
-
{"time":"2026-01-26T17:11:33.432259554+01:00","level":"INFO","source":{"function":"github.com/charmbracelet/crush/internal/app.(*App).Shutdown.func1","file":"github.com/charmbracelet/crush/internal/app/app.go","line":507},"msg":"Shutdown took 6.286852ms"}
|
|
17
|
-
{"time":"2026-01-26T17:11:33.982816329+01:00","level":"INFO","source":{"function":"github.com/charmbracelet/crush/internal/config.(*catwalkSync).Get.func1","file":"github.com/charmbracelet/crush/internal/config/catwalk.go","line":55},"msg":"Fetching providers from Catwalk"}
|
|
18
|
-
{"time":"2026-01-26T17:11:34.178260248+01:00","level":"INFO","source":{"function":"github.com/charmbracelet/crush/internal/config.(*catwalkSync).Get.func1","file":"github.com/charmbracelet/crush/internal/config/catwalk.go","line":63},"msg":"Catwalk providers not modified"}
|
|
19
|
-
{"time":"2026-01-26T17:11:34.178494988+01:00","level":"WARN","source":{"function":"github.com/charmbracelet/crush/internal/config.(*Config).configureProviders","file":"github.com/charmbracelet/crush/internal/config/load.go","line":259},"msg":"Skipping provider due to missing API key","provider":"anthropic"}
|
|
20
|
-
{"time":"2026-01-26T17:11:34.18216688+01:00","level":"INFO","msg":"goose: no migrations to run. current version: 20250812000000"}
|
|
21
|
-
{"time":"2026-01-26T17:11:34.182194111+01:00","level":"INFO","source":{"function":"github.com/charmbracelet/crush/internal/app.(*App).initLSPClients","file":"github.com/charmbracelet/crush/internal/app/lsp.go","line":21},"msg":"LSP clients initialization started in background"}
|
|
22
|
-
{"time":"2026-01-26T17:11:34.182335616+01:00","level":"INFO","source":{"function":"github.com/charmbracelet/crush/internal/app.New.func1","file":"github.com/charmbracelet/crush/internal/app/app.go","line":110},"msg":"Initializing MCP clients"}
|
|
23
|
-
{"time":"2026-01-26T17:11:34.786142525+01:00","level":"INFO","source":{"function":"github.com/charmbracelet/crush/internal/app.(*App).createAndStartLSPClient","file":"github.com/charmbracelet/crush/internal/app/lsp.go","line":76},"msg":"LSP client initialized","name":"python"}
|
|
24
|
-
{"time":"2026-01-26T17:11:43.042930337+01:00","level":"INFO","source":{"function":"github.com/charmbracelet/crush/internal/agent.(*sessionAgent).generateTitle","file":"github.com/charmbracelet/crush/internal/agent/agent.go","line":788},"msg":"generated title with small model"}
|
|
25
|
-
{"time":"2026-01-26T17:11:44.911909276+01:00","level":"WARN","source":{"function":"github.com/charmbracelet/crush/internal/agent/tools.init.func1","file":"github.com/charmbracelet/crush/internal/agent/tools/rg.go","line":18},"msg":"Ripgrep (rg) not found in $PATH. Some grep features might be limited or slower."}
|
|
26
|
-
{"time":"2026-01-26T18:10:19.727802782+01:00","level":"INFO","source":{"function":"github.com/charmbracelet/crush/internal/config.(*catwalkSync).Get.func1","file":"github.com/charmbracelet/crush/internal/config/catwalk.go","line":55},"msg":"Fetching providers from Catwalk"}
|
|
27
|
-
{"time":"2026-01-26T18:10:19.926137244+01:00","level":"INFO","source":{"function":"github.com/charmbracelet/crush/internal/config.(*catwalkSync).Get.func1","file":"github.com/charmbracelet/crush/internal/config/catwalk.go","line":63},"msg":"Catwalk providers not modified"}
|
|
28
|
-
{"time":"2026-01-26T18:10:19.926245207+01:00","level":"WARN","source":{"function":"github.com/charmbracelet/crush/internal/config.(*Config).configureProviders","file":"github.com/charmbracelet/crush/internal/config/load.go","line":259},"msg":"Skipping provider due to missing API key","provider":"anthropic"}
|
|
29
|
-
{"time":"2026-01-26T18:10:19.927808467+01:00","level":"INFO","msg":"goose: no migrations to run. current version: 20250812000000"}
|
|
30
|
-
{"time":"2026-01-26T18:10:19.927858435+01:00","level":"INFO","source":{"function":"github.com/charmbracelet/crush/internal/app.(*App).initLSPClients","file":"github.com/charmbracelet/crush/internal/app/lsp.go","line":21},"msg":"LSP clients initialization started in background"}
|
|
31
|
-
{"time":"2026-01-26T18:10:19.928006013+01:00","level":"INFO","source":{"function":"github.com/charmbracelet/crush/internal/app.New.func1","file":"github.com/charmbracelet/crush/internal/app/app.go","line":110},"msg":"Initializing MCP clients"}
|
|
32
|
-
{"time":"2026-01-26T18:10:20.546676356+01:00","level":"INFO","source":{"function":"github.com/charmbracelet/crush/internal/app.(*App).createAndStartLSPClient","file":"github.com/charmbracelet/crush/internal/app/lsp.go","line":76},"msg":"LSP client initialized","name":"python"}
|
|
33
|
-
{"time":"2026-01-26T18:11:07.640056766+01:00","level":"INFO","source":{"function":"github.com/charmbracelet/crush/internal/agent.(*sessionAgent).generateTitle","file":"github.com/charmbracelet/crush/internal/agent/agent.go","line":788},"msg":"generated title with small model"}
|
|
34
|
-
{"time":"2026-01-26T18:11:11.201161834+01:00","level":"WARN","source":{"function":"github.com/charmbracelet/crush/internal/agent/tools.init.func1","file":"github.com/charmbracelet/crush/internal/agent/tools/rg.go","line":18},"msg":"Ripgrep (rg) not found in $PATH. Some grep features might be limited or slower."}
|
|
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
|