dirsql 0.4.36__tar.gz → 0.4.37__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.36 → dirsql-0.4.37}/Cargo.lock +2 -2
- {dirsql-0.4.36 → dirsql-0.4.37}/PKG-INFO +1 -1
- {dirsql-0.4.36 → dirsql-0.4.37}/dirsql/_async.py +1 -1
- {dirsql-0.4.36 → dirsql-0.4.37}/dirsql/cli/resolve_config_extensions.py +5 -5
- dirsql-0.4.37/dirsql/has_bare_name.py +14 -0
- dirsql-0.4.37/dirsql/is_bare_name.py +14 -0
- dirsql-0.4.37/dirsql/load_extension_entries.py +28 -0
- dirsql-0.4.37/dirsql/platform_patterns.py +12 -0
- dirsql-0.4.37/dirsql/resolve_config_extensions.py +39 -0
- dirsql-0.4.37/dirsql/resolve_configs_extension_specs.py +36 -0
- dirsql-0.4.37/dirsql/resolve_entries.py +20 -0
- dirsql-0.4.37/dirsql/resolve_extension.py +38 -0
- dirsql-0.4.37/dirsql/resolve_package.py +53 -0
- dirsql-0.4.37/dirsql/toml_module.py +21 -0
- {dirsql-0.4.36 → dirsql-0.4.37}/packages/python/Cargo.toml +1 -1
- dirsql-0.4.37/packages/python/changelog.d/2026-09-05-config-extension-loader-split.md +3 -0
- dirsql-0.4.37/packages/python/changelog.d/2026-09-05-resolve-config-extensions-split.md +3 -0
- dirsql-0.4.37/packages/python/changelog.d/2026-09-05-resolve-extension-split.md +3 -0
- dirsql-0.4.37/packages/python/e2e-attestations/claude-1056-py-ofpf9.json +7 -0
- dirsql-0.4.37/packages/python/e2e-attestations/claude-1066-p1-resolve-extension.json +7 -0
- dirsql-0.4.37/packages/python/e2e-attestations/claude-1079-p2-resolve-config-extensions.json +7 -0
- {dirsql-0.4.36 → dirsql-0.4.37}/packages/python/testing-conventions.toml +1 -1
- {dirsql-0.4.36 → dirsql-0.4.37}/packages/rust/Cargo.toml +1 -1
- dirsql-0.4.36/dirsql/resolve_config_extensions.py +0 -126
- dirsql-0.4.36/dirsql/resolve_extension.py +0 -101
- {dirsql-0.4.36 → dirsql-0.4.37}/Cargo.toml +0 -0
- {dirsql-0.4.36 → dirsql-0.4.37}/README.md +0 -0
- {dirsql-0.4.36 → dirsql-0.4.37}/dirsql/__init__.py +0 -0
- {dirsql-0.4.36 → dirsql-0.4.37}/dirsql/_dirsql.pyi +0 -0
- {dirsql-0.4.36 → dirsql-0.4.37}/dirsql/cli/__init__.py +0 -0
- {dirsql-0.4.36 → dirsql-0.4.37}/dirsql/cli/config_paths_from_argv.py +0 -0
- {dirsql-0.4.36 → dirsql-0.4.37}/dirsql/cli/discover_plugins/__init__.py +0 -0
- {dirsql-0.4.36 → dirsql-0.4.37}/dirsql/cli/discover_plugins/discovered_fragments.py +0 -0
- {dirsql-0.4.36 → dirsql-0.4.37}/dirsql/cli/discover_plugins/discovery_disabled.py +0 -0
- {dirsql-0.4.36 → dirsql-0.4.37}/dirsql/cli/discover_plugins/fragment_path.py +0 -0
- {dirsql-0.4.36 → dirsql-0.4.37}/dirsql/cli/discover_plugins/user_passed_config.py +0 -0
- {dirsql-0.4.36 → dirsql-0.4.37}/dirsql/cli/discover_plugins/with_discovered_plugins.py +0 -0
- {dirsql-0.4.36 → dirsql-0.4.37}/dirsql/cli/main.py +0 -0
- {dirsql-0.4.36 → dirsql-0.4.37}/dirsql/py.typed +0 -0
- {dirsql-0.4.36 → dirsql-0.4.37}/docs/.claude/CLAUDE.md +0 -0
- {dirsql-0.4.36 → dirsql-0.4.37}/docs/.vitepress/config.ts +0 -0
- {dirsql-0.4.36 → dirsql-0.4.37}/docs/.vitepress/theme/index.ts +0 -0
- {dirsql-0.4.36 → dirsql-0.4.37}/docs/.vitepress/theme/lang.ts +0 -0
- {dirsql-0.4.36 → dirsql-0.4.37}/docs/AGENTS.md +0 -0
- {dirsql-0.4.36 → dirsql-0.4.37}/docs/explanation.md +0 -0
- {dirsql-0.4.36 → dirsql-0.4.37}/docs/getting-started.md +0 -0
- {dirsql-0.4.36 → dirsql-0.4.37}/docs/howto/columns-from-paths.md +0 -0
- {dirsql-0.4.36 → dirsql-0.4.37}/docs/howto/define-tables.md +0 -0
- {dirsql-0.4.36 → dirsql-0.4.37}/docs/howto/embed.md +0 -0
- {dirsql-0.4.36 → dirsql-0.4.37}/docs/howto/extract-from-contents.md +0 -0
- {dirsql-0.4.36 → dirsql-0.4.37}/docs/howto/load-extension.md +0 -0
- {dirsql-0.4.36 → dirsql-0.4.37}/docs/howto/parse-files-into-columns.md +0 -0
- {dirsql-0.4.36 → dirsql-0.4.37}/docs/howto/persist.md +0 -0
- {dirsql-0.4.36 → dirsql-0.4.37}/docs/howto/query-json.md +0 -0
- {dirsql-0.4.36 → dirsql-0.4.37}/docs/howto/query-without-config.md +0 -0
- {dirsql-0.4.36 → dirsql-0.4.37}/docs/howto/react-to-changes.md +0 -0
- {dirsql-0.4.36 → dirsql-0.4.37}/docs/howto/search-by-meaning.md +0 -0
- {dirsql-0.4.36 → dirsql-0.4.37}/docs/howto/search-indexes.md +0 -0
- {dirsql-0.4.36 → dirsql-0.4.37}/docs/howto/skip-files.md +0 -0
- {dirsql-0.4.36 → dirsql-0.4.37}/docs/howto/write-a-plugin.md +0 -0
- {dirsql-0.4.36 → dirsql-0.4.37}/docs/index.md +0 -0
- {dirsql-0.4.36 → dirsql-0.4.37}/docs/package.json +0 -0
- {dirsql-0.4.36 → dirsql-0.4.37}/docs/plugins.md +0 -0
- {dirsql-0.4.36 → dirsql-0.4.37}/docs/pnpm-lock.yaml +0 -0
- {dirsql-0.4.36 → dirsql-0.4.37}/docs/pnpm-workspace.yaml +0 -0
- {dirsql-0.4.36 → dirsql-0.4.37}/docs/reference/cli.md +0 -0
- {dirsql-0.4.36 → dirsql-0.4.37}/docs/reference/columns.md +0 -0
- {dirsql-0.4.36 → dirsql-0.4.37}/docs/reference/config.md +0 -0
- {dirsql-0.4.36 → dirsql-0.4.37}/docs/reference/hooks.md +0 -0
- {dirsql-0.4.36 → dirsql-0.4.37}/docs/reference/http-api.md +0 -0
- {dirsql-0.4.36 → dirsql-0.4.37}/docs/reference/path-tables.md +0 -0
- {dirsql-0.4.36 → dirsql-0.4.37}/docs/reference/sdk.md +0 -0
- {dirsql-0.4.36 → dirsql-0.4.37}/packages/python/CHANGELOG.md +0 -0
- {dirsql-0.4.36 → dirsql-0.4.37}/packages/python/MIGRATIONS.md +0 -0
- {dirsql-0.4.36 → dirsql-0.4.37}/packages/python/README.md +0 -0
- {dirsql-0.4.36 → dirsql-0.4.37}/packages/python/changelog.d/2026-07-13-drop-cwd-config-auto-detect.md +0 -0
- {dirsql-0.4.36 → dirsql-0.4.37}/packages/python/changelog.d/2026-07-13-plugin-discovery.md +0 -0
- {dirsql-0.4.36 → dirsql-0.4.37}/packages/python/changelog.d/2026-07-13-rename-extract-to-on-file.md +0 -0
- {dirsql-0.4.36 → dirsql-0.4.37}/packages/python/changelog.d/2026-07-13-repeatable-config.md +0 -0
- {dirsql-0.4.36 → dirsql-0.4.37}/packages/python/changelog.d/2026-07-13-sdk-default-baked-in-config.md +0 -0
- {dirsql-0.4.36 → dirsql-0.4.37}/packages/python/changelog.d/2026-07-20-drop-implicit-files-table.md +0 -0
- {dirsql-0.4.36 → dirsql-0.4.37}/packages/python/changelog.d/2026-07-21-remove-glob-captures.md +0 -0
- {dirsql-0.4.36 → dirsql-0.4.37}/packages/python/changelog.d/2026-07-24-hookless-table-config-error.md +0 -0
- {dirsql-0.4.36 → dirsql-0.4.37}/packages/python/changelog.d/2026-07-24-remove-stat-fact-injection.md +0 -0
- {dirsql-0.4.36 → dirsql-0.4.37}/packages/python/changelog.d/2026-07-29-restore-python-310.md +0 -0
- {dirsql-0.4.36 → dirsql-0.4.37}/packages/python/changelog.d/2026-08-02-release-profile.md +0 -0
- {dirsql-0.4.36 → dirsql-0.4.37}/packages/python/changelog.d/2026-08-02-scan-failures.md +0 -0
- {dirsql-0.4.36 → dirsql-0.4.37}/packages/python/changelog.d/2026-08-03-discovery-ext-resolution.md +0 -0
- {dirsql-0.4.36 → dirsql-0.4.37}/packages/python/changelog.d/2026-08-03-manylinux-dynamic-binary.md +0 -0
- {dirsql-0.4.36 → dirsql-0.4.37}/packages/python/changelog.d/2026-08-03-python-no-ignore.md +0 -0
- {dirsql-0.4.36 → dirsql-0.4.37}/packages/python/changelog.d/2026-08-04-cast-lints.md +0 -0
- {dirsql-0.4.36 → dirsql-0.4.37}/packages/python/changelog.d/2026-08-04-cli-in-process.md +0 -0
- {dirsql-0.4.36 → dirsql-0.4.37}/packages/python/changelog.d/2026-08-20-curtaincall-dev-dependency.md +0 -0
- {dirsql-0.4.36 → dirsql-0.4.37}/packages/python/changelog.d/2026-08-20-declared-table-name.md +0 -0
- {dirsql-0.4.36 → dirsql-0.4.37}/packages/python/changelog.d/2026-09-04-config-paths-from-argv-module.md +0 -0
- {dirsql-0.4.36 → dirsql-0.4.37}/packages/python/changelog.d/README.md +0 -0
- {dirsql-0.4.36 → dirsql-0.4.37}/packages/python/conftest.py +0 -0
- {dirsql-0.4.36 → dirsql-0.4.37}/packages/python/docs/.claude/CLAUDE.md +0 -0
- {dirsql-0.4.36 → dirsql-0.4.37}/packages/python/docs/.vitepress/config.ts +0 -0
- {dirsql-0.4.36 → dirsql-0.4.37}/packages/python/docs/.vitepress/theme/index.ts +0 -0
- {dirsql-0.4.36 → dirsql-0.4.37}/packages/python/docs/.vitepress/theme/lang.ts +0 -0
- {dirsql-0.4.36 → dirsql-0.4.37}/packages/python/docs/AGENTS.md +0 -0
- {dirsql-0.4.36 → dirsql-0.4.37}/packages/python/docs/explanation.md +0 -0
- {dirsql-0.4.36 → dirsql-0.4.37}/packages/python/docs/getting-started.md +0 -0
- {dirsql-0.4.36 → dirsql-0.4.37}/packages/python/docs/howto/columns-from-paths.md +0 -0
- {dirsql-0.4.36 → dirsql-0.4.37}/packages/python/docs/howto/define-tables.md +0 -0
- {dirsql-0.4.36 → dirsql-0.4.37}/packages/python/docs/howto/embed.md +0 -0
- {dirsql-0.4.36 → dirsql-0.4.37}/packages/python/docs/howto/extract-from-contents.md +0 -0
- {dirsql-0.4.36 → dirsql-0.4.37}/packages/python/docs/howto/load-extension.md +0 -0
- {dirsql-0.4.36 → dirsql-0.4.37}/packages/python/docs/howto/parse-files-into-columns.md +0 -0
- {dirsql-0.4.36 → dirsql-0.4.37}/packages/python/docs/howto/persist.md +0 -0
- {dirsql-0.4.36 → dirsql-0.4.37}/packages/python/docs/howto/query-json.md +0 -0
- {dirsql-0.4.36 → dirsql-0.4.37}/packages/python/docs/howto/query-without-config.md +0 -0
- {dirsql-0.4.36 → dirsql-0.4.37}/packages/python/docs/howto/react-to-changes.md +0 -0
- {dirsql-0.4.36 → dirsql-0.4.37}/packages/python/docs/howto/search-by-meaning.md +0 -0
- {dirsql-0.4.36 → dirsql-0.4.37}/packages/python/docs/howto/search-indexes.md +0 -0
- {dirsql-0.4.36 → dirsql-0.4.37}/packages/python/docs/howto/skip-files.md +0 -0
- {dirsql-0.4.36 → dirsql-0.4.37}/packages/python/docs/howto/write-a-plugin.md +0 -0
- {dirsql-0.4.36 → dirsql-0.4.37}/packages/python/docs/index.md +0 -0
- {dirsql-0.4.36 → dirsql-0.4.37}/packages/python/docs/package.json +0 -0
- {dirsql-0.4.36 → dirsql-0.4.37}/packages/python/docs/plugins.md +0 -0
- {dirsql-0.4.36 → dirsql-0.4.37}/packages/python/docs/pnpm-lock.yaml +0 -0
- {dirsql-0.4.36 → dirsql-0.4.37}/packages/python/docs/pnpm-workspace.yaml +0 -0
- {dirsql-0.4.36 → dirsql-0.4.37}/packages/python/docs/reference/cli.md +0 -0
- {dirsql-0.4.36 → dirsql-0.4.37}/packages/python/docs/reference/columns.md +0 -0
- {dirsql-0.4.36 → dirsql-0.4.37}/packages/python/docs/reference/config.md +0 -0
- {dirsql-0.4.36 → dirsql-0.4.37}/packages/python/docs/reference/hooks.md +0 -0
- {dirsql-0.4.36 → dirsql-0.4.37}/packages/python/docs/reference/http-api.md +0 -0
- {dirsql-0.4.36 → dirsql-0.4.37}/packages/python/docs/reference/path-tables.md +0 -0
- {dirsql-0.4.36 → dirsql-0.4.37}/packages/python/docs/reference/sdk.md +0 -0
- {dirsql-0.4.36 → dirsql-0.4.37}/packages/python/e2e-attestations/cc-keen-knuth-f11gyq.json +0 -0
- {dirsql-0.4.36 → dirsql-0.4.37}/packages/python/e2e-attestations/claude-819-oneshot-timeout.json +0 -0
- {dirsql-0.4.36 → dirsql-0.4.37}/packages/python/e2e-attestations/claude-827-unquote-doubled-quotes.json +0 -0
- {dirsql-0.4.36 → dirsql-0.4.37}/packages/python/e2e-attestations/claude-epic-953-slice2-reedline.json +0 -0
- {dirsql-0.4.36 → dirsql-0.4.37}/packages/python/e2e-attestations/claude-epic-953-slice3-format.json +0 -0
- {dirsql-0.4.36 → dirsql-0.4.37}/packages/python/e2e-attestations/claude-epic-953-stacked-prs-x59wm3.json +0 -0
- {dirsql-0.4.36 → dirsql-0.4.37}/packages/python/e2e-attestations/claude-github-issue-825-e4mhhp.json +0 -0
- {dirsql-0.4.36 → dirsql-0.4.37}/packages/python/e2e-attestations/claude-issue-951-0eease.json +0 -0
- {dirsql-0.4.36 → dirsql-0.4.37}/packages/python/e2e-attestations/claude-issue-962-0jjrfv.json +0 -0
- {dirsql-0.4.36 → dirsql-0.4.37}/packages/python/e2e-attestations/claude-issue-986-red-test-e7sjrb.json +0 -0
- {dirsql-0.4.36 → dirsql-0.4.37}/packages/python/e2e-attestations/claude-tackle-1034-cachesplit.json +0 -0
- {dirsql-0.4.36 → dirsql-0.4.37}/packages/python/e2e-attestations/claude-tackle-1042-py12.json +0 -0
- {dirsql-0.4.36 → dirsql-0.4.37}/packages/python/e2e-attestations/claude-tackle-956-xzen74.json +0 -0
- {dirsql-0.4.36 → dirsql-0.4.37}/packages/python/e2e-attestations/claude-tackle-957-lrm0z6-worker-calls.json +0 -0
- {dirsql-0.4.36 → dirsql-0.4.37}/packages/python/e2e-attestations/claude-tackle-957-lrm0z6.json +0 -0
- {dirsql-0.4.36 → dirsql-0.4.37}/packages/python/e2e-attestations/claude-tackle-975-n8mc2h.json +0 -0
- {dirsql-0.4.36 → dirsql-0.4.37}/packages/python/migrations.d/2026-07-13-drop-cwd-config-auto-detect.md +0 -0
- {dirsql-0.4.36 → dirsql-0.4.37}/packages/python/migrations.d/2026-07-13-rename-extract-to-on-file.md +0 -0
- {dirsql-0.4.36 → dirsql-0.4.37}/packages/python/migrations.d/2026-07-13-sdk-default-baked-in-config.md +0 -0
- {dirsql-0.4.36 → dirsql-0.4.37}/packages/python/migrations.d/2026-07-20-drop-implicit-files-table.md +0 -0
- {dirsql-0.4.36 → dirsql-0.4.37}/packages/python/migrations.d/2026-07-21-remove-glob-captures.md +0 -0
- {dirsql-0.4.36 → dirsql-0.4.37}/packages/python/migrations.d/2026-07-24-hookless-table-config-error.md +0 -0
- {dirsql-0.4.36 → dirsql-0.4.37}/packages/python/migrations.d/2026-07-24-remove-stat-fact-injection.md +0 -0
- {dirsql-0.4.36 → dirsql-0.4.37}/packages/python/migrations.d/2026-07-29-restore-python-310.md +0 -0
- {dirsql-0.4.36 → dirsql-0.4.37}/packages/python/migrations.d/2026-08-04-cli-in-process.md +0 -0
- {dirsql-0.4.36 → dirsql-0.4.37}/packages/python/migrations.d/2026-08-20-declared-table-name.md +0 -0
- {dirsql-0.4.36 → dirsql-0.4.37}/packages/python/migrations.d/README.md +0 -0
- {dirsql-0.4.36 → dirsql-0.4.37}/packages/python/src/lib.rs +0 -0
- {dirsql-0.4.36 → dirsql-0.4.37}/packages/python/tests/__init__.py +0 -0
- {dirsql-0.4.36 → dirsql-0.4.37}/packages/python/tests/conftest.py +0 -0
- {dirsql-0.4.36 → dirsql-0.4.37}/packages/python/tests/e2e/__init__.py +0 -0
- {dirsql-0.4.36 → dirsql-0.4.37}/packages/python/tests/e2e/fixtures/dirsql_plugin_fixture/__init__.py +0 -0
- {dirsql-0.4.36 → dirsql-0.4.37}/packages/python/tests/e2e/fixtures/dirsql_plugin_fixture/dirsql.toml +0 -0
- {dirsql-0.4.36 → dirsql-0.4.37}/packages/python/tests/integration/__init__.py +0 -0
- {dirsql-0.4.36 → dirsql-0.4.37}/packages/python/tests/integration/binding/__init__.py +0 -0
- {dirsql-0.4.36 → dirsql-0.4.37}/packages/python/tests/integration/hermetic/__init__.py +0 -0
- {dirsql-0.4.36 → dirsql-0.4.37}/packages/rust/CHANGELOG.md +0 -0
- {dirsql-0.4.36 → dirsql-0.4.37}/packages/rust/MIGRATIONS.md +0 -0
- {dirsql-0.4.36 → dirsql-0.4.37}/packages/rust/README.md +0 -0
- {dirsql-0.4.36 → dirsql-0.4.37}/packages/rust/benches/db_bench.rs +0 -0
- {dirsql-0.4.36 → dirsql-0.4.37}/packages/rust/benches/differ_bench.rs +0 -0
- {dirsql-0.4.36 → dirsql-0.4.37}/packages/rust/benches/matcher_bench.rs +0 -0
- {dirsql-0.4.36 → dirsql-0.4.37}/packages/rust/benches/scanner_bench.rs +0 -0
- {dirsql-0.4.36 → dirsql-0.4.37}/packages/rust/docs/explanation.md +0 -0
- {dirsql-0.4.36 → dirsql-0.4.37}/packages/rust/docs/getting-started.md +0 -0
- {dirsql-0.4.36 → dirsql-0.4.37}/packages/rust/docs/howto/columns-from-paths.md +0 -0
- {dirsql-0.4.36 → dirsql-0.4.37}/packages/rust/docs/howto/define-tables.md +0 -0
- {dirsql-0.4.36 → dirsql-0.4.37}/packages/rust/docs/howto/embed.md +0 -0
- {dirsql-0.4.36 → dirsql-0.4.37}/packages/rust/docs/howto/extract-from-contents.md +0 -0
- {dirsql-0.4.36 → dirsql-0.4.37}/packages/rust/docs/howto/load-extension.md +0 -0
- {dirsql-0.4.36 → dirsql-0.4.37}/packages/rust/docs/howto/parse-files-into-columns.md +0 -0
- {dirsql-0.4.36 → dirsql-0.4.37}/packages/rust/docs/howto/persist.md +0 -0
- {dirsql-0.4.36 → dirsql-0.4.37}/packages/rust/docs/howto/query-json.md +0 -0
- {dirsql-0.4.36 → dirsql-0.4.37}/packages/rust/docs/howto/query-without-config.md +0 -0
- {dirsql-0.4.36 → dirsql-0.4.37}/packages/rust/docs/howto/react-to-changes.md +0 -0
- {dirsql-0.4.36 → dirsql-0.4.37}/packages/rust/docs/howto/search-by-meaning.md +0 -0
- {dirsql-0.4.36 → dirsql-0.4.37}/packages/rust/docs/howto/search-indexes.md +0 -0
- {dirsql-0.4.36 → dirsql-0.4.37}/packages/rust/docs/howto/skip-files.md +0 -0
- {dirsql-0.4.36 → dirsql-0.4.37}/packages/rust/docs/howto/write-a-plugin.md +0 -0
- {dirsql-0.4.36 → dirsql-0.4.37}/packages/rust/docs/index.md +0 -0
- {dirsql-0.4.36 → dirsql-0.4.37}/packages/rust/docs/plugins.md +0 -0
- {dirsql-0.4.36 → dirsql-0.4.37}/packages/rust/docs/reference/cli.md +0 -0
- {dirsql-0.4.36 → dirsql-0.4.37}/packages/rust/docs/reference/columns.md +0 -0
- {dirsql-0.4.36 → dirsql-0.4.37}/packages/rust/docs/reference/config.md +0 -0
- {dirsql-0.4.36 → dirsql-0.4.37}/packages/rust/docs/reference/hooks.md +0 -0
- {dirsql-0.4.36 → dirsql-0.4.37}/packages/rust/docs/reference/http-api.md +0 -0
- {dirsql-0.4.36 → dirsql-0.4.37}/packages/rust/docs/reference/path-tables.md +0 -0
- {dirsql-0.4.36 → dirsql-0.4.37}/packages/rust/docs/reference/sdk.md +0 -0
- {dirsql-0.4.36 → dirsql-0.4.37}/packages/rust/src/bin/dirsql.rs +0 -0
- {dirsql-0.4.36 → dirsql-0.4.37}/packages/rust/src/cli/execute.rs +0 -0
- {dirsql-0.4.36 → dirsql-0.4.37}/packages/rust/src/cli/init.rs +0 -0
- {dirsql-0.4.36 → dirsql-0.4.37}/packages/rust/src/cli/mod.rs +0 -0
- {dirsql-0.4.36 → dirsql-0.4.37}/packages/rust/src/cli/repl.rs +0 -0
- {dirsql-0.4.36 → dirsql-0.4.37}/packages/rust/src/cli/router.rs +0 -0
- {dirsql-0.4.36 → dirsql-0.4.37}/packages/rust/src/cli/run.rs +0 -0
- {dirsql-0.4.36 → dirsql-0.4.37}/packages/rust/src/cli/serialize.rs +0 -0
- {dirsql-0.4.36 → dirsql-0.4.37}/packages/rust/src/cli/server.rs +0 -0
- {dirsql-0.4.36 → dirsql-0.4.37}/packages/rust/src/cli/table.rs +0 -0
- {dirsql-0.4.36 → dirsql-0.4.37}/packages/rust/src/command.rs +0 -0
- {dirsql-0.4.36 → dirsql-0.4.37}/packages/rust/src/config.rs +0 -0
- {dirsql-0.4.36 → dirsql-0.4.37}/packages/rust/src/db.rs +0 -0
- {dirsql-0.4.36 → dirsql-0.4.37}/packages/rust/src/default_config.toml +0 -0
- {dirsql-0.4.36 → dirsql-0.4.37}/packages/rust/src/differ.rs +0 -0
- {dirsql-0.4.36 → dirsql-0.4.37}/packages/rust/src/functions.rs +0 -0
- {dirsql-0.4.36 → dirsql-0.4.37}/packages/rust/src/infer.rs +0 -0
- {dirsql-0.4.36 → dirsql-0.4.37}/packages/rust/src/lib.rs +0 -0
- {dirsql-0.4.36 → dirsql-0.4.37}/packages/rust/src/matcher.rs +0 -0
- {dirsql-0.4.36 → dirsql-0.4.37}/packages/rust/src/parsed_cache.rs +0 -0
- {dirsql-0.4.36 → dirsql-0.4.37}/packages/rust/src/parsed_vtab.rs +0 -0
- {dirsql-0.4.36 → dirsql-0.4.37}/packages/rust/src/path_table.rs +0 -0
- {dirsql-0.4.36 → dirsql-0.4.37}/packages/rust/src/persist.rs +0 -0
- {dirsql-0.4.36 → dirsql-0.4.37}/packages/rust/src/progress.rs +0 -0
- {dirsql-0.4.36 → dirsql-0.4.37}/packages/rust/src/scanner.rs +0 -0
- {dirsql-0.4.36 → dirsql-0.4.37}/packages/rust/src/sql_literal.rs +0 -0
- {dirsql-0.4.36 → dirsql-0.4.37}/packages/rust/src/vtab.rs +0 -0
- {dirsql-0.4.36 → dirsql-0.4.37}/packages/rust/src/watcher.rs +0 -0
- {dirsql-0.4.36 → dirsql-0.4.37}/pyproject.toml +0 -0
|
@@ -540,7 +540,7 @@ checksum = "6184e33543162437515c2e2b48714794e37845ec9851711914eec9d308f6ebe8"
|
|
|
540
540
|
|
|
541
541
|
[[package]]
|
|
542
542
|
name = "dirsql"
|
|
543
|
-
version = "0.4.
|
|
543
|
+
version = "0.4.37"
|
|
544
544
|
dependencies = [
|
|
545
545
|
"assert_cmd",
|
|
546
546
|
"axum",
|
|
@@ -583,7 +583,7 @@ dependencies = [
|
|
|
583
583
|
|
|
584
584
|
[[package]]
|
|
585
585
|
name = "dirsql-py-ext"
|
|
586
|
-
version = "0.4.
|
|
586
|
+
version = "0.4.37"
|
|
587
587
|
dependencies = [
|
|
588
588
|
"dirsql",
|
|
589
589
|
"pyo3",
|
|
@@ -4,7 +4,7 @@ import asyncio
|
|
|
4
4
|
import os
|
|
5
5
|
|
|
6
6
|
from dirsql._dirsql import DirSQL as _RustDirSQL
|
|
7
|
-
from dirsql.
|
|
7
|
+
from dirsql.resolve_configs_extension_specs import resolve_configs_extension_specs
|
|
8
8
|
from dirsql.resolve_extension import resolve_extension_path
|
|
9
9
|
|
|
10
10
|
|
|
@@ -3,10 +3,10 @@
|
|
|
3
3
|
The compiled ``dirsql`` binary loads a config's extensions literally -- it
|
|
4
4
|
has no ``importlib``, so it cannot resolve a bare **package name**. When any
|
|
5
5
|
TOML config in argv names an extension by package name, the shared SDK
|
|
6
|
-
resolver (:mod:`dirsql.
|
|
7
|
-
extensions and this launcher passes the resolved literal paths to
|
|
8
|
-
via repeatable ``--extension`` flags; the binary then loads those
|
|
9
|
-
the configs' own extension entries.
|
|
6
|
+
resolver (:mod:`dirsql.resolve_configs_extension_specs`) resolves every
|
|
7
|
+
config's extensions and this launcher passes the resolved literal paths to
|
|
8
|
+
the binary via repeatable ``--extension`` flags; the binary then loads those
|
|
9
|
+
and ignores the configs' own extension entries.
|
|
10
10
|
|
|
11
11
|
Native-language configs (``.py`` / ``.js`` / ``.mjs`` / ``.cjs``) are untouched:
|
|
12
12
|
the binary dispatches those to ``dirsql interpret``, whose handshake already
|
|
@@ -15,7 +15,7 @@ carries resolved paths.
|
|
|
15
15
|
|
|
16
16
|
from __future__ import annotations
|
|
17
17
|
|
|
18
|
-
from ..
|
|
18
|
+
from ..resolve_configs_extension_specs import resolve_configs_extension_specs
|
|
19
19
|
from .config_paths_from_argv import config_paths_from_argv
|
|
20
20
|
|
|
21
21
|
# Config extensions the binary dispatches to `dirsql interpret`; never
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
"""Whether any of a config's extension entries names a package."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from .is_bare_name import is_bare_name
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
def _has_bare_name(entries):
|
|
9
|
+
return any(
|
|
10
|
+
isinstance(e, dict)
|
|
11
|
+
and isinstance(e.get("path"), str)
|
|
12
|
+
and is_bare_name(e["path"])
|
|
13
|
+
for e in entries
|
|
14
|
+
)
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
"""Whether an extension ``path`` names a package rather than a file."""
|
|
2
|
+
|
|
3
|
+
import os
|
|
4
|
+
|
|
5
|
+
# Suffixes that mark a value as "already a file path", so package resolution
|
|
6
|
+
# is never attempted.
|
|
7
|
+
_LOADABLE_SUFFIXES = (".so", ".dylib", ".dll", ".pyd")
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
def is_bare_name(path):
|
|
11
|
+
"""True when ``path`` is a bare package name rather than a file path."""
|
|
12
|
+
if os.sep in path or (os.altsep and os.altsep in path):
|
|
13
|
+
return False
|
|
14
|
+
return not path.endswith(_LOADABLE_SUFFIXES)
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
"""Reading one TOML config's ``[[dirsql.extension]]`` array off disk."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import os
|
|
6
|
+
|
|
7
|
+
from .toml_module import _toml
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
def _load_extension_entries(config_path):
|
|
11
|
+
"""Return ``(entries, base_dir)`` for a config's ``[[dirsql.extension]]``.
|
|
12
|
+
|
|
13
|
+
``None`` when the config is missing, unreadable/malformed, or declares no
|
|
14
|
+
extension array -- the caller should leave such configs to the core.
|
|
15
|
+
"""
|
|
16
|
+
if not os.path.isfile(config_path):
|
|
17
|
+
return None
|
|
18
|
+
try:
|
|
19
|
+
with open(config_path, "rb") as f:
|
|
20
|
+
doc = _toml.load(f)
|
|
21
|
+
except (OSError, _toml.TOMLDecodeError):
|
|
22
|
+
# Leave a malformed / unreadable config for the core to report.
|
|
23
|
+
return None
|
|
24
|
+
|
|
25
|
+
entries = (doc.get("dirsql") or {}).get("extension")
|
|
26
|
+
if not isinstance(entries, list):
|
|
27
|
+
return None
|
|
28
|
+
return entries, os.path.dirname(os.path.abspath(config_path))
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
"""The loadable-file glob pattern(s) the running platform uses."""
|
|
2
|
+
|
|
3
|
+
import sys
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
def _platform_patterns():
|
|
7
|
+
"""Loadable-file glob(s) for the current platform."""
|
|
8
|
+
if sys.platform == "darwin":
|
|
9
|
+
return ("*.dylib",)
|
|
10
|
+
if sys.platform == "win32":
|
|
11
|
+
return ("*.dll", "*.pyd")
|
|
12
|
+
return ("*.so",)
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
"""SDK-side resolution of a TOML config's ``[[dirsql.extension]]`` entries.
|
|
2
|
+
|
|
3
|
+
The Rust core loads a config's extensions literally -- it has no
|
|
4
|
+
``importlib``, so it cannot resolve a bare **package name**. When a TOML
|
|
5
|
+
config names an extension by package name, the SDK resolves every one of its
|
|
6
|
+
extensions here, hands the core the resolved literal paths, and suppresses
|
|
7
|
+
the core's own config-extension loading (``suppress_config_extensions``) so
|
|
8
|
+
the config's entries are not loaded a second time.
|
|
9
|
+
|
|
10
|
+
Shared by the ``DirSQL`` constructor (``config=`` path) and the CLI launcher
|
|
11
|
+
(which converts the resolved specs into ``--extension`` flags), both of which
|
|
12
|
+
reach it through :mod:`dirsql.resolve_configs_extension_specs`.
|
|
13
|
+
"""
|
|
14
|
+
|
|
15
|
+
from __future__ import annotations
|
|
16
|
+
|
|
17
|
+
from .has_bare_name import _has_bare_name
|
|
18
|
+
from .load_extension_entries import _load_extension_entries
|
|
19
|
+
from .resolve_entries import _resolve_entries
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
def resolve_config_extension_specs(config_path):
|
|
23
|
+
"""Resolve a TOML config's ``[[dirsql.extension]]`` entries to literal paths.
|
|
24
|
+
|
|
25
|
+
Returns a list of ``{"path", "entrypoint"}`` dicts -- every entry resolved
|
|
26
|
+
via :func:`resolve_extension_path` against the config file's parent
|
|
27
|
+
directory -- when at least one entry's ``path`` is a bare package name.
|
|
28
|
+
Returns ``None`` when the caller should not intervene: the config is
|
|
29
|
+
missing, malformed, declares no extensions, or uses only literal paths --
|
|
30
|
+
leaving the core's own loading (and error reporting) untouched. Raises if
|
|
31
|
+
a package name cannot be resolved.
|
|
32
|
+
"""
|
|
33
|
+
loaded = _load_extension_entries(config_path)
|
|
34
|
+
if loaded is None:
|
|
35
|
+
return None
|
|
36
|
+
entries, base = loaded
|
|
37
|
+
if not _has_bare_name(entries):
|
|
38
|
+
return None
|
|
39
|
+
return _resolve_entries(entries, base)
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
"""Resolution of several TOML configs' ``[[dirsql.extension]]`` entries, in order.
|
|
2
|
+
|
|
3
|
+
The plural counterpart to :func:`dirsql.resolve_config_extensions
|
|
4
|
+
.resolve_config_extension_specs`, used by the SDK constructor and the CLI
|
|
5
|
+
launcher when argv carries more than one ``--config``.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from __future__ import annotations
|
|
9
|
+
|
|
10
|
+
from .has_bare_name import _has_bare_name
|
|
11
|
+
from .load_extension_entries import _load_extension_entries
|
|
12
|
+
from .resolve_entries import _resolve_entries
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def resolve_configs_extension_specs(config_paths):
|
|
16
|
+
"""Resolve the ``[[dirsql.extension]]`` entries of several configs, in order.
|
|
17
|
+
|
|
18
|
+
The SDK intervenes for the whole set only when **some** config names an
|
|
19
|
+
extension by bare package name (the core can resolve neither package names
|
|
20
|
+
nor -- once globally suppressed -- the literal entries of the other
|
|
21
|
+
configs). When it intervenes it resolves **every** config's entries, each
|
|
22
|
+
against that config's own parent directory, concatenated in ``config_paths``
|
|
23
|
+
order; the caller suppresses the core's config-extension loading and passes
|
|
24
|
+
the resolved list. Returns ``None`` when no config uses a package name,
|
|
25
|
+
leaving every config's loading to the core.
|
|
26
|
+
"""
|
|
27
|
+
loaded = [_load_extension_entries(p) for p in config_paths]
|
|
28
|
+
if not any(item is not None and _has_bare_name(item[0]) for item in loaded):
|
|
29
|
+
return None
|
|
30
|
+
specs = []
|
|
31
|
+
for item in loaded:
|
|
32
|
+
if item is None:
|
|
33
|
+
continue
|
|
34
|
+
entries, base = item
|
|
35
|
+
specs.extend(_resolve_entries(entries, base))
|
|
36
|
+
return specs
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
"""Resolution of one config's ``[[dirsql.extension]]`` entries to literal paths."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from .resolve_extension import resolve_extension_path
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
def _resolve_entries(entries, base):
|
|
9
|
+
specs = []
|
|
10
|
+
for e in entries:
|
|
11
|
+
entrypoint = e.get("entrypoint")
|
|
12
|
+
specs.append(
|
|
13
|
+
{
|
|
14
|
+
"path": resolve_extension_path(
|
|
15
|
+
e["path"], base=base, resolve_relative=True
|
|
16
|
+
),
|
|
17
|
+
"entrypoint": entrypoint if isinstance(entrypoint, str) else None,
|
|
18
|
+
}
|
|
19
|
+
)
|
|
20
|
+
return specs
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
"""Resolve an extension entry's ``path`` to a concrete loadable file.
|
|
2
|
+
|
|
3
|
+
Resolution is an ordered probe (file-first, then package), so only a bare
|
|
4
|
+
package name reaches the package machinery:
|
|
5
|
+
|
|
6
|
+
1. **Path-looking** (contains a separator, or ends in ``.so`` / ``.dylib`` /
|
|
7
|
+
``.dll`` / ``.pyd``) -- returned as a file path: made absolute against
|
|
8
|
+
``base`` when ``resolve_relative`` is set (config-file entries), else
|
|
9
|
+
verbatim (programmatic entries).
|
|
10
|
+
2. **Bare name** -- a same-named local file under ``base`` *shadows* the
|
|
11
|
+
package; otherwise the package dir is located via
|
|
12
|
+
:func:`importlib.util.find_spec` and the current platform's loadable is
|
|
13
|
+
globbed from inside it.
|
|
14
|
+
"""
|
|
15
|
+
|
|
16
|
+
import os
|
|
17
|
+
|
|
18
|
+
from .is_bare_name import is_bare_name
|
|
19
|
+
from .resolve_package import _resolve_package
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
def resolve_extension_path(path, base, resolve_relative):
|
|
23
|
+
"""Resolve an extension ``path`` to a concrete file.
|
|
24
|
+
|
|
25
|
+
``base`` is the directory a relative path and the bare-name shadow probe
|
|
26
|
+
resolve against (a config file's parent dir, or the cwd for programmatic
|
|
27
|
+
entries). ``resolve_relative`` makes a relative path-looking value absolute
|
|
28
|
+
against ``base`` (config-file semantics); when false it is returned verbatim
|
|
29
|
+
(programmatic semantics).
|
|
30
|
+
"""
|
|
31
|
+
if not is_bare_name(path):
|
|
32
|
+
if resolve_relative and not os.path.isabs(path):
|
|
33
|
+
return os.path.join(base, path)
|
|
34
|
+
return path
|
|
35
|
+
local = os.path.join(base, path)
|
|
36
|
+
if os.path.isfile(local):
|
|
37
|
+
return local
|
|
38
|
+
return _resolve_package(path)
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
"""Location of an extension package's loadable file for this platform.
|
|
2
|
+
|
|
3
|
+
Zero matches and multiple matches are both hard errors -- the caller must
|
|
4
|
+
disambiguate with a literal path.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
import glob as _glob
|
|
8
|
+
import importlib.util
|
|
9
|
+
import os
|
|
10
|
+
|
|
11
|
+
from .platform_patterns import _platform_patterns
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
def _resolve_package(name):
|
|
15
|
+
"""Locate ``name``'s package dir and glob its platform loadable file."""
|
|
16
|
+
try:
|
|
17
|
+
spec = importlib.util.find_spec(name)
|
|
18
|
+
except (ImportError, ValueError) as exc:
|
|
19
|
+
raise ValueError(
|
|
20
|
+
f"could not resolve extension package {name!r}: {exc}"
|
|
21
|
+
) from exc
|
|
22
|
+
if spec is None:
|
|
23
|
+
raise ValueError(f"could not resolve extension package {name!r}: not installed")
|
|
24
|
+
|
|
25
|
+
dirs = list(spec.submodule_search_locations or [])
|
|
26
|
+
if not dirs and spec.origin and spec.origin not in ("built-in", "frozen"):
|
|
27
|
+
dirs.append(os.path.dirname(spec.origin))
|
|
28
|
+
if not dirs:
|
|
29
|
+
raise ValueError(
|
|
30
|
+
f"could not resolve extension package {name!r}: no package directory"
|
|
31
|
+
)
|
|
32
|
+
|
|
33
|
+
patterns = _platform_patterns()
|
|
34
|
+
matches = set()
|
|
35
|
+
for d in dirs:
|
|
36
|
+
for pat in patterns:
|
|
37
|
+
matches.update(_glob.glob(os.path.join(d, "**", pat), recursive=True))
|
|
38
|
+
found = sorted(matches)
|
|
39
|
+
|
|
40
|
+
try:
|
|
41
|
+
(single,) = found
|
|
42
|
+
except ValueError:
|
|
43
|
+
pat_desc = " / ".join(patterns)
|
|
44
|
+
if not found:
|
|
45
|
+
raise ValueError(
|
|
46
|
+
f"no loadable extension file ({pat_desc}) found in package "
|
|
47
|
+
f"{name!r} (searched {', '.join(dirs)})"
|
|
48
|
+
) from None
|
|
49
|
+
raise ValueError(
|
|
50
|
+
f"multiple loadable extension files found in package {name!r}: "
|
|
51
|
+
f"{', '.join(found)}; disambiguate with a literal path"
|
|
52
|
+
) from None
|
|
53
|
+
return single
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
"""The TOML parser this interpreter reads ``.dirsql.toml`` files with."""
|
|
2
|
+
|
|
3
|
+
import sys
|
|
4
|
+
from importlib import import_module
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
def _load_toml_module():
|
|
8
|
+
"""Return the TOML parser module for the running interpreter.
|
|
9
|
+
|
|
10
|
+
``tomllib`` is stdlib only on 3.11+; on 3.10 the ``tomli`` backport it was
|
|
11
|
+
derived from (a version-gated dependency) provides the same surface.
|
|
12
|
+
Imported by name so a unit test can exercise both arms on any
|
|
13
|
+
interpreter -- a literal ``import tomllib`` is unreachable on 3.10 no
|
|
14
|
+
matter what ``sys.version_info`` claims.
|
|
15
|
+
"""
|
|
16
|
+
if sys.version_info >= (3, 11):
|
|
17
|
+
return import_module("tomllib")
|
|
18
|
+
return import_module("tomli")
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
_toml = _load_toml_module()
|
|
@@ -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.37"
|
|
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
|
+
- **The config-extension loader split into four modules.** `_load_toml_module` (with the `_toml` binding it produces) moved to `dirsql/toml_module.py`, `_load_extension_entries` to `dirsql/load_extension_entries.py` and `_has_bare_name` to `dirsql/has_bare_name.py`; `dirsql/resolve_config_extensions.py` keeps the intervene-or-not decision, `resolve_config_extension_specs`. Every function keeps its name and behavior — internal reorganisation with no change to the published API or CLI behavior. (#1079)
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
**Changed**
|
|
2
|
+
|
|
3
|
+
- **The config-extension resolver split into three modules.** `_resolve_entries` moved to `dirsql/resolve_entries.py` and `resolve_configs_extension_specs` to `dirsql/resolve_configs_extension_specs.py`; `dirsql/resolve_config_extensions.py` keeps the TOML loading and the single-config `resolve_config_extension_specs`. Every function keeps its name and behavior — internal reorganisation with no change to the published API or CLI behavior. (#1056)
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
**Changed**
|
|
2
|
+
|
|
3
|
+
- **The extension-path resolver split into four modules.** `_platform_patterns` moved to `dirsql/platform_patterns.py`, `is_bare_name` (with `_LOADABLE_SUFFIXES`) to `dirsql/is_bare_name.py`, and `_resolve_package` to `dirsql/resolve_package.py`; `dirsql/resolve_extension.py` keeps the ordered probe, `resolve_extension_path`. Every function keeps its name and behavior — internal reorganisation with no change to the published API or CLI behavior. (#1066)
|
|
@@ -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.37"
|
|
10
10
|
edition.workspace = true
|
|
11
11
|
# Literal `license` (not `license.workspace = true`) because
|
|
12
12
|
# putitoutthere's preflight check reads `[package].license` directly
|
|
@@ -1,126 +0,0 @@
|
|
|
1
|
-
"""SDK-side resolution of a TOML config's ``[[dirsql.extension]]`` entries.
|
|
2
|
-
|
|
3
|
-
The Rust core loads a config's extensions literally -- it has no
|
|
4
|
-
``importlib``, so it cannot resolve a bare **package name**. When a TOML
|
|
5
|
-
config names an extension by package name, the SDK resolves every one of its
|
|
6
|
-
extensions here, hands the core the resolved literal paths, and suppresses
|
|
7
|
-
the core's own config-extension loading (``suppress_config_extensions``) so
|
|
8
|
-
the config's entries are not loaded a second time.
|
|
9
|
-
|
|
10
|
-
Shared by the ``DirSQL`` constructor (``config=`` path) and the CLI launcher
|
|
11
|
-
(which converts the resolved specs into ``--extension`` flags).
|
|
12
|
-
"""
|
|
13
|
-
|
|
14
|
-
from __future__ import annotations
|
|
15
|
-
|
|
16
|
-
import os
|
|
17
|
-
import sys
|
|
18
|
-
from importlib import import_module
|
|
19
|
-
|
|
20
|
-
from .resolve_extension import is_bare_name, resolve_extension_path
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
def _load_toml_module():
|
|
24
|
-
"""Return the TOML parser module for the running interpreter.
|
|
25
|
-
|
|
26
|
-
``tomllib`` is stdlib only on 3.11+; on 3.10 the ``tomli`` backport it was
|
|
27
|
-
derived from (a version-gated dependency) provides the same surface.
|
|
28
|
-
Imported by name so a unit test can exercise both arms on any
|
|
29
|
-
interpreter -- a literal ``import tomllib`` is unreachable on 3.10 no
|
|
30
|
-
matter what ``sys.version_info`` claims.
|
|
31
|
-
"""
|
|
32
|
-
if sys.version_info >= (3, 11):
|
|
33
|
-
return import_module("tomllib")
|
|
34
|
-
return import_module("tomli")
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
_toml = _load_toml_module()
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
def _load_extension_entries(config_path):
|
|
41
|
-
"""Return ``(entries, base_dir)`` for a config's ``[[dirsql.extension]]``.
|
|
42
|
-
|
|
43
|
-
``None`` when the config is missing, unreadable/malformed, or declares no
|
|
44
|
-
extension array -- the caller should leave such configs to the core.
|
|
45
|
-
"""
|
|
46
|
-
if not os.path.isfile(config_path):
|
|
47
|
-
return None
|
|
48
|
-
try:
|
|
49
|
-
with open(config_path, "rb") as f:
|
|
50
|
-
doc = _toml.load(f)
|
|
51
|
-
except (OSError, _toml.TOMLDecodeError):
|
|
52
|
-
# Leave a malformed / unreadable config for the core to report.
|
|
53
|
-
return None
|
|
54
|
-
|
|
55
|
-
entries = (doc.get("dirsql") or {}).get("extension")
|
|
56
|
-
if not isinstance(entries, list):
|
|
57
|
-
return None
|
|
58
|
-
return entries, os.path.dirname(os.path.abspath(config_path))
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
def _has_bare_name(entries):
|
|
62
|
-
return any(
|
|
63
|
-
isinstance(e, dict)
|
|
64
|
-
and isinstance(e.get("path"), str)
|
|
65
|
-
and is_bare_name(e["path"])
|
|
66
|
-
for e in entries
|
|
67
|
-
)
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
def _resolve_entries(entries, base):
|
|
71
|
-
specs = []
|
|
72
|
-
for e in entries:
|
|
73
|
-
entrypoint = e.get("entrypoint")
|
|
74
|
-
specs.append(
|
|
75
|
-
{
|
|
76
|
-
"path": resolve_extension_path(
|
|
77
|
-
e["path"], base=base, resolve_relative=True
|
|
78
|
-
),
|
|
79
|
-
"entrypoint": entrypoint if isinstance(entrypoint, str) else None,
|
|
80
|
-
}
|
|
81
|
-
)
|
|
82
|
-
return specs
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
def resolve_config_extension_specs(config_path):
|
|
86
|
-
"""Resolve a TOML config's ``[[dirsql.extension]]`` entries to literal paths.
|
|
87
|
-
|
|
88
|
-
Returns a list of ``{"path", "entrypoint"}`` dicts -- every entry resolved
|
|
89
|
-
via :func:`resolve_extension_path` against the config file's parent
|
|
90
|
-
directory -- when at least one entry's ``path`` is a bare package name.
|
|
91
|
-
Returns ``None`` when the caller should not intervene: the config is
|
|
92
|
-
missing, malformed, declares no extensions, or uses only literal paths --
|
|
93
|
-
leaving the core's own loading (and error reporting) untouched. Raises if
|
|
94
|
-
a package name cannot be resolved.
|
|
95
|
-
"""
|
|
96
|
-
loaded = _load_extension_entries(config_path)
|
|
97
|
-
if loaded is None:
|
|
98
|
-
return None
|
|
99
|
-
entries, base = loaded
|
|
100
|
-
if not _has_bare_name(entries):
|
|
101
|
-
return None
|
|
102
|
-
return _resolve_entries(entries, base)
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
def resolve_configs_extension_specs(config_paths):
|
|
106
|
-
"""Resolve the ``[[dirsql.extension]]`` entries of several configs, in order.
|
|
107
|
-
|
|
108
|
-
The SDK intervenes for the whole set only when **some** config names an
|
|
109
|
-
extension by bare package name (the core can resolve neither package names
|
|
110
|
-
nor -- once globally suppressed -- the literal entries of the other
|
|
111
|
-
configs). When it intervenes it resolves **every** config's entries, each
|
|
112
|
-
against that config's own parent directory, concatenated in ``config_paths``
|
|
113
|
-
order; the caller suppresses the core's config-extension loading and passes
|
|
114
|
-
the resolved list. Returns ``None`` when no config uses a package name,
|
|
115
|
-
leaving every config's loading to the core.
|
|
116
|
-
"""
|
|
117
|
-
loaded = [_load_extension_entries(p) for p in config_paths]
|
|
118
|
-
if not any(item is not None and _has_bare_name(item[0]) for item in loaded):
|
|
119
|
-
return None
|
|
120
|
-
specs = []
|
|
121
|
-
for item in loaded:
|
|
122
|
-
if item is None:
|
|
123
|
-
continue
|
|
124
|
-
entries, base = item
|
|
125
|
-
specs.extend(_resolve_entries(entries, base))
|
|
126
|
-
return specs
|
|
@@ -1,101 +0,0 @@
|
|
|
1
|
-
"""Resolve an extension entry's ``path`` to a concrete loadable file.
|
|
2
|
-
|
|
3
|
-
Resolution is an ordered probe (file-first, then package), so only a bare
|
|
4
|
-
package name reaches the package machinery:
|
|
5
|
-
|
|
6
|
-
1. **Path-looking** (contains a separator, or ends in ``.so`` / ``.dylib`` /
|
|
7
|
-
``.dll`` / ``.pyd``) -- returned as a file path: made absolute against
|
|
8
|
-
``base`` when ``resolve_relative`` is set (config-file entries), else
|
|
9
|
-
verbatim (programmatic entries).
|
|
10
|
-
2. **Bare name** -- a same-named local file under ``base`` *shadows* the
|
|
11
|
-
package; otherwise the package dir is located via
|
|
12
|
-
:func:`importlib.util.find_spec` and the current platform's loadable is
|
|
13
|
-
globbed from inside it. Zero matches and multiple matches are both hard
|
|
14
|
-
errors -- the caller must disambiguate with a literal path.
|
|
15
|
-
"""
|
|
16
|
-
|
|
17
|
-
import glob as _glob
|
|
18
|
-
import importlib.util
|
|
19
|
-
import os
|
|
20
|
-
import sys
|
|
21
|
-
|
|
22
|
-
# Suffixes that mark a value as "already a file path", so package resolution
|
|
23
|
-
# is never attempted.
|
|
24
|
-
_LOADABLE_SUFFIXES = (".so", ".dylib", ".dll", ".pyd")
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
def _platform_patterns():
|
|
28
|
-
"""Loadable-file glob(s) for the current platform."""
|
|
29
|
-
if sys.platform == "darwin":
|
|
30
|
-
return ("*.dylib",)
|
|
31
|
-
if sys.platform == "win32":
|
|
32
|
-
return ("*.dll", "*.pyd")
|
|
33
|
-
return ("*.so",)
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
def is_bare_name(path):
|
|
37
|
-
"""True when ``path`` is a bare package name rather than a file path."""
|
|
38
|
-
if os.sep in path or (os.altsep and os.altsep in path):
|
|
39
|
-
return False
|
|
40
|
-
return not path.endswith(_LOADABLE_SUFFIXES)
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
def _resolve_package(name):
|
|
44
|
-
"""Locate ``name``'s package dir and glob its platform loadable file."""
|
|
45
|
-
try:
|
|
46
|
-
spec = importlib.util.find_spec(name)
|
|
47
|
-
except (ImportError, ValueError) as exc:
|
|
48
|
-
raise ValueError(
|
|
49
|
-
f"could not resolve extension package {name!r}: {exc}"
|
|
50
|
-
) from exc
|
|
51
|
-
if spec is None:
|
|
52
|
-
raise ValueError(f"could not resolve extension package {name!r}: not installed")
|
|
53
|
-
|
|
54
|
-
dirs = list(spec.submodule_search_locations or [])
|
|
55
|
-
if not dirs and spec.origin and spec.origin not in ("built-in", "frozen"):
|
|
56
|
-
dirs.append(os.path.dirname(spec.origin))
|
|
57
|
-
if not dirs:
|
|
58
|
-
raise ValueError(
|
|
59
|
-
f"could not resolve extension package {name!r}: no package directory"
|
|
60
|
-
)
|
|
61
|
-
|
|
62
|
-
patterns = _platform_patterns()
|
|
63
|
-
matches = set()
|
|
64
|
-
for d in dirs:
|
|
65
|
-
for pat in patterns:
|
|
66
|
-
matches.update(_glob.glob(os.path.join(d, "**", pat), recursive=True))
|
|
67
|
-
found = sorted(matches)
|
|
68
|
-
|
|
69
|
-
try:
|
|
70
|
-
(single,) = found
|
|
71
|
-
except ValueError:
|
|
72
|
-
pat_desc = " / ".join(patterns)
|
|
73
|
-
if not found:
|
|
74
|
-
raise ValueError(
|
|
75
|
-
f"no loadable extension file ({pat_desc}) found in package "
|
|
76
|
-
f"{name!r} (searched {', '.join(dirs)})"
|
|
77
|
-
) from None
|
|
78
|
-
raise ValueError(
|
|
79
|
-
f"multiple loadable extension files found in package {name!r}: "
|
|
80
|
-
f"{', '.join(found)}; disambiguate with a literal path"
|
|
81
|
-
) from None
|
|
82
|
-
return single
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
def resolve_extension_path(path, base, resolve_relative):
|
|
86
|
-
"""Resolve an extension ``path`` to a concrete file.
|
|
87
|
-
|
|
88
|
-
``base`` is the directory a relative path and the bare-name shadow probe
|
|
89
|
-
resolve against (a config file's parent dir, or the cwd for programmatic
|
|
90
|
-
entries). ``resolve_relative`` makes a relative path-looking value absolute
|
|
91
|
-
against ``base`` (config-file semantics); when false it is returned verbatim
|
|
92
|
-
(programmatic semantics).
|
|
93
|
-
"""
|
|
94
|
-
if not is_bare_name(path):
|
|
95
|
-
if resolve_relative and not os.path.isabs(path):
|
|
96
|
-
return os.path.join(base, path)
|
|
97
|
-
return path
|
|
98
|
-
local = os.path.join(base, path)
|
|
99
|
-
if os.path.isfile(local):
|
|
100
|
-
return local
|
|
101
|
-
return _resolve_package(path)
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|