dirsql 0.4.43__tar.gz → 0.4.45__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.4.43 → dirsql-0.4.45}/Cargo.lock +2 -2
- {dirsql-0.4.43 → dirsql-0.4.45}/PKG-INFO +1 -2
- {dirsql-0.4.43 → dirsql-0.4.45}/dirsql/_dirsql.pyi +19 -0
- dirsql-0.4.45/dirsql/plan_entry_path.py +20 -0
- dirsql-0.4.45/dirsql/read_config.py +15 -0
- {dirsql-0.4.43 → dirsql-0.4.45}/dirsql/resolve_configs_extension_specs.py +17 -15
- {dirsql-0.4.43 → dirsql-0.4.45}/dirsql/resolve_extension.py +2 -2
- dirsql-0.4.45/dirsql/resolve_package.py +37 -0
- {dirsql-0.4.43 → dirsql-0.4.45}/packages/python/Cargo.toml +1 -1
- dirsql-0.4.45/packages/python/changelog.d/2026-09-17-extension-resolution-via-core.md +3 -0
- dirsql-0.4.45/packages/python/e2e-attestations/claude-1119-ext-plan.json +7 -0
- dirsql-0.4.45/packages/python/e2e-attestations/claude-1120-py-ext.json +7 -0
- {dirsql-0.4.43 → dirsql-0.4.45}/packages/python/src/lib.rs +211 -2
- {dirsql-0.4.43 → dirsql-0.4.45}/packages/rust/Cargo.toml +1 -1
- dirsql-0.4.45/packages/rust/src/extension_resolution.rs +421 -0
- {dirsql-0.4.43 → dirsql-0.4.45}/packages/rust/src/lib.rs +2 -0
- {dirsql-0.4.43 → dirsql-0.4.45}/pyproject.toml +0 -4
- dirsql-0.4.43/dirsql/has_bare_name.py +0 -14
- dirsql-0.4.43/dirsql/is_bare_name.py +0 -14
- dirsql-0.4.43/dirsql/load_extension_entries.py +0 -28
- dirsql-0.4.43/dirsql/platform_patterns.py +0 -12
- dirsql-0.4.43/dirsql/resolve_config_extensions.py +0 -39
- dirsql-0.4.43/dirsql/resolve_entries.py +0 -20
- dirsql-0.4.43/dirsql/resolve_package.py +0 -53
- dirsql-0.4.43/dirsql/toml_module.py +0 -21
- {dirsql-0.4.43 → dirsql-0.4.45}/Cargo.toml +0 -0
- {dirsql-0.4.43 → dirsql-0.4.45}/README.md +0 -0
- {dirsql-0.4.43 → dirsql-0.4.45}/dirsql/__init__.py +0 -0
- {dirsql-0.4.43 → dirsql-0.4.45}/dirsql/_async.py +0 -0
- {dirsql-0.4.43 → dirsql-0.4.45}/dirsql/cli/__init__.py +0 -0
- {dirsql-0.4.43 → dirsql-0.4.45}/dirsql/cli/discover_plugins/__init__.py +0 -0
- {dirsql-0.4.43 → dirsql-0.4.45}/dirsql/cli/discover_plugins/discovered_fragments.py +0 -0
- {dirsql-0.4.43 → dirsql-0.4.45}/dirsql/cli/discover_plugins/discovery_disabled.py +0 -0
- {dirsql-0.4.43 → dirsql-0.4.45}/dirsql/cli/discover_plugins/fragment_path.py +0 -0
- {dirsql-0.4.43 → dirsql-0.4.45}/dirsql/cli/discover_plugins/user_passed_config.py +0 -0
- {dirsql-0.4.43 → dirsql-0.4.45}/dirsql/cli/discover_plugins/with_discovered_plugins.py +0 -0
- {dirsql-0.4.43 → dirsql-0.4.45}/dirsql/cli/main.py +0 -0
- {dirsql-0.4.43 → dirsql-0.4.45}/dirsql/cli/resolve_config_extensions.py +0 -0
- {dirsql-0.4.43 → dirsql-0.4.45}/dirsql/py.typed +0 -0
- {dirsql-0.4.43 → dirsql-0.4.45}/docs/.claude/CLAUDE.md +0 -0
- {dirsql-0.4.43 → dirsql-0.4.45}/docs/.vitepress/config.ts +0 -0
- {dirsql-0.4.43 → dirsql-0.4.45}/docs/.vitepress/theme/index.ts +0 -0
- {dirsql-0.4.43 → dirsql-0.4.45}/docs/.vitepress/theme/lang.ts +0 -0
- {dirsql-0.4.43 → dirsql-0.4.45}/docs/AGENTS.md +0 -0
- {dirsql-0.4.43 → dirsql-0.4.45}/docs/explanation.md +0 -0
- {dirsql-0.4.43 → dirsql-0.4.45}/docs/getting-started.md +0 -0
- {dirsql-0.4.43 → dirsql-0.4.45}/docs/howto/columns-from-paths.md +0 -0
- {dirsql-0.4.43 → dirsql-0.4.45}/docs/howto/define-tables.md +0 -0
- {dirsql-0.4.43 → dirsql-0.4.45}/docs/howto/embed.md +0 -0
- {dirsql-0.4.43 → dirsql-0.4.45}/docs/howto/extract-from-contents.md +0 -0
- {dirsql-0.4.43 → dirsql-0.4.45}/docs/howto/load-extension.md +0 -0
- {dirsql-0.4.43 → dirsql-0.4.45}/docs/howto/parse-files-into-columns.md +0 -0
- {dirsql-0.4.43 → dirsql-0.4.45}/docs/howto/persist.md +0 -0
- {dirsql-0.4.43 → dirsql-0.4.45}/docs/howto/query-json.md +0 -0
- {dirsql-0.4.43 → dirsql-0.4.45}/docs/howto/query-without-config.md +0 -0
- {dirsql-0.4.43 → dirsql-0.4.45}/docs/howto/react-to-changes.md +0 -0
- {dirsql-0.4.43 → dirsql-0.4.45}/docs/howto/search-by-meaning.md +0 -0
- {dirsql-0.4.43 → dirsql-0.4.45}/docs/howto/search-indexes.md +0 -0
- {dirsql-0.4.43 → dirsql-0.4.45}/docs/howto/skip-files.md +0 -0
- {dirsql-0.4.43 → dirsql-0.4.45}/docs/howto/write-a-plugin.md +0 -0
- {dirsql-0.4.43 → dirsql-0.4.45}/docs/index.md +0 -0
- {dirsql-0.4.43 → dirsql-0.4.45}/docs/package.json +0 -0
- {dirsql-0.4.43 → dirsql-0.4.45}/docs/plugins.md +0 -0
- {dirsql-0.4.43 → dirsql-0.4.45}/docs/pnpm-lock.yaml +0 -0
- {dirsql-0.4.43 → dirsql-0.4.45}/docs/pnpm-workspace.yaml +0 -0
- {dirsql-0.4.43 → dirsql-0.4.45}/docs/reference/cli.md +0 -0
- {dirsql-0.4.43 → dirsql-0.4.45}/docs/reference/columns.md +0 -0
- {dirsql-0.4.43 → dirsql-0.4.45}/docs/reference/config.md +0 -0
- {dirsql-0.4.43 → dirsql-0.4.45}/docs/reference/hooks.md +0 -0
- {dirsql-0.4.43 → dirsql-0.4.45}/docs/reference/http-api.md +0 -0
- {dirsql-0.4.43 → dirsql-0.4.45}/docs/reference/path-tables.md +0 -0
- {dirsql-0.4.43 → dirsql-0.4.45}/docs/reference/sdk.md +0 -0
- {dirsql-0.4.43 → dirsql-0.4.45}/packages/python/CHANGELOG.md +0 -0
- {dirsql-0.4.43 → dirsql-0.4.45}/packages/python/MIGRATIONS.md +0 -0
- {dirsql-0.4.43 → dirsql-0.4.45}/packages/python/README.md +0 -0
- {dirsql-0.4.43 → dirsql-0.4.45}/packages/python/changelog.d/2026-07-13-drop-cwd-config-auto-detect.md +0 -0
- {dirsql-0.4.43 → dirsql-0.4.45}/packages/python/changelog.d/2026-07-13-plugin-discovery.md +0 -0
- {dirsql-0.4.43 → dirsql-0.4.45}/packages/python/changelog.d/2026-07-13-rename-extract-to-on-file.md +0 -0
- {dirsql-0.4.43 → dirsql-0.4.45}/packages/python/changelog.d/2026-07-13-repeatable-config.md +0 -0
- {dirsql-0.4.43 → dirsql-0.4.45}/packages/python/changelog.d/2026-07-13-sdk-default-baked-in-config.md +0 -0
- {dirsql-0.4.43 → dirsql-0.4.45}/packages/python/changelog.d/2026-07-20-drop-implicit-files-table.md +0 -0
- {dirsql-0.4.43 → dirsql-0.4.45}/packages/python/changelog.d/2026-07-21-remove-glob-captures.md +0 -0
- {dirsql-0.4.43 → dirsql-0.4.45}/packages/python/changelog.d/2026-07-24-hookless-table-config-error.md +0 -0
- {dirsql-0.4.43 → dirsql-0.4.45}/packages/python/changelog.d/2026-07-24-remove-stat-fact-injection.md +0 -0
- {dirsql-0.4.43 → dirsql-0.4.45}/packages/python/changelog.d/2026-07-29-restore-python-310.md +0 -0
- {dirsql-0.4.43 → dirsql-0.4.45}/packages/python/changelog.d/2026-08-02-release-profile.md +0 -0
- {dirsql-0.4.43 → dirsql-0.4.45}/packages/python/changelog.d/2026-08-02-scan-failures.md +0 -0
- {dirsql-0.4.43 → dirsql-0.4.45}/packages/python/changelog.d/2026-08-03-discovery-ext-resolution.md +0 -0
- {dirsql-0.4.43 → dirsql-0.4.45}/packages/python/changelog.d/2026-08-03-manylinux-dynamic-binary.md +0 -0
- {dirsql-0.4.43 → dirsql-0.4.45}/packages/python/changelog.d/2026-08-03-python-no-ignore.md +0 -0
- {dirsql-0.4.43 → dirsql-0.4.45}/packages/python/changelog.d/2026-08-04-cast-lints.md +0 -0
- {dirsql-0.4.43 → dirsql-0.4.45}/packages/python/changelog.d/2026-08-04-cli-in-process.md +0 -0
- {dirsql-0.4.43 → dirsql-0.4.45}/packages/python/changelog.d/2026-08-20-curtaincall-dev-dependency.md +0 -0
- {dirsql-0.4.43 → dirsql-0.4.45}/packages/python/changelog.d/2026-08-20-declared-table-name.md +0 -0
- {dirsql-0.4.43 → dirsql-0.4.45}/packages/python/changelog.d/2026-09-04-config-paths-from-argv-module.md +0 -0
- {dirsql-0.4.43 → dirsql-0.4.45}/packages/python/changelog.d/2026-09-05-config-extension-loader-split.md +0 -0
- {dirsql-0.4.43 → dirsql-0.4.45}/packages/python/changelog.d/2026-09-05-resolve-config-extensions-split.md +0 -0
- {dirsql-0.4.43 → dirsql-0.4.45}/packages/python/changelog.d/2026-09-05-resolve-extension-split.md +0 -0
- {dirsql-0.4.43 → dirsql-0.4.45}/packages/python/changelog.d/2026-09-09-launcher-config-path-scan.md +0 -0
- {dirsql-0.4.43 → dirsql-0.4.45}/packages/python/changelog.d/README.md +0 -0
- {dirsql-0.4.43 → dirsql-0.4.45}/packages/python/conftest.py +0 -0
- {dirsql-0.4.43 → dirsql-0.4.45}/packages/python/docs/.claude/CLAUDE.md +0 -0
- {dirsql-0.4.43 → dirsql-0.4.45}/packages/python/docs/.vitepress/config.ts +0 -0
- {dirsql-0.4.43 → dirsql-0.4.45}/packages/python/docs/.vitepress/theme/index.ts +0 -0
- {dirsql-0.4.43 → dirsql-0.4.45}/packages/python/docs/.vitepress/theme/lang.ts +0 -0
- {dirsql-0.4.43 → dirsql-0.4.45}/packages/python/docs/AGENTS.md +0 -0
- {dirsql-0.4.43 → dirsql-0.4.45}/packages/python/docs/explanation.md +0 -0
- {dirsql-0.4.43 → dirsql-0.4.45}/packages/python/docs/getting-started.md +0 -0
- {dirsql-0.4.43 → dirsql-0.4.45}/packages/python/docs/howto/columns-from-paths.md +0 -0
- {dirsql-0.4.43 → dirsql-0.4.45}/packages/python/docs/howto/define-tables.md +0 -0
- {dirsql-0.4.43 → dirsql-0.4.45}/packages/python/docs/howto/embed.md +0 -0
- {dirsql-0.4.43 → dirsql-0.4.45}/packages/python/docs/howto/extract-from-contents.md +0 -0
- {dirsql-0.4.43 → dirsql-0.4.45}/packages/python/docs/howto/load-extension.md +0 -0
- {dirsql-0.4.43 → dirsql-0.4.45}/packages/python/docs/howto/parse-files-into-columns.md +0 -0
- {dirsql-0.4.43 → dirsql-0.4.45}/packages/python/docs/howto/persist.md +0 -0
- {dirsql-0.4.43 → dirsql-0.4.45}/packages/python/docs/howto/query-json.md +0 -0
- {dirsql-0.4.43 → dirsql-0.4.45}/packages/python/docs/howto/query-without-config.md +0 -0
- {dirsql-0.4.43 → dirsql-0.4.45}/packages/python/docs/howto/react-to-changes.md +0 -0
- {dirsql-0.4.43 → dirsql-0.4.45}/packages/python/docs/howto/search-by-meaning.md +0 -0
- {dirsql-0.4.43 → dirsql-0.4.45}/packages/python/docs/howto/search-indexes.md +0 -0
- {dirsql-0.4.43 → dirsql-0.4.45}/packages/python/docs/howto/skip-files.md +0 -0
- {dirsql-0.4.43 → dirsql-0.4.45}/packages/python/docs/howto/write-a-plugin.md +0 -0
- {dirsql-0.4.43 → dirsql-0.4.45}/packages/python/docs/index.md +0 -0
- {dirsql-0.4.43 → dirsql-0.4.45}/packages/python/docs/package.json +0 -0
- {dirsql-0.4.43 → dirsql-0.4.45}/packages/python/docs/plugins.md +0 -0
- {dirsql-0.4.43 → dirsql-0.4.45}/packages/python/docs/pnpm-lock.yaml +0 -0
- {dirsql-0.4.43 → dirsql-0.4.45}/packages/python/docs/pnpm-workspace.yaml +0 -0
- {dirsql-0.4.43 → dirsql-0.4.45}/packages/python/docs/reference/cli.md +0 -0
- {dirsql-0.4.43 → dirsql-0.4.45}/packages/python/docs/reference/columns.md +0 -0
- {dirsql-0.4.43 → dirsql-0.4.45}/packages/python/docs/reference/config.md +0 -0
- {dirsql-0.4.43 → dirsql-0.4.45}/packages/python/docs/reference/hooks.md +0 -0
- {dirsql-0.4.43 → dirsql-0.4.45}/packages/python/docs/reference/http-api.md +0 -0
- {dirsql-0.4.43 → dirsql-0.4.45}/packages/python/docs/reference/path-tables.md +0 -0
- {dirsql-0.4.43 → dirsql-0.4.45}/packages/python/docs/reference/sdk.md +0 -0
- {dirsql-0.4.43 → dirsql-0.4.45}/packages/python/e2e-attestations/cc-keen-knuth-f11gyq.json +0 -0
- {dirsql-0.4.43 → dirsql-0.4.45}/packages/python/e2e-attestations/claude-1056-py-ofpf9.json +0 -0
- {dirsql-0.4.43 → dirsql-0.4.45}/packages/python/e2e-attestations/claude-1066-p1-resolve-extension.json +0 -0
- {dirsql-0.4.43 → dirsql-0.4.45}/packages/python/e2e-attestations/claude-1078-argv-config-paths-core.json +0 -0
- {dirsql-0.4.43 → dirsql-0.4.45}/packages/python/e2e-attestations/claude-1079-p2-resolve-config-extensions.json +0 -0
- {dirsql-0.4.43 → dirsql-0.4.45}/packages/python/e2e-attestations/claude-1080-share-vtab-scaffolding.json +0 -0
- {dirsql-0.4.43 → dirsql-0.4.45}/packages/python/e2e-attestations/claude-1081-indicatif-progress.json +0 -0
- {dirsql-0.4.43 → dirsql-0.4.45}/packages/python/e2e-attestations/claude-1096-watch-moved-dir.json +0 -0
- {dirsql-0.4.43 → dirsql-0.4.45}/packages/python/e2e-attestations/claude-1109-watch-moved-out.json +0 -0
- {dirsql-0.4.43 → dirsql-0.4.45}/packages/python/e2e-attestations/claude-819-oneshot-timeout.json +0 -0
- {dirsql-0.4.43 → dirsql-0.4.45}/packages/python/e2e-attestations/claude-827-unquote-doubled-quotes.json +0 -0
- {dirsql-0.4.43 → dirsql-0.4.45}/packages/python/e2e-attestations/claude-epic-953-slice2-reedline.json +0 -0
- {dirsql-0.4.43 → dirsql-0.4.45}/packages/python/e2e-attestations/claude-epic-953-slice3-format.json +0 -0
- {dirsql-0.4.43 → dirsql-0.4.45}/packages/python/e2e-attestations/claude-epic-953-stacked-prs-x59wm3.json +0 -0
- {dirsql-0.4.43 → dirsql-0.4.45}/packages/python/e2e-attestations/claude-github-issue-825-e4mhhp.json +0 -0
- {dirsql-0.4.43 → dirsql-0.4.45}/packages/python/e2e-attestations/claude-issue-951-0eease.json +0 -0
- {dirsql-0.4.43 → dirsql-0.4.45}/packages/python/e2e-attestations/claude-issue-962-0jjrfv.json +0 -0
- {dirsql-0.4.43 → dirsql-0.4.45}/packages/python/e2e-attestations/claude-issue-986-red-test-e7sjrb.json +0 -0
- {dirsql-0.4.43 → dirsql-0.4.45}/packages/python/e2e-attestations/claude-tackle-1034-cachesplit.json +0 -0
- {dirsql-0.4.43 → dirsql-0.4.45}/packages/python/e2e-attestations/claude-tackle-1042-py12.json +0 -0
- {dirsql-0.4.43 → dirsql-0.4.45}/packages/python/e2e-attestations/claude-tackle-956-xzen74.json +0 -0
- {dirsql-0.4.43 → dirsql-0.4.45}/packages/python/e2e-attestations/claude-tackle-957-lrm0z6-worker-calls.json +0 -0
- {dirsql-0.4.43 → dirsql-0.4.45}/packages/python/e2e-attestations/claude-tackle-957-lrm0z6.json +0 -0
- {dirsql-0.4.43 → dirsql-0.4.45}/packages/python/e2e-attestations/claude-tackle-975-n8mc2h.json +0 -0
- {dirsql-0.4.43 → dirsql-0.4.45}/packages/python/migrations.d/2026-07-13-drop-cwd-config-auto-detect.md +0 -0
- {dirsql-0.4.43 → dirsql-0.4.45}/packages/python/migrations.d/2026-07-13-rename-extract-to-on-file.md +0 -0
- {dirsql-0.4.43 → dirsql-0.4.45}/packages/python/migrations.d/2026-07-13-sdk-default-baked-in-config.md +0 -0
- {dirsql-0.4.43 → dirsql-0.4.45}/packages/python/migrations.d/2026-07-20-drop-implicit-files-table.md +0 -0
- {dirsql-0.4.43 → dirsql-0.4.45}/packages/python/migrations.d/2026-07-21-remove-glob-captures.md +0 -0
- {dirsql-0.4.43 → dirsql-0.4.45}/packages/python/migrations.d/2026-07-24-hookless-table-config-error.md +0 -0
- {dirsql-0.4.43 → dirsql-0.4.45}/packages/python/migrations.d/2026-07-24-remove-stat-fact-injection.md +0 -0
- {dirsql-0.4.43 → dirsql-0.4.45}/packages/python/migrations.d/2026-07-29-restore-python-310.md +0 -0
- {dirsql-0.4.43 → dirsql-0.4.45}/packages/python/migrations.d/2026-08-04-cli-in-process.md +0 -0
- {dirsql-0.4.43 → dirsql-0.4.45}/packages/python/migrations.d/2026-08-20-declared-table-name.md +0 -0
- {dirsql-0.4.43 → dirsql-0.4.45}/packages/python/migrations.d/README.md +0 -0
- {dirsql-0.4.43 → dirsql-0.4.45}/packages/python/testing-conventions.toml +0 -0
- {dirsql-0.4.43 → dirsql-0.4.45}/packages/python/tests/__init__.py +0 -0
- {dirsql-0.4.43 → dirsql-0.4.45}/packages/python/tests/conftest.py +0 -0
- {dirsql-0.4.43 → dirsql-0.4.45}/packages/python/tests/e2e/__init__.py +0 -0
- {dirsql-0.4.43 → dirsql-0.4.45}/packages/python/tests/e2e/fixtures/dirsql_plugin_fixture/__init__.py +0 -0
- {dirsql-0.4.43 → dirsql-0.4.45}/packages/python/tests/e2e/fixtures/dirsql_plugin_fixture/dirsql.toml +0 -0
- {dirsql-0.4.43 → dirsql-0.4.45}/packages/python/tests/integration/__init__.py +0 -0
- {dirsql-0.4.43 → dirsql-0.4.45}/packages/python/tests/integration/binding/__init__.py +0 -0
- {dirsql-0.4.43 → dirsql-0.4.45}/packages/python/tests/integration/hermetic/__init__.py +0 -0
- {dirsql-0.4.43 → dirsql-0.4.45}/packages/rust/CHANGELOG.md +0 -0
- {dirsql-0.4.43 → dirsql-0.4.45}/packages/rust/MIGRATIONS.md +0 -0
- {dirsql-0.4.43 → dirsql-0.4.45}/packages/rust/README.md +0 -0
- {dirsql-0.4.43 → dirsql-0.4.45}/packages/rust/benches/db_bench.rs +0 -0
- {dirsql-0.4.43 → dirsql-0.4.45}/packages/rust/benches/differ_bench.rs +0 -0
- {dirsql-0.4.43 → dirsql-0.4.45}/packages/rust/benches/matcher_bench.rs +0 -0
- {dirsql-0.4.43 → dirsql-0.4.45}/packages/rust/benches/scanner_bench.rs +0 -0
- {dirsql-0.4.43 → dirsql-0.4.45}/packages/rust/docs/explanation.md +0 -0
- {dirsql-0.4.43 → dirsql-0.4.45}/packages/rust/docs/getting-started.md +0 -0
- {dirsql-0.4.43 → dirsql-0.4.45}/packages/rust/docs/howto/columns-from-paths.md +0 -0
- {dirsql-0.4.43 → dirsql-0.4.45}/packages/rust/docs/howto/define-tables.md +0 -0
- {dirsql-0.4.43 → dirsql-0.4.45}/packages/rust/docs/howto/embed.md +0 -0
- {dirsql-0.4.43 → dirsql-0.4.45}/packages/rust/docs/howto/extract-from-contents.md +0 -0
- {dirsql-0.4.43 → dirsql-0.4.45}/packages/rust/docs/howto/load-extension.md +0 -0
- {dirsql-0.4.43 → dirsql-0.4.45}/packages/rust/docs/howto/parse-files-into-columns.md +0 -0
- {dirsql-0.4.43 → dirsql-0.4.45}/packages/rust/docs/howto/persist.md +0 -0
- {dirsql-0.4.43 → dirsql-0.4.45}/packages/rust/docs/howto/query-json.md +0 -0
- {dirsql-0.4.43 → dirsql-0.4.45}/packages/rust/docs/howto/query-without-config.md +0 -0
- {dirsql-0.4.43 → dirsql-0.4.45}/packages/rust/docs/howto/react-to-changes.md +0 -0
- {dirsql-0.4.43 → dirsql-0.4.45}/packages/rust/docs/howto/search-by-meaning.md +0 -0
- {dirsql-0.4.43 → dirsql-0.4.45}/packages/rust/docs/howto/search-indexes.md +0 -0
- {dirsql-0.4.43 → dirsql-0.4.45}/packages/rust/docs/howto/skip-files.md +0 -0
- {dirsql-0.4.43 → dirsql-0.4.45}/packages/rust/docs/howto/write-a-plugin.md +0 -0
- {dirsql-0.4.43 → dirsql-0.4.45}/packages/rust/docs/index.md +0 -0
- {dirsql-0.4.43 → dirsql-0.4.45}/packages/rust/docs/plugins.md +0 -0
- {dirsql-0.4.43 → dirsql-0.4.45}/packages/rust/docs/reference/cli.md +0 -0
- {dirsql-0.4.43 → dirsql-0.4.45}/packages/rust/docs/reference/columns.md +0 -0
- {dirsql-0.4.43 → dirsql-0.4.45}/packages/rust/docs/reference/config.md +0 -0
- {dirsql-0.4.43 → dirsql-0.4.45}/packages/rust/docs/reference/hooks.md +0 -0
- {dirsql-0.4.43 → dirsql-0.4.45}/packages/rust/docs/reference/http-api.md +0 -0
- {dirsql-0.4.43 → dirsql-0.4.45}/packages/rust/docs/reference/path-tables.md +0 -0
- {dirsql-0.4.43 → dirsql-0.4.45}/packages/rust/docs/reference/sdk.md +0 -0
- {dirsql-0.4.43 → dirsql-0.4.45}/packages/rust/src/bin/dirsql.rs +0 -0
- {dirsql-0.4.43 → dirsql-0.4.45}/packages/rust/src/cli/execute.rs +0 -0
- {dirsql-0.4.43 → dirsql-0.4.45}/packages/rust/src/cli/init.rs +0 -0
- {dirsql-0.4.43 → dirsql-0.4.45}/packages/rust/src/cli/mod.rs +0 -0
- {dirsql-0.4.43 → dirsql-0.4.45}/packages/rust/src/cli/repl.rs +0 -0
- {dirsql-0.4.43 → dirsql-0.4.45}/packages/rust/src/cli/router.rs +0 -0
- {dirsql-0.4.43 → dirsql-0.4.45}/packages/rust/src/cli/run.rs +0 -0
- {dirsql-0.4.43 → dirsql-0.4.45}/packages/rust/src/cli/serialize.rs +0 -0
- {dirsql-0.4.43 → dirsql-0.4.45}/packages/rust/src/cli/server.rs +0 -0
- {dirsql-0.4.43 → dirsql-0.4.45}/packages/rust/src/cli/table.rs +0 -0
- {dirsql-0.4.43 → dirsql-0.4.45}/packages/rust/src/command.rs +0 -0
- {dirsql-0.4.43 → dirsql-0.4.45}/packages/rust/src/config.rs +0 -0
- {dirsql-0.4.43 → dirsql-0.4.45}/packages/rust/src/db.rs +0 -0
- {dirsql-0.4.43 → dirsql-0.4.45}/packages/rust/src/default_config.toml +0 -0
- {dirsql-0.4.43 → dirsql-0.4.45}/packages/rust/src/differ.rs +0 -0
- {dirsql-0.4.43 → dirsql-0.4.45}/packages/rust/src/functions.rs +0 -0
- {dirsql-0.4.43 → dirsql-0.4.45}/packages/rust/src/infer.rs +0 -0
- {dirsql-0.4.43 → dirsql-0.4.45}/packages/rust/src/launcher.rs +0 -0
- {dirsql-0.4.43 → dirsql-0.4.45}/packages/rust/src/matcher.rs +0 -0
- {dirsql-0.4.43 → dirsql-0.4.45}/packages/rust/src/parsed_cache.rs +0 -0
- {dirsql-0.4.43 → dirsql-0.4.45}/packages/rust/src/parsed_vtab.rs +0 -0
- {dirsql-0.4.43 → dirsql-0.4.45}/packages/rust/src/path_table.rs +0 -0
- {dirsql-0.4.43 → dirsql-0.4.45}/packages/rust/src/persist.rs +0 -0
- {dirsql-0.4.43 → dirsql-0.4.45}/packages/rust/src/progress.rs +0 -0
- {dirsql-0.4.43 → dirsql-0.4.45}/packages/rust/src/scanner.rs +0 -0
- {dirsql-0.4.43 → dirsql-0.4.45}/packages/rust/src/sql_literal.rs +0 -0
- {dirsql-0.4.43 → dirsql-0.4.45}/packages/rust/src/vtab.rs +0 -0
- {dirsql-0.4.43 → dirsql-0.4.45}/packages/rust/src/vtab_scaffold.rs +0 -0
- {dirsql-0.4.43 → dirsql-0.4.45}/packages/rust/src/watcher.rs +0 -0
|
@@ -552,7 +552,7 @@ checksum = "6184e33543162437515c2e2b48714794e37845ec9851711914eec9d308f6ebe8"
|
|
|
552
552
|
|
|
553
553
|
[[package]]
|
|
554
554
|
name = "dirsql"
|
|
555
|
-
version = "0.4.
|
|
555
|
+
version = "0.4.45"
|
|
556
556
|
dependencies = [
|
|
557
557
|
"assert_cmd",
|
|
558
558
|
"axum",
|
|
@@ -597,7 +597,7 @@ dependencies = [
|
|
|
597
597
|
|
|
598
598
|
[[package]]
|
|
599
599
|
name = "dirsql-py-ext"
|
|
600
|
-
version = "0.4.
|
|
600
|
+
version = "0.4.45"
|
|
601
601
|
dependencies = [
|
|
602
602
|
"dirsql",
|
|
603
603
|
"pyo3",
|
|
@@ -78,4 +78,23 @@ class DirSQL:
|
|
|
78
78
|
def _start_watcher(self) -> None: ...
|
|
79
79
|
def _poll_events(self, timeout_ms: int) -> list[RowEvent]: ...
|
|
80
80
|
|
|
81
|
+
class ExtensionPlanEntry:
|
|
82
|
+
"""One planned ``[[dirsql.extension]]`` entry. Exactly one of ``path`` and
|
|
83
|
+
``package`` is set: a ``path`` is ready to load, a ``package`` must be
|
|
84
|
+
located with ``importlib`` -- unless ``shadow`` names an existing file,
|
|
85
|
+
which takes precedence over the package."""
|
|
86
|
+
|
|
87
|
+
path: str | None
|
|
88
|
+
package: str | None
|
|
89
|
+
shadow: str | None
|
|
90
|
+
entrypoint: str | None
|
|
91
|
+
|
|
92
|
+
@override
|
|
93
|
+
def __repr__(self) -> str: ...
|
|
94
|
+
|
|
81
95
|
def config_paths_from_argv(argv: list[str]) -> list[str]: ...
|
|
96
|
+
def plan_config_extensions(
|
|
97
|
+
configs: list[tuple[str, str | None]],
|
|
98
|
+
) -> list[ExtensionPlanEntry] | None: ...
|
|
99
|
+
def select_loadable(name: str, dirs: list[str], candidates: list[str]) -> str: ...
|
|
100
|
+
def is_bare_name(path: str) -> bool: ...
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
"""The loadable path one planned extension entry resolves to."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import os
|
|
6
|
+
|
|
7
|
+
from .resolve_package import _resolve_package
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
def _plan_entry_path(entry):
|
|
11
|
+
"""Resolve a planned entry to a concrete file.
|
|
12
|
+
|
|
13
|
+
A literal entry is already resolved. A package entry prefers a same-named
|
|
14
|
+
file shadowing it next to the config, then the installed package.
|
|
15
|
+
"""
|
|
16
|
+
if entry.path is not None:
|
|
17
|
+
return entry.path
|
|
18
|
+
if os.path.isfile(entry.shadow):
|
|
19
|
+
return entry.shadow
|
|
20
|
+
return _resolve_package(entry.package)
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
"""Reading one TOML config off disk for the core's extension planner."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
def _read_config(config_path):
|
|
7
|
+
"""Return the config's text, or ``None`` when it cannot be read.
|
|
8
|
+
|
|
9
|
+
A missing or unreadable config is left for the core to report.
|
|
10
|
+
"""
|
|
11
|
+
try:
|
|
12
|
+
with open(config_path, encoding="utf-8") as f:
|
|
13
|
+
return f.read()
|
|
14
|
+
except OSError:
|
|
15
|
+
return None
|
|
@@ -1,15 +1,19 @@
|
|
|
1
1
|
"""Resolution of several TOML configs' ``[[dirsql.extension]]`` entries, in order.
|
|
2
2
|
|
|
3
|
-
The
|
|
4
|
-
|
|
5
|
-
|
|
3
|
+
The planning -- which configs parse, whether any entry names a package rather
|
|
4
|
+
than a file, and what each literal path resolves to against its own config's
|
|
5
|
+
directory -- lives in the Rust core (``_dirsql.plan_config_extensions``). This
|
|
6
|
+
module supplies the two host-specific halves the core cannot have: reading the
|
|
7
|
+
files, and locating an installed package with ``importlib``.
|
|
6
8
|
"""
|
|
7
9
|
|
|
8
10
|
from __future__ import annotations
|
|
9
11
|
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
from .
|
|
12
|
+
import os
|
|
13
|
+
|
|
14
|
+
from ._dirsql import plan_config_extensions
|
|
15
|
+
from .plan_entry_path import _plan_entry_path
|
|
16
|
+
from .read_config import _read_config
|
|
13
17
|
|
|
14
18
|
|
|
15
19
|
def resolve_configs_extension_specs(config_paths):
|
|
@@ -24,13 +28,11 @@ def resolve_configs_extension_specs(config_paths):
|
|
|
24
28
|
the resolved list. Returns ``None`` when no config uses a package name,
|
|
25
29
|
leaving every config's loading to the core.
|
|
26
30
|
"""
|
|
27
|
-
|
|
28
|
-
|
|
31
|
+
sources = [(os.path.abspath(p), _read_config(p)) for p in config_paths]
|
|
32
|
+
plan = plan_config_extensions(sources)
|
|
33
|
+
if plan is None:
|
|
29
34
|
return None
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
entries, base = item
|
|
35
|
-
specs.extend(_resolve_entries(entries, base))
|
|
36
|
-
return specs
|
|
35
|
+
return [
|
|
36
|
+
{"path": _plan_entry_path(entry), "entrypoint": entry.entrypoint}
|
|
37
|
+
for entry in plan
|
|
38
|
+
]
|
|
@@ -10,12 +10,12 @@ package name reaches the package machinery:
|
|
|
10
10
|
2. **Bare name** -- a same-named local file under ``base`` *shadows* the
|
|
11
11
|
package; otherwise the package dir is located via
|
|
12
12
|
:func:`importlib.util.find_spec` and the current platform's loadable is
|
|
13
|
-
|
|
13
|
+
picked from inside it.
|
|
14
14
|
"""
|
|
15
15
|
|
|
16
16
|
import os
|
|
17
17
|
|
|
18
|
-
from .
|
|
18
|
+
from ._dirsql import is_bare_name
|
|
19
19
|
from .resolve_package import _resolve_package
|
|
20
20
|
|
|
21
21
|
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
"""Location of an extension package's loadable file for this platform.
|
|
2
|
+
|
|
3
|
+
``importlib`` finds the package's directories; the core picks the one loadable
|
|
4
|
+
file inside them (and raises on zero or several -- the caller must then
|
|
5
|
+
disambiguate with a literal path).
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
import glob as _glob
|
|
9
|
+
import importlib.util
|
|
10
|
+
import os
|
|
11
|
+
|
|
12
|
+
from ._dirsql import select_loadable
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def _resolve_package(name):
|
|
16
|
+
"""Locate ``name``'s package dir and pick its platform loadable file."""
|
|
17
|
+
try:
|
|
18
|
+
spec = importlib.util.find_spec(name)
|
|
19
|
+
except (ImportError, ValueError) as exc:
|
|
20
|
+
raise ValueError(
|
|
21
|
+
f"could not resolve extension package {name!r}: {exc}"
|
|
22
|
+
) from exc
|
|
23
|
+
if spec is None:
|
|
24
|
+
raise ValueError(f"could not resolve extension package {name!r}: not installed")
|
|
25
|
+
|
|
26
|
+
dirs = list(spec.submodule_search_locations or [])
|
|
27
|
+
if not dirs and spec.origin and spec.origin not in ("built-in", "frozen"):
|
|
28
|
+
dirs.append(os.path.dirname(spec.origin))
|
|
29
|
+
if not dirs:
|
|
30
|
+
raise ValueError(
|
|
31
|
+
f"could not resolve extension package {name!r}: no package directory"
|
|
32
|
+
)
|
|
33
|
+
|
|
34
|
+
candidates = []
|
|
35
|
+
for d in dirs:
|
|
36
|
+
candidates.extend(_glob.glob(os.path.join(d, "**", "*"), recursive=True))
|
|
37
|
+
return select_loadable(name, dirs, candidates)
|
|
@@ -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.4.
|
|
7
|
+
version = "0.4.45"
|
|
8
8
|
# abi3 note: the `abi3-py310` pyo3 feature (below) builds ONE stable-ABI
|
|
9
9
|
# `cp310-abi3` wheel per platform that loads on every CPython >= 3.10
|
|
10
10
|
# (matching `pyproject.toml`'s `requires-python = ">=3.10"`), instead of
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
**Changed**
|
|
2
|
+
|
|
3
|
+
- **Extension resolution now plans in the Rust core.** `resolve_configs_extension_specs` reads each config off disk and hands `(path, contents)` pairs to `dirsql._dirsql.plan_config_extensions`; `_resolve_package` hands the located package directories and their files to `dirsql._dirsql.select_loadable`; `resolve_extension_path` classifies through `dirsql._dirsql.is_bare_name`. Python keeps only the two host-specific halves — reading the files, and `importlib.util.find_spec`. Seven internal modules go away (`is_bare_name`, `has_bare_name`, `load_extension_entries`, `resolve_entries`, `platform_patterns`, `resolve_config_extensions`, `toml_module`) against two added (`read_config`, `plan_entry_path`), and with them the `tomli` dependency on Python 3.10. No change to the published API or CLI behavior. (#1120)
|
|
@@ -12,12 +12,13 @@
|
|
|
12
12
|
|
|
13
13
|
#[cfg(feature = "extension-module")]
|
|
14
14
|
mod python {
|
|
15
|
+
use ::dirsql::extension_resolution::{self, ConfigSource, PlanEntry};
|
|
15
16
|
use ::dirsql::{DirSQL, Extension, Row, RowEvent, Table, Value};
|
|
16
|
-
use pyo3::exceptions::{PyOverflowError, PyRuntimeError};
|
|
17
|
+
use pyo3::exceptions::{PyOverflowError, PyRuntimeError, PyValueError};
|
|
17
18
|
use pyo3::prelude::*;
|
|
18
19
|
use pyo3::types::{PyBool, PyByteArray, PyBytes, PyDict, PyInt, PyList};
|
|
19
20
|
use std::collections::HashMap;
|
|
20
|
-
use std::path::PathBuf;
|
|
21
|
+
use std::path::{Path, PathBuf};
|
|
21
22
|
use std::time::Duration;
|
|
22
23
|
|
|
23
24
|
/// A table definition. Mirrors `dirsql::Table` but holds a Python
|
|
@@ -469,6 +470,115 @@ mod python {
|
|
|
469
470
|
dirsql::launcher::config_paths_from_argv(&argv)
|
|
470
471
|
}
|
|
471
472
|
|
|
473
|
+
/// The loadable-file suffixes a CPython host recognizes.
|
|
474
|
+
const PY_SUFFIXES: &[&str] = &[".so", ".dylib", ".dll", ".pyd"];
|
|
475
|
+
|
|
476
|
+
/// The subset this platform actually builds, used when picking a
|
|
477
|
+
/// package's loadable out of everything installed beside it.
|
|
478
|
+
#[cfg(target_os = "macos")]
|
|
479
|
+
const PLATFORM_SUFFIXES: &[&str] = &[".dylib"];
|
|
480
|
+
#[cfg(target_os = "windows")]
|
|
481
|
+
const PLATFORM_SUFFIXES: &[&str] = &[".dll", ".pyd"];
|
|
482
|
+
#[cfg(not(any(target_os = "macos", target_os = "windows")))]
|
|
483
|
+
const PLATFORM_SUFFIXES: &[&str] = &[".so"];
|
|
484
|
+
|
|
485
|
+
/// One planned `[[dirsql.extension]]` entry.
|
|
486
|
+
///
|
|
487
|
+
/// Exactly one of `path` and `package` is set: a `path` is ready to load,
|
|
488
|
+
/// a `package` must be located with `importlib` first — unless `shadow`
|
|
489
|
+
/// names an existing file, which takes precedence over the package.
|
|
490
|
+
#[pyclass(name = "ExtensionPlanEntry", frozen)]
|
|
491
|
+
struct PyExtensionPlanEntry {
|
|
492
|
+
#[pyo3(get)]
|
|
493
|
+
path: Option<String>,
|
|
494
|
+
#[pyo3(get)]
|
|
495
|
+
package: Option<String>,
|
|
496
|
+
#[pyo3(get)]
|
|
497
|
+
shadow: Option<String>,
|
|
498
|
+
#[pyo3(get)]
|
|
499
|
+
entrypoint: Option<String>,
|
|
500
|
+
}
|
|
501
|
+
|
|
502
|
+
#[pymethods]
|
|
503
|
+
impl PyExtensionPlanEntry {
|
|
504
|
+
fn __repr__(&self) -> String {
|
|
505
|
+
format!(
|
|
506
|
+
"ExtensionPlanEntry(path={:?}, package={:?}, shadow={:?}, entrypoint={:?})",
|
|
507
|
+
self.path, self.package, self.shadow, self.entrypoint
|
|
508
|
+
)
|
|
509
|
+
}
|
|
510
|
+
}
|
|
511
|
+
|
|
512
|
+
fn plan_entry_to_py(entry: PlanEntry) -> PyExtensionPlanEntry {
|
|
513
|
+
match entry {
|
|
514
|
+
PlanEntry::Literal { path, entrypoint } => PyExtensionPlanEntry {
|
|
515
|
+
path: Some(display(&path)),
|
|
516
|
+
package: None,
|
|
517
|
+
shadow: None,
|
|
518
|
+
entrypoint,
|
|
519
|
+
},
|
|
520
|
+
PlanEntry::Package {
|
|
521
|
+
name,
|
|
522
|
+
shadow,
|
|
523
|
+
entrypoint,
|
|
524
|
+
} => PyExtensionPlanEntry {
|
|
525
|
+
path: None,
|
|
526
|
+
package: Some(name),
|
|
527
|
+
shadow: Some(display(&shadow)),
|
|
528
|
+
entrypoint,
|
|
529
|
+
},
|
|
530
|
+
}
|
|
531
|
+
}
|
|
532
|
+
|
|
533
|
+
fn display(path: &Path) -> String {
|
|
534
|
+
path.to_string_lossy().into_owned()
|
|
535
|
+
}
|
|
536
|
+
|
|
537
|
+
/// Plan several configs' `[[dirsql.extension]]` entries.
|
|
538
|
+
///
|
|
539
|
+
/// `configs` pairs each config's absolute path with its contents, or
|
|
540
|
+
/// `None` when the launcher could not read it. `None` back means no entry
|
|
541
|
+
/// names a package, so the core's own config loading handles them all.
|
|
542
|
+
#[pyfunction]
|
|
543
|
+
fn plan_config_extensions(
|
|
544
|
+
configs: Vec<(String, Option<String>)>,
|
|
545
|
+
) -> Option<Vec<PyExtensionPlanEntry>> {
|
|
546
|
+
let sources: Vec<ConfigSource<'_>> = configs
|
|
547
|
+
.iter()
|
|
548
|
+
.map(|(path, contents)| ConfigSource {
|
|
549
|
+
path: Path::new(path),
|
|
550
|
+
contents: contents.as_deref(),
|
|
551
|
+
})
|
|
552
|
+
.collect();
|
|
553
|
+
let plan = extension_resolution::plan_config_extensions(&sources, PY_SUFFIXES)?;
|
|
554
|
+
Some(plan.into_iter().map(plan_entry_to_py).collect())
|
|
555
|
+
}
|
|
556
|
+
|
|
557
|
+
/// Pick package `name`'s single loadable file out of `candidates`.
|
|
558
|
+
#[pyfunction]
|
|
559
|
+
fn select_loadable(name: &str, dirs: Vec<String>, candidates: Vec<String>) -> PyResult<String> {
|
|
560
|
+
selected_loadable(name, dirs, candidates).map_err(PyValueError::new_err)
|
|
561
|
+
}
|
|
562
|
+
|
|
563
|
+
/// The interpreter-free half of [`select_loadable`], so it stays unit-testable.
|
|
564
|
+
fn selected_loadable(
|
|
565
|
+
name: &str,
|
|
566
|
+
dirs: Vec<String>,
|
|
567
|
+
candidates: Vec<String>,
|
|
568
|
+
) -> Result<String, String> {
|
|
569
|
+
let dirs: Vec<PathBuf> = dirs.into_iter().map(PathBuf::from).collect();
|
|
570
|
+
let candidates: Vec<PathBuf> = candidates.into_iter().map(PathBuf::from).collect();
|
|
571
|
+
extension_resolution::select_loadable(name, &dirs, &candidates, PLATFORM_SUFFIXES)
|
|
572
|
+
.map(|path| display(&path))
|
|
573
|
+
.map_err(|err| err.to_string())
|
|
574
|
+
}
|
|
575
|
+
|
|
576
|
+
/// Whether an extension entry names a package rather than a file.
|
|
577
|
+
#[pyfunction]
|
|
578
|
+
fn is_bare_name(path: &str) -> bool {
|
|
579
|
+
extension_resolution::is_bare_name(path, PY_SUFFIXES)
|
|
580
|
+
}
|
|
581
|
+
|
|
472
582
|
#[pymodule]
|
|
473
583
|
#[pyo3(name = "_dirsql")]
|
|
474
584
|
fn py_dirsql_module(m: &Bound<'_, PyModule>) -> PyResult<()> {
|
|
@@ -479,6 +589,10 @@ mod python {
|
|
|
479
589
|
m.add_class::<PyScanFailure>()?;
|
|
480
590
|
m.add_function(wrap_pyfunction!(run_cli, m)?)?;
|
|
481
591
|
m.add_function(wrap_pyfunction!(config_paths_from_argv, m)?)?;
|
|
592
|
+
m.add_function(wrap_pyfunction!(plan_config_extensions, m)?)?;
|
|
593
|
+
m.add_function(wrap_pyfunction!(select_loadable, m)?)?;
|
|
594
|
+
m.add_function(wrap_pyfunction!(is_bare_name, m)?)?;
|
|
595
|
+
m.add_class::<PyExtensionPlanEntry>()?;
|
|
482
596
|
Ok(())
|
|
483
597
|
}
|
|
484
598
|
|
|
@@ -561,6 +675,101 @@ mod python {
|
|
|
561
675
|
assert_eq!(OnFileError("bad".to_string()).to_string(), "bad");
|
|
562
676
|
}
|
|
563
677
|
|
|
678
|
+
#[test]
|
|
679
|
+
fn planning_returns_none_when_no_entry_names_a_package() {
|
|
680
|
+
let plan = plan_config_extensions(vec![(
|
|
681
|
+
"/cfg/.dirsql.toml".into(),
|
|
682
|
+
Some("[[dirsql.extension]]\npath = \"vec0.so\"\n".into()),
|
|
683
|
+
)]);
|
|
684
|
+
assert!(plan.is_none());
|
|
685
|
+
}
|
|
686
|
+
|
|
687
|
+
#[test]
|
|
688
|
+
fn planning_marshals_a_literal_against_its_own_config_directory() {
|
|
689
|
+
let plan = plan_config_extensions(vec![(
|
|
690
|
+
"/cfg/.dirsql.toml".into(),
|
|
691
|
+
Some(
|
|
692
|
+
"[[dirsql.extension]]\npath = \"ext/vec0.so\"\nentrypoint = \"init\"\n\n[[dirsql.extension]]\npath = \"sqlite_vec\"\n"
|
|
693
|
+
.into(),
|
|
694
|
+
),
|
|
695
|
+
)])
|
|
696
|
+
.expect("a bare name makes the SDK intervene");
|
|
697
|
+
|
|
698
|
+
assert_eq!(plan[0].path.as_deref(), Some("/cfg/ext/vec0.so"));
|
|
699
|
+
assert_eq!(plan[0].package, None);
|
|
700
|
+
assert_eq!(plan[0].shadow, None);
|
|
701
|
+
assert_eq!(plan[0].entrypoint.as_deref(), Some("init"));
|
|
702
|
+
}
|
|
703
|
+
|
|
704
|
+
#[test]
|
|
705
|
+
fn planning_marshals_a_package_with_its_shadow_probe() {
|
|
706
|
+
let plan = plan_config_extensions(vec![(
|
|
707
|
+
"/cfg/.dirsql.toml".into(),
|
|
708
|
+
Some("[[dirsql.extension]]\npath = \"sqlite_vec\"\n".into()),
|
|
709
|
+
)])
|
|
710
|
+
.expect("a bare name makes the SDK intervene");
|
|
711
|
+
|
|
712
|
+
assert_eq!(plan[0].path, None);
|
|
713
|
+
assert_eq!(plan[0].package.as_deref(), Some("sqlite_vec"));
|
|
714
|
+
assert_eq!(plan[0].shadow.as_deref(), Some("/cfg/sqlite_vec"));
|
|
715
|
+
assert_eq!(plan[0].entrypoint, None);
|
|
716
|
+
}
|
|
717
|
+
|
|
718
|
+
#[test]
|
|
719
|
+
fn an_unreadable_config_is_skipped_rather_than_reported() {
|
|
720
|
+
assert!(plan_config_extensions(vec![("/cfg/.dirsql.toml".into(), None)]).is_none());
|
|
721
|
+
}
|
|
722
|
+
|
|
723
|
+
#[test]
|
|
724
|
+
fn plan_entry_repr_names_every_field() {
|
|
725
|
+
let entry = plan_entry_to_py(PlanEntry::Package {
|
|
726
|
+
name: "vec".into(),
|
|
727
|
+
shadow: "/cfg/vec".into(),
|
|
728
|
+
entrypoint: Some("init".into()),
|
|
729
|
+
});
|
|
730
|
+
assert_eq!(
|
|
731
|
+
entry.__repr__(),
|
|
732
|
+
"ExtensionPlanEntry(path=None, package=Some(\"vec\"), shadow=Some(\"/cfg/vec\"), entrypoint=Some(\"init\"))"
|
|
733
|
+
);
|
|
734
|
+
}
|
|
735
|
+
|
|
736
|
+
#[cfg(target_os = "macos")]
|
|
737
|
+
const EXPECTED_PATTERNS: &str = "*.dylib";
|
|
738
|
+
#[cfg(target_os = "windows")]
|
|
739
|
+
const EXPECTED_PATTERNS: &str = "*.dll / *.pyd";
|
|
740
|
+
#[cfg(not(any(target_os = "macos", target_os = "windows")))]
|
|
741
|
+
const EXPECTED_PATTERNS: &str = "*.so";
|
|
742
|
+
|
|
743
|
+
#[test]
|
|
744
|
+
fn select_loadable_returns_the_single_match() {
|
|
745
|
+
let found = selected_loadable(
|
|
746
|
+
"vec",
|
|
747
|
+
vec!["/pkg".into()],
|
|
748
|
+
vec!["/pkg/__init__.py".into(), "/pkg/vec0.so".into()],
|
|
749
|
+
);
|
|
750
|
+
assert_eq!(found, Ok("/pkg/vec0.so".to_string()));
|
|
751
|
+
}
|
|
752
|
+
|
|
753
|
+
#[test]
|
|
754
|
+
fn select_loadable_carries_the_cores_message_verbatim() {
|
|
755
|
+
let err = selected_loadable("vec", vec!["/pkg".into()], vec![])
|
|
756
|
+
.expect_err("no loadable file");
|
|
757
|
+
assert_eq!(
|
|
758
|
+
err,
|
|
759
|
+
format!(
|
|
760
|
+
"no loadable extension file ({EXPECTED_PATTERNS}) found in package 'vec' (searched /pkg)"
|
|
761
|
+
)
|
|
762
|
+
);
|
|
763
|
+
}
|
|
764
|
+
|
|
765
|
+
#[test]
|
|
766
|
+
fn is_bare_name_applies_the_cpython_suffix_list() {
|
|
767
|
+
assert!(is_bare_name("sqlite_vec"));
|
|
768
|
+
assert!(!is_bare_name("vec0.pyd"));
|
|
769
|
+
assert!(is_bare_name("vec0.node"));
|
|
770
|
+
assert!(!is_bare_name("ext/vec0"));
|
|
771
|
+
}
|
|
772
|
+
|
|
564
773
|
#[test]
|
|
565
774
|
fn config_paths_from_argv_forwards_to_the_core_scan() {
|
|
566
775
|
assert_eq!(
|
|
@@ -6,7 +6,7 @@ description = "Ephemeral SQL index over a local directory"
|
|
|
6
6
|
# version stays for the binding crates (publish = false). The literal
|
|
7
7
|
# intentionally lags the published version: putitoutthere rewrites it to
|
|
8
8
|
# the planned release version at build time and never commits it back.
|
|
9
|
-
version = "0.4.
|
|
9
|
+
version = "0.4.45"
|
|
10
10
|
edition.workspace = true
|
|
11
11
|
# Literal `license` (not `license.workspace = true`) because
|
|
12
12
|
# putitoutthere's preflight check reads `[package].license` directly
|