vgi-python 0.29.0__tar.gz → 0.29.3__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.0 → vgi_python-0.29.3}/PKG-INFO +10 -6
- {vgi_python-0.29.0 → vgi_python-0.29.3}/README.md +9 -5
- vgi_python-0.29.3/docs/vgi-logo.png +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/pyproject.toml +1 -1
- vgi_python-0.29.3/tests/client/test_batch_metadata_callback.py +77 -0
- vgi_python-0.29.3/tests/client/test_scan_branches_client.py +67 -0
- vgi_python-0.29.3/tests/client/test_split_client.py +93 -0
- vgi_python-0.29.3/tests/client/test_time_travel_client.py +85 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/uv.lock +10 -5
- {vgi_python-0.29.0 → vgi_python-0.29.3}/vgi/_test_fixtures/table_in_out.py +96 -1
- {vgi_python-0.29.0 → vgi_python-0.29.3}/vgi/_test_fixtures/worker.py +2 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/vgi/client/catalog_mixin.py +86 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/vgi/client/client.py +230 -9
- {vgi_python-0.29.0 → vgi_python-0.29.3}/vgi/codegen/cpp_request_builders.py +98 -12
- {vgi_python-0.29.0 → vgi_python-0.29.3}/vgi/worker.py +11 -0
- vgi_python-0.29.0/docs/vgi-logo.png +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/.gitattributes +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/.github/dependabot.yml +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/.github/styles/config/vocabularies/VGI/accept.txt +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/.github/workflows/ci.yml +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/.github/workflows/docs.yml +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/.github/workflows/integration.yml +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/.github/workflows/release.yml +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/.gitignore +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/.python-version +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/.vale.ini +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/CLAUDE.md +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/DOCS_ACCEPTANCE_CRITERIA.md +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/DOCS_REVIEW_RUBRIC.md +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/DOCS_USABILITY_TEST.md +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/LICENSE +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/RELEASE-RUNBOOK.md +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/SECURITY.md +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/ci/README.md +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/ci/preprocess-require.awk +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/ci/run-integration.sh +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/dist-vgi/.gitignore +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/docs/aggregate-functions.md +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/docs/api/arguments.md +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/docs/api/auth.md +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/docs/api/catalogs.md +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/docs/api/client.md +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/docs/api/exceptions.md +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/docs/api/filters.md +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/docs/api/functions.md +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/docs/api/http.md +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/docs/api/index.md +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/docs/api/metadata.md +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/docs/api/observability.md +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/docs/api/storage.md +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/docs/api/transactor.md +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/docs/api/worker.md +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/docs/argument-serialization.md +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/docs/assets/apple-touch-icon.png +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/docs/assets/favicon-16x16.png +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/docs/assets/favicon-32x32.png +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/docs/assets/favicon.ico +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/docs/assets/kinds/aggregate.svg +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/docs/assets/kinds/buffering.svg +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/docs/assets/kinds/scalar.svg +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/docs/assets/kinds/table-in-out.svg +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/docs/assets/kinds/table.svg +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/docs/assets/logo.png +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/docs/assets/social-card.png +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/docs/authentication.md +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/docs/catalog-interface.md +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/docs/cli.md +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/docs/column-statistics.md +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/docs/concepts/index.md +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/docs/contributing-docs.md +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/docs/filter-pushdown.md +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/docs/generator-api.md +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/docs/global-functions.md +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/docs/how-to/catalogs.md +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/docs/how-to/function-patterns.md +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/docs/how-to/http-auth.md +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/docs/how-to/index.md +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/docs/how-to/pushdown-and-statistics.md +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/docs/how-to/state-storage.md +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/docs/index.md +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/docs/lifecycle.md +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/docs/metadata.md +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/docs/overrides/main.html +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/docs/robots.txt +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/docs/shared-storage.md +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/docs/stylesheets/extra.css +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/docs/tutorial/index.md +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/docs/tutorial/scalar.md +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/docs/tutorial/table.md +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/examples/batch_index_worker.py +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/examples/cache_worker.py +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/examples/calc_scalar_worker.py +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/examples/calc_worker.py +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/examples/copy_format_worker.py +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/examples/filter_worker.py +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/examples/greeting_scalar_worker.py +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/examples/row_count_worker.py +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/examples/series_streaming_worker.py +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/examples/sum_worker.py +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/mkdocs.yml +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/packages/vgi-fixtures/LICENSE +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/packages/vgi-fixtures/README.md +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/packages/vgi-fixtures/docker/Dockerfile +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/packages/vgi-fixtures/docker/docker-entrypoint.sh +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/packages/vgi-fixtures/pyproject.toml +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/scripts/measure_startup.py +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/scripts/run_all_tests.sh +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/test-data/generate.sh +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/tests/__init__.py +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/tests/_http_fixtures.py +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/tests/catalog/__init__.py +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/tests/catalog/test_attach_option.py +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/tests/catalog/test_catalog_interface.py +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/tests/catalog/test_client_catalog.py +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/tests/catalog/test_column_statistics.py +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/tests/catalog/test_declarative.py +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/tests/catalog/test_example_worker_catalog.py +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/tests/catalog/test_integration.py +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/tests/catalog/test_required_filters.py +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/tests/catalog/test_scan_branches.py +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/tests/catalog/test_serialization.py +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/tests/catalog/test_setting.py +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/tests/catalog/test_storage.py +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/tests/catalog/test_time_travel.py +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/tests/catalog/test_writable_table.py +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/tests/client/__init__.py +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/tests/client/test_aggregate_client.py +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/tests/client/test_broken_pipe.py +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/tests/client/test_cli.py +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/tests/client/test_cli_catalog_functions.py +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/tests/client/test_copy_client.py +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/tests/client/test_stop_force.py +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/tests/client/test_table_column_statistics.py +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/tests/client/test_worker_debug.py +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/tests/conformance/__init__.py +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/tests/conformance/_stub.py +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/tests/conformance/conftest.py +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/tests/conformance/test_accumulate.py +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/tests/conformance/test_aggregate.py +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/tests/conformance/test_attach.py +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/tests/conformance/test_bearer_auth.py +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/tests/conformance/test_const_param_enforcement.py +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/tests/conformance/test_container.py +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/tests/conformance/test_copy_from.py +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/tests/conformance/test_copy_to.py +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/tests/conformance/test_directory_parity.py +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/tests/conformance/test_function_inventory.py +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/tests/conformance/test_github.py +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/tests/conformance/test_http_client.py +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/tests/conformance/test_http_external_location.py +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/tests/conformance/test_http_upload_url.py +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/tests/conformance/test_macro.py +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/tests/conformance/test_overload.py +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/tests/conformance/test_protocol_inventory.py +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/tests/conformance/test_protocol_version.py +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/tests/conformance/test_resumable_scan.py +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/tests/conformance/test_scalar.py +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/tests/conformance/test_scalar_attach_opaque_data.py +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/tests/conformance/test_secret.py +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/tests/conformance/test_settings.py +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/tests/conformance/test_splits.py +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/tests/conformance/test_table.py +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/tests/conformance/test_table_in_out.py +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/tests/conformance/test_view.py +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/tests/conformance/test_writable.py +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/tests/conftest.py +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/tests/data/split_tokens/anchor_len_overrun.bin +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/tests/data/split_tokens/bad_fingerprint.bin +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/tests/data/split_tokens/bad_flags_unsealed_but_key_present.bin +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/tests/data/split_tokens/bad_version.bin +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/tests/data/split_tokens/generate.py +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/tests/data/split_tokens/manifest.json +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/tests/data/split_tokens/reserved_flag_bit.bin +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/tests/data/split_tokens/stale_anchor.bin +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/tests/data/split_tokens/truncated.bin +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/tests/data/split_tokens/valid_sealed.bin +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/tests/data/split_tokens/valid_unsealed.bin +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/tests/scalar/__init__.py +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/tests/scalar/test_bernoulli_function.py +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/tests/scalar/test_binary_packet_function.py +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/tests/scalar/test_client.py +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/tests/scalar/test_conditional_message_function.py +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/tests/scalar/test_hash_seed_function.py +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/tests/scalar/test_multiply_by_setting_function.py +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/tests/scalar/test_multiply_function.py +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/tests/scalar/test_random_bytes_function.py +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/tests/scalar/test_return_secret_value_function.py +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/tests/table/__init__.py +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/tests/table/generator/__init__.py +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/tests/table/generator/test_constant_columns_function.py +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/tests/table/generator/test_double_sequence_function.py +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/tests/table/generator/test_exception_function.py +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/tests/table/generator/test_filter_echo_function.py +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/tests/table/generator/test_logging_function.py +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/tests/table/generator/test_nested_sequence_function.py +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/tests/table/generator/test_partitioned_function.py +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/tests/table/generator/test_projected_data_function.py +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/tests/table/generator/test_sequence_function.py +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/tests/table/generator/test_settings_function.py +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/tests/table/generator/test_struct_settings_function.py +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/tests/table/generator/test_ten_thousand_function.py +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/tests/table/test_wide_columns.py +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/tests/table_in_out/__init__.py +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/tests/table_in_out/generator/__init__.py +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/tests/table_in_out/generator/test_buffer_input_function.py +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/tests/table_in_out/generator/test_echo_function.py +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/tests/table_in_out/generator/test_exception_functions.py +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/tests/table_in_out/generator/test_filter_by_setting_function.py +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/tests/table_in_out/generator/test_repeat_inputs_function.py +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/tests/table_in_out/generator/test_substream_partial_sum_function.py +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/tests/table_in_out/generator/test_sum_all_columns_function.py +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/tests/table_in_out/test_blended_metadata.py +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/tests/table_in_out/test_client.py +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/tests/test_access_log_audit.py +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/tests/test_aggregate_function.py +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/tests/test_argument_spec.py +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/tests/test_auth.py +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/tests/test_bind_exceptions.py +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/tests/test_bind_request_at_clause.py +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/tests/test_bound_storage_conformance.py +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/tests/test_cache_control.py +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/tests/test_call_state_attach.py +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/tests/test_catalog_auth_binding.py +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/tests/test_copy_from_function.py +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/tests/test_copy_to_function.py +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/tests/test_docstrings.py +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/tests/test_documentation_examples.py +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/tests/test_example_function_arg_types.py +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/tests/test_examples_workers.py +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/tests/test_exception_handling.py +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/tests/test_exceptions.py +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/tests/test_filter_pushdown.py +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/tests/test_filter_pushdown_extension.py +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/tests/test_fixture_catalog_parity.py +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/tests/test_function_storage.py +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/tests/test_function_storage_azure_sql.py +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/tests/test_function_storage_cf_do.py +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/tests/test_function_storage_cf_do_integration.py +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/tests/test_function_storage_conformance.py +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/tests/test_generated_cpp_constants.py +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/tests/test_generated_cpp_protocol_version.py +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/tests/test_generated_cpp_request_builders.py +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/tests/test_generated_cpp_schemas.py +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/tests/test_generated_cpp_secret.py +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/tests/test_generated_go_schemas.py +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/tests/test_generated_java_schemas.py +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/tests/test_generated_protocol_version.py +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/tests/test_generated_rust_request_builders.py +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/tests/test_generated_rust_schemas.py +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/tests/test_generated_schemas_cross_lang.py +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/tests/test_generated_ts_client.py +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/tests/test_generated_ts_schemas.py +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/tests/test_http_demo_storage.py +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/tests/test_http_s3_offload_input.py +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/tests/test_http_s3_offload_output.py +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/tests/test_metadata.py +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/tests/test_mypy_consolidated.py +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/tests/test_nest_tensor.py +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/tests/test_otel.py +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/tests/test_projection_enforcement.py +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/tests/test_projection_repro.py +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/tests/test_protocol_classes.py +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/tests/test_resolved_secrets.py +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/tests/test_schema_scoped_functions.py +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/tests/test_schema_utils.py +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/tests/test_serve.py +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/tests/test_setting_secret_annotations.py +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/tests/test_signing_key.py +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/tests/test_split_token.py +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/tests/test_table_buffering_function.py +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/tests/test_table_function_dynamic_to_string.py +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/tests/test_tcp_transport.py +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/tests/test_type_bounds.py +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/tests/test_union_argument.py +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/tests/test_wire_record_schema_parity.py +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/tests/test_worker.py +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/tests/test_worker_cli.py +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/tests/test_worker_page.py +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/tests/transactor/__init__.py +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/tests/transactor/test_transactor.py +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/vgi/__init__.py +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/vgi/_duckdb.py +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/vgi/_storage_profile.py +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/vgi/_test_fixtures/__init__.py +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/vgi/_test_fixtures/accumulate/__init__.py +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/vgi/_test_fixtures/accumulate/worker.py +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/vgi/_test_fixtures/aggregate/__init__.py +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/vgi/_test_fixtures/aggregate/_common.py +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/vgi/_test_fixtures/aggregate/basic.py +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/vgi/_test_fixtures/aggregate/dynamic.py +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/vgi/_test_fixtures/aggregate/generic.py +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/vgi/_test_fixtures/aggregate/listagg.py +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/vgi/_test_fixtures/aggregate/percentile.py +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/vgi/_test_fixtures/aggregate/same_name.py +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/vgi/_test_fixtures/aggregate/secret_typed.py +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/vgi/_test_fixtures/aggregate/streaming.py +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/vgi/_test_fixtures/aggregate/varargs.py +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/vgi/_test_fixtures/aggregate/window.py +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/vgi/_test_fixtures/attach_options.py +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/vgi/_test_fixtures/bad_enum.py +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/vgi/_test_fixtures/bad_protocol.py +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/vgi/_test_fixtures/cancellable.py +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/vgi/_test_fixtures/catalog.py +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/vgi/_test_fixtures/companion.py +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/vgi/_test_fixtures/copy_from.py +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/vgi/_test_fixtures/copy_to.py +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/vgi/_test_fixtures/global_functions.py +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/vgi/_test_fixtures/http_server.py +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/vgi/_test_fixtures/narrow_bind/__init__.py +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/vgi/_test_fixtures/narrow_bind/worker.py +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/vgi/_test_fixtures/nest_tensor.py +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/vgi/_test_fixtures/orchard_catalog.py +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/vgi/_test_fixtures/projection_repro/__init__.py +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/vgi/_test_fixtures/projection_repro/worker.py +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/vgi/_test_fixtures/scalar/__init__.py +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/vgi/_test_fixtures/scalar/_common.py +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/vgi/_test_fixtures/scalar/arithmetic.py +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/vgi/_test_fixtures/scalar/bench_ladder.py +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/vgi/_test_fixtures/scalar/binary.py +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/vgi/_test_fixtures/scalar/formatting.py +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/vgi/_test_fixtures/scalar/geo.py +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/vgi/_test_fixtures/scalar/null_handling.py +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/vgi/_test_fixtures/scalar/random_demo.py +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/vgi/_test_fixtures/scalar/same_name.py +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/vgi/_test_fixtures/scalar/settings_secrets.py +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/vgi/_test_fixtures/scalar/type_info.py +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/vgi/_test_fixtures/schema_reconcile/__init__.py +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/vgi/_test_fixtures/schema_reconcile/worker.py +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/vgi/_test_fixtures/simple_writable.py +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/vgi/_test_fixtures/table/__init__.py +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/vgi/_test_fixtures/table/_common.py +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/vgi/_test_fixtures/table/batch_index.py +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/vgi/_test_fixtures/table/batch_index_broken.py +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/vgi/_test_fixtures/table/cache.py +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/vgi/_test_fixtures/table/catalog_scans.py +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/vgi/_test_fixtures/table/filters.py +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/vgi/_test_fixtures/table/late_materialization.py +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/vgi/_test_fixtures/table/make_series.py +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/vgi/_test_fixtures/table/misc.py +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/vgi/_test_fixtures/table/order_modes.py +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/vgi/_test_fixtures/table/pairs.py +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/vgi/_test_fixtures/table/partition_columns.py +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/vgi/_test_fixtures/table/partition_columns_broken.py +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/vgi/_test_fixtures/table/profiling_example.py +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/vgi/_test_fixtures/table/required_filters.py +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/vgi/_test_fixtures/table/same_name_cached.py +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/vgi/_test_fixtures/table/sequence.py +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/vgi/_test_fixtures/table/settings.py +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/vgi/_test_fixtures/table/splits.py +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/vgi/_test_fixtures/table/transaction_storage.py +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/vgi/_test_fixtures/table/tt_pushdown.py +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/vgi/_test_fixtures/table/typed_probe.py +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/vgi/_test_fixtures/table/versioned.py +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/vgi/_test_fixtures/table/wide.py +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/vgi/_test_fixtures/table_in_out_same_name.py +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/vgi/_test_fixtures/twin_catalogs.py +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/vgi/_test_fixtures/versioned.py +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/vgi/_test_fixtures/versioned_tables.py +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/vgi/_test_fixtures/writable/__init__.py +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/vgi/_test_fixtures/writable/generic.py +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/vgi/_test_fixtures/writable/table.py +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/vgi/_test_fixtures/writable/worker.py +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/vgi/aggregate_function.py +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/vgi/argument_spec.py +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/vgi/arguments.py +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/vgi/attach_header.py +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/vgi/auth.py +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/vgi/cache_control.py +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/vgi/catalog/__init__.py +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/vgi/catalog/_descriptor_spec.py +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/vgi/catalog/attach_option.py +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/vgi/catalog/catalog_interface.py +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/vgi/catalog/descriptors.py +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/vgi/catalog/duckdb_statistics.py +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/vgi/catalog/secret_type.py +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/vgi/catalog/setting.py +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/vgi/catalog/storage.py +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/vgi/client/__init__.py +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/vgi/client/aggregate.py +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/vgi/client/cli.py +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/vgi/client/cli_catalog.py +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/vgi/client/cli_schema.py +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/vgi/client/cli_table.py +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/vgi/client/cli_transaction.py +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/vgi/client/cli_utils.py +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/vgi/client/cli_view.py +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/vgi/client/errors.py +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/vgi/codegen/__init__.py +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/vgi/codegen/_common.py +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/vgi/codegen/cpp_constants.py +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/vgi/codegen/cpp_protocol_version.py +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/vgi/codegen/cpp_schemas.py +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/vgi/codegen/cpp_secret_protocol_version.py +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/vgi/codegen/cpp_secret_request_builders.py +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/vgi/codegen/cpp_secret_schemas.py +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/vgi/codegen/go_schemas.py +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/vgi/codegen/java_schemas.py +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/vgi/codegen/protocol_version.py +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/vgi/codegen/rust_request_builders.py +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/vgi/codegen/rust_schemas.py +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/vgi/codegen/ts_client.py +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/vgi/codegen/ts_schemas.py +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/vgi/copy_from_function.py +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/vgi/copy_to_function.py +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/vgi/exceptions.py +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/vgi/function.py +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/vgi/function_storage.py +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/vgi/function_storage_azure_sql.py +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/vgi/function_storage_cf_do.py +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/vgi/http/__init__.py +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/vgi/http/demo_storage.py +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/vgi/http/landing.html +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/vgi/http/landing_page.py +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/vgi/http/vgi-client.js +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/vgi/http/worker_page.py +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/vgi/invocation.py +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/vgi/logging_config.py +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/vgi/meta_worker.py +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/vgi/metadata.py +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/vgi/otel.py +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/vgi/profiling.py +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/vgi/protocol.py +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/vgi/protocol_version.txt +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/vgi/py.typed +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/vgi/scalar_function.py +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/vgi/schema_utils.py +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/vgi/secret_protocol.py +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/vgi/secret_service.py +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/vgi/serve.py +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/vgi/split_token.py +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/vgi/table_buffering_function.py +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/vgi/table_filter_pushdown.py +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/vgi/table_function.py +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/vgi/table_in_out_function.py +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/vgi/transactor/__init__.py +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/vgi/transactor/_duckdb_compat.py +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/vgi/transactor/client.py +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/vgi/transactor/protocol.py +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/vgi/transactor/server.py +0 -0
- {vgi_python-0.29.0 → vgi_python-0.29.3}/wrangler.jsonc +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: vgi-python
|
|
3
|
-
Version: 0.29.
|
|
3
|
+
Version: 0.29.3
|
|
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
|
|
@@ -212,18 +212,22 @@ Provides-Extra: transactor
|
|
|
212
212
|
Requires-Dist: sqlglot; extra == 'transactor'
|
|
213
213
|
Description-Content-Type: text/markdown
|
|
214
214
|
|
|
215
|
-
# VGI (Vector Gateway Interface)
|
|
216
|
-
|
|
217
215
|
<p align="center">
|
|
218
|
-
<img src="https://raw.githubusercontent.com/Query-farm/vgi-python/main/docs/vgi-logo.png" alt="
|
|
216
|
+
<img src="https://raw.githubusercontent.com/Query-farm/vgi-python/main/docs/vgi-logo.png?v=2" alt="Vector Gateway Interface logo" width="320">
|
|
219
217
|
</p>
|
|
220
218
|
|
|
219
|
+
<h1 align="center">VGI</h1>
|
|
220
|
+
|
|
221
221
|
<p align="center">
|
|
222
|
-
|
|
222
|
+
Apache Arrow-based protocol for extending DuckDB using any language — the Python reference implementation.<br>
|
|
223
|
+
Built by <a href="https://query.farm">🚜 Query.Farm</a>
|
|
223
224
|
</p>
|
|
224
225
|
|
|
225
226
|
<p align="center">
|
|
226
|
-
|
|
227
|
+
<a href="https://github.com/Query-farm/vgi-python/actions/workflows/ci.yml"><img src="https://github.com/Query-farm/vgi-python/actions/workflows/ci.yml/badge.svg" alt="CI"></a>
|
|
228
|
+
<a href="https://pypi.org/project/vgi-python/"><img src="https://img.shields.io/pypi/v/vgi-python" alt="PyPI"></a>
|
|
229
|
+
<a href="https://pypi.org/project/vgi-python/"><img src="https://img.shields.io/pypi/pyversions/vgi-python" alt="Python versions"></a>
|
|
230
|
+
<a href="LICENSE"><img src="https://img.shields.io/pypi/l/vgi-python" alt="License"></a>
|
|
227
231
|
</p>
|
|
228
232
|
|
|
229
233
|
---
|
|
@@ -1,15 +1,19 @@
|
|
|
1
|
-
# VGI (Vector Gateway Interface)
|
|
2
|
-
|
|
3
1
|
<p align="center">
|
|
4
|
-
<img src="https://raw.githubusercontent.com/Query-farm/vgi-python/main/docs/vgi-logo.png" alt="
|
|
2
|
+
<img src="https://raw.githubusercontent.com/Query-farm/vgi-python/main/docs/vgi-logo.png?v=2" alt="Vector Gateway Interface logo" width="320">
|
|
5
3
|
</p>
|
|
6
4
|
|
|
5
|
+
<h1 align="center">VGI</h1>
|
|
6
|
+
|
|
7
7
|
<p align="center">
|
|
8
|
-
|
|
8
|
+
Apache Arrow-based protocol for extending DuckDB using any language — the Python reference implementation.<br>
|
|
9
|
+
Built by <a href="https://query.farm">🚜 Query.Farm</a>
|
|
9
10
|
</p>
|
|
10
11
|
|
|
11
12
|
<p align="center">
|
|
12
|
-
|
|
13
|
+
<a href="https://github.com/Query-farm/vgi-python/actions/workflows/ci.yml"><img src="https://github.com/Query-farm/vgi-python/actions/workflows/ci.yml/badge.svg" alt="CI"></a>
|
|
14
|
+
<a href="https://pypi.org/project/vgi-python/"><img src="https://img.shields.io/pypi/v/vgi-python" alt="PyPI"></a>
|
|
15
|
+
<a href="https://pypi.org/project/vgi-python/"><img src="https://img.shields.io/pypi/pyversions/vgi-python" alt="Python versions"></a>
|
|
16
|
+
<a href="LICENSE"><img src="https://img.shields.io/pypi/l/vgi-python" alt="License"></a>
|
|
13
17
|
</p>
|
|
14
18
|
|
|
15
19
|
---
|
|
Binary file
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
# Copyright 2026 Query Farm LLC - https://query.farm
|
|
2
|
+
|
|
3
|
+
# ruff: noqa: S101, D101, D102, D103
|
|
4
|
+
"""`Client.table_function(batch_metadata_callback=...)`.
|
|
5
|
+
|
|
6
|
+
`_table_function_parallel` previously discarded `AnnotatedBatch.custom_metadata`
|
|
7
|
+
unconditionally (`if output.batch.num_rows > 0: output_queue.put(output.batch)`)
|
|
8
|
+
and only forwarded the bare `pa.RecordBatch` — so a worker's `vgi.cache.*`
|
|
9
|
+
cacheability advertisement (`vgi/cache_control.py`), which rides
|
|
10
|
+
`custom_metadata`, was structurally unreachable through the public
|
|
11
|
+
`table_function()` generator. `batch_metadata_callback` mirrors the existing
|
|
12
|
+
`bind_result_callback` pattern to fix that additively, with no change to the
|
|
13
|
+
generator's yield type. Exercised against `cacheable_numbers`
|
|
14
|
+
(`vgi/_test_fixtures/table/cache.py`), which advertises `vgi.cache.ttl` on its
|
|
15
|
+
first batch.
|
|
16
|
+
"""
|
|
17
|
+
|
|
18
|
+
from __future__ import annotations
|
|
19
|
+
|
|
20
|
+
from typing import Any
|
|
21
|
+
|
|
22
|
+
import pyarrow as pa
|
|
23
|
+
import pytest
|
|
24
|
+
|
|
25
|
+
from vgi.arguments import Arguments
|
|
26
|
+
|
|
27
|
+
DATA = "data"
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
@pytest.fixture
|
|
31
|
+
def client(client_transport: Any) -> Any:
|
|
32
|
+
with client_transport() as c:
|
|
33
|
+
c.catalog_attach(name="example", data_version_spec=None, implementation_version=None)
|
|
34
|
+
yield c
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
def test_callback_receives_cache_control_metadata(client: Any) -> None:
|
|
38
|
+
metas: list[pa.KeyValueMetadata | None] = []
|
|
39
|
+
batches = list(
|
|
40
|
+
client.table_function(
|
|
41
|
+
function_name="cacheable_numbers",
|
|
42
|
+
schema_name=DATA,
|
|
43
|
+
arguments=Arguments(named={"n": pa.scalar(5)}),
|
|
44
|
+
batch_metadata_callback=metas.append,
|
|
45
|
+
)
|
|
46
|
+
)
|
|
47
|
+
assert sum(b.num_rows for b in batches) == 5
|
|
48
|
+
assert len(metas) == len(batches)
|
|
49
|
+
assert metas[0] is not None
|
|
50
|
+
assert dict(metas[0])[b"vgi.cache.ttl"] == b"300"
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
def test_callback_is_optional_and_defaults_to_none(client: Any) -> None:
|
|
54
|
+
"""No `batch_metadata_callback` -> unchanged behavior, no crash."""
|
|
55
|
+
batches = list(
|
|
56
|
+
client.table_function(
|
|
57
|
+
function_name="cacheable_numbers",
|
|
58
|
+
schema_name=DATA,
|
|
59
|
+
arguments=Arguments(named={"n": pa.scalar(3)}),
|
|
60
|
+
)
|
|
61
|
+
)
|
|
62
|
+
assert sum(b.num_rows for b in batches) == 3
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
def test_callback_sees_none_for_a_batch_without_custom_metadata(client: Any) -> None:
|
|
66
|
+
"""A function that never advertises cache control still drives the callback once per batch, with `None`."""
|
|
67
|
+
metas: list[pa.KeyValueMetadata | None] = []
|
|
68
|
+
list(
|
|
69
|
+
client.table_function(
|
|
70
|
+
function_name="sequence",
|
|
71
|
+
schema_name="main",
|
|
72
|
+
arguments=Arguments(positional=[pa.scalar(4)]),
|
|
73
|
+
batch_metadata_callback=metas.append,
|
|
74
|
+
)
|
|
75
|
+
)
|
|
76
|
+
assert metas
|
|
77
|
+
assert all(m is None for m in metas)
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
# Copyright 2026 Query Farm LLC - https://query.farm
|
|
2
|
+
|
|
3
|
+
# ruff: noqa: S101, D101, D102, D103
|
|
4
|
+
"""`Client.table_scan_branches_get`.
|
|
5
|
+
|
|
6
|
+
`Client` had no wrapper for `catalog_table_scan_branches_get` at all —
|
|
7
|
+
grepped the whole `vgi/client/` package for "branch" and the only hit was an
|
|
8
|
+
unrelated code comment ("skip the subprocess branch"). A multi-branch table
|
|
9
|
+
was therefore invisible to any non-DuckDB caller, not just unsupported by a
|
|
10
|
+
higher-level connector. Exercised against `data.multi_branch_numbers` (two
|
|
11
|
+
`sequence(50)` arms — `vgi/_test_fixtures/worker.py`) and, for the legacy
|
|
12
|
+
fallback, `data.numbers` (an ordinary single-branch table whose worker only
|
|
13
|
+
implements the older `table_scan_function_get`).
|
|
14
|
+
"""
|
|
15
|
+
|
|
16
|
+
from __future__ import annotations
|
|
17
|
+
|
|
18
|
+
from typing import Any
|
|
19
|
+
|
|
20
|
+
import pytest
|
|
21
|
+
|
|
22
|
+
from vgi.catalog import ScanBranch, ScanBranchesResult
|
|
23
|
+
|
|
24
|
+
DATA = "data"
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
@pytest.fixture
|
|
28
|
+
def client(client_transport: Any) -> Any:
|
|
29
|
+
with client_transport() as c:
|
|
30
|
+
c.catalog_attach(name="example", data_version_spec=None, implementation_version=None)
|
|
31
|
+
yield c
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
def _attach_opaque(client: Any) -> Any:
|
|
35
|
+
# catalog_attach() was already called by the fixture above (its return
|
|
36
|
+
# value discarded) — re-attach here to get the opaque data this method
|
|
37
|
+
# needs, mirroring how CatalogClientMixin methods are used standalone.
|
|
38
|
+
return client.catalog_attach(name="example", data_version_spec=None, implementation_version=None).attach_opaque_data
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
def test_multi_branch_table_returns_all_branches(client: Any) -> None:
|
|
42
|
+
result = client.table_scan_branches_get(
|
|
43
|
+
attach_opaque_data=_attach_opaque(client),
|
|
44
|
+
schema_name=DATA,
|
|
45
|
+
name="multi_branch_numbers",
|
|
46
|
+
)
|
|
47
|
+
assert isinstance(result, ScanBranchesResult)
|
|
48
|
+
assert len(result.branches) == 2
|
|
49
|
+
for branch in result.branches:
|
|
50
|
+
assert isinstance(branch, ScanBranch)
|
|
51
|
+
assert branch.function_name == "sequence"
|
|
52
|
+
assert branch.source_table is None # function branch, not catalog-table
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
def test_single_branch_table_falls_back_to_legacy_rpc(client: Any) -> None:
|
|
56
|
+
"""`data.numbers` only implements `table_scan_function_get` — the fallback wraps it as one branch."""
|
|
57
|
+
result = client.table_scan_branches_get(
|
|
58
|
+
attach_opaque_data=_attach_opaque(client),
|
|
59
|
+
schema_name=DATA,
|
|
60
|
+
name="numbers",
|
|
61
|
+
)
|
|
62
|
+
assert len(result.branches) == 1
|
|
63
|
+
assert result.branches[0].function_name == client.table_scan_function_get(
|
|
64
|
+
attach_opaque_data=_attach_opaque(client),
|
|
65
|
+
schema_name=DATA,
|
|
66
|
+
name="numbers",
|
|
67
|
+
).function_name
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
# Copyright 2026 Query Farm LLC - https://query.farm
|
|
2
|
+
|
|
3
|
+
# ruff: noqa: S101, D101, D102, D103
|
|
4
|
+
"""`Client.table_function_plan` + `Client.table_function(split_tokens=...)`.
|
|
5
|
+
|
|
6
|
+
Splits were previously entirely unreachable from `Client` — no wrapper for
|
|
7
|
+
`on_plan()` existed at all, and `table_function()`/`_do_init` had no
|
|
8
|
+
`split_tokens` parameter to redeem one, even though the wire protocol
|
|
9
|
+
(`TableFunctionPlanRequest`/`PlanResponse`/`InitRequest.split_tokens`) and the
|
|
10
|
+
`VgiProtocol.table_function_plan` RPC already supported it — the DuckDB C++
|
|
11
|
+
extension drives this today, but the reference Python client never grew the
|
|
12
|
+
equivalent. Exercised against `split_sequence` (the split-capable twin of
|
|
13
|
+
`sequence`, `vgi/_test_fixtures/table/splits.py`) over every client transport.
|
|
14
|
+
"""
|
|
15
|
+
|
|
16
|
+
from __future__ import annotations
|
|
17
|
+
|
|
18
|
+
from typing import Any
|
|
19
|
+
|
|
20
|
+
import pyarrow as pa
|
|
21
|
+
import pytest
|
|
22
|
+
|
|
23
|
+
from vgi.arguments import Arguments
|
|
24
|
+
from vgi.protocol import ScanSplit
|
|
25
|
+
|
|
26
|
+
MAIN = "main"
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
@pytest.fixture
|
|
30
|
+
def client(client_transport: Any) -> Any:
|
|
31
|
+
with client_transport() as c:
|
|
32
|
+
c.catalog_attach(name="example", data_version_spec=None, implementation_version=None)
|
|
33
|
+
yield c
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
def test_plan_returns_typed_scan_splits(client: Any) -> None:
|
|
37
|
+
args = Arguments(named={"n": pa.scalar(20), "splits": pa.scalar(4)})
|
|
38
|
+
plan = client.table_function_plan(function_name="split_sequence", schema_name=MAIN, arguments=args)
|
|
39
|
+
assert len(plan.splits) == 4
|
|
40
|
+
for split in plan.splits:
|
|
41
|
+
assert isinstance(split, ScanSplit)
|
|
42
|
+
assert split.token # framework-stamped, non-empty
|
|
43
|
+
assert split.estimated_rows == 5
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
def test_redeeming_each_split_in_order_reproduces_the_whole_scan(client: Any) -> None:
|
|
47
|
+
"""split_sequence redeemed split-by-split must equal sequence(n)'s output.
|
|
48
|
+
|
|
49
|
+
Also threads ``split_execution_id``/``split_init_opaque_data`` from the
|
|
50
|
+
plan on every redemption — this fixture doesn't need cross-split shared
|
|
51
|
+
state to be correct, but this proves the wire path accepts and round-trips
|
|
52
|
+
them without erroring, for workers that do.
|
|
53
|
+
"""
|
|
54
|
+
args = Arguments(named={"n": pa.scalar(37), "splits": pa.scalar(5)})
|
|
55
|
+
plan = client.table_function_plan(function_name="split_sequence", schema_name=MAIN, arguments=args)
|
|
56
|
+
|
|
57
|
+
all_rows: list[int] = []
|
|
58
|
+
for split in plan.splits:
|
|
59
|
+
batches = list(
|
|
60
|
+
client.table_function(
|
|
61
|
+
function_name="split_sequence",
|
|
62
|
+
schema_name=MAIN,
|
|
63
|
+
arguments=args,
|
|
64
|
+
split_tokens=[split.token],
|
|
65
|
+
split_execution_id=plan.execution_id,
|
|
66
|
+
split_init_opaque_data=plan.init_opaque_data,
|
|
67
|
+
)
|
|
68
|
+
)
|
|
69
|
+
for batch in batches:
|
|
70
|
+
all_rows.extend(batch.column("n").to_pylist())
|
|
71
|
+
|
|
72
|
+
assert sorted(all_rows) == list(range(37))
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
def test_split_zero_yields_no_splits_and_no_rows(client: Any) -> None:
|
|
76
|
+
args = Arguments(named={"n": pa.scalar(10), "splits": pa.scalar(4)})
|
|
77
|
+
plan = client.table_function_plan(function_name="split_zero", schema_name=MAIN, arguments=args)
|
|
78
|
+
assert plan.splits == []
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
def test_redeeming_a_split_forces_single_worker(client: Any) -> None:
|
|
82
|
+
"""`split_tokens` bypasses `_spawn_additional_workers` — no additional worker connections open."""
|
|
83
|
+
args = Arguments(named={"n": pa.scalar(8), "splits": pa.scalar(2)})
|
|
84
|
+
plan = client.table_function_plan(function_name="split_sequence", schema_name=MAIN, arguments=args)
|
|
85
|
+
list(
|
|
86
|
+
client.table_function(
|
|
87
|
+
function_name="split_sequence",
|
|
88
|
+
schema_name=MAIN,
|
|
89
|
+
arguments=args,
|
|
90
|
+
split_tokens=[plan.splits[0].token],
|
|
91
|
+
)
|
|
92
|
+
)
|
|
93
|
+
assert client._additional_workers == []
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
# Copyright 2026 Query Farm LLC - https://query.farm
|
|
2
|
+
|
|
3
|
+
# ruff: noqa: S101, D101, D102, D103
|
|
4
|
+
"""`Client.table_get`/`table_function(at_unit=..., at_value=...)`.
|
|
5
|
+
|
|
6
|
+
Both methods previously dropped `at_unit`/`at_value` on the floor even though
|
|
7
|
+
the underlying wire RPCs (`catalog_table_get`, `BindRequest.at_unit`/
|
|
8
|
+
`.at_value`) already carried them — `table_scan_function_get` was the only
|
|
9
|
+
`Client` method that exposed time travel at all. Two distinct worker
|
|
10
|
+
patterns are exercised, both real fixtures, proving this isn't just plumbing
|
|
11
|
+
that happens to compile:
|
|
12
|
+
|
|
13
|
+
* `data.versioned_data` reads its version through a pre-resolved bind
|
|
14
|
+
argument (`table_scan_function_get(at_unit=...)` bakes it into the
|
|
15
|
+
returned `ScanFunctionResult.arguments`) — `table_get(at_unit=...)` is
|
|
16
|
+
what needed fixing here, to see the schema at that version at all.
|
|
17
|
+
* `data.tt_pushdown_fn` (`tt_pushdown_scan`) reads `at_unit`/`at_value`
|
|
18
|
+
**directly off the init request** (`ProcessParams.at_unit`/`.at_value`,
|
|
19
|
+
see `vgi/_test_fixtures/table/tt_pushdown.py`) — this is the pattern that
|
|
20
|
+
needed `table_function(at_unit=...)` specifically; no amount of
|
|
21
|
+
pre-resolved arguments would reach it.
|
|
22
|
+
"""
|
|
23
|
+
|
|
24
|
+
from __future__ import annotations
|
|
25
|
+
|
|
26
|
+
from typing import Any
|
|
27
|
+
|
|
28
|
+
import pyarrow as pa
|
|
29
|
+
import pytest
|
|
30
|
+
|
|
31
|
+
from vgi.arguments import Arguments
|
|
32
|
+
|
|
33
|
+
DATA = "data"
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
@pytest.fixture
|
|
37
|
+
def client(client_transport: Any) -> Any:
|
|
38
|
+
with client_transport() as c:
|
|
39
|
+
c.catalog_attach(name="example", data_version_spec=None, implementation_version=None)
|
|
40
|
+
yield c
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
def _attach_opaque(client: Any) -> Any:
|
|
44
|
+
result = client.catalog_attach(name="example", data_version_spec=None, implementation_version=None)
|
|
45
|
+
return result.attach_opaque_data
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
def test_table_get_at_unit_returns_the_versioned_schema(client: Any) -> None:
|
|
49
|
+
opaque = _attach_opaque(client)
|
|
50
|
+
v1 = client.table_get(
|
|
51
|
+
attach_opaque_data=opaque, schema_name=DATA, name="versioned_data", at_unit="VERSION", at_value="1"
|
|
52
|
+
)
|
|
53
|
+
live = client.table_get(attach_opaque_data=opaque, schema_name=DATA, name="versioned_data")
|
|
54
|
+
|
|
55
|
+
v1_schema = pa.ipc.read_schema(pa.py_buffer(v1.columns))
|
|
56
|
+
live_schema = pa.ipc.read_schema(pa.py_buffer(live.columns))
|
|
57
|
+
assert v1_schema.names == ["id"] # version 1: (id int64) only
|
|
58
|
+
assert live_schema.names == ["id", "score"] # current: version 3
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
def test_table_get_with_no_at_clause_is_unaffected(client: Any) -> None:
|
|
62
|
+
"""The new `at_unit`/`at_value` params default to `None` — unchanged behavior without them."""
|
|
63
|
+
info = client.table_get(attach_opaque_data=_attach_opaque(client), schema_name=DATA, name="numbers")
|
|
64
|
+
assert info is not None
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
def test_table_function_at_unit_reaches_a_worker_that_reads_it_from_init(client: Any) -> None:
|
|
68
|
+
"""`tt_pushdown_scan` reads `at_unit`/`at_value` off the init request, not a resolved bind arg."""
|
|
69
|
+
v1_batches = list(
|
|
70
|
+
client.table_function(function_name="tt_pushdown_scan", schema_name=DATA, at_unit="VERSION", at_value="1")
|
|
71
|
+
)
|
|
72
|
+
live_batches = list(client.table_function(function_name="tt_pushdown_scan", schema_name=DATA))
|
|
73
|
+
|
|
74
|
+
assert sum(b.num_rows for b in v1_batches) == 5
|
|
75
|
+
assert sum(b.num_rows for b in live_batches) == 10
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
def test_table_function_with_no_at_clause_is_unaffected(client: Any) -> None:
|
|
79
|
+
"""The new `at_unit`/`at_value` params default to `None` — unchanged behavior without them."""
|
|
80
|
+
batches = list(
|
|
81
|
+
client.table_function(
|
|
82
|
+
function_name="sequence", schema_name="main", arguments=Arguments(positional=[pa.scalar(5)])
|
|
83
|
+
)
|
|
84
|
+
)
|
|
85
|
+
assert sum(b.num_rows for b in batches) == 5
|
|
@@ -929,6 +929,11 @@ wheels = [
|
|
|
929
929
|
{ url = "https://files.pythonhosted.org/packages/b9/6d/a637d52449d98a6892d9a4dc0262587afdb6a66f201871842dce5a97b1c1/httpx2-2.10.0-py3-none-any.whl", hash = "sha256:5e3194a432701e1cc6f69a8b1b2fa199ef907013fede8d9a09a2c5b7b8141a18", size = 94355, upload-time = "2026-08-09T09:11:30.882Z" },
|
|
930
930
|
]
|
|
931
931
|
|
|
932
|
+
[package.optional-dependencies]
|
|
933
|
+
zstd = [
|
|
934
|
+
{ name = "zstandard", marker = "python_full_version < '3.14'" },
|
|
935
|
+
]
|
|
936
|
+
|
|
932
937
|
[[package]]
|
|
933
938
|
name = "httpx2-jsfetch"
|
|
934
939
|
version = "1.0"
|
|
@@ -2555,7 +2560,7 @@ requires-dist = [
|
|
|
2555
2560
|
|
|
2556
2561
|
[[package]]
|
|
2557
2562
|
name = "vgi-python"
|
|
2558
|
-
version = "0.
|
|
2563
|
+
version = "0.29.2"
|
|
2559
2564
|
source = { editable = "." }
|
|
2560
2565
|
dependencies = [
|
|
2561
2566
|
{ name = "click" },
|
|
@@ -2698,7 +2703,7 @@ docs = [
|
|
|
2698
2703
|
|
|
2699
2704
|
[[package]]
|
|
2700
2705
|
name = "vgi-rpc"
|
|
2701
|
-
version = "0.43.
|
|
2706
|
+
version = "0.43.1"
|
|
2702
2707
|
source = { registry = "https://pypi.org/simple" }
|
|
2703
2708
|
dependencies = [
|
|
2704
2709
|
{ name = "docstring-parser" },
|
|
@@ -2706,9 +2711,9 @@ dependencies = [
|
|
|
2706
2711
|
{ name = "pywin32", marker = "sys_platform == 'win32'" },
|
|
2707
2712
|
{ name = "tzdata", marker = "sys_platform == 'win32'" },
|
|
2708
2713
|
]
|
|
2709
|
-
sdist = { url = "https://files.pythonhosted.org/packages/
|
|
2714
|
+
sdist = { url = "https://files.pythonhosted.org/packages/27/a0/b308cc62cde38fe2a7bc7a2c57bbb8e956084dd04134a4b0d805378daf16/vgi_rpc-0.43.1.tar.gz", hash = "sha256:d94a3c2cfcf90e1122b2b7ec23a47912f1b3e2d265267aa6704bd64c3a7f2a55", size = 1145519, upload-time = "2026-08-27T14:51:14.923Z" }
|
|
2710
2715
|
wheels = [
|
|
2711
|
-
{ url = "https://files.pythonhosted.org/packages/
|
|
2716
|
+
{ url = "https://files.pythonhosted.org/packages/96/f2/15bd8a76ee3534c4d911b0f76c948378db4c175a40ceeb30325e6ab994a6/vgi_rpc-0.43.1-py3-none-any.whl", hash = "sha256:1eecd6c17f06d6fadae332be33998d22cdd01e5caaaae7889b747f0c1eaac498", size = 526753, upload-time = "2026-08-27T14:51:12.975Z" },
|
|
2712
2717
|
]
|
|
2713
2718
|
|
|
2714
2719
|
[package.optional-dependencies]
|
|
@@ -2723,7 +2728,7 @@ external = [
|
|
|
2723
2728
|
]
|
|
2724
2729
|
http = [
|
|
2725
2730
|
{ name = "falcon" },
|
|
2726
|
-
{ name = "httpx2" },
|
|
2731
|
+
{ name = "httpx2", extra = ["zstd"] },
|
|
2727
2732
|
{ name = "msgpack" },
|
|
2728
2733
|
{ name = "pycryptodome" },
|
|
2729
2734
|
{ name = "pynacl", marker = "sys_platform == 'linux'" },
|
|
@@ -95,6 +95,7 @@ __all__ = [
|
|
|
95
95
|
"RowSumFunction",
|
|
96
96
|
"BlendedDropFunction",
|
|
97
97
|
"SubstreamPartialSumFunction",
|
|
98
|
+
"MultiBatchFinishFunction",
|
|
98
99
|
"SumAllColumnsFunction",
|
|
99
100
|
"SumAllColumnsSimpleDistributed",
|
|
100
101
|
"ExceptionProcessFunction",
|
|
@@ -195,6 +196,88 @@ class SubstreamPartialSumFunction(TableInOutFunction[SingleTableArguments, Subst
|
|
|
195
196
|
return [pa.RecordBatch.from_pydict({name: [total]}, schema=params.output_schema)]
|
|
196
197
|
|
|
197
198
|
|
|
199
|
+
@dataclass(kw_only=True)
|
|
200
|
+
class MultiBatchFinishState(ArrowSerializableDataclass):
|
|
201
|
+
"""This substream's running total and the number of rows it saw."""
|
|
202
|
+
|
|
203
|
+
total: int = 0
|
|
204
|
+
rows: int = 0
|
|
205
|
+
|
|
206
|
+
|
|
207
|
+
class MultiBatchFinishFunction(TableInOutFunction[SingleTableArguments, MultiBatchFinishState]):
|
|
208
|
+
"""Streaming FINALIZE that emits MANY batches — the shape no SDK had a fixture for.
|
|
209
|
+
|
|
210
|
+
Every other finalize fixture returns a single batch, and one batch is the
|
|
211
|
+
easy case: over HTTP a producer is strictly lock-step (one batch per
|
|
212
|
+
response), so a single-batch flush completes in one turn and never needs a
|
|
213
|
+
continuation. A flush of TWO OR MORE batches does, and in vgi-rust that path
|
|
214
|
+
was a hard error rather than a pagination — invisible for as long as nothing
|
|
215
|
+
exercised it.
|
|
216
|
+
|
|
217
|
+
So this emits one batch per input row the substream saw: ``rows`` batches,
|
|
218
|
+
the first carrying that substream's ``total`` and the rest carrying 0. The
|
|
219
|
+
split is deliberate — it makes the two failure modes distinguishable:
|
|
220
|
+
|
|
221
|
+
* ``SUM(n)`` wrong → a batch's CONTENTS were lost, duplicated or reordered.
|
|
222
|
+
* ``COUNT(*)`` wrong → a BATCH was lost or repeated. This is the one that
|
|
223
|
+
catches a broken continuation: a flush truncated after its first batch
|
|
224
|
+
still sums correctly and only the count betrays it.
|
|
225
|
+
|
|
226
|
+
Both invariants hold regardless of how DuckDB fans the input across
|
|
227
|
+
substreams (each substream's partials sum to the whole, and its batch count
|
|
228
|
+
equals its row count), so the test needs no assumption about thread count.
|
|
229
|
+
"""
|
|
230
|
+
|
|
231
|
+
class Meta:
|
|
232
|
+
name = "multi_batch_finish"
|
|
233
|
+
description = "Streaming finalize that emits one batch per input row (multi-batch flush)"
|
|
234
|
+
categories = ["testing", "aggregation"]
|
|
235
|
+
|
|
236
|
+
@classmethod
|
|
237
|
+
def cardinality(cls, params: BindParams[SingleTableArguments]) -> TableCardinality:
|
|
238
|
+
# One output row per input row, but the input size is unknown up-front.
|
|
239
|
+
return TableCardinality(estimate=1, max=None)
|
|
240
|
+
|
|
241
|
+
@classmethod
|
|
242
|
+
def on_bind(cls, params: BindParams[SingleTableArguments]) -> BindResponse:
|
|
243
|
+
assert params.bind_call.input_schema is not None
|
|
244
|
+
field = params.bind_call.input_schema.field(0)
|
|
245
|
+
return BindResponse(output_schema=schema({field.name: pa.int64()}))
|
|
246
|
+
|
|
247
|
+
@classmethod
|
|
248
|
+
def initial_state(cls, params: ProcessParams[SingleTableArguments]) -> MultiBatchFinishState:
|
|
249
|
+
return MultiBatchFinishState(total=0, rows=0)
|
|
250
|
+
|
|
251
|
+
@classmethod
|
|
252
|
+
def transform(
|
|
253
|
+
cls,
|
|
254
|
+
batch: pa.RecordBatch,
|
|
255
|
+
params: ProcessParams[SingleTableArguments],
|
|
256
|
+
state: MultiBatchFinishState | None,
|
|
257
|
+
) -> list[pa.RecordBatch]:
|
|
258
|
+
if state is None:
|
|
259
|
+
raise ValueError("State must not be None in transform()")
|
|
260
|
+
col_sum = pc.sum(batch.column(0))
|
|
261
|
+
if col_sum.is_valid:
|
|
262
|
+
state.total += col_sum.as_py()
|
|
263
|
+
state.rows += batch.num_rows
|
|
264
|
+
return [] # accumulate only; the whole point is the flush
|
|
265
|
+
|
|
266
|
+
@classmethod
|
|
267
|
+
def finish(
|
|
268
|
+
cls,
|
|
269
|
+
params: ProcessParams[SingleTableArguments],
|
|
270
|
+
states: list[MultiBatchFinishState],
|
|
271
|
+
) -> list[pa.RecordBatch]:
|
|
272
|
+
total = sum(st.total for st in states)
|
|
273
|
+
rows = sum(st.rows for st in states)
|
|
274
|
+
name = params.output_schema.names[0]
|
|
275
|
+
return [
|
|
276
|
+
pa.RecordBatch.from_pydict({name: [total if i == 0 else 0]}, schema=params.output_schema)
|
|
277
|
+
for i in range(rows)
|
|
278
|
+
]
|
|
279
|
+
|
|
280
|
+
|
|
198
281
|
class EchoFunction(TableInOutGenerator[SingleTableArguments]):
|
|
199
282
|
"""Passthrough function that emits each input batch unchanged.
|
|
200
283
|
|
|
@@ -1097,7 +1180,19 @@ class CrashOnProcessFunction(BufferInputFunction):
|
|
|
1097
1180
|
os.kill(os.getpid(), signal.SIGABRT)
|
|
1098
1181
|
else:
|
|
1099
1182
|
os.kill(os.getpid(), signal.SIGKILL)
|
|
1100
|
-
|
|
1183
|
+
# Killing YOURSELF is not synchronous: kill(2) returns on the calling
|
|
1184
|
+
# thread and the kernel tears the task down asynchronously. RETURNING
|
|
1185
|
+
# here hands that window to the framework, which then races to serialize
|
|
1186
|
+
# and write the process response — and how many bytes escape before the
|
|
1187
|
+
# process actually dies decides what the client sees: nothing (the
|
|
1188
|
+
# "RPC response stream EOF" these tests assert), a schema only, a
|
|
1189
|
+
# truncated batch message, or the whole response, in which case the
|
|
1190
|
+
# query SUCCEEDS with zero rows. Measured in the Go SDK, whose fixture
|
|
1191
|
+
# had the identical shape, that was a 23% failure rate — see
|
|
1192
|
+
# vgi-go 41f18d1. CPython's slower interpreter makes it rarer here, not
|
|
1193
|
+
# impossible. Park instead, so this worker can never write another byte.
|
|
1194
|
+
time.sleep(5)
|
|
1195
|
+
raise AssertionError("crash_on_process: SIGKILL did not terminate the worker")
|
|
1101
1196
|
|
|
1102
1197
|
|
|
1103
1198
|
class CrashOnCombineFunction(BufferInputFunction):
|
|
@@ -286,6 +286,7 @@ from vgi._test_fixtures.table_in_out import (
|
|
|
286
286
|
HangOnProcessFunction,
|
|
287
287
|
HostileProvenanceFunction,
|
|
288
288
|
LargeStateFunction,
|
|
289
|
+
MultiBatchFinishFunction,
|
|
289
290
|
OrderedBufferInputFunction,
|
|
290
291
|
OrderedSourceFunction,
|
|
291
292
|
ProjectableBlendedFunction,
|
|
@@ -441,6 +442,7 @@ _EXAMPLE_CATALOG = Catalog(
|
|
|
441
442
|
SecretInOutFunction,
|
|
442
443
|
RepeatInputsFunction,
|
|
443
444
|
SlowCancellableInOutFunction,
|
|
445
|
+
MultiBatchFinishFunction,
|
|
444
446
|
SubstreamPartialSumFunction,
|
|
445
447
|
SumAllColumnsFunction,
|
|
446
448
|
SumAllColumnsSimpleDistributed,
|