vgi-python 0.29.3__tar.gz → 0.29.4__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.3 → vgi_python-0.29.4}/PKG-INFO +6 -3
- {vgi_python-0.29.3 → vgi_python-0.29.4}/pyproject.toml +9 -4
- vgi_python-0.29.4/tests/test_launch_transport.py +114 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/uv.lock +27 -9
- {vgi_python-0.29.3 → vgi_python-0.29.4}/vgi/client/catalog_mixin.py +31 -4
- {vgi_python-0.29.3 → vgi_python-0.29.4}/vgi/client/client.py +150 -8
- {vgi_python-0.29.3 → vgi_python-0.29.4}/.gitattributes +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/.github/dependabot.yml +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/.github/styles/config/vocabularies/VGI/accept.txt +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/.github/workflows/ci.yml +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/.github/workflows/docs.yml +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/.github/workflows/integration.yml +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/.github/workflows/release.yml +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/.gitignore +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/.python-version +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/.vale.ini +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/CLAUDE.md +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/DOCS_ACCEPTANCE_CRITERIA.md +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/DOCS_REVIEW_RUBRIC.md +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/DOCS_USABILITY_TEST.md +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/LICENSE +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/README.md +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/RELEASE-RUNBOOK.md +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/SECURITY.md +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/ci/README.md +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/ci/preprocess-require.awk +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/ci/run-integration.sh +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/dist-vgi/.gitignore +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/docs/aggregate-functions.md +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/docs/api/arguments.md +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/docs/api/auth.md +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/docs/api/catalogs.md +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/docs/api/client.md +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/docs/api/exceptions.md +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/docs/api/filters.md +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/docs/api/functions.md +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/docs/api/http.md +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/docs/api/index.md +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/docs/api/metadata.md +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/docs/api/observability.md +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/docs/api/storage.md +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/docs/api/transactor.md +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/docs/api/worker.md +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/docs/argument-serialization.md +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/docs/assets/apple-touch-icon.png +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/docs/assets/favicon-16x16.png +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/docs/assets/favicon-32x32.png +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/docs/assets/favicon.ico +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/docs/assets/kinds/aggregate.svg +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/docs/assets/kinds/buffering.svg +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/docs/assets/kinds/scalar.svg +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/docs/assets/kinds/table-in-out.svg +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/docs/assets/kinds/table.svg +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/docs/assets/logo.png +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/docs/assets/social-card.png +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/docs/authentication.md +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/docs/catalog-interface.md +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/docs/cli.md +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/docs/column-statistics.md +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/docs/concepts/index.md +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/docs/contributing-docs.md +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/docs/filter-pushdown.md +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/docs/generator-api.md +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/docs/global-functions.md +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/docs/how-to/catalogs.md +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/docs/how-to/function-patterns.md +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/docs/how-to/http-auth.md +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/docs/how-to/index.md +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/docs/how-to/pushdown-and-statistics.md +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/docs/how-to/state-storage.md +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/docs/index.md +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/docs/lifecycle.md +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/docs/metadata.md +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/docs/overrides/main.html +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/docs/robots.txt +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/docs/shared-storage.md +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/docs/stylesheets/extra.css +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/docs/tutorial/index.md +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/docs/tutorial/scalar.md +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/docs/tutorial/table.md +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/docs/vgi-logo.png +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/examples/batch_index_worker.py +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/examples/cache_worker.py +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/examples/calc_scalar_worker.py +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/examples/calc_worker.py +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/examples/copy_format_worker.py +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/examples/filter_worker.py +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/examples/greeting_scalar_worker.py +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/examples/row_count_worker.py +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/examples/series_streaming_worker.py +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/examples/sum_worker.py +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/mkdocs.yml +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/packages/vgi-fixtures/LICENSE +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/packages/vgi-fixtures/README.md +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/packages/vgi-fixtures/docker/Dockerfile +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/packages/vgi-fixtures/docker/docker-entrypoint.sh +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/packages/vgi-fixtures/pyproject.toml +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/scripts/measure_startup.py +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/scripts/run_all_tests.sh +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/test-data/generate.sh +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/tests/__init__.py +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/tests/_http_fixtures.py +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/tests/catalog/__init__.py +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/tests/catalog/test_attach_option.py +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/tests/catalog/test_catalog_interface.py +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/tests/catalog/test_client_catalog.py +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/tests/catalog/test_column_statistics.py +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/tests/catalog/test_declarative.py +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/tests/catalog/test_example_worker_catalog.py +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/tests/catalog/test_integration.py +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/tests/catalog/test_required_filters.py +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/tests/catalog/test_scan_branches.py +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/tests/catalog/test_serialization.py +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/tests/catalog/test_setting.py +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/tests/catalog/test_storage.py +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/tests/catalog/test_time_travel.py +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/tests/catalog/test_writable_table.py +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/tests/client/__init__.py +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/tests/client/test_aggregate_client.py +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/tests/client/test_batch_metadata_callback.py +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/tests/client/test_broken_pipe.py +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/tests/client/test_cli.py +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/tests/client/test_cli_catalog_functions.py +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/tests/client/test_copy_client.py +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/tests/client/test_scan_branches_client.py +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/tests/client/test_split_client.py +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/tests/client/test_stop_force.py +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/tests/client/test_table_column_statistics.py +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/tests/client/test_time_travel_client.py +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/tests/client/test_worker_debug.py +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/tests/conformance/__init__.py +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/tests/conformance/_stub.py +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/tests/conformance/conftest.py +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/tests/conformance/test_accumulate.py +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/tests/conformance/test_aggregate.py +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/tests/conformance/test_attach.py +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/tests/conformance/test_bearer_auth.py +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/tests/conformance/test_const_param_enforcement.py +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/tests/conformance/test_container.py +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/tests/conformance/test_copy_from.py +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/tests/conformance/test_copy_to.py +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/tests/conformance/test_directory_parity.py +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/tests/conformance/test_function_inventory.py +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/tests/conformance/test_github.py +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/tests/conformance/test_http_client.py +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/tests/conformance/test_http_external_location.py +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/tests/conformance/test_http_upload_url.py +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/tests/conformance/test_macro.py +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/tests/conformance/test_overload.py +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/tests/conformance/test_protocol_inventory.py +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/tests/conformance/test_protocol_version.py +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/tests/conformance/test_resumable_scan.py +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/tests/conformance/test_scalar.py +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/tests/conformance/test_scalar_attach_opaque_data.py +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/tests/conformance/test_secret.py +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/tests/conformance/test_settings.py +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/tests/conformance/test_splits.py +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/tests/conformance/test_table.py +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/tests/conformance/test_table_in_out.py +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/tests/conformance/test_view.py +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/tests/conformance/test_writable.py +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/tests/conftest.py +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/tests/data/split_tokens/anchor_len_overrun.bin +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/tests/data/split_tokens/bad_fingerprint.bin +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/tests/data/split_tokens/bad_flags_unsealed_but_key_present.bin +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/tests/data/split_tokens/bad_version.bin +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/tests/data/split_tokens/generate.py +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/tests/data/split_tokens/manifest.json +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/tests/data/split_tokens/reserved_flag_bit.bin +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/tests/data/split_tokens/stale_anchor.bin +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/tests/data/split_tokens/truncated.bin +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/tests/data/split_tokens/valid_sealed.bin +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/tests/data/split_tokens/valid_unsealed.bin +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/tests/scalar/__init__.py +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/tests/scalar/test_bernoulli_function.py +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/tests/scalar/test_binary_packet_function.py +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/tests/scalar/test_client.py +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/tests/scalar/test_conditional_message_function.py +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/tests/scalar/test_hash_seed_function.py +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/tests/scalar/test_multiply_by_setting_function.py +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/tests/scalar/test_multiply_function.py +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/tests/scalar/test_random_bytes_function.py +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/tests/scalar/test_return_secret_value_function.py +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/tests/table/__init__.py +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/tests/table/generator/__init__.py +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/tests/table/generator/test_constant_columns_function.py +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/tests/table/generator/test_double_sequence_function.py +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/tests/table/generator/test_exception_function.py +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/tests/table/generator/test_filter_echo_function.py +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/tests/table/generator/test_logging_function.py +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/tests/table/generator/test_nested_sequence_function.py +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/tests/table/generator/test_partitioned_function.py +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/tests/table/generator/test_projected_data_function.py +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/tests/table/generator/test_sequence_function.py +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/tests/table/generator/test_settings_function.py +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/tests/table/generator/test_struct_settings_function.py +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/tests/table/generator/test_ten_thousand_function.py +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/tests/table/test_wide_columns.py +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/tests/table_in_out/__init__.py +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/tests/table_in_out/generator/__init__.py +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/tests/table_in_out/generator/test_buffer_input_function.py +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/tests/table_in_out/generator/test_echo_function.py +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/tests/table_in_out/generator/test_exception_functions.py +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/tests/table_in_out/generator/test_filter_by_setting_function.py +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/tests/table_in_out/generator/test_repeat_inputs_function.py +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/tests/table_in_out/generator/test_substream_partial_sum_function.py +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/tests/table_in_out/generator/test_sum_all_columns_function.py +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/tests/table_in_out/test_blended_metadata.py +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/tests/table_in_out/test_client.py +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/tests/test_access_log_audit.py +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/tests/test_aggregate_function.py +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/tests/test_argument_spec.py +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/tests/test_auth.py +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/tests/test_bind_exceptions.py +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/tests/test_bind_request_at_clause.py +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/tests/test_bound_storage_conformance.py +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/tests/test_cache_control.py +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/tests/test_call_state_attach.py +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/tests/test_catalog_auth_binding.py +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/tests/test_copy_from_function.py +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/tests/test_copy_to_function.py +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/tests/test_docstrings.py +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/tests/test_documentation_examples.py +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/tests/test_example_function_arg_types.py +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/tests/test_examples_workers.py +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/tests/test_exception_handling.py +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/tests/test_exceptions.py +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/tests/test_filter_pushdown.py +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/tests/test_filter_pushdown_extension.py +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/tests/test_fixture_catalog_parity.py +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/tests/test_function_storage.py +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/tests/test_function_storage_azure_sql.py +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/tests/test_function_storage_cf_do.py +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/tests/test_function_storage_cf_do_integration.py +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/tests/test_function_storage_conformance.py +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/tests/test_generated_cpp_constants.py +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/tests/test_generated_cpp_protocol_version.py +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/tests/test_generated_cpp_request_builders.py +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/tests/test_generated_cpp_schemas.py +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/tests/test_generated_cpp_secret.py +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/tests/test_generated_go_schemas.py +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/tests/test_generated_java_schemas.py +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/tests/test_generated_protocol_version.py +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/tests/test_generated_rust_request_builders.py +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/tests/test_generated_rust_schemas.py +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/tests/test_generated_schemas_cross_lang.py +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/tests/test_generated_ts_client.py +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/tests/test_generated_ts_schemas.py +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/tests/test_http_demo_storage.py +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/tests/test_http_s3_offload_input.py +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/tests/test_http_s3_offload_output.py +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/tests/test_metadata.py +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/tests/test_mypy_consolidated.py +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/tests/test_nest_tensor.py +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/tests/test_otel.py +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/tests/test_projection_enforcement.py +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/tests/test_projection_repro.py +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/tests/test_protocol_classes.py +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/tests/test_resolved_secrets.py +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/tests/test_schema_scoped_functions.py +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/tests/test_schema_utils.py +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/tests/test_serve.py +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/tests/test_setting_secret_annotations.py +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/tests/test_signing_key.py +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/tests/test_split_token.py +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/tests/test_table_buffering_function.py +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/tests/test_table_function_dynamic_to_string.py +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/tests/test_tcp_transport.py +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/tests/test_type_bounds.py +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/tests/test_union_argument.py +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/tests/test_wire_record_schema_parity.py +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/tests/test_worker.py +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/tests/test_worker_cli.py +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/tests/test_worker_page.py +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/tests/transactor/__init__.py +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/tests/transactor/test_transactor.py +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/vgi/__init__.py +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/vgi/_duckdb.py +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/vgi/_storage_profile.py +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/vgi/_test_fixtures/__init__.py +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/vgi/_test_fixtures/accumulate/__init__.py +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/vgi/_test_fixtures/accumulate/worker.py +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/vgi/_test_fixtures/aggregate/__init__.py +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/vgi/_test_fixtures/aggregate/_common.py +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/vgi/_test_fixtures/aggregate/basic.py +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/vgi/_test_fixtures/aggregate/dynamic.py +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/vgi/_test_fixtures/aggregate/generic.py +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/vgi/_test_fixtures/aggregate/listagg.py +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/vgi/_test_fixtures/aggregate/percentile.py +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/vgi/_test_fixtures/aggregate/same_name.py +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/vgi/_test_fixtures/aggregate/secret_typed.py +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/vgi/_test_fixtures/aggregate/streaming.py +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/vgi/_test_fixtures/aggregate/varargs.py +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/vgi/_test_fixtures/aggregate/window.py +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/vgi/_test_fixtures/attach_options.py +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/vgi/_test_fixtures/bad_enum.py +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/vgi/_test_fixtures/bad_protocol.py +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/vgi/_test_fixtures/cancellable.py +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/vgi/_test_fixtures/catalog.py +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/vgi/_test_fixtures/companion.py +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/vgi/_test_fixtures/copy_from.py +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/vgi/_test_fixtures/copy_to.py +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/vgi/_test_fixtures/global_functions.py +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/vgi/_test_fixtures/http_server.py +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/vgi/_test_fixtures/narrow_bind/__init__.py +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/vgi/_test_fixtures/narrow_bind/worker.py +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/vgi/_test_fixtures/nest_tensor.py +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/vgi/_test_fixtures/orchard_catalog.py +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/vgi/_test_fixtures/projection_repro/__init__.py +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/vgi/_test_fixtures/projection_repro/worker.py +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/vgi/_test_fixtures/scalar/__init__.py +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/vgi/_test_fixtures/scalar/_common.py +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/vgi/_test_fixtures/scalar/arithmetic.py +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/vgi/_test_fixtures/scalar/bench_ladder.py +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/vgi/_test_fixtures/scalar/binary.py +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/vgi/_test_fixtures/scalar/formatting.py +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/vgi/_test_fixtures/scalar/geo.py +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/vgi/_test_fixtures/scalar/null_handling.py +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/vgi/_test_fixtures/scalar/random_demo.py +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/vgi/_test_fixtures/scalar/same_name.py +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/vgi/_test_fixtures/scalar/settings_secrets.py +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/vgi/_test_fixtures/scalar/type_info.py +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/vgi/_test_fixtures/schema_reconcile/__init__.py +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/vgi/_test_fixtures/schema_reconcile/worker.py +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/vgi/_test_fixtures/simple_writable.py +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/vgi/_test_fixtures/table/__init__.py +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/vgi/_test_fixtures/table/_common.py +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/vgi/_test_fixtures/table/batch_index.py +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/vgi/_test_fixtures/table/batch_index_broken.py +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/vgi/_test_fixtures/table/cache.py +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/vgi/_test_fixtures/table/catalog_scans.py +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/vgi/_test_fixtures/table/filters.py +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/vgi/_test_fixtures/table/late_materialization.py +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/vgi/_test_fixtures/table/make_series.py +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/vgi/_test_fixtures/table/misc.py +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/vgi/_test_fixtures/table/order_modes.py +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/vgi/_test_fixtures/table/pairs.py +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/vgi/_test_fixtures/table/partition_columns.py +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/vgi/_test_fixtures/table/partition_columns_broken.py +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/vgi/_test_fixtures/table/profiling_example.py +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/vgi/_test_fixtures/table/required_filters.py +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/vgi/_test_fixtures/table/same_name_cached.py +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/vgi/_test_fixtures/table/sequence.py +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/vgi/_test_fixtures/table/settings.py +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/vgi/_test_fixtures/table/splits.py +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/vgi/_test_fixtures/table/transaction_storage.py +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/vgi/_test_fixtures/table/tt_pushdown.py +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/vgi/_test_fixtures/table/typed_probe.py +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/vgi/_test_fixtures/table/versioned.py +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/vgi/_test_fixtures/table/wide.py +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/vgi/_test_fixtures/table_in_out.py +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/vgi/_test_fixtures/table_in_out_same_name.py +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/vgi/_test_fixtures/twin_catalogs.py +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/vgi/_test_fixtures/versioned.py +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/vgi/_test_fixtures/versioned_tables.py +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/vgi/_test_fixtures/worker.py +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/vgi/_test_fixtures/writable/__init__.py +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/vgi/_test_fixtures/writable/generic.py +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/vgi/_test_fixtures/writable/table.py +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/vgi/_test_fixtures/writable/worker.py +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/vgi/aggregate_function.py +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/vgi/argument_spec.py +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/vgi/arguments.py +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/vgi/attach_header.py +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/vgi/auth.py +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/vgi/cache_control.py +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/vgi/catalog/__init__.py +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/vgi/catalog/_descriptor_spec.py +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/vgi/catalog/attach_option.py +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/vgi/catalog/catalog_interface.py +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/vgi/catalog/descriptors.py +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/vgi/catalog/duckdb_statistics.py +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/vgi/catalog/secret_type.py +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/vgi/catalog/setting.py +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/vgi/catalog/storage.py +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/vgi/client/__init__.py +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/vgi/client/aggregate.py +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/vgi/client/cli.py +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/vgi/client/cli_catalog.py +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/vgi/client/cli_schema.py +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/vgi/client/cli_table.py +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/vgi/client/cli_transaction.py +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/vgi/client/cli_utils.py +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/vgi/client/cli_view.py +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/vgi/client/errors.py +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/vgi/codegen/__init__.py +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/vgi/codegen/_common.py +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/vgi/codegen/cpp_constants.py +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/vgi/codegen/cpp_protocol_version.py +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/vgi/codegen/cpp_request_builders.py +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/vgi/codegen/cpp_schemas.py +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/vgi/codegen/cpp_secret_protocol_version.py +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/vgi/codegen/cpp_secret_request_builders.py +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/vgi/codegen/cpp_secret_schemas.py +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/vgi/codegen/go_schemas.py +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/vgi/codegen/java_schemas.py +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/vgi/codegen/protocol_version.py +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/vgi/codegen/rust_request_builders.py +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/vgi/codegen/rust_schemas.py +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/vgi/codegen/ts_client.py +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/vgi/codegen/ts_schemas.py +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/vgi/copy_from_function.py +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/vgi/copy_to_function.py +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/vgi/exceptions.py +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/vgi/function.py +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/vgi/function_storage.py +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/vgi/function_storage_azure_sql.py +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/vgi/function_storage_cf_do.py +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/vgi/http/__init__.py +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/vgi/http/demo_storage.py +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/vgi/http/landing.html +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/vgi/http/landing_page.py +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/vgi/http/vgi-client.js +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/vgi/http/worker_page.py +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/vgi/invocation.py +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/vgi/logging_config.py +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/vgi/meta_worker.py +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/vgi/metadata.py +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/vgi/otel.py +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/vgi/profiling.py +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/vgi/protocol.py +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/vgi/protocol_version.txt +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/vgi/py.typed +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/vgi/scalar_function.py +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/vgi/schema_utils.py +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/vgi/secret_protocol.py +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/vgi/secret_service.py +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/vgi/serve.py +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/vgi/split_token.py +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/vgi/table_buffering_function.py +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/vgi/table_filter_pushdown.py +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/vgi/table_function.py +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/vgi/table_in_out_function.py +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/vgi/transactor/__init__.py +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/vgi/transactor/_duckdb_compat.py +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/vgi/transactor/client.py +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/vgi/transactor/protocol.py +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/vgi/transactor/server.py +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/vgi/worker.py +0 -0
- {vgi_python-0.29.3 → vgi_python-0.29.4}/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.4
|
|
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.43.
|
|
165
|
+
Requires-Dist: vgi-rpc>=0.43.2
|
|
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'
|
|
@@ -181,7 +181,8 @@ Requires-Dist: pytest-ruff; extra == 'dev'
|
|
|
181
181
|
Requires-Dist: pytest-xdist; extra == 'dev'
|
|
182
182
|
Requires-Dist: ruff; extra == 'dev'
|
|
183
183
|
Requires-Dist: sqlglot; extra == 'dev'
|
|
184
|
-
Requires-Dist: vgi-rpc[conformance,external,http,oauth,otel,sentry]; extra == 'dev'
|
|
184
|
+
Requires-Dist: vgi-rpc[cli,conformance,external,http,oauth,otel,sentry]; extra == 'dev'
|
|
185
|
+
Requires-Dist: vgi-rpc[cli]; extra == 'dev'
|
|
185
186
|
Requires-Dist: vgi-rpc[http]; extra == 'dev'
|
|
186
187
|
Requires-Dist: vgi-rpc[oauth]; extra == 'dev'
|
|
187
188
|
Requires-Dist: vgi-rpc[otel]; extra == 'dev'
|
|
@@ -197,6 +198,8 @@ Provides-Extra: haybarn
|
|
|
197
198
|
Requires-Dist: haybarn>=1.5.5rc1; extra == 'haybarn'
|
|
198
199
|
Provides-Extra: http
|
|
199
200
|
Requires-Dist: vgi-rpc[http]; extra == 'http'
|
|
201
|
+
Provides-Extra: launch
|
|
202
|
+
Requires-Dist: vgi-rpc[cli]; extra == 'launch'
|
|
200
203
|
Provides-Extra: oauth
|
|
201
204
|
Requires-Dist: vgi-rpc[oauth]; extra == 'oauth'
|
|
202
205
|
Provides-Extra: otel
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "vgi-python"
|
|
3
|
-
version = "0.29.
|
|
3
|
+
version = "0.29.4"
|
|
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.
|
|
43
|
+
"vgi-rpc>=0.43.2",
|
|
44
44
|
"httpx2>=2.9.1",
|
|
45
45
|
]
|
|
46
46
|
|
|
@@ -52,6 +52,11 @@ dependencies = [
|
|
|
52
52
|
haybarn = ["haybarn>=1.5.5rc1"]
|
|
53
53
|
duckdb = ["duckdb>=1.5.3"]
|
|
54
54
|
http = ["vgi-rpc[http]"]
|
|
55
|
+
# transport="launch": vgi_rpc.launcher imports filelock unconditionally at
|
|
56
|
+
# module level, which lives behind vgi-rpc's own `cli` extra (alongside
|
|
57
|
+
# typer, already a core dependency here, and httpx2, ditto) rather than in
|
|
58
|
+
# vgi-rpc's core dependency set.
|
|
59
|
+
launch = ["vgi-rpc[cli]"]
|
|
55
60
|
# Alternative HTTP server: granian moves socket I/O and HTTP parsing into Rust,
|
|
56
61
|
# off the GIL. Optional because it is a compiled extension where waitress is
|
|
57
62
|
# pure Python; select it with `vgi-serve --http --server granian`.
|
|
@@ -93,8 +98,8 @@ dev = [
|
|
|
93
98
|
"pytest-ruff",
|
|
94
99
|
"pytest-xdist",
|
|
95
100
|
"ruff",
|
|
96
|
-
"vgi-python[test-fixtures,test-fixtures-writable,http,oauth,otel,sentry,azure]",
|
|
97
|
-
"vgi-rpc[conformance,external,http,oauth,otel,sentry]",
|
|
101
|
+
"vgi-python[test-fixtures,test-fixtures-writable,http,launch,oauth,otel,sentry,azure]",
|
|
102
|
+
"vgi-rpc[cli,conformance,external,http,oauth,otel,sentry]",
|
|
98
103
|
]
|
|
99
104
|
[project.scripts]
|
|
100
105
|
vgi-serve = "vgi.serve:main"
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
# Copyright 2025, 2026 Query Farm LLC - https://query.farm
|
|
2
|
+
|
|
3
|
+
"""Round-trip tests for the launcher-managed (``transport="launch"``) transport.
|
|
4
|
+
|
|
5
|
+
Drives ``vgi._test_fixtures.worker`` (the same fixture module ``test_tcp_transport.py``
|
|
6
|
+
uses) through ``Client.from_launch(...)`` — no separate fixture worker needed, since
|
|
7
|
+
``MetaWorker.serve`` already passes argv through to ``vgi_rpc.rpc.run_server()``, which
|
|
8
|
+
participates in the AF_UNIX launcher path (``--unix PATH --idle-timeout SEC``) the same
|
|
9
|
+
way it participates in the TCP path (``--tcp HOST:PORT``).
|
|
10
|
+
"""
|
|
11
|
+
|
|
12
|
+
from __future__ import annotations
|
|
13
|
+
|
|
14
|
+
import shutil
|
|
15
|
+
import sys
|
|
16
|
+
import tempfile
|
|
17
|
+
import uuid
|
|
18
|
+
from collections.abc import Iterator
|
|
19
|
+
from pathlib import Path
|
|
20
|
+
|
|
21
|
+
import pyarrow as pa
|
|
22
|
+
import pytest
|
|
23
|
+
from vgi_rpc.launcher import status_rows
|
|
24
|
+
|
|
25
|
+
from vgi.arguments import Arguments
|
|
26
|
+
from vgi.client import Client
|
|
27
|
+
|
|
28
|
+
_WORKER_ARGV = (sys.executable, "-m", "vgi._test_fixtures.worker")
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
@pytest.fixture
|
|
32
|
+
def state_dir() -> Iterator[str]:
|
|
33
|
+
"""Per-test state dir under ``/tmp`` to stay under macOS's 104-byte AF_UNIX limit.
|
|
34
|
+
|
|
35
|
+
Mirrors ``vgi-rpc``'s own ``test_launcher.py`` fixture — ``tmp_path`` resolves to a
|
|
36
|
+
deeply nested path that, concatenated with ``<hash>.sock``, blows past the cap.
|
|
37
|
+
"""
|
|
38
|
+
d = Path(tempfile.gettempdir()) / f"vgi-launch-test-{uuid.uuid4().hex[:8]}"
|
|
39
|
+
d.mkdir(mode=0o700)
|
|
40
|
+
try:
|
|
41
|
+
yield str(d)
|
|
42
|
+
finally:
|
|
43
|
+
shutil.rmtree(d, ignore_errors=True)
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
def test_launch_round_trip_table_function(state_dir: str) -> None:
|
|
47
|
+
"""A table function streams rows correctly over the launch transport."""
|
|
48
|
+
with Client.from_launch(_WORKER_ARGV, idle_timeout=10.0, state_dir=state_dir) as client:
|
|
49
|
+
batches = list(
|
|
50
|
+
client.table_function(
|
|
51
|
+
function_name="sequence",
|
|
52
|
+
schema_name="main",
|
|
53
|
+
arguments=Arguments(positional=(pa.scalar(5),)),
|
|
54
|
+
)
|
|
55
|
+
)
|
|
56
|
+
|
|
57
|
+
table = pa.Table.from_batches(batches)
|
|
58
|
+
assert table.column("n").to_pylist() == [0, 1, 2, 3, 4]
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
def test_launch_round_trip_catalog_listing(state_dir: str) -> None:
|
|
62
|
+
"""Catalog discovery works over the launch transport (catalog_mixin path)."""
|
|
63
|
+
with Client.from_launch(_WORKER_ARGV, idle_timeout=10.0, state_dir=state_dir) as client:
|
|
64
|
+
catalogs = client.catalogs()
|
|
65
|
+
|
|
66
|
+
assert any(c.name == "example" for c in catalogs)
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
def test_launch_shares_one_worker_across_clients(state_dir: str) -> None:
|
|
70
|
+
"""Two `Client`s with the same worker_argv + state_dir share one warm worker.
|
|
71
|
+
|
|
72
|
+
The whole point of the launcher over plain subprocess/TCP: a second client
|
|
73
|
+
pointing at the same command must reuse the first client's worker rather than
|
|
74
|
+
spawning its own. Proven by checking exactly one tracked worker exists in the
|
|
75
|
+
shared state dir after both clients have connected, not by any client-visible
|
|
76
|
+
process identity (the client has no API for that, by design — it shouldn't need
|
|
77
|
+
to know or care).
|
|
78
|
+
"""
|
|
79
|
+
with Client.from_launch(_WORKER_ARGV, idle_timeout=10.0, state_dir=state_dir) as client_a:
|
|
80
|
+
assert client_a.catalogs()
|
|
81
|
+
with Client.from_launch(_WORKER_ARGV, idle_timeout=10.0, state_dir=state_dir) as client_b:
|
|
82
|
+
assert client_b.catalogs()
|
|
83
|
+
rows = status_rows(Path(state_dir))
|
|
84
|
+
assert len(rows) == 1, f"expected exactly one shared worker, found {len(rows)}: {rows}"
|
|
85
|
+
assert rows[0].alive
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
class TestLaunchConstructorValidation:
|
|
89
|
+
"""``transport='launch'`` argument validation."""
|
|
90
|
+
|
|
91
|
+
def test_requires_launch_argv(self) -> None:
|
|
92
|
+
"""Launch transport without launch_argv is rejected."""
|
|
93
|
+
with pytest.raises(ValueError, match="requires a non-empty launch_argv"):
|
|
94
|
+
Client(transport="launch", pool=None)
|
|
95
|
+
|
|
96
|
+
def test_rejects_empty_launch_argv(self) -> None:
|
|
97
|
+
"""An explicitly empty launch_argv is rejected the same as omitting it."""
|
|
98
|
+
with pytest.raises(ValueError, match="requires a non-empty launch_argv"):
|
|
99
|
+
Client(transport="launch", launch_argv=(), pool=None)
|
|
100
|
+
|
|
101
|
+
def test_rejects_server_path(self) -> None:
|
|
102
|
+
"""server_path is subprocess-only."""
|
|
103
|
+
with pytest.raises(ValueError, match="server_path is only meaningful"):
|
|
104
|
+
Client("some-worker", transport="launch", launch_argv=("x",), pool=None)
|
|
105
|
+
|
|
106
|
+
def test_rejects_base_url(self) -> None:
|
|
107
|
+
"""base_url is http-only."""
|
|
108
|
+
with pytest.raises(ValueError, match="base_url is only meaningful"):
|
|
109
|
+
Client(transport="launch", launch_argv=("x",), base_url="http://x", pool=None)
|
|
110
|
+
|
|
111
|
+
def test_rejects_tcp_host_and_port(self) -> None:
|
|
112
|
+
"""tcp_host/tcp_port are tcp-only."""
|
|
113
|
+
with pytest.raises(ValueError, match="tcp_host/tcp_port are only meaningful"):
|
|
114
|
+
Client(transport="launch", launch_argv=("x",), tcp_host="127.0.0.1", tcp_port=1, pool=None)
|
|
@@ -714,6 +714,15 @@ wheels = [
|
|
|
714
714
|
{ url = "https://files.pythonhosted.org/packages/da/ef/5790e74a7b39d2c085554f347be22a1882649a29a7a65e9c81bfaf9e8fc6/falcon-4.3.1-py3-none-any.whl", hash = "sha256:5402602d14bc426afc01c388538f2ad402ac4c8c2477415dfe972a2deee17248", size = 332719, upload-time = "2026-06-16T05:31:23.373Z" },
|
|
715
715
|
]
|
|
716
716
|
|
|
717
|
+
[[package]]
|
|
718
|
+
name = "filelock"
|
|
719
|
+
version = "3.32.4"
|
|
720
|
+
source = { registry = "https://pypi.org/simple" }
|
|
721
|
+
sdist = { url = "https://files.pythonhosted.org/packages/6d/30/03b03951873a1a0ffc7e8ca0e10c15597b59e8d0e39260704cd2ea087bc4/filelock-3.32.4.tar.gz", hash = "sha256:2bde2e4cf732e0153406d8a7bc80620ecf5e621fe0d25e41143c4e3b4733ff30", size = 222126, upload-time = "2026-08-23T17:37:55.363Z" }
|
|
722
|
+
wheels = [
|
|
723
|
+
{ url = "https://files.pythonhosted.org/packages/01/a4/9b63d595d748e3aff8812b65eacc1a2c4bd90b7c2012e08e72373b4835eb/filelock-3.32.4-py3-none-any.whl", hash = "sha256:22e58ca3b1ae3b98993b762d7338367ae64fe50252bf78d59da3bfebcdf1cedd", size = 99864, upload-time = "2026-08-23T17:37:53.913Z" },
|
|
724
|
+
]
|
|
725
|
+
|
|
717
726
|
[[package]]
|
|
718
727
|
name = "frozenlist"
|
|
719
728
|
version = "1.8.0"
|
|
@@ -2560,7 +2569,7 @@ requires-dist = [
|
|
|
2560
2569
|
|
|
2561
2570
|
[[package]]
|
|
2562
2571
|
name = "vgi-python"
|
|
2563
|
-
version = "0.29.
|
|
2572
|
+
version = "0.29.4"
|
|
2564
2573
|
source = { editable = "." }
|
|
2565
2574
|
dependencies = [
|
|
2566
2575
|
{ name = "click" },
|
|
@@ -2591,7 +2600,7 @@ dev = [
|
|
|
2591
2600
|
{ name = "pytest-xdist" },
|
|
2592
2601
|
{ name = "ruff" },
|
|
2593
2602
|
{ name = "sqlglot" },
|
|
2594
|
-
{ name = "vgi-rpc", extra = ["conformance", "external", "http", "oauth", "otel", "sentry"] },
|
|
2603
|
+
{ name = "vgi-rpc", extra = ["cli", "conformance", "external", "http", "oauth", "otel", "sentry"] },
|
|
2595
2604
|
]
|
|
2596
2605
|
duckdb = [
|
|
2597
2606
|
{ name = "duckdb" },
|
|
@@ -2609,6 +2618,9 @@ haybarn = [
|
|
|
2609
2618
|
http = [
|
|
2610
2619
|
{ name = "vgi-rpc", extra = ["http"] },
|
|
2611
2620
|
]
|
|
2621
|
+
launch = [
|
|
2622
|
+
{ name = "vgi-rpc", extra = ["cli"] },
|
|
2623
|
+
]
|
|
2612
2624
|
oauth = [
|
|
2613
2625
|
{ name = "vgi-rpc", extra = ["oauth"] },
|
|
2614
2626
|
]
|
|
@@ -2672,17 +2684,18 @@ requires-dist = [
|
|
|
2672
2684
|
{ name = "typer", specifier = ">=0.9" },
|
|
2673
2685
|
{ name = "vgi-fixtures", marker = "extra == 'fixtures'", editable = "packages/vgi-fixtures" },
|
|
2674
2686
|
{ name = "vgi-python", extras = ["test-fixtures"], marker = "extra == 'test-fixtures-writable'" },
|
|
2675
|
-
{ name = "vgi-python", extras = ["test-fixtures", "test-fixtures-writable", "http", "oauth", "otel", "sentry", "azure"], marker = "extra == 'dev'" },
|
|
2687
|
+
{ name = "vgi-python", extras = ["test-fixtures", "test-fixtures-writable", "http", "launch", "oauth", "otel", "sentry", "azure"], marker = "extra == 'dev'" },
|
|
2676
2688
|
{ name = "vgi-python", extras = ["transactor"], marker = "extra == 'test-fixtures-writable'" },
|
|
2677
|
-
{ name = "vgi-rpc", specifier = ">=0.43.
|
|
2678
|
-
{ name = "vgi-rpc", extras = ["
|
|
2689
|
+
{ name = "vgi-rpc", specifier = ">=0.43.2" },
|
|
2690
|
+
{ name = "vgi-rpc", extras = ["cli"], marker = "extra == 'launch'" },
|
|
2691
|
+
{ name = "vgi-rpc", extras = ["cli", "conformance", "external", "http", "oauth", "otel", "sentry"], marker = "extra == 'dev'" },
|
|
2679
2692
|
{ name = "vgi-rpc", extras = ["http"], marker = "extra == 'granian'" },
|
|
2680
2693
|
{ name = "vgi-rpc", extras = ["http"], marker = "extra == 'http'" },
|
|
2681
2694
|
{ name = "vgi-rpc", extras = ["oauth"], marker = "extra == 'oauth'" },
|
|
2682
2695
|
{ name = "vgi-rpc", extras = ["otel"], marker = "extra == 'otel'" },
|
|
2683
2696
|
{ name = "vgi-rpc", extras = ["sentry"], marker = "extra == 'sentry'" },
|
|
2684
2697
|
]
|
|
2685
|
-
provides-extras = ["haybarn", "duckdb", "http", "granian", "oauth", "otel", "sentry", "azure", "test-fixtures", "transactor", "fixtures", "test-fixtures-writable", "dev"]
|
|
2698
|
+
provides-extras = ["haybarn", "duckdb", "http", "launch", "granian", "oauth", "otel", "sentry", "azure", "test-fixtures", "transactor", "fixtures", "test-fixtures-writable", "dev"]
|
|
2686
2699
|
|
|
2687
2700
|
[package.metadata.requires-dev]
|
|
2688
2701
|
dev = [
|
|
@@ -2703,7 +2716,7 @@ docs = [
|
|
|
2703
2716
|
|
|
2704
2717
|
[[package]]
|
|
2705
2718
|
name = "vgi-rpc"
|
|
2706
|
-
version = "0.43.
|
|
2719
|
+
version = "0.43.2"
|
|
2707
2720
|
source = { registry = "https://pypi.org/simple" }
|
|
2708
2721
|
dependencies = [
|
|
2709
2722
|
{ name = "docstring-parser" },
|
|
@@ -2711,12 +2724,17 @@ dependencies = [
|
|
|
2711
2724
|
{ name = "pywin32", marker = "sys_platform == 'win32'" },
|
|
2712
2725
|
{ name = "tzdata", marker = "sys_platform == 'win32'" },
|
|
2713
2726
|
]
|
|
2714
|
-
sdist = { url = "https://files.pythonhosted.org/packages/
|
|
2727
|
+
sdist = { url = "https://files.pythonhosted.org/packages/ce/04/efb99f0fb56535bcba110e6c12448c31b429e0861aae4bc2f7136299cfc2/vgi_rpc-0.43.2.tar.gz", hash = "sha256:6a06437af17442451bfe07186bc472a2efb57e030b0e5b38a28922034a814123", size = 1147340, upload-time = "2026-08-27T18:33:54.608Z" }
|
|
2715
2728
|
wheels = [
|
|
2716
|
-
{ url = "https://files.pythonhosted.org/packages/
|
|
2729
|
+
{ url = "https://files.pythonhosted.org/packages/ac/b9/33cdb4fe27ef3893e1cded63f396af8bc517e390615f34db6f4bd227ef4c/vgi_rpc-0.43.2-py3-none-any.whl", hash = "sha256:b112ab76828367176a41f1b9a4ceeaba8979629e4e5972f64bf769c94b3e36a4", size = 528134, upload-time = "2026-08-27T18:33:52.829Z" },
|
|
2717
2730
|
]
|
|
2718
2731
|
|
|
2719
2732
|
[package.optional-dependencies]
|
|
2733
|
+
cli = [
|
|
2734
|
+
{ name = "filelock" },
|
|
2735
|
+
{ name = "httpx2" },
|
|
2736
|
+
{ name = "typer" },
|
|
2737
|
+
]
|
|
2720
2738
|
conformance = [
|
|
2721
2739
|
{ name = "jsonschema" },
|
|
2722
2740
|
{ name = "psutil" },
|
|
@@ -100,9 +100,11 @@ class CatalogClientMixin:
|
|
|
100
100
|
non-DuckDB use case this mixin supports.
|
|
101
101
|
|
|
102
102
|
Other attributes expected from ``Client``: ``_transport`` (subprocess,
|
|
103
|
-
http, or
|
|
104
|
-
(TCP endpoint),
|
|
105
|
-
|
|
103
|
+
http, tcp, or launch), ``_base_url`` (HTTP base URL), ``_tcp_host`` /
|
|
104
|
+
``_tcp_port`` (TCP endpoint), ``_launch_argv`` / ``_launch_idle_timeout`` /
|
|
105
|
+
``_launch_state_dir`` / ``_launch_socket_path`` (launcher worker
|
|
106
|
+
identity + lifecycle), and ``_get_or_create_httpx_client()`` (shared
|
|
107
|
+
HTTP client factory).
|
|
106
108
|
|
|
107
109
|
Attributes:
|
|
108
110
|
server_path: Worker command used for subprocess transport — a string to
|
|
@@ -111,10 +113,14 @@ class CatalogClientMixin:
|
|
|
111
113
|
|
|
112
114
|
# Type hints for attributes expected from Client
|
|
113
115
|
server_path: str | Sequence[str]
|
|
114
|
-
_transport: Literal["subprocess", "http", "tcp"]
|
|
116
|
+
_transport: Literal["subprocess", "http", "tcp", "launch"]
|
|
115
117
|
_base_url: str | None
|
|
116
118
|
_tcp_host: str | None
|
|
117
119
|
_tcp_port: int | None
|
|
120
|
+
_launch_argv: tuple[str, ...] | None
|
|
121
|
+
_launch_idle_timeout: float
|
|
122
|
+
_launch_state_dir: str | None
|
|
123
|
+
_launch_socket_path: str | None
|
|
118
124
|
_external_location: Any | None
|
|
119
125
|
|
|
120
126
|
def _worker_argv(self) -> list[str]:
|
|
@@ -144,6 +150,11 @@ class CatalogClientMixin:
|
|
|
144
150
|
``Client._get_or_create_httpx_client`` so auth headers and
|
|
145
151
|
connection pooling are consistent.
|
|
146
152
|
|
|
153
|
+
Launch: opens a short-lived ``resolve_and_connect`` session per call
|
|
154
|
+
against the launcher-managed shared worker — same warm-worker sharing
|
|
155
|
+
as exchange-mode calls (``Client._spawn_launch_connection``), just a
|
|
156
|
+
fresh connection to it per catalog RPC rather than one held open.
|
|
157
|
+
|
|
147
158
|
Worker errors are caught and re-raised as ``CatalogClientError``.
|
|
148
159
|
|
|
149
160
|
Yields:
|
|
@@ -173,6 +184,22 @@ class CatalogClientMixin:
|
|
|
173
184
|
external_location=getattr(self, "_external_location", None),
|
|
174
185
|
) as proxy:
|
|
175
186
|
yield proxy
|
|
187
|
+
elif transport == "launch":
|
|
188
|
+
from vgi_rpc.launcher import LaunchConfig, resolve_and_connect
|
|
189
|
+
|
|
190
|
+
assert self._launch_argv is not None
|
|
191
|
+
config = LaunchConfig(
|
|
192
|
+
worker_argv=self._launch_argv,
|
|
193
|
+
socket_path=self._launch_socket_path,
|
|
194
|
+
idle_timeout=self._launch_idle_timeout,
|
|
195
|
+
state_dir=self._launch_state_dir,
|
|
196
|
+
)
|
|
197
|
+
with resolve_and_connect(
|
|
198
|
+
VgiProtocol, # type: ignore[type-abstract]
|
|
199
|
+
config,
|
|
200
|
+
external_location=getattr(self, "_external_location", None),
|
|
201
|
+
) as proxy:
|
|
202
|
+
yield proxy
|
|
176
203
|
else:
|
|
177
204
|
cmd = self._worker_argv()
|
|
178
205
|
with _catalog_pool.connect(VgiProtocol, cmd) as proxy: # type: ignore[type-abstract]
|
|
@@ -184,10 +184,10 @@ _HTTP_TRANSPORT_READY = True
|
|
|
184
184
|
|
|
185
185
|
@dataclass
|
|
186
186
|
class WorkerConnection:
|
|
187
|
-
"""Holds state for a single worker connection (subprocess, HTTP, or
|
|
187
|
+
"""Holds state for a single worker connection (subprocess, HTTP, TCP, or launch).
|
|
188
188
|
|
|
189
|
-
Exactly one of {proc+connection, _pool_ctx, _http_ctx, _tcp_ctx}
|
|
190
|
-
per connection — transport-specific teardown inspects these fields.
|
|
189
|
+
Exactly one of {proc+connection, _pool_ctx, _http_ctx, _tcp_ctx, _launch_ctx}
|
|
190
|
+
is active per connection — transport-specific teardown inspects these fields.
|
|
191
191
|
|
|
192
192
|
Attributes:
|
|
193
193
|
proxy: The typed `[`VgiProtocol`][]` proxy used to invoke the worker.
|
|
@@ -209,6 +209,8 @@ class WorkerConnection:
|
|
|
209
209
|
_http_ctx: AbstractContextManager[Any] | None = field(default=None, repr=False)
|
|
210
210
|
# TCP transport: context manager from vgi_rpc.rpc.tcp_connect.
|
|
211
211
|
_tcp_ctx: AbstractContextManager[Any] | None = field(default=None, repr=False)
|
|
212
|
+
# Launch transport: context manager from vgi_rpc.launcher.resolve_and_connect.
|
|
213
|
+
_launch_ctx: AbstractContextManager[Any] | None = field(default=None, repr=False)
|
|
212
214
|
|
|
213
215
|
|
|
214
216
|
class Client(CatalogClientMixin, AggregateClientMixin):
|
|
@@ -389,13 +391,17 @@ class Client(CatalogClientMixin, AggregateClientMixin):
|
|
|
389
391
|
attach_opaque_data: bytes | None = None,
|
|
390
392
|
pool: WorkerPool | None = _default_pool,
|
|
391
393
|
*,
|
|
392
|
-
transport: Literal["subprocess", "http", "tcp"] = "subprocess",
|
|
394
|
+
transport: Literal["subprocess", "http", "tcp", "launch"] = "subprocess",
|
|
393
395
|
base_url: str | None = None,
|
|
394
396
|
tcp_host: str | None = None,
|
|
395
397
|
tcp_port: int | None = None,
|
|
396
398
|
bearer_token: str | None = None,
|
|
397
399
|
httpx_client: Any | None = None,
|
|
398
400
|
external_location: Any | None = None,
|
|
401
|
+
launch_argv: Sequence[str] | None = None,
|
|
402
|
+
launch_idle_timeout: float = 300.0,
|
|
403
|
+
launch_state_dir: str | None = None,
|
|
404
|
+
launch_socket_path: str | None = None,
|
|
399
405
|
):
|
|
400
406
|
"""Initialize the VGI client.
|
|
401
407
|
|
|
@@ -430,7 +436,10 @@ class Client(CatalogClientMixin, AggregateClientMixin):
|
|
|
430
436
|
a running worker via ``vgi_rpc.http.http_connect``; ``"tcp"``
|
|
431
437
|
connects to a running worker via ``vgi_rpc.rpc.tcp_connect``
|
|
432
438
|
(raw Arrow-IPC framing, no auth/encryption — loopback /
|
|
433
|
-
trusted networks only; use ``Client.from_tcp(...)``)
|
|
439
|
+
trusted networks only; use ``Client.from_tcp(...)``); ``"launch"``
|
|
440
|
+
spawns-or-reuses a warm worker shared across every client
|
|
441
|
+
pointing at the same command, coordinated via
|
|
442
|
+
``vgi_rpc.launcher`` (use ``Client.from_launch(...)``).
|
|
434
443
|
base_url: HTTP-only. Base URL of the running worker, e.g.
|
|
435
444
|
``"http://127.0.0.1:8765"``.
|
|
436
445
|
tcp_host: TCP-only. Hostname or IP of the running worker.
|
|
@@ -449,6 +458,20 @@ class Client(CatalogClientMixin, AggregateClientMixin):
|
|
|
449
458
|
transport so pointer batches are resolved automatically.
|
|
450
459
|
Subprocess transport ignores this — subprocess workers
|
|
451
460
|
don't return pointer batches.
|
|
461
|
+
launch_argv: Launch-only. The worker command and arguments (an
|
|
462
|
+
argv sequence, not a shell string — matches
|
|
463
|
+
``vgi_rpc.launcher.LaunchConfig.worker_argv``). Requires the
|
|
464
|
+
``vgi-python[launch]`` extra (pulls in ``vgi-rpc[cli]`` for
|
|
465
|
+
``filelock``, which ``vgi_rpc.launcher`` imports unconditionally).
|
|
466
|
+
launch_idle_timeout: Launch-only. The shared worker self-terminates
|
|
467
|
+
after this many idle seconds with zero connected clients.
|
|
468
|
+
Forwarded to ``LaunchConfig.idle_timeout``.
|
|
469
|
+
launch_state_dir: Launch-only. Override the launcher's default
|
|
470
|
+
per-user state directory (lockfiles + sockets). Forwarded to
|
|
471
|
+
``LaunchConfig.state_dir``.
|
|
472
|
+
launch_socket_path: Launch-only. Explicit socket path, skipping
|
|
473
|
+
the hash-derived default. Forwarded to
|
|
474
|
+
``LaunchConfig.socket_path``.
|
|
452
475
|
|
|
453
476
|
Raises:
|
|
454
477
|
ValueError: If the transport / server_path / base_url
|
|
@@ -472,6 +495,15 @@ class Client(CatalogClientMixin, AggregateClientMixin):
|
|
|
472
495
|
raise ValueError("server_path is only meaningful for transport='subprocess'")
|
|
473
496
|
if base_url is not None:
|
|
474
497
|
raise ValueError("base_url is only meaningful for transport='http'")
|
|
498
|
+
elif transport == "launch":
|
|
499
|
+
if not launch_argv:
|
|
500
|
+
raise ValueError("transport='launch' requires a non-empty launch_argv")
|
|
501
|
+
if server_path is not None:
|
|
502
|
+
raise ValueError("server_path is only meaningful for transport='subprocess'")
|
|
503
|
+
if base_url is not None:
|
|
504
|
+
raise ValueError("base_url is only meaningful for transport='http'")
|
|
505
|
+
if tcp_host is not None or tcp_port is not None:
|
|
506
|
+
raise ValueError("tcp_host/tcp_port are only meaningful for transport='tcp'")
|
|
475
507
|
else:
|
|
476
508
|
raise ValueError(f"unknown transport {transport!r}")
|
|
477
509
|
|
|
@@ -482,13 +514,19 @@ class Client(CatalogClientMixin, AggregateClientMixin):
|
|
|
482
514
|
self._tcp_port = tcp_port
|
|
483
515
|
self._bearer_token = bearer_token
|
|
484
516
|
self._httpx_client = httpx_client
|
|
517
|
+
self._launch_argv = tuple(launch_argv) if launch_argv is not None else None
|
|
518
|
+
self._launch_idle_timeout = launch_idle_timeout
|
|
519
|
+
self._launch_state_dir = launch_state_dir
|
|
520
|
+
self._launch_socket_path = launch_socket_path
|
|
485
521
|
# True when ``_get_or_create_httpx_client`` constructed the client and
|
|
486
522
|
# is therefore responsible for closing it on ``stop()``. False when
|
|
487
523
|
# the caller passed ``httpx_client=`` — ownership stays with them.
|
|
488
524
|
self._httpx_client_owned = False
|
|
489
|
-
# Auto-enable pointer-batch resolution for HTTP unless the
|
|
490
|
-
# asked for something different
|
|
491
|
-
|
|
525
|
+
# Auto-enable pointer-batch resolution for HTTP/TCP/launch unless the
|
|
526
|
+
# caller asked for something different — all three are ordinary RPC
|
|
527
|
+
# transports a worker can externalize batches over, unlike subprocess
|
|
528
|
+
# (which never returns pointer batches). See ``external_location`` docs above.
|
|
529
|
+
if transport in ("http", "tcp", "launch") and external_location is None:
|
|
492
530
|
from vgi_rpc.external import ExternalLocationConfig
|
|
493
531
|
|
|
494
532
|
external_location = ExternalLocationConfig()
|
|
@@ -565,6 +603,63 @@ class Client(CatalogClientMixin, AggregateClientMixin):
|
|
|
565
603
|
pool=None,
|
|
566
604
|
)
|
|
567
605
|
|
|
606
|
+
@classmethod
|
|
607
|
+
def from_launch(
|
|
608
|
+
cls,
|
|
609
|
+
worker_argv: Sequence[str],
|
|
610
|
+
*,
|
|
611
|
+
idle_timeout: float = 300.0,
|
|
612
|
+
state_dir: str | None = None,
|
|
613
|
+
socket_path: str | None = None,
|
|
614
|
+
external_location: Any | None = None,
|
|
615
|
+
worker_limit: int | None = None,
|
|
616
|
+
attach_opaque_data: bytes | None = None,
|
|
617
|
+
) -> Client:
|
|
618
|
+
"""Create a `[`Client`][]` bound to a launcher-managed warm worker.
|
|
619
|
+
|
|
620
|
+
Spawns (or reuses) a worker process serving over an ``AF_UNIX``
|
|
621
|
+
socket via ``vgi_rpc.launcher`` — every client across the machine
|
|
622
|
+
pointing at the same ``worker_argv`` shares one warm worker,
|
|
623
|
+
coordinated by a per-command-hash flock, and the worker
|
|
624
|
+
self-terminates after ``idle_timeout`` idle seconds with zero
|
|
625
|
+
connected clients. This is the Python client-side counterpart to the
|
|
626
|
+
VGI DuckDB extension's ``launch:<argv>`` LOCATION scheme. Requires
|
|
627
|
+
the ``vgi-python[launch]`` extra.
|
|
628
|
+
|
|
629
|
+
Args:
|
|
630
|
+
worker_argv: The worker command and arguments, as an argv
|
|
631
|
+
sequence — not a shell string, and not split with
|
|
632
|
+
``shlex.split`` the way ``server_path`` is for
|
|
633
|
+
``transport="subprocess"``.
|
|
634
|
+
idle_timeout: Shared worker self-shutdown after this many idle
|
|
635
|
+
seconds.
|
|
636
|
+
state_dir: Override the launcher's default per-user state
|
|
637
|
+
directory (lockfiles + sockets).
|
|
638
|
+
socket_path: Explicit socket path, skipping the hash-derived
|
|
639
|
+
default — every caller passing the same explicit path
|
|
640
|
+
shares that worker regardless of ``worker_argv`` differences.
|
|
641
|
+
external_location: Optional ``ExternalLocationConfig`` — see the
|
|
642
|
+
constructor's docstring.
|
|
643
|
+
worker_limit: Maximum number of parallel worker connections.
|
|
644
|
+
attach_opaque_data: Optional unique identifier for the DuckDB
|
|
645
|
+
database attachment.
|
|
646
|
+
|
|
647
|
+
Returns:
|
|
648
|
+
A `[`Client`][]` bound to the launcher-managed worker.
|
|
649
|
+
|
|
650
|
+
"""
|
|
651
|
+
return cls(
|
|
652
|
+
transport="launch",
|
|
653
|
+
launch_argv=worker_argv,
|
|
654
|
+
launch_idle_timeout=idle_timeout,
|
|
655
|
+
launch_state_dir=state_dir,
|
|
656
|
+
launch_socket_path=socket_path,
|
|
657
|
+
external_location=external_location,
|
|
658
|
+
worker_limit=worker_limit,
|
|
659
|
+
attach_opaque_data=attach_opaque_data,
|
|
660
|
+
pool=None,
|
|
661
|
+
)
|
|
662
|
+
|
|
568
663
|
def _drain_stderr(self, stderr: IO[bytes]) -> None:
|
|
569
664
|
"""Background thread that continuously reads stderr.
|
|
570
665
|
|
|
@@ -660,6 +755,8 @@ class Client(CatalogClientMixin, AggregateClientMixin):
|
|
|
660
755
|
return self._spawn_http_connection(worker_index)
|
|
661
756
|
if self._transport == "tcp":
|
|
662
757
|
return self._spawn_tcp_connection(worker_index)
|
|
758
|
+
if self._transport == "launch":
|
|
759
|
+
return self._spawn_launch_connection(worker_index)
|
|
663
760
|
return self._spawn_subprocess_connection(worker_index)
|
|
664
761
|
|
|
665
762
|
def _spawn_tcp_connection(self, worker_index: int) -> WorkerConnection:
|
|
@@ -692,6 +789,41 @@ class Client(CatalogClientMixin, AggregateClientMixin):
|
|
|
692
789
|
_tcp_ctx=ctx,
|
|
693
790
|
)
|
|
694
791
|
|
|
792
|
+
def _spawn_launch_connection(self, worker_index: int) -> WorkerConnection:
|
|
793
|
+
"""Connect to a launcher-managed worker via ``vgi_rpc.launcher.resolve_and_connect``.
|
|
794
|
+
|
|
795
|
+
Every ``Client`` (in this process or any other on the machine) built
|
|
796
|
+
with the same ``launch_argv`` shares one warm worker — see
|
|
797
|
+
``from_launch``. Multiple ``worker_index`` values open independent
|
|
798
|
+
connections to that same shared worker.
|
|
799
|
+
"""
|
|
800
|
+
from vgi_rpc.launcher import LaunchConfig, resolve_and_connect
|
|
801
|
+
|
|
802
|
+
assert self._launch_argv is not None # enforced in __init__
|
|
803
|
+
config = LaunchConfig(
|
|
804
|
+
worker_argv=self._launch_argv,
|
|
805
|
+
socket_path=self._launch_socket_path,
|
|
806
|
+
idle_timeout=self._launch_idle_timeout,
|
|
807
|
+
state_dir=self._launch_state_dir,
|
|
808
|
+
)
|
|
809
|
+
ctx: AbstractContextManager[VgiProtocol] = resolve_and_connect(
|
|
810
|
+
VgiProtocol, # type: ignore[type-abstract]
|
|
811
|
+
config,
|
|
812
|
+
on_log=self._on_worker_log,
|
|
813
|
+
external_location=self._external_location,
|
|
814
|
+
)
|
|
815
|
+
proxy = ctx.__enter__()
|
|
816
|
+
_logger.debug(
|
|
817
|
+
"launch_connection_opened worker_index=%s argv=%s",
|
|
818
|
+
worker_index,
|
|
819
|
+
self._launch_argv,
|
|
820
|
+
)
|
|
821
|
+
return WorkerConnection(
|
|
822
|
+
proxy=proxy,
|
|
823
|
+
worker_index=worker_index,
|
|
824
|
+
_launch_ctx=ctx,
|
|
825
|
+
)
|
|
826
|
+
|
|
695
827
|
def _spawn_http_connection(self, worker_index: int) -> WorkerConnection:
|
|
696
828
|
"""Connect to a remote HTTP worker via ``vgi_rpc.http.http_connect``.
|
|
697
829
|
|
|
@@ -863,6 +995,14 @@ class Client(CatalogClientMixin, AggregateClientMixin):
|
|
|
863
995
|
_logger.debug("tcp_connection_closed worker_index=%s", worker.worker_index)
|
|
864
996
|
return 0
|
|
865
997
|
|
|
998
|
+
if worker._launch_ctx is not None:
|
|
999
|
+
# Launch transport — close the RPC proxy (and its socket). The
|
|
1000
|
+
# shared worker process itself is untouched: it lives on for other
|
|
1001
|
+
# clients and self-terminates via its own idle timer.
|
|
1002
|
+
worker._launch_ctx.__exit__(None, None, None)
|
|
1003
|
+
_logger.debug("launch_connection_closed worker_index=%s", worker.worker_index)
|
|
1004
|
+
return 0
|
|
1005
|
+
|
|
866
1006
|
if worker._pool_ctx is not None:
|
|
867
1007
|
# Return to pool — pool handles subprocess lifecycle
|
|
868
1008
|
worker._pool_ctx.__exit__(None, None, None)
|
|
@@ -979,6 +1119,8 @@ class Client(CatalogClientMixin, AggregateClientMixin):
|
|
|
979
1119
|
id_repr = f"http({self._base_url})"
|
|
980
1120
|
elif self._primary._tcp_ctx is not None:
|
|
981
1121
|
id_repr = f"tcp({self._tcp_host}:{self._tcp_port})"
|
|
1122
|
+
elif self._primary._launch_ctx is not None:
|
|
1123
|
+
id_repr = f"launch({' '.join(self._launch_argv or ())})"
|
|
982
1124
|
else:
|
|
983
1125
|
id_repr = "pooled"
|
|
984
1126
|
_logger.debug("server_started id=%s", id_repr)
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|