vgi-python 0.8.4__tar.gz → 0.8.6__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.8.4 → vgi_python-0.8.6}/PKG-INFO +1 -1
- {vgi_python-0.8.4 → vgi_python-0.8.6}/pyproject.toml +1 -1
- {vgi_python-0.8.4 → vgi_python-0.8.6}/tests/catalog/test_serialization.py +134 -0
- {vgi_python-0.8.4 → vgi_python-0.8.6}/tests/test_argument_spec.py +48 -0
- {vgi_python-0.8.4 → vgi_python-0.8.6}/uv.lock +1 -1
- {vgi_python-0.8.4 → vgi_python-0.8.6}/vgi/_test_fixtures/catalog.py +2 -0
- {vgi_python-0.8.4 → vgi_python-0.8.6}/vgi/_test_fixtures/worker.py +10 -0
- {vgi_python-0.8.4 → vgi_python-0.8.6}/vgi/argument_spec.py +105 -0
- {vgi_python-0.8.4 → vgi_python-0.8.6}/vgi/catalog/catalog_interface.py +28 -1
- {vgi_python-0.8.4 → vgi_python-0.8.6}/vgi/catalog/descriptors.py +20 -1
- {vgi_python-0.8.4 → vgi_python-0.8.6}/vgi/client/catalog_mixin.py +6 -0
- {vgi_python-0.8.4 → vgi_python-0.8.6}/vgi/codegen/go_schemas.py +10 -4
- {vgi_python-0.8.4 → vgi_python-0.8.6}/vgi/protocol.py +8 -0
- {vgi_python-0.8.4 → vgi_python-0.8.6}/vgi/worker.py +1 -0
- {vgi_python-0.8.4 → vgi_python-0.8.6}/.gitattributes +0 -0
- {vgi_python-0.8.4 → vgi_python-0.8.6}/.github/dependabot.yml +0 -0
- {vgi_python-0.8.4 → vgi_python-0.8.6}/.github/styles/config/vocabularies/VGI/accept.txt +0 -0
- {vgi_python-0.8.4 → vgi_python-0.8.6}/.github/workflows/ci.yml +0 -0
- {vgi_python-0.8.4 → vgi_python-0.8.6}/.github/workflows/docs.yml +0 -0
- {vgi_python-0.8.4 → vgi_python-0.8.6}/.github/workflows/integration.yml +0 -0
- {vgi_python-0.8.4 → vgi_python-0.8.6}/.github/workflows/release.yml +0 -0
- {vgi_python-0.8.4 → vgi_python-0.8.6}/.gitignore +0 -0
- {vgi_python-0.8.4 → vgi_python-0.8.6}/.python-version +0 -0
- {vgi_python-0.8.4 → vgi_python-0.8.6}/.vale.ini +0 -0
- {vgi_python-0.8.4 → vgi_python-0.8.6}/CLAUDE.md +0 -0
- {vgi_python-0.8.4 → vgi_python-0.8.6}/DOCS_ACCEPTANCE_CRITERIA.md +0 -0
- {vgi_python-0.8.4 → vgi_python-0.8.6}/DOCS_REVIEW_RUBRIC.md +0 -0
- {vgi_python-0.8.4 → vgi_python-0.8.6}/DOCS_USABILITY_TEST.md +0 -0
- {vgi_python-0.8.4 → vgi_python-0.8.6}/LICENSE +0 -0
- {vgi_python-0.8.4 → vgi_python-0.8.6}/README.md +0 -0
- {vgi_python-0.8.4 → vgi_python-0.8.6}/SECURITY.md +0 -0
- {vgi_python-0.8.4 → vgi_python-0.8.6}/ci/README.md +0 -0
- {vgi_python-0.8.4 → vgi_python-0.8.6}/ci/preprocess-require.awk +0 -0
- {vgi_python-0.8.4 → vgi_python-0.8.6}/ci/run-integration.sh +0 -0
- {vgi_python-0.8.4 → vgi_python-0.8.6}/dist-vgi/.gitignore +0 -0
- {vgi_python-0.8.4 → vgi_python-0.8.6}/docs/aggregate-functions.md +0 -0
- {vgi_python-0.8.4 → vgi_python-0.8.6}/docs/api/arguments.md +0 -0
- {vgi_python-0.8.4 → vgi_python-0.8.6}/docs/api/auth.md +0 -0
- {vgi_python-0.8.4 → vgi_python-0.8.6}/docs/api/catalogs.md +0 -0
- {vgi_python-0.8.4 → vgi_python-0.8.6}/docs/api/client.md +0 -0
- {vgi_python-0.8.4 → vgi_python-0.8.6}/docs/api/exceptions.md +0 -0
- {vgi_python-0.8.4 → vgi_python-0.8.6}/docs/api/filters.md +0 -0
- {vgi_python-0.8.4 → vgi_python-0.8.6}/docs/api/functions.md +0 -0
- {vgi_python-0.8.4 → vgi_python-0.8.6}/docs/api/http.md +0 -0
- {vgi_python-0.8.4 → vgi_python-0.8.6}/docs/api/index.md +0 -0
- {vgi_python-0.8.4 → vgi_python-0.8.6}/docs/api/metadata.md +0 -0
- {vgi_python-0.8.4 → vgi_python-0.8.6}/docs/api/observability.md +0 -0
- {vgi_python-0.8.4 → vgi_python-0.8.6}/docs/api/storage.md +0 -0
- {vgi_python-0.8.4 → vgi_python-0.8.6}/docs/api/transactor.md +0 -0
- {vgi_python-0.8.4 → vgi_python-0.8.6}/docs/api/worker.md +0 -0
- {vgi_python-0.8.4 → vgi_python-0.8.6}/docs/argument-serialization.md +0 -0
- {vgi_python-0.8.4 → vgi_python-0.8.6}/docs/assets/apple-touch-icon.png +0 -0
- {vgi_python-0.8.4 → vgi_python-0.8.6}/docs/assets/favicon-16x16.png +0 -0
- {vgi_python-0.8.4 → vgi_python-0.8.6}/docs/assets/favicon-32x32.png +0 -0
- {vgi_python-0.8.4 → vgi_python-0.8.6}/docs/assets/favicon.ico +0 -0
- {vgi_python-0.8.4 → vgi_python-0.8.6}/docs/assets/kinds/aggregate.svg +0 -0
- {vgi_python-0.8.4 → vgi_python-0.8.6}/docs/assets/kinds/buffering.svg +0 -0
- {vgi_python-0.8.4 → vgi_python-0.8.6}/docs/assets/kinds/scalar.svg +0 -0
- {vgi_python-0.8.4 → vgi_python-0.8.6}/docs/assets/kinds/table-in-out.svg +0 -0
- {vgi_python-0.8.4 → vgi_python-0.8.6}/docs/assets/kinds/table.svg +0 -0
- {vgi_python-0.8.4 → vgi_python-0.8.6}/docs/assets/logo.png +0 -0
- {vgi_python-0.8.4 → vgi_python-0.8.6}/docs/assets/social-card.png +0 -0
- {vgi_python-0.8.4 → vgi_python-0.8.6}/docs/authentication.md +0 -0
- {vgi_python-0.8.4 → vgi_python-0.8.6}/docs/catalog-interface.md +0 -0
- {vgi_python-0.8.4 → vgi_python-0.8.6}/docs/cli.md +0 -0
- {vgi_python-0.8.4 → vgi_python-0.8.6}/docs/column-statistics.md +0 -0
- {vgi_python-0.8.4 → vgi_python-0.8.6}/docs/concepts/index.md +0 -0
- {vgi_python-0.8.4 → vgi_python-0.8.6}/docs/contributing-docs.md +0 -0
- {vgi_python-0.8.4 → vgi_python-0.8.6}/docs/filter-pushdown.md +0 -0
- {vgi_python-0.8.4 → vgi_python-0.8.6}/docs/generator-api.md +0 -0
- {vgi_python-0.8.4 → vgi_python-0.8.6}/docs/how-to/catalogs.md +0 -0
- {vgi_python-0.8.4 → vgi_python-0.8.6}/docs/how-to/function-patterns.md +0 -0
- {vgi_python-0.8.4 → vgi_python-0.8.6}/docs/how-to/http-auth.md +0 -0
- {vgi_python-0.8.4 → vgi_python-0.8.6}/docs/how-to/index.md +0 -0
- {vgi_python-0.8.4 → vgi_python-0.8.6}/docs/how-to/pushdown-and-statistics.md +0 -0
- {vgi_python-0.8.4 → vgi_python-0.8.6}/docs/how-to/state-storage.md +0 -0
- {vgi_python-0.8.4 → vgi_python-0.8.6}/docs/index.md +0 -0
- {vgi_python-0.8.4 → vgi_python-0.8.6}/docs/lifecycle.md +0 -0
- {vgi_python-0.8.4 → vgi_python-0.8.6}/docs/metadata.md +0 -0
- {vgi_python-0.8.4 → vgi_python-0.8.6}/docs/overrides/main.html +0 -0
- {vgi_python-0.8.4 → vgi_python-0.8.6}/docs/robots.txt +0 -0
- {vgi_python-0.8.4 → vgi_python-0.8.6}/docs/shared-storage.md +0 -0
- {vgi_python-0.8.4 → vgi_python-0.8.6}/docs/stylesheets/extra.css +0 -0
- {vgi_python-0.8.4 → vgi_python-0.8.6}/docs/tutorial/index.md +0 -0
- {vgi_python-0.8.4 → vgi_python-0.8.6}/docs/tutorial/scalar.md +0 -0
- {vgi_python-0.8.4 → vgi_python-0.8.6}/docs/tutorial/table.md +0 -0
- {vgi_python-0.8.4 → vgi_python-0.8.6}/docs/vgi-logo.png +0 -0
- {vgi_python-0.8.4 → vgi_python-0.8.6}/examples/calc_scalar_worker.py +0 -0
- {vgi_python-0.8.4 → vgi_python-0.8.6}/examples/calc_worker.py +0 -0
- {vgi_python-0.8.4 → vgi_python-0.8.6}/examples/filter_worker.py +0 -0
- {vgi_python-0.8.4 → vgi_python-0.8.6}/examples/greeting_scalar_worker.py +0 -0
- {vgi_python-0.8.4 → vgi_python-0.8.6}/examples/row_count_worker.py +0 -0
- {vgi_python-0.8.4 → vgi_python-0.8.6}/examples/series_streaming_worker.py +0 -0
- {vgi_python-0.8.4 → vgi_python-0.8.6}/examples/sum_worker.py +0 -0
- {vgi_python-0.8.4 → vgi_python-0.8.6}/mkdocs.yml +0 -0
- {vgi_python-0.8.4 → vgi_python-0.8.6}/packages/vgi-fixtures/LICENSE +0 -0
- {vgi_python-0.8.4 → vgi_python-0.8.6}/packages/vgi-fixtures/README.md +0 -0
- {vgi_python-0.8.4 → vgi_python-0.8.6}/packages/vgi-fixtures/pyproject.toml +0 -0
- {vgi_python-0.8.4 → vgi_python-0.8.6}/scripts/measure_startup.py +0 -0
- {vgi_python-0.8.4 → vgi_python-0.8.6}/scripts/run_all_tests.sh +0 -0
- {vgi_python-0.8.4 → vgi_python-0.8.6}/test-data/generate.sh +0 -0
- {vgi_python-0.8.4 → vgi_python-0.8.6}/tests/__init__.py +0 -0
- {vgi_python-0.8.4 → vgi_python-0.8.6}/tests/_http_fixtures.py +0 -0
- {vgi_python-0.8.4 → vgi_python-0.8.6}/tests/catalog/__init__.py +0 -0
- {vgi_python-0.8.4 → vgi_python-0.8.6}/tests/catalog/test_catalog_interface.py +0 -0
- {vgi_python-0.8.4 → vgi_python-0.8.6}/tests/catalog/test_client_catalog.py +0 -0
- {vgi_python-0.8.4 → vgi_python-0.8.6}/tests/catalog/test_column_statistics.py +0 -0
- {vgi_python-0.8.4 → vgi_python-0.8.6}/tests/catalog/test_declarative.py +0 -0
- {vgi_python-0.8.4 → vgi_python-0.8.6}/tests/catalog/test_example_worker_catalog.py +0 -0
- {vgi_python-0.8.4 → vgi_python-0.8.6}/tests/catalog/test_integration.py +0 -0
- {vgi_python-0.8.4 → vgi_python-0.8.6}/tests/catalog/test_required_field_filter_paths.py +0 -0
- {vgi_python-0.8.4 → vgi_python-0.8.6}/tests/catalog/test_scan_branches.py +0 -0
- {vgi_python-0.8.4 → vgi_python-0.8.6}/tests/catalog/test_setting.py +0 -0
- {vgi_python-0.8.4 → vgi_python-0.8.6}/tests/catalog/test_storage.py +0 -0
- {vgi_python-0.8.4 → vgi_python-0.8.6}/tests/catalog/test_time_travel.py +0 -0
- {vgi_python-0.8.4 → vgi_python-0.8.6}/tests/catalog/test_writable_table.py +0 -0
- {vgi_python-0.8.4 → vgi_python-0.8.6}/tests/client/__init__.py +0 -0
- {vgi_python-0.8.4 → vgi_python-0.8.6}/tests/client/test_broken_pipe.py +0 -0
- {vgi_python-0.8.4 → vgi_python-0.8.6}/tests/client/test_cli.py +0 -0
- {vgi_python-0.8.4 → vgi_python-0.8.6}/tests/client/test_cli_catalog_functions.py +0 -0
- {vgi_python-0.8.4 → vgi_python-0.8.6}/tests/client/test_worker_debug.py +0 -0
- {vgi_python-0.8.4 → vgi_python-0.8.6}/tests/conformance/__init__.py +0 -0
- {vgi_python-0.8.4 → vgi_python-0.8.6}/tests/conformance/_stub.py +0 -0
- {vgi_python-0.8.4 → vgi_python-0.8.6}/tests/conformance/conftest.py +0 -0
- {vgi_python-0.8.4 → vgi_python-0.8.6}/tests/conformance/test_accumulate.py +0 -0
- {vgi_python-0.8.4 → vgi_python-0.8.6}/tests/conformance/test_aggregate.py +0 -0
- {vgi_python-0.8.4 → vgi_python-0.8.6}/tests/conformance/test_attach.py +0 -0
- {vgi_python-0.8.4 → vgi_python-0.8.6}/tests/conformance/test_bearer_auth.py +0 -0
- {vgi_python-0.8.4 → vgi_python-0.8.6}/tests/conformance/test_directory_parity.py +0 -0
- {vgi_python-0.8.4 → vgi_python-0.8.6}/tests/conformance/test_function_inventory.py +0 -0
- {vgi_python-0.8.4 → vgi_python-0.8.6}/tests/conformance/test_http_client.py +0 -0
- {vgi_python-0.8.4 → vgi_python-0.8.6}/tests/conformance/test_http_external_location.py +0 -0
- {vgi_python-0.8.4 → vgi_python-0.8.6}/tests/conformance/test_http_upload_url.py +0 -0
- {vgi_python-0.8.4 → vgi_python-0.8.6}/tests/conformance/test_macro.py +0 -0
- {vgi_python-0.8.4 → vgi_python-0.8.6}/tests/conformance/test_overload.py +0 -0
- {vgi_python-0.8.4 → vgi_python-0.8.6}/tests/conformance/test_protocol_inventory.py +0 -0
- {vgi_python-0.8.4 → vgi_python-0.8.6}/tests/conformance/test_protocol_version.py +0 -0
- {vgi_python-0.8.4 → vgi_python-0.8.6}/tests/conformance/test_resumable_scan.py +0 -0
- {vgi_python-0.8.4 → vgi_python-0.8.6}/tests/conformance/test_scalar.py +0 -0
- {vgi_python-0.8.4 → vgi_python-0.8.6}/tests/conformance/test_scalar_attach_opaque_data.py +0 -0
- {vgi_python-0.8.4 → vgi_python-0.8.6}/tests/conformance/test_secret.py +0 -0
- {vgi_python-0.8.4 → vgi_python-0.8.6}/tests/conformance/test_settings.py +0 -0
- {vgi_python-0.8.4 → vgi_python-0.8.6}/tests/conformance/test_table.py +0 -0
- {vgi_python-0.8.4 → vgi_python-0.8.6}/tests/conformance/test_table_in_out.py +0 -0
- {vgi_python-0.8.4 → vgi_python-0.8.6}/tests/conformance/test_view.py +0 -0
- {vgi_python-0.8.4 → vgi_python-0.8.6}/tests/conformance/test_writable.py +0 -0
- {vgi_python-0.8.4 → vgi_python-0.8.6}/tests/conftest.py +0 -0
- {vgi_python-0.8.4 → vgi_python-0.8.6}/tests/scalar/__init__.py +0 -0
- {vgi_python-0.8.4 → vgi_python-0.8.6}/tests/scalar/test_bernoulli_function.py +0 -0
- {vgi_python-0.8.4 → vgi_python-0.8.6}/tests/scalar/test_binary_packet_function.py +0 -0
- {vgi_python-0.8.4 → vgi_python-0.8.6}/tests/scalar/test_client.py +0 -0
- {vgi_python-0.8.4 → vgi_python-0.8.6}/tests/scalar/test_conditional_message_function.py +0 -0
- {vgi_python-0.8.4 → vgi_python-0.8.6}/tests/scalar/test_hash_seed_function.py +0 -0
- {vgi_python-0.8.4 → vgi_python-0.8.6}/tests/scalar/test_multiply_by_setting_function.py +0 -0
- {vgi_python-0.8.4 → vgi_python-0.8.6}/tests/scalar/test_multiply_function.py +0 -0
- {vgi_python-0.8.4 → vgi_python-0.8.6}/tests/scalar/test_random_bytes_function.py +0 -0
- {vgi_python-0.8.4 → vgi_python-0.8.6}/tests/scalar/test_return_secret_value_function.py +0 -0
- {vgi_python-0.8.4 → vgi_python-0.8.6}/tests/table/__init__.py +0 -0
- {vgi_python-0.8.4 → vgi_python-0.8.6}/tests/table/generator/__init__.py +0 -0
- {vgi_python-0.8.4 → vgi_python-0.8.6}/tests/table/generator/test_constant_columns_function.py +0 -0
- {vgi_python-0.8.4 → vgi_python-0.8.6}/tests/table/generator/test_double_sequence_function.py +0 -0
- {vgi_python-0.8.4 → vgi_python-0.8.6}/tests/table/generator/test_exception_function.py +0 -0
- {vgi_python-0.8.4 → vgi_python-0.8.6}/tests/table/generator/test_filter_echo_function.py +0 -0
- {vgi_python-0.8.4 → vgi_python-0.8.6}/tests/table/generator/test_logging_function.py +0 -0
- {vgi_python-0.8.4 → vgi_python-0.8.6}/tests/table/generator/test_nested_sequence_function.py +0 -0
- {vgi_python-0.8.4 → vgi_python-0.8.6}/tests/table/generator/test_partitioned_function.py +0 -0
- {vgi_python-0.8.4 → vgi_python-0.8.6}/tests/table/generator/test_projected_data_function.py +0 -0
- {vgi_python-0.8.4 → vgi_python-0.8.6}/tests/table/generator/test_sequence_function.py +0 -0
- {vgi_python-0.8.4 → vgi_python-0.8.6}/tests/table/generator/test_settings_function.py +0 -0
- {vgi_python-0.8.4 → vgi_python-0.8.6}/tests/table/generator/test_struct_settings_function.py +0 -0
- {vgi_python-0.8.4 → vgi_python-0.8.6}/tests/table/generator/test_ten_thousand_function.py +0 -0
- {vgi_python-0.8.4 → vgi_python-0.8.6}/tests/table_in_out/__init__.py +0 -0
- {vgi_python-0.8.4 → vgi_python-0.8.6}/tests/table_in_out/generator/__init__.py +0 -0
- {vgi_python-0.8.4 → vgi_python-0.8.6}/tests/table_in_out/generator/test_buffer_input_function.py +0 -0
- {vgi_python-0.8.4 → vgi_python-0.8.6}/tests/table_in_out/generator/test_echo_function.py +0 -0
- {vgi_python-0.8.4 → vgi_python-0.8.6}/tests/table_in_out/generator/test_exception_functions.py +0 -0
- {vgi_python-0.8.4 → vgi_python-0.8.6}/tests/table_in_out/generator/test_filter_by_setting_function.py +0 -0
- {vgi_python-0.8.4 → vgi_python-0.8.6}/tests/table_in_out/generator/test_repeat_inputs_function.py +0 -0
- {vgi_python-0.8.4 → vgi_python-0.8.6}/tests/table_in_out/generator/test_sum_all_columns_function.py +0 -0
- {vgi_python-0.8.4 → vgi_python-0.8.6}/tests/table_in_out/test_client.py +0 -0
- {vgi_python-0.8.4 → vgi_python-0.8.6}/tests/test_access_log_audit.py +0 -0
- {vgi_python-0.8.4 → vgi_python-0.8.6}/tests/test_aggregate_function.py +0 -0
- {vgi_python-0.8.4 → vgi_python-0.8.6}/tests/test_auth.py +0 -0
- {vgi_python-0.8.4 → vgi_python-0.8.6}/tests/test_bind_exceptions.py +0 -0
- {vgi_python-0.8.4 → vgi_python-0.8.6}/tests/test_bind_request_at_clause.py +0 -0
- {vgi_python-0.8.4 → vgi_python-0.8.6}/tests/test_bound_storage_conformance.py +0 -0
- {vgi_python-0.8.4 → vgi_python-0.8.6}/tests/test_catalog_auth_binding.py +0 -0
- {vgi_python-0.8.4 → vgi_python-0.8.6}/tests/test_docstrings.py +0 -0
- {vgi_python-0.8.4 → vgi_python-0.8.6}/tests/test_documentation_examples.py +0 -0
- {vgi_python-0.8.4 → vgi_python-0.8.6}/tests/test_example_function_arg_types.py +0 -0
- {vgi_python-0.8.4 → vgi_python-0.8.6}/tests/test_examples_workers.py +0 -0
- {vgi_python-0.8.4 → vgi_python-0.8.6}/tests/test_exception_handling.py +0 -0
- {vgi_python-0.8.4 → vgi_python-0.8.6}/tests/test_exceptions.py +0 -0
- {vgi_python-0.8.4 → vgi_python-0.8.6}/tests/test_filter_pushdown.py +0 -0
- {vgi_python-0.8.4 → vgi_python-0.8.6}/tests/test_filter_pushdown_extension.py +0 -0
- {vgi_python-0.8.4 → vgi_python-0.8.6}/tests/test_function_storage.py +0 -0
- {vgi_python-0.8.4 → vgi_python-0.8.6}/tests/test_function_storage_azure_sql.py +0 -0
- {vgi_python-0.8.4 → vgi_python-0.8.6}/tests/test_function_storage_cf_do.py +0 -0
- {vgi_python-0.8.4 → vgi_python-0.8.6}/tests/test_function_storage_cf_do_integration.py +0 -0
- {vgi_python-0.8.4 → vgi_python-0.8.6}/tests/test_function_storage_conformance.py +0 -0
- {vgi_python-0.8.4 → vgi_python-0.8.6}/tests/test_generated_cpp_constants.py +0 -0
- {vgi_python-0.8.4 → vgi_python-0.8.6}/tests/test_generated_cpp_protocol_version.py +0 -0
- {vgi_python-0.8.4 → vgi_python-0.8.6}/tests/test_generated_cpp_request_builders.py +0 -0
- {vgi_python-0.8.4 → vgi_python-0.8.6}/tests/test_generated_cpp_schemas.py +0 -0
- {vgi_python-0.8.4 → vgi_python-0.8.6}/tests/test_generated_cpp_secret.py +0 -0
- {vgi_python-0.8.4 → vgi_python-0.8.6}/tests/test_generated_go_schemas.py +0 -0
- {vgi_python-0.8.4 → vgi_python-0.8.6}/tests/test_generated_protocol_version.py +0 -0
- {vgi_python-0.8.4 → vgi_python-0.8.6}/tests/test_generated_schemas_cross_lang.py +0 -0
- {vgi_python-0.8.4 → vgi_python-0.8.6}/tests/test_generated_ts_client.py +0 -0
- {vgi_python-0.8.4 → vgi_python-0.8.6}/tests/test_generated_ts_schemas.py +0 -0
- {vgi_python-0.8.4 → vgi_python-0.8.6}/tests/test_http_demo_storage.py +0 -0
- {vgi_python-0.8.4 → vgi_python-0.8.6}/tests/test_http_s3_offload_input.py +0 -0
- {vgi_python-0.8.4 → vgi_python-0.8.6}/tests/test_http_s3_offload_output.py +0 -0
- {vgi_python-0.8.4 → vgi_python-0.8.6}/tests/test_metadata.py +0 -0
- {vgi_python-0.8.4 → vgi_python-0.8.6}/tests/test_mypy_consolidated.py +0 -0
- {vgi_python-0.8.4 → vgi_python-0.8.6}/tests/test_nest_tensor.py +0 -0
- {vgi_python-0.8.4 → vgi_python-0.8.6}/tests/test_otel.py +0 -0
- {vgi_python-0.8.4 → vgi_python-0.8.6}/tests/test_projection_enforcement.py +0 -0
- {vgi_python-0.8.4 → vgi_python-0.8.6}/tests/test_projection_repro.py +0 -0
- {vgi_python-0.8.4 → vgi_python-0.8.6}/tests/test_protocol_classes.py +0 -0
- {vgi_python-0.8.4 → vgi_python-0.8.6}/tests/test_schema_utils.py +0 -0
- {vgi_python-0.8.4 → vgi_python-0.8.6}/tests/test_serve.py +0 -0
- {vgi_python-0.8.4 → vgi_python-0.8.6}/tests/test_setting_secret_annotations.py +0 -0
- {vgi_python-0.8.4 → vgi_python-0.8.6}/tests/test_table_buffering_function.py +0 -0
- {vgi_python-0.8.4 → vgi_python-0.8.6}/tests/test_table_function_dynamic_to_string.py +0 -0
- {vgi_python-0.8.4 → vgi_python-0.8.6}/tests/test_type_bounds.py +0 -0
- {vgi_python-0.8.4 → vgi_python-0.8.6}/tests/test_union_argument.py +0 -0
- {vgi_python-0.8.4 → vgi_python-0.8.6}/tests/test_worker.py +0 -0
- {vgi_python-0.8.4 → vgi_python-0.8.6}/tests/test_worker_cli.py +0 -0
- {vgi_python-0.8.4 → vgi_python-0.8.6}/tests/test_worker_page.py +0 -0
- {vgi_python-0.8.4 → vgi_python-0.8.6}/tests/transactor/__init__.py +0 -0
- {vgi_python-0.8.4 → vgi_python-0.8.6}/tests/transactor/test_transactor.py +0 -0
- {vgi_python-0.8.4 → vgi_python-0.8.6}/vgi/__init__.py +0 -0
- {vgi_python-0.8.4 → vgi_python-0.8.6}/vgi/_duckdb.py +0 -0
- {vgi_python-0.8.4 → vgi_python-0.8.6}/vgi/_storage_profile.py +0 -0
- {vgi_python-0.8.4 → vgi_python-0.8.6}/vgi/_test_fixtures/__init__.py +0 -0
- {vgi_python-0.8.4 → vgi_python-0.8.6}/vgi/_test_fixtures/accumulate/__init__.py +0 -0
- {vgi_python-0.8.4 → vgi_python-0.8.6}/vgi/_test_fixtures/accumulate/worker.py +0 -0
- {vgi_python-0.8.4 → vgi_python-0.8.6}/vgi/_test_fixtures/aggregate/__init__.py +0 -0
- {vgi_python-0.8.4 → vgi_python-0.8.6}/vgi/_test_fixtures/aggregate/_common.py +0 -0
- {vgi_python-0.8.4 → vgi_python-0.8.6}/vgi/_test_fixtures/aggregate/basic.py +0 -0
- {vgi_python-0.8.4 → vgi_python-0.8.6}/vgi/_test_fixtures/aggregate/dynamic.py +0 -0
- {vgi_python-0.8.4 → vgi_python-0.8.6}/vgi/_test_fixtures/aggregate/generic.py +0 -0
- {vgi_python-0.8.4 → vgi_python-0.8.6}/vgi/_test_fixtures/aggregate/listagg.py +0 -0
- {vgi_python-0.8.4 → vgi_python-0.8.6}/vgi/_test_fixtures/aggregate/percentile.py +0 -0
- {vgi_python-0.8.4 → vgi_python-0.8.6}/vgi/_test_fixtures/aggregate/streaming.py +0 -0
- {vgi_python-0.8.4 → vgi_python-0.8.6}/vgi/_test_fixtures/aggregate/varargs.py +0 -0
- {vgi_python-0.8.4 → vgi_python-0.8.6}/vgi/_test_fixtures/aggregate/window.py +0 -0
- {vgi_python-0.8.4 → vgi_python-0.8.6}/vgi/_test_fixtures/attach_options.py +0 -0
- {vgi_python-0.8.4 → vgi_python-0.8.6}/vgi/_test_fixtures/bad_enum.py +0 -0
- {vgi_python-0.8.4 → vgi_python-0.8.6}/vgi/_test_fixtures/bad_protocol.py +0 -0
- {vgi_python-0.8.4 → vgi_python-0.8.6}/vgi/_test_fixtures/cancellable.py +0 -0
- {vgi_python-0.8.4 → vgi_python-0.8.6}/vgi/_test_fixtures/http_server.py +0 -0
- {vgi_python-0.8.4 → vgi_python-0.8.6}/vgi/_test_fixtures/narrow_bind/__init__.py +0 -0
- {vgi_python-0.8.4 → vgi_python-0.8.6}/vgi/_test_fixtures/narrow_bind/worker.py +0 -0
- {vgi_python-0.8.4 → vgi_python-0.8.6}/vgi/_test_fixtures/nest_tensor.py +0 -0
- {vgi_python-0.8.4 → vgi_python-0.8.6}/vgi/_test_fixtures/orchard_catalog.py +0 -0
- {vgi_python-0.8.4 → vgi_python-0.8.6}/vgi/_test_fixtures/projection_repro/__init__.py +0 -0
- {vgi_python-0.8.4 → vgi_python-0.8.6}/vgi/_test_fixtures/projection_repro/worker.py +0 -0
- {vgi_python-0.8.4 → vgi_python-0.8.6}/vgi/_test_fixtures/scalar/__init__.py +0 -0
- {vgi_python-0.8.4 → vgi_python-0.8.6}/vgi/_test_fixtures/scalar/_common.py +0 -0
- {vgi_python-0.8.4 → vgi_python-0.8.6}/vgi/_test_fixtures/scalar/arithmetic.py +0 -0
- {vgi_python-0.8.4 → vgi_python-0.8.6}/vgi/_test_fixtures/scalar/binary.py +0 -0
- {vgi_python-0.8.4 → vgi_python-0.8.6}/vgi/_test_fixtures/scalar/formatting.py +0 -0
- {vgi_python-0.8.4 → vgi_python-0.8.6}/vgi/_test_fixtures/scalar/geo.py +0 -0
- {vgi_python-0.8.4 → vgi_python-0.8.6}/vgi/_test_fixtures/scalar/null_handling.py +0 -0
- {vgi_python-0.8.4 → vgi_python-0.8.6}/vgi/_test_fixtures/scalar/random_demo.py +0 -0
- {vgi_python-0.8.4 → vgi_python-0.8.6}/vgi/_test_fixtures/scalar/settings_secrets.py +0 -0
- {vgi_python-0.8.4 → vgi_python-0.8.6}/vgi/_test_fixtures/scalar/type_info.py +0 -0
- {vgi_python-0.8.4 → vgi_python-0.8.6}/vgi/_test_fixtures/schema_reconcile/__init__.py +0 -0
- {vgi_python-0.8.4 → vgi_python-0.8.6}/vgi/_test_fixtures/schema_reconcile/worker.py +0 -0
- {vgi_python-0.8.4 → vgi_python-0.8.6}/vgi/_test_fixtures/simple_writable.py +0 -0
- {vgi_python-0.8.4 → vgi_python-0.8.6}/vgi/_test_fixtures/table/__init__.py +0 -0
- {vgi_python-0.8.4 → vgi_python-0.8.6}/vgi/_test_fixtures/table/_common.py +0 -0
- {vgi_python-0.8.4 → vgi_python-0.8.6}/vgi/_test_fixtures/table/batch_index.py +0 -0
- {vgi_python-0.8.4 → vgi_python-0.8.6}/vgi/_test_fixtures/table/batch_index_broken.py +0 -0
- {vgi_python-0.8.4 → vgi_python-0.8.6}/vgi/_test_fixtures/table/catalog_scans.py +0 -0
- {vgi_python-0.8.4 → vgi_python-0.8.6}/vgi/_test_fixtures/table/filters.py +0 -0
- {vgi_python-0.8.4 → vgi_python-0.8.6}/vgi/_test_fixtures/table/late_materialization.py +0 -0
- {vgi_python-0.8.4 → vgi_python-0.8.6}/vgi/_test_fixtures/table/make_series.py +0 -0
- {vgi_python-0.8.4 → vgi_python-0.8.6}/vgi/_test_fixtures/table/misc.py +0 -0
- {vgi_python-0.8.4 → vgi_python-0.8.6}/vgi/_test_fixtures/table/order_modes.py +0 -0
- {vgi_python-0.8.4 → vgi_python-0.8.6}/vgi/_test_fixtures/table/pairs.py +0 -0
- {vgi_python-0.8.4 → vgi_python-0.8.6}/vgi/_test_fixtures/table/partition_columns.py +0 -0
- {vgi_python-0.8.4 → vgi_python-0.8.6}/vgi/_test_fixtures/table/partition_columns_broken.py +0 -0
- {vgi_python-0.8.4 → vgi_python-0.8.6}/vgi/_test_fixtures/table/profiling_example.py +0 -0
- {vgi_python-0.8.4 → vgi_python-0.8.6}/vgi/_test_fixtures/table/required_filters.py +0 -0
- {vgi_python-0.8.4 → vgi_python-0.8.6}/vgi/_test_fixtures/table/sequence.py +0 -0
- {vgi_python-0.8.4 → vgi_python-0.8.6}/vgi/_test_fixtures/table/settings.py +0 -0
- {vgi_python-0.8.4 → vgi_python-0.8.6}/vgi/_test_fixtures/table/transaction_storage.py +0 -0
- {vgi_python-0.8.4 → vgi_python-0.8.6}/vgi/_test_fixtures/table/tt_pushdown.py +0 -0
- {vgi_python-0.8.4 → vgi_python-0.8.6}/vgi/_test_fixtures/table/typed_probe.py +0 -0
- {vgi_python-0.8.4 → vgi_python-0.8.6}/vgi/_test_fixtures/table/versioned.py +0 -0
- {vgi_python-0.8.4 → vgi_python-0.8.6}/vgi/_test_fixtures/table_in_out.py +0 -0
- {vgi_python-0.8.4 → vgi_python-0.8.6}/vgi/_test_fixtures/versioned.py +0 -0
- {vgi_python-0.8.4 → vgi_python-0.8.6}/vgi/_test_fixtures/versioned_tables.py +0 -0
- {vgi_python-0.8.4 → vgi_python-0.8.6}/vgi/_test_fixtures/writable/__init__.py +0 -0
- {vgi_python-0.8.4 → vgi_python-0.8.6}/vgi/_test_fixtures/writable/generic.py +0 -0
- {vgi_python-0.8.4 → vgi_python-0.8.6}/vgi/_test_fixtures/writable/table.py +0 -0
- {vgi_python-0.8.4 → vgi_python-0.8.6}/vgi/_test_fixtures/writable/worker.py +0 -0
- {vgi_python-0.8.4 → vgi_python-0.8.6}/vgi/aggregate_function.py +0 -0
- {vgi_python-0.8.4 → vgi_python-0.8.6}/vgi/arguments.py +0 -0
- {vgi_python-0.8.4 → vgi_python-0.8.6}/vgi/auth.py +0 -0
- {vgi_python-0.8.4 → vgi_python-0.8.6}/vgi/catalog/__init__.py +0 -0
- {vgi_python-0.8.4 → vgi_python-0.8.6}/vgi/catalog/_descriptor_spec.py +0 -0
- {vgi_python-0.8.4 → vgi_python-0.8.6}/vgi/catalog/attach_option.py +0 -0
- {vgi_python-0.8.4 → vgi_python-0.8.6}/vgi/catalog/duckdb_statistics.py +0 -0
- {vgi_python-0.8.4 → vgi_python-0.8.6}/vgi/catalog/secret_type.py +0 -0
- {vgi_python-0.8.4 → vgi_python-0.8.6}/vgi/catalog/setting.py +0 -0
- {vgi_python-0.8.4 → vgi_python-0.8.6}/vgi/catalog/storage.py +0 -0
- {vgi_python-0.8.4 → vgi_python-0.8.6}/vgi/client/__init__.py +0 -0
- {vgi_python-0.8.4 → vgi_python-0.8.6}/vgi/client/cli.py +0 -0
- {vgi_python-0.8.4 → vgi_python-0.8.6}/vgi/client/cli_catalog.py +0 -0
- {vgi_python-0.8.4 → vgi_python-0.8.6}/vgi/client/cli_schema.py +0 -0
- {vgi_python-0.8.4 → vgi_python-0.8.6}/vgi/client/cli_table.py +0 -0
- {vgi_python-0.8.4 → vgi_python-0.8.6}/vgi/client/cli_transaction.py +0 -0
- {vgi_python-0.8.4 → vgi_python-0.8.6}/vgi/client/cli_utils.py +0 -0
- {vgi_python-0.8.4 → vgi_python-0.8.6}/vgi/client/cli_view.py +0 -0
- {vgi_python-0.8.4 → vgi_python-0.8.6}/vgi/client/client.py +0 -0
- {vgi_python-0.8.4 → vgi_python-0.8.6}/vgi/codegen/__init__.py +0 -0
- {vgi_python-0.8.4 → vgi_python-0.8.6}/vgi/codegen/_common.py +0 -0
- {vgi_python-0.8.4 → vgi_python-0.8.6}/vgi/codegen/cpp_constants.py +0 -0
- {vgi_python-0.8.4 → vgi_python-0.8.6}/vgi/codegen/cpp_protocol_version.py +0 -0
- {vgi_python-0.8.4 → vgi_python-0.8.6}/vgi/codegen/cpp_request_builders.py +0 -0
- {vgi_python-0.8.4 → vgi_python-0.8.6}/vgi/codegen/cpp_schemas.py +0 -0
- {vgi_python-0.8.4 → vgi_python-0.8.6}/vgi/codegen/cpp_secret_protocol_version.py +0 -0
- {vgi_python-0.8.4 → vgi_python-0.8.6}/vgi/codegen/cpp_secret_request_builders.py +0 -0
- {vgi_python-0.8.4 → vgi_python-0.8.6}/vgi/codegen/cpp_secret_schemas.py +0 -0
- {vgi_python-0.8.4 → vgi_python-0.8.6}/vgi/codegen/protocol_version.py +0 -0
- {vgi_python-0.8.4 → vgi_python-0.8.6}/vgi/codegen/ts_client.py +0 -0
- {vgi_python-0.8.4 → vgi_python-0.8.6}/vgi/codegen/ts_schemas.py +0 -0
- {vgi_python-0.8.4 → vgi_python-0.8.6}/vgi/exceptions.py +0 -0
- {vgi_python-0.8.4 → vgi_python-0.8.6}/vgi/function.py +0 -0
- {vgi_python-0.8.4 → vgi_python-0.8.6}/vgi/function_storage.py +0 -0
- {vgi_python-0.8.4 → vgi_python-0.8.6}/vgi/function_storage_azure_sql.py +0 -0
- {vgi_python-0.8.4 → vgi_python-0.8.6}/vgi/function_storage_cf_do.py +0 -0
- {vgi_python-0.8.4 → vgi_python-0.8.6}/vgi/http/__init__.py +0 -0
- {vgi_python-0.8.4 → vgi_python-0.8.6}/vgi/http/demo_storage.py +0 -0
- {vgi_python-0.8.4 → vgi_python-0.8.6}/vgi/http/worker_page.py +0 -0
- {vgi_python-0.8.4 → vgi_python-0.8.6}/vgi/invocation.py +0 -0
- {vgi_python-0.8.4 → vgi_python-0.8.6}/vgi/logging_config.py +0 -0
- {vgi_python-0.8.4 → vgi_python-0.8.6}/vgi/meta_worker.py +0 -0
- {vgi_python-0.8.4 → vgi_python-0.8.6}/vgi/metadata.py +0 -0
- {vgi_python-0.8.4 → vgi_python-0.8.6}/vgi/otel.py +0 -0
- {vgi_python-0.8.4 → vgi_python-0.8.6}/vgi/protocol_version.txt +0 -0
- {vgi_python-0.8.4 → vgi_python-0.8.6}/vgi/py.typed +0 -0
- {vgi_python-0.8.4 → vgi_python-0.8.6}/vgi/scalar_function.py +0 -0
- {vgi_python-0.8.4 → vgi_python-0.8.6}/vgi/schema_utils.py +0 -0
- {vgi_python-0.8.4 → vgi_python-0.8.6}/vgi/secret_protocol.py +0 -0
- {vgi_python-0.8.4 → vgi_python-0.8.6}/vgi/secret_service.py +0 -0
- {vgi_python-0.8.4 → vgi_python-0.8.6}/vgi/serve.py +0 -0
- {vgi_python-0.8.4 → vgi_python-0.8.6}/vgi/table_buffering_function.py +0 -0
- {vgi_python-0.8.4 → vgi_python-0.8.6}/vgi/table_filter_pushdown.py +0 -0
- {vgi_python-0.8.4 → vgi_python-0.8.6}/vgi/table_function.py +0 -0
- {vgi_python-0.8.4 → vgi_python-0.8.6}/vgi/table_in_out_function.py +0 -0
- {vgi_python-0.8.4 → vgi_python-0.8.6}/vgi/transactor/__init__.py +0 -0
- {vgi_python-0.8.4 → vgi_python-0.8.6}/vgi/transactor/_duckdb_compat.py +0 -0
- {vgi_python-0.8.4 → vgi_python-0.8.6}/vgi/transactor/client.py +0 -0
- {vgi_python-0.8.4 → vgi_python-0.8.6}/vgi/transactor/protocol.py +0 -0
- {vgi_python-0.8.4 → vgi_python-0.8.6}/vgi/transactor/server.py +0 -0
- {vgi_python-0.8.4 → vgi_python-0.8.6}/wrangler.jsonc +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: vgi-python
|
|
3
|
-
Version: 0.8.
|
|
3
|
+
Version: 0.8.6
|
|
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
|
|
@@ -615,6 +615,140 @@ class TestMacroInfoSerialization:
|
|
|
615
615
|
restored = MacroInfo.deserialize_from_batch(batch)
|
|
616
616
|
assert restored.macro_type == macro_type
|
|
617
617
|
|
|
618
|
+
def test_arguments_schema_round_trip(self) -> None:
|
|
619
|
+
"""arguments_schema carries vgi_doc per documented param; absent doc -> no key."""
|
|
620
|
+
from vgi.argument_spec import VGI_DOC_KEY, macro_arguments_schema, macro_parameter_docs_from_schema
|
|
621
|
+
|
|
622
|
+
defaults = pa.RecordBatch.from_pydict({"lo": pa.array([0], type=pa.int64())})
|
|
623
|
+
args = macro_arguments_schema(
|
|
624
|
+
parameters=["val", "lo", "hi"],
|
|
625
|
+
parameter_default_values=defaults,
|
|
626
|
+
parameter_docs={"val": "value to clamp", "hi": "upper bound"},
|
|
627
|
+
)
|
|
628
|
+
original = MacroInfo(
|
|
629
|
+
name="clamp",
|
|
630
|
+
schema_name="main",
|
|
631
|
+
macro_type=MacroType.SCALAR,
|
|
632
|
+
parameters=["val", "lo", "hi"],
|
|
633
|
+
parameter_default_values=defaults,
|
|
634
|
+
definition="GREATEST(lo, LEAST(hi, val))",
|
|
635
|
+
comment=None,
|
|
636
|
+
tags={},
|
|
637
|
+
arguments_schema=args,
|
|
638
|
+
)
|
|
639
|
+
serialized = original.serialize_to_bytes()
|
|
640
|
+
batch, _ = deserialize_record_batch(serialized)
|
|
641
|
+
restored = MacroInfo.deserialize_from_batch(batch)
|
|
642
|
+
|
|
643
|
+
assert restored.arguments_schema is not None
|
|
644
|
+
rs = restored.arguments_schema
|
|
645
|
+
# One field per parameter, in order.
|
|
646
|
+
assert rs.names == ["val", "lo", "hi"]
|
|
647
|
+
# Field type tracks the default value type when known, else null.
|
|
648
|
+
assert rs.field("lo").type == pa.int64()
|
|
649
|
+
assert rs.field("val").type == pa.null()
|
|
650
|
+
assert rs.field("hi").type == pa.null()
|
|
651
|
+
# Documented params carry vgi_doc; undocumented (lo) has no key.
|
|
652
|
+
assert (rs.field("val").metadata or {}).get(VGI_DOC_KEY) == b"value to clamp"
|
|
653
|
+
assert (rs.field("hi").metadata or {}).get(VGI_DOC_KEY) == b"upper bound"
|
|
654
|
+
assert VGI_DOC_KEY not in (rs.field("lo").metadata or {})
|
|
655
|
+
# Convenience extractor returns only documented params.
|
|
656
|
+
assert macro_parameter_docs_from_schema(rs) == {"val": "value to clamp", "hi": "upper bound"}
|
|
657
|
+
|
|
658
|
+
def test_none_arguments_schema(self) -> None:
|
|
659
|
+
"""arguments_schema defaults to None (older workers) and survives round-trip."""
|
|
660
|
+
original = MacroInfo(
|
|
661
|
+
name="simple",
|
|
662
|
+
schema_name="main",
|
|
663
|
+
macro_type=MacroType.SCALAR,
|
|
664
|
+
parameters=["x"],
|
|
665
|
+
definition="x",
|
|
666
|
+
comment=None,
|
|
667
|
+
tags={},
|
|
668
|
+
)
|
|
669
|
+
serialized = original.serialize_to_bytes()
|
|
670
|
+
batch, _ = deserialize_record_batch(serialized)
|
|
671
|
+
restored = MacroInfo.deserialize_from_batch(batch)
|
|
672
|
+
assert restored.arguments_schema is None
|
|
673
|
+
|
|
674
|
+
|
|
675
|
+
class TestMacroArgumentsSchemaWire:
|
|
676
|
+
"""Macro per-parameter docs flow over create/list wire types."""
|
|
677
|
+
|
|
678
|
+
def test_declarative_macro_to_info_carries_docs(self) -> None:
|
|
679
|
+
"""Declarative Macro.parameter_docs -> MacroInfo.arguments_schema vgi_doc."""
|
|
680
|
+
from vgi.argument_spec import macro_parameter_docs_from_schema
|
|
681
|
+
from vgi.catalog.descriptors import Macro
|
|
682
|
+
|
|
683
|
+
m = Macro(
|
|
684
|
+
name="clamp",
|
|
685
|
+
macro_type=MacroType.SCALAR,
|
|
686
|
+
parameters=["x", "lo", "hi"],
|
|
687
|
+
parameter_default_values=pa.RecordBatch.from_pydict(
|
|
688
|
+
{"lo": pa.array([0], type=pa.int64()), "hi": pa.array([100], type=pa.int64())}
|
|
689
|
+
),
|
|
690
|
+
parameter_docs={"x": "value to clamp"},
|
|
691
|
+
definition="GREATEST(lo, LEAST(hi, x))",
|
|
692
|
+
)
|
|
693
|
+
info = m.to_macro_info("main")
|
|
694
|
+
assert info.arguments_schema is not None
|
|
695
|
+
assert info.arguments_schema.names == ["x", "lo", "hi"]
|
|
696
|
+
assert macro_parameter_docs_from_schema(info.arguments_schema) == {"x": "value to clamp"}
|
|
697
|
+
|
|
698
|
+
def test_declarative_macro_rejects_unknown_doc_param(self) -> None:
|
|
699
|
+
"""parameter_docs keys must be in parameters (validated like defaults)."""
|
|
700
|
+
from vgi.catalog.descriptors import Macro
|
|
701
|
+
|
|
702
|
+
with pytest.raises(ValueError, match="documented parameter 'bogus' not found"):
|
|
703
|
+
Macro(
|
|
704
|
+
name="bad",
|
|
705
|
+
macro_type=MacroType.SCALAR,
|
|
706
|
+
parameters=["x"],
|
|
707
|
+
parameter_docs={"bogus": "nope"},
|
|
708
|
+
definition="x",
|
|
709
|
+
)
|
|
710
|
+
|
|
711
|
+
def test_macro_create_request_round_trip(self) -> None:
|
|
712
|
+
"""MacroCreateRequest carries arguments_schema over the wire."""
|
|
713
|
+
from vgi.argument_spec import macro_arguments_schema, macro_parameter_docs_from_schema
|
|
714
|
+
from vgi.catalog import OnConflict
|
|
715
|
+
from vgi.protocol import MacroCreateRequest
|
|
716
|
+
|
|
717
|
+
args = macro_arguments_schema(
|
|
718
|
+
parameters=["x", "y"],
|
|
719
|
+
parameter_docs={"x": "first", "y": "second"},
|
|
720
|
+
)
|
|
721
|
+
req = MacroCreateRequest(
|
|
722
|
+
attach_opaque_data=b"attach",
|
|
723
|
+
schema_name="main",
|
|
724
|
+
name="add",
|
|
725
|
+
macro_type=MacroType.SCALAR,
|
|
726
|
+
parameters=["x", "y"],
|
|
727
|
+
definition="x + y",
|
|
728
|
+
on_conflict=OnConflict.ERROR,
|
|
729
|
+
arguments_schema=args,
|
|
730
|
+
)
|
|
731
|
+
restored = MacroCreateRequest.deserialize_from_bytes(req.serialize_to_bytes())
|
|
732
|
+
assert restored.arguments_schema is not None
|
|
733
|
+
assert macro_parameter_docs_from_schema(restored.arguments_schema) == {"x": "first", "y": "second"}
|
|
734
|
+
|
|
735
|
+
def test_macro_create_request_none_arguments_schema(self) -> None:
|
|
736
|
+
"""MacroCreateRequest.arguments_schema defaults to None and round-trips."""
|
|
737
|
+
from vgi.catalog import OnConflict
|
|
738
|
+
from vgi.protocol import MacroCreateRequest
|
|
739
|
+
|
|
740
|
+
req = MacroCreateRequest(
|
|
741
|
+
attach_opaque_data=b"attach",
|
|
742
|
+
schema_name="main",
|
|
743
|
+
name="add",
|
|
744
|
+
macro_type=MacroType.SCALAR,
|
|
745
|
+
parameters=["x", "y"],
|
|
746
|
+
definition="x + y",
|
|
747
|
+
on_conflict=OnConflict.ERROR,
|
|
748
|
+
)
|
|
749
|
+
restored = MacroCreateRequest.deserialize_from_bytes(req.serialize_to_bytes())
|
|
750
|
+
assert restored.arguments_schema is None
|
|
751
|
+
|
|
618
752
|
|
|
619
753
|
class TestFunctionInfoSerialization:
|
|
620
754
|
"""Test FunctionInfo serialization round-trip."""
|
|
@@ -12,6 +12,7 @@ import pytest
|
|
|
12
12
|
from vgi.argument_spec import (
|
|
13
13
|
VGI_ARG_KEY,
|
|
14
14
|
VGI_ARG_NAMED,
|
|
15
|
+
VGI_DOC_KEY,
|
|
15
16
|
VGI_TYPE_ANY,
|
|
16
17
|
VGI_TYPE_KEY,
|
|
17
18
|
VGI_TYPE_TABLE,
|
|
@@ -674,3 +675,50 @@ class TestArgumentSpecRepr:
|
|
|
674
675
|
)
|
|
675
676
|
result = repr(spec)
|
|
676
677
|
assert "any_type" in result
|
|
678
|
+
|
|
679
|
+
|
|
680
|
+
class TestArgumentDoc:
|
|
681
|
+
"""Per-argument description via the vgi_doc field-metadata key."""
|
|
682
|
+
|
|
683
|
+
def test_doc_serialized_as_utf8_field_metadata(self) -> None:
|
|
684
|
+
"""A non-empty doc is emitted as the vgi_doc field metadata (UTF-8)."""
|
|
685
|
+
specs = [ArgumentSpec(name="unit", position=0, arrow_type=pa.utf8(), doc="Source unit, e.g. 'mi'")]
|
|
686
|
+
schema = argument_specs_to_schema(specs)
|
|
687
|
+
meta = schema.field("unit").metadata or {}
|
|
688
|
+
assert meta.get(VGI_DOC_KEY) == b"Source unit, e.g. 'mi'"
|
|
689
|
+
|
|
690
|
+
def test_doc_absent_when_empty(self) -> None:
|
|
691
|
+
"""Presence-only: an empty doc emits no vgi_doc key (absent = undocumented)."""
|
|
692
|
+
specs = [ArgumentSpec(name="x", position=0, arrow_type=pa.int64())]
|
|
693
|
+
schema = argument_specs_to_schema(specs)
|
|
694
|
+
meta = schema.field("x").metadata or {}
|
|
695
|
+
assert VGI_DOC_KEY not in meta
|
|
696
|
+
|
|
697
|
+
def test_doc_round_trips(self) -> None:
|
|
698
|
+
"""Doc survives schema -> specs round-trip; missing doc decodes to ''."""
|
|
699
|
+
specs = [
|
|
700
|
+
ArgumentSpec(name="a", position=0, arrow_type=pa.int64(), doc="first arg"),
|
|
701
|
+
ArgumentSpec(name="b", position=1, arrow_type=pa.utf8()),
|
|
702
|
+
]
|
|
703
|
+
out = schema_to_argument_specs(argument_specs_to_schema(specs))
|
|
704
|
+
by_name = {s.name: s for s in out}
|
|
705
|
+
assert by_name["a"].doc == "first arg"
|
|
706
|
+
assert by_name["b"].doc == ""
|
|
707
|
+
|
|
708
|
+
def test_doc_unicode_round_trips(self) -> None:
|
|
709
|
+
"""Non-ASCII docs (µ, ≥, em-dash) survive the UTF-8 round-trip."""
|
|
710
|
+
doc = "value in µm — must be ≥ 1"
|
|
711
|
+
specs = [ArgumentSpec(name="v", position=0, arrow_type=pa.float64(), doc=doc)]
|
|
712
|
+
out = schema_to_argument_specs(argument_specs_to_schema(specs))
|
|
713
|
+
assert out[0].doc == doc
|
|
714
|
+
|
|
715
|
+
def test_extract_doc_from_arg(self) -> None:
|
|
716
|
+
"""extract_argument_specs captures the Arg(doc=...) string."""
|
|
717
|
+
|
|
718
|
+
class FunctionWithDocs(TableInOutFunction): # type: ignore[type-arg]
|
|
719
|
+
unit: str = Arg[str](0, doc="Unit string, e.g. 'mi'") # type: ignore[assignment]
|
|
720
|
+
scale: float = Arg[float](1) # type: ignore[assignment]
|
|
721
|
+
|
|
722
|
+
specs = {s.name: s for s in extract_argument_specs(FunctionWithDocs)}
|
|
723
|
+
assert specs["unit"].doc == "Unit string, e.g. 'mi'"
|
|
724
|
+
assert specs["scale"].doc == ""
|
|
@@ -752,6 +752,7 @@ class InMemoryCatalog(CatalogInterface):
|
|
|
752
752
|
definition: str,
|
|
753
753
|
on_conflict: OnConflict,
|
|
754
754
|
parameter_default_values: pa.RecordBatch | None = None,
|
|
755
|
+
arguments_schema: pa.Schema | None = None,
|
|
755
756
|
) -> None:
|
|
756
757
|
"""Create a new macro."""
|
|
757
758
|
schema_data = self._get_schema(attach_opaque_data, schema_name)
|
|
@@ -773,6 +774,7 @@ class InMemoryCatalog(CatalogInterface):
|
|
|
773
774
|
definition=definition,
|
|
774
775
|
comment=None,
|
|
775
776
|
tags={},
|
|
777
|
+
arguments_schema=arguments_schema,
|
|
776
778
|
)
|
|
777
779
|
)
|
|
778
780
|
self._increment_version(attach_opaque_data)
|
|
@@ -519,6 +519,10 @@ _EXAMPLE_CATALOG = Catalog(
|
|
|
519
519
|
parameters=["x", "y"],
|
|
520
520
|
definition="x * y",
|
|
521
521
|
comment="Multiply two values",
|
|
522
|
+
parameter_docs={
|
|
523
|
+
"x": "First factor",
|
|
524
|
+
"y": "Second factor",
|
|
525
|
+
},
|
|
522
526
|
),
|
|
523
527
|
Macro(
|
|
524
528
|
name="vgi_clamp",
|
|
@@ -530,6 +534,11 @@ _EXAMPLE_CATALOG = Catalog(
|
|
|
530
534
|
),
|
|
531
535
|
definition="GREATEST(lo, LEAST(hi, val))",
|
|
532
536
|
comment="Clamp a value between lo and hi (defaults: 0..100)",
|
|
537
|
+
parameter_docs={
|
|
538
|
+
"val": "Value to clamp",
|
|
539
|
+
"lo": "Lower bound (inclusive)",
|
|
540
|
+
"hi": "Upper bound (inclusive)",
|
|
541
|
+
},
|
|
533
542
|
),
|
|
534
543
|
Macro(
|
|
535
544
|
name="vgi_range_table",
|
|
@@ -537,6 +546,7 @@ _EXAMPLE_CATALOG = Catalog(
|
|
|
537
546
|
parameters=["n"],
|
|
538
547
|
definition="SELECT * FROM range(n)",
|
|
539
548
|
comment="Table macro returning range of values",
|
|
549
|
+
parameter_docs={"n": "Number of rows to generate"},
|
|
540
550
|
),
|
|
541
551
|
],
|
|
542
552
|
),
|
|
@@ -27,6 +27,8 @@ __all__ = [
|
|
|
27
27
|
"ArgumentSpec",
|
|
28
28
|
"argument_specs_to_schema",
|
|
29
29
|
"extract_argument_specs",
|
|
30
|
+
"macro_arguments_schema",
|
|
31
|
+
"macro_parameter_docs_from_schema",
|
|
30
32
|
"schema_to_argument_specs",
|
|
31
33
|
# Metadata constants for parsing schemas
|
|
32
34
|
"VGI_ARG_KEY",
|
|
@@ -38,6 +40,7 @@ __all__ = [
|
|
|
38
40
|
"VGI_VARARGS_TRUE",
|
|
39
41
|
"VGI_CONST_KEY",
|
|
40
42
|
"VGI_CONST_TRUE",
|
|
43
|
+
"VGI_DOC_KEY",
|
|
41
44
|
]
|
|
42
45
|
|
|
43
46
|
# =============================================================================
|
|
@@ -61,6 +64,11 @@ VGI_VARARGS_TRUE = b"true"
|
|
|
61
64
|
VGI_CONST_KEY = b"vgi_const"
|
|
62
65
|
VGI_CONST_TRUE = b"true"
|
|
63
66
|
|
|
67
|
+
# Key carrying the per-argument description (UTF-8 text). Presence-only: the key
|
|
68
|
+
# is omitted entirely when there is no doc (absent = undocumented). The
|
|
69
|
+
# ``vgi_doc_*`` prefix is reserved for future per-argument doc variants.
|
|
70
|
+
VGI_DOC_KEY = b"vgi_doc"
|
|
71
|
+
|
|
64
72
|
|
|
65
73
|
def _argument_spec_sort_key(spec: "ArgumentSpec") -> tuple[int, int | str]:
|
|
66
74
|
"""Sort key: positional first (by index), then named (alphabetically)."""
|
|
@@ -98,6 +106,9 @@ class ArgumentSpec:
|
|
|
98
106
|
is_const: True if this argument is constant-folded ([`ConstParam`][]).
|
|
99
107
|
Constant arguments are scalar values known at planning time,
|
|
100
108
|
rather than columnar data processed at runtime.
|
|
109
|
+
doc: Optional human/agent-facing description of the argument. Surfaced
|
|
110
|
+
through the catalog as the ``vgi_doc`` Arrow field metadata key
|
|
111
|
+
(UTF-8); empty string means undocumented.
|
|
101
112
|
|
|
102
113
|
Note:
|
|
103
114
|
For named arguments, the Python attribute name (``name``) and the SQL
|
|
@@ -119,6 +130,7 @@ class ArgumentSpec:
|
|
|
119
130
|
is_any_type: bool = False
|
|
120
131
|
is_varargs: bool = False
|
|
121
132
|
is_const: bool = False
|
|
133
|
+
doc: str = ""
|
|
122
134
|
|
|
123
135
|
def __repr__(self) -> str:
|
|
124
136
|
"""Return concise repr showing key attributes."""
|
|
@@ -197,6 +209,10 @@ def argument_specs_to_schema(specs: Sequence[ArgumentSpec]) -> pa.Schema:
|
|
|
197
209
|
if spec.is_const:
|
|
198
210
|
metadata[VGI_CONST_KEY] = VGI_CONST_TRUE
|
|
199
211
|
|
|
212
|
+
# Per-argument description (UTF-8; presence-only — omit when empty)
|
|
213
|
+
if spec.doc:
|
|
214
|
+
metadata[VGI_DOC_KEY] = spec.doc.encode("utf-8")
|
|
215
|
+
|
|
200
216
|
# Create field with or without metadata
|
|
201
217
|
field = pa.field(
|
|
202
218
|
spec.name,
|
|
@@ -246,6 +262,10 @@ def schema_to_argument_specs(schema: pa.Schema) -> list[ArgumentSpec]:
|
|
|
246
262
|
# Check const
|
|
247
263
|
is_const = metadata.get(VGI_CONST_KEY) == VGI_CONST_TRUE
|
|
248
264
|
|
|
265
|
+
# Per-argument description (UTF-8; absent = undocumented)
|
|
266
|
+
doc_bytes = metadata.get(VGI_DOC_KEY)
|
|
267
|
+
doc = doc_bytes.decode("utf-8") if doc_bytes else ""
|
|
268
|
+
|
|
249
269
|
specs.append(
|
|
250
270
|
ArgumentSpec(
|
|
251
271
|
name=field.name,
|
|
@@ -255,12 +275,93 @@ def schema_to_argument_specs(schema: pa.Schema) -> list[ArgumentSpec]:
|
|
|
255
275
|
is_any_type=is_any_type,
|
|
256
276
|
is_varargs=is_varargs,
|
|
257
277
|
is_const=is_const,
|
|
278
|
+
doc=doc,
|
|
258
279
|
)
|
|
259
280
|
)
|
|
260
281
|
|
|
261
282
|
return specs
|
|
262
283
|
|
|
263
284
|
|
|
285
|
+
# =============================================================================
|
|
286
|
+
# Macro Argument Schemas
|
|
287
|
+
# =============================================================================
|
|
288
|
+
|
|
289
|
+
|
|
290
|
+
def macro_arguments_schema(
|
|
291
|
+
parameters: Sequence[str],
|
|
292
|
+
parameter_default_values: pa.RecordBatch | None = None,
|
|
293
|
+
parameter_docs: dict[str, str] | None = None,
|
|
294
|
+
) -> pa.Schema:
|
|
295
|
+
"""Build a macro ``arguments_schema`` describing macro parameters.
|
|
296
|
+
|
|
297
|
+
Mirrors the function ``arguments_schema`` mechanism: one Arrow field per
|
|
298
|
+
macro parameter, in ``parameters`` order, each nullable. The per-parameter
|
|
299
|
+
description is carried via the same ``vgi_doc`` field-metadata key functions
|
|
300
|
+
use (UTF-8, presence-only — the key is omitted entirely when there is no
|
|
301
|
+
doc). A parameter's field type is the type of its default value when one is
|
|
302
|
+
known (from ``parameter_default_values``), else ``pa.null()``.
|
|
303
|
+
|
|
304
|
+
Args:
|
|
305
|
+
parameters: Ordered list of macro parameter names.
|
|
306
|
+
parameter_default_values: Optional one-row ``RecordBatch`` whose columns
|
|
307
|
+
are parameter names with typed default values; used to infer each
|
|
308
|
+
parameter's field type.
|
|
309
|
+
parameter_docs: Optional mapping of parameter name to description. Empty
|
|
310
|
+
or missing descriptions yield no ``vgi_doc`` metadata on the field.
|
|
311
|
+
|
|
312
|
+
Returns:
|
|
313
|
+
Arrow schema with one nullable field per parameter, in order.
|
|
314
|
+
|
|
315
|
+
"""
|
|
316
|
+
docs = parameter_docs or {}
|
|
317
|
+
|
|
318
|
+
# Map parameter name -> Arrow type from the typed default values, if any.
|
|
319
|
+
default_types: dict[str, pa.DataType] = {}
|
|
320
|
+
if parameter_default_values is not None:
|
|
321
|
+
for default_field in parameter_default_values.schema:
|
|
322
|
+
default_types[default_field.name] = default_field.type
|
|
323
|
+
|
|
324
|
+
fields: list[pa.Field[Any]] = []
|
|
325
|
+
for name in parameters:
|
|
326
|
+
metadata: dict[bytes, bytes] = {}
|
|
327
|
+
doc = docs.get(name, "")
|
|
328
|
+
if doc:
|
|
329
|
+
metadata[VGI_DOC_KEY] = doc.encode("utf-8")
|
|
330
|
+
|
|
331
|
+
field = pa.field(
|
|
332
|
+
name,
|
|
333
|
+
default_types.get(name, pa.null()),
|
|
334
|
+
nullable=True,
|
|
335
|
+
metadata=metadata if metadata else None,
|
|
336
|
+
)
|
|
337
|
+
fields.append(field)
|
|
338
|
+
|
|
339
|
+
return pa.schema(fields)
|
|
340
|
+
|
|
341
|
+
|
|
342
|
+
def macro_parameter_docs_from_schema(schema: pa.Schema) -> dict[str, str]:
|
|
343
|
+
"""Extract per-parameter descriptions from a macro ``arguments_schema``.
|
|
344
|
+
|
|
345
|
+
Inverse of [`macro_arguments_schema`][]'s ``vgi_doc`` handling: reads the
|
|
346
|
+
``vgi_doc`` field metadata (UTF-8) for each field. Fields without the key
|
|
347
|
+
(undocumented) are omitted from the result.
|
|
348
|
+
|
|
349
|
+
Args:
|
|
350
|
+
schema: A macro ``arguments_schema`` (one field per parameter).
|
|
351
|
+
|
|
352
|
+
Returns:
|
|
353
|
+
Mapping of parameter name to description, for documented parameters only.
|
|
354
|
+
|
|
355
|
+
"""
|
|
356
|
+
docs: dict[str, str] = {}
|
|
357
|
+
for field in schema:
|
|
358
|
+
metadata = field.metadata or {}
|
|
359
|
+
doc_bytes = metadata.get(VGI_DOC_KEY)
|
|
360
|
+
if doc_bytes:
|
|
361
|
+
docs[field.name] = doc_bytes.decode("utf-8")
|
|
362
|
+
return docs
|
|
363
|
+
|
|
364
|
+
|
|
264
365
|
# =============================================================================
|
|
265
366
|
# Extraction from Function Classes
|
|
266
367
|
# =============================================================================
|
|
@@ -312,6 +413,7 @@ def extract_argument_specs(
|
|
|
312
413
|
is_any_type=param_arg.is_any,
|
|
313
414
|
is_varargs=param_arg.varargs,
|
|
314
415
|
is_const=False,
|
|
416
|
+
doc=param_arg.doc or "",
|
|
315
417
|
)
|
|
316
418
|
)
|
|
317
419
|
|
|
@@ -328,6 +430,7 @@ def extract_argument_specs(
|
|
|
328
430
|
is_any_type=const_arg.is_any,
|
|
329
431
|
is_varargs=const_arg.varargs,
|
|
330
432
|
is_const=True,
|
|
433
|
+
doc=const_arg.doc or "",
|
|
331
434
|
)
|
|
332
435
|
)
|
|
333
436
|
|
|
@@ -392,6 +495,7 @@ def extract_argument_specs(
|
|
|
392
495
|
is_any_type=is_any_type,
|
|
393
496
|
is_varargs=arg_instance.varargs,
|
|
394
497
|
is_const=getattr(arg_instance, "const", False),
|
|
498
|
+
doc=getattr(arg_instance, "doc", "") or "",
|
|
395
499
|
)
|
|
396
500
|
)
|
|
397
501
|
|
|
@@ -466,6 +570,7 @@ def extract_argument_specs(
|
|
|
466
570
|
is_any_type=is_any_type,
|
|
467
571
|
is_varargs=is_varargs,
|
|
468
572
|
is_const=is_const,
|
|
573
|
+
doc=getattr(arg_legacy, "doc", "") or "",
|
|
469
574
|
)
|
|
470
575
|
)
|
|
471
576
|
|
|
@@ -435,6 +435,15 @@ class MacroInfo(CatalogSchemaObject, ArrowSerializableDataclass):
|
|
|
435
435
|
names and values are typed defaults. None if no defaults.
|
|
436
436
|
Serialized as IPC bytes over the wire.
|
|
437
437
|
definition: The SQL expression (scalar) or query (table).
|
|
438
|
+
arguments_schema: Optional Arrow schema (serialized as IPC bytes) with one
|
|
439
|
+
nullable field per parameter, in ``parameters`` order. Each field's type
|
|
440
|
+
is the parameter's default value type when known (else null), and the
|
|
441
|
+
``vgi_doc`` field metadata key carries the parameter's description (UTF-8,
|
|
442
|
+
presence-only — omitted when undocumented). Mirrors the per-argument doc
|
|
443
|
+
channel functions expose via ``FunctionInfo.arguments``. None means the
|
|
444
|
+
worker did not supply per-parameter docs (older workers); the extension
|
|
445
|
+
falls back to ``parameters`` for names. Built with
|
|
446
|
+
``vgi.argument_spec.macro_arguments_schema``.
|
|
438
447
|
|
|
439
448
|
"""
|
|
440
449
|
|
|
@@ -442,6 +451,7 @@ class MacroInfo(CatalogSchemaObject, ArrowSerializableDataclass):
|
|
|
442
451
|
parameters: list[str]
|
|
443
452
|
parameter_default_values: Annotated[pa.RecordBatch | None, ArrowType(pa.binary())] = None
|
|
444
453
|
definition: str = ""
|
|
454
|
+
arguments_schema: Annotated[pa.Schema | None, ArrowType(pa.binary())] = None
|
|
445
455
|
|
|
446
456
|
|
|
447
457
|
class FunctionType(Enum):
|
|
@@ -1979,8 +1989,25 @@ class CatalogInterface(ABC):
|
|
|
1979
1989
|
definition: str,
|
|
1980
1990
|
on_conflict: OnConflict,
|
|
1981
1991
|
parameter_default_values: pa.RecordBatch | None = None,
|
|
1992
|
+
arguments_schema: pa.Schema | None = None,
|
|
1982
1993
|
) -> None:
|
|
1983
|
-
"""Create a new macro with the given definition.
|
|
1994
|
+
"""Create a new macro with the given definition.
|
|
1995
|
+
|
|
1996
|
+
Args:
|
|
1997
|
+
attach_opaque_data: Per-attach catalog session token.
|
|
1998
|
+
transaction_opaque_data: Optional transaction handle.
|
|
1999
|
+
schema_name: Schema to create the macro in.
|
|
2000
|
+
name: Name for the new macro.
|
|
2001
|
+
macro_type: Whether this is a scalar or table macro.
|
|
2002
|
+
parameters: Ordered list of parameter names.
|
|
2003
|
+
definition: SQL expression (scalar) or query (table).
|
|
2004
|
+
on_conflict: Behavior if the macro already exists.
|
|
2005
|
+
parameter_default_values: One-row ``RecordBatch`` with typed defaults.
|
|
2006
|
+
arguments_schema: Optional Arrow schema (one nullable field per
|
|
2007
|
+
parameter, in ``parameters`` order) carrying per-parameter
|
|
2008
|
+
descriptions via the ``vgi_doc`` field metadata key. ``None`` when
|
|
2009
|
+
no per-parameter docs are supplied.
|
|
2010
|
+
"""
|
|
1984
2011
|
raise NotImplementedError("Macro create not implemented.")
|
|
1985
2012
|
|
|
1986
2013
|
def macro_drop(
|
|
@@ -18,6 +18,7 @@ from typing import TYPE_CHECKING, Any, Union
|
|
|
18
18
|
|
|
19
19
|
import pyarrow as pa
|
|
20
20
|
|
|
21
|
+
from vgi.argument_spec import macro_arguments_schema
|
|
21
22
|
from vgi.arguments import Arguments
|
|
22
23
|
from vgi.catalog.catalog_interface import (
|
|
23
24
|
AttachOpaqueData,
|
|
@@ -695,6 +696,11 @@ class Macro:
|
|
|
695
696
|
parameter_default_values: One-row `RecordBatch` where columns are parameter
|
|
696
697
|
names and values are typed defaults. None if no defaults.
|
|
697
698
|
Example: pa.RecordBatch.from_pydict({"b": [5]}) for b := 5.
|
|
699
|
+
parameter_docs: Optional mapping of parameter name to a human/agent-facing
|
|
700
|
+
description. Keys must appear in ``parameters``. Descriptions flow over
|
|
701
|
+
the wire via the macro ``arguments_schema``'s ``vgi_doc`` field metadata
|
|
702
|
+
(the same channel functions use), so the DuckDB extension's
|
|
703
|
+
``vgi_function_arguments()`` can surface them. Empty/default = no docs.
|
|
698
704
|
definition: SQL expression (scalar) or query (table).
|
|
699
705
|
comment: Optional macro comment.
|
|
700
706
|
tags: Optional metadata tags.
|
|
@@ -705,12 +711,14 @@ class Macro:
|
|
|
705
711
|
macro_type: MacroType
|
|
706
712
|
parameters: list[str] = field(default_factory=list)
|
|
707
713
|
parameter_default_values: pa.RecordBatch | None = None
|
|
714
|
+
parameter_docs: dict[str, str] = field(default_factory=dict)
|
|
708
715
|
definition: str = ""
|
|
709
716
|
comment: str | None = None
|
|
710
717
|
tags: dict[str, str] = field(default_factory=dict)
|
|
711
718
|
|
|
712
719
|
def __post_init__(self) -> None:
|
|
713
720
|
"""Validate macro configuration."""
|
|
721
|
+
param_set = set(self.parameters)
|
|
714
722
|
if self.parameter_default_values is not None:
|
|
715
723
|
if self.parameter_default_values.num_rows != 1:
|
|
716
724
|
raise ValueError(
|
|
@@ -718,13 +726,19 @@ class Macro:
|
|
|
718
726
|
f"got {self.parameter_default_values.num_rows}"
|
|
719
727
|
)
|
|
720
728
|
# Validate that default param column names exist in parameters list
|
|
721
|
-
param_set = set(self.parameters)
|
|
722
729
|
for col_name in self.parameter_default_values.schema.names:
|
|
723
730
|
if col_name not in param_set:
|
|
724
731
|
raise ValueError(
|
|
725
732
|
f"Macro '{self.name}': default parameter '{col_name}' not found "
|
|
726
733
|
f"in parameters list {self.parameters}"
|
|
727
734
|
)
|
|
735
|
+
# Validate that documented parameter names exist in parameters list
|
|
736
|
+
for doc_name in self.parameter_docs:
|
|
737
|
+
if doc_name not in param_set:
|
|
738
|
+
raise ValueError(
|
|
739
|
+
f"Macro '{self.name}': documented parameter '{doc_name}' not found "
|
|
740
|
+
f"in parameters list {self.parameters}"
|
|
741
|
+
)
|
|
728
742
|
|
|
729
743
|
def to_macro_info(self, schema_name: str) -> MacroInfo:
|
|
730
744
|
"""Convert to [`MacroInfo`][] for catalog response."""
|
|
@@ -737,6 +751,11 @@ class Macro:
|
|
|
737
751
|
definition=self.definition,
|
|
738
752
|
comment=self.comment,
|
|
739
753
|
tags=dict(self.tags),
|
|
754
|
+
arguments_schema=macro_arguments_schema(
|
|
755
|
+
self.parameters,
|
|
756
|
+
self.parameter_default_values,
|
|
757
|
+
self.parameter_docs,
|
|
758
|
+
),
|
|
740
759
|
)
|
|
741
760
|
|
|
742
761
|
|
|
@@ -1196,6 +1196,7 @@ class CatalogClientMixin:
|
|
|
1196
1196
|
definition: str,
|
|
1197
1197
|
on_conflict: OnConflict = OnConflict.ERROR,
|
|
1198
1198
|
parameter_default_values: pa.RecordBatch | None = None,
|
|
1199
|
+
arguments_schema: pa.Schema | None = None,
|
|
1199
1200
|
) -> None:
|
|
1200
1201
|
"""Create a new macro.
|
|
1201
1202
|
|
|
@@ -1209,6 +1210,10 @@ class CatalogClientMixin:
|
|
|
1209
1210
|
definition: SQL expression (scalar) or query (table).
|
|
1210
1211
|
on_conflict: Behavior if macro already exists.
|
|
1211
1212
|
parameter_default_values: One-row `RecordBatch` with typed defaults.
|
|
1213
|
+
arguments_schema: Optional Arrow schema (one nullable field per
|
|
1214
|
+
parameter, in ``parameters`` order) carrying per-parameter
|
|
1215
|
+
descriptions via the ``vgi_doc`` field metadata key. Build with
|
|
1216
|
+
``vgi.argument_spec.macro_arguments_schema``.
|
|
1212
1217
|
|
|
1213
1218
|
"""
|
|
1214
1219
|
with self._catalog_connect() as proxy:
|
|
@@ -1222,6 +1227,7 @@ class CatalogClientMixin:
|
|
|
1222
1227
|
definition=definition,
|
|
1223
1228
|
on_conflict=on_conflict,
|
|
1224
1229
|
parameter_default_values=parameter_default_values,
|
|
1230
|
+
arguments_schema=arguments_schema,
|
|
1225
1231
|
transaction_opaque_data=transaction_opaque_data,
|
|
1226
1232
|
)
|
|
1227
1233
|
)
|
|
@@ -155,8 +155,14 @@ def _emit_field_literal(field: pa.Field[Any], *, origin: str) -> str:
|
|
|
155
155
|
|
|
156
156
|
def _emit_var(es: EmittedSchema) -> str:
|
|
157
157
|
body = f"// Origin: {es.origin}\n"
|
|
158
|
+
fields = list(es.schema)
|
|
159
|
+
# Empty schemas must collapse to `[]arrow.Field{}` on one line — gofmt
|
|
160
|
+
# rejects the multi-line `{\n}` form, and vgi-go's CI runs `gofmt -l`.
|
|
161
|
+
if not fields:
|
|
162
|
+
body += f"var {es.name}Schema = arrow.NewSchema([]arrow.Field{{}}, nil)\n"
|
|
163
|
+
return body
|
|
158
164
|
body += f"var {es.name}Schema = arrow.NewSchema([]arrow.Field{{\n"
|
|
159
|
-
for f in
|
|
165
|
+
for f in fields:
|
|
160
166
|
body += "\t" + _emit_field_literal(f, origin=f"{es.name}.{f.name}") + ",\n"
|
|
161
167
|
body += "}, nil)\n"
|
|
162
168
|
return body
|
|
@@ -178,9 +184,9 @@ def emit(out: TextIO) -> None:
|
|
|
178
184
|
body.write("\n")
|
|
179
185
|
body.write("var _ = arrow.BinaryTypes.String // keep import live when no schemas reference it\n")
|
|
180
186
|
body.write("\n")
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
187
|
+
# Blank line BETWEEN blocks, but no trailing blank line at EOF (gofmt rejects
|
|
188
|
+
# it; vgi-go CI runs `gofmt -l`). Each block already ends in "\n".
|
|
189
|
+
body.write("\n".join(_emit_var(es) for es in schemas))
|
|
184
190
|
|
|
185
191
|
out.write(
|
|
186
192
|
provenance_comment(
|
|
@@ -562,6 +562,13 @@ class MacroCreateRequest(ArrowSerializableDataclass):
|
|
|
562
562
|
ERROR/IGNORE/REPLACE).
|
|
563
563
|
parameter_default_values: One-row `RecordBatch` where column names are
|
|
564
564
|
parameter names and values are typed defaults; ``None`` if no defaults.
|
|
565
|
+
arguments_schema: Optional Arrow schema (serialized as IPC bytes) with one
|
|
566
|
+
nullable field per parameter, in ``parameters`` order. Each field's type
|
|
567
|
+
is the parameter's default value type when known (else null), and the
|
|
568
|
+
``vgi_doc`` field metadata key carries the parameter's description (UTF-8,
|
|
569
|
+
presence-only — omitted when undocumented). Mirrors the per-argument doc
|
|
570
|
+
channel functions expose. ``None`` when no per-parameter docs are
|
|
571
|
+
supplied. Built with ``vgi.argument_spec.macro_arguments_schema``.
|
|
565
572
|
transaction_opaque_data: Opaque DuckDB transaction handle (bytes); ``None``
|
|
566
573
|
when not inside a transaction.
|
|
567
574
|
"""
|
|
@@ -574,6 +581,7 @@ class MacroCreateRequest(ArrowSerializableDataclass):
|
|
|
574
581
|
definition: str
|
|
575
582
|
on_conflict: OnConflict
|
|
576
583
|
parameter_default_values: Annotated[pa.RecordBatch | None, ArrowType(pa.binary())] = None
|
|
584
|
+
arguments_schema: Annotated[pa.Schema | None, ArrowType(pa.binary())] = None
|
|
577
585
|
transaction_opaque_data: bytes | None = None
|
|
578
586
|
|
|
579
587
|
|