vgi-python 0.14.0__tar.gz → 0.16.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {vgi_python-0.14.0 → vgi_python-0.16.0}/PKG-INFO +1 -1
- {vgi_python-0.14.0 → vgi_python-0.16.0}/ci/run-integration.sh +34 -3
- {vgi_python-0.14.0 → vgi_python-0.16.0}/pyproject.toml +1 -1
- {vgi_python-0.14.0 → vgi_python-0.16.0}/tests/catalog/test_declarative.py +187 -6
- vgi_python-0.16.0/tests/catalog/test_required_filters.py +92 -0
- {vgi_python-0.14.0 → vgi_python-0.16.0}/tests/catalog/test_serialization.py +4 -4
- {vgi_python-0.14.0 → vgi_python-0.16.0}/tests/landing/describe.expected.json +103 -8
- vgi_python-0.16.0/tests/table_in_out/generator/test_substream_partial_sum_function.py +70 -0
- {vgi_python-0.14.0 → vgi_python-0.16.0}/tests/table_in_out/generator/test_sum_all_columns_function.py +5 -5
- vgi_python-0.16.0/tests/table_in_out/test_blended_metadata.py +150 -0
- {vgi_python-0.14.0 → vgi_python-0.16.0}/uv.lock +1 -1
- {vgi_python-0.14.0 → vgi_python-0.16.0}/vgi/_test_fixtures/table/required_filters.py +7 -7
- {vgi_python-0.14.0 → vgi_python-0.16.0}/vgi/_test_fixtures/table_in_out.py +747 -61
- {vgi_python-0.14.0 → vgi_python-0.16.0}/vgi/_test_fixtures/worker.py +68 -32
- {vgi_python-0.14.0 → vgi_python-0.16.0}/vgi/catalog/catalog_interface.py +76 -15
- {vgi_python-0.14.0 → vgi_python-0.16.0}/vgi/catalog/descriptors.py +49 -32
- {vgi_python-0.14.0 → vgi_python-0.16.0}/vgi/metadata.py +69 -1
- {vgi_python-0.14.0 → vgi_python-0.16.0}/vgi/protocol.py +83 -2
- {vgi_python-0.14.0 → vgi_python-0.16.0}/vgi/table_function.py +40 -3
- {vgi_python-0.14.0 → vgi_python-0.16.0}/vgi/table_in_out_function.py +49 -0
- {vgi_python-0.14.0 → vgi_python-0.16.0}/vgi/worker.py +69 -9
- vgi_python-0.14.0/tests/catalog/test_required_field_filter_paths.py +0 -98
- {vgi_python-0.14.0 → vgi_python-0.16.0}/.gitattributes +0 -0
- {vgi_python-0.14.0 → vgi_python-0.16.0}/.github/dependabot.yml +0 -0
- {vgi_python-0.14.0 → vgi_python-0.16.0}/.github/styles/config/vocabularies/VGI/accept.txt +0 -0
- {vgi_python-0.14.0 → vgi_python-0.16.0}/.github/workflows/ci.yml +0 -0
- {vgi_python-0.14.0 → vgi_python-0.16.0}/.github/workflows/docs.yml +0 -0
- {vgi_python-0.14.0 → vgi_python-0.16.0}/.github/workflows/integration.yml +0 -0
- {vgi_python-0.14.0 → vgi_python-0.16.0}/.github/workflows/release.yml +0 -0
- {vgi_python-0.14.0 → vgi_python-0.16.0}/.gitignore +0 -0
- {vgi_python-0.14.0 → vgi_python-0.16.0}/.python-version +0 -0
- {vgi_python-0.14.0 → vgi_python-0.16.0}/.vale.ini +0 -0
- {vgi_python-0.14.0 → vgi_python-0.16.0}/CLAUDE.md +0 -0
- {vgi_python-0.14.0 → vgi_python-0.16.0}/DOCS_ACCEPTANCE_CRITERIA.md +0 -0
- {vgi_python-0.14.0 → vgi_python-0.16.0}/DOCS_REVIEW_RUBRIC.md +0 -0
- {vgi_python-0.14.0 → vgi_python-0.16.0}/DOCS_USABILITY_TEST.md +0 -0
- {vgi_python-0.14.0 → vgi_python-0.16.0}/LICENSE +0 -0
- {vgi_python-0.14.0 → vgi_python-0.16.0}/README.md +0 -0
- {vgi_python-0.14.0 → vgi_python-0.16.0}/SECURITY.md +0 -0
- {vgi_python-0.14.0 → vgi_python-0.16.0}/ci/README.md +0 -0
- {vgi_python-0.14.0 → vgi_python-0.16.0}/ci/preprocess-require.awk +0 -0
- {vgi_python-0.14.0 → vgi_python-0.16.0}/dist-vgi/.gitignore +0 -0
- {vgi_python-0.14.0 → vgi_python-0.16.0}/docs/aggregate-functions.md +0 -0
- {vgi_python-0.14.0 → vgi_python-0.16.0}/docs/api/arguments.md +0 -0
- {vgi_python-0.14.0 → vgi_python-0.16.0}/docs/api/auth.md +0 -0
- {vgi_python-0.14.0 → vgi_python-0.16.0}/docs/api/catalogs.md +0 -0
- {vgi_python-0.14.0 → vgi_python-0.16.0}/docs/api/client.md +0 -0
- {vgi_python-0.14.0 → vgi_python-0.16.0}/docs/api/exceptions.md +0 -0
- {vgi_python-0.14.0 → vgi_python-0.16.0}/docs/api/filters.md +0 -0
- {vgi_python-0.14.0 → vgi_python-0.16.0}/docs/api/functions.md +0 -0
- {vgi_python-0.14.0 → vgi_python-0.16.0}/docs/api/http.md +0 -0
- {vgi_python-0.14.0 → vgi_python-0.16.0}/docs/api/index.md +0 -0
- {vgi_python-0.14.0 → vgi_python-0.16.0}/docs/api/metadata.md +0 -0
- {vgi_python-0.14.0 → vgi_python-0.16.0}/docs/api/observability.md +0 -0
- {vgi_python-0.14.0 → vgi_python-0.16.0}/docs/api/storage.md +0 -0
- {vgi_python-0.14.0 → vgi_python-0.16.0}/docs/api/transactor.md +0 -0
- {vgi_python-0.14.0 → vgi_python-0.16.0}/docs/api/worker.md +0 -0
- {vgi_python-0.14.0 → vgi_python-0.16.0}/docs/argument-serialization.md +0 -0
- {vgi_python-0.14.0 → vgi_python-0.16.0}/docs/assets/apple-touch-icon.png +0 -0
- {vgi_python-0.14.0 → vgi_python-0.16.0}/docs/assets/favicon-16x16.png +0 -0
- {vgi_python-0.14.0 → vgi_python-0.16.0}/docs/assets/favicon-32x32.png +0 -0
- {vgi_python-0.14.0 → vgi_python-0.16.0}/docs/assets/favicon.ico +0 -0
- {vgi_python-0.14.0 → vgi_python-0.16.0}/docs/assets/kinds/aggregate.svg +0 -0
- {vgi_python-0.14.0 → vgi_python-0.16.0}/docs/assets/kinds/buffering.svg +0 -0
- {vgi_python-0.14.0 → vgi_python-0.16.0}/docs/assets/kinds/scalar.svg +0 -0
- {vgi_python-0.14.0 → vgi_python-0.16.0}/docs/assets/kinds/table-in-out.svg +0 -0
- {vgi_python-0.14.0 → vgi_python-0.16.0}/docs/assets/kinds/table.svg +0 -0
- {vgi_python-0.14.0 → vgi_python-0.16.0}/docs/assets/logo.png +0 -0
- {vgi_python-0.14.0 → vgi_python-0.16.0}/docs/assets/social-card.png +0 -0
- {vgi_python-0.14.0 → vgi_python-0.16.0}/docs/authentication.md +0 -0
- {vgi_python-0.14.0 → vgi_python-0.16.0}/docs/catalog-interface.md +0 -0
- {vgi_python-0.14.0 → vgi_python-0.16.0}/docs/cli.md +0 -0
- {vgi_python-0.14.0 → vgi_python-0.16.0}/docs/column-statistics.md +0 -0
- {vgi_python-0.14.0 → vgi_python-0.16.0}/docs/concepts/index.md +0 -0
- {vgi_python-0.14.0 → vgi_python-0.16.0}/docs/contributing-docs.md +0 -0
- {vgi_python-0.14.0 → vgi_python-0.16.0}/docs/filter-pushdown.md +0 -0
- {vgi_python-0.14.0 → vgi_python-0.16.0}/docs/generator-api.md +0 -0
- {vgi_python-0.14.0 → vgi_python-0.16.0}/docs/how-to/catalogs.md +0 -0
- {vgi_python-0.14.0 → vgi_python-0.16.0}/docs/how-to/function-patterns.md +0 -0
- {vgi_python-0.14.0 → vgi_python-0.16.0}/docs/how-to/http-auth.md +0 -0
- {vgi_python-0.14.0 → vgi_python-0.16.0}/docs/how-to/index.md +0 -0
- {vgi_python-0.14.0 → vgi_python-0.16.0}/docs/how-to/pushdown-and-statistics.md +0 -0
- {vgi_python-0.14.0 → vgi_python-0.16.0}/docs/how-to/state-storage.md +0 -0
- {vgi_python-0.14.0 → vgi_python-0.16.0}/docs/index.md +0 -0
- {vgi_python-0.14.0 → vgi_python-0.16.0}/docs/lifecycle.md +0 -0
- {vgi_python-0.14.0 → vgi_python-0.16.0}/docs/metadata.md +0 -0
- {vgi_python-0.14.0 → vgi_python-0.16.0}/docs/overrides/main.html +0 -0
- {vgi_python-0.14.0 → vgi_python-0.16.0}/docs/robots.txt +0 -0
- {vgi_python-0.14.0 → vgi_python-0.16.0}/docs/shared-storage.md +0 -0
- {vgi_python-0.14.0 → vgi_python-0.16.0}/docs/stylesheets/extra.css +0 -0
- {vgi_python-0.14.0 → vgi_python-0.16.0}/docs/tutorial/index.md +0 -0
- {vgi_python-0.14.0 → vgi_python-0.16.0}/docs/tutorial/scalar.md +0 -0
- {vgi_python-0.14.0 → vgi_python-0.16.0}/docs/tutorial/table.md +0 -0
- {vgi_python-0.14.0 → vgi_python-0.16.0}/docs/vgi-logo.png +0 -0
- {vgi_python-0.14.0 → vgi_python-0.16.0}/examples/calc_scalar_worker.py +0 -0
- {vgi_python-0.14.0 → vgi_python-0.16.0}/examples/calc_worker.py +0 -0
- {vgi_python-0.14.0 → vgi_python-0.16.0}/examples/filter_worker.py +0 -0
- {vgi_python-0.14.0 → vgi_python-0.16.0}/examples/greeting_scalar_worker.py +0 -0
- {vgi_python-0.14.0 → vgi_python-0.16.0}/examples/row_count_worker.py +0 -0
- {vgi_python-0.14.0 → vgi_python-0.16.0}/examples/series_streaming_worker.py +0 -0
- {vgi_python-0.14.0 → vgi_python-0.16.0}/examples/sum_worker.py +0 -0
- {vgi_python-0.14.0 → vgi_python-0.16.0}/mkdocs.yml +0 -0
- {vgi_python-0.14.0 → vgi_python-0.16.0}/packages/vgi-fixtures/LICENSE +0 -0
- {vgi_python-0.14.0 → vgi_python-0.16.0}/packages/vgi-fixtures/README.md +0 -0
- {vgi_python-0.14.0 → vgi_python-0.16.0}/packages/vgi-fixtures/docker/Dockerfile +0 -0
- {vgi_python-0.14.0 → vgi_python-0.16.0}/packages/vgi-fixtures/docker/docker-entrypoint.sh +0 -0
- {vgi_python-0.14.0 → vgi_python-0.16.0}/packages/vgi-fixtures/pyproject.toml +0 -0
- {vgi_python-0.14.0 → vgi_python-0.16.0}/scripts/measure_startup.py +0 -0
- {vgi_python-0.14.0 → vgi_python-0.16.0}/scripts/run_all_tests.sh +0 -0
- {vgi_python-0.14.0 → vgi_python-0.16.0}/test-data/generate.sh +0 -0
- {vgi_python-0.14.0 → vgi_python-0.16.0}/tests/__init__.py +0 -0
- {vgi_python-0.14.0 → vgi_python-0.16.0}/tests/_http_fixtures.py +0 -0
- {vgi_python-0.14.0 → vgi_python-0.16.0}/tests/catalog/__init__.py +0 -0
- {vgi_python-0.14.0 → vgi_python-0.16.0}/tests/catalog/test_catalog_interface.py +0 -0
- {vgi_python-0.14.0 → vgi_python-0.16.0}/tests/catalog/test_client_catalog.py +0 -0
- {vgi_python-0.14.0 → vgi_python-0.16.0}/tests/catalog/test_column_statistics.py +0 -0
- {vgi_python-0.14.0 → vgi_python-0.16.0}/tests/catalog/test_example_worker_catalog.py +0 -0
- {vgi_python-0.14.0 → vgi_python-0.16.0}/tests/catalog/test_integration.py +0 -0
- {vgi_python-0.14.0 → vgi_python-0.16.0}/tests/catalog/test_scan_branches.py +0 -0
- {vgi_python-0.14.0 → vgi_python-0.16.0}/tests/catalog/test_setting.py +0 -0
- {vgi_python-0.14.0 → vgi_python-0.16.0}/tests/catalog/test_storage.py +0 -0
- {vgi_python-0.14.0 → vgi_python-0.16.0}/tests/catalog/test_time_travel.py +0 -0
- {vgi_python-0.14.0 → vgi_python-0.16.0}/tests/catalog/test_writable_table.py +0 -0
- {vgi_python-0.14.0 → vgi_python-0.16.0}/tests/client/__init__.py +0 -0
- {vgi_python-0.14.0 → vgi_python-0.16.0}/tests/client/test_broken_pipe.py +0 -0
- {vgi_python-0.14.0 → vgi_python-0.16.0}/tests/client/test_cli.py +0 -0
- {vgi_python-0.14.0 → vgi_python-0.16.0}/tests/client/test_cli_catalog_functions.py +0 -0
- {vgi_python-0.14.0 → vgi_python-0.16.0}/tests/client/test_worker_debug.py +0 -0
- {vgi_python-0.14.0 → vgi_python-0.16.0}/tests/conformance/__init__.py +0 -0
- {vgi_python-0.14.0 → vgi_python-0.16.0}/tests/conformance/_stub.py +0 -0
- {vgi_python-0.14.0 → vgi_python-0.16.0}/tests/conformance/conftest.py +0 -0
- {vgi_python-0.14.0 → vgi_python-0.16.0}/tests/conformance/test_accumulate.py +0 -0
- {vgi_python-0.14.0 → vgi_python-0.16.0}/tests/conformance/test_aggregate.py +0 -0
- {vgi_python-0.14.0 → vgi_python-0.16.0}/tests/conformance/test_attach.py +0 -0
- {vgi_python-0.14.0 → vgi_python-0.16.0}/tests/conformance/test_bearer_auth.py +0 -0
- {vgi_python-0.14.0 → vgi_python-0.16.0}/tests/conformance/test_const_param_enforcement.py +0 -0
- {vgi_python-0.14.0 → vgi_python-0.16.0}/tests/conformance/test_container.py +0 -0
- {vgi_python-0.14.0 → vgi_python-0.16.0}/tests/conformance/test_copy_from.py +0 -0
- {vgi_python-0.14.0 → vgi_python-0.16.0}/tests/conformance/test_copy_to.py +0 -0
- {vgi_python-0.14.0 → vgi_python-0.16.0}/tests/conformance/test_directory_parity.py +0 -0
- {vgi_python-0.14.0 → vgi_python-0.16.0}/tests/conformance/test_function_inventory.py +0 -0
- {vgi_python-0.14.0 → vgi_python-0.16.0}/tests/conformance/test_github.py +0 -0
- {vgi_python-0.14.0 → vgi_python-0.16.0}/tests/conformance/test_http_client.py +0 -0
- {vgi_python-0.14.0 → vgi_python-0.16.0}/tests/conformance/test_http_external_location.py +0 -0
- {vgi_python-0.14.0 → vgi_python-0.16.0}/tests/conformance/test_http_upload_url.py +0 -0
- {vgi_python-0.14.0 → vgi_python-0.16.0}/tests/conformance/test_macro.py +0 -0
- {vgi_python-0.14.0 → vgi_python-0.16.0}/tests/conformance/test_overload.py +0 -0
- {vgi_python-0.14.0 → vgi_python-0.16.0}/tests/conformance/test_protocol_inventory.py +0 -0
- {vgi_python-0.14.0 → vgi_python-0.16.0}/tests/conformance/test_protocol_version.py +0 -0
- {vgi_python-0.14.0 → vgi_python-0.16.0}/tests/conformance/test_resumable_scan.py +0 -0
- {vgi_python-0.14.0 → vgi_python-0.16.0}/tests/conformance/test_scalar.py +0 -0
- {vgi_python-0.14.0 → vgi_python-0.16.0}/tests/conformance/test_scalar_attach_opaque_data.py +0 -0
- {vgi_python-0.14.0 → vgi_python-0.16.0}/tests/conformance/test_secret.py +0 -0
- {vgi_python-0.14.0 → vgi_python-0.16.0}/tests/conformance/test_settings.py +0 -0
- {vgi_python-0.14.0 → vgi_python-0.16.0}/tests/conformance/test_table.py +0 -0
- {vgi_python-0.14.0 → vgi_python-0.16.0}/tests/conformance/test_table_in_out.py +0 -0
- {vgi_python-0.14.0 → vgi_python-0.16.0}/tests/conformance/test_view.py +0 -0
- {vgi_python-0.14.0 → vgi_python-0.16.0}/tests/conformance/test_writable.py +0 -0
- {vgi_python-0.14.0 → vgi_python-0.16.0}/tests/conftest.py +0 -0
- {vgi_python-0.14.0 → vgi_python-0.16.0}/tests/landing/_checker.py +0 -0
- {vgi_python-0.14.0 → vgi_python-0.16.0}/tests/landing/describe.schema.json +0 -0
- {vgi_python-0.14.0 → vgi_python-0.16.0}/tests/scalar/__init__.py +0 -0
- {vgi_python-0.14.0 → vgi_python-0.16.0}/tests/scalar/test_bernoulli_function.py +0 -0
- {vgi_python-0.14.0 → vgi_python-0.16.0}/tests/scalar/test_binary_packet_function.py +0 -0
- {vgi_python-0.14.0 → vgi_python-0.16.0}/tests/scalar/test_client.py +0 -0
- {vgi_python-0.14.0 → vgi_python-0.16.0}/tests/scalar/test_conditional_message_function.py +0 -0
- {vgi_python-0.14.0 → vgi_python-0.16.0}/tests/scalar/test_hash_seed_function.py +0 -0
- {vgi_python-0.14.0 → vgi_python-0.16.0}/tests/scalar/test_multiply_by_setting_function.py +0 -0
- {vgi_python-0.14.0 → vgi_python-0.16.0}/tests/scalar/test_multiply_function.py +0 -0
- {vgi_python-0.14.0 → vgi_python-0.16.0}/tests/scalar/test_random_bytes_function.py +0 -0
- {vgi_python-0.14.0 → vgi_python-0.16.0}/tests/scalar/test_return_secret_value_function.py +0 -0
- {vgi_python-0.14.0 → vgi_python-0.16.0}/tests/table/__init__.py +0 -0
- {vgi_python-0.14.0 → vgi_python-0.16.0}/tests/table/generator/__init__.py +0 -0
- {vgi_python-0.14.0 → vgi_python-0.16.0}/tests/table/generator/test_constant_columns_function.py +0 -0
- {vgi_python-0.14.0 → vgi_python-0.16.0}/tests/table/generator/test_double_sequence_function.py +0 -0
- {vgi_python-0.14.0 → vgi_python-0.16.0}/tests/table/generator/test_exception_function.py +0 -0
- {vgi_python-0.14.0 → vgi_python-0.16.0}/tests/table/generator/test_filter_echo_function.py +0 -0
- {vgi_python-0.14.0 → vgi_python-0.16.0}/tests/table/generator/test_logging_function.py +0 -0
- {vgi_python-0.14.0 → vgi_python-0.16.0}/tests/table/generator/test_nested_sequence_function.py +0 -0
- {vgi_python-0.14.0 → vgi_python-0.16.0}/tests/table/generator/test_partitioned_function.py +0 -0
- {vgi_python-0.14.0 → vgi_python-0.16.0}/tests/table/generator/test_projected_data_function.py +0 -0
- {vgi_python-0.14.0 → vgi_python-0.16.0}/tests/table/generator/test_sequence_function.py +0 -0
- {vgi_python-0.14.0 → vgi_python-0.16.0}/tests/table/generator/test_settings_function.py +0 -0
- {vgi_python-0.14.0 → vgi_python-0.16.0}/tests/table/generator/test_struct_settings_function.py +0 -0
- {vgi_python-0.14.0 → vgi_python-0.16.0}/tests/table/generator/test_ten_thousand_function.py +0 -0
- {vgi_python-0.14.0 → vgi_python-0.16.0}/tests/table_in_out/__init__.py +0 -0
- {vgi_python-0.14.0 → vgi_python-0.16.0}/tests/table_in_out/generator/__init__.py +0 -0
- {vgi_python-0.14.0 → vgi_python-0.16.0}/tests/table_in_out/generator/test_buffer_input_function.py +0 -0
- {vgi_python-0.14.0 → vgi_python-0.16.0}/tests/table_in_out/generator/test_echo_function.py +0 -0
- {vgi_python-0.14.0 → vgi_python-0.16.0}/tests/table_in_out/generator/test_exception_functions.py +0 -0
- {vgi_python-0.14.0 → vgi_python-0.16.0}/tests/table_in_out/generator/test_filter_by_setting_function.py +0 -0
- {vgi_python-0.14.0 → vgi_python-0.16.0}/tests/table_in_out/generator/test_repeat_inputs_function.py +0 -0
- {vgi_python-0.14.0 → vgi_python-0.16.0}/tests/table_in_out/test_client.py +0 -0
- {vgi_python-0.14.0 → vgi_python-0.16.0}/tests/test_access_log_audit.py +0 -0
- {vgi_python-0.14.0 → vgi_python-0.16.0}/tests/test_aggregate_function.py +0 -0
- {vgi_python-0.14.0 → vgi_python-0.16.0}/tests/test_argument_spec.py +0 -0
- {vgi_python-0.14.0 → vgi_python-0.16.0}/tests/test_auth.py +0 -0
- {vgi_python-0.14.0 → vgi_python-0.16.0}/tests/test_bind_exceptions.py +0 -0
- {vgi_python-0.14.0 → vgi_python-0.16.0}/tests/test_bind_request_at_clause.py +0 -0
- {vgi_python-0.14.0 → vgi_python-0.16.0}/tests/test_bound_storage_conformance.py +0 -0
- {vgi_python-0.14.0 → vgi_python-0.16.0}/tests/test_cache_control.py +0 -0
- {vgi_python-0.14.0 → vgi_python-0.16.0}/tests/test_catalog_auth_binding.py +0 -0
- {vgi_python-0.14.0 → vgi_python-0.16.0}/tests/test_copy_from_function.py +0 -0
- {vgi_python-0.14.0 → vgi_python-0.16.0}/tests/test_copy_to_function.py +0 -0
- {vgi_python-0.14.0 → vgi_python-0.16.0}/tests/test_docstrings.py +0 -0
- {vgi_python-0.14.0 → vgi_python-0.16.0}/tests/test_documentation_examples.py +0 -0
- {vgi_python-0.14.0 → vgi_python-0.16.0}/tests/test_example_function_arg_types.py +0 -0
- {vgi_python-0.14.0 → vgi_python-0.16.0}/tests/test_examples_workers.py +0 -0
- {vgi_python-0.14.0 → vgi_python-0.16.0}/tests/test_exception_handling.py +0 -0
- {vgi_python-0.14.0 → vgi_python-0.16.0}/tests/test_exceptions.py +0 -0
- {vgi_python-0.14.0 → vgi_python-0.16.0}/tests/test_filter_pushdown.py +0 -0
- {vgi_python-0.14.0 → vgi_python-0.16.0}/tests/test_filter_pushdown_extension.py +0 -0
- {vgi_python-0.14.0 → vgi_python-0.16.0}/tests/test_function_storage.py +0 -0
- {vgi_python-0.14.0 → vgi_python-0.16.0}/tests/test_function_storage_azure_sql.py +0 -0
- {vgi_python-0.14.0 → vgi_python-0.16.0}/tests/test_function_storage_cf_do.py +0 -0
- {vgi_python-0.14.0 → vgi_python-0.16.0}/tests/test_function_storage_cf_do_integration.py +0 -0
- {vgi_python-0.14.0 → vgi_python-0.16.0}/tests/test_function_storage_conformance.py +0 -0
- {vgi_python-0.14.0 → vgi_python-0.16.0}/tests/test_generated_cpp_constants.py +0 -0
- {vgi_python-0.14.0 → vgi_python-0.16.0}/tests/test_generated_cpp_protocol_version.py +0 -0
- {vgi_python-0.14.0 → vgi_python-0.16.0}/tests/test_generated_cpp_request_builders.py +0 -0
- {vgi_python-0.14.0 → vgi_python-0.16.0}/tests/test_generated_cpp_schemas.py +0 -0
- {vgi_python-0.14.0 → vgi_python-0.16.0}/tests/test_generated_cpp_secret.py +0 -0
- {vgi_python-0.14.0 → vgi_python-0.16.0}/tests/test_generated_go_schemas.py +0 -0
- {vgi_python-0.14.0 → vgi_python-0.16.0}/tests/test_generated_protocol_version.py +0 -0
- {vgi_python-0.14.0 → vgi_python-0.16.0}/tests/test_generated_schemas_cross_lang.py +0 -0
- {vgi_python-0.14.0 → vgi_python-0.16.0}/tests/test_generated_ts_client.py +0 -0
- {vgi_python-0.14.0 → vgi_python-0.16.0}/tests/test_generated_ts_schemas.py +0 -0
- {vgi_python-0.14.0 → vgi_python-0.16.0}/tests/test_http_demo_storage.py +0 -0
- {vgi_python-0.14.0 → vgi_python-0.16.0}/tests/test_http_s3_offload_input.py +0 -0
- {vgi_python-0.14.0 → vgi_python-0.16.0}/tests/test_http_s3_offload_output.py +0 -0
- {vgi_python-0.14.0 → vgi_python-0.16.0}/tests/test_landing_conformance.py +0 -0
- {vgi_python-0.14.0 → vgi_python-0.16.0}/tests/test_metadata.py +0 -0
- {vgi_python-0.14.0 → vgi_python-0.16.0}/tests/test_mypy_consolidated.py +0 -0
- {vgi_python-0.14.0 → vgi_python-0.16.0}/tests/test_nest_tensor.py +0 -0
- {vgi_python-0.14.0 → vgi_python-0.16.0}/tests/test_otel.py +0 -0
- {vgi_python-0.14.0 → vgi_python-0.16.0}/tests/test_projection_enforcement.py +0 -0
- {vgi_python-0.14.0 → vgi_python-0.16.0}/tests/test_projection_repro.py +0 -0
- {vgi_python-0.14.0 → vgi_python-0.16.0}/tests/test_protocol_classes.py +0 -0
- {vgi_python-0.14.0 → vgi_python-0.16.0}/tests/test_resolved_secrets.py +0 -0
- {vgi_python-0.14.0 → vgi_python-0.16.0}/tests/test_schema_utils.py +0 -0
- {vgi_python-0.14.0 → vgi_python-0.16.0}/tests/test_serve.py +0 -0
- {vgi_python-0.14.0 → vgi_python-0.16.0}/tests/test_setting_secret_annotations.py +0 -0
- {vgi_python-0.14.0 → vgi_python-0.16.0}/tests/test_table_buffering_function.py +0 -0
- {vgi_python-0.14.0 → vgi_python-0.16.0}/tests/test_table_function_dynamic_to_string.py +0 -0
- {vgi_python-0.14.0 → vgi_python-0.16.0}/tests/test_tcp_transport.py +0 -0
- {vgi_python-0.14.0 → vgi_python-0.16.0}/tests/test_type_bounds.py +0 -0
- {vgi_python-0.14.0 → vgi_python-0.16.0}/tests/test_union_argument.py +0 -0
- {vgi_python-0.14.0 → vgi_python-0.16.0}/tests/test_worker.py +0 -0
- {vgi_python-0.14.0 → vgi_python-0.16.0}/tests/test_worker_cli.py +0 -0
- {vgi_python-0.14.0 → vgi_python-0.16.0}/tests/test_worker_page.py +0 -0
- {vgi_python-0.14.0 → vgi_python-0.16.0}/tests/transactor/__init__.py +0 -0
- {vgi_python-0.14.0 → vgi_python-0.16.0}/tests/transactor/test_transactor.py +0 -0
- {vgi_python-0.14.0 → vgi_python-0.16.0}/vgi/__init__.py +0 -0
- {vgi_python-0.14.0 → vgi_python-0.16.0}/vgi/_duckdb.py +0 -0
- {vgi_python-0.14.0 → vgi_python-0.16.0}/vgi/_storage_profile.py +0 -0
- {vgi_python-0.14.0 → vgi_python-0.16.0}/vgi/_test_fixtures/__init__.py +0 -0
- {vgi_python-0.14.0 → vgi_python-0.16.0}/vgi/_test_fixtures/accumulate/__init__.py +0 -0
- {vgi_python-0.14.0 → vgi_python-0.16.0}/vgi/_test_fixtures/accumulate/worker.py +0 -0
- {vgi_python-0.14.0 → vgi_python-0.16.0}/vgi/_test_fixtures/aggregate/__init__.py +0 -0
- {vgi_python-0.14.0 → vgi_python-0.16.0}/vgi/_test_fixtures/aggregate/_common.py +0 -0
- {vgi_python-0.14.0 → vgi_python-0.16.0}/vgi/_test_fixtures/aggregate/basic.py +0 -0
- {vgi_python-0.14.0 → vgi_python-0.16.0}/vgi/_test_fixtures/aggregate/dynamic.py +0 -0
- {vgi_python-0.14.0 → vgi_python-0.16.0}/vgi/_test_fixtures/aggregate/generic.py +0 -0
- {vgi_python-0.14.0 → vgi_python-0.16.0}/vgi/_test_fixtures/aggregate/listagg.py +0 -0
- {vgi_python-0.14.0 → vgi_python-0.16.0}/vgi/_test_fixtures/aggregate/percentile.py +0 -0
- {vgi_python-0.14.0 → vgi_python-0.16.0}/vgi/_test_fixtures/aggregate/secret_typed.py +0 -0
- {vgi_python-0.14.0 → vgi_python-0.16.0}/vgi/_test_fixtures/aggregate/streaming.py +0 -0
- {vgi_python-0.14.0 → vgi_python-0.16.0}/vgi/_test_fixtures/aggregate/varargs.py +0 -0
- {vgi_python-0.14.0 → vgi_python-0.16.0}/vgi/_test_fixtures/aggregate/window.py +0 -0
- {vgi_python-0.14.0 → vgi_python-0.16.0}/vgi/_test_fixtures/attach_options.py +0 -0
- {vgi_python-0.14.0 → vgi_python-0.16.0}/vgi/_test_fixtures/bad_enum.py +0 -0
- {vgi_python-0.14.0 → vgi_python-0.16.0}/vgi/_test_fixtures/bad_protocol.py +0 -0
- {vgi_python-0.14.0 → vgi_python-0.16.0}/vgi/_test_fixtures/cancellable.py +0 -0
- {vgi_python-0.14.0 → vgi_python-0.16.0}/vgi/_test_fixtures/catalog.py +0 -0
- {vgi_python-0.14.0 → vgi_python-0.16.0}/vgi/_test_fixtures/companion.py +0 -0
- {vgi_python-0.14.0 → vgi_python-0.16.0}/vgi/_test_fixtures/copy_from.py +0 -0
- {vgi_python-0.14.0 → vgi_python-0.16.0}/vgi/_test_fixtures/copy_to.py +0 -0
- {vgi_python-0.14.0 → vgi_python-0.16.0}/vgi/_test_fixtures/http_server.py +0 -0
- {vgi_python-0.14.0 → vgi_python-0.16.0}/vgi/_test_fixtures/narrow_bind/__init__.py +0 -0
- {vgi_python-0.14.0 → vgi_python-0.16.0}/vgi/_test_fixtures/narrow_bind/worker.py +0 -0
- {vgi_python-0.14.0 → vgi_python-0.16.0}/vgi/_test_fixtures/nest_tensor.py +0 -0
- {vgi_python-0.14.0 → vgi_python-0.16.0}/vgi/_test_fixtures/orchard_catalog.py +0 -0
- {vgi_python-0.14.0 → vgi_python-0.16.0}/vgi/_test_fixtures/projection_repro/__init__.py +0 -0
- {vgi_python-0.14.0 → vgi_python-0.16.0}/vgi/_test_fixtures/projection_repro/worker.py +0 -0
- {vgi_python-0.14.0 → vgi_python-0.16.0}/vgi/_test_fixtures/scalar/__init__.py +0 -0
- {vgi_python-0.14.0 → vgi_python-0.16.0}/vgi/_test_fixtures/scalar/_common.py +0 -0
- {vgi_python-0.14.0 → vgi_python-0.16.0}/vgi/_test_fixtures/scalar/arithmetic.py +0 -0
- {vgi_python-0.14.0 → vgi_python-0.16.0}/vgi/_test_fixtures/scalar/binary.py +0 -0
- {vgi_python-0.14.0 → vgi_python-0.16.0}/vgi/_test_fixtures/scalar/formatting.py +0 -0
- {vgi_python-0.14.0 → vgi_python-0.16.0}/vgi/_test_fixtures/scalar/geo.py +0 -0
- {vgi_python-0.14.0 → vgi_python-0.16.0}/vgi/_test_fixtures/scalar/null_handling.py +0 -0
- {vgi_python-0.14.0 → vgi_python-0.16.0}/vgi/_test_fixtures/scalar/random_demo.py +0 -0
- {vgi_python-0.14.0 → vgi_python-0.16.0}/vgi/_test_fixtures/scalar/settings_secrets.py +0 -0
- {vgi_python-0.14.0 → vgi_python-0.16.0}/vgi/_test_fixtures/scalar/type_info.py +0 -0
- {vgi_python-0.14.0 → vgi_python-0.16.0}/vgi/_test_fixtures/schema_reconcile/__init__.py +0 -0
- {vgi_python-0.14.0 → vgi_python-0.16.0}/vgi/_test_fixtures/schema_reconcile/worker.py +0 -0
- {vgi_python-0.14.0 → vgi_python-0.16.0}/vgi/_test_fixtures/simple_writable.py +0 -0
- {vgi_python-0.14.0 → vgi_python-0.16.0}/vgi/_test_fixtures/table/__init__.py +0 -0
- {vgi_python-0.14.0 → vgi_python-0.16.0}/vgi/_test_fixtures/table/_common.py +0 -0
- {vgi_python-0.14.0 → vgi_python-0.16.0}/vgi/_test_fixtures/table/batch_index.py +0 -0
- {vgi_python-0.14.0 → vgi_python-0.16.0}/vgi/_test_fixtures/table/batch_index_broken.py +0 -0
- {vgi_python-0.14.0 → vgi_python-0.16.0}/vgi/_test_fixtures/table/cache.py +0 -0
- {vgi_python-0.14.0 → vgi_python-0.16.0}/vgi/_test_fixtures/table/catalog_scans.py +0 -0
- {vgi_python-0.14.0 → vgi_python-0.16.0}/vgi/_test_fixtures/table/filters.py +0 -0
- {vgi_python-0.14.0 → vgi_python-0.16.0}/vgi/_test_fixtures/table/late_materialization.py +0 -0
- {vgi_python-0.14.0 → vgi_python-0.16.0}/vgi/_test_fixtures/table/make_series.py +0 -0
- {vgi_python-0.14.0 → vgi_python-0.16.0}/vgi/_test_fixtures/table/misc.py +0 -0
- {vgi_python-0.14.0 → vgi_python-0.16.0}/vgi/_test_fixtures/table/order_modes.py +0 -0
- {vgi_python-0.14.0 → vgi_python-0.16.0}/vgi/_test_fixtures/table/pairs.py +0 -0
- {vgi_python-0.14.0 → vgi_python-0.16.0}/vgi/_test_fixtures/table/partition_columns.py +0 -0
- {vgi_python-0.14.0 → vgi_python-0.16.0}/vgi/_test_fixtures/table/partition_columns_broken.py +0 -0
- {vgi_python-0.14.0 → vgi_python-0.16.0}/vgi/_test_fixtures/table/profiling_example.py +0 -0
- {vgi_python-0.14.0 → vgi_python-0.16.0}/vgi/_test_fixtures/table/sequence.py +0 -0
- {vgi_python-0.14.0 → vgi_python-0.16.0}/vgi/_test_fixtures/table/settings.py +0 -0
- {vgi_python-0.14.0 → vgi_python-0.16.0}/vgi/_test_fixtures/table/transaction_storage.py +0 -0
- {vgi_python-0.14.0 → vgi_python-0.16.0}/vgi/_test_fixtures/table/tt_pushdown.py +0 -0
- {vgi_python-0.14.0 → vgi_python-0.16.0}/vgi/_test_fixtures/table/typed_probe.py +0 -0
- {vgi_python-0.14.0 → vgi_python-0.16.0}/vgi/_test_fixtures/table/versioned.py +0 -0
- {vgi_python-0.14.0 → vgi_python-0.16.0}/vgi/_test_fixtures/versioned.py +0 -0
- {vgi_python-0.14.0 → vgi_python-0.16.0}/vgi/_test_fixtures/versioned_tables.py +0 -0
- {vgi_python-0.14.0 → vgi_python-0.16.0}/vgi/_test_fixtures/writable/__init__.py +0 -0
- {vgi_python-0.14.0 → vgi_python-0.16.0}/vgi/_test_fixtures/writable/generic.py +0 -0
- {vgi_python-0.14.0 → vgi_python-0.16.0}/vgi/_test_fixtures/writable/table.py +0 -0
- {vgi_python-0.14.0 → vgi_python-0.16.0}/vgi/_test_fixtures/writable/worker.py +0 -0
- {vgi_python-0.14.0 → vgi_python-0.16.0}/vgi/aggregate_function.py +0 -0
- {vgi_python-0.14.0 → vgi_python-0.16.0}/vgi/argument_spec.py +0 -0
- {vgi_python-0.14.0 → vgi_python-0.16.0}/vgi/arguments.py +0 -0
- {vgi_python-0.14.0 → vgi_python-0.16.0}/vgi/auth.py +0 -0
- {vgi_python-0.14.0 → vgi_python-0.16.0}/vgi/cache_control.py +0 -0
- {vgi_python-0.14.0 → vgi_python-0.16.0}/vgi/catalog/__init__.py +0 -0
- {vgi_python-0.14.0 → vgi_python-0.16.0}/vgi/catalog/_descriptor_spec.py +0 -0
- {vgi_python-0.14.0 → vgi_python-0.16.0}/vgi/catalog/attach_option.py +0 -0
- {vgi_python-0.14.0 → vgi_python-0.16.0}/vgi/catalog/duckdb_statistics.py +0 -0
- {vgi_python-0.14.0 → vgi_python-0.16.0}/vgi/catalog/secret_type.py +0 -0
- {vgi_python-0.14.0 → vgi_python-0.16.0}/vgi/catalog/setting.py +0 -0
- {vgi_python-0.14.0 → vgi_python-0.16.0}/vgi/catalog/storage.py +0 -0
- {vgi_python-0.14.0 → vgi_python-0.16.0}/vgi/client/__init__.py +0 -0
- {vgi_python-0.14.0 → vgi_python-0.16.0}/vgi/client/catalog_mixin.py +0 -0
- {vgi_python-0.14.0 → vgi_python-0.16.0}/vgi/client/cli.py +0 -0
- {vgi_python-0.14.0 → vgi_python-0.16.0}/vgi/client/cli_catalog.py +0 -0
- {vgi_python-0.14.0 → vgi_python-0.16.0}/vgi/client/cli_schema.py +0 -0
- {vgi_python-0.14.0 → vgi_python-0.16.0}/vgi/client/cli_table.py +0 -0
- {vgi_python-0.14.0 → vgi_python-0.16.0}/vgi/client/cli_transaction.py +0 -0
- {vgi_python-0.14.0 → vgi_python-0.16.0}/vgi/client/cli_utils.py +0 -0
- {vgi_python-0.14.0 → vgi_python-0.16.0}/vgi/client/cli_view.py +0 -0
- {vgi_python-0.14.0 → vgi_python-0.16.0}/vgi/client/client.py +0 -0
- {vgi_python-0.14.0 → vgi_python-0.16.0}/vgi/codegen/__init__.py +0 -0
- {vgi_python-0.14.0 → vgi_python-0.16.0}/vgi/codegen/_common.py +0 -0
- {vgi_python-0.14.0 → vgi_python-0.16.0}/vgi/codegen/cpp_constants.py +0 -0
- {vgi_python-0.14.0 → vgi_python-0.16.0}/vgi/codegen/cpp_protocol_version.py +0 -0
- {vgi_python-0.14.0 → vgi_python-0.16.0}/vgi/codegen/cpp_request_builders.py +0 -0
- {vgi_python-0.14.0 → vgi_python-0.16.0}/vgi/codegen/cpp_schemas.py +0 -0
- {vgi_python-0.14.0 → vgi_python-0.16.0}/vgi/codegen/cpp_secret_protocol_version.py +0 -0
- {vgi_python-0.14.0 → vgi_python-0.16.0}/vgi/codegen/cpp_secret_request_builders.py +0 -0
- {vgi_python-0.14.0 → vgi_python-0.16.0}/vgi/codegen/cpp_secret_schemas.py +0 -0
- {vgi_python-0.14.0 → vgi_python-0.16.0}/vgi/codegen/go_schemas.py +0 -0
- {vgi_python-0.14.0 → vgi_python-0.16.0}/vgi/codegen/protocol_version.py +0 -0
- {vgi_python-0.14.0 → vgi_python-0.16.0}/vgi/codegen/ts_client.py +0 -0
- {vgi_python-0.14.0 → vgi_python-0.16.0}/vgi/codegen/ts_schemas.py +0 -0
- {vgi_python-0.14.0 → vgi_python-0.16.0}/vgi/copy_from_function.py +0 -0
- {vgi_python-0.14.0 → vgi_python-0.16.0}/vgi/copy_to_function.py +0 -0
- {vgi_python-0.14.0 → vgi_python-0.16.0}/vgi/exceptions.py +0 -0
- {vgi_python-0.14.0 → vgi_python-0.16.0}/vgi/function.py +0 -0
- {vgi_python-0.14.0 → vgi_python-0.16.0}/vgi/function_storage.py +0 -0
- {vgi_python-0.14.0 → vgi_python-0.16.0}/vgi/function_storage_azure_sql.py +0 -0
- {vgi_python-0.14.0 → vgi_python-0.16.0}/vgi/function_storage_cf_do.py +0 -0
- {vgi_python-0.14.0 → vgi_python-0.16.0}/vgi/http/__init__.py +0 -0
- {vgi_python-0.14.0 → vgi_python-0.16.0}/vgi/http/demo_storage.py +0 -0
- {vgi_python-0.14.0 → vgi_python-0.16.0}/vgi/http/describe_json.py +0 -0
- {vgi_python-0.14.0 → vgi_python-0.16.0}/vgi/http/landing.html +0 -0
- {vgi_python-0.14.0 → vgi_python-0.16.0}/vgi/http/landing_page.py +0 -0
- {vgi_python-0.14.0 → vgi_python-0.16.0}/vgi/http/worker_page.py +0 -0
- {vgi_python-0.14.0 → vgi_python-0.16.0}/vgi/invocation.py +0 -0
- {vgi_python-0.14.0 → vgi_python-0.16.0}/vgi/logging_config.py +0 -0
- {vgi_python-0.14.0 → vgi_python-0.16.0}/vgi/meta_worker.py +0 -0
- {vgi_python-0.14.0 → vgi_python-0.16.0}/vgi/otel.py +0 -0
- {vgi_python-0.14.0 → vgi_python-0.16.0}/vgi/protocol_version.txt +0 -0
- {vgi_python-0.14.0 → vgi_python-0.16.0}/vgi/py.typed +0 -0
- {vgi_python-0.14.0 → vgi_python-0.16.0}/vgi/scalar_function.py +0 -0
- {vgi_python-0.14.0 → vgi_python-0.16.0}/vgi/schema_utils.py +0 -0
- {vgi_python-0.14.0 → vgi_python-0.16.0}/vgi/secret_protocol.py +0 -0
- {vgi_python-0.14.0 → vgi_python-0.16.0}/vgi/secret_service.py +0 -0
- {vgi_python-0.14.0 → vgi_python-0.16.0}/vgi/serve.py +0 -0
- {vgi_python-0.14.0 → vgi_python-0.16.0}/vgi/table_buffering_function.py +0 -0
- {vgi_python-0.14.0 → vgi_python-0.16.0}/vgi/table_filter_pushdown.py +0 -0
- {vgi_python-0.14.0 → vgi_python-0.16.0}/vgi/transactor/__init__.py +0 -0
- {vgi_python-0.14.0 → vgi_python-0.16.0}/vgi/transactor/_duckdb_compat.py +0 -0
- {vgi_python-0.14.0 → vgi_python-0.16.0}/vgi/transactor/client.py +0 -0
- {vgi_python-0.14.0 → vgi_python-0.16.0}/vgi/transactor/protocol.py +0 -0
- {vgi_python-0.14.0 → vgi_python-0.16.0}/vgi/transactor/server.py +0 -0
- {vgi_python-0.14.0 → vgi_python-0.16.0}/wrangler.jsonc +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: vgi-python
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.16.0
|
|
4
4
|
Summary: Vector Gateway Interface - Connect DuckDB to external programs via Apache Arrow
|
|
5
5
|
Project-URL: Homepage, https://query.farm
|
|
6
6
|
Project-URL: Repository, https://github.com/Query-farm/vgi-python
|
|
@@ -257,12 +257,43 @@ rm -f "$STAGE/test/_warm.test"
|
|
|
257
257
|
# simple_writable); the http lane's writes self-skip.
|
|
258
258
|
echo "Running suite ($SUITE_GLOB, transport=$TRANSPORT) ..."
|
|
259
259
|
suite_rc=0
|
|
260
|
+
|
|
261
|
+
# run_unittest — invoke haybarn-unittest, streaming its output, and additionally
|
|
262
|
+
# fail on a fatal-signal report that the process's own exit code cannot express.
|
|
263
|
+
#
|
|
264
|
+
# Catch2 arms handlers for SIGTERM/SIGINT/SIGSEGV/... for the duration of a test
|
|
265
|
+
# case. Those handlers are inherited by any process the extension fork()s, and
|
|
266
|
+
# run in the child if a signal lands before it execs. The child then prints a
|
|
267
|
+
# full "FAILED: ... due to a fatal error condition: SIGTERM" block plus a run
|
|
268
|
+
# summary — the *parent's* accumulated counters, since it's an address-space
|
|
269
|
+
# copy — and dies. The parent never sees it, records no failure, and exits 0.
|
|
270
|
+
# The only trace is on stdout, so that is what we scan. Seen on the shm lane in
|
|
271
|
+
# https://github.com/Query-farm/vgi-python/actions/runs/29051359074.
|
|
272
|
+
run_unittest() {
|
|
273
|
+
local log rc=0
|
|
274
|
+
log="$(mktemp)"
|
|
275
|
+
# `set +e` rather than `|| true`: the latter runs before PIPESTATUS is read and
|
|
276
|
+
# overwrites it with true's 0, silently swallowing every real test failure.
|
|
277
|
+
set +e
|
|
278
|
+
"$HAYBARN_UNITTEST" "$@" 2>&1 | tee "$log"
|
|
279
|
+
rc="${PIPESTATUS[0]}"
|
|
280
|
+
set -e
|
|
281
|
+
if grep -q 'due to a fatal error condition' "$log"; then
|
|
282
|
+
echo "::error::a forked child ran the test harness's signal handler (see the" \
|
|
283
|
+
"'fatal error condition' block above). The parent exited $rc and would" \
|
|
284
|
+
"otherwise have passed. This is invisible to the exit code by construction."
|
|
285
|
+
rc=1
|
|
286
|
+
fi
|
|
287
|
+
rm -f "$log"
|
|
288
|
+
return "$rc"
|
|
289
|
+
}
|
|
290
|
+
|
|
260
291
|
if [ "$TRANSPORT" = "launch" ]; then
|
|
261
|
-
|
|
292
|
+
run_unittest "$SUITE_GLOB" || suite_rc=$?
|
|
262
293
|
else
|
|
263
|
-
|
|
294
|
+
run_unittest "$SUITE_GLOB" "~test/sql/integration/simple_writable/*" || suite_rc=$?
|
|
264
295
|
echo "Running simple_writable (isolated process) ..."
|
|
265
|
-
|
|
296
|
+
run_unittest "test/sql/integration/simple_writable/*" || suite_rc=$?
|
|
266
297
|
fi
|
|
267
298
|
|
|
268
299
|
exit "$suite_rc"
|
|
@@ -14,13 +14,13 @@ Tests cover:
|
|
|
14
14
|
from __future__ import annotations
|
|
15
15
|
|
|
16
16
|
from dataclasses import dataclass
|
|
17
|
-
from typing import ClassVar
|
|
17
|
+
from typing import Annotated, ClassVar
|
|
18
18
|
|
|
19
19
|
import pyarrow as pa
|
|
20
20
|
import pytest
|
|
21
21
|
from vgi_rpc.rpc import OutputCollector
|
|
22
22
|
|
|
23
|
-
from vgi import Worker
|
|
23
|
+
from vgi import Arg, Arguments, Worker
|
|
24
24
|
from vgi.catalog import (
|
|
25
25
|
AttachOpaqueData,
|
|
26
26
|
Catalog,
|
|
@@ -50,6 +50,7 @@ from vgi.table_function import (
|
|
|
50
50
|
bind_fixed_schema,
|
|
51
51
|
init_single_worker,
|
|
52
52
|
)
|
|
53
|
+
from vgi.table_in_out_function import TableInOutGenerator
|
|
53
54
|
|
|
54
55
|
# =============================================================================
|
|
55
56
|
# Test Fixtures: Example Functions for Function-Backed Tables
|
|
@@ -61,6 +62,45 @@ class EmptyArgs:
|
|
|
61
62
|
"""No arguments."""
|
|
62
63
|
|
|
63
64
|
|
|
65
|
+
@dataclass(frozen=True)
|
|
66
|
+
class CountedRowsArgs:
|
|
67
|
+
"""A required positional argument plus an optional named one."""
|
|
68
|
+
|
|
69
|
+
count: Annotated[int, Arg(0, doc="Number of rows to generate", ge=0)]
|
|
70
|
+
label: Annotated[str, Arg("label", default="rows", doc="Label for the rows")]
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
@init_single_worker
|
|
74
|
+
@bind_fixed_schema
|
|
75
|
+
class CountedRowsFunction(TableFunctionGenerator[CountedRowsArgs]):
|
|
76
|
+
"""Table function with a required positional arg, for arg-propagation tests."""
|
|
77
|
+
|
|
78
|
+
class Meta: # noqa: D106
|
|
79
|
+
name = "counted_rows"
|
|
80
|
+
description = "Generate N rows"
|
|
81
|
+
|
|
82
|
+
FIXED_SCHEMA: ClassVar[pa.Schema] = schema({"n": pa.int64()})
|
|
83
|
+
|
|
84
|
+
@classmethod
|
|
85
|
+
def process( # noqa: D102
|
|
86
|
+
cls, params: ProcessParams[CountedRowsArgs], state: None, out: OutputCollector
|
|
87
|
+
) -> None:
|
|
88
|
+
out.emit(
|
|
89
|
+
pa.RecordBatch.from_pydict(
|
|
90
|
+
{"n": list(range(params.args.count))},
|
|
91
|
+
schema=params.output_schema,
|
|
92
|
+
)
|
|
93
|
+
)
|
|
94
|
+
out.finish()
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
class CountedRowsInsert(TableInOutGenerator[None, None]):
|
|
98
|
+
"""Stub insert function, for the write-path arg-propagation test."""
|
|
99
|
+
|
|
100
|
+
class Meta: # noqa: D106
|
|
101
|
+
name = "counted_rows_insert"
|
|
102
|
+
|
|
103
|
+
|
|
64
104
|
@init_single_worker
|
|
65
105
|
@bind_fixed_schema
|
|
66
106
|
class UsersFunction(TableFunctionGenerator[EmptyArgs]):
|
|
@@ -262,6 +302,87 @@ class TestTableWithFunction:
|
|
|
262
302
|
assert info.update_function is None
|
|
263
303
|
assert info.delete_function is None
|
|
264
304
|
|
|
305
|
+
def test_inlined_scan_function_carries_declared_positional_arguments(self) -> None:
|
|
306
|
+
"""``Table.arguments`` must reach the scan-time bind, not just ``bind()``.
|
|
307
|
+
|
|
308
|
+
Regression: the inlined ``ScanFunctionResult`` used to hardcode empty
|
|
309
|
+
arguments, so a backing function with a required positional ``Arg(0)``
|
|
310
|
+
saw zero positional args at scan and failed with
|
|
311
|
+
``IndexError: Argument 0: index out of range``.
|
|
312
|
+
"""
|
|
313
|
+
from vgi_rpc.utils import deserialize_record_batch
|
|
314
|
+
|
|
315
|
+
table = Table(
|
|
316
|
+
name="counted",
|
|
317
|
+
function=CountedRowsFunction,
|
|
318
|
+
arguments=Arguments(positional=(pa.scalar(7),)),
|
|
319
|
+
)
|
|
320
|
+
info = table.to_table_info("main")
|
|
321
|
+
assert info.scan_function is not None
|
|
322
|
+
batch, _ = deserialize_record_batch(info.scan_function)
|
|
323
|
+
sfr = ScanFunctionResult.deserialize(batch)
|
|
324
|
+
assert sfr.function_name == "counted_rows"
|
|
325
|
+
assert [s.as_py() for s in sfr.positional_arguments] == [7]
|
|
326
|
+
assert sfr.named_arguments == {}
|
|
327
|
+
|
|
328
|
+
def test_inlined_scan_function_carries_declared_named_arguments(self) -> None:
|
|
329
|
+
"""Named args declared on the Table also reach the scan-time bind."""
|
|
330
|
+
from vgi_rpc.utils import deserialize_record_batch
|
|
331
|
+
|
|
332
|
+
table = Table(
|
|
333
|
+
name="counted",
|
|
334
|
+
function=CountedRowsFunction,
|
|
335
|
+
arguments=Arguments(
|
|
336
|
+
positional=(pa.scalar(3),),
|
|
337
|
+
named={"label": pa.scalar("widgets")},
|
|
338
|
+
),
|
|
339
|
+
)
|
|
340
|
+
info = table.to_table_info("main")
|
|
341
|
+
assert info.scan_function is not None
|
|
342
|
+
batch, _ = deserialize_record_batch(info.scan_function)
|
|
343
|
+
sfr = ScanFunctionResult.deserialize(batch)
|
|
344
|
+
assert [s.as_py() for s in sfr.positional_arguments] == [3]
|
|
345
|
+
assert {k: v.as_py() for k, v in sfr.named_arguments.items()} == {"label": "widgets"}
|
|
346
|
+
|
|
347
|
+
def test_inlined_write_functions_ignore_table_arguments(self) -> None:
|
|
348
|
+
"""Only the *scan* function is parameterized by ``Table.arguments``.
|
|
349
|
+
|
|
350
|
+
Insert/update/delete functions receive their rows via the streaming table
|
|
351
|
+
input, so their inlined results stay argument-free.
|
|
352
|
+
"""
|
|
353
|
+
from vgi_rpc.utils import deserialize_record_batch
|
|
354
|
+
|
|
355
|
+
table = Table(
|
|
356
|
+
name="counted",
|
|
357
|
+
function=CountedRowsFunction,
|
|
358
|
+
arguments=Arguments(positional=(pa.scalar(7),)),
|
|
359
|
+
insert_function=CountedRowsInsert,
|
|
360
|
+
)
|
|
361
|
+
info = table.to_table_info("main")
|
|
362
|
+
assert info.insert_function is not None
|
|
363
|
+
batch, _ = deserialize_record_batch(info.insert_function)
|
|
364
|
+
sfr = ScanFunctionResult.deserialize(batch)
|
|
365
|
+
assert sfr.positional_arguments == []
|
|
366
|
+
assert sfr.named_arguments == {}
|
|
367
|
+
|
|
368
|
+
def test_none_positional_slot_is_rejected(self) -> None:
|
|
369
|
+
"""A ``None`` positional slot would shift later args — reject it loudly.
|
|
370
|
+
|
|
371
|
+
Exercised on the ``scan_arguments_from`` helper directly: a Table carrying
|
|
372
|
+
such a slot already fails earlier, in bind()-based schema derivation. This
|
|
373
|
+
guards the serializer against ever silently dropping the slot instead.
|
|
374
|
+
"""
|
|
375
|
+
from vgi.catalog.catalog_interface import scan_arguments_from
|
|
376
|
+
|
|
377
|
+
with pytest.raises(ValueError, match="positional slot 0 is None"):
|
|
378
|
+
scan_arguments_from(Arguments(positional=(None, pa.scalar(7))))
|
|
379
|
+
|
|
380
|
+
def test_scan_arguments_from_none_is_empty(self) -> None:
|
|
381
|
+
"""A table declaring no arguments serializes empty args (unchanged behavior)."""
|
|
382
|
+
from vgi.catalog.catalog_interface import scan_arguments_from
|
|
383
|
+
|
|
384
|
+
assert scan_arguments_from(None) == ([], {})
|
|
385
|
+
|
|
265
386
|
def test_table_propagates_cardinality_to_table_info(self) -> None:
|
|
266
387
|
"""``Table.cardinality_estimate`` / ``cardinality_max`` flow into TableInfo.
|
|
267
388
|
|
|
@@ -1121,8 +1242,6 @@ class TestSchemaDescriptor:
|
|
|
1121
1242
|
client hits a cold miss. Reporting an explicit ``0`` for empty
|
|
1122
1243
|
categories lets the client skip the bulk RPC entirely.
|
|
1123
1244
|
"""
|
|
1124
|
-
from typing import Annotated
|
|
1125
|
-
|
|
1126
1245
|
from vgi.arguments import Param, Returns
|
|
1127
1246
|
from vgi.scalar_function import ScalarFunction
|
|
1128
1247
|
|
|
@@ -1174,8 +1293,6 @@ class TestLegacyFunctionsListSchemaInfo:
|
|
|
1174
1293
|
"""
|
|
1175
1294
|
|
|
1176
1295
|
def _interface(self) -> ReadOnlyCatalogInterface:
|
|
1177
|
-
from typing import Annotated
|
|
1178
|
-
|
|
1179
1296
|
from vgi.arguments import Param, Returns
|
|
1180
1297
|
from vgi.scalar_function import ScalarFunction
|
|
1181
1298
|
|
|
@@ -1694,6 +1811,70 @@ class TestTableScanFunctionGet:
|
|
|
1694
1811
|
)
|
|
1695
1812
|
assert isinstance(result, ScanFunctionResult)
|
|
1696
1813
|
assert result.function_name == "users"
|
|
1814
|
+
# No declared Table.arguments => empty args, unchanged behavior.
|
|
1815
|
+
assert result.positional_arguments == []
|
|
1816
|
+
assert result.named_arguments == {}
|
|
1817
|
+
|
|
1818
|
+
def test_auto_scan_forwards_declared_arguments(self) -> None:
|
|
1819
|
+
"""The RPC auto-impl forwards ``Table.arguments`` to the scan bind.
|
|
1820
|
+
|
|
1821
|
+
Companion to the inlined-path regression: workers that don't inline
|
|
1822
|
+
``TableInfo.scan_function`` reach the scan through this RPC instead.
|
|
1823
|
+
"""
|
|
1824
|
+
counted = Table(
|
|
1825
|
+
name="counted",
|
|
1826
|
+
function=CountedRowsFunction,
|
|
1827
|
+
arguments=Arguments(
|
|
1828
|
+
positional=(pa.scalar(7),),
|
|
1829
|
+
named={"label": pa.scalar("widgets")},
|
|
1830
|
+
),
|
|
1831
|
+
)
|
|
1832
|
+
|
|
1833
|
+
class TestCatalog(ReadOnlyCatalogInterface):
|
|
1834
|
+
catalog = Catalog(
|
|
1835
|
+
name="test",
|
|
1836
|
+
schemas=[Schema(name="main", tables=[counted])],
|
|
1837
|
+
)
|
|
1838
|
+
|
|
1839
|
+
result = TestCatalog().table_scan_function_get(
|
|
1840
|
+
attach_opaque_data=AttachOpaqueData(b"test"),
|
|
1841
|
+
transaction_opaque_data=None,
|
|
1842
|
+
schema_name="main",
|
|
1843
|
+
name="counted",
|
|
1844
|
+
at_unit=None,
|
|
1845
|
+
at_value=None,
|
|
1846
|
+
)
|
|
1847
|
+
assert result.function_name == "counted_rows"
|
|
1848
|
+
assert [s.as_py() for s in result.positional_arguments] == [7]
|
|
1849
|
+
assert {k: v.as_py() for k, v in result.named_arguments.items()} == {"label": "widgets"}
|
|
1850
|
+
|
|
1851
|
+
def test_scan_branches_default_inherits_declared_arguments(self) -> None:
|
|
1852
|
+
"""The default ``table_scan_branches_get`` delegates to the legacy method.
|
|
1853
|
+
|
|
1854
|
+
So the one-branch synthesis must carry the declared arguments too.
|
|
1855
|
+
"""
|
|
1856
|
+
counted = Table(
|
|
1857
|
+
name="counted",
|
|
1858
|
+
function=CountedRowsFunction,
|
|
1859
|
+
arguments=Arguments(positional=(pa.scalar(7),)),
|
|
1860
|
+
)
|
|
1861
|
+
|
|
1862
|
+
class TestCatalog(ReadOnlyCatalogInterface):
|
|
1863
|
+
catalog = Catalog(
|
|
1864
|
+
name="test",
|
|
1865
|
+
schemas=[Schema(name="main", tables=[counted])],
|
|
1866
|
+
)
|
|
1867
|
+
|
|
1868
|
+
result = TestCatalog().table_scan_branches_get(
|
|
1869
|
+
attach_opaque_data=AttachOpaqueData(b"test"),
|
|
1870
|
+
transaction_opaque_data=None,
|
|
1871
|
+
schema_name="main",
|
|
1872
|
+
name="counted",
|
|
1873
|
+
at_unit=None,
|
|
1874
|
+
at_value=None,
|
|
1875
|
+
)
|
|
1876
|
+
assert len(result.branches) == 1
|
|
1877
|
+
assert [s.as_py() for s in result.branches[0].positional_arguments] == [7]
|
|
1697
1878
|
|
|
1698
1879
|
def test_explicit_columns_table_raises(self) -> None:
|
|
1699
1880
|
"""Tables with explicit columns raise NotImplementedError."""
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
"""Unit tests for the ``Table.required_filters`` field.
|
|
2
|
+
|
|
3
|
+
The field is purely declarative on the Python side — enforcement runs in the C++
|
|
4
|
+
optimizer extension. It is conjunctive normal form: an AND (outer tuple) of
|
|
5
|
+
OR-groups (inner tuples) of dotted-path column references. These tests cover:
|
|
6
|
+
|
|
7
|
+
1. Default-empty behaviour (no field set → ``TableInfo`` ships an empty list).
|
|
8
|
+
2. Populated round-trip (singleton groups + a multi-path OR-group preserved).
|
|
9
|
+
3. Validation: each path's leading dotted segment must be a real column.
|
|
10
|
+
4. Empty-string paths and empty OR-groups are rejected loudly.
|
|
11
|
+
"""
|
|
12
|
+
|
|
13
|
+
from __future__ import annotations
|
|
14
|
+
|
|
15
|
+
import pyarrow as pa
|
|
16
|
+
import pytest
|
|
17
|
+
|
|
18
|
+
from vgi.catalog.descriptors import Table
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
class TestRequiredFiltersField:
|
|
22
|
+
"""Behaviour of the declarative required_filters field."""
|
|
23
|
+
|
|
24
|
+
def _bbox_columns(self) -> pa.Schema:
|
|
25
|
+
"""Return a small schema with a ``bbox`` STRUCT plus flat id/ticker."""
|
|
26
|
+
return pa.schema(
|
|
27
|
+
[
|
|
28
|
+
("id", pa.int64()),
|
|
29
|
+
("ticker", pa.string()),
|
|
30
|
+
(
|
|
31
|
+
"bbox",
|
|
32
|
+
pa.struct(
|
|
33
|
+
[
|
|
34
|
+
("xmin", pa.float64()),
|
|
35
|
+
("ymin", pa.float64()),
|
|
36
|
+
("xmax", pa.float64()),
|
|
37
|
+
("ymax", pa.float64()),
|
|
38
|
+
]
|
|
39
|
+
),
|
|
40
|
+
),
|
|
41
|
+
]
|
|
42
|
+
)
|
|
43
|
+
|
|
44
|
+
def test_default_is_empty_tuple(self) -> None:
|
|
45
|
+
"""Default is an empty tuple; TableInfo wire field is an empty list."""
|
|
46
|
+
t = Table(name="t", columns=self._bbox_columns())
|
|
47
|
+
assert t.required_filters == ()
|
|
48
|
+
info = t.to_table_info("main")
|
|
49
|
+
assert info.required_filters == []
|
|
50
|
+
|
|
51
|
+
def test_singleton_groups_round_trip(self) -> None:
|
|
52
|
+
"""Singleton groups (the AND-only case) survive as a list of lists."""
|
|
53
|
+
groups = (("bbox.xmin",), ("bbox.xmax",), ("bbox.ymin",), ("bbox.ymax",))
|
|
54
|
+
t = Table(name="place", columns=self._bbox_columns(), required_filters=groups)
|
|
55
|
+
assert t.required_filters == groups
|
|
56
|
+
info = t.to_table_info("main")
|
|
57
|
+
assert info.required_filters == [list(g) for g in groups]
|
|
58
|
+
|
|
59
|
+
def test_or_group_round_trip(self) -> None:
|
|
60
|
+
"""A multi-path OR-group survives alongside a singleton mandatory group."""
|
|
61
|
+
groups = (("id",), ("id", "ticker"))
|
|
62
|
+
t = Table(name="t", columns=self._bbox_columns(), required_filters=groups)
|
|
63
|
+
info = t.to_table_info("main")
|
|
64
|
+
assert info.required_filters == [["id"], ["id", "ticker"]]
|
|
65
|
+
|
|
66
|
+
def test_top_level_path(self) -> None:
|
|
67
|
+
"""A top-level column name (no dots) is a valid path."""
|
|
68
|
+
t = Table(name="t", columns=self._bbox_columns(), required_filters=(("id",),))
|
|
69
|
+
assert t.to_table_info("main").required_filters == [["id"]]
|
|
70
|
+
|
|
71
|
+
def test_nested_path_is_not_unpacked_for_validation(self) -> None:
|
|
72
|
+
"""Only the leading dotted segment is validated; deeper segments pass through."""
|
|
73
|
+
# Subfield validity isn't checked here (descriptor doesn't unpack struct
|
|
74
|
+
# schemas) — only the leading segment matters. Typos like ``bbox.nope``
|
|
75
|
+
# go through and DuckDB catches them at scan time.
|
|
76
|
+
t = Table(name="t", columns=self._bbox_columns(), required_filters=(("bbox.nope",),))
|
|
77
|
+
assert t.required_filters == (("bbox.nope",),)
|
|
78
|
+
|
|
79
|
+
def test_unknown_leading_segment_raises(self) -> None:
|
|
80
|
+
"""A path whose leading segment is not a real column is rejected."""
|
|
81
|
+
with pytest.raises(ValueError, match=r"unknown column 'nope'"):
|
|
82
|
+
Table(name="t", columns=self._bbox_columns(), required_filters=(("nope.xmin",),))
|
|
83
|
+
|
|
84
|
+
def test_empty_string_path_raises(self) -> None:
|
|
85
|
+
"""An empty string path is rejected loudly rather than silently accepted."""
|
|
86
|
+
with pytest.raises(ValueError, match="must not contain empty strings"):
|
|
87
|
+
Table(name="t", columns=self._bbox_columns(), required_filters=(("",),))
|
|
88
|
+
|
|
89
|
+
def test_empty_group_raises(self) -> None:
|
|
90
|
+
"""An empty OR-group is rejected loudly."""
|
|
91
|
+
with pytest.raises(ValueError, match="must not contain empty groups"):
|
|
92
|
+
Table(name="t", columns=self._bbox_columns(), required_filters=((),))
|
|
@@ -1149,10 +1149,10 @@ class TestArrowSchemaCorrectness:
|
|
|
1149
1149
|
assert schema.field("cardinality_estimate").type == pa.int64()
|
|
1150
1150
|
assert schema.field("column_statistics").type == pa.binary()
|
|
1151
1151
|
assert schema.field("bind_result").type == pa.binary()
|
|
1152
|
-
assert schema.field("
|
|
1153
|
-
#
|
|
1154
|
-
#
|
|
1155
|
-
assert schema.field(len(schema) - 1).name == "
|
|
1152
|
+
assert schema.field("required_filters").type == pa.list_(pa.list_(pa.string()))
|
|
1153
|
+
# required_filters is the LAST field (positional schema compatibility:
|
|
1154
|
+
# old C++ extensions ignore-by-position trailing fields).
|
|
1155
|
+
assert schema.field(len(schema) - 1).name == "required_filters"
|
|
1156
1156
|
|
|
1157
1157
|
def test_view_info_schema(self) -> None:
|
|
1158
1158
|
"""Verify ViewInfo Arrow schema."""
|
|
@@ -3,9 +3,9 @@
|
|
|
3
3
|
{
|
|
4
4
|
"attach_options": [],
|
|
5
5
|
"counts": {
|
|
6
|
-
"functions":
|
|
6
|
+
"functions": 188,
|
|
7
7
|
"schemas": 2,
|
|
8
|
-
"tables":
|
|
8
|
+
"tables": 59,
|
|
9
9
|
"views": 3
|
|
10
10
|
},
|
|
11
11
|
"data_version_spec": null,
|
|
@@ -225,9 +225,14 @@
|
|
|
225
225
|
},
|
|
226
226
|
{
|
|
227
227
|
"cols": 2,
|
|
228
|
-
"comment": "rff_none — control table with no
|
|
228
|
+
"comment": "rff_none — control table with no required_filters (opt-out fast path).",
|
|
229
229
|
"name": "rff_none"
|
|
230
230
|
},
|
|
231
|
+
{
|
|
232
|
+
"cols": 2,
|
|
233
|
+
"comment": "rff_or — requires a filter on 'a' OR 'b' (a single OR-group).",
|
|
234
|
+
"name": "rff_or"
|
|
235
|
+
},
|
|
231
236
|
{
|
|
232
237
|
"cols": 2,
|
|
233
238
|
"comment": "rff_parquet — native read_parquet delegation with bbox.* required filters.",
|
|
@@ -1242,6 +1247,18 @@
|
|
|
1242
1247
|
"returns": "string",
|
|
1243
1248
|
"type": "scalar"
|
|
1244
1249
|
},
|
|
1250
|
+
{
|
|
1251
|
+
"args": [
|
|
1252
|
+
{
|
|
1253
|
+
"desc": "Input column (ignored)",
|
|
1254
|
+
"name": "x",
|
|
1255
|
+
"type": "double"
|
|
1256
|
+
}
|
|
1257
|
+
],
|
|
1258
|
+
"doc": "Blended 1->0 map emitting a single 0-row batch (literal scan-mode)",
|
|
1259
|
+
"name": "blended_drop",
|
|
1260
|
+
"type": "table"
|
|
1261
|
+
},
|
|
1245
1262
|
{
|
|
1246
1263
|
"args": [
|
|
1247
1264
|
{
|
|
@@ -1815,6 +1832,59 @@
|
|
|
1815
1832
|
"name": "generator_exception",
|
|
1816
1833
|
"type": "table"
|
|
1817
1834
|
},
|
|
1835
|
+
{
|
|
1836
|
+
"args": [
|
|
1837
|
+
{
|
|
1838
|
+
"desc": "Latitude input column",
|
|
1839
|
+
"name": "latitude",
|
|
1840
|
+
"type": "double"
|
|
1841
|
+
},
|
|
1842
|
+
{
|
|
1843
|
+
"desc": "Longitude input column",
|
|
1844
|
+
"name": "longitude",
|
|
1845
|
+
"type": "double"
|
|
1846
|
+
},
|
|
1847
|
+
{
|
|
1848
|
+
"default": "4",
|
|
1849
|
+
"desc": "Rounding precision",
|
|
1850
|
+
"name": "precision",
|
|
1851
|
+
"named": true,
|
|
1852
|
+
"type": "int64"
|
|
1853
|
+
}
|
|
1854
|
+
],
|
|
1855
|
+
"doc": "Blended per-row geo encoder (lat, lon -> geohash)",
|
|
1856
|
+
"name": "geo_encode",
|
|
1857
|
+
"type": "table"
|
|
1858
|
+
},
|
|
1859
|
+
{
|
|
1860
|
+
"args": [
|
|
1861
|
+
{
|
|
1862
|
+
"desc": "Latitude input column",
|
|
1863
|
+
"name": "latitude",
|
|
1864
|
+
"type": "double"
|
|
1865
|
+
},
|
|
1866
|
+
{
|
|
1867
|
+
"desc": "Longitude input column",
|
|
1868
|
+
"name": "longitude",
|
|
1869
|
+
"type": "double"
|
|
1870
|
+
},
|
|
1871
|
+
{
|
|
1872
|
+
"desc": "Altitude input column",
|
|
1873
|
+
"name": "altitude",
|
|
1874
|
+
"type": "double"
|
|
1875
|
+
},
|
|
1876
|
+
{
|
|
1877
|
+
"default": "4",
|
|
1878
|
+
"desc": "Rounding precision",
|
|
1879
|
+
"name": "precision",
|
|
1880
|
+
"named": true,
|
|
1881
|
+
"type": "int64"
|
|
1882
|
+
}
|
|
1883
|
+
],
|
|
1884
|
+
"doc": "Blended per-row geo encoder (lat, lon, alt -> geohash)",
|
|
1885
|
+
"name": "geo_encode",
|
|
1886
|
+
"type": "table"
|
|
1887
|
+
},
|
|
1818
1888
|
{
|
|
1819
1889
|
"args": [
|
|
1820
1890
|
{
|
|
@@ -2316,13 +2386,13 @@
|
|
|
2316
2386
|
},
|
|
2317
2387
|
{
|
|
2318
2388
|
"args": [],
|
|
2319
|
-
"doc": "rff_nested — nested STRUCT(wrapper.mid.leaf) for
|
|
2389
|
+
"doc": "rff_nested — nested STRUCT(wrapper.mid.leaf) for required_filters tests",
|
|
2320
2390
|
"name": "rff_nested_scan",
|
|
2321
2391
|
"type": "table"
|
|
2322
2392
|
},
|
|
2323
2393
|
{
|
|
2324
2394
|
"args": [],
|
|
2325
|
-
"doc": "rff_none — control table with no
|
|
2395
|
+
"doc": "rff_none — control table with no required_filters",
|
|
2326
2396
|
"name": "rff_none_scan",
|
|
2327
2397
|
"type": "table"
|
|
2328
2398
|
},
|
|
@@ -2334,16 +2404,35 @@
|
|
|
2334
2404
|
},
|
|
2335
2405
|
{
|
|
2336
2406
|
"args": [],
|
|
2337
|
-
"doc": "rff_simple — flat columns (a, b) for
|
|
2407
|
+
"doc": "rff_simple — flat columns (a, b) for required_filters tests",
|
|
2338
2408
|
"name": "rff_simple_scan",
|
|
2339
2409
|
"type": "table"
|
|
2340
2410
|
},
|
|
2341
2411
|
{
|
|
2342
2412
|
"args": [],
|
|
2343
|
-
"doc": "rff_struct — STRUCT(s.a, s.b) + other for
|
|
2413
|
+
"doc": "rff_struct — STRUCT(s.a, s.b) + other for required_filters tests",
|
|
2344
2414
|
"name": "rff_struct_scan",
|
|
2345
2415
|
"type": "table"
|
|
2346
2416
|
},
|
|
2417
|
+
{
|
|
2418
|
+
"args": [
|
|
2419
|
+
{
|
|
2420
|
+
"desc": "Numeric input columns",
|
|
2421
|
+
"name": "values",
|
|
2422
|
+
"type": "double"
|
|
2423
|
+
},
|
|
2424
|
+
{
|
|
2425
|
+
"default": "false",
|
|
2426
|
+
"desc": "Sum absolute values",
|
|
2427
|
+
"name": "absolute",
|
|
2428
|
+
"named": true,
|
|
2429
|
+
"type": "bool"
|
|
2430
|
+
}
|
|
2431
|
+
],
|
|
2432
|
+
"doc": "Blended per-row varargs sum",
|
|
2433
|
+
"name": "row_sum",
|
|
2434
|
+
"type": "table"
|
|
2435
|
+
},
|
|
2347
2436
|
{
|
|
2348
2437
|
"args": [
|
|
2349
2438
|
{
|
|
@@ -2938,6 +3027,12 @@
|
|
|
2938
3027
|
"name": "slow_cancellable_buffering",
|
|
2939
3028
|
"type": "table_in_out"
|
|
2940
3029
|
},
|
|
3030
|
+
{
|
|
3031
|
+
"args": [],
|
|
3032
|
+
"doc": "Per-substream partial sum emitted at finalize (parallel streaming finalize)",
|
|
3033
|
+
"name": "substream_partial_sum",
|
|
3034
|
+
"type": "table_in_out"
|
|
3035
|
+
},
|
|
2941
3036
|
{
|
|
2942
3037
|
"args": [
|
|
2943
3038
|
{
|
|
@@ -2954,7 +3049,7 @@
|
|
|
2954
3049
|
},
|
|
2955
3050
|
{
|
|
2956
3051
|
"args": [],
|
|
2957
|
-
"doc": "Distributed sum using
|
|
3052
|
+
"doc": "Distributed sum using the buffered (Sink+Combine+Source) model",
|
|
2958
3053
|
"name": "sum_all_columns_simple_distributed",
|
|
2959
3054
|
"type": "table_in_out"
|
|
2960
3055
|
}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
# Copyright 2025, 2026 Query Farm LLC - https://query.farm
|
|
2
|
+
|
|
3
|
+
"""Tests for SubstreamPartialSumFunction (parallel streaming finalize, A4).
|
|
4
|
+
|
|
5
|
+
At the single-worker client level there is exactly one substream, so ``finish()``
|
|
6
|
+
sees all input and emits one partial row equal to the whole sum. The per-substream
|
|
7
|
+
fan-out (many partials re-aggregated by an outer ``SELECT sum()``) is exercised by
|
|
8
|
+
the C++ integration test ``table_in_out/parallel_finalize.test`` over both
|
|
9
|
+
transports; here we assert the worker-side transform/finish contract in isolation.
|
|
10
|
+
"""
|
|
11
|
+
|
|
12
|
+
from __future__ import annotations
|
|
13
|
+
|
|
14
|
+
import pyarrow as pa
|
|
15
|
+
|
|
16
|
+
from tests.conftest import filter_non_empty, make_schema
|
|
17
|
+
from vgi.client import Client
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
class TestSubstreamPartialSumFunction:
|
|
21
|
+
"""Worker-side contract for substream_partial_sum."""
|
|
22
|
+
|
|
23
|
+
def test_partial_sum_single_batch(self, fixture_worker: str) -> None:
|
|
24
|
+
"""One substream (single client worker) → one partial = the whole sum."""
|
|
25
|
+
schema = make_schema([pa.field("n", pa.int64())])
|
|
26
|
+
batch = pa.RecordBatch.from_pydict({"n": [1, 2, 3, 4, 5]}, schema=schema)
|
|
27
|
+
with Client(fixture_worker) as client:
|
|
28
|
+
output = list(
|
|
29
|
+
client.table_in_out_function(
|
|
30
|
+
function_name="substream_partial_sum",
|
|
31
|
+
input=iter([batch]),
|
|
32
|
+
)
|
|
33
|
+
)
|
|
34
|
+
non_empty = filter_non_empty(output)
|
|
35
|
+
assert len(non_empty) == 1
|
|
36
|
+
assert non_empty[0].to_pydict() == {"n": [15]}
|
|
37
|
+
|
|
38
|
+
def test_partial_sum_many_batches(self, fixture_worker: str) -> None:
|
|
39
|
+
"""Accumulates across many input batches, emits one partial at finalize."""
|
|
40
|
+
schema = make_schema([pa.field("n", pa.int64())])
|
|
41
|
+
batches = [
|
|
42
|
+
pa.RecordBatch.from_pydict({"n": list(range(i * 100, (i + 1) * 100))}, schema=schema) for i in range(20)
|
|
43
|
+
]
|
|
44
|
+
expected = sum(range(0, 2000))
|
|
45
|
+
with Client(fixture_worker) as client:
|
|
46
|
+
output = list(
|
|
47
|
+
client.table_in_out_function(
|
|
48
|
+
function_name="substream_partial_sum",
|
|
49
|
+
input=iter(batches),
|
|
50
|
+
)
|
|
51
|
+
)
|
|
52
|
+
non_empty = filter_non_empty(output)
|
|
53
|
+
assert len(non_empty) == 1
|
|
54
|
+
assert non_empty[0].to_pydict() == {"n": [expected]}
|
|
55
|
+
|
|
56
|
+
def test_partial_sum_empty_input(self, fixture_worker: str) -> None:
|
|
57
|
+
"""No input rows → the single substream's partial is 0."""
|
|
58
|
+
schema = make_schema([pa.field("n", pa.int64())])
|
|
59
|
+
empty = pa.RecordBatch.from_pydict({"n": []}, schema=schema)
|
|
60
|
+
with Client(fixture_worker) as client:
|
|
61
|
+
output = list(
|
|
62
|
+
client.table_in_out_function(
|
|
63
|
+
function_name="substream_partial_sum",
|
|
64
|
+
input=iter([empty]),
|
|
65
|
+
)
|
|
66
|
+
)
|
|
67
|
+
non_empty = filter_non_empty(output)
|
|
68
|
+
# A single substream with zero rows still finalizes → one 0 partial.
|
|
69
|
+
assert len(non_empty) == 1
|
|
70
|
+
assert non_empty[0].to_pydict() == {"n": [0]}
|