vgi-python 0.29.6__tar.gz → 0.31.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.29.6 → vgi_python-0.31.0}/PKG-INFO +2 -2
- {vgi_python-0.29.6 → vgi_python-0.31.0}/pyproject.toml +2 -2
- {vgi_python-0.29.6 → vgi_python-0.31.0}/tests/catalog/test_serialization.py +65 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/tests/client/test_batch_metadata_callback.py +1 -1
- {vgi_python-0.29.6 → vgi_python-0.31.0}/tests/client/test_scan_branches_client.py +8 -5
- {vgi_python-0.29.6 → vgi_python-0.31.0}/tests/client/test_time_travel_client.py +1 -1
- {vgi_python-0.29.6 → vgi_python-0.31.0}/tests/conformance/test_protocol_version.py +3 -3
- vgi_python-0.31.0/tests/test_client_oauth.py +204 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/tests/test_wire_record_schema_parity.py +2 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/uv.lock +5 -5
- vgi_python-0.31.0/vgi/_test_fixtures/table/same_name_schemas.py +136 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/vgi/_test_fixtures/worker.py +63 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/vgi/catalog/catalog_interface.py +51 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/vgi/catalog/descriptors.py +15 -4
- {vgi_python-0.29.6 → vgi_python-0.31.0}/vgi/client/client.py +112 -11
- {vgi_python-0.29.6 → vgi_python-0.31.0}/vgi/codegen/cpp_request_builders.py +1 -1
- {vgi_python-0.29.6 → vgi_python-0.31.0}/vgi/protocol.py +1 -1
- vgi_python-0.31.0/vgi/protocol_version.txt +1 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/vgi/worker.py +44 -15
- vgi_python-0.29.6/vgi/protocol_version.txt +0 -1
- {vgi_python-0.29.6 → vgi_python-0.31.0}/.gitattributes +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/.github/dependabot.yml +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/.github/styles/config/vocabularies/VGI/accept.txt +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/.github/workflows/ci.yml +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/.github/workflows/docs.yml +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/.github/workflows/integration.yml +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/.github/workflows/release.yml +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/.gitignore +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/.python-version +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/.vale.ini +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/CLAUDE.md +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/DOCS_ACCEPTANCE_CRITERIA.md +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/DOCS_REVIEW_RUBRIC.md +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/DOCS_USABILITY_TEST.md +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/LICENSE +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/README.md +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/RELEASE-RUNBOOK.md +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/SECURITY.md +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/ci/README.md +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/ci/preprocess-require.awk +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/ci/run-integration.sh +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/dist-vgi/.gitignore +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/docs/aggregate-functions.md +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/docs/api/arguments.md +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/docs/api/auth.md +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/docs/api/catalogs.md +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/docs/api/client.md +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/docs/api/exceptions.md +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/docs/api/filters.md +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/docs/api/functions.md +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/docs/api/http.md +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/docs/api/index.md +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/docs/api/metadata.md +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/docs/api/observability.md +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/docs/api/storage.md +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/docs/api/transactor.md +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/docs/api/worker.md +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/docs/argument-serialization.md +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/docs/assets/apple-touch-icon.png +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/docs/assets/favicon-16x16.png +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/docs/assets/favicon-32x32.png +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/docs/assets/favicon.ico +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/docs/assets/kinds/aggregate.svg +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/docs/assets/kinds/buffering.svg +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/docs/assets/kinds/scalar.svg +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/docs/assets/kinds/table-in-out.svg +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/docs/assets/kinds/table.svg +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/docs/assets/logo.png +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/docs/assets/social-card.png +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/docs/authentication.md +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/docs/catalog-interface.md +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/docs/cli.md +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/docs/column-statistics.md +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/docs/concepts/index.md +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/docs/contributing-docs.md +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/docs/filter-pushdown.md +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/docs/generator-api.md +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/docs/global-functions.md +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/docs/how-to/catalogs.md +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/docs/how-to/function-patterns.md +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/docs/how-to/http-auth.md +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/docs/how-to/index.md +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/docs/how-to/pushdown-and-statistics.md +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/docs/how-to/state-storage.md +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/docs/index.md +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/docs/lifecycle.md +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/docs/metadata.md +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/docs/overrides/main.html +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/docs/robots.txt +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/docs/shared-storage.md +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/docs/stylesheets/extra.css +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/docs/tutorial/index.md +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/docs/tutorial/scalar.md +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/docs/tutorial/table.md +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/docs/vgi-logo.png +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/examples/batch_index_worker.py +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/examples/cache_worker.py +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/examples/calc_scalar_worker.py +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/examples/calc_worker.py +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/examples/copy_format_worker.py +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/examples/filter_worker.py +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/examples/greeting_scalar_worker.py +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/examples/row_count_worker.py +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/examples/series_streaming_worker.py +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/examples/sum_worker.py +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/mkdocs.yml +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/packages/vgi-fixtures/LICENSE +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/packages/vgi-fixtures/README.md +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/packages/vgi-fixtures/docker/Dockerfile +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/packages/vgi-fixtures/docker/docker-entrypoint.sh +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/packages/vgi-fixtures/pyproject.toml +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/scripts/measure_startup.py +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/scripts/run_all_tests.sh +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/test-data/generate.sh +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/tests/__init__.py +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/tests/_http_fixtures.py +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/tests/catalog/__init__.py +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/tests/catalog/test_attach_option.py +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/tests/catalog/test_catalog_interface.py +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/tests/catalog/test_client_catalog.py +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/tests/catalog/test_column_statistics.py +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/tests/catalog/test_declarative.py +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/tests/catalog/test_example_worker_catalog.py +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/tests/catalog/test_integration.py +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/tests/catalog/test_required_filters.py +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/tests/catalog/test_scan_branches.py +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/tests/catalog/test_setting.py +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/tests/catalog/test_storage.py +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/tests/catalog/test_time_travel.py +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/tests/catalog/test_writable_table.py +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/tests/client/__init__.py +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/tests/client/test_aggregate_client.py +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/tests/client/test_broken_pipe.py +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/tests/client/test_cli.py +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/tests/client/test_cli_catalog_functions.py +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/tests/client/test_copy_client.py +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/tests/client/test_split_client.py +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/tests/client/test_stop_force.py +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/tests/client/test_table_column_statistics.py +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/tests/client/test_worker_debug.py +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/tests/conformance/__init__.py +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/tests/conformance/_stub.py +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/tests/conformance/conftest.py +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/tests/conformance/test_accumulate.py +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/tests/conformance/test_aggregate.py +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/tests/conformance/test_attach.py +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/tests/conformance/test_bearer_auth.py +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/tests/conformance/test_const_param_enforcement.py +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/tests/conformance/test_container.py +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/tests/conformance/test_copy_from.py +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/tests/conformance/test_copy_to.py +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/tests/conformance/test_directory_parity.py +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/tests/conformance/test_function_inventory.py +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/tests/conformance/test_github.py +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/tests/conformance/test_http_client.py +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/tests/conformance/test_http_external_location.py +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/tests/conformance/test_http_upload_url.py +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/tests/conformance/test_macro.py +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/tests/conformance/test_overload.py +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/tests/conformance/test_protocol_inventory.py +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/tests/conformance/test_resumable_scan.py +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/tests/conformance/test_scalar.py +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/tests/conformance/test_scalar_attach_opaque_data.py +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/tests/conformance/test_secret.py +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/tests/conformance/test_settings.py +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/tests/conformance/test_splits.py +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/tests/conformance/test_table.py +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/tests/conformance/test_table_in_out.py +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/tests/conformance/test_view.py +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/tests/conformance/test_writable.py +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/tests/conftest.py +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/tests/data/split_tokens/anchor_len_overrun.bin +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/tests/data/split_tokens/bad_fingerprint.bin +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/tests/data/split_tokens/bad_flags_unsealed_but_key_present.bin +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/tests/data/split_tokens/bad_version.bin +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/tests/data/split_tokens/generate.py +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/tests/data/split_tokens/manifest.json +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/tests/data/split_tokens/reserved_flag_bit.bin +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/tests/data/split_tokens/stale_anchor.bin +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/tests/data/split_tokens/truncated.bin +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/tests/data/split_tokens/valid_sealed.bin +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/tests/data/split_tokens/valid_unsealed.bin +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/tests/scalar/__init__.py +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/tests/scalar/test_bernoulli_function.py +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/tests/scalar/test_binary_packet_function.py +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/tests/scalar/test_client.py +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/tests/scalar/test_conditional_message_function.py +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/tests/scalar/test_hash_seed_function.py +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/tests/scalar/test_multiply_by_setting_function.py +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/tests/scalar/test_multiply_function.py +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/tests/scalar/test_random_bytes_function.py +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/tests/scalar/test_return_secret_value_function.py +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/tests/table/__init__.py +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/tests/table/generator/__init__.py +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/tests/table/generator/test_constant_columns_function.py +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/tests/table/generator/test_double_sequence_function.py +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/tests/table/generator/test_exception_function.py +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/tests/table/generator/test_filter_echo_function.py +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/tests/table/generator/test_logging_function.py +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/tests/table/generator/test_nested_sequence_function.py +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/tests/table/generator/test_partitioned_function.py +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/tests/table/generator/test_projected_data_function.py +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/tests/table/generator/test_sequence_function.py +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/tests/table/generator/test_settings_function.py +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/tests/table/generator/test_struct_settings_function.py +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/tests/table/generator/test_ten_thousand_function.py +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/tests/table/test_wide_columns.py +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/tests/table_in_out/__init__.py +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/tests/table_in_out/generator/__init__.py +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/tests/table_in_out/generator/test_buffer_input_function.py +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/tests/table_in_out/generator/test_echo_function.py +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/tests/table_in_out/generator/test_exception_functions.py +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/tests/table_in_out/generator/test_filter_by_setting_function.py +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/tests/table_in_out/generator/test_repeat_inputs_function.py +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/tests/table_in_out/generator/test_substream_partial_sum_function.py +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/tests/table_in_out/generator/test_sum_all_columns_function.py +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/tests/table_in_out/test_blended_exchange.py +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/tests/table_in_out/test_blended_metadata.py +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/tests/table_in_out/test_client.py +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/tests/test_access_log_audit.py +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/tests/test_aggregate_function.py +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/tests/test_argument_spec.py +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/tests/test_auth.py +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/tests/test_bind_exceptions.py +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/tests/test_bind_request_at_clause.py +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/tests/test_bound_storage_conformance.py +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/tests/test_cache_control.py +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/tests/test_call_state_attach.py +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/tests/test_catalog_auth_binding.py +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/tests/test_copy_from_function.py +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/tests/test_copy_to_function.py +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/tests/test_docstrings.py +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/tests/test_documentation_examples.py +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/tests/test_example_function_arg_types.py +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/tests/test_examples_workers.py +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/tests/test_exception_handling.py +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/tests/test_exceptions.py +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/tests/test_filter_pushdown.py +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/tests/test_filter_pushdown_extension.py +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/tests/test_fixture_catalog_parity.py +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/tests/test_function_storage.py +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/tests/test_function_storage_azure_sql.py +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/tests/test_function_storage_cf_do.py +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/tests/test_function_storage_cf_do_integration.py +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/tests/test_function_storage_conformance.py +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/tests/test_generated_cpp_constants.py +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/tests/test_generated_cpp_protocol_version.py +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/tests/test_generated_cpp_request_builders.py +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/tests/test_generated_cpp_schemas.py +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/tests/test_generated_cpp_secret.py +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/tests/test_generated_go_schemas.py +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/tests/test_generated_java_schemas.py +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/tests/test_generated_protocol_version.py +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/tests/test_generated_rust_request_builders.py +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/tests/test_generated_rust_schemas.py +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/tests/test_generated_schemas_cross_lang.py +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/tests/test_generated_ts_client.py +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/tests/test_generated_ts_schemas.py +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/tests/test_http_demo_storage.py +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/tests/test_http_s3_offload_input.py +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/tests/test_http_s3_offload_output.py +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/tests/test_launch_transport.py +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/tests/test_metadata.py +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/tests/test_mypy_consolidated.py +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/tests/test_nest_tensor.py +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/tests/test_otel.py +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/tests/test_projection_enforcement.py +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/tests/test_projection_repro.py +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/tests/test_protocol_classes.py +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/tests/test_resolved_secrets.py +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/tests/test_schema_scoped_functions.py +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/tests/test_schema_utils.py +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/tests/test_serve.py +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/tests/test_setting_secret_annotations.py +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/tests/test_signing_key.py +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/tests/test_split_token.py +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/tests/test_table_buffering_function.py +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/tests/test_table_function_dynamic_to_string.py +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/tests/test_tcp_transport.py +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/tests/test_type_bounds.py +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/tests/test_union_argument.py +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/tests/test_worker.py +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/tests/test_worker_cli.py +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/tests/test_worker_page.py +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/tests/transactor/__init__.py +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/tests/transactor/test_transactor.py +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/vgi/__init__.py +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/vgi/_duckdb.py +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/vgi/_storage_profile.py +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/vgi/_test_fixtures/__init__.py +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/vgi/_test_fixtures/accumulate/__init__.py +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/vgi/_test_fixtures/accumulate/worker.py +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/vgi/_test_fixtures/aggregate/__init__.py +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/vgi/_test_fixtures/aggregate/_common.py +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/vgi/_test_fixtures/aggregate/basic.py +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/vgi/_test_fixtures/aggregate/dynamic.py +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/vgi/_test_fixtures/aggregate/generic.py +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/vgi/_test_fixtures/aggregate/listagg.py +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/vgi/_test_fixtures/aggregate/percentile.py +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/vgi/_test_fixtures/aggregate/same_name.py +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/vgi/_test_fixtures/aggregate/secret_typed.py +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/vgi/_test_fixtures/aggregate/streaming.py +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/vgi/_test_fixtures/aggregate/varargs.py +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/vgi/_test_fixtures/aggregate/window.py +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/vgi/_test_fixtures/attach_options.py +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/vgi/_test_fixtures/bad_enum.py +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/vgi/_test_fixtures/bad_protocol.py +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/vgi/_test_fixtures/cancellable.py +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/vgi/_test_fixtures/catalog.py +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/vgi/_test_fixtures/companion.py +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/vgi/_test_fixtures/copy_from.py +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/vgi/_test_fixtures/copy_to.py +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/vgi/_test_fixtures/global_functions.py +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/vgi/_test_fixtures/http_server.py +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/vgi/_test_fixtures/narrow_bind/__init__.py +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/vgi/_test_fixtures/narrow_bind/worker.py +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/vgi/_test_fixtures/nest_tensor.py +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/vgi/_test_fixtures/orchard_catalog.py +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/vgi/_test_fixtures/projection_repro/__init__.py +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/vgi/_test_fixtures/projection_repro/worker.py +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/vgi/_test_fixtures/scalar/__init__.py +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/vgi/_test_fixtures/scalar/_common.py +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/vgi/_test_fixtures/scalar/arithmetic.py +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/vgi/_test_fixtures/scalar/bench_ladder.py +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/vgi/_test_fixtures/scalar/binary.py +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/vgi/_test_fixtures/scalar/formatting.py +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/vgi/_test_fixtures/scalar/geo.py +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/vgi/_test_fixtures/scalar/null_handling.py +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/vgi/_test_fixtures/scalar/random_demo.py +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/vgi/_test_fixtures/scalar/same_name.py +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/vgi/_test_fixtures/scalar/settings_secrets.py +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/vgi/_test_fixtures/scalar/type_info.py +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/vgi/_test_fixtures/schema_reconcile/__init__.py +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/vgi/_test_fixtures/schema_reconcile/worker.py +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/vgi/_test_fixtures/simple_writable.py +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/vgi/_test_fixtures/table/__init__.py +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/vgi/_test_fixtures/table/_common.py +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/vgi/_test_fixtures/table/batch_index.py +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/vgi/_test_fixtures/table/batch_index_broken.py +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/vgi/_test_fixtures/table/cache.py +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/vgi/_test_fixtures/table/catalog_scans.py +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/vgi/_test_fixtures/table/filters.py +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/vgi/_test_fixtures/table/late_materialization.py +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/vgi/_test_fixtures/table/make_series.py +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/vgi/_test_fixtures/table/misc.py +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/vgi/_test_fixtures/table/order_modes.py +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/vgi/_test_fixtures/table/pairs.py +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/vgi/_test_fixtures/table/partition_columns.py +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/vgi/_test_fixtures/table/partition_columns_broken.py +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/vgi/_test_fixtures/table/profiling_example.py +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/vgi/_test_fixtures/table/required_filters.py +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/vgi/_test_fixtures/table/same_name_cached.py +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/vgi/_test_fixtures/table/sequence.py +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/vgi/_test_fixtures/table/settings.py +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/vgi/_test_fixtures/table/splits.py +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/vgi/_test_fixtures/table/transaction_storage.py +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/vgi/_test_fixtures/table/tt_pushdown.py +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/vgi/_test_fixtures/table/typed_probe.py +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/vgi/_test_fixtures/table/versioned.py +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/vgi/_test_fixtures/table/wide.py +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/vgi/_test_fixtures/table_in_out.py +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/vgi/_test_fixtures/table_in_out_same_name.py +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/vgi/_test_fixtures/twin_catalogs.py +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/vgi/_test_fixtures/versioned.py +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/vgi/_test_fixtures/versioned_tables.py +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/vgi/_test_fixtures/writable/__init__.py +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/vgi/_test_fixtures/writable/generic.py +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/vgi/_test_fixtures/writable/table.py +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/vgi/_test_fixtures/writable/worker.py +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/vgi/aggregate_function.py +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/vgi/argument_spec.py +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/vgi/arguments.py +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/vgi/attach_header.py +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/vgi/auth.py +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/vgi/cache_control.py +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/vgi/catalog/__init__.py +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/vgi/catalog/_descriptor_spec.py +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/vgi/catalog/attach_option.py +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/vgi/catalog/duckdb_statistics.py +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/vgi/catalog/secret_type.py +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/vgi/catalog/setting.py +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/vgi/catalog/storage.py +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/vgi/client/__init__.py +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/vgi/client/aggregate.py +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/vgi/client/catalog_mixin.py +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/vgi/client/cli.py +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/vgi/client/cli_catalog.py +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/vgi/client/cli_schema.py +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/vgi/client/cli_table.py +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/vgi/client/cli_transaction.py +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/vgi/client/cli_utils.py +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/vgi/client/cli_view.py +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/vgi/client/errors.py +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/vgi/codegen/__init__.py +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/vgi/codegen/_common.py +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/vgi/codegen/cpp_constants.py +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/vgi/codegen/cpp_protocol_version.py +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/vgi/codegen/cpp_schemas.py +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/vgi/codegen/cpp_secret_protocol_version.py +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/vgi/codegen/cpp_secret_request_builders.py +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/vgi/codegen/cpp_secret_schemas.py +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/vgi/codegen/go_schemas.py +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/vgi/codegen/java_schemas.py +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/vgi/codegen/protocol_version.py +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/vgi/codegen/rust_request_builders.py +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/vgi/codegen/rust_schemas.py +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/vgi/codegen/ts_client.py +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/vgi/codegen/ts_schemas.py +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/vgi/copy_from_function.py +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/vgi/copy_to_function.py +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/vgi/exceptions.py +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/vgi/function.py +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/vgi/function_storage.py +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/vgi/function_storage_azure_sql.py +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/vgi/function_storage_cf_do.py +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/vgi/http/__init__.py +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/vgi/http/demo_storage.py +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/vgi/http/landing.html +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/vgi/http/landing_page.py +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/vgi/http/vgi-client.js +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/vgi/http/worker_page.py +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/vgi/invocation.py +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/vgi/logging_config.py +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/vgi/meta_worker.py +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/vgi/metadata.py +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/vgi/otel.py +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/vgi/profiling.py +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/vgi/py.typed +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/vgi/scalar_function.py +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/vgi/schema_utils.py +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/vgi/secret_protocol.py +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/vgi/secret_service.py +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/vgi/serve.py +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/vgi/split_token.py +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/vgi/table_buffering_function.py +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/vgi/table_filter_pushdown.py +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/vgi/table_function.py +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/vgi/table_in_out_function.py +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/vgi/transactor/__init__.py +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/vgi/transactor/_duckdb_compat.py +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/vgi/transactor/client.py +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/vgi/transactor/protocol.py +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/vgi/transactor/server.py +0 -0
- {vgi_python-0.29.6 → vgi_python-0.31.0}/wrangler.jsonc +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: vgi-python
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.31.0
|
|
4
4
|
Summary: Vector Gateway Interface - Connect DuckDB to external programs via Apache Arrow
|
|
5
5
|
Project-URL: Homepage, https://query.farm
|
|
6
6
|
Project-URL: Repository, https://github.com/Query-farm/vgi-python
|
|
@@ -162,7 +162,7 @@ Requires-Dist: httpx2>=2.9.1
|
|
|
162
162
|
Requires-Dist: platformdirs
|
|
163
163
|
Requires-Dist: pyarrow
|
|
164
164
|
Requires-Dist: typer>=0.9
|
|
165
|
-
Requires-Dist: vgi-rpc>=0.
|
|
165
|
+
Requires-Dist: vgi-rpc>=0.44.1
|
|
166
166
|
Provides-Extra: azure
|
|
167
167
|
Requires-Dist: azure-identity>=1.16.0; extra == 'azure'
|
|
168
168
|
Requires-Dist: pymssql>=2.3.0; extra == 'azure'
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "vgi-python"
|
|
3
|
-
version = "0.
|
|
3
|
+
version = "0.31.0"
|
|
4
4
|
description = "Vector Gateway Interface - Connect DuckDB to external programs via Apache Arrow"
|
|
5
5
|
readme = "README.md"
|
|
6
6
|
keywords = [
|
|
@@ -40,7 +40,7 @@ dependencies = [
|
|
|
40
40
|
"pyarrow",
|
|
41
41
|
"typer>=0.9",
|
|
42
42
|
"platformdirs",
|
|
43
|
-
"vgi-rpc>=0.
|
|
43
|
+
"vgi-rpc>=0.44.1",
|
|
44
44
|
"httpx2>=2.9.1",
|
|
45
45
|
]
|
|
46
46
|
|
|
@@ -1008,6 +1008,33 @@ class TestScanFunctionResultSerialization:
|
|
|
1008
1008
|
|
|
1009
1009
|
assert restored.required_extensions == ["iceberg", "parquet", "httpfs"]
|
|
1010
1010
|
|
|
1011
|
+
def test_schema_name_round_trip(self) -> None:
|
|
1012
|
+
"""schema_name (protocol 1.5.0) round-trips when set."""
|
|
1013
|
+
original = ScanFunctionResult(
|
|
1014
|
+
function_name="rowid_sequence",
|
|
1015
|
+
positional_arguments=[],
|
|
1016
|
+
named_arguments={},
|
|
1017
|
+
schema_name="main",
|
|
1018
|
+
)
|
|
1019
|
+
serialized = original.serialize()
|
|
1020
|
+
batch, _ = deserialize_record_batch(serialized)
|
|
1021
|
+
restored = ScanFunctionResult.deserialize(batch)
|
|
1022
|
+
|
|
1023
|
+
assert restored.schema_name == "main"
|
|
1024
|
+
|
|
1025
|
+
def test_schema_name_defaults_to_none(self) -> None:
|
|
1026
|
+
"""schema_name is None when the caller doesn't set it (e.g. a pre-1.5.0 peer)."""
|
|
1027
|
+
original = ScanFunctionResult(
|
|
1028
|
+
function_name="read_parquet",
|
|
1029
|
+
positional_arguments=[],
|
|
1030
|
+
named_arguments={},
|
|
1031
|
+
)
|
|
1032
|
+
serialized = original.serialize()
|
|
1033
|
+
batch, _ = deserialize_record_batch(serialized)
|
|
1034
|
+
restored = ScanFunctionResult.deserialize(batch)
|
|
1035
|
+
|
|
1036
|
+
assert restored.schema_name is None
|
|
1037
|
+
|
|
1011
1038
|
|
|
1012
1039
|
class TestSettingSpecSerialization:
|
|
1013
1040
|
"""Test SettingSpec serialization round-trip."""
|
|
@@ -1176,6 +1203,10 @@ class TestArrowSchemaCorrectness:
|
|
|
1176
1203
|
assert schema.field("function_name").type == pa.string()
|
|
1177
1204
|
assert schema.field("arguments").type == pa.binary()
|
|
1178
1205
|
assert schema.field("required_extensions").type == pa.list_(pa.string())
|
|
1206
|
+
# Added in protocol 1.5.0 — nullable so a pre-1.5.0 peer's payload
|
|
1207
|
+
# still deserializes (the column is simply absent there).
|
|
1208
|
+
assert schema.field("schema_name").type == pa.string()
|
|
1209
|
+
assert schema.field("schema_name").nullable is True
|
|
1179
1210
|
|
|
1180
1211
|
|
|
1181
1212
|
class TestScanBranchSerialization:
|
|
@@ -1192,6 +1223,10 @@ class TestScanBranchSerialization:
|
|
|
1192
1223
|
assert schema.field("branch_filter").nullable is True
|
|
1193
1224
|
assert schema.field("writable").type == pa.bool_()
|
|
1194
1225
|
assert schema.field("writable").nullable is False
|
|
1226
|
+
# Added in protocol 1.5.0 — function-branch only; None for a
|
|
1227
|
+
# catalog-table/format branch or a pre-1.5.0 peer.
|
|
1228
|
+
assert schema.field("schema_name").type == pa.string()
|
|
1229
|
+
assert schema.field("schema_name").nullable is True
|
|
1195
1230
|
|
|
1196
1231
|
def test_scan_branches_result_schema(self) -> None:
|
|
1197
1232
|
"""ScanBranchesResult Arrow schema: branches as list<binary>, required_extensions hoisted to top-level."""
|
|
@@ -1249,6 +1284,36 @@ class TestScanBranchSerialization:
|
|
|
1249
1284
|
assert restored.branch_filter == "ts >= TIMESTAMP '2026-05-15 00:00:00'"
|
|
1250
1285
|
assert len(restored.positional_arguments) == 2
|
|
1251
1286
|
|
|
1287
|
+
def test_scan_branch_schema_name_round_trip(self) -> None:
|
|
1288
|
+
"""A function branch's schema_name (protocol 1.5.0) round-trips when set."""
|
|
1289
|
+
from vgi.catalog import ScanBranch
|
|
1290
|
+
|
|
1291
|
+
original = ScanBranch(
|
|
1292
|
+
function_name="rowid_sequence",
|
|
1293
|
+
positional_arguments=[],
|
|
1294
|
+
named_arguments={},
|
|
1295
|
+
schema_name="main",
|
|
1296
|
+
)
|
|
1297
|
+
batch, _ = deserialize_record_batch(original.serialize())
|
|
1298
|
+
restored = ScanBranch.deserialize(batch)
|
|
1299
|
+
assert restored.schema_name == "main"
|
|
1300
|
+
|
|
1301
|
+
def test_scan_branch_schema_name_defaults_to_none(self) -> None:
|
|
1302
|
+
"""schema_name is None for a branch that doesn't set it (e.g. a catalog-table branch)."""
|
|
1303
|
+
from vgi.catalog import ScanBranch
|
|
1304
|
+
|
|
1305
|
+
original = ScanBranch(
|
|
1306
|
+
function_name="",
|
|
1307
|
+
positional_arguments=[],
|
|
1308
|
+
named_arguments={},
|
|
1309
|
+
source_catalog="lakehouse",
|
|
1310
|
+
source_schema="bronze",
|
|
1311
|
+
source_table="orders",
|
|
1312
|
+
)
|
|
1313
|
+
batch, _ = deserialize_record_batch(original.serialize())
|
|
1314
|
+
restored = ScanBranch.deserialize(batch)
|
|
1315
|
+
assert restored.schema_name is None
|
|
1316
|
+
|
|
1252
1317
|
def test_scan_branches_result_round_trip(self) -> None:
|
|
1253
1318
|
"""ScanBranchesResult round-trips two heterogeneous branches + required_extensions."""
|
|
1254
1319
|
from vgi.catalog import ScanBranch, ScanBranchesResult
|
|
@@ -69,7 +69,7 @@ def test_callback_sees_none_for_a_batch_without_custom_metadata(client: Any) ->
|
|
|
69
69
|
client.table_function(
|
|
70
70
|
function_name="sequence",
|
|
71
71
|
schema_name="main",
|
|
72
|
-
arguments=Arguments(positional=
|
|
72
|
+
arguments=Arguments(positional=(pa.scalar(4),)),
|
|
73
73
|
batch_metadata_callback=metas.append,
|
|
74
74
|
)
|
|
75
75
|
)
|
|
@@ -60,8 +60,11 @@ def test_single_branch_table_falls_back_to_legacy_rpc(client: Any) -> None:
|
|
|
60
60
|
name="numbers",
|
|
61
61
|
)
|
|
62
62
|
assert len(result.branches) == 1
|
|
63
|
-
assert
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
63
|
+
assert (
|
|
64
|
+
result.branches[0].function_name
|
|
65
|
+
== client.table_scan_function_get(
|
|
66
|
+
attach_opaque_data=_attach_opaque(client),
|
|
67
|
+
schema_name=DATA,
|
|
68
|
+
name="numbers",
|
|
69
|
+
).function_name
|
|
70
|
+
)
|
|
@@ -79,7 +79,7 @@ def test_table_function_with_no_at_clause_is_unaffected(client: Any) -> None:
|
|
|
79
79
|
"""The new `at_unit`/`at_value` params default to `None` — unchanged behavior without them."""
|
|
80
80
|
batches = list(
|
|
81
81
|
client.table_function(
|
|
82
|
-
function_name="sequence", schema_name="main", arguments=Arguments(positional=
|
|
82
|
+
function_name="sequence", schema_name="main", arguments=Arguments(positional=(pa.scalar(5),))
|
|
83
83
|
)
|
|
84
84
|
)
|
|
85
85
|
assert sum(b.num_rows for b in batches) == 5
|
|
@@ -32,14 +32,14 @@ CLIENT_PROTOCOL_VERSION = VgiProtocol.protocol_version
|
|
|
32
32
|
|
|
33
33
|
def test_client_protocol_version_is_canonical() -> None:
|
|
34
34
|
"""Sanity-check the constants this test reasons about haven't drifted apart."""
|
|
35
|
-
assert CLIENT_PROTOCOL_VERSION == "1.
|
|
35
|
+
assert CLIENT_PROTOCOL_VERSION == "1.5.0"
|
|
36
36
|
# The fixture must be a genuine mismatch in the major/minor that the
|
|
37
37
|
# framework compares; a patch-only difference would (correctly) pass.
|
|
38
38
|
assert BAD_PROTOCOL_VERSION.split(".")[:2] != CLIENT_PROTOCOL_VERSION.split(".")[:2]
|
|
39
39
|
|
|
40
40
|
|
|
41
41
|
def test_mismatched_worker_protocol_version_raises() -> None:
|
|
42
|
-
"""A worker enforcing 99.0.0 must reject the 1.
|
|
42
|
+
"""A worker enforcing 99.0.0 must reject the 1.5.0 client at dispatch."""
|
|
43
43
|
with Client("vgi-fixture-bad-protocol-worker") as client, pytest.raises(ClientError) as exc_info:
|
|
44
44
|
list(
|
|
45
45
|
client.table_function(
|
|
@@ -54,5 +54,5 @@ def test_mismatched_worker_protocol_version_raises() -> None:
|
|
|
54
54
|
assert "protocol_version mismatch" in message
|
|
55
55
|
assert CLIENT_PROTOCOL_VERSION in message
|
|
56
56
|
assert BAD_PROTOCOL_VERSION in message
|
|
57
|
-
# Directional hint: the client (1.
|
|
57
|
+
# Directional hint: the client (1.5.0) is older than the worker (99.0.0).
|
|
58
58
|
assert "upgrade the VGI extension/client" in message
|
|
@@ -0,0 +1,204 @@
|
|
|
1
|
+
# Copyright 2025, 2026 Query Farm LLC - https://query.farm
|
|
2
|
+
|
|
3
|
+
"""Tests for vgi.client.Client's OAuth wiring (oauth=/oauth_refresh_token=/oauth_flow=).
|
|
4
|
+
|
|
5
|
+
The device-code/PKCE flow logic itself is tested exhaustively in
|
|
6
|
+
vgi-rpc-python's tests/test_oauth_client.py (mock IdP, no network). These
|
|
7
|
+
tests cover the integration seam: does `Client` build a `VgiOAuthAuth` with
|
|
8
|
+
the right configuration, does construction-time validation reject bad
|
|
9
|
+
combinations, and does a full round trip actually work when driven through
|
|
10
|
+
`Client`'s real request path (via the `httpx_client=` escape hatch, wired to
|
|
11
|
+
a mock IdP the same way vgi-rpc-python's own tests are).
|
|
12
|
+
"""
|
|
13
|
+
|
|
14
|
+
from __future__ import annotations
|
|
15
|
+
|
|
16
|
+
import httpx2
|
|
17
|
+
import pytest
|
|
18
|
+
from vgi_rpc.http import VgiOAuthAuth
|
|
19
|
+
|
|
20
|
+
from vgi.client.client import Client
|
|
21
|
+
|
|
22
|
+
RESOURCE_METADATA_URL = "https://api.example.com/.well-known/oauth-protected-resource"
|
|
23
|
+
DEVICE_AUTH_URL = "https://auth.example.com/device/code"
|
|
24
|
+
TOKEN_URL = "https://auth.example.com/token"
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
class _MockIdp:
|
|
28
|
+
"""Minimal mock IdP + protected resource for one full device-code round trip."""
|
|
29
|
+
|
|
30
|
+
def __init__(self) -> None:
|
|
31
|
+
self.device_auth_calls = 0
|
|
32
|
+
self.granted_token = "mock-access-token"
|
|
33
|
+
|
|
34
|
+
def handler(self, request: httpx2.Request) -> httpx2.Response:
|
|
35
|
+
"""Route a request to the matching mock endpoint by exact URL."""
|
|
36
|
+
url = str(request.url)
|
|
37
|
+
if url == RESOURCE_METADATA_URL:
|
|
38
|
+
return httpx2.Response(
|
|
39
|
+
200,
|
|
40
|
+
json={
|
|
41
|
+
"resource": "https://api.example.com",
|
|
42
|
+
"authorization_servers": ["https://auth.example.com"],
|
|
43
|
+
"device_code_client_id": "device-client",
|
|
44
|
+
"device_code_client_secret": "device-secret",
|
|
45
|
+
},
|
|
46
|
+
)
|
|
47
|
+
if url == "https://auth.example.com/.well-known/openid-configuration":
|
|
48
|
+
return httpx2.Response(
|
|
49
|
+
200,
|
|
50
|
+
json={
|
|
51
|
+
"token_endpoint": TOKEN_URL,
|
|
52
|
+
"device_authorization_endpoint": DEVICE_AUTH_URL,
|
|
53
|
+
"grant_types_supported": ["urn:ietf:params:oauth:grant-type:device_code"],
|
|
54
|
+
},
|
|
55
|
+
)
|
|
56
|
+
if url == DEVICE_AUTH_URL:
|
|
57
|
+
self.device_auth_calls += 1
|
|
58
|
+
return httpx2.Response(
|
|
59
|
+
200,
|
|
60
|
+
json={
|
|
61
|
+
"device_code": "devcode-123",
|
|
62
|
+
"user_code": "ABCD-EFGH",
|
|
63
|
+
"verification_uri": "https://auth.example.com/activate",
|
|
64
|
+
"expires_in": 600,
|
|
65
|
+
"interval": 0,
|
|
66
|
+
},
|
|
67
|
+
)
|
|
68
|
+
if url == TOKEN_URL:
|
|
69
|
+
return httpx2.Response(200, json={"access_token": self.granted_token, "token_type": "Bearer"})
|
|
70
|
+
if url.endswith("/vgi/catalogs"):
|
|
71
|
+
token = request.headers.get("authorization", "")
|
|
72
|
+
if token:
|
|
73
|
+
return httpx2.Response(200, json={"authorization": token})
|
|
74
|
+
return httpx2.Response(
|
|
75
|
+
401,
|
|
76
|
+
headers={"www-authenticate": f'Bearer resource_metadata="{RESOURCE_METADATA_URL}"'},
|
|
77
|
+
)
|
|
78
|
+
return httpx2.Response(404, json={"error": "not_found", "url": url}) # pragma: no cover
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
class TestConstructorValidation:
|
|
82
|
+
"""Tests for the mutually-exclusive oauth/bearer_token/httpx_client combinations."""
|
|
83
|
+
|
|
84
|
+
def test_oauth_and_bearer_token_raises(self) -> None:
|
|
85
|
+
"""Passing both oauth=True and bearer_token= raises ValueError."""
|
|
86
|
+
with pytest.raises(ValueError, match="mutually exclusive"):
|
|
87
|
+
Client(transport="http", base_url="https://example.com", oauth=True, bearer_token="tok")
|
|
88
|
+
|
|
89
|
+
def test_oauth_refresh_token_and_bearer_token_raises(self) -> None:
|
|
90
|
+
"""oauth_refresh_token= (which implies oauth=True) also conflicts with bearer_token=."""
|
|
91
|
+
with pytest.raises(ValueError, match="mutually exclusive"):
|
|
92
|
+
Client(
|
|
93
|
+
transport="http",
|
|
94
|
+
base_url="https://example.com",
|
|
95
|
+
oauth_refresh_token="seed",
|
|
96
|
+
bearer_token="tok",
|
|
97
|
+
)
|
|
98
|
+
|
|
99
|
+
def test_oauth_and_httpx_client_raises(self) -> None:
|
|
100
|
+
"""Passing both oauth=True and httpx_client= raises ValueError."""
|
|
101
|
+
with pytest.raises(ValueError, match="httpx_client"):
|
|
102
|
+
Client(
|
|
103
|
+
transport="http",
|
|
104
|
+
base_url="https://example.com",
|
|
105
|
+
oauth=True,
|
|
106
|
+
httpx_client=httpx2.Client(),
|
|
107
|
+
)
|
|
108
|
+
|
|
109
|
+
def test_invalid_oauth_flow_raises(self) -> None:
|
|
110
|
+
"""An unrecognized oauth_flow value raises ValueError, not a silent no-op."""
|
|
111
|
+
with pytest.raises(ValueError, match="oauth_flow"):
|
|
112
|
+
Client(transport="http", base_url="https://example.com", oauth=True, oauth_flow="carrier-pigeon") # type: ignore[arg-type]
|
|
113
|
+
|
|
114
|
+
def test_invalid_oauth_prompt_raises(self) -> None:
|
|
115
|
+
"""An unrecognized oauth_prompt value raises ValueError, not a silent no-op."""
|
|
116
|
+
with pytest.raises(ValueError, match="oauth_prompt"):
|
|
117
|
+
Client(transport="http", base_url="https://example.com", oauth=True, oauth_prompt="shout") # type: ignore[arg-type]
|
|
118
|
+
|
|
119
|
+
def test_bearer_token_alone_still_works(self) -> None:
|
|
120
|
+
"""The existing bearer_token= path is unaffected by the new oauth params."""
|
|
121
|
+
client = Client(transport="http", base_url="https://example.com", bearer_token="tok")
|
|
122
|
+
assert client._bearer_token == "tok"
|
|
123
|
+
assert not client._use_oauth
|
|
124
|
+
|
|
125
|
+
|
|
126
|
+
class TestOAuthWiring:
|
|
127
|
+
"""Tests that Client(oauth=...) builds a correctly-configured VgiOAuthAuth."""
|
|
128
|
+
|
|
129
|
+
def test_oauth_true_builds_vgi_oauth_auth(self) -> None:
|
|
130
|
+
"""oauth=True lazily builds a VgiOAuthAuth with the client's own oauth_* settings."""
|
|
131
|
+
client = Client(
|
|
132
|
+
transport="http",
|
|
133
|
+
base_url="https://example.com",
|
|
134
|
+
oauth=True,
|
|
135
|
+
oauth_flow="device_code",
|
|
136
|
+
oauth_timeout_seconds=42.0,
|
|
137
|
+
oauth_prompt="consent",
|
|
138
|
+
)
|
|
139
|
+
assert client.oauth_identity() is None # nothing has authenticated yet
|
|
140
|
+
client._get_or_create_httpx_client()
|
|
141
|
+
assert isinstance(client._oauth_auth, VgiOAuthAuth)
|
|
142
|
+
assert client._oauth_auth._flow == "device_code" # noqa: SLF001 -- white-box wiring check
|
|
143
|
+
assert client._oauth_auth._timeout_seconds == 42.0 # noqa: SLF001
|
|
144
|
+
assert client._oauth_auth._prompt == "consent" # noqa: SLF001
|
|
145
|
+
client._oauth_auth.close()
|
|
146
|
+
|
|
147
|
+
def test_oauth_refresh_token_seeds_the_auth_object(self) -> None:
|
|
148
|
+
"""oauth_refresh_token= implies oauth=True and seeds the refresh token."""
|
|
149
|
+
client = Client(
|
|
150
|
+
transport="http",
|
|
151
|
+
base_url="https://example.com",
|
|
152
|
+
oauth_refresh_token="pre-seeded-token",
|
|
153
|
+
)
|
|
154
|
+
assert client._use_oauth
|
|
155
|
+
client._get_or_create_httpx_client()
|
|
156
|
+
assert client._oauth_auth is not None
|
|
157
|
+
assert client._oauth_auth._token.refresh_token == "pre-seeded-token" # noqa: SLF001
|
|
158
|
+
client._oauth_auth.close()
|
|
159
|
+
|
|
160
|
+
|
|
161
|
+
class TestOAuthEndToEnd:
|
|
162
|
+
"""A full device-code login round trip through the exact client Client would use.
|
|
163
|
+
|
|
164
|
+
Uses the httpx_client= escape hatch to wire a VgiOAuthAuth against a mock
|
|
165
|
+
IdP (httpx2.MockTransport) -- the same technique vgi-rpc-python's own
|
|
166
|
+
tests use. The device-code/PKCE flow mechanics are covered exhaustively
|
|
167
|
+
there (mock IdP, no network); this test's job is narrower: prove
|
|
168
|
+
``Client`` actually issues its RPCs through the httpx2.Client it was
|
|
169
|
+
handed (so a real attach would carry the OAuth-obtained token), and that
|
|
170
|
+
a 401-triggered login on that client completes end to end.
|
|
171
|
+
"""
|
|
172
|
+
|
|
173
|
+
def test_client_issues_requests_through_the_oauth_authed_httpx_client(self) -> None:
|
|
174
|
+
"""A 401 on the client Client._get_or_create_httpx_client() returns triggers a real login."""
|
|
175
|
+
idp = _MockIdp()
|
|
176
|
+
auth = VgiOAuthAuth(
|
|
177
|
+
base_url="https://example.com",
|
|
178
|
+
flow="device_code",
|
|
179
|
+
timeout_seconds=5.0,
|
|
180
|
+
transport=httpx2.MockTransport(idp.handler),
|
|
181
|
+
)
|
|
182
|
+
httpx_client = httpx2.Client(
|
|
183
|
+
transport=httpx2.MockTransport(idp.handler), auth=auth, base_url="https://example.com"
|
|
184
|
+
)
|
|
185
|
+
# Not started (no worker spawned) -- this test only exercises the HTTP/OAuth
|
|
186
|
+
# plumbing, not a full RPC call, so client.stop() (which requires start())
|
|
187
|
+
# doesn't apply; the httpx_client/auth are closed directly instead.
|
|
188
|
+
client = Client(transport="http", base_url="https://example.com", httpx_client=httpx_client)
|
|
189
|
+
try:
|
|
190
|
+
# This is the exact client object Client's own RPC machinery sends
|
|
191
|
+
# every request through -- not a parallel one built just for the test.
|
|
192
|
+
assert client._get_or_create_httpx_client() is httpx_client
|
|
193
|
+
|
|
194
|
+
resp = httpx_client.get("/vgi/catalogs")
|
|
195
|
+
assert resp.status_code == 200
|
|
196
|
+
assert resp.json()["authorization"] == f"Bearer {idp.granted_token}"
|
|
197
|
+
assert idp.device_auth_calls == 1
|
|
198
|
+
|
|
199
|
+
# A second request reuses the cached token -- no second login.
|
|
200
|
+
httpx_client.get("/vgi/catalogs")
|
|
201
|
+
assert idp.device_auth_calls == 1
|
|
202
|
+
finally:
|
|
203
|
+
httpx_client.close()
|
|
204
|
+
auth.close()
|
|
@@ -81,6 +81,7 @@ def _scan_function_result() -> ScanFunctionResult:
|
|
|
81
81
|
positional_arguments=positional,
|
|
82
82
|
named_arguments=named,
|
|
83
83
|
required_extensions=["parquet"],
|
|
84
|
+
schema_name="main",
|
|
84
85
|
)
|
|
85
86
|
|
|
86
87
|
|
|
@@ -98,6 +99,7 @@ def _scan_branch() -> ScanBranch:
|
|
|
98
99
|
format_name="parquet",
|
|
99
100
|
format_locations=["s3://bucket/a.parquet"],
|
|
100
101
|
format_options={"delim": pa.scalar("|", pa.string())},
|
|
102
|
+
schema_name="main",
|
|
101
103
|
)
|
|
102
104
|
|
|
103
105
|
|
|
@@ -2569,7 +2569,7 @@ requires-dist = [
|
|
|
2569
2569
|
|
|
2570
2570
|
[[package]]
|
|
2571
2571
|
name = "vgi-python"
|
|
2572
|
-
version = "0.
|
|
2572
|
+
version = "0.31.0"
|
|
2573
2573
|
source = { editable = "." }
|
|
2574
2574
|
dependencies = [
|
|
2575
2575
|
{ name = "click" },
|
|
@@ -2686,7 +2686,7 @@ requires-dist = [
|
|
|
2686
2686
|
{ name = "vgi-python", extras = ["test-fixtures"], marker = "extra == 'test-fixtures-writable'" },
|
|
2687
2687
|
{ name = "vgi-python", extras = ["test-fixtures", "test-fixtures-writable", "http", "launch", "oauth", "otel", "sentry", "azure"], marker = "extra == 'dev'" },
|
|
2688
2688
|
{ name = "vgi-python", extras = ["transactor"], marker = "extra == 'test-fixtures-writable'" },
|
|
2689
|
-
{ name = "vgi-rpc", specifier = ">=0.
|
|
2689
|
+
{ name = "vgi-rpc", specifier = ">=0.44.1" },
|
|
2690
2690
|
{ name = "vgi-rpc", extras = ["cli"], marker = "extra == 'launch'" },
|
|
2691
2691
|
{ name = "vgi-rpc", extras = ["cli", "conformance", "external", "http", "oauth", "otel", "sentry"], marker = "extra == 'dev'" },
|
|
2692
2692
|
{ name = "vgi-rpc", extras = ["http"], marker = "extra == 'granian'" },
|
|
@@ -2716,7 +2716,7 @@ docs = [
|
|
|
2716
2716
|
|
|
2717
2717
|
[[package]]
|
|
2718
2718
|
name = "vgi-rpc"
|
|
2719
|
-
version = "0.
|
|
2719
|
+
version = "0.44.1"
|
|
2720
2720
|
source = { registry = "https://pypi.org/simple" }
|
|
2721
2721
|
dependencies = [
|
|
2722
2722
|
{ name = "docstring-parser" },
|
|
@@ -2724,9 +2724,9 @@ dependencies = [
|
|
|
2724
2724
|
{ name = "pywin32", marker = "sys_platform == 'win32'" },
|
|
2725
2725
|
{ name = "tzdata", marker = "sys_platform == 'win32'" },
|
|
2726
2726
|
]
|
|
2727
|
-
sdist = { url = "https://files.pythonhosted.org/packages/
|
|
2727
|
+
sdist = { url = "https://files.pythonhosted.org/packages/1a/16/5a78053080117cac00a8945b70298d636a63d57801a33528bb63b14cdd95/vgi_rpc-0.44.1.tar.gz", hash = "sha256:37a54ae2cb7e5a7a2603aad69ece92c3c99a96906c96d2196806202ee4b70825", size = 1170809, upload-time = "2026-08-28T15:03:07.221Z" }
|
|
2728
2728
|
wheels = [
|
|
2729
|
-
{ url = "https://files.pythonhosted.org/packages/
|
|
2729
|
+
{ url = "https://files.pythonhosted.org/packages/8f/d6/3bfff42bd723ffcd0c2550d932e766aa65d39a886017cb9c002174e68196/vgi_rpc-0.44.1-py3-none-any.whl", hash = "sha256:e9785753bdb30e3f07f2bdbeafcddd09533cc014baa310e093a94fdeda6ad517", size = 545257, upload-time = "2026-08-28T15:03:05.268Z" },
|
|
2730
2730
|
]
|
|
2731
2731
|
|
|
2732
2732
|
[package.optional-dependencies]
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
# Copyright 2025, 2026 Query Farm LLC - https://query.farm
|
|
2
|
+
|
|
3
|
+
"""Same-name-in-two-schemas producer, backing a DECLARATIVE TABLE in each schema.
|
|
4
|
+
|
|
5
|
+
The table-dispatch member of the schema-disambiguation family (see
|
|
6
|
+
``scalar/same_name.py``, ``table_in_out_same_name.py``, ``aggregate/same_name.py``,
|
|
7
|
+
and ``table/same_name_cached.py`` for the result-cache member). Those probe a
|
|
8
|
+
function called directly (or the result cache); this one probes
|
|
9
|
+
``catalog_table_scan_function_get``/``catalog_table_scan_branches_get`` — the RPC
|
|
10
|
+
pair that tells a client which function backs a *declarative catalog table*.
|
|
11
|
+
|
|
12
|
+
``test_same_name_table_scan`` is a one-row producer registered under the SAME
|
|
13
|
+
NAME in BOTH the ``main`` and ``data`` schemas of the ``example`` catalog, each
|
|
14
|
+
emitting a single row tagged with its own schema. A declarative ``Table``
|
|
15
|
+
descriptor named ``test_same_name_table`` is registered in each schema too, each
|
|
16
|
+
backed by that schema's own implementation.
|
|
17
|
+
|
|
18
|
+
This is also the end-to-end regression guard for protocol 1.5.0's
|
|
19
|
+
``ScanFunctionResult.schema_name``/``ScanBranch.schema_name``: the C++ extension
|
|
20
|
+
now prefers the worker-declared schema over its old table-schema/default-schema
|
|
21
|
+
heuristic when resolving which catalog entry ``function_name`` refers to. A
|
|
22
|
+
worker that regressed to leaving ``schema_name`` unset, or a client that stopped
|
|
23
|
+
consuming it, would silently fall back to the old heuristic — which still
|
|
24
|
+
happens to get *this* two-schema case right (the table's own schema is tried
|
|
25
|
+
first and always matches here), so a regression here would show up not as a
|
|
26
|
+
wrong row, but as the exact filter/projection-pushdown breakage this session's
|
|
27
|
+
own investigation traced to passing the wire-parsed schema string somewhere the
|
|
28
|
+
resolver couldn't safely reuse it — see ``cache/filter_pushdown_keys.test`` and
|
|
29
|
+
this table family's own pushdown assertions below. Driven by
|
|
30
|
+
``table/same_name_schemas.test``.
|
|
31
|
+
"""
|
|
32
|
+
|
|
33
|
+
from __future__ import annotations
|
|
34
|
+
|
|
35
|
+
from dataclasses import dataclass
|
|
36
|
+
from typing import ClassVar
|
|
37
|
+
|
|
38
|
+
import pyarrow as pa
|
|
39
|
+
from vgi_rpc import ArrowSerializableDataclass
|
|
40
|
+
from vgi_rpc.rpc import OutputCollector
|
|
41
|
+
|
|
42
|
+
from vgi.metadata import FunctionExample
|
|
43
|
+
from vgi.schema_utils import schema
|
|
44
|
+
from vgi.table_function import (
|
|
45
|
+
ProcessParams,
|
|
46
|
+
TableFunctionGenerator,
|
|
47
|
+
bind_fixed_schema,
|
|
48
|
+
init_single_worker,
|
|
49
|
+
)
|
|
50
|
+
|
|
51
|
+
FUNCTION_NAME = "test_same_name_table_scan"
|
|
52
|
+
TABLE_NAME = "test_same_name_table"
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
@dataclass(slots=True, frozen=True)
|
|
56
|
+
class _SameNameTableArgs:
|
|
57
|
+
"""Arguments for the same-name table producer (none)."""
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
@dataclass(kw_only=True)
|
|
61
|
+
class _SameNameTableState(ArrowSerializableDataclass):
|
|
62
|
+
"""One-shot emit latch for the single output row."""
|
|
63
|
+
|
|
64
|
+
done: bool = False
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
class _SameNameTableScan(TableFunctionGenerator[_SameNameTableArgs, _SameNameTableState]):
|
|
68
|
+
"""Shared body; each subclass supplies the schema it is declared in."""
|
|
69
|
+
|
|
70
|
+
#: Schema this implementation is declared in — the tag it stamps.
|
|
71
|
+
OWNING_SCHEMA: ClassVar[str] = ""
|
|
72
|
+
|
|
73
|
+
FunctionArguments = _SameNameTableArgs
|
|
74
|
+
FIXED_SCHEMA: ClassVar[pa.Schema] = schema(tag=pa.string())
|
|
75
|
+
|
|
76
|
+
@classmethod
|
|
77
|
+
def initial_state(cls, params: ProcessParams[_SameNameTableArgs]) -> _SameNameTableState:
|
|
78
|
+
"""Fresh latch per invocation."""
|
|
79
|
+
return _SameNameTableState()
|
|
80
|
+
|
|
81
|
+
@classmethod
|
|
82
|
+
def process(
|
|
83
|
+
cls,
|
|
84
|
+
params: ProcessParams[_SameNameTableArgs],
|
|
85
|
+
state: _SameNameTableState,
|
|
86
|
+
out: OutputCollector,
|
|
87
|
+
) -> None:
|
|
88
|
+
"""Emit the single schema-tagged row once."""
|
|
89
|
+
if state.done:
|
|
90
|
+
out.finish()
|
|
91
|
+
return
|
|
92
|
+
batch = pa.RecordBatch.from_pydict({"tag": [cls.OWNING_SCHEMA]}, schema=params.output_schema)
|
|
93
|
+
out.emit(batch)
|
|
94
|
+
state.done = True
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
@init_single_worker
|
|
98
|
+
@bind_fixed_schema
|
|
99
|
+
class SameNameTableMainScan(_SameNameTableScan):
|
|
100
|
+
"""``test_same_name_table_scan`` as declared in the ``main`` schema."""
|
|
101
|
+
|
|
102
|
+
OWNING_SCHEMA = "main"
|
|
103
|
+
|
|
104
|
+
class Meta:
|
|
105
|
+
"""Function metadata."""
|
|
106
|
+
|
|
107
|
+
name = FUNCTION_NAME
|
|
108
|
+
description = "Schema-disambiguation probe; the main-schema table producer"
|
|
109
|
+
categories = ["generator", "testing"]
|
|
110
|
+
examples = [
|
|
111
|
+
FunctionExample(
|
|
112
|
+
sql="SELECT * FROM example.main.test_same_name_table",
|
|
113
|
+
description="One row tagged 'main'",
|
|
114
|
+
),
|
|
115
|
+
]
|
|
116
|
+
|
|
117
|
+
|
|
118
|
+
@init_single_worker
|
|
119
|
+
@bind_fixed_schema
|
|
120
|
+
class SameNameTableDataScan(_SameNameTableScan):
|
|
121
|
+
"""``test_same_name_table_scan`` as declared in the ``data`` schema."""
|
|
122
|
+
|
|
123
|
+
OWNING_SCHEMA = "data"
|
|
124
|
+
|
|
125
|
+
class Meta:
|
|
126
|
+
"""Function metadata."""
|
|
127
|
+
|
|
128
|
+
name = FUNCTION_NAME
|
|
129
|
+
description = "Schema-disambiguation probe; the data-schema table producer"
|
|
130
|
+
categories = ["generator", "testing"]
|
|
131
|
+
examples = [
|
|
132
|
+
FunctionExample(
|
|
133
|
+
sql="SELECT * FROM example.data.test_same_name_table",
|
|
134
|
+
description="One row tagged 'data'",
|
|
135
|
+
),
|
|
136
|
+
]
|