vgi-python 0.46.1__tar.gz → 0.47.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.46.1 → vgi_python-0.47.0}/.github/workflows/integration.yml +1 -1
- {vgi_python-0.46.1 → vgi_python-0.47.0}/PKG-INFO +1 -1
- {vgi_python-0.46.1 → vgi_python-0.47.0}/docs/generator-api.md +24 -6
- {vgi_python-0.46.1 → vgi_python-0.47.0}/docs/metadata.md +1 -0
- vgi_python-0.47.0/examples/paged_api_worker.py +117 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/packages/vgi-fixtures/pyproject.toml +1 -1
- {vgi_python-0.46.1 → vgi_python-0.47.0}/pyproject.toml +1 -1
- {vgi_python-0.46.1 → vgi_python-0.47.0}/scripts/regen_generated.py +34 -4
- vgi_python-0.47.0/tests/table_in_out/test_continuation.py +391 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/tests/test_examples_workers.py +40 -0
- vgi_python-0.47.0/tests/test_reporting_contracts.py +312 -0
- vgi_python-0.47.0/tests/test_reporting_enterprise.py +247 -0
- vgi_python-0.47.0/tests/test_reporting_scale.py +475 -0
- vgi_python-0.47.0/tests/test_reporting_sources.py +69 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/uv.lock +2 -2
- {vgi_python-0.46.1 → vgi_python-0.47.0}/vgi/_test_fixtures/table/cache.py +17 -3
- {vgi_python-0.46.1 → vgi_python-0.47.0}/vgi/_test_fixtures/table_in_out.py +339 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/vgi/_test_fixtures/worker.py +6 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/vgi/catalog/catalog_interface.py +8 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/vgi/client/client.py +22 -9
- vgi_python-0.47.0/vgi/codegen/reporting_docs.py +162 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/vgi/metadata.py +60 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/vgi/protocol.py +85 -9
- vgi_python-0.47.0/vgi/reporting/__init__.py +72 -0
- vgi_python-0.47.0/vgi/reporting/_arrow.py +26 -0
- vgi_python-0.47.0/vgi/reporting/_enums.py +69 -0
- vgi_python-0.47.0/vgi/reporting/_metadata.py +60 -0
- vgi_python-0.47.0/vgi/reporting/alerts.py +454 -0
- vgi_python-0.47.0/vgi/reporting/common.py +575 -0
- vgi_python-0.47.0/vgi/reporting/delegations.py +78 -0
- vgi_python-0.47.0/vgi/reporting/discovery.py +249 -0
- vgi_python-0.47.0/vgi/reporting/notify.py +178 -0
- vgi_python-0.47.0/vgi/reporting/objects.py +349 -0
- vgi_python-0.47.0/vgi/reporting/ownership.py +65 -0
- vgi_python-0.47.0/vgi/reporting/render.py +130 -0
- vgi_python-0.47.0/vgi/reporting/reports.py +330 -0
- vgi_python-0.47.0/vgi/reporting/resource_identity.py +186 -0
- vgi_python-0.47.0/vgi/reporting/resource_ownership.py +56 -0
- vgi_python-0.47.0/vgi/reporting/schedules.py +401 -0
- vgi_python-0.47.0/vgi/reporting/schedules_v2.py +406 -0
- vgi_python-0.47.0/vgi/reporting/sources.py +138 -0
- vgi_python-0.47.0/vgi/reporting/sql_tasks.py +476 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/vgi/table_in_out_function.py +40 -1
- {vgi_python-0.46.1 → vgi_python-0.47.0}/.dockerignore +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/.gitattributes +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/.github/dependabot.yml +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/.github/styles/config/vocabularies/VGI/accept.txt +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/.github/workflows/ci.yml +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/.github/workflows/docs.yml +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/.github/workflows/release.yml +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/.github/workflows/tailnet-integration.yml +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/.gitignore +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/.python-version +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/.vale.ini +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/CLAUDE.md +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/DOCS_ACCEPTANCE_CRITERIA.md +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/DOCS_REVIEW_RUBRIC.md +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/DOCS_USABILITY_TEST.md +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/LICENSE +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/PROTOCOL.md +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/README.md +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/RELEASE-RUNBOOK.md +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/SECURITY.md +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/ci/README.md +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/ci/preprocess-require.awk +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/ci/run-integration.sh +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/conformance/filter-v2/README.md +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/conformance/filter-v2/cases/negative/and-too-few-children.json +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/conformance/filter-v2/cases/negative/delta-required-upsert.json +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/conformance/filter-v2/cases/negative/nested-runtime-filter.json +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/conformance/filter-v2/cases/negative/remove-with-expression.json +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/conformance/filter-v2/cases/negative/required-runtime-filter.json +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/conformance/filter-v2/cases/negative/snapshot-nonzero-revision.json +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/conformance/filter-v2/cases/negative/unknown-document-property.json +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/conformance/filter-v2/cases/negative/unknown-node.json +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/conformance/filter-v2/cases/positive/advisory-upsert-delta.json +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/conformance/filter-v2/cases/positive/boolean-column-predicate.json +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/conformance/filter-v2/cases/positive/empty-snapshot.json +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/conformance/filter-v2/cases/positive/nested-required-snapshot.json +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/conformance/filter-v2/cases/positive/remove-delta.json +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/conformance/filter-v2/cases/positive/runtime-filter-snapshot.json +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/conformance/filter-v2/filter-v2.schema.json +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/conformance/filter-v2/generate_runtime.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/conformance/filter-v2/manifest.json +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/conformance/filter-v2/run_worker.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/conformance/filter-v2/runtime/arithmetic-add/expected.arrow +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/conformance/filter-v2/runtime/arithmetic-add/filter.arrow +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/conformance/filter-v2/runtime/arithmetic-add/input.arrow +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/conformance/filter-v2/runtime/arithmetic-multiply/expected.arrow +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/conformance/filter-v2/runtime/arithmetic-multiply/filter.arrow +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/conformance/filter-v2/runtime/arithmetic-multiply/input.arrow +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/conformance/filter-v2/runtime/arithmetic-negate/expected.arrow +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/conformance/filter-v2/runtime/arithmetic-negate/filter.arrow +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/conformance/filter-v2/runtime/arithmetic-negate/input.arrow +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/conformance/filter-v2/runtime/arithmetic-subtract/expected.arrow +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/conformance/filter-v2/runtime/arithmetic-subtract/filter.arrow +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/conformance/filter-v2/runtime/arithmetic-subtract/input.arrow +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/conformance/filter-v2/runtime/cast-integer-to-double/expected.arrow +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/conformance/filter-v2/runtime/cast-integer-to-double/filter.arrow +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/conformance/filter-v2/runtime/cast-integer-to-double/input.arrow +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/conformance/filter-v2/runtime/comparison-distinct_from/expected.arrow +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/conformance/filter-v2/runtime/comparison-distinct_from/filter.arrow +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/conformance/filter-v2/runtime/comparison-distinct_from/input.arrow +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/conformance/filter-v2/runtime/comparison-distinct_from/worker-expected.arrow +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/conformance/filter-v2/runtime/comparison-eq/expected.arrow +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/conformance/filter-v2/runtime/comparison-eq/filter.arrow +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/conformance/filter-v2/runtime/comparison-eq/input.arrow +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/conformance/filter-v2/runtime/comparison-eq/worker-expected.arrow +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/conformance/filter-v2/runtime/comparison-ge/expected.arrow +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/conformance/filter-v2/runtime/comparison-ge/filter.arrow +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/conformance/filter-v2/runtime/comparison-ge/input.arrow +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/conformance/filter-v2/runtime/comparison-ge/worker-expected.arrow +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/conformance/filter-v2/runtime/comparison-gt/expected.arrow +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/conformance/filter-v2/runtime/comparison-gt/filter.arrow +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/conformance/filter-v2/runtime/comparison-gt/input.arrow +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/conformance/filter-v2/runtime/comparison-gt/worker-expected.arrow +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/conformance/filter-v2/runtime/comparison-le/expected.arrow +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/conformance/filter-v2/runtime/comparison-le/filter.arrow +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/conformance/filter-v2/runtime/comparison-le/input.arrow +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/conformance/filter-v2/runtime/comparison-le/worker-expected.arrow +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/conformance/filter-v2/runtime/comparison-lt/expected.arrow +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/conformance/filter-v2/runtime/comparison-lt/filter.arrow +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/conformance/filter-v2/runtime/comparison-lt/input.arrow +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/conformance/filter-v2/runtime/comparison-lt/worker-expected.arrow +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/conformance/filter-v2/runtime/comparison-ne/expected.arrow +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/conformance/filter-v2/runtime/comparison-ne/filter.arrow +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/conformance/filter-v2/runtime/comparison-ne/input.arrow +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/conformance/filter-v2/runtime/comparison-ne/worker-expected.arrow +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/conformance/filter-v2/runtime/comparison-not_distinct_from/expected.arrow +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/conformance/filter-v2/runtime/comparison-not_distinct_from/filter.arrow +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/conformance/filter-v2/runtime/comparison-not_distinct_from/input.arrow +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/conformance/filter-v2/runtime/comparison-not_distinct_from/worker-expected.arrow +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/conformance/filter-v2/runtime/delta-atomic-multi-update/delta-0.arrow +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/conformance/filter-v2/runtime/delta-atomic-multi-update/expected.arrow +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/conformance/filter-v2/runtime/delta-atomic-multi-update/filter.arrow +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/conformance/filter-v2/runtime/delta-atomic-multi-update/input.arrow +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/conformance/filter-v2/runtime/delta-empty-noop/delta-0.arrow +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/conformance/filter-v2/runtime/delta-empty-noop/expected.arrow +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/conformance/filter-v2/runtime/delta-empty-noop/filter.arrow +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/conformance/filter-v2/runtime/delta-empty-noop/input.arrow +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/conformance/filter-v2/runtime/delta-upsert-remove-stale/delta-0.arrow +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/conformance/filter-v2/runtime/delta-upsert-remove-stale/delta-1.arrow +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/conformance/filter-v2/runtime/delta-upsert-remove-stale/delta-2.arrow +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/conformance/filter-v2/runtime/delta-upsert-remove-stale/expected.arrow +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/conformance/filter-v2/runtime/delta-upsert-remove-stale/filter.arrow +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/conformance/filter-v2/runtime/delta-upsert-remove-stale/input.arrow +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/conformance/filter-v2/runtime/empty-snapshot/expected.arrow +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/conformance/filter-v2/runtime/empty-snapshot/filter.arrow +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/conformance/filter-v2/runtime/empty-snapshot/input.arrow +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/conformance/filter-v2/runtime/empty-snapshot/worker-expected.arrow +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/conformance/filter-v2/runtime/error-cast-type-not-null/filter.arrow +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/conformance/filter-v2/runtime/error-cast-type-not-null/input.arrow +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/conformance/filter-v2/runtime/error-column-index/filter.arrow +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/conformance/filter-v2/runtime/error-column-index/input.arrow +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/conformance/filter-v2/runtime/error-column-name/filter.arrow +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/conformance/filter-v2/runtime/error-column-name/input.arrow +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/conformance/filter-v2/runtime/error-contextual-cast-without-session/filter.arrow +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/conformance/filter-v2/runtime/error-contextual-cast-without-session/input.arrow +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/conformance/filter-v2/runtime/error-duplicate-predicate-id/filter.arrow +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/conformance/filter-v2/runtime/error-duplicate-predicate-id/input.arrow +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/conformance/filter-v2/runtime/error-external-column-index/filter.arrow +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/conformance/filter-v2/runtime/error-external-column-index/input.arrow +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/conformance/filter-v2/runtime/error-external-column-index/join-keys-0.arrow +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/conformance/filter-v2/runtime/error-external-column-name/filter.arrow +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/conformance/filter-v2/runtime/error-external-column-name/input.arrow +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/conformance/filter-v2/runtime/error-external-column-name/join-keys-0.arrow +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/conformance/filter-v2/runtime/error-field-non-struct/filter.arrow +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/conformance/filter-v2/runtime/error-field-non-struct/input.arrow +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/conformance/filter-v2/runtime/error-in-payload-not-list/filter.arrow +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/conformance/filter-v2/runtime/error-in-payload-not-list/input.arrow +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/conformance/filter-v2/runtime/error-in-payload-null-list/filter.arrow +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/conformance/filter-v2/runtime/error-in-payload-null-list/input.arrow +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/conformance/filter-v2/runtime/error-invalid-overload/filter.arrow +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/conformance/filter-v2/runtime/error-invalid-overload/input.arrow +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/conformance/filter-v2/runtime/error-missing-literal/filter.arrow +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/conformance/filter-v2/runtime/error-missing-literal/input.arrow +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/conformance/filter-v2/runtime/error-non-boolean-root/filter.arrow +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/conformance/filter-v2/runtime/error-non-boolean-root/input.arrow +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/conformance/filter-v2/runtime/error-unknown-standard-function/filter.arrow +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/conformance/filter-v2/runtime/error-unknown-standard-function/input.arrow +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/conformance/filter-v2/runtime/external-in-nonzero-column/expected.arrow +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/conformance/filter-v2/runtime/external-in-nonzero-column/filter.arrow +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/conformance/filter-v2/runtime/external-in-nonzero-column/input.arrow +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/conformance/filter-v2/runtime/external-in-nonzero-column/join-keys-0.arrow +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/conformance/filter-v2/runtime/external-in-nonzero-column/worker-expected.arrow +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/conformance/filter-v2/runtime/function-contains/expected.arrow +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/conformance/filter-v2/runtime/function-contains/filter.arrow +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/conformance/filter-v2/runtime/function-contains/input.arrow +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/conformance/filter-v2/runtime/function-ends-with/expected.arrow +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/conformance/filter-v2/runtime/function-ends-with/filter.arrow +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/conformance/filter-v2/runtime/function-ends-with/input.arrow +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/conformance/filter-v2/runtime/function-list-contains/expected.arrow +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/conformance/filter-v2/runtime/function-list-contains/filter.arrow +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/conformance/filter-v2/runtime/function-list-contains/input.arrow +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/conformance/filter-v2/runtime/function-starts-with/expected.arrow +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/conformance/filter-v2/runtime/function-starts-with/filter.arrow +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/conformance/filter-v2/runtime/function-starts-with/input.arrow +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/conformance/filter-v2/runtime/in-empty/expected.arrow +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/conformance/filter-v2/runtime/in-empty/filter.arrow +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/conformance/filter-v2/runtime/in-empty/input.arrow +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/conformance/filter-v2/runtime/in-empty/worker-expected.arrow +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/conformance/filter-v2/runtime/in-with-null/expected.arrow +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/conformance/filter-v2/runtime/in-with-null/filter.arrow +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/conformance/filter-v2/runtime/in-with-null/input.arrow +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/conformance/filter-v2/runtime/in-with-null/worker-expected.arrow +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/conformance/filter-v2/runtime/is-not-null/expected.arrow +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/conformance/filter-v2/runtime/is-not-null/filter.arrow +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/conformance/filter-v2/runtime/is-not-null/input.arrow +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/conformance/filter-v2/runtime/is-not-null/worker-expected.arrow +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/conformance/filter-v2/runtime/is-null/expected.arrow +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/conformance/filter-v2/runtime/is-null/filter.arrow +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/conformance/filter-v2/runtime/is-null/input.arrow +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/conformance/filter-v2/runtime/is-null/worker-expected.arrow +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/conformance/filter-v2/runtime/kleene-and/expected.arrow +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/conformance/filter-v2/runtime/kleene-and/filter.arrow +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/conformance/filter-v2/runtime/kleene-and/input.arrow +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/conformance/filter-v2/runtime/kleene-not/expected.arrow +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/conformance/filter-v2/runtime/kleene-not/filter.arrow +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/conformance/filter-v2/runtime/kleene-not/input.arrow +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/conformance/filter-v2/runtime/kleene-or/expected.arrow +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/conformance/filter-v2/runtime/kleene-or/filter.arrow +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/conformance/filter-v2/runtime/kleene-or/input.arrow +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/conformance/filter-v2/runtime/nan-comparison/expected.arrow +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/conformance/filter-v2/runtime/nan-comparison/filter.arrow +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/conformance/filter-v2/runtime/nan-comparison/input.arrow +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/conformance/filter-v2/runtime/negative-zero-membership/expected.arrow +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/conformance/filter-v2/runtime/negative-zero-membership/filter.arrow +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/conformance/filter-v2/runtime/negative-zero-membership/input.arrow +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/conformance/filter-v2/runtime/nested-null-propagation/expected.arrow +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/conformance/filter-v2/runtime/nested-null-propagation/filter.arrow +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/conformance/filter-v2/runtime/nested-null-propagation/input.arrow +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/conformance/filter-v2/runtime/not-in-empty/expected.arrow +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/conformance/filter-v2/runtime/not-in-empty/filter.arrow +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/conformance/filter-v2/runtime/not-in-empty/input.arrow +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/conformance/filter-v2/runtime/not-in-empty/worker-expected.arrow +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/conformance/filter-v2/runtime/not-in-with-null/expected.arrow +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/conformance/filter-v2/runtime/not-in-with-null/filter.arrow +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/conformance/filter-v2/runtime/not-in-with-null/input.arrow +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/conformance/filter-v2/runtime/not-in-with-null/worker-expected.arrow +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/conformance/filter-v2/runtime/session-integer-division/expected.arrow +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/conformance/filter-v2/runtime/session-integer-division/filter.arrow +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/conformance/filter-v2/runtime/session-integer-division/input.arrow +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/conformance/filter-v2/runtime-manifest.json +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/dist-vgi/.gitignore +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/docs/aggregate-functions.md +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/docs/api/arguments.md +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/docs/api/auth.md +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/docs/api/catalogs.md +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/docs/api/client.md +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/docs/api/exceptions.md +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/docs/api/filters.md +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/docs/api/functions.md +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/docs/api/http.md +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/docs/api/index.md +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/docs/api/metadata.md +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/docs/api/observability.md +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/docs/api/storage.md +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/docs/api/transactor.md +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/docs/api/worker.md +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/docs/argument-serialization.md +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/docs/assets/apple-touch-icon.png +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/docs/assets/favicon-16x16.png +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/docs/assets/favicon-32x32.png +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/docs/assets/favicon.ico +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/docs/assets/kinds/aggregate.svg +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/docs/assets/kinds/buffering.svg +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/docs/assets/kinds/scalar.svg +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/docs/assets/kinds/table-in-out.svg +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/docs/assets/kinds/table.svg +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/docs/assets/logo.png +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/docs/assets/social-card.png +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/docs/assets/video-thumbnail.jpg +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/docs/authentication.md +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/docs/catalog-interface.md +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/docs/catalog_publication.md +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/docs/cli.md +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/docs/column-statistics.md +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/docs/concepts/index.md +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/docs/contributing-docs.md +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/docs/design/reporting-protocols/IMPLEMENTATION.md +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/docs/design/reporting-protocols/README.md +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/docs/design/reporting-protocols/alerts.md +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/docs/design/reporting-protocols/attach-tickets-plan.md +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/docs/design/reporting-protocols/credentials.md +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/docs/design/reporting-protocols/notify.md +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/docs/design/reporting-protocols/prerequisites.md +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/docs/design/reporting-protocols/render.md +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/docs/design/reporting-protocols/reporting-protocols.html +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/docs/design/reporting-protocols/reports.md +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/docs/design/reporting-protocols/schedules.md +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/docs/design/reporting-protocols/sql_tasks.md +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/docs/filter-pushdown.md +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/docs/global-functions.md +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/docs/how-to/catalogs.md +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/docs/how-to/function-patterns.md +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/docs/how-to/http-auth.md +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/docs/how-to/index.md +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/docs/how-to/iroh.md +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/docs/how-to/pushdown-and-statistics.md +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/docs/how-to/state-storage.md +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/docs/how-to/tailnet.md +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/docs/index.md +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/docs/lifecycle.md +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/docs/overrides/main.html +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/docs/protocol/index.md +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/docs/protocol/vgi-attach-tickets.md +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/docs/protocol/vgi-catalog-query-pushdown-design.md +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/docs/protocol/vgi-duckdb-filter-adapter.md +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/docs/protocol/vgi-filter-encoding-v2-spec.md +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/docs/protocol/vgi-opaque-data-sealing.md +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/docs/protocol/vgi-protocol-proposed-changes.md +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/docs/protocol/vgi-runtime-filter-artifacts.md +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/docs/protocol/vgi-secrets.md +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/docs/robots.txt +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/docs/shared-storage.md +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/docs/stylesheets/extra.css +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/docs/tutorial/index.md +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/docs/tutorial/scalar.md +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/docs/tutorial/table.md +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/docs/vgi-logo.png +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/examples/batch_index_worker.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/examples/cache_worker.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/examples/calc_scalar_worker.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/examples/calc_worker.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/examples/copy_format_worker.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/examples/filter_worker.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/examples/greeting_scalar_worker.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/examples/row_count_worker.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/examples/series_streaming_worker.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/examples/sum_worker.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/identity.png +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/mkdocs.yml +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/packages/vgi-fixtures/LICENSE +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/packages/vgi-fixtures/README.md +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/packages/vgi-fixtures/docker/Dockerfile +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/packages/vgi-fixtures/docker/docker-entrypoint.sh +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/scripts/build_reporting_protocols_html.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/scripts/catalog_publication_fixture.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/scripts/gen_attach_ticket_vectors.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/scripts/hosted_protocols_conformance.sh +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/scripts/measure_startup.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/scripts/run_all_tests.sh +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/test-data/generate.sh +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/tests/__init__.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/tests/_hosted_protocols_worker.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/tests/_http_fixtures.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/tests/catalog/__init__.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/tests/catalog/test_attach_option.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/tests/catalog/test_catalog_contents.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/tests/catalog/test_catalog_interface.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/tests/catalog/test_catalog_publication.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/tests/catalog/test_client_catalog.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/tests/catalog/test_client_load_catalog.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/tests/catalog/test_column_statistics.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/tests/catalog/test_declarative.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/tests/catalog/test_example_worker_catalog.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/tests/catalog/test_function_info_binary_dictionary.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/tests/catalog/test_integration.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/tests/catalog/test_required_filters.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/tests/catalog/test_scan_branches.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/tests/catalog/test_serialization.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/tests/catalog/test_setting.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/tests/catalog/test_storage.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/tests/catalog/test_time_travel.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/tests/catalog/test_writable_table.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/tests/client/__init__.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/tests/client/test_aggregate_client.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/tests/client/test_batch_metadata_callback.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/tests/client/test_bind_and_join_keys.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/tests/client/test_broken_pipe.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/tests/client/test_cli.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/tests/client/test_cli_catalog_functions.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/tests/client/test_copy_client.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/tests/client/test_http_response_budget.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/tests/client/test_iroh_client.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/tests/client/test_scan_branches_client.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/tests/client/test_split_client.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/tests/client/test_stop_force.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/tests/client/test_table_column_statistics.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/tests/client/test_time_travel_client.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/tests/client/test_worker_debug.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/tests/conformance/__init__.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/tests/conformance/_stub.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/tests/conformance/conftest.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/tests/conformance/test_accumulate.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/tests/conformance/test_aggregate.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/tests/conformance/test_attach.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/tests/conformance/test_bearer_auth.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/tests/conformance/test_const_param_enforcement.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/tests/conformance/test_container.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/tests/conformance/test_copy_from.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/tests/conformance/test_copy_to.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/tests/conformance/test_directory_parity.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/tests/conformance/test_function_inventory.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/tests/conformance/test_github.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/tests/conformance/test_http_client.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/tests/conformance/test_http_external_location.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/tests/conformance/test_http_upload_url.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/tests/conformance/test_macro.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/tests/conformance/test_overload.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/tests/conformance/test_protocol_inventory.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/tests/conformance/test_protocol_version.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/tests/conformance/test_resumable_scan.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/tests/conformance/test_scalar.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/tests/conformance/test_scalar_attach_opaque_data.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/tests/conformance/test_secret.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/tests/conformance/test_settings.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/tests/conformance/test_splits.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/tests/conformance/test_table.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/tests/conformance/test_table_in_out.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/tests/conformance/test_view.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/tests/conformance/test_writable.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/tests/conftest.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/tests/data/split_tokens/anchor_len_overrun.bin +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/tests/data/split_tokens/bad_fingerprint.bin +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/tests/data/split_tokens/bad_flags_unsealed_but_key_present.bin +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/tests/data/split_tokens/bad_version.bin +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/tests/data/split_tokens/generate.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/tests/data/split_tokens/manifest.json +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/tests/data/split_tokens/reserved_flag_bit.bin +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/tests/data/split_tokens/stale_anchor.bin +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/tests/data/split_tokens/truncated.bin +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/tests/data/split_tokens/valid_sealed.bin +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/tests/data/split_tokens/valid_unsealed.bin +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/tests/scalar/__init__.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/tests/scalar/test_bernoulli_function.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/tests/scalar/test_binary_packet_function.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/tests/scalar/test_client.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/tests/scalar/test_conditional_message_function.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/tests/scalar/test_hash_seed_function.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/tests/scalar/test_multiply_by_setting_function.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/tests/scalar/test_multiply_function.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/tests/scalar/test_random_bytes_function.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/tests/scalar/test_return_secret_value_function.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/tests/sdk_conformance/__init__.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/tests/sdk_conformance/test_opaque_sealing.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/tests/sdk_conformance/test_opaque_sealing_stdio.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/tests/table/__init__.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/tests/table/generator/__init__.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/tests/table/generator/test_constant_columns_function.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/tests/table/generator/test_double_sequence_function.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/tests/table/generator/test_exception_function.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/tests/table/generator/test_filter_echo_function.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/tests/table/generator/test_logging_function.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/tests/table/generator/test_nested_sequence_function.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/tests/table/generator/test_partitioned_function.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/tests/table/generator/test_projected_data_function.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/tests/table/generator/test_sequence_function.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/tests/table/generator/test_settings_function.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/tests/table/generator/test_struct_settings_function.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/tests/table/generator/test_ten_thousand_function.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/tests/table/test_wide_columns.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/tests/table_in_out/__init__.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/tests/table_in_out/generator/__init__.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/tests/table_in_out/generator/test_buffer_input_function.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/tests/table_in_out/generator/test_echo_function.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/tests/table_in_out/generator/test_exception_functions.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/tests/table_in_out/generator/test_filter_by_setting_function.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/tests/table_in_out/generator/test_repeat_inputs_function.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/tests/table_in_out/generator/test_substream_partial_sum_function.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/tests/table_in_out/generator/test_sum_all_columns_function.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/tests/table_in_out/test_blended_exchange.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/tests/table_in_out/test_blended_metadata.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/tests/table_in_out/test_client.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/tests/table_in_out/test_table_buffering_empty_input.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/tests/tailnet/Dockerfile +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/tests/tailnet/__init__.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/tests/tailnet/compose.yaml +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/tests/tailnet/probe.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/tests/tailnet/run.sh +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/tests/tailnet/test_worker.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/tests/tailnet/worker.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/tests/test_access_log_audit.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/tests/test_aggregate_function.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/tests/test_argument_spec.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/tests/test_attach_ticket.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/tests/test_auth.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/tests/test_bind_exceptions.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/tests/test_bind_request_at_clause.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/tests/test_bound_storage_conformance.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/tests/test_cache_control.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/tests/test_call_state_attach.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/tests/test_catalog_auth_binding.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/tests/test_client_oauth.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/tests/test_client_reflection.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/tests/test_codegen_request_inventory.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/tests/test_copy_from_function.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/tests/test_copy_to_function.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/tests/test_docstrings.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/tests/test_documentation_examples.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/tests/test_dynamic_filter_http_turns.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/tests/test_error_codes.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/tests/test_example_function_arg_types.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/tests/test_exception_handling.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/tests/test_exceptions.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/tests/test_filter_pushdown.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/tests/test_filter_pushdown_extension.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/tests/test_filter_v2.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/tests/test_filter_v2_builder.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/tests/test_filter_v2_runtime_corpus.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/tests/test_filter_v2_spec_schema.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/tests/test_fixture_catalog_parity.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/tests/test_function_shape_mismatch.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/tests/test_function_storage.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/tests/test_function_storage_azure_sql.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/tests/test_function_storage_cf_do.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/tests/test_function_storage_cf_do_integration.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/tests/test_function_storage_conformance.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/tests/test_function_subclass_check.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/tests/test_generated_cpp_constants.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/tests/test_generated_cpp_protocol_name.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/tests/test_generated_cpp_protocol_version.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/tests/test_generated_cpp_records.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/tests/test_generated_cpp_request_builders.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/tests/test_generated_cpp_schemas.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/tests/test_generated_cpp_secret.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/tests/test_generated_csharp.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/tests/test_generated_go_schemas.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/tests/test_generated_go_types.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/tests/test_generated_java_schemas.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/tests/test_generated_java_types.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/tests/test_generated_protocol_version.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/tests/test_generated_registry.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/tests/test_generated_rust_request_builders.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/tests/test_generated_rust_schemas.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/tests/test_generated_rust_types.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/tests/test_generated_schemas_cross_lang.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/tests/test_generated_ts_client.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/tests/test_generated_ts_schemas.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/tests/test_generated_ts_types.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/tests/test_grant_auth.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/tests/test_hosted_protocols.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/tests/test_http_demo_storage.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/tests/test_http_s3_offload_input.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/tests/test_http_s3_offload_output.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/tests/test_import_side_effects.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/tests/test_landing_discovery.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/tests/test_launch_transport.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/tests/test_metadata.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/tests/test_mypy_consolidated.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/tests/test_nest_tensor.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/tests/test_otel.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/tests/test_projection_enforcement.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/tests/test_projection_repro.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/tests/test_protocol_classes.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/tests/test_resolved_secrets.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/tests/test_schema_paths_v2.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/tests/test_schema_scoped_functions.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/tests/test_schema_utils.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/tests/test_serve.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/tests/test_setting_secret_annotations.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/tests/test_signing_key.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/tests/test_split_token.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/tests/test_subprocess_transport.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/tests/test_table_buffering_function.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/tests/test_table_function_dynamic_to_string.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/tests/test_table_function_early_close.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/tests/test_tcp_transport.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/tests/test_type_bounds.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/tests/test_union_argument.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/tests/test_wire_record_schema_parity.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/tests/test_worker.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/tests/test_worker_cli.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/tests/test_worker_page.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/tests/test_write_results.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/tests/transactor/__init__.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/tests/transactor/test_transactor.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/vgi/__init__.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/vgi/_duckdb.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/vgi/_redact.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/vgi/_storage_profile.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/vgi/_test_fixtures/__init__.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/vgi/_test_fixtures/accumulate/__init__.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/vgi/_test_fixtures/accumulate/worker.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/vgi/_test_fixtures/aggregate/__init__.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/vgi/_test_fixtures/aggregate/_common.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/vgi/_test_fixtures/aggregate/basic.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/vgi/_test_fixtures/aggregate/dynamic.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/vgi/_test_fixtures/aggregate/generic.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/vgi/_test_fixtures/aggregate/listagg.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/vgi/_test_fixtures/aggregate/percentile.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/vgi/_test_fixtures/aggregate/same_name.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/vgi/_test_fixtures/aggregate/secret_typed.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/vgi/_test_fixtures/aggregate/streaming.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/vgi/_test_fixtures/aggregate/varargs.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/vgi/_test_fixtures/aggregate/window.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/vgi/_test_fixtures/attach_options.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/vgi/_test_fixtures/attach_ticket_vectors.json +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/vgi/_test_fixtures/bad_enum.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/vgi/_test_fixtures/bad_protocol.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/vgi/_test_fixtures/cancellable.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/vgi/_test_fixtures/catalog.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/vgi/_test_fixtures/catalog_contents.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/vgi/_test_fixtures/catalog_publication.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/vgi/_test_fixtures/companion.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/vgi/_test_fixtures/copy_from.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/vgi/_test_fixtures/copy_to.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/vgi/_test_fixtures/global_functions.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/vgi/_test_fixtures/http_server.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/vgi/_test_fixtures/identity_fixture.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/vgi/_test_fixtures/narrow_bind/__init__.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/vgi/_test_fixtures/narrow_bind/worker.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/vgi/_test_fixtures/nest_tensor.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/vgi/_test_fixtures/orchard_catalog.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/vgi/_test_fixtures/projection_repro/__init__.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/vgi/_test_fixtures/projection_repro/worker.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/vgi/_test_fixtures/scalar/__init__.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/vgi/_test_fixtures/scalar/_common.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/vgi/_test_fixtures/scalar/arithmetic.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/vgi/_test_fixtures/scalar/bench_ladder.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/vgi/_test_fixtures/scalar/binary.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/vgi/_test_fixtures/scalar/formatting.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/vgi/_test_fixtures/scalar/geo.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/vgi/_test_fixtures/scalar/null_handling.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/vgi/_test_fixtures/scalar/random_demo.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/vgi/_test_fixtures/scalar/same_name.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/vgi/_test_fixtures/scalar/settings_secrets.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/vgi/_test_fixtures/scalar/type_info.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/vgi/_test_fixtures/schema_reconcile/__init__.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/vgi/_test_fixtures/schema_reconcile/worker.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/vgi/_test_fixtures/secret_cache.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/vgi/_test_fixtures/simple_writable.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/vgi/_test_fixtures/table/__init__.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/vgi/_test_fixtures/table/_common.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/vgi/_test_fixtures/table/batch_index.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/vgi/_test_fixtures/table/batch_index_broken.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/vgi/_test_fixtures/table/catalog_scans.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/vgi/_test_fixtures/table/filters.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/vgi/_test_fixtures/table/late_materialization.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/vgi/_test_fixtures/table/make_series.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/vgi/_test_fixtures/table/misc.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/vgi/_test_fixtures/table/order_modes.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/vgi/_test_fixtures/table/pairs.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/vgi/_test_fixtures/table/partition_columns.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/vgi/_test_fixtures/table/partition_columns_broken.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/vgi/_test_fixtures/table/profiling_example.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/vgi/_test_fixtures/table/required_filters.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/vgi/_test_fixtures/table/same_name_cached.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/vgi/_test_fixtures/table/same_name_schemas.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/vgi/_test_fixtures/table/sequence.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/vgi/_test_fixtures/table/settings.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/vgi/_test_fixtures/table/splits.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/vgi/_test_fixtures/table/transaction_storage.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/vgi/_test_fixtures/table/tt_pushdown.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/vgi/_test_fixtures/table/typed_probe.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/vgi/_test_fixtures/table/versioned.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/vgi/_test_fixtures/table/wide.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/vgi/_test_fixtures/table_in_out_same_name.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/vgi/_test_fixtures/ticket_probe.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/vgi/_test_fixtures/twin_catalogs.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/vgi/_test_fixtures/versioned.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/vgi/_test_fixtures/versioned_tables.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/vgi/_test_fixtures/writable/__init__.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/vgi/_test_fixtures/writable/generic.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/vgi/_test_fixtures/writable/table.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/vgi/_test_fixtures/writable/worker.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/vgi/aggregate_function.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/vgi/argument_spec.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/vgi/arguments.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/vgi/attach_header.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/vgi/attach_ticket.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/vgi/auth.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/vgi/cache_control.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/vgi/catalog/__init__.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/vgi/catalog/_descriptor_spec.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/vgi/catalog/attach_option.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/vgi/catalog/contents_codec.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/vgi/catalog/contract.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/vgi/catalog/descriptors.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/vgi/catalog/duckdb_statistics.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/vgi/catalog/secret_type.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/vgi/catalog/setting.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/vgi/catalog/snapshot.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/vgi/catalog/storage.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/vgi/client/__init__.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/vgi/client/aggregate.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/vgi/client/catalog_mixin.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/vgi/client/cli.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/vgi/client/cli_catalog.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/vgi/client/cli_schema.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/vgi/client/cli_table.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/vgi/client/cli_transaction.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/vgi/client/cli_utils.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/vgi/client/cli_view.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/vgi/client/errors.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/vgi/codegen/__init__.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/vgi/codegen/_common.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/vgi/codegen/_registry.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/vgi/codegen/_registry_backend.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/vgi/codegen/cpp_constants.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/vgi/codegen/cpp_protocol_name.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/vgi/codegen/cpp_protocol_version.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/vgi/codegen/cpp_records.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/vgi/codegen/cpp_registry.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/vgi/codegen/cpp_request_builders.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/vgi/codegen/cpp_schemas.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/vgi/codegen/cpp_secret_protocol_version.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/vgi/codegen/cpp_secret_request_builders.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/vgi/codegen/cpp_secret_schemas.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/vgi/codegen/csharp_registry.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/vgi/codegen/csharp_schemas.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/vgi/codegen/csharp_types.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/vgi/codegen/go_registry.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/vgi/codegen/go_schemas.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/vgi/codegen/go_types.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/vgi/codegen/java_registry.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/vgi/codegen/java_schemas.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/vgi/codegen/java_types.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/vgi/codegen/protocol_version.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/vgi/codegen/rust_registry.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/vgi/codegen/rust_request_builders.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/vgi/codegen/rust_schemas.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/vgi/codegen/rust_types.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/vgi/codegen/ts_client.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/vgi/codegen/ts_registry.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/vgi/codegen/ts_schemas.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/vgi/codegen/ts_types.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/vgi/copy_from_function.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/vgi/copy_to_function.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/vgi/exceptions.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/vgi/filter_v2.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/vgi/filter_v2_builder.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/vgi/function.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/vgi/function_storage.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/vgi/function_storage_azure_sql.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/vgi/function_storage_cf_do.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/vgi/http/__init__.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/vgi/http/demo_storage.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/vgi/http/landing.html +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/vgi/http/landing_page.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/vgi/http/vgi-client.js +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/vgi/http/worker_page.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/vgi/invocation.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/vgi/logging_config.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/vgi/meta_worker.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/vgi/otel.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/vgi/profiling.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/vgi/protocol_version.txt +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/vgi/py.typed +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/vgi/rpc_server.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/vgi/scalar_function.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/vgi/schema_path.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/vgi/schema_utils.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/vgi/secret_protocol.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/vgi/secret_service.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/vgi/serve.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/vgi/split_token.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/vgi/table_buffering_function.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/vgi/table_filter_pushdown.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/vgi/table_function.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/vgi/transactor/__init__.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/vgi/transactor/_duckdb_compat.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/vgi/transactor/client.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/vgi/transactor/protocol.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/vgi/transactor/server.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/vgi/worker.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/vgi/write_results.py +0 -0
- {vgi_python-0.46.1 → vgi_python-0.47.0}/wrangler.jsonc +0 -0
|
@@ -27,7 +27,7 @@ concurrency:
|
|
|
27
27
|
env:
|
|
28
28
|
# The test suite and native Actions artifact must come from this exact ref.
|
|
29
29
|
# The downloader verifies its provenance against the checked-out commit.
|
|
30
|
-
VGI_REF:
|
|
30
|
+
VGI_REF: fc3e08f7e7fd800165a0edc00313de46fed15329
|
|
31
31
|
# CI is not a user: its ATTACHes should not land in Query.Farm's adoption data.
|
|
32
32
|
# The vgi extension fires a telemetry event per successful ATTACH, and this
|
|
33
33
|
# suite performs several hundred of them per lane, so opting out keeps the
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: vgi-python
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.47.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
|
|
@@ -275,15 +275,33 @@ class SumFunction(TableInOutFunction):
|
|
|
275
275
|
)]
|
|
276
276
|
```
|
|
277
277
|
|
|
278
|
-
**Multiple outputs per input (
|
|
279
|
-
```python
|
|
280
|
-
from vgi_rpc.rpc import OutputCollector
|
|
278
|
+
**Multiple outputs per input (`more=True` and `resume()`):**
|
|
281
279
|
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
280
|
+
Each call still emits exactly one batch. To return several for one input
|
|
281
|
+
batch, emit the first with `more=True`; the framework then calls `resume()`,
|
|
282
|
+
with no input, for each next batch until one is emitted without `more=True`.
|
|
283
|
+
`resume()` continues from `state` alone, so the function must declare a
|
|
284
|
+
serializable `TState`; over HTTP it travels in the stream's state token, so
|
|
285
|
+
store positions to resume from, not output rows. A function with `resume()`
|
|
286
|
+
cannot set `max_workers = 1`: the client runs such a function on one connection
|
|
287
|
+
shared by every pipeline, which cannot leave output pending.
|
|
288
|
+
|
|
289
|
+
```python test="skip"
|
|
290
|
+
@classmethod
|
|
291
|
+
def process(cls, params, state, batch, out) -> None:
|
|
292
|
+
state.pages = plan_pages(batch) # where each page starts: small
|
|
293
|
+
cls.resume(params, state, out)
|
|
294
|
+
|
|
295
|
+
@classmethod
|
|
296
|
+
def resume(cls, params, state, out) -> None:
|
|
297
|
+
page = fetch(state.pages.pop(0))
|
|
298
|
+
out.emit(page.batch, parent_rows=page.parent_rows, more=bool(state.pages))
|
|
285
299
|
```
|
|
286
300
|
|
|
301
|
+
On the wire the reply carries `vgi.status: HAVE_MORE_OUTPUT` and the client
|
|
302
|
+
asks for the next batch with a zero-row input carrying `vgi.status: CONTINUE`.
|
|
303
|
+
While output is pending that tick is the only valid input.
|
|
304
|
+
|
|
287
305
|
**In-band logging via OutputCollector:**
|
|
288
306
|
```python
|
|
289
307
|
from vgi_rpc.rpc import OutputCollector
|
|
@@ -80,6 +80,7 @@ info = SumValuesFunction.describe()
|
|
|
80
80
|
| `tags` | `dict[str, str]` | `{}` | Custom key-value tags |
|
|
81
81
|
| `examples` | `list` | `[]` | SQL examples (str or FunctionExample) |
|
|
82
82
|
| `max_workers` | `int\|None` | `None` (unlimited) | Max parallel workers |
|
|
83
|
+
| `input_rows_per_call` | `int\|None` | `None` (a whole chunk) | `RowTransformFunction` only: most input rows per worker call; the client splits each chunk into calls of at most this many rows |
|
|
83
84
|
| `stability` | `FunctionStability` | `CONSISTENT` | Output determinism |
|
|
84
85
|
| `null_handling` | `NullHandling` | `DEFAULT` | NULL input behavior |
|
|
85
86
|
| `argument_monotonicity` | `list[ArgumentMonotonicity]\|None` | `None` | Scalar-only monotonicity claims in argument declaration order |
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
# /// script
|
|
2
|
+
# requires-python = ">=3.13"
|
|
3
|
+
# dependencies = ["vgi-python"]
|
|
4
|
+
# ///
|
|
5
|
+
"""A lateral function backed by a paged API, returning one API page per reply.
|
|
6
|
+
|
|
7
|
+
``orders(customer_id)`` lists a customer's orders from an API that returns them a
|
|
8
|
+
page at a time behind a cursor. Rather than fetching every page before replying,
|
|
9
|
+
``process()`` fetches the first page and emits it with ``more=True``; the framework
|
|
10
|
+
then calls ``resume()`` for each next page. The state holds only where to resume
|
|
11
|
+
(which input row, which page cursor), never fetched rows, so it is small enough to
|
|
12
|
+
travel in an HTTP state token.
|
|
13
|
+
|
|
14
|
+
ATTACH 'shop' (TYPE vgi, LOCATION 'uv run paged_api_worker.py');
|
|
15
|
+
SELECT c.id, o.order_id, o.total
|
|
16
|
+
FROM (VALUES (1), (2), (3)) c(id), shop.orders(c.id) o;
|
|
17
|
+
"""
|
|
18
|
+
|
|
19
|
+
from dataclasses import dataclass
|
|
20
|
+
from typing import Annotated, Any, cast
|
|
21
|
+
|
|
22
|
+
import pyarrow as pa
|
|
23
|
+
from vgi_rpc import ArrowSerializableDataclass
|
|
24
|
+
|
|
25
|
+
from vgi import Arg, Worker
|
|
26
|
+
from vgi.catalog import Catalog, Schema
|
|
27
|
+
from vgi.invocation import BindResponse
|
|
28
|
+
from vgi.table_function import BindParams, ProcessParams
|
|
29
|
+
from vgi.table_in_out_function import OutputCollector, RowTransformFunction
|
|
30
|
+
|
|
31
|
+
PAGE_SIZE = 5
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
def fetch_orders_page(customer_id: int, cursor: str) -> tuple[list[dict[str, Any]], str]:
|
|
35
|
+
"""Stand-in for an HTTP API: one page of a customer's orders and the next cursor.
|
|
36
|
+
|
|
37
|
+
Customer ``n`` has ``7 * n`` orders. An empty next cursor means the last page.
|
|
38
|
+
"""
|
|
39
|
+
start = int(cursor or "0")
|
|
40
|
+
total = 7 * customer_id
|
|
41
|
+
orders = [
|
|
42
|
+
{"order_id": customer_id * 1000 + k, "total": round(10.0 + k * 2.5, 2)}
|
|
43
|
+
for k in range(start, min(start + PAGE_SIZE, total))
|
|
44
|
+
]
|
|
45
|
+
end = start + len(orders)
|
|
46
|
+
return orders, str(end) if end < total else ""
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
@dataclass(slots=True, frozen=True, kw_only=True)
|
|
50
|
+
class OrdersArgs:
|
|
51
|
+
"""One positional input column: the customer to list orders for."""
|
|
52
|
+
|
|
53
|
+
customer_id: Annotated[int, Arg(0, doc="Customer whose orders to list")]
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
@dataclass(kw_only=True)
|
|
57
|
+
class OrdersCursor(ArrowSerializableDataclass):
|
|
58
|
+
"""Where the next reply resumes: the input's customer ids, a row, and that row's page cursor."""
|
|
59
|
+
|
|
60
|
+
customer_ids: list[int] | None = None
|
|
61
|
+
row: int = 0
|
|
62
|
+
cursor: str = ""
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
class Orders(RowTransformFunction[OrdersArgs, OrdersCursor]):
|
|
66
|
+
"""List each input customer's orders, one API page per reply."""
|
|
67
|
+
|
|
68
|
+
@classmethod
|
|
69
|
+
def on_bind(cls, params: BindParams[OrdersArgs]) -> BindResponse:
|
|
70
|
+
"""A fixed output schema."""
|
|
71
|
+
return BindResponse(output_schema=pa.schema([("order_id", pa.int64()), ("total", pa.float64())]))
|
|
72
|
+
|
|
73
|
+
@classmethod
|
|
74
|
+
def initial_state(cls, params: ProcessParams[OrdersArgs]) -> OrdersCursor:
|
|
75
|
+
"""An empty cursor; ``process()`` fills it for each input batch."""
|
|
76
|
+
return OrdersCursor()
|
|
77
|
+
|
|
78
|
+
@classmethod
|
|
79
|
+
def process(
|
|
80
|
+
cls, params: ProcessParams[OrdersArgs], state: OrdersCursor, batch: pa.RecordBatch, out: OutputCollector
|
|
81
|
+
) -> None:
|
|
82
|
+
"""Start a new input batch at its first row, then emit the first page."""
|
|
83
|
+
state.customer_ids = [-1 if c is None else c for c in batch.column("customer_id").to_pylist()]
|
|
84
|
+
state.row = 0
|
|
85
|
+
state.cursor = ""
|
|
86
|
+
cls.resume(params, state, out)
|
|
87
|
+
|
|
88
|
+
@classmethod
|
|
89
|
+
def resume(cls, params: ProcessParams[OrdersArgs], state: OrdersCursor, out: OutputCollector) -> None:
|
|
90
|
+
"""Emit the next non-empty page, with ``more=True`` unless it is the last."""
|
|
91
|
+
ids = state.customer_ids or []
|
|
92
|
+
orders: list[dict[str, Any]] = []
|
|
93
|
+
row = state.row
|
|
94
|
+
while state.row < len(ids) and not orders:
|
|
95
|
+
row = state.row
|
|
96
|
+
orders, state.cursor = fetch_orders_page(ids[row], state.cursor) if ids[row] > 0 else ([], "")
|
|
97
|
+
if not state.cursor: # that customer is done: the next page starts the next row
|
|
98
|
+
state.row += 1
|
|
99
|
+
# Every row of a page came from one input row; parent_rows says which.
|
|
100
|
+
cast(Any, out).emit(
|
|
101
|
+
pa.RecordBatch.from_pylist(orders, schema=params.output_schema),
|
|
102
|
+
parent_rows=[row] * len(orders),
|
|
103
|
+
more=state.row < len(ids),
|
|
104
|
+
)
|
|
105
|
+
|
|
106
|
+
|
|
107
|
+
class ShopWorker(Worker):
|
|
108
|
+
"""A worker exposing the ``shop`` catalog with the paged ``orders`` function."""
|
|
109
|
+
|
|
110
|
+
catalog = Catalog(
|
|
111
|
+
name="shop",
|
|
112
|
+
schemas=[Schema(path=["main"], functions=[Orders])],
|
|
113
|
+
)
|
|
114
|
+
|
|
115
|
+
|
|
116
|
+
if __name__ == "__main__":
|
|
117
|
+
ShopWorker().run()
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
# and the conformance suite import it by its normal `vgi._test_fixtures` path.
|
|
9
9
|
[project]
|
|
10
10
|
name = "vgi-fixtures"
|
|
11
|
-
version = "0.
|
|
11
|
+
version = "0.47.0"
|
|
12
12
|
description = "Example/test VGI worker modules and entry points (not for production use)"
|
|
13
13
|
readme = "README.md"
|
|
14
14
|
# Local copy of the repo-root LICENSE (kept in sync): the build can't reach
|
|
@@ -16,7 +16,11 @@ and only then written.
|
|
|
16
16
|
|
|
17
17
|
Targets in sibling repos that are not checked out are skipped, not failed:
|
|
18
18
|
nobody has all of them. A registry backend's ``root_env`` (``VGI_JAVA_ROOT``,
|
|
19
|
-
``VGI_TYPESCRIPT_ROOT``, ...) points its SDK target at another checkout
|
|
19
|
+
``VGI_TYPESCRIPT_ROOT``, ...) points its SDK target at another checkout, as does
|
|
20
|
+
``--root REPO=PATH``. ``--only REPO`` (repeatable) limits the run to those repos,
|
|
21
|
+
so regenerating one SDK's worktree writes nothing into any other checkout:
|
|
22
|
+
|
|
23
|
+
uv run python scripts/regen_generated.py --only vgi-go --root vgi-go=~/Development/vgi-go-feature
|
|
20
24
|
"""
|
|
21
25
|
|
|
22
26
|
from __future__ import annotations
|
|
@@ -96,9 +100,9 @@ _ROOT_ENV: dict[str, str] = {b.repo: b.root_env for b in _REGISTRY_BACKENDS}
|
|
|
96
100
|
_ROOT_ENV.setdefault("vgi", "VGI_EXTENSION_ROOT")
|
|
97
101
|
|
|
98
102
|
|
|
99
|
-
def _repo_root(name: str) -> Path | None:
|
|
103
|
+
def _repo_root(name: str, roots: dict[str, str]) -> Path | None:
|
|
100
104
|
"""Locate a sibling checkout, or ``None`` when it is not present."""
|
|
101
|
-
override = os.environ.get(_ROOT_ENV.get(name, ""))
|
|
105
|
+
override = roots.get(name) or os.environ.get(_ROOT_ENV.get(name, ""))
|
|
102
106
|
if override:
|
|
103
107
|
return Path(override) if Path(override).is_dir() else None
|
|
104
108
|
siblings = Path(__file__).resolve().parents[2]
|
|
@@ -135,12 +139,38 @@ def main() -> int:
|
|
|
135
139
|
action="store_true",
|
|
136
140
|
help="report drift without writing anything (exit 1 if any file is stale)",
|
|
137
141
|
)
|
|
142
|
+
parser.add_argument(
|
|
143
|
+
"--only",
|
|
144
|
+
action="append",
|
|
145
|
+
default=[],
|
|
146
|
+
metavar="REPO",
|
|
147
|
+
help="only these repos' targets (repeatable), e.g. --only vgi-go",
|
|
148
|
+
)
|
|
149
|
+
parser.add_argument(
|
|
150
|
+
"--root",
|
|
151
|
+
action="append",
|
|
152
|
+
default=[],
|
|
153
|
+
metavar="REPO=PATH",
|
|
154
|
+
help="the checkout to use for REPO (repeatable), e.g. --root vgi-go=../vgi-go-feature",
|
|
155
|
+
)
|
|
138
156
|
args = parser.parse_args()
|
|
157
|
+
known = {repo for _, _, repo in _TARGETS}
|
|
158
|
+
unknown = set(args.only) - known
|
|
159
|
+
if unknown:
|
|
160
|
+
parser.error(f"--only: unknown repo(s) {sorted(unknown)}; known: {sorted(known)}")
|
|
161
|
+
roots: dict[str, str] = {}
|
|
162
|
+
for spec in args.root:
|
|
163
|
+
repo, sep, path = spec.partition("=")
|
|
164
|
+
if not sep or repo not in known:
|
|
165
|
+
parser.error(f"--root expects REPO=PATH with REPO one of {sorted(known)}, got {spec!r}")
|
|
166
|
+
roots[repo] = str(Path(path).expanduser())
|
|
139
167
|
|
|
140
168
|
stale, wrote, skipped, failed = [], [], [], []
|
|
141
169
|
|
|
142
170
|
for module_name, relative, repo in _TARGETS:
|
|
143
|
-
|
|
171
|
+
if args.only and repo not in args.only:
|
|
172
|
+
continue
|
|
173
|
+
root = _repo_root(repo, roots)
|
|
144
174
|
if root is None:
|
|
145
175
|
skipped.append(f"{repo} (not checked out)")
|
|
146
176
|
continue
|
|
@@ -0,0 +1,391 @@
|
|
|
1
|
+
# Copyright 2025, 2026 Query Farm LLC - https://query.farm
|
|
2
|
+
|
|
3
|
+
"""Continued output: several replies for one table-in-out input batch.
|
|
4
|
+
|
|
5
|
+
A function emits ``out.emit(..., more=True)`` and the framework calls its
|
|
6
|
+
``resume()`` for each next batch. Each batch is its own reply; the client
|
|
7
|
+
fetches the next one with a zero-row ``vgi.status: CONTINUE`` tick.
|
|
8
|
+
``blended_paged`` is the fixture: ``blended_explode``'s output, ``page_size``
|
|
9
|
+
rows per reply.
|
|
10
|
+
"""
|
|
11
|
+
|
|
12
|
+
from __future__ import annotations
|
|
13
|
+
|
|
14
|
+
from collections.abc import Callable, Sequence
|
|
15
|
+
from dataclasses import dataclass
|
|
16
|
+
from typing import Annotated, Any
|
|
17
|
+
|
|
18
|
+
import pyarrow as pa
|
|
19
|
+
import pytest
|
|
20
|
+
from vgi_rpc import ArrowSerializableDataclass
|
|
21
|
+
from vgi_rpc.rpc import AnnotatedBatch, OutputCollector
|
|
22
|
+
|
|
23
|
+
from tests.conftest import make_schema
|
|
24
|
+
from vgi.arguments import Arg, Arguments, TableInput
|
|
25
|
+
from vgi.cache_control import CacheControl
|
|
26
|
+
from vgi.client import Client
|
|
27
|
+
from vgi.client.client import ClientError
|
|
28
|
+
from vgi.invocation import BindResponse
|
|
29
|
+
from vgi.metadata import resolve_metadata
|
|
30
|
+
from vgi.protocol import (
|
|
31
|
+
CONTINUE,
|
|
32
|
+
STATUS_KEY,
|
|
33
|
+
_FilteringOutputCollector,
|
|
34
|
+
_TrackingOutputCollector,
|
|
35
|
+
)
|
|
36
|
+
from vgi.schema_utils import schema
|
|
37
|
+
from vgi.table_function import BindParams, ProcessParams
|
|
38
|
+
from vgi.table_in_out_function import RowTransformFunction, TableInOutGenerator
|
|
39
|
+
|
|
40
|
+
_INPUT_SCHEMA = make_schema([pa.field("n", pa.int64())])
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
def _expected_pairs(counts: Sequence[int | None]) -> list[tuple[int, int]]:
|
|
44
|
+
return [(row, k) for row, n in enumerate(counts) for k in range(n or 0)]
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
def _run_paged(
|
|
48
|
+
client: Client,
|
|
49
|
+
monkeypatch: pytest.MonkeyPatch,
|
|
50
|
+
batches: Sequence[Sequence[int | None]],
|
|
51
|
+
page_size: int,
|
|
52
|
+
) -> tuple[list[tuple[int, int]], list[int]]:
|
|
53
|
+
"""Run ``blended_paged``; return (parent_row, value) pairs and replies per input batch."""
|
|
54
|
+
replies: list[int] = []
|
|
55
|
+
original = Client._process_batch_on_worker
|
|
56
|
+
|
|
57
|
+
def counting(self: Client, *args: Any, **kwargs: Any) -> Any:
|
|
58
|
+
outputs, parent_rows = original(self, *args, **kwargs)
|
|
59
|
+
replies.append(len(outputs))
|
|
60
|
+
return outputs, parent_rows
|
|
61
|
+
|
|
62
|
+
monkeypatch.setattr(Client, "_process_batch_on_worker", counting)
|
|
63
|
+
parent_rows_seen: list[int] = []
|
|
64
|
+
with client:
|
|
65
|
+
results = list(
|
|
66
|
+
client.table_in_out_function(
|
|
67
|
+
function_name="blended_paged",
|
|
68
|
+
schema_path=["main"],
|
|
69
|
+
input=iter(
|
|
70
|
+
[pa.RecordBatch.from_pydict({"n": list(counts)}, schema=_INPUT_SCHEMA) for counts in batches]
|
|
71
|
+
),
|
|
72
|
+
arguments=Arguments(named={"page_size": pa.scalar(page_size)}),
|
|
73
|
+
parent_row_callback=parent_rows_seen.extend,
|
|
74
|
+
)
|
|
75
|
+
)
|
|
76
|
+
values: list[Any] = [v for batch in results for v in batch.column("i").to_pylist()]
|
|
77
|
+
return list(zip(parent_rows_seen, values, strict=True)), replies
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
class TestContinuedOutput:
|
|
81
|
+
"""A client that accepts more output gets one reply per page."""
|
|
82
|
+
|
|
83
|
+
def test_pages_cover_the_output_in_order(
|
|
84
|
+
self, client_transport: Callable[[], Client], monkeypatch: pytest.MonkeyPatch
|
|
85
|
+
) -> None:
|
|
86
|
+
"""Every transport, including HTTP, where the cursor rides the state token."""
|
|
87
|
+
counts = [0, 1, 3, 2, 0, 4]
|
|
88
|
+
pairs, replies = _run_paged(client_transport(), monkeypatch, [counts], page_size=2)
|
|
89
|
+
assert pairs == _expected_pairs(counts)
|
|
90
|
+
assert replies == [5] # 10 rows, 2 per reply
|
|
91
|
+
|
|
92
|
+
def test_each_input_batch_pages_independently(
|
|
93
|
+
self, client_transport: Callable[[], Client], monkeypatch: pytest.MonkeyPatch
|
|
94
|
+
) -> None:
|
|
95
|
+
"""A second input batch starts over: provenance indexes its own rows."""
|
|
96
|
+
pairs, replies = _run_paged(client_transport(), monkeypatch, [[3], [1, 2]], page_size=2)
|
|
97
|
+
assert pairs == _expected_pairs([3]) + _expected_pairs([1, 2])
|
|
98
|
+
assert replies == [2, 2]
|
|
99
|
+
|
|
100
|
+
@pytest.mark.parametrize(("page_size", "expected_replies"), [(1, 10), (3, 4), (4, 3), (10, 1), (100, 1)])
|
|
101
|
+
def test_page_size_sets_the_reply_count(
|
|
102
|
+
self,
|
|
103
|
+
client_transport: Callable[[], Client],
|
|
104
|
+
monkeypatch: pytest.MonkeyPatch,
|
|
105
|
+
page_size: int,
|
|
106
|
+
expected_replies: int,
|
|
107
|
+
) -> None:
|
|
108
|
+
"""10 output rows: one reply per page_size rows, pages crossing input rows."""
|
|
109
|
+
counts = [0, 1, 3, 2, 0, 4]
|
|
110
|
+
pairs, replies = _run_paged(client_transport(), monkeypatch, [counts], page_size=page_size)
|
|
111
|
+
assert pairs == _expected_pairs(counts)
|
|
112
|
+
assert replies == [expected_replies]
|
|
113
|
+
|
|
114
|
+
def test_null_and_trailing_empty_rows_add_no_reply(
|
|
115
|
+
self, fixture_worker: str, monkeypatch: pytest.MonkeyPatch
|
|
116
|
+
) -> None:
|
|
117
|
+
"""NULL counts as 0, and rows with no output after the last page add no empty reply."""
|
|
118
|
+
counts: list[int | None] = [None, 2, 0, 0]
|
|
119
|
+
pairs, replies = _run_paged(Client(fixture_worker), monkeypatch, [counts], page_size=2)
|
|
120
|
+
assert pairs == _expected_pairs(counts)
|
|
121
|
+
assert replies == [1]
|
|
122
|
+
|
|
123
|
+
def test_invalid_page_size_is_refused_at_bind(self, fixture_worker: str, monkeypatch: pytest.MonkeyPatch) -> None:
|
|
124
|
+
"""page_size := 0 fails at bind, before any exchange."""
|
|
125
|
+
with pytest.raises(ClientError, match="page_size must be at least 1"):
|
|
126
|
+
_run_paged(Client(fixture_worker), monkeypatch, [[3]], page_size=0)
|
|
127
|
+
|
|
128
|
+
def test_output_that_fits_one_page_is_one_reply(self, fixture_worker: str, monkeypatch: pytest.MonkeyPatch) -> None:
|
|
129
|
+
"""A function that never says more=True answers with a single reply."""
|
|
130
|
+
pairs, replies = _run_paged(Client(fixture_worker), monkeypatch, [[2, 1]], page_size=10)
|
|
131
|
+
assert pairs == _expected_pairs([2, 1])
|
|
132
|
+
assert replies == [1]
|
|
133
|
+
|
|
134
|
+
def test_no_output_is_one_empty_reply(self, fixture_worker: str, monkeypatch: pytest.MonkeyPatch) -> None:
|
|
135
|
+
"""No output rows at all is one empty reply, not a page followed by an empty one."""
|
|
136
|
+
pairs, replies = _run_paged(Client(fixture_worker), monkeypatch, [[0, 0]], page_size=2)
|
|
137
|
+
assert pairs == []
|
|
138
|
+
assert replies == [1]
|
|
139
|
+
|
|
140
|
+
|
|
141
|
+
def _tick() -> AnnotatedBatch:
|
|
142
|
+
return AnnotatedBatch(
|
|
143
|
+
batch=pa.RecordBatch.from_pydict({"n": []}, schema=_INPUT_SCHEMA),
|
|
144
|
+
custom_metadata=pa.KeyValueMetadata({STATUS_KEY: CONTINUE}),
|
|
145
|
+
)
|
|
146
|
+
|
|
147
|
+
|
|
148
|
+
def _real(*counts: int) -> AnnotatedBatch:
|
|
149
|
+
return AnnotatedBatch(batch=pa.RecordBatch.from_pydict({"n": list(counts)}, schema=_INPUT_SCHEMA))
|
|
150
|
+
|
|
151
|
+
|
|
152
|
+
class TestOutOfTurnInput:
|
|
153
|
+
"""While output is pending only a tick is valid, and a tick only then."""
|
|
154
|
+
|
|
155
|
+
@staticmethod
|
|
156
|
+
def _send(fixture_worker: str, monkeypatch: pytest.MonkeyPatch, sequence: list[AnnotatedBatch]) -> None:
|
|
157
|
+
"""Send ``sequence`` raw on one blended_paged stream (page_size 2); the last must be refused."""
|
|
158
|
+
|
|
159
|
+
def send(self: Client, worker: Any, input_batch: pa.RecordBatch, *args: Any, **kwargs: Any) -> Any:
|
|
160
|
+
from vgi_rpc.rpc import RpcError
|
|
161
|
+
|
|
162
|
+
try:
|
|
163
|
+
for batch in sequence:
|
|
164
|
+
worker.stream.exchange(batch)
|
|
165
|
+
except RpcError as e:
|
|
166
|
+
raise ClientError.from_rpc_error(e) from e
|
|
167
|
+
raise AssertionError("the worker accepted out-of-turn input")
|
|
168
|
+
|
|
169
|
+
monkeypatch.setattr(Client, "_process_batch_on_worker", send)
|
|
170
|
+
with Client(fixture_worker) as client:
|
|
171
|
+
list(
|
|
172
|
+
client.table_in_out_function(
|
|
173
|
+
function_name="blended_paged",
|
|
174
|
+
schema_path=["main"],
|
|
175
|
+
input=iter([_real(3).batch]),
|
|
176
|
+
)
|
|
177
|
+
)
|
|
178
|
+
|
|
179
|
+
def test_tick_without_pending_output_is_refused(self, fixture_worker: str, monkeypatch: pytest.MonkeyPatch) -> None:
|
|
180
|
+
"""A tick before any reply said HAVE_MORE_OUTPUT is a protocol error."""
|
|
181
|
+
with pytest.raises(ClientError, match="no output is pending"):
|
|
182
|
+
self._send(fixture_worker, monkeypatch, [_tick()])
|
|
183
|
+
|
|
184
|
+
def test_tick_after_the_last_page_is_refused(self, fixture_worker: str, monkeypatch: pytest.MonkeyPatch) -> None:
|
|
185
|
+
"""3 rows in pages of 2: the second reply is the last, so a third tick is refused."""
|
|
186
|
+
with pytest.raises(ClientError, match="no output is pending"):
|
|
187
|
+
self._send(fixture_worker, monkeypatch, [_real(3), _tick(), _tick()])
|
|
188
|
+
|
|
189
|
+
def test_input_while_output_is_pending_is_refused(
|
|
190
|
+
self, fixture_worker: str, monkeypatch: pytest.MonkeyPatch
|
|
191
|
+
) -> None:
|
|
192
|
+
"""Skipping the pending pages with new input would lose them: refused."""
|
|
193
|
+
with pytest.raises(ClientError, match="while output is pending"):
|
|
194
|
+
self._send(fixture_worker, monkeypatch, [_real(3), _real(1)])
|
|
195
|
+
|
|
196
|
+
|
|
197
|
+
@dataclass(slots=True, frozen=True, kw_only=True)
|
|
198
|
+
class _NArgs:
|
|
199
|
+
n: Annotated[int, Arg(0)]
|
|
200
|
+
|
|
201
|
+
|
|
202
|
+
@dataclass(slots=True, frozen=True, kw_only=True)
|
|
203
|
+
class _TableArgs:
|
|
204
|
+
data: Annotated[TableInput, Arg(0)]
|
|
205
|
+
|
|
206
|
+
|
|
207
|
+
@dataclass(kw_only=True)
|
|
208
|
+
class _CursorState(ArrowSerializableDataclass):
|
|
209
|
+
row: int = 0
|
|
210
|
+
|
|
211
|
+
|
|
212
|
+
class TestResumeRegistration:
|
|
213
|
+
"""resume() continues from state alone, so it needs a serializable TState."""
|
|
214
|
+
|
|
215
|
+
def test_resume_without_state_is_refused(self) -> None:
|
|
216
|
+
"""Without a TState the cursor would be lost between HTTP turns."""
|
|
217
|
+
|
|
218
|
+
class _Stateless(RowTransformFunction[_NArgs]):
|
|
219
|
+
class Meta:
|
|
220
|
+
name = "stateless_resume"
|
|
221
|
+
|
|
222
|
+
@classmethod
|
|
223
|
+
def on_bind(cls, params: BindParams[_NArgs]) -> BindResponse:
|
|
224
|
+
return BindResponse(output_schema=schema({"i": pa.int64()}))
|
|
225
|
+
|
|
226
|
+
@classmethod
|
|
227
|
+
def resume(cls, params: ProcessParams[_NArgs], state: None, out: OutputCollector) -> None:
|
|
228
|
+
pass
|
|
229
|
+
|
|
230
|
+
with pytest.raises(TypeError, match="serializable TState"):
|
|
231
|
+
resolve_metadata(_Stateless)
|
|
232
|
+
|
|
233
|
+
def test_resume_with_max_workers_1_is_refused(self) -> None:
|
|
234
|
+
"""max_workers = 1 runs on one shared connection, which cannot continue."""
|
|
235
|
+
|
|
236
|
+
class _Serial(RowTransformFunction[_NArgs, _CursorState]):
|
|
237
|
+
class Meta:
|
|
238
|
+
name = "serial_resume"
|
|
239
|
+
max_workers = 1
|
|
240
|
+
|
|
241
|
+
@classmethod
|
|
242
|
+
def on_bind(cls, params: BindParams[_NArgs]) -> BindResponse:
|
|
243
|
+
return BindResponse(output_schema=schema({"i": pa.int64()}))
|
|
244
|
+
|
|
245
|
+
@classmethod
|
|
246
|
+
def resume(cls, params: ProcessParams[_NArgs], state: _CursorState, out: OutputCollector) -> None:
|
|
247
|
+
pass
|
|
248
|
+
|
|
249
|
+
with pytest.raises(TypeError, match="max_workers = 1"):
|
|
250
|
+
resolve_metadata(_Serial)
|
|
251
|
+
|
|
252
|
+
def test_resume_with_state_resolves(self) -> None:
|
|
253
|
+
"""RowTransformFunction[Args, State] is the supported shape."""
|
|
254
|
+
|
|
255
|
+
class _Stateful(RowTransformFunction[_NArgs, _CursorState]):
|
|
256
|
+
class Meta:
|
|
257
|
+
name = "stateful_resume"
|
|
258
|
+
|
|
259
|
+
@classmethod
|
|
260
|
+
def on_bind(cls, params: BindParams[_NArgs]) -> BindResponse:
|
|
261
|
+
return BindResponse(output_schema=schema({"i": pa.int64()}))
|
|
262
|
+
|
|
263
|
+
@classmethod
|
|
264
|
+
def resume(cls, params: ProcessParams[_NArgs], state: _CursorState, out: OutputCollector) -> None:
|
|
265
|
+
pass
|
|
266
|
+
|
|
267
|
+
assert resolve_metadata(_Stateful).input_from_args is True
|
|
268
|
+
|
|
269
|
+
|
|
270
|
+
class _RecordingCollector:
|
|
271
|
+
def __init__(self) -> None:
|
|
272
|
+
self.emits: list[dict[str, Any]] = []
|
|
273
|
+
|
|
274
|
+
def emit(self, batch: pa.RecordBatch, **kwargs: Any) -> None:
|
|
275
|
+
self.emits.append({"batch": batch, **kwargs})
|
|
276
|
+
|
|
277
|
+
|
|
278
|
+
class _MaskFilters:
|
|
279
|
+
"""Stands in for PushdownFilters: keeps the rows a fixed mask selects."""
|
|
280
|
+
|
|
281
|
+
def __init__(self, mask: list[bool]) -> None:
|
|
282
|
+
self._mask = pa.array(mask)
|
|
283
|
+
|
|
284
|
+
def __bool__(self) -> bool:
|
|
285
|
+
return True
|
|
286
|
+
|
|
287
|
+
def evaluate(self, batch: pa.RecordBatch) -> pa.BooleanArray:
|
|
288
|
+
return self._mask
|
|
289
|
+
|
|
290
|
+
|
|
291
|
+
class TestFilteredProvenance:
|
|
292
|
+
"""Auto-applied filters must drop the parent_rows of the rows they drop."""
|
|
293
|
+
|
|
294
|
+
def test_parent_rows_follow_the_filter(self) -> None:
|
|
295
|
+
"""Filtering rows 1 and 3 drops their provenance; more= passes through."""
|
|
296
|
+
inner = _RecordingCollector()
|
|
297
|
+
out = _FilteringOutputCollector(inner, RowTransformFunction, _MaskFilters([True, False, True, False])) # type: ignore[arg-type]
|
|
298
|
+
out.emit(pa.record_batch({"i": [10, 11, 12, 13]}), parent_rows=[0, 0, 1, 2], more=True)
|
|
299
|
+
[emit] = inner.emits
|
|
300
|
+
assert emit["batch"].column("i").to_pylist() == [10, 12]
|
|
301
|
+
assert emit["parent_rows"] == [0, 1]
|
|
302
|
+
assert emit["more"] is True
|
|
303
|
+
|
|
304
|
+
|
|
305
|
+
class _FakeOut:
|
|
306
|
+
"""The innermost collector: records what reaches the wire."""
|
|
307
|
+
|
|
308
|
+
def __init__(self) -> None:
|
|
309
|
+
self.emits: list[tuple[pa.RecordBatch, dict[str, str] | None]] = []
|
|
310
|
+
self.output_schema = pa.schema([pa.field("i", pa.int64())])
|
|
311
|
+
self.finished = False
|
|
312
|
+
|
|
313
|
+
def emit(self, batch: pa.RecordBatch, metadata: dict[str, str] | None = None) -> None:
|
|
314
|
+
self.emits.append((batch, metadata))
|
|
315
|
+
|
|
316
|
+
|
|
317
|
+
def _rows(*values: int) -> pa.RecordBatch:
|
|
318
|
+
return pa.record_batch({"i": pa.array(values, type=pa.int64())})
|
|
319
|
+
|
|
320
|
+
|
|
321
|
+
class TestCollectors:
|
|
322
|
+
"""The tracking collector's continuation rules."""
|
|
323
|
+
|
|
324
|
+
def test_more_sets_have_more_output(self) -> None:
|
|
325
|
+
"""more=True is the reply's vgi.status, and the collector remembers it."""
|
|
326
|
+
fake = _FakeOut()
|
|
327
|
+
out = _TrackingOutputCollector(fake, allows_more=True) # type: ignore[arg-type]
|
|
328
|
+
out.emit(_rows(1), more=True)
|
|
329
|
+
assert out.more is True
|
|
330
|
+
assert fake.emits[0][1] == {"vgi.status": "HAVE_MORE_OUTPUT"}
|
|
331
|
+
|
|
332
|
+
def test_more_is_refused_outside_a_table_in_out_exchange(self) -> None:
|
|
333
|
+
"""Only a table-in-out exchange is ever ticked, so more=True elsewhere is an error."""
|
|
334
|
+
fake = _FakeOut()
|
|
335
|
+
out = _TrackingOutputCollector(fake) # type: ignore[arg-type]
|
|
336
|
+
with pytest.raises(ValueError, match="only valid in a table-in-out"):
|
|
337
|
+
out.emit(_rows(1), more=True)
|
|
338
|
+
assert fake.emits == []
|
|
339
|
+
|
|
340
|
+
def test_cache_control_is_refused_on_a_continuation(self) -> None:
|
|
341
|
+
"""A reply to a tick is never an input's first batch, so it can't carry cache_control."""
|
|
342
|
+
out = _TrackingOutputCollector(_FakeOut(), continuation=True) # type: ignore[arg-type]
|
|
343
|
+
with pytest.raises(RuntimeError, match="only valid on the first emitted batch"):
|
|
344
|
+
out.emit(_rows(1), cache_control=CacheControl(ttl=60))
|
|
345
|
+
|
|
346
|
+
|
|
347
|
+
class TestInputRowsPerCall:
|
|
348
|
+
"""Meta.input_rows_per_call: a positive int, on a RowTransformFunction only."""
|
|
349
|
+
|
|
350
|
+
def test_declared_value_resolves_and_round_trips(self) -> None:
|
|
351
|
+
"""blended_sliced declares 3; it survives the Arrow and dict round-trips."""
|
|
352
|
+
from vgi._test_fixtures.table_in_out import BlendedSlicedFunction
|
|
353
|
+
from vgi.metadata import ResolvedMetadata, arrow_to_metadata, metadata_to_arrow
|
|
354
|
+
|
|
355
|
+
m = resolve_metadata(BlendedSlicedFunction)
|
|
356
|
+
assert m.input_rows_per_call == 3
|
|
357
|
+
assert arrow_to_metadata(metadata_to_arrow(m)).input_rows_per_call == 3
|
|
358
|
+
assert ResolvedMetadata.from_dict(m.to_dict()).input_rows_per_call == 3
|
|
359
|
+
|
|
360
|
+
def test_default_is_a_whole_chunk(self) -> None:
|
|
361
|
+
"""Undeclared means no limit: the client sends a whole chunk per call."""
|
|
362
|
+
from vgi._test_fixtures.table_in_out import BlendedPagedFunction
|
|
363
|
+
|
|
364
|
+
assert resolve_metadata(BlendedPagedFunction).input_rows_per_call is None
|
|
365
|
+
|
|
366
|
+
@pytest.mark.parametrize("value", [0, -1, True, 2.5, "3"])
|
|
367
|
+
def test_non_positive_or_non_int_is_refused(self, value: object) -> None:
|
|
368
|
+
"""Only a positive int is a row count."""
|
|
369
|
+
|
|
370
|
+
class _Bad(RowTransformFunction[_NArgs]):
|
|
371
|
+
class Meta:
|
|
372
|
+
name = "bad_rows_per_call"
|
|
373
|
+
input_rows_per_call = value
|
|
374
|
+
|
|
375
|
+
@classmethod
|
|
376
|
+
def on_bind(cls, params: BindParams[_NArgs]) -> BindResponse:
|
|
377
|
+
return BindResponse(output_schema=schema({"i": pa.int64()}))
|
|
378
|
+
|
|
379
|
+
with pytest.raises(ValueError, match="must be a positive int"):
|
|
380
|
+
resolve_metadata(_Bad)
|
|
381
|
+
|
|
382
|
+
def test_refused_outside_a_row_transform_function(self) -> None:
|
|
383
|
+
"""A classic table-in-out function receives DuckDB's chunks as they are."""
|
|
384
|
+
|
|
385
|
+
class _Classic(TableInOutGenerator[_TableArgs]):
|
|
386
|
+
class Meta:
|
|
387
|
+
name = "classic_rows_per_call"
|
|
388
|
+
input_rows_per_call = 3
|
|
389
|
+
|
|
390
|
+
with pytest.raises(TypeError, match="applies only to a RowTransformFunction"):
|
|
391
|
+
resolve_metadata(_Classic)
|