dirsql 0.3.41__tar.gz → 0.3.42__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.
- {dirsql-0.3.41 → dirsql-0.3.42}/Cargo.lock +1 -1
- {dirsql-0.3.41 → dirsql-0.3.42}/PKG-INFO +1 -1
- {dirsql-0.3.41 → dirsql-0.3.42}/dirsql/_async.py +0 -30
- dirsql-0.3.42/dirsql/cli/interpret/__init__.py +14 -0
- {dirsql-0.3.41 → dirsql-0.3.42}/dirsql/cli/main.py +2 -12
- {dirsql-0.3.41/packages/rust → dirsql-0.3.42}/docs/api/index.md +3 -2
- {dirsql-0.3.41 → dirsql-0.3.42}/packages/python/Cargo.toml +1 -1
- {dirsql-0.3.41 → dirsql-0.3.42/packages/python}/docs/api/index.md +3 -2
- {dirsql-0.3.41 → dirsql-0.3.42}/packages/python/e2e-attestation.json +2 -2
- {dirsql-0.3.41/packages/python → dirsql-0.3.42/packages/rust}/docs/api/index.md +3 -2
- {dirsql-0.3.41 → dirsql-0.3.42}/pyproject.toml +1 -1
- dirsql-0.3.41/dirsql/cli/interpret/__init__.py +0 -17
- dirsql-0.3.41/dirsql/cli/interpret/dispatch_extract.py +0 -41
- dirsql-0.3.41/dirsql/cli/interpret/load_app.py +0 -32
- dirsql-0.3.41/dirsql/cli/interpret/run.py +0 -85
- dirsql-0.3.41/dirsql/cli/interpret/write_message.py +0 -18
- dirsql-0.3.41/dirsql/resolve_config.py +0 -61
- dirsql-0.3.41/packages/python/tests/e2e/__fixtures__/data/a/meta.json +0 -1
- dirsql-0.3.41/packages/python/tests/e2e/__fixtures__/data/b/meta.json +0 -1
- dirsql-0.3.41/packages/python/tests/e2e/__fixtures__/dirsql.config.py +0 -29
- dirsql-0.3.41/packages/python/tests/e2e/__fixtures__/interpret/data/a/meta.json +0 -1
- dirsql-0.3.41/packages/python/tests/e2e/__fixtures__/interpret/data/b/meta.json +0 -1
- dirsql-0.3.41/packages/python/tests/e2e/__fixtures__/interpret/dirsql.config.py +0 -27
- dirsql-0.3.41/packages/python/tests/e2e/__fixtures__/interpret/dirsql.config_nested.py +0 -13
- dirsql-0.3.41/packages/python/tests/e2e/__fixtures__/interpret/dirsql.config_no_app.py +0 -3
- dirsql-0.3.41/packages/python/tests/e2e/__fixtures__/interpret/dirsql.config_no_root.py +0 -26
- dirsql-0.3.41/packages/python/tests/e2e/__fixtures__/interpret/dirsql.config_raises.py +0 -21
- dirsql-0.3.41/packages/python/tests/e2e/__fixtures__/interpret/nested.dirsql.toml +0 -6
- dirsql-0.3.41/packages/python/tests/e2e/interpret_subprocess.py +0 -96
- {dirsql-0.3.41 → dirsql-0.3.42}/Cargo.toml +0 -0
- {dirsql-0.3.41 → dirsql-0.3.42}/README.md +0 -0
- {dirsql-0.3.41 → dirsql-0.3.42}/dirsql/__init__.py +0 -0
- {dirsql-0.3.41 → dirsql-0.3.42}/dirsql/_dirsql.pyi +0 -0
- {dirsql-0.3.41 → dirsql-0.3.42}/dirsql/cli/__init__.py +0 -0
- {dirsql-0.3.41 → dirsql-0.3.42}/dirsql/cli/binary_path.py +0 -0
- {dirsql-0.3.41 → dirsql-0.3.42}/dirsql/cli/is_windows.py +0 -0
- {dirsql-0.3.41 → dirsql-0.3.42}/dirsql/py.typed +0 -0
- {dirsql-0.3.41 → dirsql-0.3.42}/docs/.claude/CLAUDE.md +0 -0
- {dirsql-0.3.41 → dirsql-0.3.42}/docs/.vitepress/config.ts +0 -0
- {dirsql-0.3.41 → dirsql-0.3.42}/docs/.vitepress/theme/index.ts +0 -0
- {dirsql-0.3.41 → dirsql-0.3.42}/docs/.vitepress/theme/lang.ts +0 -0
- {dirsql-0.3.41 → dirsql-0.3.42}/docs/AGENTS.md +0 -0
- {dirsql-0.3.41 → dirsql-0.3.42}/docs/cli/config.md +0 -0
- {dirsql-0.3.41 → dirsql-0.3.42}/docs/cli/http-api.md +0 -0
- {dirsql-0.3.41 → dirsql-0.3.42}/docs/cli/index.md +0 -0
- {dirsql-0.3.41 → dirsql-0.3.42}/docs/cli/init.md +0 -0
- {dirsql-0.3.41 → dirsql-0.3.42}/docs/cli/server.md +0 -0
- {dirsql-0.3.41 → dirsql-0.3.42}/docs/getting-started.md +0 -0
- {dirsql-0.3.41 → dirsql-0.3.42}/docs/guide/async.md +0 -0
- {dirsql-0.3.41 → dirsql-0.3.42}/docs/guide/crdt.md +0 -0
- {dirsql-0.3.41 → dirsql-0.3.42}/docs/guide/persistence.md +0 -0
- {dirsql-0.3.41 → dirsql-0.3.42}/docs/guide/querying.md +0 -0
- {dirsql-0.3.41 → dirsql-0.3.42}/docs/guide/tables.md +0 -0
- {dirsql-0.3.41 → dirsql-0.3.42}/docs/guide/watching.md +0 -0
- {dirsql-0.3.41 → dirsql-0.3.42}/docs/index.md +0 -0
- {dirsql-0.3.41 → dirsql-0.3.42}/docs/migrations.md +0 -0
- {dirsql-0.3.41 → dirsql-0.3.42}/docs/package.json +0 -0
- {dirsql-0.3.41 → dirsql-0.3.42}/docs/playwright.config.ts +0 -0
- {dirsql-0.3.41 → dirsql-0.3.42}/docs/pnpm-lock.yaml +0 -0
- {dirsql-0.3.41 → dirsql-0.3.42}/docs/pnpm-workspace.yaml +0 -0
- {dirsql-0.3.41 → dirsql-0.3.42}/docs/tests/integration/home.spec.ts +0 -0
- {dirsql-0.3.41 → dirsql-0.3.42}/docs/tests/integration/language-flag.spec.ts +0 -0
- {dirsql-0.3.41 → dirsql-0.3.42}/docs/tests/integration/sidebar.spec.ts +0 -0
- {dirsql-0.3.41 → dirsql-0.3.42}/docs/tests/unit/config.test.ts +0 -0
- {dirsql-0.3.41 → dirsql-0.3.42}/docs/tests/unit/lang.test.ts +0 -0
- {dirsql-0.3.41 → dirsql-0.3.42}/docs/vitest.config.ts +0 -0
- {dirsql-0.3.41 → dirsql-0.3.42}/packages/python/README.md +0 -0
- {dirsql-0.3.41 → dirsql-0.3.42}/packages/python/conftest.py +0 -0
- {dirsql-0.3.41 → dirsql-0.3.42}/packages/python/docs/.claude/CLAUDE.md +0 -0
- {dirsql-0.3.41 → dirsql-0.3.42}/packages/python/docs/.vitepress/config.ts +0 -0
- {dirsql-0.3.41 → dirsql-0.3.42}/packages/python/docs/.vitepress/theme/index.ts +0 -0
- {dirsql-0.3.41 → dirsql-0.3.42}/packages/python/docs/.vitepress/theme/lang.ts +0 -0
- {dirsql-0.3.41 → dirsql-0.3.42}/packages/python/docs/AGENTS.md +0 -0
- {dirsql-0.3.41 → dirsql-0.3.42}/packages/python/docs/cli/config.md +0 -0
- {dirsql-0.3.41 → dirsql-0.3.42}/packages/python/docs/cli/http-api.md +0 -0
- {dirsql-0.3.41 → dirsql-0.3.42}/packages/python/docs/cli/index.md +0 -0
- {dirsql-0.3.41 → dirsql-0.3.42}/packages/python/docs/cli/init.md +0 -0
- {dirsql-0.3.41 → dirsql-0.3.42}/packages/python/docs/cli/server.md +0 -0
- {dirsql-0.3.41 → dirsql-0.3.42}/packages/python/docs/getting-started.md +0 -0
- {dirsql-0.3.41 → dirsql-0.3.42}/packages/python/docs/guide/async.md +0 -0
- {dirsql-0.3.41 → dirsql-0.3.42}/packages/python/docs/guide/crdt.md +0 -0
- {dirsql-0.3.41 → dirsql-0.3.42}/packages/python/docs/guide/persistence.md +0 -0
- {dirsql-0.3.41 → dirsql-0.3.42}/packages/python/docs/guide/querying.md +0 -0
- {dirsql-0.3.41 → dirsql-0.3.42}/packages/python/docs/guide/tables.md +0 -0
- {dirsql-0.3.41 → dirsql-0.3.42}/packages/python/docs/guide/watching.md +0 -0
- {dirsql-0.3.41 → dirsql-0.3.42}/packages/python/docs/index.md +0 -0
- {dirsql-0.3.41 → dirsql-0.3.42}/packages/python/docs/migrations.md +0 -0
- {dirsql-0.3.41 → dirsql-0.3.42}/packages/python/docs/package.json +0 -0
- {dirsql-0.3.41 → dirsql-0.3.42}/packages/python/docs/playwright.config.ts +0 -0
- {dirsql-0.3.41 → dirsql-0.3.42}/packages/python/docs/pnpm-lock.yaml +0 -0
- {dirsql-0.3.41 → dirsql-0.3.42}/packages/python/docs/pnpm-workspace.yaml +0 -0
- {dirsql-0.3.41 → dirsql-0.3.42}/packages/python/docs/tests/integration/home.spec.ts +0 -0
- {dirsql-0.3.41 → dirsql-0.3.42}/packages/python/docs/tests/integration/language-flag.spec.ts +0 -0
- {dirsql-0.3.41 → dirsql-0.3.42}/packages/python/docs/tests/integration/sidebar.spec.ts +0 -0
- {dirsql-0.3.41 → dirsql-0.3.42}/packages/python/docs/tests/unit/config.test.ts +0 -0
- {dirsql-0.3.41 → dirsql-0.3.42}/packages/python/docs/tests/unit/lang.test.ts +0 -0
- {dirsql-0.3.41 → dirsql-0.3.42}/packages/python/docs/vitest.config.ts +0 -0
- {dirsql-0.3.41 → dirsql-0.3.42}/packages/python/src/lib.rs +0 -0
- {dirsql-0.3.41 → dirsql-0.3.42}/packages/python/tests/__init__.py +0 -0
- {dirsql-0.3.41 → dirsql-0.3.42}/packages/python/tests/conftest.py +0 -0
- {dirsql-0.3.41 → dirsql-0.3.42}/packages/python/tests/e2e/__init__.py +0 -0
- {dirsql-0.3.41 → dirsql-0.3.42}/packages/python/tests/integration/__init__.py +0 -0
- {dirsql-0.3.41 → dirsql-0.3.42}/packages/rust/Cargo.toml +0 -0
- {dirsql-0.3.41 → dirsql-0.3.42}/packages/rust/README.md +0 -0
- {dirsql-0.3.41 → dirsql-0.3.42}/packages/rust/benches/db_bench.rs +0 -0
- {dirsql-0.3.41 → dirsql-0.3.42}/packages/rust/benches/differ_bench.rs +0 -0
- {dirsql-0.3.41 → dirsql-0.3.42}/packages/rust/benches/matcher_bench.rs +0 -0
- {dirsql-0.3.41 → dirsql-0.3.42}/packages/rust/benches/scanner_bench.rs +0 -0
- {dirsql-0.3.41 → dirsql-0.3.42}/packages/rust/docs/cli/config.md +0 -0
- {dirsql-0.3.41 → dirsql-0.3.42}/packages/rust/docs/cli/http-api.md +0 -0
- {dirsql-0.3.41 → dirsql-0.3.42}/packages/rust/docs/cli/index.md +0 -0
- {dirsql-0.3.41 → dirsql-0.3.42}/packages/rust/docs/cli/init.md +0 -0
- {dirsql-0.3.41 → dirsql-0.3.42}/packages/rust/docs/cli/server.md +0 -0
- {dirsql-0.3.41 → dirsql-0.3.42}/packages/rust/docs/getting-started.md +0 -0
- {dirsql-0.3.41 → dirsql-0.3.42}/packages/rust/docs/guide/async.md +0 -0
- {dirsql-0.3.41 → dirsql-0.3.42}/packages/rust/docs/guide/crdt.md +0 -0
- {dirsql-0.3.41 → dirsql-0.3.42}/packages/rust/docs/guide/persistence.md +0 -0
- {dirsql-0.3.41 → dirsql-0.3.42}/packages/rust/docs/guide/querying.md +0 -0
- {dirsql-0.3.41 → dirsql-0.3.42}/packages/rust/docs/guide/tables.md +0 -0
- {dirsql-0.3.41 → dirsql-0.3.42}/packages/rust/docs/guide/watching.md +0 -0
- {dirsql-0.3.41 → dirsql-0.3.42}/packages/rust/docs/index.md +0 -0
- {dirsql-0.3.41 → dirsql-0.3.42}/packages/rust/docs/migrations.md +0 -0
- {dirsql-0.3.41 → dirsql-0.3.42}/packages/rust/src/bin/dirsql.rs +0 -0
- {dirsql-0.3.41 → dirsql-0.3.42}/packages/rust/src/cli/init.rs +0 -0
- {dirsql-0.3.41 → dirsql-0.3.42}/packages/rust/src/cli/mod.rs +0 -0
- {dirsql-0.3.41 → dirsql-0.3.42}/packages/rust/src/cli/native_config.rs +0 -0
- {dirsql-0.3.41 → dirsql-0.3.42}/packages/rust/src/cli/router.rs +0 -0
- {dirsql-0.3.41 → dirsql-0.3.42}/packages/rust/src/cli/serialize.rs +0 -0
- {dirsql-0.3.41 → dirsql-0.3.42}/packages/rust/src/cli/server.rs +0 -0
- {dirsql-0.3.41 → dirsql-0.3.42}/packages/rust/src/config.rs +0 -0
- {dirsql-0.3.41 → dirsql-0.3.42}/packages/rust/src/db.rs +0 -0
- {dirsql-0.3.41 → dirsql-0.3.42}/packages/rust/src/differ.rs +0 -0
- {dirsql-0.3.41 → dirsql-0.3.42}/packages/rust/src/lib.rs +0 -0
- {dirsql-0.3.41 → dirsql-0.3.42}/packages/rust/src/matcher.rs +0 -0
- {dirsql-0.3.41 → dirsql-0.3.42}/packages/rust/src/persist.rs +0 -0
- {dirsql-0.3.41 → dirsql-0.3.42}/packages/rust/src/scanner.rs +0 -0
- {dirsql-0.3.41 → dirsql-0.3.42}/packages/rust/src/watcher.rs +0 -0
|
@@ -1,20 +1,8 @@
|
|
|
1
1
|
"""Async-by-default DirSQL wrapper."""
|
|
2
2
|
|
|
3
3
|
import asyncio
|
|
4
|
-
from typing import TYPE_CHECKING
|
|
5
4
|
|
|
6
5
|
from dirsql._dirsql import DirSQL as _RustDirSQL
|
|
7
|
-
from dirsql.resolve_config import resolve_config
|
|
8
|
-
|
|
9
|
-
if TYPE_CHECKING:
|
|
10
|
-
# `typing.override` is 3.12+; the package supports 3.11, so source it from
|
|
11
|
-
# `typing_extensions` for the type checker only. At runtime `@override` is
|
|
12
|
-
# a pure marker, so a no-op identity avoids the runtime dependency.
|
|
13
|
-
from typing_extensions import override
|
|
14
|
-
else:
|
|
15
|
-
|
|
16
|
-
def override(func):
|
|
17
|
-
return func
|
|
18
6
|
|
|
19
7
|
|
|
20
8
|
class _WatchStream:
|
|
@@ -135,21 +123,3 @@ class DirSQL:
|
|
|
135
123
|
def watch(self):
|
|
136
124
|
"""Start watching for file changes. Returns an async iterable of RowEvent."""
|
|
137
125
|
return _WatchStream(self._db)
|
|
138
|
-
|
|
139
|
-
@property
|
|
140
|
-
@override
|
|
141
|
-
def __dict__(self):
|
|
142
|
-
"""Resolved construction state as a JSON-serializable dict.
|
|
143
|
-
|
|
144
|
-
Recomputed on each access; reads the ``.dirsql.toml`` if ``config=``
|
|
145
|
-
was supplied. Works before ``await db.ready()``.
|
|
146
|
-
"""
|
|
147
|
-
return resolve_config(
|
|
148
|
-
self._root,
|
|
149
|
-
self._tables,
|
|
150
|
-
self._ignore,
|
|
151
|
-
self._config,
|
|
152
|
-
self._persist,
|
|
153
|
-
self._persist_path,
|
|
154
|
-
self._extensions,
|
|
155
|
-
)
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
"""Empty package shell — the native-config ``interpret`` helper was removed.
|
|
2
|
+
|
|
3
|
+
The ``dirsql interpret`` subcommand and its NDJSON ``extract`` loop (``run``,
|
|
4
|
+
``load_app``, ``dispatch_extract``, ``write_message``) were removed in #321
|
|
5
|
+
(#323). The CLI now accepts only ``.dirsql.toml``; to run user-defined
|
|
6
|
+
``extract`` callbacks, use the programmatic SDK (``DirSQL(...)`` with
|
|
7
|
+
in-process closures).
|
|
8
|
+
|
|
9
|
+
This ``__init__.py`` carries no logic and no re-exports. It remains only
|
|
10
|
+
because the colocated-test tooling cannot yet express *deleting* an exempt
|
|
11
|
+
package barrel (the co-change check flags a deleted source that has no
|
|
12
|
+
co-deleted colocated test, and a retained exempt for a deleted path is
|
|
13
|
+
rejected as stale). The directory is removed once that is resolved.
|
|
14
|
+
"""
|
|
@@ -1,8 +1,6 @@
|
|
|
1
1
|
"""Console-script entry point. Execs the bundled binary on POSIX,
|
|
2
|
-
subprocesses it on Windows.
|
|
3
|
-
|
|
4
|
-
orchestrator can spawn this script for native-language configs (#196)
|
|
5
|
-
without depending on the bundled Rust binary."""
|
|
2
|
+
subprocesses it on Windows. All argv is forwarded transparently to the
|
|
3
|
+
bundled Rust binary."""
|
|
6
4
|
|
|
7
5
|
from __future__ import annotations
|
|
8
6
|
|
|
@@ -18,14 +16,6 @@ def main(argv: list[str] | None = None) -> int:
|
|
|
18
16
|
if argv is None:
|
|
19
17
|
argv = sys.argv[1:]
|
|
20
18
|
|
|
21
|
-
if argv and argv[0] == "interpret":
|
|
22
|
-
from .interpret.run import run
|
|
23
|
-
|
|
24
|
-
try:
|
|
25
|
-
return run(argv[1:])
|
|
26
|
-
except KeyboardInterrupt:
|
|
27
|
-
return 130
|
|
28
|
-
|
|
29
19
|
try:
|
|
30
20
|
binary = binary_path()
|
|
31
21
|
except FileNotFoundError as exc:
|
|
@@ -59,6 +59,7 @@ new DirSQL({
|
|
|
59
59
|
tables?: TableDef[],
|
|
60
60
|
ignore?: string[],
|
|
61
61
|
config?: string,
|
|
62
|
+
extensions?: ExtensionSpec[], // [{ path: string, entrypoint?: string }]
|
|
62
63
|
})
|
|
63
64
|
```
|
|
64
65
|
|
|
@@ -76,7 +77,7 @@ In Python, the constructor starts scanning in a background thread and returns im
|
|
|
76
77
|
- `tables` -- List of `Table` definitions. Each defines a SQLite table, a glob pattern, and an extract function.
|
|
77
78
|
- `ignore` -- Optional list of glob patterns. Files matching any ignore pattern are skipped regardless of table globs.
|
|
78
79
|
- `config` -- Optional path to a `.dirsql.toml` config file. Its `[[table]]` entries are appended to any programmatic `tables`; its `[dirsql].ignore` patterns are appended to any explicit `ignore`; its optional `[dirsql].root` supplies the root directory when `root` is not passed explicitly; its `[[dirsql.extension]]` entries are appended to any programmatic `extensions`.
|
|
79
|
-
- `extensions` -- Optional SQLite extensions to load onto the connection at startup, before any table DDL (enable → load → disable, so the SQL `load_extension()` function is never left exposed). Each entry pairs a shared-library `path` with an optional `entrypoint` init-symbol override (Python: `{ "path", "entrypoint"? }` dicts; Rust: `Extension { path, entrypoint }`). Programmatic entries load first, then any `[[dirsql.extension]]` from `config`. Available in the Python
|
|
80
|
+
- `extensions` -- Optional SQLite extensions to load onto the connection at startup, before any table DDL (enable → load → disable, so the SQL `load_extension()` function is never left exposed). Each entry pairs a shared-library `path` with an optional `entrypoint` init-symbol override (Python: `{ "path", "entrypoint"? }` dicts; Rust: `Extension { path, entrypoint }`; TypeScript: `{ path, entrypoint? }` objects). Programmatic entries load first, then any `[[dirsql.extension]]` from `config`. Available in the Python, Rust, and TypeScript SDKs. See [Loading extensions](../cli/config.md#loading-extensions).
|
|
80
81
|
|
|
81
82
|
### Methods
|
|
82
83
|
|
|
@@ -162,7 +163,7 @@ JSON.stringify(db) // via db.toJSON()
|
|
|
162
163
|
|
|
163
164
|
:::
|
|
164
165
|
|
|
165
|
-
Returns the resolved construction state as a JSON-compatible value with fields `root`, `tables`, `ignore`, `persist`, `persist_path` (camelCase `persistPath` in TypeScript). Each table is `{ ddl, glob, strict }`.
|
|
166
|
+
Returns the resolved construction state as a JSON-compatible value with fields `root`, `tables`, `ignore`, `persist`, `persist_path` (camelCase `persistPath` in TypeScript). Each table is `{ ddl, glob, strict }`. All three SDK snapshots also include `extensions` -- an array of `{ path, entrypoint }` (empty when none are configured; `entrypoint` is `null` when no override was supplied). Excludes the original `config` path (already merged into `root` / `tables` / `ignore`), per-table `extract`, and per-table `name`. Available immediately after construction in Python and TypeScript; Rust's sync `build()` returns a ready instance.
|
|
166
167
|
|
|
167
168
|
---
|
|
168
169
|
|
|
@@ -4,7 +4,7 @@ name = "dirsql-py-ext"
|
|
|
4
4
|
# pypi/maturin handler can rewrite it via `write-version` before
|
|
5
5
|
# `maturin build`. `pyproject.toml` declares `dynamic = ["version"]`
|
|
6
6
|
# and maturin reads this field. Mirrors `packages/rust/Cargo.toml`.
|
|
7
|
-
version = "0.3.
|
|
7
|
+
version = "0.3.42"
|
|
8
8
|
edition.workspace = true
|
|
9
9
|
publish = false
|
|
10
10
|
readme = "README.md"
|
|
@@ -59,6 +59,7 @@ new DirSQL({
|
|
|
59
59
|
tables?: TableDef[],
|
|
60
60
|
ignore?: string[],
|
|
61
61
|
config?: string,
|
|
62
|
+
extensions?: ExtensionSpec[], // [{ path: string, entrypoint?: string }]
|
|
62
63
|
})
|
|
63
64
|
```
|
|
64
65
|
|
|
@@ -76,7 +77,7 @@ In Python, the constructor starts scanning in a background thread and returns im
|
|
|
76
77
|
- `tables` -- List of `Table` definitions. Each defines a SQLite table, a glob pattern, and an extract function.
|
|
77
78
|
- `ignore` -- Optional list of glob patterns. Files matching any ignore pattern are skipped regardless of table globs.
|
|
78
79
|
- `config` -- Optional path to a `.dirsql.toml` config file. Its `[[table]]` entries are appended to any programmatic `tables`; its `[dirsql].ignore` patterns are appended to any explicit `ignore`; its optional `[dirsql].root` supplies the root directory when `root` is not passed explicitly; its `[[dirsql.extension]]` entries are appended to any programmatic `extensions`.
|
|
79
|
-
- `extensions` -- Optional SQLite extensions to load onto the connection at startup, before any table DDL (enable → load → disable, so the SQL `load_extension()` function is never left exposed). Each entry pairs a shared-library `path` with an optional `entrypoint` init-symbol override (Python: `{ "path", "entrypoint"? }` dicts; Rust: `Extension { path, entrypoint }`). Programmatic entries load first, then any `[[dirsql.extension]]` from `config`. Available in the Python
|
|
80
|
+
- `extensions` -- Optional SQLite extensions to load onto the connection at startup, before any table DDL (enable → load → disable, so the SQL `load_extension()` function is never left exposed). Each entry pairs a shared-library `path` with an optional `entrypoint` init-symbol override (Python: `{ "path", "entrypoint"? }` dicts; Rust: `Extension { path, entrypoint }`; TypeScript: `{ path, entrypoint? }` objects). Programmatic entries load first, then any `[[dirsql.extension]]` from `config`. Available in the Python, Rust, and TypeScript SDKs. See [Loading extensions](../cli/config.md#loading-extensions).
|
|
80
81
|
|
|
81
82
|
### Methods
|
|
82
83
|
|
|
@@ -162,7 +163,7 @@ JSON.stringify(db) // via db.toJSON()
|
|
|
162
163
|
|
|
163
164
|
:::
|
|
164
165
|
|
|
165
|
-
Returns the resolved construction state as a JSON-compatible value with fields `root`, `tables`, `ignore`, `persist`, `persist_path` (camelCase `persistPath` in TypeScript). Each table is `{ ddl, glob, strict }`.
|
|
166
|
+
Returns the resolved construction state as a JSON-compatible value with fields `root`, `tables`, `ignore`, `persist`, `persist_path` (camelCase `persistPath` in TypeScript). Each table is `{ ddl, glob, strict }`. All three SDK snapshots also include `extensions` -- an array of `{ path, entrypoint }` (empty when none are configured; `entrypoint` is `null` when no override was supplied). Excludes the original `config` path (already merged into `root` / `tables` / `ignore`), per-table `extract`, and per-table `name`. Available immediately after construction in Python and TypeScript; Rust's sync `build()` returns a ready instance.
|
|
166
167
|
|
|
167
168
|
---
|
|
168
169
|
|
|
@@ -59,6 +59,7 @@ new DirSQL({
|
|
|
59
59
|
tables?: TableDef[],
|
|
60
60
|
ignore?: string[],
|
|
61
61
|
config?: string,
|
|
62
|
+
extensions?: ExtensionSpec[], // [{ path: string, entrypoint?: string }]
|
|
62
63
|
})
|
|
63
64
|
```
|
|
64
65
|
|
|
@@ -76,7 +77,7 @@ In Python, the constructor starts scanning in a background thread and returns im
|
|
|
76
77
|
- `tables` -- List of `Table` definitions. Each defines a SQLite table, a glob pattern, and an extract function.
|
|
77
78
|
- `ignore` -- Optional list of glob patterns. Files matching any ignore pattern are skipped regardless of table globs.
|
|
78
79
|
- `config` -- Optional path to a `.dirsql.toml` config file. Its `[[table]]` entries are appended to any programmatic `tables`; its `[dirsql].ignore` patterns are appended to any explicit `ignore`; its optional `[dirsql].root` supplies the root directory when `root` is not passed explicitly; its `[[dirsql.extension]]` entries are appended to any programmatic `extensions`.
|
|
79
|
-
- `extensions` -- Optional SQLite extensions to load onto the connection at startup, before any table DDL (enable → load → disable, so the SQL `load_extension()` function is never left exposed). Each entry pairs a shared-library `path` with an optional `entrypoint` init-symbol override (Python: `{ "path", "entrypoint"? }` dicts; Rust: `Extension { path, entrypoint }`). Programmatic entries load first, then any `[[dirsql.extension]]` from `config`. Available in the Python
|
|
80
|
+
- `extensions` -- Optional SQLite extensions to load onto the connection at startup, before any table DDL (enable → load → disable, so the SQL `load_extension()` function is never left exposed). Each entry pairs a shared-library `path` with an optional `entrypoint` init-symbol override (Python: `{ "path", "entrypoint"? }` dicts; Rust: `Extension { path, entrypoint }`; TypeScript: `{ path, entrypoint? }` objects). Programmatic entries load first, then any `[[dirsql.extension]]` from `config`. Available in the Python, Rust, and TypeScript SDKs. See [Loading extensions](../cli/config.md#loading-extensions).
|
|
80
81
|
|
|
81
82
|
### Methods
|
|
82
83
|
|
|
@@ -162,7 +163,7 @@ JSON.stringify(db) // via db.toJSON()
|
|
|
162
163
|
|
|
163
164
|
:::
|
|
164
165
|
|
|
165
|
-
Returns the resolved construction state as a JSON-compatible value with fields `root`, `tables`, `ignore`, `persist`, `persist_path` (camelCase `persistPath` in TypeScript). Each table is `{ ddl, glob, strict }`.
|
|
166
|
+
Returns the resolved construction state as a JSON-compatible value with fields `root`, `tables`, `ignore`, `persist`, `persist_path` (camelCase `persistPath` in TypeScript). Each table is `{ ddl, glob, strict }`. All three SDK snapshots also include `extensions` -- an array of `{ path, entrypoint }` (empty when none are configured; `entrypoint` is `null` when no override was supplied). Excludes the original `config` path (already merged into `root` / `tables` / `ignore`), per-table `extract`, and per-table `name`. Available immediately after construction in Python and TypeScript; Rust's sync `build()` returns a ready instance.
|
|
166
167
|
|
|
167
168
|
---
|
|
168
169
|
|
|
@@ -98,7 +98,7 @@ omit = [
|
|
|
98
98
|
# them lets a test double's own branches pad the metric (e.g. a fake's
|
|
99
99
|
# empty-list return). Exclude test files so the floor reflects only
|
|
100
100
|
# library code. Recursive glob so nested packages (e.g.
|
|
101
|
-
# `dirsql/cli
|
|
101
|
+
# `dirsql/cli/`) are covered too.
|
|
102
102
|
"**/test_*.py",
|
|
103
103
|
"**/*_test.py",
|
|
104
104
|
]
|
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
"""`dirsql interpret <config>` -- long-running native config helper (#196).
|
|
2
|
-
|
|
3
|
-
Loads a Python config file, takes its module-level ``app = DirSQL(...)``,
|
|
4
|
-
and serves ``extract`` requests over NDJSON on stdin/stdout. One line in,
|
|
5
|
-
one line out, sequential.
|
|
6
|
-
|
|
7
|
-
See the individual submodules for behavior:
|
|
8
|
-
- ``run`` -- subcommand entry point invoked from ``dirsql.cli.main``
|
|
9
|
-
- ``load_app`` -- importlib-based config loader
|
|
10
|
-
- ``write_message`` -- single-line NDJSON writer
|
|
11
|
-
- ``dispatch_extract`` -- per-request handler
|
|
12
|
-
|
|
13
|
-
No top-level re-exports: the function is at ``.run.run``. Re-exporting
|
|
14
|
-
``run`` at the package level would shadow the submodule (so
|
|
15
|
-
``from . import run`` in tests would resolve to the function and break
|
|
16
|
-
``patch.object(run_module, "load_app", ...)``).
|
|
17
|
-
"""
|
|
@@ -1,41 +0,0 @@
|
|
|
1
|
-
"""Single-request handler for the `dirsql interpret` helper.
|
|
2
|
-
|
|
3
|
-
Given a parsed request line and a name->table lookup, call the user's
|
|
4
|
-
``extract`` callback and return the NDJSON response payload the loop
|
|
5
|
-
will write back to stdout.
|
|
6
|
-
"""
|
|
7
|
-
|
|
8
|
-
from __future__ import annotations
|
|
9
|
-
|
|
10
|
-
from typing import Any
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
def dispatch_extract(
|
|
14
|
-
req: dict[str, Any],
|
|
15
|
-
tables: dict[str, Any],
|
|
16
|
-
) -> dict[str, Any]:
|
|
17
|
-
"""Build the `{"type": "result", ...}` response for one extract request.
|
|
18
|
-
|
|
19
|
-
- Unknown table name -> ``ok: false`` with a name-bearing error.
|
|
20
|
-
- User's ``extract`` raising -> ``ok: false`` with ``str(exc)``.
|
|
21
|
-
- Success -> ``ok: true`` with the row list the callback returned.
|
|
22
|
-
|
|
23
|
-
``req["id"]`` is echoed back unchanged so the caller can correlate
|
|
24
|
-
request and response.
|
|
25
|
-
"""
|
|
26
|
-
rid = req.get("id")
|
|
27
|
-
name = req.get("table")
|
|
28
|
-
path = req.get("path")
|
|
29
|
-
table = tables.get(name) if isinstance(name, str) else None
|
|
30
|
-
if table is None:
|
|
31
|
-
return {
|
|
32
|
-
"type": "result",
|
|
33
|
-
"id": rid,
|
|
34
|
-
"ok": False,
|
|
35
|
-
"error": f"unknown table: {name!r}",
|
|
36
|
-
}
|
|
37
|
-
try:
|
|
38
|
-
rows = table.extract(path)
|
|
39
|
-
except Exception as exc:
|
|
40
|
-
return {"type": "result", "id": rid, "ok": False, "error": str(exc)}
|
|
41
|
-
return {"type": "result", "id": rid, "ok": True, "rows": rows}
|
|
@@ -1,32 +0,0 @@
|
|
|
1
|
-
"""importlib-based config loader for the `dirsql interpret` helper.
|
|
2
|
-
|
|
3
|
-
The user's config is a regular Python module that constructs a
|
|
4
|
-
``DirSQL`` instance and assigns it to a top-level ``app`` name. We
|
|
5
|
-
import it via ``importlib.util.spec_from_file_location`` so the user
|
|
6
|
-
doesn't have to put their config on ``sys.path``.
|
|
7
|
-
"""
|
|
8
|
-
|
|
9
|
-
from __future__ import annotations
|
|
10
|
-
|
|
11
|
-
import importlib.util
|
|
12
|
-
import os
|
|
13
|
-
from typing import Any
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
def load_app(config_path: str) -> Any:
|
|
17
|
-
"""Import ``config_path`` and return its ``app`` attribute.
|
|
18
|
-
|
|
19
|
-
Raises ``ImportError`` if the file can't be loaded as a module, and
|
|
20
|
-
``AttributeError`` if the module loads but defines no ``app``.
|
|
21
|
-
"""
|
|
22
|
-
abs_path = os.path.abspath(config_path)
|
|
23
|
-
spec = importlib.util.spec_from_file_location("_dirsql_user_config", abs_path)
|
|
24
|
-
if spec is None or spec.loader is None:
|
|
25
|
-
raise ImportError(f"could not load config: {config_path}")
|
|
26
|
-
module = importlib.util.module_from_spec(spec)
|
|
27
|
-
spec.loader.exec_module(module)
|
|
28
|
-
if not hasattr(module, "app"):
|
|
29
|
-
raise AttributeError(
|
|
30
|
-
f"{config_path}: module must define a top-level `app = DirSQL(...)`"
|
|
31
|
-
)
|
|
32
|
-
return module.app
|
|
@@ -1,85 +0,0 @@
|
|
|
1
|
-
"""Subcommand entry point for `dirsql interpret <config>`.
|
|
2
|
-
|
|
3
|
-
Glues the per-purpose helpers (`load_app`, `dispatch_extract`,
|
|
4
|
-
`write_message`) into the long-running NDJSON loop:
|
|
5
|
-
|
|
6
|
-
handshake (helper -> caller, once on startup):
|
|
7
|
-
{"type": "config", "state": <vars(app)>}
|
|
8
|
-
|
|
9
|
-
extract request (caller -> helper):
|
|
10
|
-
{"type": "extract", "id": <int>, "table": "<name>", "path": "<abs>"}
|
|
11
|
-
|
|
12
|
-
extract response (helper -> caller):
|
|
13
|
-
{"type": "result", "id": <int>, "ok": true, "rows": [...]}
|
|
14
|
-
{"type": "result", "id": <int>, "ok": false, "error": "<msg>"}
|
|
15
|
-
|
|
16
|
-
Exits 0 when stdin closes; non-zero with a single ``dirsql interpret:``
|
|
17
|
-
line on stderr if the config can't be loaded.
|
|
18
|
-
"""
|
|
19
|
-
|
|
20
|
-
from __future__ import annotations
|
|
21
|
-
|
|
22
|
-
import json
|
|
23
|
-
import os
|
|
24
|
-
import sys
|
|
25
|
-
|
|
26
|
-
from .dispatch_extract import dispatch_extract
|
|
27
|
-
from .load_app import load_app
|
|
28
|
-
from .write_message import write_message
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
def run(argv: list[str]) -> int:
|
|
32
|
-
if len(argv) != 1:
|
|
33
|
-
sys.stderr.write(
|
|
34
|
-
f"dirsql interpret: expected one config path, got {len(argv)}\n"
|
|
35
|
-
)
|
|
36
|
-
return 1
|
|
37
|
-
config_path = argv[0]
|
|
38
|
-
|
|
39
|
-
try:
|
|
40
|
-
app = load_app(config_path)
|
|
41
|
-
except Exception as exc:
|
|
42
|
-
sys.stderr.write(f"dirsql interpret: {exc}\n")
|
|
43
|
-
return 1
|
|
44
|
-
|
|
45
|
-
# A config file describes a single DirSQL; it must not itself delegate to
|
|
46
|
-
# another `config=` path. The interpret handshake has no field for a
|
|
47
|
-
# nested config and would recurse, so reject it up front.
|
|
48
|
-
if app._config is not None:
|
|
49
|
-
sys.stderr.write(
|
|
50
|
-
"dirsql interpret: a config file cannot itself set config= "
|
|
51
|
-
"(nested config is not supported)\n"
|
|
52
|
-
)
|
|
53
|
-
return 1
|
|
54
|
-
|
|
55
|
-
# Name comes from `dirsql::db::parse_table_name` -- the canonical
|
|
56
|
-
# core parser, surfaced via PyO3 on `Table.name` (#196). No regex
|
|
57
|
-
# duplication on the Python side. Tables with a name the parser
|
|
58
|
-
# couldn't extract are skipped here; the malformed DDL would also
|
|
59
|
-
# surface as a `DirSqlError::Ddl` during the SDK scan, which
|
|
60
|
-
# `await app.ready()` would re-raise -- not interpret's job to
|
|
61
|
-
# second-guess.
|
|
62
|
-
tables = {t.name: t for t in (app._tables or []) if t.name is not None}
|
|
63
|
-
|
|
64
|
-
# When the config supplies neither `root` nor `config=`, the resolved
|
|
65
|
-
# root is None. Default it to the process cwd -- the directory the
|
|
66
|
-
# `dirsql` command was launched from, which interpret inherits from the
|
|
67
|
-
# parent binary -- so a root-less config indexes "here".
|
|
68
|
-
state = vars(app)
|
|
69
|
-
if state.get("root") is None:
|
|
70
|
-
state["root"] = os.getcwd()
|
|
71
|
-
write_message({"type": "config", "state": state})
|
|
72
|
-
|
|
73
|
-
for line in sys.stdin:
|
|
74
|
-
stripped = line.strip()
|
|
75
|
-
if not stripped:
|
|
76
|
-
continue
|
|
77
|
-
try:
|
|
78
|
-
req = json.loads(stripped)
|
|
79
|
-
except json.JSONDecodeError:
|
|
80
|
-
continue
|
|
81
|
-
if not isinstance(req, dict) or req.get("type") != "extract":
|
|
82
|
-
continue
|
|
83
|
-
write_message(dispatch_extract(req, tables))
|
|
84
|
-
|
|
85
|
-
return 0
|
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
"""Single-line NDJSON writer for the `dirsql interpret` helper."""
|
|
2
|
-
|
|
3
|
-
from __future__ import annotations
|
|
4
|
-
|
|
5
|
-
import json
|
|
6
|
-
import sys
|
|
7
|
-
from typing import Any
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
def write_message(msg: dict[str, Any]) -> None:
|
|
11
|
-
"""Write one NDJSON line to stdout and flush.
|
|
12
|
-
|
|
13
|
-
The flush is required so the orchestrator on the other side of the
|
|
14
|
-
pipe sees the message immediately; without it the buffered stream
|
|
15
|
-
would deliver lines in batches.
|
|
16
|
-
"""
|
|
17
|
-
sys.stdout.write(json.dumps(msg) + "\n")
|
|
18
|
-
sys.stdout.flush()
|
|
@@ -1,61 +0,0 @@
|
|
|
1
|
-
"""Synchronous config resolver for `DirSQL.__dict__`.
|
|
2
|
-
|
|
3
|
-
Mirrors `DirSQLBuilder::resolve` in the Rust core: explicit kwargs win for
|
|
4
|
-
scalars; tables and ignore lists are concatenated; persist is OR-ed;
|
|
5
|
-
path-valued config fields resolve relative to the config file's parent.
|
|
6
|
-
"""
|
|
7
|
-
|
|
8
|
-
import os
|
|
9
|
-
import tomllib
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
def resolve_config(
|
|
13
|
-
root, tables, ignore, config, persist, persist_path, extensions=None
|
|
14
|
-
):
|
|
15
|
-
"""Merge kwargs with a `.dirsql.toml` into the serialized state shape."""
|
|
16
|
-
cfg, cfg_tables, cfg_extensions, cfg_dir = {}, [], [], None
|
|
17
|
-
if config is not None:
|
|
18
|
-
with open(config, "rb") as f:
|
|
19
|
-
doc = tomllib.load(f)
|
|
20
|
-
cfg = doc.get("dirsql") or {}
|
|
21
|
-
cfg_tables = doc.get("table") or []
|
|
22
|
-
cfg_extensions = cfg.get("extension") or []
|
|
23
|
-
cfg_dir = os.path.dirname(os.path.abspath(config))
|
|
24
|
-
|
|
25
|
-
def _abs(p):
|
|
26
|
-
# Only reached from the `"<key>" in cfg` branches below, and cfg is
|
|
27
|
-
# non-empty only after a config file was loaded -- which sets cfg_dir.
|
|
28
|
-
base = cfg_dir
|
|
29
|
-
assert base is not None
|
|
30
|
-
return p if os.path.isabs(p) else os.path.join(base, p)
|
|
31
|
-
|
|
32
|
-
return {
|
|
33
|
-
"root": root or (_abs(cfg["root"]) if "root" in cfg else cfg_dir),
|
|
34
|
-
"tables": [
|
|
35
|
-
{"ddl": t.ddl, "glob": t.glob, "strict": bool(t.strict)}
|
|
36
|
-
for t in (tables or [])
|
|
37
|
-
]
|
|
38
|
-
+ [
|
|
39
|
-
{
|
|
40
|
-
"ddl": e.get("ddl"),
|
|
41
|
-
"glob": e.get("glob"),
|
|
42
|
-
"strict": bool(e.get("strict")),
|
|
43
|
-
}
|
|
44
|
-
for e in cfg_tables
|
|
45
|
-
],
|
|
46
|
-
"ignore": list(ignore or []) + list(cfg.get("ignore") or []),
|
|
47
|
-
"persist": bool(persist or cfg.get("persist")),
|
|
48
|
-
"persist_path": persist_path
|
|
49
|
-
or (_abs(cfg["persist_path"]) if "persist_path" in cfg else None),
|
|
50
|
-
# Programmatic extensions first (verbatim paths, mirroring the Rust
|
|
51
|
-
# builder), then config-file `[[dirsql.extension]]` entries with
|
|
52
|
-
# relative paths resolved against the config's parent directory.
|
|
53
|
-
"extensions": [
|
|
54
|
-
{"path": e["path"], "entrypoint": e.get("entrypoint")}
|
|
55
|
-
for e in (extensions or [])
|
|
56
|
-
]
|
|
57
|
-
+ [
|
|
58
|
-
{"path": _abs(e["path"]), "entrypoint": e.get("entrypoint")}
|
|
59
|
-
for e in cfg_extensions
|
|
60
|
-
],
|
|
61
|
-
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"title": "Alpha"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"title": "Beta"}
|
|
@@ -1,29 +0,0 @@
|
|
|
1
|
-
"""A native Python config file for dirsql.
|
|
2
|
-
|
|
3
|
-
When ``dirsql --config <path-to-this-file>`` runs, the Rust binary
|
|
4
|
-
spawns ``dirsql interpret`` against this file. The helper loads the
|
|
5
|
-
module, takes its module-level ``app``, and dispatches ``extract``
|
|
6
|
-
callbacks over NDJSON.
|
|
7
|
-
"""
|
|
8
|
-
|
|
9
|
-
import json
|
|
10
|
-
import os
|
|
11
|
-
|
|
12
|
-
from dirsql import DirSQL, Table
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
def _extract(path):
|
|
16
|
-
with open(path) as f:
|
|
17
|
-
return [json.load(f)]
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
app = DirSQL(
|
|
21
|
-
root=os.path.join(os.path.dirname(__file__), "data"),
|
|
22
|
-
tables=[
|
|
23
|
-
Table(
|
|
24
|
-
ddl="CREATE TABLE papers (title TEXT)",
|
|
25
|
-
glob="**/meta.json",
|
|
26
|
-
extract=_extract,
|
|
27
|
-
)
|
|
28
|
-
],
|
|
29
|
-
)
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"title": "Alpha"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"title": "Beta"}
|
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
"""Happy-path fixture for `dirsql interpret` integration tests.
|
|
2
|
-
|
|
3
|
-
Exposes a single `papers` table whose `extract` reads each `meta.json`
|
|
4
|
-
under the colocated `data/` tree and returns its parsed contents.
|
|
5
|
-
"""
|
|
6
|
-
|
|
7
|
-
import json
|
|
8
|
-
import os
|
|
9
|
-
|
|
10
|
-
from dirsql import DirSQL, Table
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
def _extract(path):
|
|
14
|
-
with open(path, encoding="utf-8") as f:
|
|
15
|
-
return [json.load(f)]
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
app = DirSQL(
|
|
19
|
-
root=os.path.join(os.path.dirname(__file__), "data"),
|
|
20
|
-
tables=[
|
|
21
|
-
Table(
|
|
22
|
-
ddl="CREATE TABLE papers (title TEXT)",
|
|
23
|
-
glob="**/meta.json",
|
|
24
|
-
extract=_extract,
|
|
25
|
-
)
|
|
26
|
-
],
|
|
27
|
-
)
|
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
"""Fixture: a native Python config that itself sets ``config=``.
|
|
2
|
-
|
|
3
|
-
`dirsql interpret` must reject this -- a config file loaded by interpret
|
|
4
|
-
cannot delegate to another config file (nested config loading). The
|
|
5
|
-
referenced TOML is valid, so the rejection comes from the loader, not from
|
|
6
|
-
a TOML read error.
|
|
7
|
-
"""
|
|
8
|
-
|
|
9
|
-
import os
|
|
10
|
-
|
|
11
|
-
from dirsql import DirSQL
|
|
12
|
-
|
|
13
|
-
app = DirSQL(config=os.path.join(os.path.dirname(__file__), "nested.dirsql.toml"))
|
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
"""Fixture: a native Python config that omits ``root``.
|
|
2
|
-
|
|
3
|
-
`dirsql interpret` should resolve the root to the helper process's current
|
|
4
|
-
working directory (the cwd the orchestrator was launched from) rather than
|
|
5
|
-
erroring. Mirrors ``dirsql.config.py`` but drops the ``root=`` argument.
|
|
6
|
-
"""
|
|
7
|
-
|
|
8
|
-
import json
|
|
9
|
-
|
|
10
|
-
from dirsql import DirSQL, Table
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
def _extract(path):
|
|
14
|
-
with open(path, encoding="utf-8") as f:
|
|
15
|
-
return [json.load(f)]
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
app = DirSQL(
|
|
19
|
-
tables=[
|
|
20
|
-
Table(
|
|
21
|
-
ddl="CREATE TABLE papers (title TEXT)",
|
|
22
|
-
glob="**/meta.json",
|
|
23
|
-
extract=_extract,
|
|
24
|
-
)
|
|
25
|
-
],
|
|
26
|
-
)
|
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
"""Fixture whose `extract` raises -- exercises the `ok: false` response."""
|
|
2
|
-
|
|
3
|
-
import os
|
|
4
|
-
|
|
5
|
-
from dirsql import DirSQL, Table
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
def _boom(_path):
|
|
9
|
-
raise ValueError("synthetic extract failure")
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
app = DirSQL(
|
|
13
|
-
root=os.path.join(os.path.dirname(__file__), "data"),
|
|
14
|
-
tables=[
|
|
15
|
-
Table(
|
|
16
|
-
ddl="CREATE TABLE papers (title TEXT)",
|
|
17
|
-
glob="**/meta.json",
|
|
18
|
-
extract=_boom,
|
|
19
|
-
)
|
|
20
|
-
],
|
|
21
|
-
)
|
|
@@ -1,96 +0,0 @@
|
|
|
1
|
-
"""Subprocess plumbing for the `dirsql interpret` e2e tests.
|
|
2
|
-
|
|
3
|
-
Kept in its own module (rather than `conftest.py` or inline in the
|
|
4
|
-
test file) because these helpers are not pytest fixtures -- they are
|
|
5
|
-
plain functions that drive a child process via NDJSON. Importing them
|
|
6
|
-
keeps each test focused on the assertion, not the framing.
|
|
7
|
-
|
|
8
|
-
Naming intentionally does not match `test_*.py` / `*_test.py` so
|
|
9
|
-
pytest skips collection.
|
|
10
|
-
"""
|
|
11
|
-
|
|
12
|
-
from __future__ import annotations
|
|
13
|
-
|
|
14
|
-
import json
|
|
15
|
-
import shutil
|
|
16
|
-
import subprocess
|
|
17
|
-
import threading
|
|
18
|
-
from pathlib import Path
|
|
19
|
-
from typing import Any
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
def cli_argv() -> list[str]:
|
|
23
|
-
"""Resolve the `dirsql` console-script invocation for this test env.
|
|
24
|
-
|
|
25
|
-
Failing loudly here surfaces an environment misconfiguration rather
|
|
26
|
-
than masking it as a test assertion failure further down.
|
|
27
|
-
"""
|
|
28
|
-
dirsql = shutil.which("dirsql")
|
|
29
|
-
assert dirsql is not None, (
|
|
30
|
-
"`dirsql` console script not on PATH -- run `uv run maturin develop`"
|
|
31
|
-
)
|
|
32
|
-
return [dirsql]
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
def spawn(config_path: Path) -> subprocess.Popen:
|
|
36
|
-
"""Start `dirsql interpret <config>` with piped stdin/stdout/stderr."""
|
|
37
|
-
return subprocess.Popen(
|
|
38
|
-
[*cli_argv(), "interpret", str(config_path)],
|
|
39
|
-
stdin=subprocess.PIPE,
|
|
40
|
-
stdout=subprocess.PIPE,
|
|
41
|
-
stderr=subprocess.PIPE,
|
|
42
|
-
text=True,
|
|
43
|
-
bufsize=1,
|
|
44
|
-
)
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
def readline(proc: subprocess.Popen, timeout: float = 5.0) -> str:
|
|
48
|
-
"""Read one stdout line with a timeout.
|
|
49
|
-
|
|
50
|
-
On timeout, kill the process and surface stderr so the failure
|
|
51
|
-
message is actionable rather than an opaque hang.
|
|
52
|
-
"""
|
|
53
|
-
result: list[str | None] = [None]
|
|
54
|
-
|
|
55
|
-
def reader() -> None:
|
|
56
|
-
assert proc.stdout is not None
|
|
57
|
-
result[0] = proc.stdout.readline()
|
|
58
|
-
|
|
59
|
-
t = threading.Thread(target=reader, daemon=True)
|
|
60
|
-
t.start()
|
|
61
|
-
t.join(timeout)
|
|
62
|
-
if t.is_alive():
|
|
63
|
-
proc.kill()
|
|
64
|
-
stderr = proc.stderr.read() if proc.stderr else ""
|
|
65
|
-
raise AssertionError(
|
|
66
|
-
f"timed out waiting for stdout line; stderr was:\n{stderr}"
|
|
67
|
-
)
|
|
68
|
-
line = result[0] or ""
|
|
69
|
-
if not line:
|
|
70
|
-
stderr = proc.stderr.read() if proc.stderr else ""
|
|
71
|
-
raise AssertionError(
|
|
72
|
-
f"helper exited (code={proc.returncode}) before writing a line; "
|
|
73
|
-
f"stderr was:\n{stderr}"
|
|
74
|
-
)
|
|
75
|
-
return line
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
def send(proc: subprocess.Popen, msg: dict[str, Any]) -> None:
|
|
79
|
-
"""Write one NDJSON line to the helper's stdin."""
|
|
80
|
-
assert proc.stdin is not None
|
|
81
|
-
proc.stdin.write(json.dumps(msg) + "\n")
|
|
82
|
-
proc.stdin.flush()
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
def shutdown(proc: subprocess.Popen) -> None:
|
|
86
|
-
"""Close stdin and wait for the helper to exit cleanly."""
|
|
87
|
-
if proc.stdin is not None:
|
|
88
|
-
try:
|
|
89
|
-
proc.stdin.close()
|
|
90
|
-
except BrokenPipeError:
|
|
91
|
-
pass
|
|
92
|
-
try:
|
|
93
|
-
proc.wait(timeout=5)
|
|
94
|
-
except subprocess.TimeoutExpired:
|
|
95
|
-
proc.kill()
|
|
96
|
-
proc.wait(timeout=2)
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{dirsql-0.3.41 → dirsql-0.3.42}/packages/python/docs/tests/integration/language-flag.spec.ts
RENAMED
|
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
|