TypeDAL 4.4.2__tar.gz → 4.4.4__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.2 → typedal-4.4.4}/.crush/crush.db-shm +0 -0
- typedal-4.4.4/.crush/crush.db-wal +0 -0
- {typedal-4.4.2 → typedal-4.4.4}/.crush/logs/crush.log +9 -0
- {typedal-4.4.2 → typedal-4.4.4}/CHANGELOG.md +12 -0
- {typedal-4.4.2 → typedal-4.4.4}/PKG-INFO +3 -2
- {typedal-4.4.2 → typedal-4.4.4}/mkdocs.yml +2 -1
- {typedal-4.4.2 → typedal-4.4.4}/pyproject.toml +2 -1
- {typedal-4.4.2 → typedal-4.4.4}/src/typedal/__about__.py +1 -1
- {typedal-4.4.2 → typedal-4.4.4}/src/typedal/config.py +2 -84
- {typedal-4.4.2 → typedal-4.4.4}/src/typedal/relationships.py +8 -1
- typedal-4.4.4/tasks.py +54 -0
- {typedal-4.4.2 → typedal-4.4.4}/tests/test_relationships.py +4 -1
- typedal-4.4.2/.crush/crush.db-wal +0 -0
- {typedal-4.4.2 → typedal-4.4.4}/.crush/.gitignore +0 -0
- {typedal-4.4.2 → typedal-4.4.4}/.crush/init +0 -0
- {typedal-4.4.2 → typedal-4.4.4}/.github/workflows/su6.yml +0 -0
- {typedal-4.4.2 → typedal-4.4.4}/.gitignore +0 -0
- {typedal-4.4.2 → typedal-4.4.4}/.readthedocs.yml +0 -0
- {typedal-4.4.2 → typedal-4.4.4}/README.md +0 -0
- {typedal-4.4.2 → typedal-4.4.4}/coverage.svg +0 -0
- {typedal-4.4.2 → typedal-4.4.4}/docs/1_getting_started.md +0 -0
- {typedal-4.4.2 → typedal-4.4.4}/docs/2_defining_tables.md +0 -0
- {typedal-4.4.2 → typedal-4.4.4}/docs/3_building_queries.md +0 -0
- {typedal-4.4.2 → typedal-4.4.4}/docs/4_relationships.md +0 -0
- {typedal-4.4.2 → typedal-4.4.4}/docs/5_py4web.md +0 -0
- {typedal-4.4.2 → typedal-4.4.4}/docs/6_migrations.md +0 -0
- {typedal-4.4.2 → typedal-4.4.4}/docs/7_configuration.md +0 -0
- {typedal-4.4.2 → typedal-4.4.4}/docs/8_mixins.md +0 -0
- {typedal-4.4.2 → typedal-4.4.4}/docs/9_memoization.md +0 -0
- {typedal-4.4.2 → typedal-4.4.4}/docs/css/code_blocks.css +0 -0
- {typedal-4.4.2 → typedal-4.4.4}/docs/index.md +0 -0
- {typedal-4.4.2 → typedal-4.4.4}/docs/requirements.txt +0 -0
- {typedal-4.4.2 → typedal-4.4.4}/example_new.py +0 -0
- {typedal-4.4.2 → typedal-4.4.4}/example_old.py +0 -0
- {typedal-4.4.2 → typedal-4.4.4}/src/typedal/__init__.py +0 -0
- {typedal-4.4.2 → typedal-4.4.4}/src/typedal/caching.py +0 -0
- {typedal-4.4.2 → typedal-4.4.4}/src/typedal/cli.py +0 -0
- {typedal-4.4.2 → typedal-4.4.4}/src/typedal/constants.py +0 -0
- {typedal-4.4.2 → typedal-4.4.4}/src/typedal/core.py +0 -0
- {typedal-4.4.2 → typedal-4.4.4}/src/typedal/define.py +0 -0
- {typedal-4.4.2 → typedal-4.4.4}/src/typedal/fields.py +0 -0
- {typedal-4.4.2 → typedal-4.4.4}/src/typedal/for_py4web.py +0 -0
- {typedal-4.4.2 → typedal-4.4.4}/src/typedal/for_web2py.py +0 -0
- {typedal-4.4.2 → typedal-4.4.4}/src/typedal/helpers.py +0 -0
- {typedal-4.4.2 → typedal-4.4.4}/src/typedal/mixins.py +0 -0
- {typedal-4.4.2 → typedal-4.4.4}/src/typedal/py.typed +0 -0
- {typedal-4.4.2 → typedal-4.4.4}/src/typedal/query_builder.py +0 -0
- {typedal-4.4.2 → typedal-4.4.4}/src/typedal/rows.py +0 -0
- {typedal-4.4.2 → typedal-4.4.4}/src/typedal/serializers/as_json.py +0 -0
- {typedal-4.4.2 → typedal-4.4.4}/src/typedal/tables.py +0 -0
- {typedal-4.4.2 → typedal-4.4.4}/src/typedal/types.py +0 -0
- {typedal-4.4.2 → typedal-4.4.4}/src/typedal/web2py_py4web_shared.py +0 -0
- {typedal-4.4.2 → typedal-4.4.4}/tests/__init__.py +0 -0
- {typedal-4.4.2 → typedal-4.4.4}/tests/configs/simple.toml +0 -0
- {typedal-4.4.2 → typedal-4.4.4}/tests/configs/valid.env +0 -0
- {typedal-4.4.2 → typedal-4.4.4}/tests/configs/valid.toml +0 -0
- {typedal-4.4.2 → typedal-4.4.4}/tests/py314_tests.py +0 -0
- {typedal-4.4.2 → typedal-4.4.4}/tests/test_cli.py +0 -0
- {typedal-4.4.2 → typedal-4.4.4}/tests/test_config.py +0 -0
- {typedal-4.4.2 → typedal-4.4.4}/tests/test_docs_examples.py +0 -0
- {typedal-4.4.2 → typedal-4.4.4}/tests/test_helpers.py +0 -0
- {typedal-4.4.2 → typedal-4.4.4}/tests/test_json.py +0 -0
- {typedal-4.4.2 → typedal-4.4.4}/tests/test_main.py +0 -0
- {typedal-4.4.2 → typedal-4.4.4}/tests/test_mixins.py +0 -0
- {typedal-4.4.2 → typedal-4.4.4}/tests/test_mypy.py +0 -0
- {typedal-4.4.2 → typedal-4.4.4}/tests/test_orm.py +0 -0
- {typedal-4.4.2 → typedal-4.4.4}/tests/test_py4web.py +0 -0
- {typedal-4.4.2 → typedal-4.4.4}/tests/test_query_builder.py +0 -0
- {typedal-4.4.2 → typedal-4.4.4}/tests/test_row.py +0 -0
- {typedal-4.4.2 → typedal-4.4.4}/tests/test_stats.py +0 -0
- {typedal-4.4.2 → typedal-4.4.4}/tests/test_table.py +0 -0
- {typedal-4.4.2 → typedal-4.4.4}/tests/test_web2py.py +0 -0
- {typedal-4.4.2 → typedal-4.4.4}/tests/test_xx_others.py +0 -0
- {typedal-4.4.2 → typedal-4.4.4}/tests/timings.py +0 -0
|
Binary file
|
|
Binary file
|
|
@@ -23,3 +23,12 @@
|
|
|
23
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
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
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."}
|
|
@@ -2,6 +2,18 @@
|
|
|
2
2
|
|
|
3
3
|
<!--next-version-placeholder-->
|
|
4
4
|
|
|
5
|
+
## v4.4.4 (2026-02-25)
|
|
6
|
+
|
|
7
|
+
### Fix
|
|
8
|
+
|
|
9
|
+
* **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))
|
|
10
|
+
|
|
11
|
+
## v4.4.3 (2026-02-11)
|
|
12
|
+
|
|
13
|
+
### Fix
|
|
14
|
+
|
|
15
|
+
* Move env shell-style expansion to configuraptor, improved functionality using expandvars instead of custom implementation ([`8b41b91`](https://github.com/trialandsuccess/TypeDAL/commit/8b41b91d55c8893d5ce15c2decf6daa855fa230b))
|
|
16
|
+
|
|
5
17
|
## v4.4.2 (2026-01-26)
|
|
6
18
|
|
|
7
19
|
### Fix
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: TypeDAL
|
|
3
|
-
Version: 4.4.
|
|
3
|
+
Version: 4.4.4
|
|
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
|
|
@@ -16,7 +16,7 @@ Classifier: Programming Language :: Python :: Implementation :: CPython
|
|
|
16
16
|
Classifier: Programming Language :: Python :: Implementation :: PyPy
|
|
17
17
|
Requires-Python: >=3.11
|
|
18
18
|
Requires-Dist: configurable-json<2
|
|
19
|
-
Requires-Dist: configuraptor<2
|
|
19
|
+
Requires-Dist: configuraptor<3,>=2.0.1
|
|
20
20
|
Requires-Dist: dill<1
|
|
21
21
|
Requires-Dist: legacy-cgi; python_version >= '3.13'
|
|
22
22
|
Requires-Dist: pydal>=20251012.3
|
|
@@ -32,6 +32,7 @@ Requires-Dist: tomlkit; extra == 'all'
|
|
|
32
32
|
Requires-Dist: typer<0.19,>=0.18; extra == 'all'
|
|
33
33
|
Provides-Extra: dev
|
|
34
34
|
Requires-Dist: contextlib-chdir; extra == 'dev'
|
|
35
|
+
Requires-Dist: ewok; extra == 'dev'
|
|
35
36
|
Requires-Dist: hatch; extra == 'dev'
|
|
36
37
|
Requires-Dist: mkdocs; extra == 'dev'
|
|
37
38
|
Requires-Dist: mkdocs-dracula-theme; extra == 'dev'
|
|
@@ -6,10 +6,11 @@ nav:
|
|
|
6
6
|
- 2. Defining Tables: 2_defining_tables.md
|
|
7
7
|
- 3. Building Queries: 3_building_queries.md
|
|
8
8
|
- 4. Relationships: 4_relationships.md
|
|
9
|
-
- 5. py4web: 5_py4web.md
|
|
9
|
+
- 5. py4web and web2py: 5_py4web.md
|
|
10
10
|
- 6. Migrations: 6_migrations.md
|
|
11
11
|
- 7. Configuration: 7_configuration.md
|
|
12
12
|
- 8. Mixins: 8_mixins.md
|
|
13
|
+
- 9. Function Memoization: 9_memoization.md
|
|
13
14
|
extra:
|
|
14
15
|
version:
|
|
15
16
|
default: stable
|
|
@@ -29,7 +29,7 @@ classifiers = [
|
|
|
29
29
|
dependencies = [
|
|
30
30
|
"pydal >= 20251012.3", # core
|
|
31
31
|
"dill < 1", # caching
|
|
32
|
-
"configuraptor >=
|
|
32
|
+
"configuraptor >= 2.0.1, < 3", # config
|
|
33
33
|
"Configurable-JSON < 2", # json dumping
|
|
34
34
|
"python-slugify < 9",
|
|
35
35
|
"legacy-cgi; python_version >= '3.13'",
|
|
@@ -63,6 +63,7 @@ all = [
|
|
|
63
63
|
dev = [
|
|
64
64
|
# build:
|
|
65
65
|
"hatch",
|
|
66
|
+
"ewok",
|
|
66
67
|
# test:
|
|
67
68
|
"su6[all]>=1.9.0",
|
|
68
69
|
"python-semantic-release < 8",
|
|
@@ -3,10 +3,8 @@ TypeDAL can be configured by a combination of pyproject.toml (static), env (dyna
|
|
|
3
3
|
"""
|
|
4
4
|
|
|
5
5
|
import os
|
|
6
|
-
import re
|
|
7
6
|
import typing as t
|
|
8
7
|
import warnings
|
|
9
|
-
from collections import defaultdict
|
|
10
8
|
from pathlib import Path
|
|
11
9
|
|
|
12
10
|
import tomli
|
|
@@ -16,6 +14,8 @@ from dotenv import dotenv_values, find_dotenv
|
|
|
16
14
|
|
|
17
15
|
from .types import AnyDict
|
|
18
16
|
|
|
17
|
+
from configuraptor.helpers import expand_env_vars_into_toml_values
|
|
18
|
+
|
|
19
19
|
if t.TYPE_CHECKING:
|
|
20
20
|
from edwh_migrate import Config as MigrateConfig
|
|
21
21
|
from pydal2sql.typer_support import Config as P2SConfig
|
|
@@ -244,88 +244,6 @@ def transform(data: AnyDict, prop: str) -> bool:
|
|
|
244
244
|
return False
|
|
245
245
|
|
|
246
246
|
|
|
247
|
-
def expand_posix_vars(posix_expr: str, context: dict[str, str]) -> str:
|
|
248
|
-
"""
|
|
249
|
-
Replace case-insensitive POSIX and Docker Compose-like environment variables in a string with their values.
|
|
250
|
-
|
|
251
|
-
Args:
|
|
252
|
-
posix_expr (str): The input string containing case-insensitive POSIX or Docker Compose-like variables.
|
|
253
|
-
context (dict): A dictionary containing variable names and their respective values.
|
|
254
|
-
|
|
255
|
-
Returns:
|
|
256
|
-
str: The string with replaced variable values.
|
|
257
|
-
|
|
258
|
-
See Also:
|
|
259
|
-
https://stackoverflow.com/questions/386934/how-to-evaluate-environment-variables-into-a-string-in-python
|
|
260
|
-
and ChatGPT
|
|
261
|
-
"""
|
|
262
|
-
env = defaultdict(lambda: "")
|
|
263
|
-
for key, value in context.items():
|
|
264
|
-
env[key.lower()] = value
|
|
265
|
-
|
|
266
|
-
# Regular expression to match "${VAR:default}" pattern
|
|
267
|
-
pattern = r"\$\{([^}]+)\}"
|
|
268
|
-
|
|
269
|
-
def replace_var(match: re.Match[t.Any]) -> str:
|
|
270
|
-
var_with_default = match.group(1)
|
|
271
|
-
var_name, default_value = var_with_default.split(":") if ":" in var_with_default else (var_with_default, "")
|
|
272
|
-
return env.get(var_name.lower(), default_value)
|
|
273
|
-
|
|
274
|
-
return re.sub(pattern, replace_var, posix_expr)
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
def expand_env_vars_into_toml_values(toml: AnyDict, env: AnyDict) -> None:
|
|
278
|
-
"""
|
|
279
|
-
Recursively expands POSIX/Docker Compose-like environment variables in a TOML dictionary.
|
|
280
|
-
|
|
281
|
-
This function traverses a TOML dictionary and expands POSIX/Docker Compose-like
|
|
282
|
-
environment variables (${VAR:default}) using values provided in the 'env' dictionary.
|
|
283
|
-
It performs in-place modification of the 'toml' dictionary.
|
|
284
|
-
|
|
285
|
-
Args:
|
|
286
|
-
toml (dict): A TOML dictionary with string values possibly containing environment variables.
|
|
287
|
-
env (dict): A dictionary containing environment variable names and their respective values.
|
|
288
|
-
|
|
289
|
-
Returns:
|
|
290
|
-
None: The function modifies the 'toml' dictionary in place.
|
|
291
|
-
|
|
292
|
-
Notes:
|
|
293
|
-
The function recursively traverses the 'toml' dictionary. If a value is a string or a list of strings,
|
|
294
|
-
it attempts to substitute any environment variables found within those strings using the 'env' dictionary.
|
|
295
|
-
|
|
296
|
-
Example:
|
|
297
|
-
toml_data = {
|
|
298
|
-
'key1': 'This has ${ENV_VAR:default}',
|
|
299
|
-
'key2': ['String with ${ANOTHER_VAR}', 'Another ${YET_ANOTHER_VAR}']
|
|
300
|
-
}
|
|
301
|
-
environment = {
|
|
302
|
-
'ENV_VAR': 'replaced_value',
|
|
303
|
-
'ANOTHER_VAR': 'value_1',
|
|
304
|
-
'YET_ANOTHER_VAR': 'value_2'
|
|
305
|
-
}
|
|
306
|
-
|
|
307
|
-
expand_env_vars_into_toml_values(toml_data, environment)
|
|
308
|
-
# 'toml_data' will be modified in place:
|
|
309
|
-
# {
|
|
310
|
-
# 'key1': 'This has replaced_value',
|
|
311
|
-
# 'key2': ['String with value_1', 'Another value_2']
|
|
312
|
-
# }
|
|
313
|
-
"""
|
|
314
|
-
if not toml or not env:
|
|
315
|
-
return
|
|
316
|
-
|
|
317
|
-
for key, var in toml.items():
|
|
318
|
-
if isinstance(var, dict):
|
|
319
|
-
expand_env_vars_into_toml_values(var, env)
|
|
320
|
-
elif isinstance(var, list):
|
|
321
|
-
toml[key] = [expand_posix_vars(_, env) for _ in var if isinstance(_, str)]
|
|
322
|
-
elif isinstance(var, str):
|
|
323
|
-
toml[key] = expand_posix_vars(var, env)
|
|
324
|
-
else:
|
|
325
|
-
# nothing to substitute
|
|
326
|
-
continue
|
|
327
|
-
|
|
328
|
-
|
|
329
247
|
def load_config(
|
|
330
248
|
connection_name: t.Optional[str] = None,
|
|
331
249
|
_use_pyproject: bool | str | None = True,
|
|
@@ -37,6 +37,7 @@ class Relationship(t.Generic[To_Type]):
|
|
|
37
37
|
nested: dict[str, t.Self]
|
|
38
38
|
explicit: bool
|
|
39
39
|
name: str | None = None # set by __set_name__
|
|
40
|
+
_owner: t.Type["TypedTable"] | None = None
|
|
40
41
|
|
|
41
42
|
def __init__(
|
|
42
43
|
self,
|
|
@@ -120,6 +121,7 @@ class Relationship(t.Generic[To_Type]):
|
|
|
120
121
|
|
|
121
122
|
def __set_name__(self, owner: t.Type["TypedTable"], name: str) -> None:
|
|
122
123
|
"""Called automatically when assigned to a class attribute."""
|
|
124
|
+
self._owner = owner
|
|
123
125
|
self.name = name
|
|
124
126
|
|
|
125
127
|
def get_table(self, db: "TypeDAL") -> t.Type["TypedTable"]:
|
|
@@ -145,7 +147,12 @@ class Relationship(t.Generic[To_Type]):
|
|
|
145
147
|
Returns:
|
|
146
148
|
TypeDAL | None: The database instance if it exists, or None otherwise.
|
|
147
149
|
"""
|
|
148
|
-
|
|
150
|
+
target = self.table
|
|
151
|
+
|
|
152
|
+
if isinstance(target, str) and (owner := self._owner):
|
|
153
|
+
target = owner
|
|
154
|
+
|
|
155
|
+
return getattr(target, "_db", None)
|
|
149
156
|
|
|
150
157
|
@property
|
|
151
158
|
def lazy(self) -> LazyPolicy:
|
typedal-4.4.4/tasks.py
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
"""Task automation using ewok (invoke-compatible)."""
|
|
2
|
+
|
|
3
|
+
import re
|
|
4
|
+
from pathlib import Path
|
|
5
|
+
|
|
6
|
+
from ewok import Context, task
|
|
7
|
+
|
|
8
|
+
# Compiled regex pattern for replacing the nav section in mkdocs.yml
|
|
9
|
+
NAV_SECTION_PATTERN = re.compile(r"nav:.*?(?=\n[a-z_]+:|$)", re.DOTALL)
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
def extract_title(md_file: Path) -> str:
|
|
13
|
+
"""Extract the title from a markdown file's first heading."""
|
|
14
|
+
first_line = md_file.read_text(encoding="utf-8").split("\n", 1)[0].strip()
|
|
15
|
+
# Remove the leading # and any extra whitespace
|
|
16
|
+
return first_line.lstrip("#").strip()
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def generate_nav_entries() -> list[str]:
|
|
20
|
+
"""Generate nav entries from numbered markdown files in docs/."""
|
|
21
|
+
docs_dir = Path(__file__).parent / "docs"
|
|
22
|
+
|
|
23
|
+
# Find all numbered chapter files (supports 1-N digits)
|
|
24
|
+
chapters = [f for f in docs_dir.glob("*_*.md") if f.stem.split("_", 1)[0].isdigit()]
|
|
25
|
+
|
|
26
|
+
return [
|
|
27
|
+
f" - {extract_title(chapter)}: {chapter.name}"
|
|
28
|
+
for chapter in sorted(
|
|
29
|
+
chapters,
|
|
30
|
+
key=lambda f: int(f.stem.split("_", 1)[0]),
|
|
31
|
+
)
|
|
32
|
+
]
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
@task
|
|
36
|
+
def update_docs_nav(ctx: Context) -> None:
|
|
37
|
+
"""Update mkdocs.yml nav section from actual markdown files to prevent sync issues."""
|
|
38
|
+
mkdocs_file = Path(__file__).parent / "mkdocs.yml"
|
|
39
|
+
|
|
40
|
+
content = mkdocs_file.read_text(encoding="utf-8")
|
|
41
|
+
|
|
42
|
+
# Generate new nav entries
|
|
43
|
+
nav_entries = generate_nav_entries()
|
|
44
|
+
new_nav_section = "nav:\n" + "\n".join(nav_entries)
|
|
45
|
+
|
|
46
|
+
# Replace the nav section
|
|
47
|
+
updated_content = NAV_SECTION_PATTERN.sub(new_nav_section, content)
|
|
48
|
+
|
|
49
|
+
mkdocs_file.write_text(updated_content, encoding="utf-8")
|
|
50
|
+
|
|
51
|
+
print(f"✓ Updated mkdocs.yml with {len(nav_entries)} chapters")
|
|
52
|
+
print("\nGenerated nav:")
|
|
53
|
+
for entry in nav_entries:
|
|
54
|
+
print(entry)
|
|
@@ -19,7 +19,7 @@ from src.typedal.caching import (
|
|
|
19
19
|
from src.typedal.serializers import as_json
|
|
20
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
|
|
|
Binary file
|
|
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
|