vgi-python 0.41.0__tar.gz → 0.42.0__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.
- {vgi_python-0.41.0 → vgi_python-0.42.0}/CLAUDE.md +19 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/PKG-INFO +2 -2
- {vgi_python-0.41.0 → vgi_python-0.42.0}/docs/api/index.md +1 -1
- vgi_python-0.42.0/docs/api/transactor.md +32 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/docs/authentication.md +43 -1
- {vgi_python-0.41.0 → vgi_python-0.42.0}/docs/catalog-interface.md +28 -3
- {vgi_python-0.41.0 → vgi_python-0.42.0}/docs/cli.md +1 -1
- {vgi_python-0.41.0 → vgi_python-0.42.0}/docs/how-to/function-patterns.md +9 -6
- {vgi_python-0.41.0 → vgi_python-0.42.0}/docs/how-to/state-storage.md +5 -3
- {vgi_python-0.41.0 → vgi_python-0.42.0}/docs/shared-storage.md +2 -2
- {vgi_python-0.41.0 → vgi_python-0.42.0}/pyproject.toml +2 -2
- vgi_python-0.42.0/tests/test_grant_auth.py +290 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/uv.lock +5 -5
- {vgi_python-0.41.0 → vgi_python-0.42.0}/vgi/_duckdb.py +3 -3
- {vgi_python-0.41.0 → vgi_python-0.42.0}/vgi/_test_fixtures/http_server.py +2 -1
- {vgi_python-0.41.0 → vgi_python-0.42.0}/vgi/_test_fixtures/identity_fixture.py +7 -1
- {vgi_python-0.41.0 → vgi_python-0.42.0}/vgi/rpc_server.py +56 -3
- {vgi_python-0.41.0 → vgi_python-0.42.0}/vgi/serve.py +73 -2
- vgi_python-0.41.0/docs/api/transactor.md +0 -12
- {vgi_python-0.41.0 → vgi_python-0.42.0}/.dockerignore +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/.gitattributes +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/.github/dependabot.yml +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/.github/styles/config/vocabularies/VGI/accept.txt +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/.github/workflows/ci.yml +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/.github/workflows/docs.yml +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/.github/workflows/integration.yml +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/.github/workflows/release.yml +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/.github/workflows/tailnet-integration.yml +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/.gitignore +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/.python-version +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/.vale.ini +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/DOCS_ACCEPTANCE_CRITERIA.md +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/DOCS_REVIEW_RUBRIC.md +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/DOCS_USABILITY_TEST.md +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/LICENSE +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/PROTOCOL.md +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/README.md +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/RELEASE-RUNBOOK.md +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/SECURITY.md +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/ci/README.md +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/ci/preprocess-require.awk +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/ci/run-integration.sh +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/conformance/filter-v2/README.md +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/conformance/filter-v2/cases/negative/and-too-few-children.json +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/conformance/filter-v2/cases/negative/delta-required-upsert.json +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/conformance/filter-v2/cases/negative/nested-runtime-filter.json +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/conformance/filter-v2/cases/negative/remove-with-expression.json +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/conformance/filter-v2/cases/negative/required-runtime-filter.json +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/conformance/filter-v2/cases/negative/snapshot-nonzero-revision.json +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/conformance/filter-v2/cases/negative/unknown-document-property.json +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/conformance/filter-v2/cases/negative/unknown-node.json +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/conformance/filter-v2/cases/positive/advisory-upsert-delta.json +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/conformance/filter-v2/cases/positive/boolean-column-predicate.json +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/conformance/filter-v2/cases/positive/empty-snapshot.json +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/conformance/filter-v2/cases/positive/nested-required-snapshot.json +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/conformance/filter-v2/cases/positive/remove-delta.json +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/conformance/filter-v2/cases/positive/runtime-filter-snapshot.json +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/conformance/filter-v2/filter-v2.schema.json +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/conformance/filter-v2/generate_runtime.py +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/conformance/filter-v2/manifest.json +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/conformance/filter-v2/run_worker.py +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/conformance/filter-v2/runtime/arithmetic-add/expected.arrow +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/conformance/filter-v2/runtime/arithmetic-add/filter.arrow +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/conformance/filter-v2/runtime/arithmetic-add/input.arrow +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/conformance/filter-v2/runtime/arithmetic-multiply/expected.arrow +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/conformance/filter-v2/runtime/arithmetic-multiply/filter.arrow +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/conformance/filter-v2/runtime/arithmetic-multiply/input.arrow +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/conformance/filter-v2/runtime/arithmetic-negate/expected.arrow +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/conformance/filter-v2/runtime/arithmetic-negate/filter.arrow +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/conformance/filter-v2/runtime/arithmetic-negate/input.arrow +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/conformance/filter-v2/runtime/arithmetic-subtract/expected.arrow +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/conformance/filter-v2/runtime/arithmetic-subtract/filter.arrow +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/conformance/filter-v2/runtime/arithmetic-subtract/input.arrow +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/conformance/filter-v2/runtime/cast-integer-to-double/expected.arrow +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/conformance/filter-v2/runtime/cast-integer-to-double/filter.arrow +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/conformance/filter-v2/runtime/cast-integer-to-double/input.arrow +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/conformance/filter-v2/runtime/comparison-distinct_from/expected.arrow +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/conformance/filter-v2/runtime/comparison-distinct_from/filter.arrow +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/conformance/filter-v2/runtime/comparison-distinct_from/input.arrow +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/conformance/filter-v2/runtime/comparison-distinct_from/worker-expected.arrow +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/conformance/filter-v2/runtime/comparison-eq/expected.arrow +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/conformance/filter-v2/runtime/comparison-eq/filter.arrow +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/conformance/filter-v2/runtime/comparison-eq/input.arrow +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/conformance/filter-v2/runtime/comparison-eq/worker-expected.arrow +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/conformance/filter-v2/runtime/comparison-ge/expected.arrow +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/conformance/filter-v2/runtime/comparison-ge/filter.arrow +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/conformance/filter-v2/runtime/comparison-ge/input.arrow +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/conformance/filter-v2/runtime/comparison-ge/worker-expected.arrow +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/conformance/filter-v2/runtime/comparison-gt/expected.arrow +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/conformance/filter-v2/runtime/comparison-gt/filter.arrow +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/conformance/filter-v2/runtime/comparison-gt/input.arrow +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/conformance/filter-v2/runtime/comparison-gt/worker-expected.arrow +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/conformance/filter-v2/runtime/comparison-le/expected.arrow +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/conformance/filter-v2/runtime/comparison-le/filter.arrow +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/conformance/filter-v2/runtime/comparison-le/input.arrow +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/conformance/filter-v2/runtime/comparison-le/worker-expected.arrow +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/conformance/filter-v2/runtime/comparison-lt/expected.arrow +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/conformance/filter-v2/runtime/comparison-lt/filter.arrow +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/conformance/filter-v2/runtime/comparison-lt/input.arrow +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/conformance/filter-v2/runtime/comparison-lt/worker-expected.arrow +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/conformance/filter-v2/runtime/comparison-ne/expected.arrow +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/conformance/filter-v2/runtime/comparison-ne/filter.arrow +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/conformance/filter-v2/runtime/comparison-ne/input.arrow +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/conformance/filter-v2/runtime/comparison-ne/worker-expected.arrow +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/conformance/filter-v2/runtime/comparison-not_distinct_from/expected.arrow +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/conformance/filter-v2/runtime/comparison-not_distinct_from/filter.arrow +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/conformance/filter-v2/runtime/comparison-not_distinct_from/input.arrow +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/conformance/filter-v2/runtime/comparison-not_distinct_from/worker-expected.arrow +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/conformance/filter-v2/runtime/delta-atomic-multi-update/delta-0.arrow +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/conformance/filter-v2/runtime/delta-atomic-multi-update/expected.arrow +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/conformance/filter-v2/runtime/delta-atomic-multi-update/filter.arrow +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/conformance/filter-v2/runtime/delta-atomic-multi-update/input.arrow +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/conformance/filter-v2/runtime/delta-empty-noop/delta-0.arrow +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/conformance/filter-v2/runtime/delta-empty-noop/expected.arrow +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/conformance/filter-v2/runtime/delta-empty-noop/filter.arrow +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/conformance/filter-v2/runtime/delta-empty-noop/input.arrow +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/conformance/filter-v2/runtime/delta-upsert-remove-stale/delta-0.arrow +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/conformance/filter-v2/runtime/delta-upsert-remove-stale/delta-1.arrow +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/conformance/filter-v2/runtime/delta-upsert-remove-stale/delta-2.arrow +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/conformance/filter-v2/runtime/delta-upsert-remove-stale/expected.arrow +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/conformance/filter-v2/runtime/delta-upsert-remove-stale/filter.arrow +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/conformance/filter-v2/runtime/delta-upsert-remove-stale/input.arrow +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/conformance/filter-v2/runtime/empty-snapshot/expected.arrow +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/conformance/filter-v2/runtime/empty-snapshot/filter.arrow +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/conformance/filter-v2/runtime/empty-snapshot/input.arrow +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/conformance/filter-v2/runtime/empty-snapshot/worker-expected.arrow +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/conformance/filter-v2/runtime/error-cast-type-not-null/filter.arrow +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/conformance/filter-v2/runtime/error-cast-type-not-null/input.arrow +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/conformance/filter-v2/runtime/error-column-index/filter.arrow +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/conformance/filter-v2/runtime/error-column-index/input.arrow +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/conformance/filter-v2/runtime/error-column-name/filter.arrow +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/conformance/filter-v2/runtime/error-column-name/input.arrow +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/conformance/filter-v2/runtime/error-contextual-cast-without-session/filter.arrow +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/conformance/filter-v2/runtime/error-contextual-cast-without-session/input.arrow +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/conformance/filter-v2/runtime/error-duplicate-predicate-id/filter.arrow +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/conformance/filter-v2/runtime/error-duplicate-predicate-id/input.arrow +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/conformance/filter-v2/runtime/error-external-column-index/filter.arrow +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/conformance/filter-v2/runtime/error-external-column-index/input.arrow +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/conformance/filter-v2/runtime/error-external-column-index/join-keys-0.arrow +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/conformance/filter-v2/runtime/error-external-column-name/filter.arrow +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/conformance/filter-v2/runtime/error-external-column-name/input.arrow +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/conformance/filter-v2/runtime/error-external-column-name/join-keys-0.arrow +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/conformance/filter-v2/runtime/error-field-non-struct/filter.arrow +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/conformance/filter-v2/runtime/error-field-non-struct/input.arrow +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/conformance/filter-v2/runtime/error-in-payload-not-list/filter.arrow +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/conformance/filter-v2/runtime/error-in-payload-not-list/input.arrow +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/conformance/filter-v2/runtime/error-in-payload-null-list/filter.arrow +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/conformance/filter-v2/runtime/error-in-payload-null-list/input.arrow +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/conformance/filter-v2/runtime/error-invalid-overload/filter.arrow +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/conformance/filter-v2/runtime/error-invalid-overload/input.arrow +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/conformance/filter-v2/runtime/error-missing-literal/filter.arrow +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/conformance/filter-v2/runtime/error-missing-literal/input.arrow +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/conformance/filter-v2/runtime/error-non-boolean-root/filter.arrow +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/conformance/filter-v2/runtime/error-non-boolean-root/input.arrow +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/conformance/filter-v2/runtime/error-unknown-standard-function/filter.arrow +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/conformance/filter-v2/runtime/error-unknown-standard-function/input.arrow +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/conformance/filter-v2/runtime/external-in-nonzero-column/expected.arrow +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/conformance/filter-v2/runtime/external-in-nonzero-column/filter.arrow +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/conformance/filter-v2/runtime/external-in-nonzero-column/input.arrow +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/conformance/filter-v2/runtime/external-in-nonzero-column/join-keys-0.arrow +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/conformance/filter-v2/runtime/external-in-nonzero-column/worker-expected.arrow +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/conformance/filter-v2/runtime/function-contains/expected.arrow +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/conformance/filter-v2/runtime/function-contains/filter.arrow +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/conformance/filter-v2/runtime/function-contains/input.arrow +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/conformance/filter-v2/runtime/function-ends-with/expected.arrow +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/conformance/filter-v2/runtime/function-ends-with/filter.arrow +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/conformance/filter-v2/runtime/function-ends-with/input.arrow +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/conformance/filter-v2/runtime/function-list-contains/expected.arrow +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/conformance/filter-v2/runtime/function-list-contains/filter.arrow +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/conformance/filter-v2/runtime/function-list-contains/input.arrow +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/conformance/filter-v2/runtime/function-starts-with/expected.arrow +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/conformance/filter-v2/runtime/function-starts-with/filter.arrow +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/conformance/filter-v2/runtime/function-starts-with/input.arrow +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/conformance/filter-v2/runtime/in-empty/expected.arrow +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/conformance/filter-v2/runtime/in-empty/filter.arrow +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/conformance/filter-v2/runtime/in-empty/input.arrow +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/conformance/filter-v2/runtime/in-empty/worker-expected.arrow +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/conformance/filter-v2/runtime/in-with-null/expected.arrow +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/conformance/filter-v2/runtime/in-with-null/filter.arrow +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/conformance/filter-v2/runtime/in-with-null/input.arrow +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/conformance/filter-v2/runtime/in-with-null/worker-expected.arrow +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/conformance/filter-v2/runtime/is-not-null/expected.arrow +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/conformance/filter-v2/runtime/is-not-null/filter.arrow +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/conformance/filter-v2/runtime/is-not-null/input.arrow +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/conformance/filter-v2/runtime/is-not-null/worker-expected.arrow +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/conformance/filter-v2/runtime/is-null/expected.arrow +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/conformance/filter-v2/runtime/is-null/filter.arrow +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/conformance/filter-v2/runtime/is-null/input.arrow +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/conformance/filter-v2/runtime/is-null/worker-expected.arrow +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/conformance/filter-v2/runtime/kleene-and/expected.arrow +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/conformance/filter-v2/runtime/kleene-and/filter.arrow +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/conformance/filter-v2/runtime/kleene-and/input.arrow +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/conformance/filter-v2/runtime/kleene-not/expected.arrow +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/conformance/filter-v2/runtime/kleene-not/filter.arrow +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/conformance/filter-v2/runtime/kleene-not/input.arrow +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/conformance/filter-v2/runtime/kleene-or/expected.arrow +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/conformance/filter-v2/runtime/kleene-or/filter.arrow +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/conformance/filter-v2/runtime/kleene-or/input.arrow +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/conformance/filter-v2/runtime/nan-comparison/expected.arrow +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/conformance/filter-v2/runtime/nan-comparison/filter.arrow +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/conformance/filter-v2/runtime/nan-comparison/input.arrow +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/conformance/filter-v2/runtime/negative-zero-membership/expected.arrow +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/conformance/filter-v2/runtime/negative-zero-membership/filter.arrow +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/conformance/filter-v2/runtime/negative-zero-membership/input.arrow +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/conformance/filter-v2/runtime/nested-null-propagation/expected.arrow +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/conformance/filter-v2/runtime/nested-null-propagation/filter.arrow +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/conformance/filter-v2/runtime/nested-null-propagation/input.arrow +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/conformance/filter-v2/runtime/not-in-empty/expected.arrow +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/conformance/filter-v2/runtime/not-in-empty/filter.arrow +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/conformance/filter-v2/runtime/not-in-empty/input.arrow +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/conformance/filter-v2/runtime/not-in-empty/worker-expected.arrow +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/conformance/filter-v2/runtime/not-in-with-null/expected.arrow +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/conformance/filter-v2/runtime/not-in-with-null/filter.arrow +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/conformance/filter-v2/runtime/not-in-with-null/input.arrow +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/conformance/filter-v2/runtime/not-in-with-null/worker-expected.arrow +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/conformance/filter-v2/runtime/session-integer-division/expected.arrow +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/conformance/filter-v2/runtime/session-integer-division/filter.arrow +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/conformance/filter-v2/runtime/session-integer-division/input.arrow +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/conformance/filter-v2/runtime-manifest.json +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/dist-vgi/.gitignore +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/docs/aggregate-functions.md +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/docs/api/arguments.md +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/docs/api/auth.md +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/docs/api/catalogs.md +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/docs/api/client.md +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/docs/api/exceptions.md +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/docs/api/filters.md +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/docs/api/functions.md +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/docs/api/http.md +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/docs/api/metadata.md +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/docs/api/observability.md +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/docs/api/storage.md +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/docs/api/worker.md +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/docs/argument-serialization.md +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/docs/assets/apple-touch-icon.png +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/docs/assets/favicon-16x16.png +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/docs/assets/favicon-32x32.png +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/docs/assets/favicon.ico +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/docs/assets/kinds/aggregate.svg +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/docs/assets/kinds/buffering.svg +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/docs/assets/kinds/scalar.svg +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/docs/assets/kinds/table-in-out.svg +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/docs/assets/kinds/table.svg +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/docs/assets/logo.png +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/docs/assets/social-card.png +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/docs/assets/video-thumbnail.jpg +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/docs/column-statistics.md +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/docs/concepts/index.md +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/docs/contributing-docs.md +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/docs/filter-pushdown.md +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/docs/generator-api.md +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/docs/global-functions.md +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/docs/how-to/catalogs.md +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/docs/how-to/http-auth.md +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/docs/how-to/index.md +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/docs/how-to/iroh.md +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/docs/how-to/pushdown-and-statistics.md +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/docs/how-to/tailnet.md +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/docs/index.md +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/docs/lifecycle.md +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/docs/metadata.md +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/docs/overrides/main.html +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/docs/protocol/index.md +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/docs/protocol/vgi-catalog-query-pushdown-design.md +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/docs/protocol/vgi-duckdb-filter-adapter.md +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/docs/protocol/vgi-filter-encoding-v2-spec.md +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/docs/protocol/vgi-protocol-proposed-changes.md +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/docs/protocol/vgi-runtime-filter-artifacts.md +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/docs/robots.txt +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/docs/stylesheets/extra.css +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/docs/tutorial/index.md +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/docs/tutorial/scalar.md +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/docs/tutorial/table.md +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/docs/vgi-logo.png +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/examples/batch_index_worker.py +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/examples/cache_worker.py +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/examples/calc_scalar_worker.py +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/examples/calc_worker.py +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/examples/copy_format_worker.py +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/examples/filter_worker.py +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/examples/greeting_scalar_worker.py +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/examples/row_count_worker.py +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/examples/series_streaming_worker.py +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/examples/sum_worker.py +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/identity.png +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/mkdocs.yml +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/packages/vgi-fixtures/LICENSE +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/packages/vgi-fixtures/README.md +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/packages/vgi-fixtures/docker/Dockerfile +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/packages/vgi-fixtures/docker/docker-entrypoint.sh +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/packages/vgi-fixtures/pyproject.toml +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/scripts/hosted_protocols_conformance.sh +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/scripts/measure_startup.py +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/scripts/regen_generated.py +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/scripts/run_all_tests.sh +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/test-data/generate.sh +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/tests/__init__.py +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/tests/_hosted_protocols_worker.py +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/tests/_http_fixtures.py +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/tests/catalog/__init__.py +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/tests/catalog/test_attach_option.py +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/tests/catalog/test_catalog_contents.py +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/tests/catalog/test_catalog_interface.py +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/tests/catalog/test_client_catalog.py +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/tests/catalog/test_client_load_catalog.py +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/tests/catalog/test_column_statistics.py +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/tests/catalog/test_declarative.py +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/tests/catalog/test_example_worker_catalog.py +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/tests/catalog/test_integration.py +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/tests/catalog/test_required_filters.py +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/tests/catalog/test_scan_branches.py +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/tests/catalog/test_serialization.py +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/tests/catalog/test_setting.py +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/tests/catalog/test_storage.py +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/tests/catalog/test_time_travel.py +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/tests/catalog/test_writable_table.py +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/tests/client/__init__.py +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/tests/client/test_aggregate_client.py +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/tests/client/test_batch_metadata_callback.py +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/tests/client/test_bind_and_join_keys.py +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/tests/client/test_broken_pipe.py +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/tests/client/test_cli.py +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/tests/client/test_cli_catalog_functions.py +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/tests/client/test_copy_client.py +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/tests/client/test_http_response_budget.py +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/tests/client/test_iroh_client.py +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/tests/client/test_scan_branches_client.py +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/tests/client/test_split_client.py +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/tests/client/test_stop_force.py +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/tests/client/test_table_column_statistics.py +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/tests/client/test_time_travel_client.py +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/tests/client/test_worker_debug.py +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/tests/conformance/__init__.py +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/tests/conformance/_stub.py +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/tests/conformance/conftest.py +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/tests/conformance/test_accumulate.py +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/tests/conformance/test_aggregate.py +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/tests/conformance/test_attach.py +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/tests/conformance/test_bearer_auth.py +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/tests/conformance/test_const_param_enforcement.py +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/tests/conformance/test_container.py +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/tests/conformance/test_copy_from.py +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/tests/conformance/test_copy_to.py +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/tests/conformance/test_directory_parity.py +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/tests/conformance/test_function_inventory.py +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/tests/conformance/test_github.py +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/tests/conformance/test_http_client.py +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/tests/conformance/test_http_external_location.py +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/tests/conformance/test_http_upload_url.py +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/tests/conformance/test_macro.py +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/tests/conformance/test_overload.py +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/tests/conformance/test_protocol_inventory.py +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/tests/conformance/test_protocol_version.py +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/tests/conformance/test_resumable_scan.py +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/tests/conformance/test_scalar.py +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/tests/conformance/test_scalar_attach_opaque_data.py +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/tests/conformance/test_secret.py +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/tests/conformance/test_settings.py +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/tests/conformance/test_splits.py +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/tests/conformance/test_table.py +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/tests/conformance/test_table_in_out.py +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/tests/conformance/test_view.py +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/tests/conformance/test_writable.py +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/tests/conftest.py +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/tests/data/split_tokens/anchor_len_overrun.bin +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/tests/data/split_tokens/bad_fingerprint.bin +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/tests/data/split_tokens/bad_flags_unsealed_but_key_present.bin +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/tests/data/split_tokens/bad_version.bin +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/tests/data/split_tokens/generate.py +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/tests/data/split_tokens/manifest.json +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/tests/data/split_tokens/reserved_flag_bit.bin +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/tests/data/split_tokens/stale_anchor.bin +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/tests/data/split_tokens/truncated.bin +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/tests/data/split_tokens/valid_sealed.bin +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/tests/data/split_tokens/valid_unsealed.bin +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/tests/scalar/__init__.py +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/tests/scalar/test_bernoulli_function.py +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/tests/scalar/test_binary_packet_function.py +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/tests/scalar/test_client.py +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/tests/scalar/test_conditional_message_function.py +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/tests/scalar/test_hash_seed_function.py +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/tests/scalar/test_multiply_by_setting_function.py +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/tests/scalar/test_multiply_function.py +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/tests/scalar/test_random_bytes_function.py +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/tests/scalar/test_return_secret_value_function.py +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/tests/table/__init__.py +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/tests/table/generator/__init__.py +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/tests/table/generator/test_constant_columns_function.py +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/tests/table/generator/test_double_sequence_function.py +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/tests/table/generator/test_exception_function.py +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/tests/table/generator/test_filter_echo_function.py +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/tests/table/generator/test_logging_function.py +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/tests/table/generator/test_nested_sequence_function.py +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/tests/table/generator/test_partitioned_function.py +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/tests/table/generator/test_projected_data_function.py +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/tests/table/generator/test_sequence_function.py +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/tests/table/generator/test_settings_function.py +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/tests/table/generator/test_struct_settings_function.py +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/tests/table/generator/test_ten_thousand_function.py +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/tests/table/test_wide_columns.py +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/tests/table_in_out/__init__.py +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/tests/table_in_out/generator/__init__.py +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/tests/table_in_out/generator/test_buffer_input_function.py +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/tests/table_in_out/generator/test_echo_function.py +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/tests/table_in_out/generator/test_exception_functions.py +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/tests/table_in_out/generator/test_filter_by_setting_function.py +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/tests/table_in_out/generator/test_repeat_inputs_function.py +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/tests/table_in_out/generator/test_substream_partial_sum_function.py +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/tests/table_in_out/generator/test_sum_all_columns_function.py +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/tests/table_in_out/test_blended_exchange.py +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/tests/table_in_out/test_blended_metadata.py +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/tests/table_in_out/test_client.py +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/tests/table_in_out/test_table_buffering_empty_input.py +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/tests/tailnet/Dockerfile +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/tests/tailnet/__init__.py +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/tests/tailnet/compose.yaml +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/tests/tailnet/probe.py +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/tests/tailnet/run.sh +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/tests/tailnet/test_worker.py +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/tests/tailnet/worker.py +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/tests/test_access_log_audit.py +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/tests/test_aggregate_function.py +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/tests/test_argument_spec.py +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/tests/test_auth.py +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/tests/test_bind_exceptions.py +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/tests/test_bind_request_at_clause.py +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/tests/test_bound_storage_conformance.py +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/tests/test_cache_control.py +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/tests/test_call_state_attach.py +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/tests/test_catalog_auth_binding.py +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/tests/test_client_oauth.py +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/tests/test_codegen_request_inventory.py +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/tests/test_copy_from_function.py +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/tests/test_copy_to_function.py +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/tests/test_docstrings.py +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/tests/test_documentation_examples.py +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/tests/test_dynamic_filter_http_turns.py +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/tests/test_example_function_arg_types.py +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/tests/test_examples_workers.py +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/tests/test_exception_handling.py +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/tests/test_exceptions.py +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/tests/test_filter_pushdown.py +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/tests/test_filter_pushdown_extension.py +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/tests/test_filter_v2.py +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/tests/test_filter_v2_builder.py +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/tests/test_filter_v2_runtime_corpus.py +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/tests/test_filter_v2_spec_schema.py +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/tests/test_fixture_catalog_parity.py +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/tests/test_function_shape_mismatch.py +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/tests/test_function_storage.py +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/tests/test_function_storage_azure_sql.py +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/tests/test_function_storage_cf_do.py +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/tests/test_function_storage_cf_do_integration.py +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/tests/test_function_storage_conformance.py +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/tests/test_generated_cpp_constants.py +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/tests/test_generated_cpp_protocol_name.py +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/tests/test_generated_cpp_protocol_version.py +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/tests/test_generated_cpp_request_builders.py +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/tests/test_generated_cpp_schemas.py +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/tests/test_generated_cpp_secret.py +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/tests/test_generated_csharp.py +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/tests/test_generated_go_schemas.py +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/tests/test_generated_go_types.py +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/tests/test_generated_java_schemas.py +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/tests/test_generated_java_types.py +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/tests/test_generated_protocol_version.py +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/tests/test_generated_rust_request_builders.py +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/tests/test_generated_rust_schemas.py +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/tests/test_generated_rust_types.py +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/tests/test_generated_schemas_cross_lang.py +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/tests/test_generated_ts_client.py +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/tests/test_generated_ts_schemas.py +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/tests/test_generated_ts_types.py +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/tests/test_hosted_protocols.py +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/tests/test_http_demo_storage.py +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/tests/test_http_s3_offload_input.py +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/tests/test_http_s3_offload_output.py +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/tests/test_import_side_effects.py +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/tests/test_landing_discovery.py +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/tests/test_launch_transport.py +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/tests/test_metadata.py +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/tests/test_mypy_consolidated.py +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/tests/test_nest_tensor.py +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/tests/test_otel.py +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/tests/test_projection_enforcement.py +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/tests/test_projection_repro.py +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/tests/test_protocol_classes.py +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/tests/test_resolved_secrets.py +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/tests/test_schema_paths_v2.py +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/tests/test_schema_scoped_functions.py +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/tests/test_schema_utils.py +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/tests/test_serve.py +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/tests/test_setting_secret_annotations.py +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/tests/test_signing_key.py +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/tests/test_split_token.py +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/tests/test_subprocess_transport.py +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/tests/test_table_buffering_function.py +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/tests/test_table_function_dynamic_to_string.py +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/tests/test_tcp_transport.py +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/tests/test_type_bounds.py +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/tests/test_union_argument.py +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/tests/test_wire_record_schema_parity.py +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/tests/test_worker.py +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/tests/test_worker_cli.py +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/tests/test_worker_page.py +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/tests/test_write_results.py +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/tests/transactor/__init__.py +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/tests/transactor/test_transactor.py +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/vgi/__init__.py +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/vgi/_storage_profile.py +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/vgi/_test_fixtures/__init__.py +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/vgi/_test_fixtures/accumulate/__init__.py +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/vgi/_test_fixtures/accumulate/worker.py +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/vgi/_test_fixtures/aggregate/__init__.py +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/vgi/_test_fixtures/aggregate/_common.py +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/vgi/_test_fixtures/aggregate/basic.py +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/vgi/_test_fixtures/aggregate/dynamic.py +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/vgi/_test_fixtures/aggregate/generic.py +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/vgi/_test_fixtures/aggregate/listagg.py +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/vgi/_test_fixtures/aggregate/percentile.py +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/vgi/_test_fixtures/aggregate/same_name.py +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/vgi/_test_fixtures/aggregate/secret_typed.py +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/vgi/_test_fixtures/aggregate/streaming.py +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/vgi/_test_fixtures/aggregate/varargs.py +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/vgi/_test_fixtures/aggregate/window.py +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/vgi/_test_fixtures/attach_options.py +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/vgi/_test_fixtures/bad_enum.py +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/vgi/_test_fixtures/bad_protocol.py +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/vgi/_test_fixtures/cancellable.py +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/vgi/_test_fixtures/catalog.py +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/vgi/_test_fixtures/catalog_contents.py +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/vgi/_test_fixtures/companion.py +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/vgi/_test_fixtures/copy_from.py +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/vgi/_test_fixtures/copy_to.py +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/vgi/_test_fixtures/global_functions.py +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/vgi/_test_fixtures/narrow_bind/__init__.py +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/vgi/_test_fixtures/narrow_bind/worker.py +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/vgi/_test_fixtures/nest_tensor.py +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/vgi/_test_fixtures/orchard_catalog.py +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/vgi/_test_fixtures/projection_repro/__init__.py +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/vgi/_test_fixtures/projection_repro/worker.py +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/vgi/_test_fixtures/scalar/__init__.py +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/vgi/_test_fixtures/scalar/_common.py +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/vgi/_test_fixtures/scalar/arithmetic.py +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/vgi/_test_fixtures/scalar/bench_ladder.py +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/vgi/_test_fixtures/scalar/binary.py +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/vgi/_test_fixtures/scalar/formatting.py +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/vgi/_test_fixtures/scalar/geo.py +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/vgi/_test_fixtures/scalar/null_handling.py +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/vgi/_test_fixtures/scalar/random_demo.py +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/vgi/_test_fixtures/scalar/same_name.py +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/vgi/_test_fixtures/scalar/settings_secrets.py +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/vgi/_test_fixtures/scalar/type_info.py +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/vgi/_test_fixtures/schema_reconcile/__init__.py +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/vgi/_test_fixtures/schema_reconcile/worker.py +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/vgi/_test_fixtures/secret_cache.py +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/vgi/_test_fixtures/simple_writable.py +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/vgi/_test_fixtures/table/__init__.py +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/vgi/_test_fixtures/table/_common.py +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/vgi/_test_fixtures/table/batch_index.py +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/vgi/_test_fixtures/table/batch_index_broken.py +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/vgi/_test_fixtures/table/cache.py +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/vgi/_test_fixtures/table/catalog_scans.py +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/vgi/_test_fixtures/table/filters.py +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/vgi/_test_fixtures/table/late_materialization.py +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/vgi/_test_fixtures/table/make_series.py +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/vgi/_test_fixtures/table/misc.py +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/vgi/_test_fixtures/table/order_modes.py +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/vgi/_test_fixtures/table/pairs.py +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/vgi/_test_fixtures/table/partition_columns.py +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/vgi/_test_fixtures/table/partition_columns_broken.py +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/vgi/_test_fixtures/table/profiling_example.py +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/vgi/_test_fixtures/table/required_filters.py +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/vgi/_test_fixtures/table/same_name_cached.py +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/vgi/_test_fixtures/table/same_name_schemas.py +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/vgi/_test_fixtures/table/sequence.py +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/vgi/_test_fixtures/table/settings.py +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/vgi/_test_fixtures/table/splits.py +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/vgi/_test_fixtures/table/transaction_storage.py +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/vgi/_test_fixtures/table/tt_pushdown.py +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/vgi/_test_fixtures/table/typed_probe.py +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/vgi/_test_fixtures/table/versioned.py +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/vgi/_test_fixtures/table/wide.py +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/vgi/_test_fixtures/table_in_out.py +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/vgi/_test_fixtures/table_in_out_same_name.py +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/vgi/_test_fixtures/twin_catalogs.py +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/vgi/_test_fixtures/versioned.py +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/vgi/_test_fixtures/versioned_tables.py +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/vgi/_test_fixtures/worker.py +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/vgi/_test_fixtures/writable/__init__.py +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/vgi/_test_fixtures/writable/generic.py +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/vgi/_test_fixtures/writable/table.py +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/vgi/_test_fixtures/writable/worker.py +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/vgi/aggregate_function.py +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/vgi/argument_spec.py +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/vgi/arguments.py +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/vgi/attach_header.py +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/vgi/auth.py +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/vgi/cache_control.py +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/vgi/catalog/__init__.py +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/vgi/catalog/_descriptor_spec.py +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/vgi/catalog/attach_option.py +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/vgi/catalog/catalog_interface.py +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/vgi/catalog/descriptors.py +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/vgi/catalog/duckdb_statistics.py +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/vgi/catalog/secret_type.py +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/vgi/catalog/setting.py +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/vgi/catalog/storage.py +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/vgi/client/__init__.py +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/vgi/client/aggregate.py +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/vgi/client/catalog_mixin.py +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/vgi/client/cli.py +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/vgi/client/cli_catalog.py +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/vgi/client/cli_schema.py +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/vgi/client/cli_table.py +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/vgi/client/cli_transaction.py +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/vgi/client/cli_utils.py +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/vgi/client/cli_view.py +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/vgi/client/client.py +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/vgi/client/errors.py +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/vgi/codegen/__init__.py +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/vgi/codegen/_common.py +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/vgi/codegen/cpp_constants.py +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/vgi/codegen/cpp_protocol_name.py +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/vgi/codegen/cpp_protocol_version.py +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/vgi/codegen/cpp_request_builders.py +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/vgi/codegen/cpp_schemas.py +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/vgi/codegen/cpp_secret_protocol_version.py +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/vgi/codegen/cpp_secret_request_builders.py +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/vgi/codegen/cpp_secret_schemas.py +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/vgi/codegen/csharp_schemas.py +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/vgi/codegen/csharp_types.py +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/vgi/codegen/go_schemas.py +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/vgi/codegen/go_types.py +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/vgi/codegen/java_schemas.py +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/vgi/codegen/java_types.py +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/vgi/codegen/protocol_version.py +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/vgi/codegen/rust_request_builders.py +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/vgi/codegen/rust_schemas.py +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/vgi/codegen/rust_types.py +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/vgi/codegen/ts_client.py +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/vgi/codegen/ts_schemas.py +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/vgi/codegen/ts_types.py +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/vgi/copy_from_function.py +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/vgi/copy_to_function.py +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/vgi/exceptions.py +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/vgi/filter_v2.py +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/vgi/filter_v2_builder.py +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/vgi/function.py +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/vgi/function_storage.py +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/vgi/function_storage_azure_sql.py +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/vgi/function_storage_cf_do.py +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/vgi/http/__init__.py +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/vgi/http/demo_storage.py +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/vgi/http/landing.html +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/vgi/http/landing_page.py +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/vgi/http/vgi-client.js +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/vgi/http/worker_page.py +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/vgi/invocation.py +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/vgi/logging_config.py +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/vgi/meta_worker.py +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/vgi/metadata.py +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/vgi/otel.py +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/vgi/profiling.py +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/vgi/protocol.py +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/vgi/protocol_version.txt +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/vgi/py.typed +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/vgi/scalar_function.py +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/vgi/schema_path.py +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/vgi/schema_utils.py +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/vgi/secret_protocol.py +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/vgi/secret_service.py +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/vgi/split_token.py +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/vgi/table_buffering_function.py +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/vgi/table_filter_pushdown.py +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/vgi/table_function.py +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/vgi/table_in_out_function.py +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/vgi/transactor/__init__.py +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/vgi/transactor/_duckdb_compat.py +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/vgi/transactor/client.py +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/vgi/transactor/protocol.py +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/vgi/transactor/server.py +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/vgi/worker.py +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/vgi/write_results.py +0 -0
- {vgi_python-0.41.0 → vgi_python-0.42.0}/wrangler.jsonc +0 -0
|
@@ -297,6 +297,7 @@ vgi-client --input data.parquet --function sum_all_columns --worker vgi-fixture-
|
|
|
297
297
|
| `VGI_OAUTH_DEVICE_CODE_CLIENT_ID` | Client ID for device-code flow (optional, URL-safe chars only) |
|
|
298
298
|
| `VGI_OAUTH_DEVICE_CODE_CLIENT_SECRET` | Client secret for device-code flow (optional, URL-safe chars only) |
|
|
299
299
|
| `VGI_OAUTH_USE_ID_TOKEN` | When `1`/`true`/`yes`, clients use OIDC `id_token` as Bearer instead of `access_token` |
|
|
300
|
+
| `VGI_RPC_GRANT_KEYS` | Comma-separated base64 32-byte sealed-grant keys (first mints, all verify); enables grants as HTTP bearers. Also `VGI_RPC_GRANT_AUDIENCE`, `VGI_RPC_GRANT_MAX_TTL_SECONDS` |
|
|
300
301
|
| `VGI_INTROSPECT_PRINCIPALS` | Comma-separated principals permitted to call `vgi_rpc.Identity.v1`'s `introspect_token`. Required — no permissive default — whenever the worker implements `resolve_token()` (see below) |
|
|
301
302
|
| `VGI_WORKER_ACCESS_LOG_SAMPLE` | Fraction of *successful* calls to keep in the access log, `0.0`–`1.0`. Errors are always kept; the decision is per call, so every record of one stream shares a fate |
|
|
302
303
|
| `VGI_WORKER_ACCESS_LOG_ASYNC` | When `1`/`true`/`yes`, emit access-log records from a listener thread. Bounded queue; full means drop, and a crash loses whatever is queued |
|
|
@@ -484,6 +485,24 @@ sidecar outage raised as one is read as "not my credential, try the next" and
|
|
|
484
485
|
ends up a 401 from the end of the chain, restarting every session in the fleet
|
|
485
486
|
over a thirty-second blip.
|
|
486
487
|
|
|
488
|
+
### Grants and `resolve_token` as HTTP Bearers
|
|
489
|
+
|
|
490
|
+
With `VGI_RPC_GRANT_KEYS` (or `vgi-serve --grant-key`) set, the HTTP worker
|
|
491
|
+
hosts Identity even without hooks. It mints sealed `vgig1.` grants through
|
|
492
|
+
`issue_grant`, unless the worker overrides `mint_grant`, and accepts them back
|
|
493
|
+
as `Authorization: Bearer` credentials, authenticated as the grant's owner. A
|
|
494
|
+
worker that overrides `resolve_token` also has it consulted for bearers. The
|
|
495
|
+
order is the deployment's authenticator, then grants, then `resolve_token`. A
|
|
496
|
+
bad `vgig1.` token is a 401 and never reaches `resolve_token`. vgi-rpc composes
|
|
497
|
+
this in `make_wsgi_app`. vgi-python resolves the keys in
|
|
498
|
+
`vgi.rpc_server.resolve_grant_keys` and passes them explicitly to `RpcServer`
|
|
499
|
+
(`None` off HTTP, never vgi-rpc's `"env"` default), so grants stay HTTP-only. It
|
|
500
|
+
also puts the bearers *inside* VGI's proxy-proof gate
|
|
501
|
+
(`serve._compose_identity_bearer`), because vgi-rpc refuses to OR them beside
|
|
502
|
+
one. Allowlist rules are unchanged. See `docs/authentication.md` and
|
|
503
|
+
`tests/test_grant_auth.py`, which also runs the shared
|
|
504
|
+
`grant_token_vectors.json` through `create_app`.
|
|
505
|
+
|
|
487
506
|
### Hosting Additional Protocols (`hosted_protocols`)
|
|
488
507
|
|
|
489
508
|
Every transport (stdio, unix/named pipe, TCP, Iroh, HTTP) builds its `RpcServer`
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: vgi-python
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.42.0
|
|
4
4
|
Summary: Vector Gateway Interface - Connect DuckDB to external programs via Apache Arrow
|
|
5
5
|
Project-URL: Homepage, https://query.farm
|
|
6
6
|
Project-URL: Repository, https://github.com/Query-farm/vgi-python
|
|
@@ -162,7 +162,7 @@ Requires-Dist: httpx2>=2.12.0
|
|
|
162
162
|
Requires-Dist: platformdirs
|
|
163
163
|
Requires-Dist: pyarrow
|
|
164
164
|
Requires-Dist: typer>=0.9
|
|
165
|
-
Requires-Dist: vgi-rpc>=0.
|
|
165
|
+
Requires-Dist: vgi-rpc>=0.49.0
|
|
166
166
|
Provides-Extra: azure
|
|
167
167
|
Requires-Dist: azure-identity>=1.16.0; extra == 'azure'
|
|
168
168
|
Requires-Dist: pymssql>=2.3.0; extra == 'azure'
|
|
@@ -32,7 +32,7 @@ added incrementally.
|
|
|
32
32
|
| [Auth & Secrets](auth.md) | `AuthContext`, `CallContext`, bearer/JWT authenticators, secret protocol | HTTP: `[http]`; JWT: `[oauth]` |
|
|
33
33
|
| [Observability](observability.md) | OpenTelemetry tracing, worker logging configuration | `[otel]` for tracing |
|
|
34
34
|
| [HTTP](http.md) | Worker page, blob storage, request-size middleware | `pip install vgi-python[http]` |
|
|
35
|
-
| [Transactor](transactor.md) | `TransactorClient`, `TransactorProtocol` | `
|
|
35
|
+
| [Transactor](transactor.md) | `TransactorClient`, `TransactorProtocol` | `[transactor]` extra and a [compatible engine build](transactor.md#runtime-requirements) |
|
|
36
36
|
| [Exceptions](exceptions.md) | VGI exception types | — |
|
|
37
37
|
|
|
38
38
|
## Import Convention
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
# Transactor
|
|
2
|
+
|
|
3
|
+
!!! note "Advanced — reference only"
|
|
4
|
+
The transactor is an advanced feature without a dedicated how-to guide yet. This page is the
|
|
5
|
+
API reference; start from the [tutorial](../tutorial/index.md) and
|
|
6
|
+
[function patterns](../how-to/function-patterns.md) if you're new to VGI.
|
|
7
|
+
|
|
8
|
+
The transactor is a long-lived subprocess that gives worker functions transactional access to a
|
|
9
|
+
database, mediated by `TransactorClient` over the `TransactorProtocol`.
|
|
10
|
+
|
|
11
|
+
## Runtime requirements
|
|
12
|
+
|
|
13
|
+
The bundled transactor requires both:
|
|
14
|
+
|
|
15
|
+
- `pip install 'vgi-python[transactor]'` for its Python dependencies.
|
|
16
|
+
- A VGI fork build of `duckdb-python` providing `DuckDBPyConnection.subcursor()`,
|
|
17
|
+
which lets reads share an open write transaction. This extension has not yet
|
|
18
|
+
been merged into Haybarn or upstream DuckDB; installing the extra alone is
|
|
19
|
+
insufficient.
|
|
20
|
+
|
|
21
|
+
Engine resolution prefers `haybarn` when installed, then falls back to `duckdb`.
|
|
22
|
+
Use an environment where the selected engine provides `subcursor()`; installing
|
|
23
|
+
a compatible `duckdb` build alongside an incompatible `haybarn` installation
|
|
24
|
+
does not override that preference.
|
|
25
|
+
|
|
26
|
+
These requirements apply to the bundled transactor. Workers can implement
|
|
27
|
+
[table writes](../catalog-interface.md#table-writes-and-indexes) against their own
|
|
28
|
+
backing data sources without using it.
|
|
29
|
+
|
|
30
|
+
## API
|
|
31
|
+
|
|
32
|
+
::: vgi.transactor
|
|
@@ -24,7 +24,7 @@ the principal in the `AuthContext` available to functions.
|
|
|
24
24
|
| Variable | Description |
|
|
25
25
|
|----------|-------------|
|
|
26
26
|
| `VGI_BEARER_TOKENS` | Comma-separated `token=principal` pairs for static bearer auth |
|
|
27
|
-
| `VGI_JWT_ISSUER` | JWT issuer URL (requires `vgi[oauth]` extra) |
|
|
27
|
+
| `VGI_JWT_ISSUER` | JWT issuer URL (requires `vgi-python[oauth]` extra) |
|
|
28
28
|
| `VGI_JWT_AUDIENCE` | JWT audience string, comma-separated for multiple audiences (required when `VGI_JWT_ISSUER` is set) |
|
|
29
29
|
| `VGI_JWT_JWKS_URI` | JWKS endpoint URL (auto-discovered from issuer if omitted) |
|
|
30
30
|
| `VGI_OAUTH_RESOURCE` | OAuth resource URL for RFC 9728 metadata |
|
|
@@ -39,6 +39,48 @@ When both `VGI_BEARER_TOKENS` and `VGI_JWT_ISSUER` are set, they are
|
|
|
39
39
|
chained — JWT validation is attempted first, falling back to bearer token
|
|
40
40
|
lookup.
|
|
41
41
|
|
|
42
|
+
## Grants and resolved tokens as bearer credentials
|
|
43
|
+
|
|
44
|
+
`vgi_rpc.Identity.v1`'s `issue_grant` mints a standing credential that
|
|
45
|
+
unattended automation later presents as an ordinary bearer. Over HTTP the
|
|
46
|
+
worker accepts two kinds of identity credential after the deployment's own
|
|
47
|
+
authenticator:
|
|
48
|
+
|
|
49
|
+
1. **Sealed grants** (opt-in). Set `VGI_RPC_GRANT_KEYS` (or
|
|
50
|
+
`vgi-serve --http --grant-key KEY`, repeatable). `issue_grant` then mints a
|
|
51
|
+
`vgig1.` grant sealed with the first key, unless the worker overrides
|
|
52
|
+
`mint_grant`. Every key verifies, so to rotate you add the new key first and
|
|
53
|
+
drop the old one once its grants have expired. A request carrying
|
|
54
|
+
`Authorization: Bearer vgig1.…` is authenticated as the grant's owner, with
|
|
55
|
+
`domain="grant"` and claims `grant_id`, `scopes` and `purpose`. The claims
|
|
56
|
+
carry no `auth_time`, so a grant cannot mint another grant.
|
|
57
|
+
2. **`resolve_token`**. A worker that overrides
|
|
58
|
+
[`Worker.resolve_token`][vgi.worker.Worker.resolve_token] has it consulted
|
|
59
|
+
for any other bearer, with `domain="token"`. `None` means the credential is
|
|
60
|
+
unknown, which is a 401 unless something else accepts it.
|
|
61
|
+
`AuthUnavailableError` is a 503 with the hook's `Retry-After`.
|
|
62
|
+
|
|
63
|
+
The order is the deployment's authenticator (JWT, static bearer), then sealed
|
|
64
|
+
grants, then `resolve_token`. A `vgig1.` token that does not verify is a 401
|
|
65
|
+
that stops the chain: it never reaches `resolve_token`. A JWS-shaped token or
|
|
66
|
+
one over 4096 bytes never reaches the hook either. Your own `authenticate`
|
|
67
|
+
callback must raise `ValueError` for a credential it does not recognise, so the
|
|
68
|
+
chain moves on. One that answers anonymous for every request ends the chain
|
|
69
|
+
before grants are checked. With no authenticator configured, a request with no
|
|
70
|
+
`Authorization` header stays anonymous as before.
|
|
71
|
+
|
|
72
|
+
| Variable | Description |
|
|
73
|
+
|----------|-------------|
|
|
74
|
+
| `VGI_RPC_GRANT_KEYS` | Comma-separated standard-base64 keys, 32 bytes each. The first mints and all verify. Unset means grants are off. A malformed key stops startup |
|
|
75
|
+
| `VGI_RPC_GRANT_AUDIENCE` | Bound into every grant, so two deployments that share a key still reject each other's grants |
|
|
76
|
+
| `VGI_RPC_GRANT_MAX_TTL_SECONDS` | Ceiling on a grant's lifetime (default 7 days) |
|
|
77
|
+
|
|
78
|
+
The startup rules are unchanged. Overriding `resolve_token` still requires
|
|
79
|
+
`VGI_INTROSPECT_PRINCIPALS`. Grant keys alone need no allowlist, because
|
|
80
|
+
minting answers only for the caller. Grants and `resolve_token` bearers are
|
|
81
|
+
HTTP-only, like the rest of Identity. When `VGI_PROXY_PROOF_MODE` is on, both
|
|
82
|
+
are accepted only *inside* the proxy-proof gate, never as an alternative to it.
|
|
83
|
+
|
|
42
84
|
## Programmatic API
|
|
43
85
|
|
|
44
86
|
```python test="skip"
|
|
@@ -944,7 +944,7 @@ if __name__ == "__main__":
|
|
|
944
944
|
|
|
945
945
|
---
|
|
946
946
|
|
|
947
|
-
##
|
|
947
|
+
## Catalog capabilities and limitations { #api-limitations }
|
|
948
948
|
|
|
949
949
|
The current CatalogInterface has the following limitations:
|
|
950
950
|
|
|
@@ -952,8 +952,33 @@ The current CatalogInterface has the following limitations:
|
|
|
952
952
|
- **Tags**: Cannot be updated after object creation
|
|
953
953
|
- **Schema metadata**: Comments and tags cannot be updated on schemas
|
|
954
954
|
- **Constraints**: Only NOT NULL can be added/dropped (no ALTER for UNIQUE/CHECK)
|
|
955
|
-
|
|
956
|
-
|
|
955
|
+
|
|
956
|
+
### Table writes and indexes
|
|
957
|
+
|
|
958
|
+
`INSERT`, `UPDATE`, and `DELETE` are supported when the catalog supplies a write
|
|
959
|
+
function for the operation. For declarative catalogs, configure the
|
|
960
|
+
[`Table`][vgi.catalog.descriptors.Table] descriptor:
|
|
961
|
+
|
|
962
|
+
| Operation | Descriptor field | Requirement |
|
|
963
|
+
|-----------|------------------|-------------|
|
|
964
|
+
| `INSERT` | `insert_function` | A `TableInOutGenerator` that accepts rows to insert |
|
|
965
|
+
| `UPDATE` | `update_function` | A write function and a scan `function` that provides row IDs |
|
|
966
|
+
| `DELETE` | `delete_function` | A write function and a scan `function` that provides row IDs |
|
|
967
|
+
|
|
968
|
+
Each field defaults to `None`, which leaves that operation unsupported. Custom
|
|
969
|
+
catalogs implement `table_insert_function_get()`, `table_update_function_get()`,
|
|
970
|
+
or `table_delete_function_get()` to return the corresponding `ScanFunctionResult`.
|
|
971
|
+
The worker's write functions implement the changes to the backing data source;
|
|
972
|
+
declaring a table alone does not make it writable.
|
|
973
|
+
|
|
974
|
+
`ReadOnlyCatalogInterface` rejects catalog DDL, but can expose these write functions
|
|
975
|
+
on declarative tables. Table writes do not require the bundled
|
|
976
|
+
[transactor](api/transactor.md); that is an optional database-access service with
|
|
977
|
+
additional engine requirements.
|
|
978
|
+
|
|
979
|
+
Index metadata can be declared with [`Index`][vgi.catalog.descriptors.Index]. Custom
|
|
980
|
+
catalogs can implement `index_get()`, `index_create()`, and `index_drop()`; support
|
|
981
|
+
depends on the catalog implementation and backing data source.
|
|
957
982
|
|
|
958
983
|
---
|
|
959
984
|
|
|
@@ -545,7 +545,7 @@ vgi-fixture-worker --log-format json
|
|
|
545
545
|
| `VGI_QUIET=1` | Suppress the interactive-terminal startup warning (same as `--quiet`) |
|
|
546
546
|
| `VGI_FILTER_DEBUG=1` | Enable filter pushdown debug logging |
|
|
547
547
|
| `VGI_BEARER_TOKENS` | Comma-separated `token=principal` pairs for static bearer auth (HTTP only) |
|
|
548
|
-
| `VGI_JWT_ISSUER` | JWT issuer URL for JWT/JWKS auth (requires `vgi[oauth]` extra) |
|
|
548
|
+
| `VGI_JWT_ISSUER` | JWT issuer URL for JWT/JWKS auth (requires `vgi-python[oauth]` extra) |
|
|
549
549
|
| `VGI_JWT_AUDIENCE` | JWT audience string, comma-separated for multiple audiences (required when `VGI_JWT_ISSUER` is set) |
|
|
550
550
|
| `VGI_JWT_JWKS_URI` | JWKS endpoint URL (auto-discovered if omitted) |
|
|
551
551
|
| `VGI_OAUTH_RESOURCE` | OAuth resource URL for RFC 9728 metadata |
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
---
|
|
2
|
-
description: "How to write each of the
|
|
2
|
+
description: "How to write each of the five VGI function patterns: scalar, table, table-in-out, aggregate, and buffering — with a complete runnable worker for each."
|
|
3
3
|
---
|
|
4
4
|
|
|
5
5
|
# Function patterns
|
|
@@ -178,11 +178,14 @@ ATTACH 'aggregates' (TYPE vgi, LOCATION 'uv run sum_worker.py');
|
|
|
178
178
|
SELECT category, aggregates.vgi_sum(value) FROM t GROUP BY category;
|
|
179
179
|
```
|
|
180
180
|
|
|
181
|
-
??? info "State must be
|
|
182
|
-
Table generators and aggregates keep state between calls.
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
181
|
+
??? info "State must be serializable"
|
|
182
|
+
Table generators and aggregates keep state between calls. A state type must provide
|
|
183
|
+
`serialize_to_bytes()` and `deserialize_from_bytes()` so the framework can carry it across
|
|
184
|
+
HTTP round-trips or persist it between aggregate calls. `ArrowSerializableDataclass`
|
|
185
|
+
implements these methods for you and is the usual starting point. Custom state types can
|
|
186
|
+
implement the same [`StreamStateCodec`][vgi.function.StreamStateCodec] contract without
|
|
187
|
+
inheriting from `ArrowSerializableDataclass`. See
|
|
188
|
+
[State Class](../aggregate-functions.md#state-class) for both approaches.
|
|
186
189
|
|
|
187
190
|
## Buffering
|
|
188
191
|
|
|
@@ -22,9 +22,11 @@ function that coordinates partial results across workers.
|
|
|
22
22
|
|
|
23
23
|
## Two kinds of "state" — don't confuse them
|
|
24
24
|
|
|
25
|
-
- **Generator cursor state** — the small
|
|
26
|
-
*within one scan* (see [streaming with state](function-patterns.md#streaming-with-state)).
|
|
27
|
-
|
|
25
|
+
- **Generator cursor state** — the small serializable object a table generator keeps
|
|
26
|
+
*within one scan* (see [streaming with state](function-patterns.md#streaming-with-state)).
|
|
27
|
+
Over HTTP, the framework serializes it between requests. `ArrowSerializableDataclass`
|
|
28
|
+
supplies the serialization methods; custom types can implement
|
|
29
|
+
[`StreamStateCodec`][vgi.function.StreamStateCodec] instead.
|
|
28
30
|
- **Shared storage** (this page) — state that must outlive a single call or be shared across
|
|
29
31
|
**separate worker processes**, e.g. combining partial aggregate results. This is backed by a
|
|
30
32
|
pluggable store.
|
|
@@ -10,7 +10,7 @@ variable.
|
|
|
10
10
|
| Backend | Value | Use Case | Dependencies |
|
|
11
11
|
|---------|-------|----------|-------------|
|
|
12
12
|
| SQLite | `sqlite` (default) | Local / subprocess transport | None (stdlib) |
|
|
13
|
-
| Azure SQL | `azure-sql` | Azure cloud deployments | `vgi[azure]` |
|
|
13
|
+
| Azure SQL | `azure-sql` | Azure cloud deployments | `vgi-python[azure]` |
|
|
14
14
|
| Cloudflare DO | `cloudflare-do` | Edge / multi-cloud deployments | None (stdlib) |
|
|
15
15
|
|
|
16
16
|
## SQLite (Default)
|
|
@@ -36,7 +36,7 @@ workers run on separate hosts.
|
|
|
36
36
|
1. Install the Azure extra:
|
|
37
37
|
|
|
38
38
|
```bash
|
|
39
|
-
pip install vgi[azure]
|
|
39
|
+
pip install 'vgi-python[azure]'
|
|
40
40
|
```
|
|
41
41
|
|
|
42
42
|
2. Create an Azure SQL Database (Serverless recommended for cost):
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "vgi-python"
|
|
3
|
-
version = "0.
|
|
3
|
+
version = "0.42.0"
|
|
4
4
|
description = "Vector Gateway Interface - Connect DuckDB to external programs via Apache Arrow"
|
|
5
5
|
readme = "README.md"
|
|
6
6
|
keywords = [
|
|
@@ -40,7 +40,7 @@ dependencies = [
|
|
|
40
40
|
"pyarrow",
|
|
41
41
|
"typer>=0.9",
|
|
42
42
|
"platformdirs",
|
|
43
|
-
"vgi-rpc>=0.
|
|
43
|
+
"vgi-rpc>=0.49.0",
|
|
44
44
|
"httpx2>=2.12.0",
|
|
45
45
|
]
|
|
46
46
|
|
|
@@ -0,0 +1,290 @@
|
|
|
1
|
+
# Copyright 2025, 2026 Query Farm LLC - https://query.farm
|
|
2
|
+
|
|
3
|
+
"""Identity credentials accepted as HTTP bearers: sealed grants and ``resolve_token``.
|
|
4
|
+
|
|
5
|
+
vgi-rpc's ``Identity.v1`` mints grants "presented later by unattended
|
|
6
|
+
automation as an ordinary bearer". These tests close that loop through
|
|
7
|
+
vgi-python's own HTTP surface (``create_app``), not vgi-rpc in isolation:
|
|
8
|
+
|
|
9
|
+
- with ``VGI_RPC_GRANT_KEYS`` set, ``issue_grant`` mints a sealed grant and a
|
|
10
|
+
``vgi.v2`` call presenting it is authenticated as the grant's owner;
|
|
11
|
+
- a worker that overrides ``resolve_token`` has it consulted for bearers;
|
|
12
|
+
- the shared vectors (``vgi_rpc/conformance/grant_token_vectors.json``) are
|
|
13
|
+
accepted and rejected through the full chain;
|
|
14
|
+
- VGI's proxy-proof gate still guards every request when grants are on.
|
|
15
|
+
"""
|
|
16
|
+
|
|
17
|
+
from __future__ import annotations
|
|
18
|
+
|
|
19
|
+
import base64
|
|
20
|
+
import json
|
|
21
|
+
import time
|
|
22
|
+
import types
|
|
23
|
+
from collections.abc import Iterator
|
|
24
|
+
from importlib.resources import files
|
|
25
|
+
from typing import Any
|
|
26
|
+
|
|
27
|
+
import pyarrow as pa
|
|
28
|
+
import pytest
|
|
29
|
+
from vgi_rpc.grants import GRANT_KEYS_ENV, GrantKeys, mint_grant_token
|
|
30
|
+
from vgi_rpc.http import http_connect
|
|
31
|
+
from vgi_rpc.http._testing import _SyncTestClient
|
|
32
|
+
from vgi_rpc.rpc import AuthContext
|
|
33
|
+
from vgi_rpc.rpc._token_identity import Identity
|
|
34
|
+
|
|
35
|
+
from tests.test_serve import _PeerAuthWorker
|
|
36
|
+
from vgi.arguments import Arguments
|
|
37
|
+
from vgi.auth import TokenIdentity
|
|
38
|
+
from vgi.client import Client, ClientError
|
|
39
|
+
from vgi.rpc_server import build_rpc_server, resolve_grant_keys
|
|
40
|
+
from vgi.serve import create_app
|
|
41
|
+
|
|
42
|
+
_KEY_B64 = base64.b64encode(bytes(range(32))).decode()
|
|
43
|
+
_OTHER_KEY_B64 = base64.b64encode(bytes(range(32, 64))).decode()
|
|
44
|
+
_SIGNING_KEY = b"grant-auth-test-signing-key-0001"
|
|
45
|
+
_IDENTITY = "vgi_rpc.Identity.v1"
|
|
46
|
+
_GRANT_ENV = (GRANT_KEYS_ENV, "VGI_RPC_GRANT_AUDIENCE", "VGI_RPC_GRANT_MAX_TTL_SECONDS")
|
|
47
|
+
|
|
48
|
+
_VECTORS = json.loads(files("vgi_rpc.conformance").joinpath("grant_token_vectors.json").read_text(encoding="utf-8"))
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
@pytest.fixture(autouse=True)
|
|
52
|
+
def _clean_env(monkeypatch: pytest.MonkeyPatch) -> Iterator[None]:
|
|
53
|
+
"""No ambient grant, auth or allowlist configuration leaks into a test."""
|
|
54
|
+
for key in (*_GRANT_ENV, "VGI_INTROSPECT_PRINCIPALS", "VGI_BEARER_TOKENS", "VGI_JWT_ISSUER"):
|
|
55
|
+
monkeypatch.delenv(key, raising=False)
|
|
56
|
+
for key in ("VGI_PROXY_PROOF_MODE", "VGI_PROXY_PROOF_ORIGIN_ID", "VGI_PROXY_PROOF_SECRETS"):
|
|
57
|
+
monkeypatch.delenv(key, raising=False)
|
|
58
|
+
yield
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
def _header_authenticate(req: Any) -> AuthContext:
|
|
62
|
+
"""Deployment authenticator: ``X-Test-Principal`` with a fresh ``auth_time``.
|
|
63
|
+
|
|
64
|
+
Raises ``ValueError`` for a bare bearer, as the chain contract requires, so
|
|
65
|
+
grants and ``resolve_token`` get to answer it.
|
|
66
|
+
"""
|
|
67
|
+
principal = req.get_header("X-Test-Principal")
|
|
68
|
+
if principal:
|
|
69
|
+
return AuthContext(domain="test", authenticated=True, principal=principal, claims={"auth_time": time.time()})
|
|
70
|
+
if req.get_header("Authorization"):
|
|
71
|
+
raise ValueError("not a test-principal request")
|
|
72
|
+
return AuthContext.anonymous()
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
def _whoami(app: Any, *, bearer: str) -> str:
|
|
76
|
+
"""Call ``peer_auth_echo`` (a vgi.v2 scalar function) and return its principal."""
|
|
77
|
+
client = _SyncTestClient(app, default_headers={"Authorization": f"Bearer {bearer}"})
|
|
78
|
+
with Client.from_http("http://vgi.test", httpx_client=client) as vgi:
|
|
79
|
+
out = list(
|
|
80
|
+
vgi.scalar_function(
|
|
81
|
+
function_name="peer_auth_echo",
|
|
82
|
+
schema_path=["main"],
|
|
83
|
+
arguments=Arguments(positional=(pa.scalar("value"),)),
|
|
84
|
+
input=iter((pa.record_batch({"value": pa.array([1], type=pa.int64())}),)),
|
|
85
|
+
)
|
|
86
|
+
)
|
|
87
|
+
return str(out[0].column("result")[0].as_py())
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
def _app(worker: type = _PeerAuthWorker, **kwargs: Any) -> Any:
|
|
91
|
+
return create_app(worker, describe=False, signing_key=_SIGNING_KEY, **kwargs)
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
class TestGrantKeyConfiguration:
|
|
95
|
+
"""Opt-in, from the environment or ``--grant-key``; malformed keys stop startup."""
|
|
96
|
+
|
|
97
|
+
def test_no_key_means_grants_off(self) -> None:
|
|
98
|
+
"""No key means grants off."""
|
|
99
|
+
assert resolve_grant_keys() is None
|
|
100
|
+
assert _IDENTITY not in build_rpc_server(_PeerAuthWorker(quiet=True), transport="http").bindings
|
|
101
|
+
|
|
102
|
+
def test_env_keys_parse(self, monkeypatch: pytest.MonkeyPatch) -> None:
|
|
103
|
+
"""Env keys parse."""
|
|
104
|
+
monkeypatch.setenv(GRANT_KEYS_ENV, f"{_KEY_B64},{_OTHER_KEY_B64}")
|
|
105
|
+
monkeypatch.setenv("VGI_RPC_GRANT_AUDIENCE", "aud")
|
|
106
|
+
keys = resolve_grant_keys()
|
|
107
|
+
assert keys is not None
|
|
108
|
+
assert keys.keys == (bytes(range(32)), bytes(range(32, 64)))
|
|
109
|
+
assert keys.audience == "aud"
|
|
110
|
+
|
|
111
|
+
def test_explicit_keys_win_over_env(self, monkeypatch: pytest.MonkeyPatch) -> None:
|
|
112
|
+
"""Explicit keys win over env."""
|
|
113
|
+
monkeypatch.setenv(GRANT_KEYS_ENV, _OTHER_KEY_B64)
|
|
114
|
+
keys = resolve_grant_keys([_KEY_B64])
|
|
115
|
+
assert keys is not None
|
|
116
|
+
assert keys.keys == (bytes(range(32)),)
|
|
117
|
+
|
|
118
|
+
@pytest.mark.parametrize("bad", ["not-base64!", base64.b64encode(b"short").decode()])
|
|
119
|
+
def test_malformed_key_refuses_to_start(self, monkeypatch: pytest.MonkeyPatch, bad: str) -> None:
|
|
120
|
+
"""Malformed key refuses to start."""
|
|
121
|
+
monkeypatch.setenv(GRANT_KEYS_ENV, bad)
|
|
122
|
+
with pytest.raises(SystemExit):
|
|
123
|
+
_app()
|
|
124
|
+
|
|
125
|
+
def test_keys_alone_host_issue_grant_without_an_allowlist(self, monkeypatch: pytest.MonkeyPatch) -> None:
|
|
126
|
+
"""Minting is not an oracle, so the introspection allowlist rule does not apply."""
|
|
127
|
+
monkeypatch.setenv(GRANT_KEYS_ENV, _KEY_B64)
|
|
128
|
+
server = build_rpc_server(_PeerAuthWorker(quiet=True), transport="http", grant_keys=resolve_grant_keys())
|
|
129
|
+
assert server.bindings[_IDENTITY].methods.keys() == {"issue_grant"}
|
|
130
|
+
|
|
131
|
+
def test_keys_are_http_only(self, monkeypatch: pytest.MonkeyPatch) -> None:
|
|
132
|
+
"""Keys are http only."""
|
|
133
|
+
monkeypatch.setenv(GRANT_KEYS_ENV, _KEY_B64)
|
|
134
|
+
server = build_rpc_server(_PeerAuthWorker(quiet=True), transport="unix", grant_keys=resolve_grant_keys())
|
|
135
|
+
assert _IDENTITY not in server.bindings
|
|
136
|
+
|
|
137
|
+
|
|
138
|
+
class TestSealedGrantEndToEnd:
|
|
139
|
+
"""issue_grant with fresh auth, then a vgi.v2 call with ``Bearer <grant>``, as the owner."""
|
|
140
|
+
|
|
141
|
+
def test_minted_grant_authenticates_as_its_owner(self, monkeypatch: pytest.MonkeyPatch) -> None:
|
|
142
|
+
"""Minted grant authenticates as its owner."""
|
|
143
|
+
monkeypatch.setenv(GRANT_KEYS_ENV, _KEY_B64)
|
|
144
|
+
app = _app(authenticate=_header_authenticate)
|
|
145
|
+
|
|
146
|
+
minter = _SyncTestClient(app, default_headers={"X-Test-Principal": "alice@example.com"})
|
|
147
|
+
with http_connect(Identity, client=minter) as identity: # type: ignore[type-abstract]
|
|
148
|
+
grant = identity.issue_grant(purpose="nightly-report", scopes=["read"], ttl_seconds=600)
|
|
149
|
+
assert grant.token.startswith("vgig1.")
|
|
150
|
+
|
|
151
|
+
assert _whoami(app, bearer=grant.token) == "alice@example.com"
|
|
152
|
+
|
|
153
|
+
def test_tampered_grant_is_refused(self, monkeypatch: pytest.MonkeyPatch) -> None:
|
|
154
|
+
"""Tampered grant is refused."""
|
|
155
|
+
monkeypatch.setenv(GRANT_KEYS_ENV, _KEY_B64)
|
|
156
|
+
keys = GrantKeys.parse([_KEY_B64])
|
|
157
|
+
token, _ = mint_grant_token(keys, principal="alice", scopes=[], purpose="p", ttl_seconds=60)
|
|
158
|
+
tampered = token[:-2] + ("A" if token[-2] != "A" else "B") + token[-1]
|
|
159
|
+
with pytest.raises(ClientError):
|
|
160
|
+
_whoami(_app(authenticate=_header_authenticate), bearer=tampered)
|
|
161
|
+
|
|
162
|
+
def test_unknown_bearer_without_grants_configured_stays_unaccepted(self) -> None:
|
|
163
|
+
"""No keys, no hook: nothing changes -- the deployment authenticator decides."""
|
|
164
|
+
app = _app(authenticate=_header_authenticate)
|
|
165
|
+
with pytest.raises(ClientError):
|
|
166
|
+
_whoami(app, bearer="vgig1.AAAA")
|
|
167
|
+
|
|
168
|
+
|
|
169
|
+
class _ResolvingWorker(_PeerAuthWorker):
|
|
170
|
+
"""Resolves one opaque credential; counts calls so routing is observable."""
|
|
171
|
+
|
|
172
|
+
calls: list[str] = []
|
|
173
|
+
|
|
174
|
+
@classmethod
|
|
175
|
+
def resolve_token(cls, token: str) -> TokenIdentity | None:
|
|
176
|
+
"""Resolve token."""
|
|
177
|
+
cls.calls.append(token)
|
|
178
|
+
return TokenIdentity(principal="svc-reporting") if token == "opaque-api-key" else None
|
|
179
|
+
|
|
180
|
+
|
|
181
|
+
class TestResolveTokenBearer:
|
|
182
|
+
"""A worker's resolve_token is consulted for bearers it did not mint."""
|
|
183
|
+
|
|
184
|
+
@pytest.fixture
|
|
185
|
+
def app(self, monkeypatch: pytest.MonkeyPatch) -> Any:
|
|
186
|
+
"""App."""
|
|
187
|
+
monkeypatch.setenv("VGI_INTROSPECT_PRINCIPALS", "proxy-a")
|
|
188
|
+
monkeypatch.setenv(GRANT_KEYS_ENV, _KEY_B64)
|
|
189
|
+
_ResolvingWorker.calls = []
|
|
190
|
+
return _app(_ResolvingWorker, authenticate=_header_authenticate)
|
|
191
|
+
|
|
192
|
+
def test_resolved_bearer_authenticates(self, app: Any) -> None:
|
|
193
|
+
"""Resolved bearer authenticates."""
|
|
194
|
+
assert _whoami(app, bearer="opaque-api-key") == "svc-reporting"
|
|
195
|
+
|
|
196
|
+
def test_unresolved_bearer_is_refused(self, app: Any) -> None:
|
|
197
|
+
"""Unresolved bearer is refused."""
|
|
198
|
+
with pytest.raises(ClientError):
|
|
199
|
+
_whoami(app, bearer="unknown-key")
|
|
200
|
+
|
|
201
|
+
def test_a_bad_grant_never_reaches_the_resolver(self, app: Any) -> None:
|
|
202
|
+
"""A bad grant never reaches the resolver."""
|
|
203
|
+
with pytest.raises(ClientError):
|
|
204
|
+
_whoami(app, bearer="vgig1.AAAA")
|
|
205
|
+
assert "vgig1.AAAA" not in _ResolvingWorker.calls
|
|
206
|
+
|
|
207
|
+
def test_allowlist_rule_unchanged(self, monkeypatch: pytest.MonkeyPatch) -> None:
|
|
208
|
+
"""Allowlist rule unchanged."""
|
|
209
|
+
monkeypatch.delenv("VGI_INTROSPECT_PRINCIPALS", raising=False)
|
|
210
|
+
with pytest.raises(SystemExit):
|
|
211
|
+
_app(_ResolvingWorker)
|
|
212
|
+
|
|
213
|
+
|
|
214
|
+
def _vector_env(monkeypatch: pytest.MonkeyPatch, verify_keys: list[str], audience: str, max_ttl: int) -> None:
|
|
215
|
+
monkeypatch.setenv(GRANT_KEYS_ENV, ",".join(verify_keys))
|
|
216
|
+
monkeypatch.setenv("VGI_RPC_GRANT_AUDIENCE", audience)
|
|
217
|
+
monkeypatch.setenv("VGI_RPC_GRANT_MAX_TTL_SECONDS", str(max_ttl))
|
|
218
|
+
|
|
219
|
+
|
|
220
|
+
def _at(monkeypatch: pytest.MonkeyPatch, now: float) -> None:
|
|
221
|
+
"""Pin the grant verifier's clock without touching the process clock."""
|
|
222
|
+
import vgi_rpc.grants
|
|
223
|
+
|
|
224
|
+
monkeypatch.setattr(vgi_rpc.grants, "time", types.SimpleNamespace(time=lambda: now))
|
|
225
|
+
|
|
226
|
+
|
|
227
|
+
class TestSharedVectors:
|
|
228
|
+
"""The shared vectors, accepted and rejected through create_app's whole chain."""
|
|
229
|
+
|
|
230
|
+
@pytest.mark.parametrize("case", _VECTORS["mint"], ids=lambda c: c["name"])
|
|
231
|
+
def test_minted_vector_authenticates(self, monkeypatch: pytest.MonkeyPatch, case: dict[str, Any]) -> None:
|
|
232
|
+
"""Minted vector authenticates."""
|
|
233
|
+
verify = [case["minting_key_b64"], *_VECTORS["defaults"]["verify_keys_b64"]]
|
|
234
|
+
_vector_env(monkeypatch, list(dict.fromkeys(verify)), case["audience"], case["max_ttl_seconds"])
|
|
235
|
+
_at(monkeypatch, case["now"] + 1)
|
|
236
|
+
assert _whoami(_app(), bearer=case["token"]) == case["claims"]["principal"]
|
|
237
|
+
|
|
238
|
+
@pytest.mark.parametrize("case", _VECTORS["accept"], ids=lambda c: c["name"])
|
|
239
|
+
def test_accept_case(self, monkeypatch: pytest.MonkeyPatch, case: dict[str, Any]) -> None:
|
|
240
|
+
"""Accept case."""
|
|
241
|
+
d = _VECTORS["defaults"]
|
|
242
|
+
_vector_env(
|
|
243
|
+
monkeypatch,
|
|
244
|
+
case.get("verify_keys_b64", d["verify_keys_b64"]),
|
|
245
|
+
case.get("audience", d["audience"]),
|
|
246
|
+
case.get("max_ttl_seconds", d["max_ttl_seconds"]),
|
|
247
|
+
)
|
|
248
|
+
_at(monkeypatch, case.get("now", d["now"]))
|
|
249
|
+
assert _whoami(_app(), bearer=case["token"]) != "anonymous"
|
|
250
|
+
|
|
251
|
+
@pytest.mark.parametrize("case", _VECTORS["reject"], ids=lambda c: c["name"])
|
|
252
|
+
def test_reject_case(self, monkeypatch: pytest.MonkeyPatch, case: dict[str, Any]) -> None:
|
|
253
|
+
"""Reject case."""
|
|
254
|
+
d = _VECTORS["defaults"]
|
|
255
|
+
_vector_env(
|
|
256
|
+
monkeypatch,
|
|
257
|
+
case.get("verify_keys_b64", d["verify_keys_b64"]),
|
|
258
|
+
case.get("audience", d["audience"]),
|
|
259
|
+
case.get("max_ttl_seconds", d["max_ttl_seconds"]),
|
|
260
|
+
)
|
|
261
|
+
_at(monkeypatch, case.get("now", d["now"]))
|
|
262
|
+
with pytest.raises(ClientError):
|
|
263
|
+
_whoami(_app(), bearer=case["token"])
|
|
264
|
+
|
|
265
|
+
|
|
266
|
+
class TestProxyProofGateStillGuards:
|
|
267
|
+
"""Grants go inside VGI's proxy-proof gate, never beside it."""
|
|
268
|
+
|
|
269
|
+
@pytest.fixture
|
|
270
|
+
def gated(self, monkeypatch: pytest.MonkeyPatch) -> None:
|
|
271
|
+
"""Gated."""
|
|
272
|
+
monkeypatch.setenv("VGI_PROXY_PROOF_MODE", "require")
|
|
273
|
+
monkeypatch.setenv("VGI_PROXY_PROOF_ORIGIN_ID", "worker-a")
|
|
274
|
+
monkeypatch.setenv("VGI_PROXY_PROOF_SECRETS", "k:" + "11" * 32)
|
|
275
|
+
monkeypatch.setenv(GRANT_KEYS_ENV, _KEY_B64)
|
|
276
|
+
|
|
277
|
+
def test_gated_worker_with_grants_starts(self, gated: None) -> None:
|
|
278
|
+
"""vgi-rpc refuses to OR grants beside a proxy gate; create_app composes inside it."""
|
|
279
|
+
from vgi.serve import _resolve_authenticate
|
|
280
|
+
|
|
281
|
+
_app(authenticate=_resolve_authenticate())
|
|
282
|
+
|
|
283
|
+
def test_valid_grant_without_proof_is_refused(self, gated: None) -> None:
|
|
284
|
+
"""Valid grant without proof is refused."""
|
|
285
|
+
from vgi.serve import _resolve_authenticate
|
|
286
|
+
|
|
287
|
+
keys = GrantKeys.parse([_KEY_B64])
|
|
288
|
+
token, _ = mint_grant_token(keys, principal="alice", scopes=[], purpose="p", ttl_seconds=60)
|
|
289
|
+
with pytest.raises(ClientError):
|
|
290
|
+
_whoami(_app(authenticate=_resolve_authenticate()), bearer=token)
|
|
@@ -2670,7 +2670,7 @@ requires-dist = [
|
|
|
2670
2670
|
|
|
2671
2671
|
[[package]]
|
|
2672
2672
|
name = "vgi-python"
|
|
2673
|
-
version = "0.
|
|
2673
|
+
version = "0.42.0"
|
|
2674
2674
|
source = { editable = "." }
|
|
2675
2675
|
dependencies = [
|
|
2676
2676
|
{ name = "click" },
|
|
@@ -2790,7 +2790,7 @@ requires-dist = [
|
|
|
2790
2790
|
{ name = "vgi-python", extras = ["test-fixtures"], marker = "extra == 'test-fixtures-writable'" },
|
|
2791
2791
|
{ name = "vgi-python", extras = ["test-fixtures", "test-fixtures-writable", "http", "launch", "oauth", "otel", "sentry", "azure"], marker = "extra == 'dev'" },
|
|
2792
2792
|
{ name = "vgi-python", extras = ["transactor"], marker = "extra == 'test-fixtures-writable'" },
|
|
2793
|
-
{ name = "vgi-rpc", specifier = ">=0.
|
|
2793
|
+
{ name = "vgi-rpc", specifier = ">=0.49.0" },
|
|
2794
2794
|
{ name = "vgi-rpc", extras = ["cli"], marker = "extra == 'launch'" },
|
|
2795
2795
|
{ name = "vgi-rpc", extras = ["cli", "conformance", "external", "http", "oauth", "otel", "sentry"], marker = "extra == 'dev'" },
|
|
2796
2796
|
{ name = "vgi-rpc", extras = ["http"], marker = "extra == 'granian'" },
|
|
@@ -2821,7 +2821,7 @@ docs = [
|
|
|
2821
2821
|
|
|
2822
2822
|
[[package]]
|
|
2823
2823
|
name = "vgi-rpc"
|
|
2824
|
-
version = "0.
|
|
2824
|
+
version = "0.49.0"
|
|
2825
2825
|
source = { registry = "https://pypi.org/simple" }
|
|
2826
2826
|
dependencies = [
|
|
2827
2827
|
{ name = "docstring-parser" },
|
|
@@ -2829,9 +2829,9 @@ dependencies = [
|
|
|
2829
2829
|
{ name = "pywin32", marker = "sys_platform == 'win32'" },
|
|
2830
2830
|
{ name = "tzdata", marker = "sys_platform == 'win32'" },
|
|
2831
2831
|
]
|
|
2832
|
-
sdist = { url = "https://files.pythonhosted.org/packages/
|
|
2832
|
+
sdist = { url = "https://files.pythonhosted.org/packages/d5/1c/29d313c20c578d711eadcff65680f7ebf4c574f157dbf45a6689d78f3fb8/vgi_rpc-0.49.0.tar.gz", hash = "sha256:84a1ea49cb24805bdad8ebe2006f63fb69a82fb5a8746b10b3f0a7345f4bb0a9", size = 1610726, upload-time = "2026-10-06T17:29:24.272Z" }
|
|
2833
2833
|
wheels = [
|
|
2834
|
-
{ url = "https://files.pythonhosted.org/packages/
|
|
2834
|
+
{ url = "https://files.pythonhosted.org/packages/bf/8d/c444dc959722506d3fa5c4fd623a790c3f140cccae2341d97c55d7df403a/vgi_rpc-0.49.0-py3-none-any.whl", hash = "sha256:faae05f9a3d08202c031d0b783c5ff93c6770833fd22fb1479a556267ad4ef63", size = 756201, upload-time = "2026-10-06T17:29:21.983Z" },
|
|
2835
2835
|
]
|
|
2836
2836
|
|
|
2837
2837
|
[package.optional-dependencies]
|
|
@@ -7,8 +7,8 @@ engine (expression-filter evaluation, the transactor, the statistics
|
|
|
7
7
|
fixtures) resolves it through this module, which prefers Query Farm's
|
|
8
8
|
``haybarn`` distribution when installed and falls back to stock ``duckdb``.
|
|
9
9
|
|
|
10
|
-
Install one via the extras: ``pip install vgi[haybarn]`` (preferred) or
|
|
11
|
-
``pip install vgi[duckdb]``.
|
|
10
|
+
Install one via the extras: ``pip install 'vgi-python[haybarn]'`` (preferred) or
|
|
11
|
+
``pip install 'vgi-python[duckdb]'``.
|
|
12
12
|
"""
|
|
13
13
|
|
|
14
14
|
from __future__ import annotations
|
|
@@ -50,7 +50,7 @@ def engine_module() -> ModuleType:
|
|
|
50
50
|
else:
|
|
51
51
|
raise ImportError(
|
|
52
52
|
"No DuckDB-compatible engine is installed. Install 'haybarn' (preferred) "
|
|
53
|
-
"or 'duckdb', e.g. `pip install vgi[haybarn]` or `pip install vgi[duckdb]`."
|
|
53
|
+
"or 'duckdb', e.g. `pip install 'vgi-python[haybarn]'` or `pip install 'vgi-python[duckdb]'`."
|
|
54
54
|
)
|
|
55
55
|
return _engine
|
|
56
56
|
|