vgi-python 0.22.0__tar.gz → 0.23.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.22.0 → vgi_python-0.23.0}/.github/workflows/integration.yml +7 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/PKG-INFO +2 -2
- {vgi_python-0.22.0 → vgi_python-0.23.0}/pyproject.toml +2 -2
- {vgi_python-0.22.0 → vgi_python-0.23.0}/tests/test_serve.py +51 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/uv.lock +5 -5
- {vgi_python-0.22.0 → vgi_python-0.23.0}/vgi/_test_fixtures/http_server.py +4 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/vgi/argument_spec.py +51 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/vgi/logging_config.py +68 -0
- vgi_python-0.23.0/vgi/profiling.py +93 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/vgi/serve.py +17 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/.gitattributes +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/.github/dependabot.yml +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/.github/styles/config/vocabularies/VGI/accept.txt +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/.github/workflows/ci.yml +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/.github/workflows/docs.yml +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/.github/workflows/release.yml +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/.gitignore +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/.python-version +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/.vale.ini +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/CLAUDE.md +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/DOCS_ACCEPTANCE_CRITERIA.md +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/DOCS_REVIEW_RUBRIC.md +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/DOCS_USABILITY_TEST.md +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/LICENSE +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/README.md +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/SECURITY.md +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/ci/README.md +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/ci/preprocess-require.awk +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/ci/run-integration.sh +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/dist-vgi/.gitignore +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/docs/aggregate-functions.md +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/docs/api/arguments.md +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/docs/api/auth.md +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/docs/api/catalogs.md +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/docs/api/client.md +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/docs/api/exceptions.md +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/docs/api/filters.md +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/docs/api/functions.md +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/docs/api/http.md +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/docs/api/index.md +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/docs/api/metadata.md +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/docs/api/observability.md +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/docs/api/storage.md +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/docs/api/transactor.md +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/docs/api/worker.md +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/docs/argument-serialization.md +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/docs/assets/apple-touch-icon.png +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/docs/assets/favicon-16x16.png +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/docs/assets/favicon-32x32.png +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/docs/assets/favicon.ico +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/docs/assets/kinds/aggregate.svg +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/docs/assets/kinds/buffering.svg +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/docs/assets/kinds/scalar.svg +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/docs/assets/kinds/table-in-out.svg +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/docs/assets/kinds/table.svg +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/docs/assets/logo.png +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/docs/assets/social-card.png +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/docs/authentication.md +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/docs/catalog-interface.md +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/docs/cli.md +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/docs/column-statistics.md +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/docs/concepts/index.md +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/docs/contributing-docs.md +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/docs/filter-pushdown.md +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/docs/generator-api.md +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/docs/how-to/catalogs.md +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/docs/how-to/function-patterns.md +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/docs/how-to/http-auth.md +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/docs/how-to/index.md +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/docs/how-to/pushdown-and-statistics.md +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/docs/how-to/state-storage.md +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/docs/index.md +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/docs/lifecycle.md +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/docs/metadata.md +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/docs/overrides/main.html +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/docs/robots.txt +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/docs/shared-storage.md +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/docs/stylesheets/extra.css +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/docs/tutorial/index.md +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/docs/tutorial/scalar.md +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/docs/tutorial/table.md +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/docs/vgi-logo.png +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/examples/calc_scalar_worker.py +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/examples/calc_worker.py +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/examples/filter_worker.py +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/examples/greeting_scalar_worker.py +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/examples/row_count_worker.py +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/examples/series_streaming_worker.py +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/examples/sum_worker.py +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/mkdocs.yml +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/packages/vgi-fixtures/LICENSE +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/packages/vgi-fixtures/README.md +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/packages/vgi-fixtures/docker/Dockerfile +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/packages/vgi-fixtures/docker/docker-entrypoint.sh +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/packages/vgi-fixtures/pyproject.toml +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/scripts/measure_startup.py +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/scripts/run_all_tests.sh +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/test-data/generate.sh +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/tests/__init__.py +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/tests/_http_fixtures.py +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/tests/catalog/__init__.py +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/tests/catalog/test_catalog_interface.py +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/tests/catalog/test_client_catalog.py +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/tests/catalog/test_column_statistics.py +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/tests/catalog/test_declarative.py +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/tests/catalog/test_example_worker_catalog.py +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/tests/catalog/test_integration.py +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/tests/catalog/test_required_filters.py +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/tests/catalog/test_scan_branches.py +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/tests/catalog/test_serialization.py +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/tests/catalog/test_setting.py +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/tests/catalog/test_storage.py +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/tests/catalog/test_time_travel.py +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/tests/catalog/test_writable_table.py +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/tests/client/__init__.py +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/tests/client/test_broken_pipe.py +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/tests/client/test_cli.py +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/tests/client/test_cli_catalog_functions.py +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/tests/client/test_worker_debug.py +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/tests/conformance/__init__.py +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/tests/conformance/_stub.py +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/tests/conformance/conftest.py +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/tests/conformance/test_accumulate.py +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/tests/conformance/test_aggregate.py +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/tests/conformance/test_attach.py +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/tests/conformance/test_bearer_auth.py +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/tests/conformance/test_const_param_enforcement.py +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/tests/conformance/test_container.py +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/tests/conformance/test_copy_from.py +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/tests/conformance/test_copy_to.py +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/tests/conformance/test_directory_parity.py +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/tests/conformance/test_function_inventory.py +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/tests/conformance/test_github.py +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/tests/conformance/test_http_client.py +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/tests/conformance/test_http_external_location.py +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/tests/conformance/test_http_upload_url.py +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/tests/conformance/test_macro.py +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/tests/conformance/test_overload.py +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/tests/conformance/test_protocol_inventory.py +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/tests/conformance/test_protocol_version.py +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/tests/conformance/test_resumable_scan.py +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/tests/conformance/test_scalar.py +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/tests/conformance/test_scalar_attach_opaque_data.py +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/tests/conformance/test_secret.py +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/tests/conformance/test_settings.py +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/tests/conformance/test_table.py +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/tests/conformance/test_table_in_out.py +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/tests/conformance/test_view.py +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/tests/conformance/test_writable.py +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/tests/conftest.py +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/tests/landing/_checker.py +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/tests/landing/describe.expected.json +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/tests/landing/describe.schema.json +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/tests/scalar/__init__.py +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/tests/scalar/test_bernoulli_function.py +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/tests/scalar/test_binary_packet_function.py +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/tests/scalar/test_client.py +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/tests/scalar/test_conditional_message_function.py +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/tests/scalar/test_hash_seed_function.py +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/tests/scalar/test_multiply_by_setting_function.py +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/tests/scalar/test_multiply_function.py +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/tests/scalar/test_random_bytes_function.py +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/tests/scalar/test_return_secret_value_function.py +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/tests/table/__init__.py +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/tests/table/generator/__init__.py +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/tests/table/generator/test_constant_columns_function.py +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/tests/table/generator/test_double_sequence_function.py +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/tests/table/generator/test_exception_function.py +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/tests/table/generator/test_filter_echo_function.py +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/tests/table/generator/test_logging_function.py +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/tests/table/generator/test_nested_sequence_function.py +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/tests/table/generator/test_partitioned_function.py +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/tests/table/generator/test_projected_data_function.py +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/tests/table/generator/test_sequence_function.py +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/tests/table/generator/test_settings_function.py +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/tests/table/generator/test_struct_settings_function.py +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/tests/table/generator/test_ten_thousand_function.py +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/tests/table_in_out/__init__.py +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/tests/table_in_out/generator/__init__.py +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/tests/table_in_out/generator/test_buffer_input_function.py +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/tests/table_in_out/generator/test_echo_function.py +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/tests/table_in_out/generator/test_exception_functions.py +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/tests/table_in_out/generator/test_filter_by_setting_function.py +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/tests/table_in_out/generator/test_repeat_inputs_function.py +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/tests/table_in_out/generator/test_substream_partial_sum_function.py +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/tests/table_in_out/generator/test_sum_all_columns_function.py +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/tests/table_in_out/test_blended_metadata.py +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/tests/table_in_out/test_client.py +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/tests/test_access_log_audit.py +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/tests/test_aggregate_function.py +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/tests/test_argument_spec.py +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/tests/test_auth.py +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/tests/test_bind_exceptions.py +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/tests/test_bind_request_at_clause.py +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/tests/test_bound_storage_conformance.py +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/tests/test_cache_control.py +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/tests/test_catalog_auth_binding.py +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/tests/test_copy_from_function.py +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/tests/test_copy_to_function.py +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/tests/test_docstrings.py +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/tests/test_documentation_examples.py +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/tests/test_example_function_arg_types.py +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/tests/test_examples_workers.py +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/tests/test_exception_handling.py +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/tests/test_exceptions.py +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/tests/test_filter_pushdown.py +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/tests/test_filter_pushdown_extension.py +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/tests/test_function_storage.py +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/tests/test_function_storage_azure_sql.py +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/tests/test_function_storage_cf_do.py +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/tests/test_function_storage_cf_do_integration.py +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/tests/test_function_storage_conformance.py +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/tests/test_generated_cpp_constants.py +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/tests/test_generated_cpp_protocol_version.py +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/tests/test_generated_cpp_request_builders.py +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/tests/test_generated_cpp_schemas.py +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/tests/test_generated_cpp_secret.py +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/tests/test_generated_go_schemas.py +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/tests/test_generated_protocol_version.py +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/tests/test_generated_schemas_cross_lang.py +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/tests/test_generated_ts_client.py +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/tests/test_generated_ts_schemas.py +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/tests/test_http_demo_storage.py +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/tests/test_http_s3_offload_input.py +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/tests/test_http_s3_offload_output.py +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/tests/test_landing_conformance.py +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/tests/test_metadata.py +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/tests/test_mypy_consolidated.py +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/tests/test_nest_tensor.py +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/tests/test_otel.py +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/tests/test_projection_enforcement.py +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/tests/test_projection_repro.py +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/tests/test_protocol_classes.py +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/tests/test_resolved_secrets.py +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/tests/test_schema_scoped_functions.py +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/tests/test_schema_utils.py +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/tests/test_setting_secret_annotations.py +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/tests/test_table_buffering_function.py +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/tests/test_table_function_dynamic_to_string.py +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/tests/test_tcp_transport.py +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/tests/test_type_bounds.py +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/tests/test_union_argument.py +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/tests/test_worker.py +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/tests/test_worker_cli.py +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/tests/test_worker_page.py +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/tests/transactor/__init__.py +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/tests/transactor/test_transactor.py +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/vgi/__init__.py +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/vgi/_duckdb.py +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/vgi/_storage_profile.py +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/vgi/_test_fixtures/__init__.py +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/vgi/_test_fixtures/accumulate/__init__.py +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/vgi/_test_fixtures/accumulate/worker.py +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/vgi/_test_fixtures/aggregate/__init__.py +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/vgi/_test_fixtures/aggregate/_common.py +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/vgi/_test_fixtures/aggregate/basic.py +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/vgi/_test_fixtures/aggregate/dynamic.py +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/vgi/_test_fixtures/aggregate/generic.py +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/vgi/_test_fixtures/aggregate/listagg.py +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/vgi/_test_fixtures/aggregate/percentile.py +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/vgi/_test_fixtures/aggregate/same_name.py +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/vgi/_test_fixtures/aggregate/secret_typed.py +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/vgi/_test_fixtures/aggregate/streaming.py +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/vgi/_test_fixtures/aggregate/varargs.py +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/vgi/_test_fixtures/aggregate/window.py +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/vgi/_test_fixtures/attach_options.py +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/vgi/_test_fixtures/bad_enum.py +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/vgi/_test_fixtures/bad_protocol.py +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/vgi/_test_fixtures/cancellable.py +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/vgi/_test_fixtures/catalog.py +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/vgi/_test_fixtures/companion.py +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/vgi/_test_fixtures/copy_from.py +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/vgi/_test_fixtures/copy_to.py +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/vgi/_test_fixtures/narrow_bind/__init__.py +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/vgi/_test_fixtures/narrow_bind/worker.py +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/vgi/_test_fixtures/nest_tensor.py +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/vgi/_test_fixtures/orchard_catalog.py +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/vgi/_test_fixtures/projection_repro/__init__.py +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/vgi/_test_fixtures/projection_repro/worker.py +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/vgi/_test_fixtures/scalar/__init__.py +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/vgi/_test_fixtures/scalar/_common.py +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/vgi/_test_fixtures/scalar/arithmetic.py +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/vgi/_test_fixtures/scalar/bench_ladder.py +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/vgi/_test_fixtures/scalar/binary.py +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/vgi/_test_fixtures/scalar/formatting.py +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/vgi/_test_fixtures/scalar/geo.py +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/vgi/_test_fixtures/scalar/null_handling.py +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/vgi/_test_fixtures/scalar/random_demo.py +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/vgi/_test_fixtures/scalar/same_name.py +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/vgi/_test_fixtures/scalar/settings_secrets.py +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/vgi/_test_fixtures/scalar/type_info.py +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/vgi/_test_fixtures/schema_reconcile/__init__.py +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/vgi/_test_fixtures/schema_reconcile/worker.py +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/vgi/_test_fixtures/simple_writable.py +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/vgi/_test_fixtures/table/__init__.py +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/vgi/_test_fixtures/table/_common.py +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/vgi/_test_fixtures/table/batch_index.py +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/vgi/_test_fixtures/table/batch_index_broken.py +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/vgi/_test_fixtures/table/cache.py +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/vgi/_test_fixtures/table/catalog_scans.py +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/vgi/_test_fixtures/table/filters.py +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/vgi/_test_fixtures/table/late_materialization.py +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/vgi/_test_fixtures/table/make_series.py +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/vgi/_test_fixtures/table/misc.py +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/vgi/_test_fixtures/table/order_modes.py +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/vgi/_test_fixtures/table/pairs.py +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/vgi/_test_fixtures/table/partition_columns.py +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/vgi/_test_fixtures/table/partition_columns_broken.py +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/vgi/_test_fixtures/table/profiling_example.py +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/vgi/_test_fixtures/table/required_filters.py +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/vgi/_test_fixtures/table/same_name_cached.py +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/vgi/_test_fixtures/table/sequence.py +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/vgi/_test_fixtures/table/settings.py +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/vgi/_test_fixtures/table/transaction_storage.py +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/vgi/_test_fixtures/table/tt_pushdown.py +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/vgi/_test_fixtures/table/typed_probe.py +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/vgi/_test_fixtures/table/versioned.py +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/vgi/_test_fixtures/table_in_out.py +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/vgi/_test_fixtures/table_in_out_same_name.py +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/vgi/_test_fixtures/twin_catalogs.py +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/vgi/_test_fixtures/versioned.py +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/vgi/_test_fixtures/versioned_tables.py +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/vgi/_test_fixtures/worker.py +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/vgi/_test_fixtures/writable/__init__.py +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/vgi/_test_fixtures/writable/generic.py +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/vgi/_test_fixtures/writable/table.py +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/vgi/_test_fixtures/writable/worker.py +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/vgi/aggregate_function.py +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/vgi/arguments.py +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/vgi/attach_header.py +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/vgi/auth.py +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/vgi/cache_control.py +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/vgi/catalog/__init__.py +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/vgi/catalog/_descriptor_spec.py +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/vgi/catalog/attach_option.py +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/vgi/catalog/catalog_interface.py +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/vgi/catalog/descriptors.py +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/vgi/catalog/duckdb_statistics.py +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/vgi/catalog/secret_type.py +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/vgi/catalog/setting.py +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/vgi/catalog/storage.py +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/vgi/client/__init__.py +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/vgi/client/catalog_mixin.py +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/vgi/client/cli.py +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/vgi/client/cli_catalog.py +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/vgi/client/cli_schema.py +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/vgi/client/cli_table.py +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/vgi/client/cli_transaction.py +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/vgi/client/cli_utils.py +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/vgi/client/cli_view.py +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/vgi/client/client.py +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/vgi/codegen/__init__.py +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/vgi/codegen/_common.py +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/vgi/codegen/cpp_constants.py +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/vgi/codegen/cpp_protocol_version.py +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/vgi/codegen/cpp_request_builders.py +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/vgi/codegen/cpp_schemas.py +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/vgi/codegen/cpp_secret_protocol_version.py +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/vgi/codegen/cpp_secret_request_builders.py +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/vgi/codegen/cpp_secret_schemas.py +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/vgi/codegen/go_schemas.py +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/vgi/codegen/protocol_version.py +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/vgi/codegen/ts_client.py +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/vgi/codegen/ts_schemas.py +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/vgi/copy_from_function.py +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/vgi/copy_to_function.py +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/vgi/exceptions.py +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/vgi/function.py +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/vgi/function_storage.py +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/vgi/function_storage_azure_sql.py +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/vgi/function_storage_cf_do.py +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/vgi/http/__init__.py +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/vgi/http/demo_storage.py +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/vgi/http/describe_json.py +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/vgi/http/landing.html +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/vgi/http/landing_page.py +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/vgi/http/worker_page.py +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/vgi/invocation.py +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/vgi/meta_worker.py +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/vgi/metadata.py +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/vgi/otel.py +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/vgi/protocol.py +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/vgi/protocol_version.txt +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/vgi/py.typed +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/vgi/scalar_function.py +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/vgi/schema_utils.py +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/vgi/secret_protocol.py +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/vgi/secret_service.py +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/vgi/table_buffering_function.py +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/vgi/table_filter_pushdown.py +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/vgi/table_function.py +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/vgi/table_in_out_function.py +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/vgi/transactor/__init__.py +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/vgi/transactor/_duckdb_compat.py +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/vgi/transactor/client.py +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/vgi/transactor/protocol.py +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/vgi/transactor/server.py +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/vgi/worker.py +0 -0
- {vgi_python-0.22.0 → vgi_python-0.23.0}/wrangler.jsonc +0 -0
|
@@ -33,6 +33,13 @@ env:
|
|
|
33
33
|
# The Haybarn release providing the prebuilt haybarn-unittest binary. Must be
|
|
34
34
|
# ABI-compatible with the community-published vgi extension.
|
|
35
35
|
HAYBARN_RELEASE: haybarn-v1.5.4-rc3
|
|
36
|
+
# CI is not a user: its ATTACHes should not land in Query.Farm's adoption data.
|
|
37
|
+
# The vgi extension fires a telemetry event per successful ATTACH, and this
|
|
38
|
+
# suite performs several hundred of them per lane, so opting out keeps the
|
|
39
|
+
# numbers honest. It also removes telemetry as a variable in lane timings —
|
|
40
|
+
# the per-ATTACH event was added in Query-farm/vgi 71e2d51 (2026-07-12), and
|
|
41
|
+
# the stdio lane total stepped from ~690s to ~870s across that window.
|
|
42
|
+
QUERY_FARM_TELEMETRY_OPT_OUT: "1"
|
|
36
43
|
|
|
37
44
|
jobs:
|
|
38
45
|
integration:
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: vgi-python
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.23.0
|
|
4
4
|
Summary: Vector Gateway Interface - Connect DuckDB to external programs via Apache Arrow
|
|
5
5
|
Project-URL: Homepage, https://query.farm
|
|
6
6
|
Project-URL: Repository, https://github.com/Query-farm/vgi-python
|
|
@@ -162,7 +162,7 @@ Requires-Dist: httpx>=0.24
|
|
|
162
162
|
Requires-Dist: platformdirs
|
|
163
163
|
Requires-Dist: pyarrow
|
|
164
164
|
Requires-Dist: typer>=0.9
|
|
165
|
-
Requires-Dist: vgi-rpc>=0.28.
|
|
165
|
+
Requires-Dist: vgi-rpc>=0.28.3
|
|
166
166
|
Provides-Extra: azure
|
|
167
167
|
Requires-Dist: azure-identity>=1.16.0; extra == 'azure'
|
|
168
168
|
Requires-Dist: pymssql>=2.3.0; extra == 'azure'
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "vgi-python"
|
|
3
|
-
version = "0.
|
|
3
|
+
version = "0.23.0"
|
|
4
4
|
description = "Vector Gateway Interface - Connect DuckDB to external programs via Apache Arrow"
|
|
5
5
|
readme = "README.md"
|
|
6
6
|
keywords = [
|
|
@@ -40,7 +40,7 @@ dependencies = [
|
|
|
40
40
|
"pyarrow",
|
|
41
41
|
"typer>=0.9",
|
|
42
42
|
"platformdirs",
|
|
43
|
-
"vgi-rpc>=0.28.
|
|
43
|
+
"vgi-rpc>=0.28.3",
|
|
44
44
|
"httpx>=0.24",
|
|
45
45
|
]
|
|
46
46
|
|
|
@@ -206,6 +206,57 @@ class TestCreateApp:
|
|
|
206
206
|
|
|
207
207
|
assert isinstance(app, falcon.App)
|
|
208
208
|
|
|
209
|
+
@staticmethod
|
|
210
|
+
def _health_proof_header(**env: str) -> str | None:
|
|
211
|
+
"""Serve an app under ``env`` and read the proof capability header.
|
|
212
|
+
|
|
213
|
+
Args:
|
|
214
|
+
**env: ``VGI_PROXY_PROOF_*`` values to set for the duration.
|
|
215
|
+
|
|
216
|
+
Returns:
|
|
217
|
+
The ``VGI-Proxy-Proof-Required`` value, or ``None`` when absent.
|
|
218
|
+
|
|
219
|
+
"""
|
|
220
|
+
import falcon.testing
|
|
221
|
+
|
|
222
|
+
with pytest.MonkeyPatch.context() as mp:
|
|
223
|
+
for key in ("VGI_PROXY_PROOF_MODE", "VGI_PROXY_PROOF_ORIGIN_ID", "VGI_PROXY_PROOF_SECRETS"):
|
|
224
|
+
mp.delenv(key, raising=False)
|
|
225
|
+
for key, value in env.items():
|
|
226
|
+
mp.setenv(key, value)
|
|
227
|
+
app = create_app(_SingleWorker, prefix="/vgi", describe=False)
|
|
228
|
+
resp = falcon.testing.TestClient(app).simulate_get("/vgi/health")
|
|
229
|
+
assert resp.status_code == 200
|
|
230
|
+
return {k.lower(): v for k, v in resp.headers.items()}.get("vgi-proxy-proof-required")
|
|
231
|
+
|
|
232
|
+
def test_advertises_proof_required_in_require_mode(self) -> None:
|
|
233
|
+
"""A ``require``-mode worker tells proxies it actually enforces.
|
|
234
|
+
|
|
235
|
+
Derived from ``VGI_PROXY_PROOF_MODE`` rather than passed separately,
|
|
236
|
+
because that env var is also where the gate itself comes from — so the
|
|
237
|
+
advertisement cannot drift from the posture it describes.
|
|
238
|
+
"""
|
|
239
|
+
value = self._health_proof_header(
|
|
240
|
+
VGI_PROXY_PROOF_MODE="require",
|
|
241
|
+
VGI_PROXY_PROOF_ORIGIN_ID="worker-a",
|
|
242
|
+
VGI_PROXY_PROOF_SECRETS="k:" + "11" * 32,
|
|
243
|
+
)
|
|
244
|
+
assert value == "true"
|
|
245
|
+
|
|
246
|
+
@pytest.mark.parametrize("mode", ["off", "allow"])
|
|
247
|
+
def test_does_not_advertise_below_require(self, mode: str) -> None:
|
|
248
|
+
"""Only ``require`` advertises — ``allow`` never denies, so it must not.
|
|
249
|
+
|
|
250
|
+
A proxy reads this to confirm a rollout landed; an ``allow``-mode worker
|
|
251
|
+
that claimed to require would report the rollout complete while every
|
|
252
|
+
unproofed direct caller still sailed through.
|
|
253
|
+
"""
|
|
254
|
+
env = {"VGI_PROXY_PROOF_MODE": mode}
|
|
255
|
+
if mode != "off":
|
|
256
|
+
env["VGI_PROXY_PROOF_ORIGIN_ID"] = "worker-a"
|
|
257
|
+
env["VGI_PROXY_PROOF_SECRETS"] = "k:" + "11" * 32
|
|
258
|
+
assert self._health_proof_header(**env) is None
|
|
259
|
+
|
|
209
260
|
def test_signing_key_passed(self) -> None:
|
|
210
261
|
"""Explicit signing_key is accepted without warning."""
|
|
211
262
|
import warnings
|
|
@@ -2228,7 +2228,7 @@ requires-dist = [
|
|
|
2228
2228
|
|
|
2229
2229
|
[[package]]
|
|
2230
2230
|
name = "vgi-python"
|
|
2231
|
-
version = "0.
|
|
2231
|
+
version = "0.23.0"
|
|
2232
2232
|
source = { editable = "." }
|
|
2233
2233
|
dependencies = [
|
|
2234
2234
|
{ name = "click" },
|
|
@@ -2338,7 +2338,7 @@ requires-dist = [
|
|
|
2338
2338
|
{ name = "vgi-python", extras = ["test-fixtures"], marker = "extra == 'test-fixtures-writable'" },
|
|
2339
2339
|
{ name = "vgi-python", extras = ["test-fixtures", "test-fixtures-writable", "http", "oauth", "otel", "sentry", "azure"], marker = "extra == 'dev'" },
|
|
2340
2340
|
{ name = "vgi-python", extras = ["transactor"], marker = "extra == 'test-fixtures-writable'" },
|
|
2341
|
-
{ name = "vgi-rpc", specifier = ">=0.28.
|
|
2341
|
+
{ name = "vgi-rpc", specifier = ">=0.28.3" },
|
|
2342
2342
|
{ name = "vgi-rpc", extras = ["conformance", "external", "http", "oauth", "otel", "sentry"], marker = "extra == 'dev'" },
|
|
2343
2343
|
{ name = "vgi-rpc", extras = ["http"], marker = "extra == 'http'" },
|
|
2344
2344
|
{ name = "vgi-rpc", extras = ["oauth"], marker = "extra == 'oauth'" },
|
|
@@ -2367,7 +2367,7 @@ docs = [
|
|
|
2367
2367
|
|
|
2368
2368
|
[[package]]
|
|
2369
2369
|
name = "vgi-rpc"
|
|
2370
|
-
version = "0.28.
|
|
2370
|
+
version = "0.28.3"
|
|
2371
2371
|
source = { registry = "https://pypi.org/simple" }
|
|
2372
2372
|
dependencies = [
|
|
2373
2373
|
{ name = "docstring-parser" },
|
|
@@ -2375,9 +2375,9 @@ dependencies = [
|
|
|
2375
2375
|
{ name = "pywin32", marker = "sys_platform == 'win32'" },
|
|
2376
2376
|
{ name = "tzdata", marker = "sys_platform == 'win32'" },
|
|
2377
2377
|
]
|
|
2378
|
-
sdist = { url = "https://files.pythonhosted.org/packages/
|
|
2378
|
+
sdist = { url = "https://files.pythonhosted.org/packages/a0/5a/1996a64ca9ecb0a030cee5a4b9944301f20d6269369b39a5d30f07bf71a9/vgi_rpc-0.28.3.tar.gz", hash = "sha256:772f535912926ce47c17c3eba33769ad226171277159c591f441169f642e14d6", size = 908548, upload-time = "2026-07-27T16:45:47.344Z" }
|
|
2379
2379
|
wheels = [
|
|
2380
|
-
{ url = "https://files.pythonhosted.org/packages/
|
|
2380
|
+
{ url = "https://files.pythonhosted.org/packages/70/d1/db1b3aa48d1d0526bc30ad72e51ad8fd7f67f693310de8c143e707a87d0a/vgi_rpc-0.28.3-py3-none-any.whl", hash = "sha256:bf913b9b95ac4abde4e4ddad5b228c1d81bd748268773f9a2e5fa9626cc68bf7", size = 406388, upload-time = "2026-07-27T16:45:45.905Z" },
|
|
2381
2381
|
]
|
|
2382
2382
|
|
|
2383
2383
|
[package.optional-dependencies]
|
|
@@ -27,6 +27,7 @@ from vgi._test_fixtures.schema_reconcile.worker import SchemaReconcileWorker
|
|
|
27
27
|
from vgi._test_fixtures.worker import ExampleWorker
|
|
28
28
|
from vgi.logging_config import LogFormat, LogLevel, configure_worker_logging
|
|
29
29
|
from vgi.meta_worker import MetaWorker
|
|
30
|
+
from vgi.profiling import maybe_start_profile
|
|
30
31
|
|
|
31
32
|
if TYPE_CHECKING:
|
|
32
33
|
from vgi_rpc.external import UploadUrl
|
|
@@ -209,12 +210,15 @@ def main() -> None:
|
|
|
209
210
|
|
|
210
211
|
env_debug = os.environ.get("VGI_WORKER_DEBUG", "").lower() in ("1", "true", "yes")
|
|
211
212
|
effective_debug = debug or env_debug
|
|
213
|
+
# VGI_WORKER_LOG_* overrides are applied inside configure_worker_logging,
|
|
214
|
+
# so this server and `vgi-serve` are configurable the same way.
|
|
212
215
|
effective_level = configure_worker_logging(
|
|
213
216
|
debug=effective_debug,
|
|
214
217
|
log_level=log_level,
|
|
215
218
|
log_loggers=log_logger,
|
|
216
219
|
log_format=log_format,
|
|
217
220
|
)
|
|
221
|
+
maybe_start_profile()
|
|
218
222
|
|
|
219
223
|
bucket = s3_bucket or os.environ.get("VGI_HTTP_S3_BUCKET")
|
|
220
224
|
external_location = None
|
|
@@ -18,6 +18,7 @@ import json
|
|
|
18
18
|
import warnings
|
|
19
19
|
from collections.abc import Sequence
|
|
20
20
|
from dataclasses import dataclass
|
|
21
|
+
from functools import cache
|
|
21
22
|
from typing import Annotated, Any, get_args, get_origin, get_type_hints
|
|
22
23
|
|
|
23
24
|
import pyarrow as pa
|
|
@@ -519,6 +520,10 @@ def extract_argument_specs(
|
|
|
519
520
|
2. Type annotation with `PYTHON_TO_ARROW` mapping
|
|
520
521
|
3. Default to pa.null() with warning for unknown types
|
|
521
522
|
|
|
523
|
+
Memoized per class — see :func:`_extract_argument_specs_cached`. A fresh
|
|
524
|
+
list is returned each call so a caller that mutates it cannot corrupt the
|
|
525
|
+
cache; the `ArgumentSpec`s inside are frozen dataclasses and safe to share.
|
|
526
|
+
|
|
522
527
|
Args:
|
|
523
528
|
cls: Function class with `Arg` descriptors.
|
|
524
529
|
|
|
@@ -527,6 +532,52 @@ def extract_argument_specs(
|
|
|
527
532
|
then named).
|
|
528
533
|
|
|
529
534
|
"""
|
|
535
|
+
return list(_extract_argument_specs_cached(cls))
|
|
536
|
+
|
|
537
|
+
|
|
538
|
+
@cache
|
|
539
|
+
def _extract_argument_specs_cached(cls: type) -> tuple[ArgumentSpec, ...]:
|
|
540
|
+
"""Memoized :func:`_extract_argument_specs`, keyed on the class.
|
|
541
|
+
|
|
542
|
+
A function class's argument specs are fixed once the class exists — they are
|
|
543
|
+
derived from its annotations, its ``FunctionArguments``, and the `Arg`
|
|
544
|
+
descriptors on its MRO, none of which change at runtime. Deriving them was
|
|
545
|
+
nonetheless repeated on **every** catalog listing and every overload match:
|
|
546
|
+
profiling one run of the upstream integration suite through the proxy showed
|
|
547
|
+
58,058 calls costing 15.8s, which drove 131,653 ``typing.get_type_hints``
|
|
548
|
+
calls, 2.4M ``_eval_type`` calls and 648k ``compile`` calls — roughly a
|
|
549
|
+
quarter of the worker's CPU. ``catalog_schema_contents_functions`` was 38ms
|
|
550
|
+
per call against 0.1-2ms for every other catalog method, entirely because of
|
|
551
|
+
this.
|
|
552
|
+
|
|
553
|
+
Unbounded (``functools.cache``) is the right size: the keys are function
|
|
554
|
+
classes, which the catalog already holds for the process's lifetime, so the
|
|
555
|
+
cache adds no retention that did not already exist. It is also thread safe,
|
|
556
|
+
which matters because workers serve requests on a pool.
|
|
557
|
+
|
|
558
|
+
Returns a tuple so the cached value cannot be mutated through a caller's
|
|
559
|
+
reference.
|
|
560
|
+
|
|
561
|
+
Args:
|
|
562
|
+
cls: Function class with `Arg` descriptors.
|
|
563
|
+
|
|
564
|
+
Returns:
|
|
565
|
+
The class's argument specs, sorted.
|
|
566
|
+
"""
|
|
567
|
+
return tuple(_extract_argument_specs(cls))
|
|
568
|
+
|
|
569
|
+
|
|
570
|
+
def _extract_argument_specs(
|
|
571
|
+
cls: type,
|
|
572
|
+
) -> list[ArgumentSpec]:
|
|
573
|
+
"""Derive a class's argument specs, without caching.
|
|
574
|
+
|
|
575
|
+
Args:
|
|
576
|
+
cls: Function class with `Arg` descriptors.
|
|
577
|
+
|
|
578
|
+
Returns:
|
|
579
|
+
List of `ArgumentSpec` objects, sorted by position.
|
|
580
|
+
"""
|
|
530
581
|
specs: list[ArgumentSpec] = []
|
|
531
582
|
seen_names: set[str] = set()
|
|
532
583
|
|
|
@@ -11,6 +11,7 @@ VGI workers.
|
|
|
11
11
|
from __future__ import annotations
|
|
12
12
|
|
|
13
13
|
import logging
|
|
14
|
+
import os
|
|
14
15
|
import sys
|
|
15
16
|
from enum import StrEnum
|
|
16
17
|
|
|
@@ -46,6 +47,68 @@ _KNOWN_LOGGERS: list[tuple[str, str, str]] = [
|
|
|
46
47
|
]
|
|
47
48
|
|
|
48
49
|
|
|
50
|
+
def _env_overrides(
|
|
51
|
+
log_level: LogLevel,
|
|
52
|
+
log_loggers: list[str] | None,
|
|
53
|
+
log_format: LogFormat,
|
|
54
|
+
) -> tuple[LogLevel, list[str] | None, LogFormat]:
|
|
55
|
+
"""Apply ``VGI_WORKER_LOG_*`` environment overrides to the CLI options.
|
|
56
|
+
|
|
57
|
+
The access log (``vgi_rpc.access``) already records ``duration_ms``,
|
|
58
|
+
``method`` and row/byte counts for every RPC, but reaching it required
|
|
59
|
+
passing ``--log-logger vgi_rpc.access --log-format json`` on the command
|
|
60
|
+
line. Anything that launches a worker without owning its argv — a container
|
|
61
|
+
image, a test harness spawning workers from a dozen call sites — could not
|
|
62
|
+
turn it on. These variables make the same configuration reachable the way
|
|
63
|
+
``VGI_SIGNING_KEY`` and ``VGI_ENABLE_DESCRIBE`` already are.
|
|
64
|
+
|
|
65
|
+
Applied here rather than in a single CLI so that *every* worker entry point
|
|
66
|
+
honours them identically — ``vgi-serve`` and the fixture servers had
|
|
67
|
+
byte-identical logging blocks, and an override wired into only one of them
|
|
68
|
+
would be a trap.
|
|
69
|
+
|
|
70
|
+
Each variable wins when set, matching ``VGI_ENABLE_DESCRIBE``: Typer cannot
|
|
71
|
+
distinguish "user passed the default" from "user passed nothing", so
|
|
72
|
+
deferring to an explicit environment setting is the only unambiguous rule.
|
|
73
|
+
|
|
74
|
+
Args:
|
|
75
|
+
log_level: The ``--log-level`` value.
|
|
76
|
+
log_loggers: The ``--log-logger`` values, if any.
|
|
77
|
+
log_format: The ``--log-format`` value.
|
|
78
|
+
|
|
79
|
+
Returns:
|
|
80
|
+
The effective ``(level, loggers, format)``.
|
|
81
|
+
|
|
82
|
+
Raises:
|
|
83
|
+
SystemExit: If a variable names a level or format that does not exist.
|
|
84
|
+
A typo would otherwise silently leave logging as it was, which is
|
|
85
|
+
indistinguishable from the feature not working.
|
|
86
|
+
"""
|
|
87
|
+
raw_level = os.environ.get("VGI_WORKER_LOG_LEVEL")
|
|
88
|
+
if raw_level:
|
|
89
|
+
try:
|
|
90
|
+
log_level = LogLevel(raw_level.upper())
|
|
91
|
+
except ValueError:
|
|
92
|
+
valid = ", ".join(level.value for level in LogLevel)
|
|
93
|
+
sys.exit(f"VGI_WORKER_LOG_LEVEL={raw_level!r} is not a log level (expected one of: {valid})")
|
|
94
|
+
|
|
95
|
+
raw_format = os.environ.get("VGI_WORKER_LOG_FORMAT")
|
|
96
|
+
if raw_format:
|
|
97
|
+
try:
|
|
98
|
+
log_format = LogFormat(raw_format.lower())
|
|
99
|
+
except ValueError:
|
|
100
|
+
valid = ", ".join(fmt.value for fmt in LogFormat)
|
|
101
|
+
sys.exit(f"VGI_WORKER_LOG_FORMAT={raw_format!r} is not a log format (expected one of: {valid})")
|
|
102
|
+
|
|
103
|
+
raw_loggers = os.environ.get("VGI_WORKER_LOG_LOGGERS")
|
|
104
|
+
if raw_loggers:
|
|
105
|
+
names = [name.strip() for name in raw_loggers.split(",") if name.strip()]
|
|
106
|
+
if names:
|
|
107
|
+
log_loggers = names
|
|
108
|
+
|
|
109
|
+
return log_level, log_loggers, log_format
|
|
110
|
+
|
|
111
|
+
|
|
49
112
|
def configure_worker_logging(
|
|
50
113
|
*,
|
|
51
114
|
debug: bool = False,
|
|
@@ -55,6 +118,10 @@ def configure_worker_logging(
|
|
|
55
118
|
) -> int:
|
|
56
119
|
"""Configure stdlib logging for a VGI worker process.
|
|
57
120
|
|
|
121
|
+
``VGI_WORKER_LOG_LEVEL``, ``VGI_WORKER_LOG_FORMAT`` and
|
|
122
|
+
``VGI_WORKER_LOG_LOGGERS`` override the corresponding arguments when set —
|
|
123
|
+
see :func:`_env_overrides`.
|
|
124
|
+
|
|
58
125
|
Args:
|
|
59
126
|
debug: If True, force DEBUG on all default loggers (overrides *log_level*).
|
|
60
127
|
log_level: Logging level when *debug* is False.
|
|
@@ -65,6 +132,7 @@ def configure_worker_logging(
|
|
|
65
132
|
The effective numeric log level.
|
|
66
133
|
|
|
67
134
|
"""
|
|
135
|
+
log_level, log_loggers, log_format = _env_overrides(log_level, log_loggers, log_format)
|
|
68
136
|
effective_level = logging.DEBUG if debug else getattr(logging, log_level.value)
|
|
69
137
|
|
|
70
138
|
handler = logging.StreamHandler(sys.stderr)
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
# Copyright 2025, 2026 Query Farm LLC - https://query.farm
|
|
2
|
+
|
|
3
|
+
"""Opt-in CPU profiling for VGI worker processes.
|
|
4
|
+
|
|
5
|
+
A worker is normally a subprocess someone else launched — a container, a test
|
|
6
|
+
harness, a DuckDB client spawning it over stdio — so the usual ways of profiling
|
|
7
|
+
Python (``python -m cProfile``, an interactive session) are not available to
|
|
8
|
+
whoever needs the answer. Setting one environment variable is.
|
|
9
|
+
|
|
10
|
+
Shared by every worker entry point rather than living in one CLI, so that
|
|
11
|
+
``vgi-serve`` and the fixture servers profile identically.
|
|
12
|
+
"""
|
|
13
|
+
|
|
14
|
+
from __future__ import annotations
|
|
15
|
+
|
|
16
|
+
import os
|
|
17
|
+
import pathlib
|
|
18
|
+
import sys
|
|
19
|
+
|
|
20
|
+
__all__ = ["maybe_start_profile"]
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
def maybe_start_profile() -> None:
|
|
24
|
+
"""Start a ``cProfile`` profiler when ``VGI_WORKER_PROFILE`` names a path.
|
|
25
|
+
|
|
26
|
+
Set ``VGI_WORKER_PROFILE`` to a directory (or a file path) and the worker
|
|
27
|
+
writes ``pstats`` data on exit, readable with :mod:`pstats`, snakeviz, or
|
|
28
|
+
``python -m pstats``. A directory gets one file per process
|
|
29
|
+
(``worker-<pid>.prof``), which is what you want when the thing under
|
|
30
|
+
investigation spawns more than one worker.
|
|
31
|
+
|
|
32
|
+
**All threads are covered by the single profiler.** That matters because
|
|
33
|
+
under ``--http`` a worker runs on waitress, which serves every request on a
|
|
34
|
+
pool thread — a main-thread-only profile would faithfully report time spent
|
|
35
|
+
in ``select()`` and nothing about the work being measured. Since Python 3.12
|
|
36
|
+
``cProfile`` is built on :mod:`sys.monitoring`, whose tool registration is
|
|
37
|
+
process-global rather than per-thread, so one profiler observes the pool
|
|
38
|
+
threads too.
|
|
39
|
+
|
|
40
|
+
The corollary is that there can be only **one** active profiler in the
|
|
41
|
+
process: ``sys.monitoring`` allows a given tool id to be claimed once, so a
|
|
42
|
+
profiler-per-thread raises ``ValueError: Another profiling tool is already
|
|
43
|
+
active`` in every waitress thread — and because that happens as the thread
|
|
44
|
+
starts, the server never accepts a connection at all.
|
|
45
|
+
|
|
46
|
+
``atexit`` alone would not be enough: a worker is normally stopped with
|
|
47
|
+
``SIGTERM``, whose default action terminates without unwinding, so the
|
|
48
|
+
profile would be lost on every normal shutdown. A handler turns it into an
|
|
49
|
+
ordinary exit — but only if nothing else has claimed ``SIGTERM``, since
|
|
50
|
+
stealing another component's shutdown path would be a worse bug than a
|
|
51
|
+
missing profile.
|
|
52
|
+
"""
|
|
53
|
+
dest = os.environ.get("VGI_WORKER_PROFILE")
|
|
54
|
+
if not dest:
|
|
55
|
+
return
|
|
56
|
+
|
|
57
|
+
import atexit
|
|
58
|
+
import cProfile
|
|
59
|
+
import signal
|
|
60
|
+
|
|
61
|
+
path = pathlib.Path(dest)
|
|
62
|
+
if path.is_dir() or dest.endswith(os.sep):
|
|
63
|
+
path.mkdir(parents=True, exist_ok=True)
|
|
64
|
+
path = path / f"worker-{os.getpid()}.prof"
|
|
65
|
+
else:
|
|
66
|
+
path.parent.mkdir(parents=True, exist_ok=True)
|
|
67
|
+
|
|
68
|
+
profiler = cProfile.Profile()
|
|
69
|
+
profiler.enable()
|
|
70
|
+
dumped = False
|
|
71
|
+
|
|
72
|
+
def _dump() -> None:
|
|
73
|
+
# atexit and the SIGTERM handler can both reach this; dumping twice
|
|
74
|
+
# would truncate the file the first call just wrote.
|
|
75
|
+
nonlocal dumped
|
|
76
|
+
if dumped:
|
|
77
|
+
return
|
|
78
|
+
dumped = True
|
|
79
|
+
try:
|
|
80
|
+
profiler.disable()
|
|
81
|
+
profiler.dump_stats(str(path))
|
|
82
|
+
except Exception as exc: # noqa: BLE001 — never fail a shutdown over telemetry
|
|
83
|
+
sys.stderr.write(f"vgi: could not write profile: {exc}\n")
|
|
84
|
+
return
|
|
85
|
+
sys.stderr.write(f"vgi: wrote profile to {path}\n")
|
|
86
|
+
|
|
87
|
+
atexit.register(_dump)
|
|
88
|
+
|
|
89
|
+
def _on_sigterm(signum: int, frame: object) -> None:
|
|
90
|
+
raise SystemExit(128 + signum)
|
|
91
|
+
|
|
92
|
+
if signal.getsignal(signal.SIGTERM) in (signal.SIG_DFL, None):
|
|
93
|
+
signal.signal(signal.SIGTERM, _on_sigterm)
|
|
@@ -35,6 +35,7 @@ from types import ModuleType
|
|
|
35
35
|
from typing import TYPE_CHECKING, Any, Literal
|
|
36
36
|
|
|
37
37
|
from vgi.logging_config import LogFormat, LogLevel
|
|
38
|
+
from vgi.profiling import maybe_start_profile
|
|
38
39
|
|
|
39
40
|
if TYPE_CHECKING:
|
|
40
41
|
import falcon
|
|
@@ -202,6 +203,7 @@ def create_app(
|
|
|
202
203
|
signing_key: bytes | None = None,
|
|
203
204
|
log_level: int = logging.INFO,
|
|
204
205
|
authenticate: Callable[[falcon.Request], AuthContext] | None = None,
|
|
206
|
+
proxy_proof_required: bool | None = None,
|
|
205
207
|
oauth_resource_metadata: Any = None,
|
|
206
208
|
otel_config: OtelConfig | None = None,
|
|
207
209
|
max_stream_response_bytes: int | None = None,
|
|
@@ -224,6 +226,12 @@ def create_app(
|
|
|
224
226
|
authenticate: Optional callback that validates each HTTP request
|
|
225
227
|
and returns an `AuthContext`. When ``None``, all requests are
|
|
226
228
|
anonymous.
|
|
229
|
+
proxy_proof_required: Whether to advertise ``VGI-Proxy-Proof-Required``
|
|
230
|
+
so a proxy can confirm this worker actually enforces the proof it
|
|
231
|
+
mints. ``None`` (the default) derives it from
|
|
232
|
+
``VGI_PROXY_PROOF_MODE``, which is also where the gate itself comes
|
|
233
|
+
from — so the advertisement cannot drift from the posture. Pass a
|
|
234
|
+
bool only when supplying a hand-built gate via ``authenticate``.
|
|
227
235
|
oauth_resource_metadata: Optional `OAuthResourceMetadata` for
|
|
228
236
|
RFC 9728 discovery endpoint.
|
|
229
237
|
otel_config: Optional OpenTelemetry configuration. When provided,
|
|
@@ -259,6 +267,9 @@ def create_app(
|
|
|
259
267
|
if signing_key is None:
|
|
260
268
|
signing_key = os.urandom(32)
|
|
261
269
|
|
|
270
|
+
if proxy_proof_required is None:
|
|
271
|
+
proxy_proof_required = (os.environ.get("VGI_PROXY_PROOF_MODE") or "").strip().lower() == "require"
|
|
272
|
+
|
|
262
273
|
worker = worker_cls(quiet=True, log_level=log_level)
|
|
263
274
|
worker._vgi_tracer = VgiTracer.create(otel_config)
|
|
264
275
|
worker._signing_key = signing_key
|
|
@@ -271,6 +282,7 @@ def create_app(
|
|
|
271
282
|
cors_origins=cors_origins,
|
|
272
283
|
token_key=signing_key,
|
|
273
284
|
authenticate=authenticate,
|
|
285
|
+
proxy_proof_required=proxy_proof_required,
|
|
274
286
|
oauth_resource_metadata=oauth_resource_metadata,
|
|
275
287
|
otel_config=otel_config,
|
|
276
288
|
max_stream_response_bytes=max_stream_response_bytes,
|
|
@@ -353,12 +365,17 @@ def main() -> None:
|
|
|
353
365
|
) -> None:
|
|
354
366
|
env_debug = os.environ.get("VGI_WORKER_DEBUG", "").lower() in ("1", "true", "yes")
|
|
355
367
|
effective_debug = debug or env_debug
|
|
368
|
+
# VGI_WORKER_LOG_* overrides are applied inside configure_worker_logging,
|
|
369
|
+
# so every worker entry point honours them identically.
|
|
356
370
|
effective_level = configure_worker_logging(
|
|
357
371
|
debug=effective_debug,
|
|
358
372
|
log_level=log_level,
|
|
359
373
|
log_loggers=log_logger,
|
|
360
374
|
log_format=log_format,
|
|
361
375
|
)
|
|
376
|
+
# Before the worker class is imported, so module-import cost lands in
|
|
377
|
+
# the profile too — for many workers that is the bulk of startup.
|
|
378
|
+
maybe_start_profile()
|
|
362
379
|
|
|
363
380
|
# Resolve env var overrides
|
|
364
381
|
describe = _resolve_describe(describe)
|
|
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
|
|
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
|
|
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
|