vgi-python 0.9.0__tar.gz → 0.10.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.
Files changed (378) hide show
  1. {vgi_python-0.9.0 → vgi_python-0.10.0}/PKG-INFO +1 -1
  2. {vgi_python-0.9.0 → vgi_python-0.10.0}/packages/vgi-fixtures/pyproject.toml +1 -0
  3. {vgi_python-0.9.0 → vgi_python-0.10.0}/pyproject.toml +1 -1
  4. {vgi_python-0.9.0 → vgi_python-0.10.0}/tests/catalog/test_declarative.py +39 -1
  5. {vgi_python-0.9.0 → vgi_python-0.10.0}/tests/catalog/test_serialization.py +2 -1
  6. vgi_python-0.10.0/tests/conformance/test_const_param_enforcement.py +69 -0
  7. vgi_python-0.10.0/tests/conformance/test_container.py +17 -0
  8. vgi_python-0.10.0/tests/conformance/test_copy_from.py +16 -0
  9. vgi_python-0.10.0/tests/conformance/test_copy_to.py +21 -0
  10. vgi_python-0.10.0/tests/conformance/test_github.py +15 -0
  11. {vgi_python-0.9.0 → vgi_python-0.10.0}/tests/conformance/test_secret.py +3 -0
  12. {vgi_python-0.9.0 → vgi_python-0.10.0}/tests/test_aggregate_function.py +51 -1
  13. {vgi_python-0.9.0 → vgi_python-0.10.0}/tests/test_argument_spec.py +101 -0
  14. {vgi_python-0.9.0 → vgi_python-0.10.0}/vgi/_test_fixtures/aggregate/__init__.py +2 -0
  15. vgi_python-0.10.0/vgi/_test_fixtures/aggregate/secret_typed.py +115 -0
  16. vgi_python-0.10.0/vgi/_test_fixtures/companion.py +169 -0
  17. {vgi_python-0.9.0 → vgi_python-0.10.0}/vgi/_test_fixtures/scalar/formatting.py +2 -2
  18. {vgi_python-0.9.0 → vgi_python-0.10.0}/vgi/_test_fixtures/table_in_out.py +46 -0
  19. {vgi_python-0.9.0 → vgi_python-0.10.0}/vgi/_test_fixtures/worker.py +48 -0
  20. {vgi_python-0.9.0 → vgi_python-0.10.0}/vgi/argument_spec.py +146 -1
  21. {vgi_python-0.9.0 → vgi_python-0.10.0}/vgi/arguments.py +71 -1
  22. {vgi_python-0.9.0 → vgi_python-0.10.0}/vgi/catalog/__init__.py +2 -0
  23. {vgi_python-0.9.0 → vgi_python-0.10.0}/vgi/catalog/catalog_interface.py +96 -2
  24. {vgi_python-0.9.0 → vgi_python-0.10.0}/vgi/catalog/descriptors.py +15 -1
  25. {vgi_python-0.9.0 → vgi_python-0.10.0}/vgi/codegen/_common.py +2 -0
  26. {vgi_python-0.9.0 → vgi_python-0.10.0}/vgi/scalar_function.py +33 -1
  27. {vgi_python-0.9.0 → vgi_python-0.10.0}/vgi/worker.py +16 -1
  28. {vgi_python-0.9.0 → vgi_python-0.10.0}/.gitattributes +0 -0
  29. {vgi_python-0.9.0 → vgi_python-0.10.0}/.github/dependabot.yml +0 -0
  30. {vgi_python-0.9.0 → vgi_python-0.10.0}/.github/styles/config/vocabularies/VGI/accept.txt +0 -0
  31. {vgi_python-0.9.0 → vgi_python-0.10.0}/.github/workflows/ci.yml +0 -0
  32. {vgi_python-0.9.0 → vgi_python-0.10.0}/.github/workflows/docs.yml +0 -0
  33. {vgi_python-0.9.0 → vgi_python-0.10.0}/.github/workflows/integration.yml +0 -0
  34. {vgi_python-0.9.0 → vgi_python-0.10.0}/.github/workflows/release.yml +0 -0
  35. {vgi_python-0.9.0 → vgi_python-0.10.0}/.gitignore +0 -0
  36. {vgi_python-0.9.0 → vgi_python-0.10.0}/.python-version +0 -0
  37. {vgi_python-0.9.0 → vgi_python-0.10.0}/.vale.ini +0 -0
  38. {vgi_python-0.9.0 → vgi_python-0.10.0}/CLAUDE.md +0 -0
  39. {vgi_python-0.9.0 → vgi_python-0.10.0}/DOCS_ACCEPTANCE_CRITERIA.md +0 -0
  40. {vgi_python-0.9.0 → vgi_python-0.10.0}/DOCS_REVIEW_RUBRIC.md +0 -0
  41. {vgi_python-0.9.0 → vgi_python-0.10.0}/DOCS_USABILITY_TEST.md +0 -0
  42. {vgi_python-0.9.0 → vgi_python-0.10.0}/LICENSE +0 -0
  43. {vgi_python-0.9.0 → vgi_python-0.10.0}/README.md +0 -0
  44. {vgi_python-0.9.0 → vgi_python-0.10.0}/SECURITY.md +0 -0
  45. {vgi_python-0.9.0 → vgi_python-0.10.0}/ci/README.md +0 -0
  46. {vgi_python-0.9.0 → vgi_python-0.10.0}/ci/preprocess-require.awk +0 -0
  47. {vgi_python-0.9.0 → vgi_python-0.10.0}/ci/run-integration.sh +0 -0
  48. {vgi_python-0.9.0 → vgi_python-0.10.0}/dist-vgi/.gitignore +0 -0
  49. {vgi_python-0.9.0 → vgi_python-0.10.0}/docs/aggregate-functions.md +0 -0
  50. {vgi_python-0.9.0 → vgi_python-0.10.0}/docs/api/arguments.md +0 -0
  51. {vgi_python-0.9.0 → vgi_python-0.10.0}/docs/api/auth.md +0 -0
  52. {vgi_python-0.9.0 → vgi_python-0.10.0}/docs/api/catalogs.md +0 -0
  53. {vgi_python-0.9.0 → vgi_python-0.10.0}/docs/api/client.md +0 -0
  54. {vgi_python-0.9.0 → vgi_python-0.10.0}/docs/api/exceptions.md +0 -0
  55. {vgi_python-0.9.0 → vgi_python-0.10.0}/docs/api/filters.md +0 -0
  56. {vgi_python-0.9.0 → vgi_python-0.10.0}/docs/api/functions.md +0 -0
  57. {vgi_python-0.9.0 → vgi_python-0.10.0}/docs/api/http.md +0 -0
  58. {vgi_python-0.9.0 → vgi_python-0.10.0}/docs/api/index.md +0 -0
  59. {vgi_python-0.9.0 → vgi_python-0.10.0}/docs/api/metadata.md +0 -0
  60. {vgi_python-0.9.0 → vgi_python-0.10.0}/docs/api/observability.md +0 -0
  61. {vgi_python-0.9.0 → vgi_python-0.10.0}/docs/api/storage.md +0 -0
  62. {vgi_python-0.9.0 → vgi_python-0.10.0}/docs/api/transactor.md +0 -0
  63. {vgi_python-0.9.0 → vgi_python-0.10.0}/docs/api/worker.md +0 -0
  64. {vgi_python-0.9.0 → vgi_python-0.10.0}/docs/argument-serialization.md +0 -0
  65. {vgi_python-0.9.0 → vgi_python-0.10.0}/docs/assets/apple-touch-icon.png +0 -0
  66. {vgi_python-0.9.0 → vgi_python-0.10.0}/docs/assets/favicon-16x16.png +0 -0
  67. {vgi_python-0.9.0 → vgi_python-0.10.0}/docs/assets/favicon-32x32.png +0 -0
  68. {vgi_python-0.9.0 → vgi_python-0.10.0}/docs/assets/favicon.ico +0 -0
  69. {vgi_python-0.9.0 → vgi_python-0.10.0}/docs/assets/kinds/aggregate.svg +0 -0
  70. {vgi_python-0.9.0 → vgi_python-0.10.0}/docs/assets/kinds/buffering.svg +0 -0
  71. {vgi_python-0.9.0 → vgi_python-0.10.0}/docs/assets/kinds/scalar.svg +0 -0
  72. {vgi_python-0.9.0 → vgi_python-0.10.0}/docs/assets/kinds/table-in-out.svg +0 -0
  73. {vgi_python-0.9.0 → vgi_python-0.10.0}/docs/assets/kinds/table.svg +0 -0
  74. {vgi_python-0.9.0 → vgi_python-0.10.0}/docs/assets/logo.png +0 -0
  75. {vgi_python-0.9.0 → vgi_python-0.10.0}/docs/assets/social-card.png +0 -0
  76. {vgi_python-0.9.0 → vgi_python-0.10.0}/docs/authentication.md +0 -0
  77. {vgi_python-0.9.0 → vgi_python-0.10.0}/docs/catalog-interface.md +0 -0
  78. {vgi_python-0.9.0 → vgi_python-0.10.0}/docs/cli.md +0 -0
  79. {vgi_python-0.9.0 → vgi_python-0.10.0}/docs/column-statistics.md +0 -0
  80. {vgi_python-0.9.0 → vgi_python-0.10.0}/docs/concepts/index.md +0 -0
  81. {vgi_python-0.9.0 → vgi_python-0.10.0}/docs/contributing-docs.md +0 -0
  82. {vgi_python-0.9.0 → vgi_python-0.10.0}/docs/filter-pushdown.md +0 -0
  83. {vgi_python-0.9.0 → vgi_python-0.10.0}/docs/generator-api.md +0 -0
  84. {vgi_python-0.9.0 → vgi_python-0.10.0}/docs/how-to/catalogs.md +0 -0
  85. {vgi_python-0.9.0 → vgi_python-0.10.0}/docs/how-to/function-patterns.md +0 -0
  86. {vgi_python-0.9.0 → vgi_python-0.10.0}/docs/how-to/http-auth.md +0 -0
  87. {vgi_python-0.9.0 → vgi_python-0.10.0}/docs/how-to/index.md +0 -0
  88. {vgi_python-0.9.0 → vgi_python-0.10.0}/docs/how-to/pushdown-and-statistics.md +0 -0
  89. {vgi_python-0.9.0 → vgi_python-0.10.0}/docs/how-to/state-storage.md +0 -0
  90. {vgi_python-0.9.0 → vgi_python-0.10.0}/docs/index.md +0 -0
  91. {vgi_python-0.9.0 → vgi_python-0.10.0}/docs/lifecycle.md +0 -0
  92. {vgi_python-0.9.0 → vgi_python-0.10.0}/docs/metadata.md +0 -0
  93. {vgi_python-0.9.0 → vgi_python-0.10.0}/docs/overrides/main.html +0 -0
  94. {vgi_python-0.9.0 → vgi_python-0.10.0}/docs/robots.txt +0 -0
  95. {vgi_python-0.9.0 → vgi_python-0.10.0}/docs/shared-storage.md +0 -0
  96. {vgi_python-0.9.0 → vgi_python-0.10.0}/docs/stylesheets/extra.css +0 -0
  97. {vgi_python-0.9.0 → vgi_python-0.10.0}/docs/tutorial/index.md +0 -0
  98. {vgi_python-0.9.0 → vgi_python-0.10.0}/docs/tutorial/scalar.md +0 -0
  99. {vgi_python-0.9.0 → vgi_python-0.10.0}/docs/tutorial/table.md +0 -0
  100. {vgi_python-0.9.0 → vgi_python-0.10.0}/docs/vgi-logo.png +0 -0
  101. {vgi_python-0.9.0 → vgi_python-0.10.0}/examples/calc_scalar_worker.py +0 -0
  102. {vgi_python-0.9.0 → vgi_python-0.10.0}/examples/calc_worker.py +0 -0
  103. {vgi_python-0.9.0 → vgi_python-0.10.0}/examples/filter_worker.py +0 -0
  104. {vgi_python-0.9.0 → vgi_python-0.10.0}/examples/greeting_scalar_worker.py +0 -0
  105. {vgi_python-0.9.0 → vgi_python-0.10.0}/examples/row_count_worker.py +0 -0
  106. {vgi_python-0.9.0 → vgi_python-0.10.0}/examples/series_streaming_worker.py +0 -0
  107. {vgi_python-0.9.0 → vgi_python-0.10.0}/examples/sum_worker.py +0 -0
  108. {vgi_python-0.9.0 → vgi_python-0.10.0}/mkdocs.yml +0 -0
  109. {vgi_python-0.9.0 → vgi_python-0.10.0}/packages/vgi-fixtures/LICENSE +0 -0
  110. {vgi_python-0.9.0 → vgi_python-0.10.0}/packages/vgi-fixtures/README.md +0 -0
  111. {vgi_python-0.9.0 → vgi_python-0.10.0}/packages/vgi-fixtures/docker/Dockerfile +0 -0
  112. {vgi_python-0.9.0 → vgi_python-0.10.0}/packages/vgi-fixtures/docker/docker-entrypoint.sh +0 -0
  113. {vgi_python-0.9.0 → vgi_python-0.10.0}/scripts/measure_startup.py +0 -0
  114. {vgi_python-0.9.0 → vgi_python-0.10.0}/scripts/run_all_tests.sh +0 -0
  115. {vgi_python-0.9.0 → vgi_python-0.10.0}/test-data/generate.sh +0 -0
  116. {vgi_python-0.9.0 → vgi_python-0.10.0}/tests/__init__.py +0 -0
  117. {vgi_python-0.9.0 → vgi_python-0.10.0}/tests/_http_fixtures.py +0 -0
  118. {vgi_python-0.9.0 → vgi_python-0.10.0}/tests/catalog/__init__.py +0 -0
  119. {vgi_python-0.9.0 → vgi_python-0.10.0}/tests/catalog/test_catalog_interface.py +0 -0
  120. {vgi_python-0.9.0 → vgi_python-0.10.0}/tests/catalog/test_client_catalog.py +0 -0
  121. {vgi_python-0.9.0 → vgi_python-0.10.0}/tests/catalog/test_column_statistics.py +0 -0
  122. {vgi_python-0.9.0 → vgi_python-0.10.0}/tests/catalog/test_example_worker_catalog.py +0 -0
  123. {vgi_python-0.9.0 → vgi_python-0.10.0}/tests/catalog/test_integration.py +0 -0
  124. {vgi_python-0.9.0 → vgi_python-0.10.0}/tests/catalog/test_required_field_filter_paths.py +0 -0
  125. {vgi_python-0.9.0 → vgi_python-0.10.0}/tests/catalog/test_scan_branches.py +0 -0
  126. {vgi_python-0.9.0 → vgi_python-0.10.0}/tests/catalog/test_setting.py +0 -0
  127. {vgi_python-0.9.0 → vgi_python-0.10.0}/tests/catalog/test_storage.py +0 -0
  128. {vgi_python-0.9.0 → vgi_python-0.10.0}/tests/catalog/test_time_travel.py +0 -0
  129. {vgi_python-0.9.0 → vgi_python-0.10.0}/tests/catalog/test_writable_table.py +0 -0
  130. {vgi_python-0.9.0 → vgi_python-0.10.0}/tests/client/__init__.py +0 -0
  131. {vgi_python-0.9.0 → vgi_python-0.10.0}/tests/client/test_broken_pipe.py +0 -0
  132. {vgi_python-0.9.0 → vgi_python-0.10.0}/tests/client/test_cli.py +0 -0
  133. {vgi_python-0.9.0 → vgi_python-0.10.0}/tests/client/test_cli_catalog_functions.py +0 -0
  134. {vgi_python-0.9.0 → vgi_python-0.10.0}/tests/client/test_worker_debug.py +0 -0
  135. {vgi_python-0.9.0 → vgi_python-0.10.0}/tests/conformance/__init__.py +0 -0
  136. {vgi_python-0.9.0 → vgi_python-0.10.0}/tests/conformance/_stub.py +0 -0
  137. {vgi_python-0.9.0 → vgi_python-0.10.0}/tests/conformance/conftest.py +0 -0
  138. {vgi_python-0.9.0 → vgi_python-0.10.0}/tests/conformance/test_accumulate.py +0 -0
  139. {vgi_python-0.9.0 → vgi_python-0.10.0}/tests/conformance/test_aggregate.py +0 -0
  140. {vgi_python-0.9.0 → vgi_python-0.10.0}/tests/conformance/test_attach.py +0 -0
  141. {vgi_python-0.9.0 → vgi_python-0.10.0}/tests/conformance/test_bearer_auth.py +0 -0
  142. {vgi_python-0.9.0 → vgi_python-0.10.0}/tests/conformance/test_directory_parity.py +0 -0
  143. {vgi_python-0.9.0 → vgi_python-0.10.0}/tests/conformance/test_function_inventory.py +0 -0
  144. {vgi_python-0.9.0 → vgi_python-0.10.0}/tests/conformance/test_http_client.py +0 -0
  145. {vgi_python-0.9.0 → vgi_python-0.10.0}/tests/conformance/test_http_external_location.py +0 -0
  146. {vgi_python-0.9.0 → vgi_python-0.10.0}/tests/conformance/test_http_upload_url.py +0 -0
  147. {vgi_python-0.9.0 → vgi_python-0.10.0}/tests/conformance/test_macro.py +0 -0
  148. {vgi_python-0.9.0 → vgi_python-0.10.0}/tests/conformance/test_overload.py +0 -0
  149. {vgi_python-0.9.0 → vgi_python-0.10.0}/tests/conformance/test_protocol_inventory.py +0 -0
  150. {vgi_python-0.9.0 → vgi_python-0.10.0}/tests/conformance/test_protocol_version.py +0 -0
  151. {vgi_python-0.9.0 → vgi_python-0.10.0}/tests/conformance/test_resumable_scan.py +0 -0
  152. {vgi_python-0.9.0 → vgi_python-0.10.0}/tests/conformance/test_scalar.py +0 -0
  153. {vgi_python-0.9.0 → vgi_python-0.10.0}/tests/conformance/test_scalar_attach_opaque_data.py +0 -0
  154. {vgi_python-0.9.0 → vgi_python-0.10.0}/tests/conformance/test_settings.py +0 -0
  155. {vgi_python-0.9.0 → vgi_python-0.10.0}/tests/conformance/test_table.py +0 -0
  156. {vgi_python-0.9.0 → vgi_python-0.10.0}/tests/conformance/test_table_in_out.py +0 -0
  157. {vgi_python-0.9.0 → vgi_python-0.10.0}/tests/conformance/test_view.py +0 -0
  158. {vgi_python-0.9.0 → vgi_python-0.10.0}/tests/conformance/test_writable.py +0 -0
  159. {vgi_python-0.9.0 → vgi_python-0.10.0}/tests/conftest.py +0 -0
  160. {vgi_python-0.9.0 → vgi_python-0.10.0}/tests/scalar/__init__.py +0 -0
  161. {vgi_python-0.9.0 → vgi_python-0.10.0}/tests/scalar/test_bernoulli_function.py +0 -0
  162. {vgi_python-0.9.0 → vgi_python-0.10.0}/tests/scalar/test_binary_packet_function.py +0 -0
  163. {vgi_python-0.9.0 → vgi_python-0.10.0}/tests/scalar/test_client.py +0 -0
  164. {vgi_python-0.9.0 → vgi_python-0.10.0}/tests/scalar/test_conditional_message_function.py +0 -0
  165. {vgi_python-0.9.0 → vgi_python-0.10.0}/tests/scalar/test_hash_seed_function.py +0 -0
  166. {vgi_python-0.9.0 → vgi_python-0.10.0}/tests/scalar/test_multiply_by_setting_function.py +0 -0
  167. {vgi_python-0.9.0 → vgi_python-0.10.0}/tests/scalar/test_multiply_function.py +0 -0
  168. {vgi_python-0.9.0 → vgi_python-0.10.0}/tests/scalar/test_random_bytes_function.py +0 -0
  169. {vgi_python-0.9.0 → vgi_python-0.10.0}/tests/scalar/test_return_secret_value_function.py +0 -0
  170. {vgi_python-0.9.0 → vgi_python-0.10.0}/tests/table/__init__.py +0 -0
  171. {vgi_python-0.9.0 → vgi_python-0.10.0}/tests/table/generator/__init__.py +0 -0
  172. {vgi_python-0.9.0 → vgi_python-0.10.0}/tests/table/generator/test_constant_columns_function.py +0 -0
  173. {vgi_python-0.9.0 → vgi_python-0.10.0}/tests/table/generator/test_double_sequence_function.py +0 -0
  174. {vgi_python-0.9.0 → vgi_python-0.10.0}/tests/table/generator/test_exception_function.py +0 -0
  175. {vgi_python-0.9.0 → vgi_python-0.10.0}/tests/table/generator/test_filter_echo_function.py +0 -0
  176. {vgi_python-0.9.0 → vgi_python-0.10.0}/tests/table/generator/test_logging_function.py +0 -0
  177. {vgi_python-0.9.0 → vgi_python-0.10.0}/tests/table/generator/test_nested_sequence_function.py +0 -0
  178. {vgi_python-0.9.0 → vgi_python-0.10.0}/tests/table/generator/test_partitioned_function.py +0 -0
  179. {vgi_python-0.9.0 → vgi_python-0.10.0}/tests/table/generator/test_projected_data_function.py +0 -0
  180. {vgi_python-0.9.0 → vgi_python-0.10.0}/tests/table/generator/test_sequence_function.py +0 -0
  181. {vgi_python-0.9.0 → vgi_python-0.10.0}/tests/table/generator/test_settings_function.py +0 -0
  182. {vgi_python-0.9.0 → vgi_python-0.10.0}/tests/table/generator/test_struct_settings_function.py +0 -0
  183. {vgi_python-0.9.0 → vgi_python-0.10.0}/tests/table/generator/test_ten_thousand_function.py +0 -0
  184. {vgi_python-0.9.0 → vgi_python-0.10.0}/tests/table_in_out/__init__.py +0 -0
  185. {vgi_python-0.9.0 → vgi_python-0.10.0}/tests/table_in_out/generator/__init__.py +0 -0
  186. {vgi_python-0.9.0 → vgi_python-0.10.0}/tests/table_in_out/generator/test_buffer_input_function.py +0 -0
  187. {vgi_python-0.9.0 → vgi_python-0.10.0}/tests/table_in_out/generator/test_echo_function.py +0 -0
  188. {vgi_python-0.9.0 → vgi_python-0.10.0}/tests/table_in_out/generator/test_exception_functions.py +0 -0
  189. {vgi_python-0.9.0 → vgi_python-0.10.0}/tests/table_in_out/generator/test_filter_by_setting_function.py +0 -0
  190. {vgi_python-0.9.0 → vgi_python-0.10.0}/tests/table_in_out/generator/test_repeat_inputs_function.py +0 -0
  191. {vgi_python-0.9.0 → vgi_python-0.10.0}/tests/table_in_out/generator/test_sum_all_columns_function.py +0 -0
  192. {vgi_python-0.9.0 → vgi_python-0.10.0}/tests/table_in_out/test_client.py +0 -0
  193. {vgi_python-0.9.0 → vgi_python-0.10.0}/tests/test_access_log_audit.py +0 -0
  194. {vgi_python-0.9.0 → vgi_python-0.10.0}/tests/test_auth.py +0 -0
  195. {vgi_python-0.9.0 → vgi_python-0.10.0}/tests/test_bind_exceptions.py +0 -0
  196. {vgi_python-0.9.0 → vgi_python-0.10.0}/tests/test_bind_request_at_clause.py +0 -0
  197. {vgi_python-0.9.0 → vgi_python-0.10.0}/tests/test_bound_storage_conformance.py +0 -0
  198. {vgi_python-0.9.0 → vgi_python-0.10.0}/tests/test_catalog_auth_binding.py +0 -0
  199. {vgi_python-0.9.0 → vgi_python-0.10.0}/tests/test_copy_from_function.py +0 -0
  200. {vgi_python-0.9.0 → vgi_python-0.10.0}/tests/test_copy_to_function.py +0 -0
  201. {vgi_python-0.9.0 → vgi_python-0.10.0}/tests/test_docstrings.py +0 -0
  202. {vgi_python-0.9.0 → vgi_python-0.10.0}/tests/test_documentation_examples.py +0 -0
  203. {vgi_python-0.9.0 → vgi_python-0.10.0}/tests/test_example_function_arg_types.py +0 -0
  204. {vgi_python-0.9.0 → vgi_python-0.10.0}/tests/test_examples_workers.py +0 -0
  205. {vgi_python-0.9.0 → vgi_python-0.10.0}/tests/test_exception_handling.py +0 -0
  206. {vgi_python-0.9.0 → vgi_python-0.10.0}/tests/test_exceptions.py +0 -0
  207. {vgi_python-0.9.0 → vgi_python-0.10.0}/tests/test_filter_pushdown.py +0 -0
  208. {vgi_python-0.9.0 → vgi_python-0.10.0}/tests/test_filter_pushdown_extension.py +0 -0
  209. {vgi_python-0.9.0 → vgi_python-0.10.0}/tests/test_function_storage.py +0 -0
  210. {vgi_python-0.9.0 → vgi_python-0.10.0}/tests/test_function_storage_azure_sql.py +0 -0
  211. {vgi_python-0.9.0 → vgi_python-0.10.0}/tests/test_function_storage_cf_do.py +0 -0
  212. {vgi_python-0.9.0 → vgi_python-0.10.0}/tests/test_function_storage_cf_do_integration.py +0 -0
  213. {vgi_python-0.9.0 → vgi_python-0.10.0}/tests/test_function_storage_conformance.py +0 -0
  214. {vgi_python-0.9.0 → vgi_python-0.10.0}/tests/test_generated_cpp_constants.py +0 -0
  215. {vgi_python-0.9.0 → vgi_python-0.10.0}/tests/test_generated_cpp_protocol_version.py +0 -0
  216. {vgi_python-0.9.0 → vgi_python-0.10.0}/tests/test_generated_cpp_request_builders.py +0 -0
  217. {vgi_python-0.9.0 → vgi_python-0.10.0}/tests/test_generated_cpp_schemas.py +0 -0
  218. {vgi_python-0.9.0 → vgi_python-0.10.0}/tests/test_generated_cpp_secret.py +0 -0
  219. {vgi_python-0.9.0 → vgi_python-0.10.0}/tests/test_generated_go_schemas.py +0 -0
  220. {vgi_python-0.9.0 → vgi_python-0.10.0}/tests/test_generated_protocol_version.py +0 -0
  221. {vgi_python-0.9.0 → vgi_python-0.10.0}/tests/test_generated_schemas_cross_lang.py +0 -0
  222. {vgi_python-0.9.0 → vgi_python-0.10.0}/tests/test_generated_ts_client.py +0 -0
  223. {vgi_python-0.9.0 → vgi_python-0.10.0}/tests/test_generated_ts_schemas.py +0 -0
  224. {vgi_python-0.9.0 → vgi_python-0.10.0}/tests/test_http_demo_storage.py +0 -0
  225. {vgi_python-0.9.0 → vgi_python-0.10.0}/tests/test_http_s3_offload_input.py +0 -0
  226. {vgi_python-0.9.0 → vgi_python-0.10.0}/tests/test_http_s3_offload_output.py +0 -0
  227. {vgi_python-0.9.0 → vgi_python-0.10.0}/tests/test_metadata.py +0 -0
  228. {vgi_python-0.9.0 → vgi_python-0.10.0}/tests/test_mypy_consolidated.py +0 -0
  229. {vgi_python-0.9.0 → vgi_python-0.10.0}/tests/test_nest_tensor.py +0 -0
  230. {vgi_python-0.9.0 → vgi_python-0.10.0}/tests/test_otel.py +0 -0
  231. {vgi_python-0.9.0 → vgi_python-0.10.0}/tests/test_projection_enforcement.py +0 -0
  232. {vgi_python-0.9.0 → vgi_python-0.10.0}/tests/test_projection_repro.py +0 -0
  233. {vgi_python-0.9.0 → vgi_python-0.10.0}/tests/test_protocol_classes.py +0 -0
  234. {vgi_python-0.9.0 → vgi_python-0.10.0}/tests/test_resolved_secrets.py +0 -0
  235. {vgi_python-0.9.0 → vgi_python-0.10.0}/tests/test_schema_utils.py +0 -0
  236. {vgi_python-0.9.0 → vgi_python-0.10.0}/tests/test_serve.py +0 -0
  237. {vgi_python-0.9.0 → vgi_python-0.10.0}/tests/test_setting_secret_annotations.py +0 -0
  238. {vgi_python-0.9.0 → vgi_python-0.10.0}/tests/test_table_buffering_function.py +0 -0
  239. {vgi_python-0.9.0 → vgi_python-0.10.0}/tests/test_table_function_dynamic_to_string.py +0 -0
  240. {vgi_python-0.9.0 → vgi_python-0.10.0}/tests/test_tcp_transport.py +0 -0
  241. {vgi_python-0.9.0 → vgi_python-0.10.0}/tests/test_type_bounds.py +0 -0
  242. {vgi_python-0.9.0 → vgi_python-0.10.0}/tests/test_union_argument.py +0 -0
  243. {vgi_python-0.9.0 → vgi_python-0.10.0}/tests/test_worker.py +0 -0
  244. {vgi_python-0.9.0 → vgi_python-0.10.0}/tests/test_worker_cli.py +0 -0
  245. {vgi_python-0.9.0 → vgi_python-0.10.0}/tests/test_worker_page.py +0 -0
  246. {vgi_python-0.9.0 → vgi_python-0.10.0}/tests/transactor/__init__.py +0 -0
  247. {vgi_python-0.9.0 → vgi_python-0.10.0}/tests/transactor/test_transactor.py +0 -0
  248. {vgi_python-0.9.0 → vgi_python-0.10.0}/uv.lock +0 -0
  249. {vgi_python-0.9.0 → vgi_python-0.10.0}/vgi/__init__.py +0 -0
  250. {vgi_python-0.9.0 → vgi_python-0.10.0}/vgi/_duckdb.py +0 -0
  251. {vgi_python-0.9.0 → vgi_python-0.10.0}/vgi/_storage_profile.py +0 -0
  252. {vgi_python-0.9.0 → vgi_python-0.10.0}/vgi/_test_fixtures/__init__.py +0 -0
  253. {vgi_python-0.9.0 → vgi_python-0.10.0}/vgi/_test_fixtures/accumulate/__init__.py +0 -0
  254. {vgi_python-0.9.0 → vgi_python-0.10.0}/vgi/_test_fixtures/accumulate/worker.py +0 -0
  255. {vgi_python-0.9.0 → vgi_python-0.10.0}/vgi/_test_fixtures/aggregate/_common.py +0 -0
  256. {vgi_python-0.9.0 → vgi_python-0.10.0}/vgi/_test_fixtures/aggregate/basic.py +0 -0
  257. {vgi_python-0.9.0 → vgi_python-0.10.0}/vgi/_test_fixtures/aggregate/dynamic.py +0 -0
  258. {vgi_python-0.9.0 → vgi_python-0.10.0}/vgi/_test_fixtures/aggregate/generic.py +0 -0
  259. {vgi_python-0.9.0 → vgi_python-0.10.0}/vgi/_test_fixtures/aggregate/listagg.py +0 -0
  260. {vgi_python-0.9.0 → vgi_python-0.10.0}/vgi/_test_fixtures/aggregate/percentile.py +0 -0
  261. {vgi_python-0.9.0 → vgi_python-0.10.0}/vgi/_test_fixtures/aggregate/streaming.py +0 -0
  262. {vgi_python-0.9.0 → vgi_python-0.10.0}/vgi/_test_fixtures/aggregate/varargs.py +0 -0
  263. {vgi_python-0.9.0 → vgi_python-0.10.0}/vgi/_test_fixtures/aggregate/window.py +0 -0
  264. {vgi_python-0.9.0 → vgi_python-0.10.0}/vgi/_test_fixtures/attach_options.py +0 -0
  265. {vgi_python-0.9.0 → vgi_python-0.10.0}/vgi/_test_fixtures/bad_enum.py +0 -0
  266. {vgi_python-0.9.0 → vgi_python-0.10.0}/vgi/_test_fixtures/bad_protocol.py +0 -0
  267. {vgi_python-0.9.0 → vgi_python-0.10.0}/vgi/_test_fixtures/cancellable.py +0 -0
  268. {vgi_python-0.9.0 → vgi_python-0.10.0}/vgi/_test_fixtures/catalog.py +0 -0
  269. {vgi_python-0.9.0 → vgi_python-0.10.0}/vgi/_test_fixtures/copy_from.py +0 -0
  270. {vgi_python-0.9.0 → vgi_python-0.10.0}/vgi/_test_fixtures/copy_to.py +0 -0
  271. {vgi_python-0.9.0 → vgi_python-0.10.0}/vgi/_test_fixtures/http_server.py +0 -0
  272. {vgi_python-0.9.0 → vgi_python-0.10.0}/vgi/_test_fixtures/narrow_bind/__init__.py +0 -0
  273. {vgi_python-0.9.0 → vgi_python-0.10.0}/vgi/_test_fixtures/narrow_bind/worker.py +0 -0
  274. {vgi_python-0.9.0 → vgi_python-0.10.0}/vgi/_test_fixtures/nest_tensor.py +0 -0
  275. {vgi_python-0.9.0 → vgi_python-0.10.0}/vgi/_test_fixtures/orchard_catalog.py +0 -0
  276. {vgi_python-0.9.0 → vgi_python-0.10.0}/vgi/_test_fixtures/projection_repro/__init__.py +0 -0
  277. {vgi_python-0.9.0 → vgi_python-0.10.0}/vgi/_test_fixtures/projection_repro/worker.py +0 -0
  278. {vgi_python-0.9.0 → vgi_python-0.10.0}/vgi/_test_fixtures/scalar/__init__.py +0 -0
  279. {vgi_python-0.9.0 → vgi_python-0.10.0}/vgi/_test_fixtures/scalar/_common.py +0 -0
  280. {vgi_python-0.9.0 → vgi_python-0.10.0}/vgi/_test_fixtures/scalar/arithmetic.py +0 -0
  281. {vgi_python-0.9.0 → vgi_python-0.10.0}/vgi/_test_fixtures/scalar/binary.py +0 -0
  282. {vgi_python-0.9.0 → vgi_python-0.10.0}/vgi/_test_fixtures/scalar/geo.py +0 -0
  283. {vgi_python-0.9.0 → vgi_python-0.10.0}/vgi/_test_fixtures/scalar/null_handling.py +0 -0
  284. {vgi_python-0.9.0 → vgi_python-0.10.0}/vgi/_test_fixtures/scalar/random_demo.py +0 -0
  285. {vgi_python-0.9.0 → vgi_python-0.10.0}/vgi/_test_fixtures/scalar/settings_secrets.py +0 -0
  286. {vgi_python-0.9.0 → vgi_python-0.10.0}/vgi/_test_fixtures/scalar/type_info.py +0 -0
  287. {vgi_python-0.9.0 → vgi_python-0.10.0}/vgi/_test_fixtures/schema_reconcile/__init__.py +0 -0
  288. {vgi_python-0.9.0 → vgi_python-0.10.0}/vgi/_test_fixtures/schema_reconcile/worker.py +0 -0
  289. {vgi_python-0.9.0 → vgi_python-0.10.0}/vgi/_test_fixtures/simple_writable.py +0 -0
  290. {vgi_python-0.9.0 → vgi_python-0.10.0}/vgi/_test_fixtures/table/__init__.py +0 -0
  291. {vgi_python-0.9.0 → vgi_python-0.10.0}/vgi/_test_fixtures/table/_common.py +0 -0
  292. {vgi_python-0.9.0 → vgi_python-0.10.0}/vgi/_test_fixtures/table/batch_index.py +0 -0
  293. {vgi_python-0.9.0 → vgi_python-0.10.0}/vgi/_test_fixtures/table/batch_index_broken.py +0 -0
  294. {vgi_python-0.9.0 → vgi_python-0.10.0}/vgi/_test_fixtures/table/catalog_scans.py +0 -0
  295. {vgi_python-0.9.0 → vgi_python-0.10.0}/vgi/_test_fixtures/table/filters.py +0 -0
  296. {vgi_python-0.9.0 → vgi_python-0.10.0}/vgi/_test_fixtures/table/late_materialization.py +0 -0
  297. {vgi_python-0.9.0 → vgi_python-0.10.0}/vgi/_test_fixtures/table/make_series.py +0 -0
  298. {vgi_python-0.9.0 → vgi_python-0.10.0}/vgi/_test_fixtures/table/misc.py +0 -0
  299. {vgi_python-0.9.0 → vgi_python-0.10.0}/vgi/_test_fixtures/table/order_modes.py +0 -0
  300. {vgi_python-0.9.0 → vgi_python-0.10.0}/vgi/_test_fixtures/table/pairs.py +0 -0
  301. {vgi_python-0.9.0 → vgi_python-0.10.0}/vgi/_test_fixtures/table/partition_columns.py +0 -0
  302. {vgi_python-0.9.0 → vgi_python-0.10.0}/vgi/_test_fixtures/table/partition_columns_broken.py +0 -0
  303. {vgi_python-0.9.0 → vgi_python-0.10.0}/vgi/_test_fixtures/table/profiling_example.py +0 -0
  304. {vgi_python-0.9.0 → vgi_python-0.10.0}/vgi/_test_fixtures/table/required_filters.py +0 -0
  305. {vgi_python-0.9.0 → vgi_python-0.10.0}/vgi/_test_fixtures/table/sequence.py +0 -0
  306. {vgi_python-0.9.0 → vgi_python-0.10.0}/vgi/_test_fixtures/table/settings.py +0 -0
  307. {vgi_python-0.9.0 → vgi_python-0.10.0}/vgi/_test_fixtures/table/transaction_storage.py +0 -0
  308. {vgi_python-0.9.0 → vgi_python-0.10.0}/vgi/_test_fixtures/table/tt_pushdown.py +0 -0
  309. {vgi_python-0.9.0 → vgi_python-0.10.0}/vgi/_test_fixtures/table/typed_probe.py +0 -0
  310. {vgi_python-0.9.0 → vgi_python-0.10.0}/vgi/_test_fixtures/table/versioned.py +0 -0
  311. {vgi_python-0.9.0 → vgi_python-0.10.0}/vgi/_test_fixtures/versioned.py +0 -0
  312. {vgi_python-0.9.0 → vgi_python-0.10.0}/vgi/_test_fixtures/versioned_tables.py +0 -0
  313. {vgi_python-0.9.0 → vgi_python-0.10.0}/vgi/_test_fixtures/writable/__init__.py +0 -0
  314. {vgi_python-0.9.0 → vgi_python-0.10.0}/vgi/_test_fixtures/writable/generic.py +0 -0
  315. {vgi_python-0.9.0 → vgi_python-0.10.0}/vgi/_test_fixtures/writable/table.py +0 -0
  316. {vgi_python-0.9.0 → vgi_python-0.10.0}/vgi/_test_fixtures/writable/worker.py +0 -0
  317. {vgi_python-0.9.0 → vgi_python-0.10.0}/vgi/aggregate_function.py +0 -0
  318. {vgi_python-0.9.0 → vgi_python-0.10.0}/vgi/auth.py +0 -0
  319. {vgi_python-0.9.0 → vgi_python-0.10.0}/vgi/catalog/_descriptor_spec.py +0 -0
  320. {vgi_python-0.9.0 → vgi_python-0.10.0}/vgi/catalog/attach_option.py +0 -0
  321. {vgi_python-0.9.0 → vgi_python-0.10.0}/vgi/catalog/duckdb_statistics.py +0 -0
  322. {vgi_python-0.9.0 → vgi_python-0.10.0}/vgi/catalog/secret_type.py +0 -0
  323. {vgi_python-0.9.0 → vgi_python-0.10.0}/vgi/catalog/setting.py +0 -0
  324. {vgi_python-0.9.0 → vgi_python-0.10.0}/vgi/catalog/storage.py +0 -0
  325. {vgi_python-0.9.0 → vgi_python-0.10.0}/vgi/client/__init__.py +0 -0
  326. {vgi_python-0.9.0 → vgi_python-0.10.0}/vgi/client/catalog_mixin.py +0 -0
  327. {vgi_python-0.9.0 → vgi_python-0.10.0}/vgi/client/cli.py +0 -0
  328. {vgi_python-0.9.0 → vgi_python-0.10.0}/vgi/client/cli_catalog.py +0 -0
  329. {vgi_python-0.9.0 → vgi_python-0.10.0}/vgi/client/cli_schema.py +0 -0
  330. {vgi_python-0.9.0 → vgi_python-0.10.0}/vgi/client/cli_table.py +0 -0
  331. {vgi_python-0.9.0 → vgi_python-0.10.0}/vgi/client/cli_transaction.py +0 -0
  332. {vgi_python-0.9.0 → vgi_python-0.10.0}/vgi/client/cli_utils.py +0 -0
  333. {vgi_python-0.9.0 → vgi_python-0.10.0}/vgi/client/cli_view.py +0 -0
  334. {vgi_python-0.9.0 → vgi_python-0.10.0}/vgi/client/client.py +0 -0
  335. {vgi_python-0.9.0 → vgi_python-0.10.0}/vgi/codegen/__init__.py +0 -0
  336. {vgi_python-0.9.0 → vgi_python-0.10.0}/vgi/codegen/cpp_constants.py +0 -0
  337. {vgi_python-0.9.0 → vgi_python-0.10.0}/vgi/codegen/cpp_protocol_version.py +0 -0
  338. {vgi_python-0.9.0 → vgi_python-0.10.0}/vgi/codegen/cpp_request_builders.py +0 -0
  339. {vgi_python-0.9.0 → vgi_python-0.10.0}/vgi/codegen/cpp_schemas.py +0 -0
  340. {vgi_python-0.9.0 → vgi_python-0.10.0}/vgi/codegen/cpp_secret_protocol_version.py +0 -0
  341. {vgi_python-0.9.0 → vgi_python-0.10.0}/vgi/codegen/cpp_secret_request_builders.py +0 -0
  342. {vgi_python-0.9.0 → vgi_python-0.10.0}/vgi/codegen/cpp_secret_schemas.py +0 -0
  343. {vgi_python-0.9.0 → vgi_python-0.10.0}/vgi/codegen/go_schemas.py +0 -0
  344. {vgi_python-0.9.0 → vgi_python-0.10.0}/vgi/codegen/protocol_version.py +0 -0
  345. {vgi_python-0.9.0 → vgi_python-0.10.0}/vgi/codegen/ts_client.py +0 -0
  346. {vgi_python-0.9.0 → vgi_python-0.10.0}/vgi/codegen/ts_schemas.py +0 -0
  347. {vgi_python-0.9.0 → vgi_python-0.10.0}/vgi/copy_from_function.py +0 -0
  348. {vgi_python-0.9.0 → vgi_python-0.10.0}/vgi/copy_to_function.py +0 -0
  349. {vgi_python-0.9.0 → vgi_python-0.10.0}/vgi/exceptions.py +0 -0
  350. {vgi_python-0.9.0 → vgi_python-0.10.0}/vgi/function.py +0 -0
  351. {vgi_python-0.9.0 → vgi_python-0.10.0}/vgi/function_storage.py +0 -0
  352. {vgi_python-0.9.0 → vgi_python-0.10.0}/vgi/function_storage_azure_sql.py +0 -0
  353. {vgi_python-0.9.0 → vgi_python-0.10.0}/vgi/function_storage_cf_do.py +0 -0
  354. {vgi_python-0.9.0 → vgi_python-0.10.0}/vgi/http/__init__.py +0 -0
  355. {vgi_python-0.9.0 → vgi_python-0.10.0}/vgi/http/demo_storage.py +0 -0
  356. {vgi_python-0.9.0 → vgi_python-0.10.0}/vgi/http/worker_page.py +0 -0
  357. {vgi_python-0.9.0 → vgi_python-0.10.0}/vgi/invocation.py +0 -0
  358. {vgi_python-0.9.0 → vgi_python-0.10.0}/vgi/logging_config.py +0 -0
  359. {vgi_python-0.9.0 → vgi_python-0.10.0}/vgi/meta_worker.py +0 -0
  360. {vgi_python-0.9.0 → vgi_python-0.10.0}/vgi/metadata.py +0 -0
  361. {vgi_python-0.9.0 → vgi_python-0.10.0}/vgi/otel.py +0 -0
  362. {vgi_python-0.9.0 → vgi_python-0.10.0}/vgi/protocol.py +0 -0
  363. {vgi_python-0.9.0 → vgi_python-0.10.0}/vgi/protocol_version.txt +0 -0
  364. {vgi_python-0.9.0 → vgi_python-0.10.0}/vgi/py.typed +0 -0
  365. {vgi_python-0.9.0 → vgi_python-0.10.0}/vgi/schema_utils.py +0 -0
  366. {vgi_python-0.9.0 → vgi_python-0.10.0}/vgi/secret_protocol.py +0 -0
  367. {vgi_python-0.9.0 → vgi_python-0.10.0}/vgi/secret_service.py +0 -0
  368. {vgi_python-0.9.0 → vgi_python-0.10.0}/vgi/serve.py +0 -0
  369. {vgi_python-0.9.0 → vgi_python-0.10.0}/vgi/table_buffering_function.py +0 -0
  370. {vgi_python-0.9.0 → vgi_python-0.10.0}/vgi/table_filter_pushdown.py +0 -0
  371. {vgi_python-0.9.0 → vgi_python-0.10.0}/vgi/table_function.py +0 -0
  372. {vgi_python-0.9.0 → vgi_python-0.10.0}/vgi/table_in_out_function.py +0 -0
  373. {vgi_python-0.9.0 → vgi_python-0.10.0}/vgi/transactor/__init__.py +0 -0
  374. {vgi_python-0.9.0 → vgi_python-0.10.0}/vgi/transactor/_duckdb_compat.py +0 -0
  375. {vgi_python-0.9.0 → vgi_python-0.10.0}/vgi/transactor/client.py +0 -0
  376. {vgi_python-0.9.0 → vgi_python-0.10.0}/vgi/transactor/protocol.py +0 -0
  377. {vgi_python-0.9.0 → vgi_python-0.10.0}/vgi/transactor/server.py +0 -0
  378. {vgi_python-0.9.0 → vgi_python-0.10.0}/wrangler.jsonc +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: vgi-python
3
- Version: 0.9.0
3
+ Version: 0.10.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
@@ -38,6 +38,7 @@ dependencies = ["vgi-python[test-fixtures-writable]", "vgi-python[duckdb]"]
38
38
 
39
39
  [project.scripts]
40
40
  vgi-fixture-worker = "vgi._test_fixtures.worker:main"
41
+ vgi-fixture-companion-worker = "vgi._test_fixtures.companion:main"
41
42
  vgi-fixture-http = "vgi._test_fixtures.http_server:main"
42
43
  vgi-fixture-versioned-worker = "vgi._test_fixtures.versioned:main"
43
44
  vgi-fixture-versioned-tables-worker = "vgi._test_fixtures.versioned_tables:main"
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "vgi-python"
3
- version = "0.9.0"
3
+ version = "0.10.0"
4
4
  description = "Vector Gateway Interface - Connect DuckDB to external programs via Apache Arrow"
5
5
  readme = "README.md"
6
6
  keywords = [
@@ -41,8 +41,10 @@ from vgi.catalog import (
41
41
  View,
42
42
  ViewInfo,
43
43
  )
44
+ from vgi.invocation import BindResponse
44
45
  from vgi.schema_utils import schema
45
46
  from vgi.table_function import (
47
+ BindParams,
46
48
  ProcessParams,
47
49
  TableFunctionGenerator,
48
50
  bind_fixed_schema,
@@ -81,6 +83,31 @@ class UsersFunction(TableFunctionGenerator[EmptyArgs]):
81
83
  out.finish()
82
84
 
83
85
 
86
+ @init_single_worker
87
+ class SecretLookupFunction(TableFunctionGenerator[EmptyArgs]):
88
+ """Backing function whose ``on_bind`` performs a two-phase secret lookup.
89
+
90
+ This exercises the bug where ``Table(function=...)`` schema derivation took
91
+ the empty secret-scope-request schema instead of retrying the bind.
92
+ """
93
+
94
+ class Meta: # noqa: D106
95
+ name = "secret_scan"
96
+ description = "Backing function that looks up a secret at bind time"
97
+
98
+ FIXED_SCHEMA: ClassVar[pa.Schema] = schema({"id": pa.int64(), "name": pa.string()})
99
+
100
+ @classmethod
101
+ def on_bind(cls, params: BindParams[EmptyArgs]) -> BindResponse: # noqa: D102
102
+ params.secrets.get("some_secret") # unresolved -> registers a two-phase lookup
103
+ return BindResponse(output_schema=cls.FIXED_SCHEMA)
104
+
105
+ @classmethod
106
+ def process(cls, params: ProcessParams[EmptyArgs], state: None, out: OutputCollector) -> None: # noqa: D102
107
+ out.emit(pa.RecordBatch.from_pydict({"id": [1], "name": ["x"]}, schema=params.output_schema))
108
+ out.finish()
109
+
110
+
84
111
  @init_single_worker
85
112
  @bind_fixed_schema
86
113
  class EventsFunction(TableFunctionGenerator[EmptyArgs]):
@@ -186,6 +213,18 @@ class TestTableWithFunction:
186
213
  assert resolved.field(0).name == "id"
187
214
  assert resolved.field(1).name == "name"
188
215
 
216
+ def test_function_backed_table_derives_schema_despite_secret_lookup(self) -> None:
217
+ """A backing function that calls secrets.get() in on_bind still yields its schema.
218
+
219
+ Regression: on_bind's two-phase secret lookup makes the first bind return an
220
+ empty secret-scope-request schema; schema derivation must retry with resolved
221
+ secrets rather than adopt the empty schema (which produced 0-column tables).
222
+ """
223
+ table = Table(name="things", function=SecretLookupFunction)
224
+ resolved = table.resolved_columns
225
+ assert [f.name for f in resolved] == ["id", "name"]
226
+ assert len(resolved) == 2
227
+
189
228
  def test_table_function_backed_with_constraints(self) -> None:
190
229
  """Function-backed table can have constraints validated."""
191
230
  table = Table(
@@ -336,7 +375,6 @@ class TestTableWithFunction:
336
375
  from typing import Any as _Any
337
376
 
338
377
  from vgi.invocation import BindResponse
339
- from vgi.table_function import BindParams
340
378
 
341
379
  @init_single_worker
342
380
  class _ManualBindFn(TableFunctionGenerator[EmptyArgs]):
@@ -1110,7 +1110,7 @@ class TestArrowSchemaCorrectness:
1110
1110
  def test_catalog_attach_result_schema(self) -> None:
1111
1111
  """Verify CatalogAttachResult Arrow schema."""
1112
1112
  schema = CatalogAttachResult.ARROW_SCHEMA
1113
- assert len(schema) == 14
1113
+ assert len(schema) == 15
1114
1114
  assert schema.field("attach_opaque_data").type == pa.binary()
1115
1115
  assert schema.field("supports_transactions").type == pa.bool_()
1116
1116
  assert schema.field("supports_time_travel").type == pa.bool_()
@@ -1120,6 +1120,7 @@ class TestArrowSchemaCorrectness:
1120
1120
  assert schema.field("default_schema").type == pa.string()
1121
1121
  assert schema.field("settings").type == pa.list_(pa.binary())
1122
1122
  assert schema.field("secret_types").type == pa.list_(pa.binary())
1123
+ assert schema.field("attach_catalogs").type == pa.list_(pa.binary())
1123
1124
  assert schema.field("resolved_data_version").type == pa.string()
1124
1125
  assert schema.field("resolved_implementation_version").type == pa.string()
1125
1126
 
@@ -0,0 +1,69 @@
1
+ # Copyright 2025, 2026 Query Farm LLC - https://query.farm
2
+
3
+ """Conformance test: ConstParam value constraints are enforced at bind.
4
+
5
+ A ``ConstParam`` may declare ``choices``/``ge``/``le``/``gt``/``lt``/``pattern``.
6
+ Those are surfaced for agent discovery (via ``vgi_function_arguments()``) AND
7
+ must be enforced: a const value that violates a declared constraint fails at
8
+ bind with ``ArgumentValidationError``, rather than silently reaching
9
+ ``compute()``. This mirrors the legacy ``Arg`` descriptor path.
10
+ """
11
+
12
+ from __future__ import annotations
13
+
14
+ from typing import Annotated
15
+
16
+ import pyarrow as pa
17
+ import pytest
18
+
19
+ from vgi.arguments import Arguments, ArgumentValidationError, ConstParam, Param, Returns
20
+ from vgi.protocol import BindRequest, FunctionType
21
+ from vgi.scalar_function import BindResult, ScalarFunction
22
+
23
+
24
+ class _Measure(ScalarFunction):
25
+ class Meta:
26
+ name = "measure"
27
+
28
+ @classmethod
29
+ def on_bind(cls, params: object) -> BindResult:
30
+ return BindResult(pa.string())
31
+
32
+ @classmethod
33
+ def compute(
34
+ cls,
35
+ unit: Annotated[str, ConstParam("Output unit", choices=["mm", "cm", "m"])],
36
+ precision: Annotated[int, ConstParam("Decimals", ge=0, le=10)],
37
+ value: Annotated[pa.DoubleArray, Param(doc="Value")],
38
+ ) -> Annotated[pa.StringArray, Returns()]:
39
+ return pa.array([str(value)], type=pa.string())
40
+
41
+
42
+ def _bind(unit: str, precision: int) -> None:
43
+ _Measure.bind(
44
+ BindRequest(
45
+ function_name="measure",
46
+ arguments=Arguments(positional=(pa.scalar(unit), pa.scalar(precision))),
47
+ function_type=FunctionType.SCALAR,
48
+ input_schema=pa.schema([("value", pa.float64())]),
49
+ )
50
+ )
51
+
52
+
53
+ def test_valid_const_values_bind() -> None:
54
+ """A const value inside every declared constraint binds cleanly."""
55
+ _bind("cm", 2)
56
+
57
+
58
+ def test_choice_violation_raises_at_bind() -> None:
59
+ """A const value outside the choice set fails at bind."""
60
+ with pytest.raises(ArgumentValidationError) as exc:
61
+ _bind("xx", 2)
62
+ assert "unit" in str(exc.value)
63
+
64
+
65
+ def test_range_violation_raises_at_bind() -> None:
66
+ """A const value outside the numeric range fails at bind."""
67
+ with pytest.raises(ArgumentValidationError) as exc:
68
+ _bind("cm", 99)
69
+ assert "precision" in str(exc.value)
@@ -0,0 +1,17 @@
1
+ # Copyright 2025, 2026 Query Farm LLC - https://query.farm
2
+
3
+ """Conformance stub for ``vgi/test/sql/integration/container/``."""
4
+
5
+ from __future__ import annotations
6
+
7
+ from tests.conformance._stub import skip_area
8
+
9
+ skip_area(
10
+ "container",
11
+ [
12
+ "errors.test",
13
+ "shared_http.test",
14
+ "shared_tcp.test",
15
+ "sklearn_smoke.test",
16
+ ],
17
+ )
@@ -0,0 +1,16 @@
1
+ # Copyright 2025, 2026 Query Farm LLC - https://query.farm
2
+
3
+ """Conformance stub for ``vgi/test/sql/integration/copy_from/``."""
4
+
5
+ from __future__ import annotations
6
+
7
+ from tests.conformance._stub import skip_area
8
+
9
+ skip_area(
10
+ "copy_from",
11
+ [
12
+ "basic.test",
13
+ "options.test",
14
+ "secrets.test",
15
+ ],
16
+ )
@@ -0,0 +1,21 @@
1
+ # Copyright 2025, 2026 Query Farm LLC - https://query.farm
2
+
3
+ """Conformance stub for ``vgi/test/sql/integration/copy_to/``."""
4
+
5
+ from __future__ import annotations
6
+
7
+ from tests.conformance._stub import skip_area
8
+
9
+ skip_area(
10
+ "copy_to",
11
+ [
12
+ "basic.test",
13
+ "failure.test",
14
+ "options.test",
15
+ "ordered.test",
16
+ "parallel.test",
17
+ "secrets.test",
18
+ "tmp_file.test",
19
+ "types.test",
20
+ ],
21
+ )
@@ -0,0 +1,15 @@
1
+ # Copyright 2025, 2026 Query Farm LLC - https://query.farm
2
+
3
+ """Conformance stub for ``vgi/test/sql/integration/github/``."""
4
+
5
+ from __future__ import annotations
6
+
7
+ from tests.conformance._stub import skip_area
8
+
9
+ skip_area(
10
+ "github",
11
+ [
12
+ "download.test",
13
+ "errors.test",
14
+ ],
15
+ )
@@ -9,10 +9,13 @@ from tests.conformance._stub import skip_area
9
9
  skip_area(
10
10
  "secret",
11
11
  [
12
+ "secret_aggregate.test",
13
+ "secret_function_backed_table.test",
12
14
  "secret_no_secret.test",
13
15
  "secret_registration.test",
14
16
  "secret_scalar.test",
15
17
  "secret_scoped.test",
16
18
  "secret_table_function.test",
19
+ "secret_table_in_out.test",
17
20
  ],
18
21
  )
@@ -13,7 +13,14 @@ import pytest
13
13
  from vgi_rpc import ArrowSerializableDataclass, ArrowType
14
14
 
15
15
  from vgi.aggregate_function import AggregateFunction
16
- from vgi.arguments import ConstParam, Param, Returns
16
+ from vgi.arguments import (
17
+ Arguments,
18
+ ArgumentValidationError,
19
+ ConstParam,
20
+ Param,
21
+ Returns,
22
+ validate_const_arg_constraints,
23
+ )
17
24
  from vgi.table_function import ProcessParams
18
25
 
19
26
  # ---------------------------------------------------------------------------
@@ -199,6 +206,49 @@ class TestInitSubclassParameterExtraction:
199
206
  assert arg.arrow_type == pa.float64()
200
207
  assert arg.const is True
201
208
 
209
+ def test_const_param_constraints_enforced(self) -> None:
210
+ """A ConstParam's declared constraints are enforced at bind (same as scalar)."""
211
+
212
+ class BoundedAgg(AggregateFunction[SimpleState]):
213
+ class Meta:
214
+ name = "test_bounded_agg"
215
+
216
+ @classmethod
217
+ def initial_state(cls, params: ProcessParams[Any]) -> SimpleState:
218
+ return SimpleState()
219
+
220
+ @classmethod
221
+ def update(
222
+ cls,
223
+ states: dict[int, SimpleState],
224
+ group_ids: pa.Int64Array,
225
+ value: Annotated[pa.DoubleArray, Param(doc="Values")],
226
+ mode: Annotated[str, ConstParam("Mode", choices=["min", "max"])] = "min",
227
+ ) -> None:
228
+ pass
229
+
230
+ @classmethod
231
+ def combine(cls, source: SimpleState, target: SimpleState, params: ProcessParams[Any]) -> SimpleState:
232
+ return SimpleState()
233
+
234
+ @classmethod
235
+ def finalize(
236
+ cls,
237
+ group_ids: pa.Int64Array,
238
+ states: dict[int, SimpleState],
239
+ params: ProcessParams[Any],
240
+ ) -> Annotated[pa.RecordBatch, Returns(pa.float64())]:
241
+ return pa.record_batch({"result": pa.array([], type=pa.float64())})
242
+
243
+ # The ConstParam carries its choices (threaded via _const_param_to_arg)...
244
+ const_params = BoundedAgg._const_params
245
+ assert const_params["mode"].choices == ["min", "max"]
246
+ # ...and the shared bind-time validator (called by aggregate_bind) enforces it.
247
+ validate_const_arg_constraints(const_params, Arguments(positional=(pa.scalar("max"),)))
248
+ with pytest.raises(ArgumentValidationError) as exc:
249
+ validate_const_arg_constraints(const_params, Arguments(positional=(pa.scalar("median"),)))
250
+ assert "mode" in str(exc.value)
251
+
202
252
  def test_const_param_phases(self) -> None:
203
253
  """ConstParam phase values are stored correctly."""
204
254
 
@@ -12,13 +12,18 @@ import pytest
12
12
  from vgi.argument_spec import (
13
13
  VGI_ARG_KEY,
14
14
  VGI_ARG_NAMED,
15
+ VGI_CHOICES_KEY,
16
+ VGI_DEFAULT_KEY,
15
17
  VGI_DOC_KEY,
18
+ VGI_PATTERN_KEY,
19
+ VGI_RANGE_KEY,
16
20
  VGI_TYPE_ANY,
17
21
  VGI_TYPE_KEY,
18
22
  VGI_TYPE_TABLE,
19
23
  VGI_VARARGS_KEY,
20
24
  VGI_VARARGS_TRUE,
21
25
  ArgumentSpec,
26
+ _format_range,
22
27
  argument_specs_to_schema,
23
28
  extract_argument_specs,
24
29
  schema_to_argument_specs,
@@ -722,3 +727,99 @@ class TestArgumentDoc:
722
727
  specs = {s.name: s for s in extract_argument_specs(FunctionWithDocs)}
723
728
  assert specs["unit"].doc == "Unit string, e.g. 'mi'"
724
729
  assert specs["scale"].doc == ""
730
+
731
+
732
+ class TestArgumentConstraints:
733
+ """Per-argument constraint metadata (choices / range / pattern / default)."""
734
+
735
+ def test_format_range_notation(self) -> None:
736
+ """Interval notation covers inclusive, exclusive, open, and empty bounds."""
737
+ assert _format_range(0, 100, None, None) == "[0, 100]"
738
+ assert _format_range(None, None, 0, None) == "(0, +inf)"
739
+ assert _format_range(1, None, None, 10) == "[1, 10)"
740
+ assert _format_range(None, 5, None, None) == "(-inf, 5]"
741
+ assert _format_range(None, None, None, None) is None
742
+
743
+ def test_writer_emits_constraint_keys(self) -> None:
744
+ """A constrained spec writes value-encoded constraint metadata keys."""
745
+ spec = ArgumentSpec(
746
+ name="unit",
747
+ position="unit",
748
+ arrow_type=pa.utf8(),
749
+ default_json='"mm"',
750
+ choices_json='["mm", "cm", "m"]',
751
+ range_notation="[0, 100]",
752
+ pattern="^[A-Z]{2}$",
753
+ )
754
+ meta = argument_specs_to_schema([spec])[0].metadata
755
+ assert meta[VGI_DEFAULT_KEY] == b'"mm"'
756
+ assert meta[VGI_CHOICES_KEY] == b'["mm", "cm", "m"]'
757
+ assert meta[VGI_RANGE_KEY] == b"[0, 100]"
758
+ assert meta[VGI_PATTERN_KEY] == b"^[A-Z]{2}$"
759
+
760
+ def test_unconstrained_arg_omits_keys(self) -> None:
761
+ """An arg without constraints yields none of the constraint keys."""
762
+ meta = argument_specs_to_schema([ArgumentSpec(name="v", position=0, arrow_type=pa.int64())])[0].metadata
763
+ for key in (VGI_DEFAULT_KEY, VGI_CHOICES_KEY, VGI_RANGE_KEY, VGI_PATTERN_KEY):
764
+ assert meta is None or key not in meta
765
+
766
+ def test_constraints_round_trip(self) -> None:
767
+ """Constraint metadata survives the schema round-trip."""
768
+ spec = ArgumentSpec(
769
+ name="mode",
770
+ position="mode",
771
+ arrow_type=pa.utf8(),
772
+ default_json='"add"',
773
+ choices_json='["add", "mul"]',
774
+ range_notation="[0, 10)",
775
+ pattern="^x+$",
776
+ )
777
+ out = schema_to_argument_specs(argument_specs_to_schema([spec]))[0]
778
+ assert out.default_json == '"add"'
779
+ assert out.choices_json == '["add", "mul"]'
780
+ assert out.range_notation == "[0, 10)"
781
+ assert out.pattern == "^x+$"
782
+
783
+ def test_extract_constraints_from_arg(self) -> None:
784
+ """extract_argument_specs reads choices/default/bounds/pattern off Arg."""
785
+
786
+ class FunctionWithConstraints(TableInOutFunction): # type: ignore[type-arg]
787
+ mode: str = Arg[str]( # type: ignore[assignment]
788
+ "mode", doc="Blend mode", choices=["add", "mul"], default="add"
789
+ )
790
+ level: int = Arg[int](0, ge=1, le=10) # type: ignore[assignment]
791
+ code: str = Arg[str](1, pattern="^[A-Z]{2}$") # type: ignore[assignment]
792
+
793
+ specs = {s.name: s for s in extract_argument_specs(FunctionWithConstraints)}
794
+ assert specs["mode"].choices_json == '["add", "mul"]'
795
+ assert specs["mode"].default_json == '"add"'
796
+ assert specs["level"].range_notation == "[1, 10]"
797
+ assert specs["code"].pattern == "^[A-Z]{2}$"
798
+
799
+ def test_const_param_constraints_surface(self) -> None:
800
+ """The modern Param/ConstParam API surfaces choices / range / pattern."""
801
+ from vgi.arguments import ConstParam, Param, Returns
802
+ from vgi.scalar_function import ScalarFunction
803
+
804
+ class ConstrainedScalar(ScalarFunction):
805
+ class Meta:
806
+ name = "constrained_scalar"
807
+ description = "constraint demo"
808
+
809
+ @classmethod
810
+ def compute(
811
+ cls,
812
+ unit: Annotated[str, ConstParam("Output unit", choices=["mm", "cm", "m"])],
813
+ precision: Annotated[int, ConstParam("Decimals", ge=0, le=10)],
814
+ code: Annotated[str, ConstParam("Label code", pattern="^[A-Z]{2}$")],
815
+ value: Annotated[pa.DoubleArray, Param(doc="Value")],
816
+ ) -> Annotated[pa.StringArray, Returns()]:
817
+ return value # never executed — the test only reads arg specs
818
+
819
+ specs = {s.name: s for s in extract_argument_specs(ConstrainedScalar)}
820
+ assert specs["unit"].choices_json == '["mm", "cm", "m"]'
821
+ assert specs["precision"].range_notation == "[0, 10]"
822
+ assert specs["code"].pattern == "^[A-Z]{2}$"
823
+ # The columnar Param carries no constraints.
824
+ assert specs["value"].choices_json is None
825
+ assert specs["value"].range_notation is None
@@ -32,6 +32,7 @@ from vgi._test_fixtures.aggregate.dynamic import (
32
32
  from vgi._test_fixtures.aggregate.generic import GenericSumFunction
33
33
  from vgi._test_fixtures.aggregate.listagg import ListAggFunction
34
34
  from vgi._test_fixtures.aggregate.percentile import PercentileFunction
35
+ from vgi._test_fixtures.aggregate.secret_typed import SecretTypedSumFunction
35
36
  from vgi._test_fixtures.aggregate.streaming import StreamingSumFunction
36
37
  from vgi._test_fixtures.aggregate.varargs import SumAllFunction
37
38
  from vgi._test_fixtures.aggregate.window import (
@@ -50,6 +51,7 @@ __all__ = [
50
51
  "ListAggFunction",
51
52
  "ListAggState",
52
53
  "PercentileFunction",
54
+ "SecretTypedSumFunction",
53
55
  "StreamingSumFunction",
54
56
  "SumAllFunction",
55
57
  "SumFunction",
@@ -0,0 +1,115 @@
1
+ # Copyright 2025, 2026 Query Farm LLC - https://query.farm
2
+
3
+ """Secret-aware aggregate fixture (secret_typed_sum).
4
+
5
+ Demonstrates the *supported* aggregate x secret intersection: an aggregate
6
+ reads a statically-resolved secret in ``on_bind`` (declared via the ``Secret()``
7
+ annotation, so the C++ extension resolves it up front and delivers it on
8
+ ``AggregateBindRequest.secrets``) and uses a secret *value* to shape its output
9
+ type. The aggregated value itself is computed normally in ``update`` /
10
+ ``finalize``.
11
+
12
+ Boundary (intentional, see ``vgi.worker.aggregate_bind``): secret *values* are
13
+ only available at bind time. ``aggregate_update`` / ``aggregate_finalize``
14
+ receive an empty ``ResolvedSecrets`` (persisting secrets to shared aggregate
15
+ storage would leak them), and a two-phase ``params.secrets.get()`` inside an
16
+ aggregate's ``on_bind`` raises ``NotImplementedError``. This fixture therefore
17
+ resolves the secret statically and threads the bind-time decision to
18
+ ``finalize`` via the output schema (which round-trips bind -> finalize).
19
+ """
20
+
21
+ from __future__ import annotations
22
+
23
+ from typing import Annotated, Any
24
+
25
+ import pyarrow as pa
26
+
27
+ from vgi._test_fixtures.aggregate._common import SumState
28
+ from vgi.aggregate_function import AggregateBindParams, AggregateFunction
29
+ from vgi.arguments import Param, Returns, Secret
30
+ from vgi.invocation import BindResponse
31
+ from vgi.metadata import FunctionExample
32
+ from vgi.schema_utils import schema
33
+ from vgi.table_function import ProcessParams
34
+
35
+
36
+ class SecretTypedSumFunction(AggregateFunction[SumState]):
37
+ """Sum an integer column, choosing the result type from a secret.
38
+
39
+ ``on_bind`` reads the ``vgi_example`` secret (resolved statically by the C++
40
+ extension). When the secret's ``use_ssl`` field is true the aggregate returns
41
+ the sum as ``DOUBLE``; otherwise as ``BIGINT``. This proves the secret's
42
+ *value* was delivered to the aggregate's bind — an aggregate that never
43
+ declared a secret could not vary its output type this way.
44
+
45
+ SQL: ``SELECT secret_typed_sum(n) FROM t GROUP BY g``
46
+ """
47
+
48
+ class Meta:
49
+ name = "secret_typed_sum"
50
+ description = "Sum an integer column; the result type is chosen from a secret"
51
+ categories = ["aggregate", "secret"]
52
+ examples = [
53
+ FunctionExample(
54
+ sql="SELECT secret_typed_sum(n) FROM (SELECT 1 AS n UNION ALL SELECT 2)",
55
+ description="Sum a column with the result type selected by the vgi_example secret",
56
+ ),
57
+ ]
58
+
59
+ @classmethod
60
+ def on_bind(
61
+ cls,
62
+ params: AggregateBindParams,
63
+ *,
64
+ vgi_example: Annotated[dict[str, pa.Scalar[Any]] | None, Secret("vgi_example")] = None,
65
+ **kwargs: Any,
66
+ ) -> BindResponse:
67
+ """Choose the result type from the statically-resolved secret.
68
+
69
+ The ``Secret()`` annotation advertises the requirement so the extension
70
+ pre-resolves the secret and delivers it on the bind request (keyed by the
71
+ DuckDB secret *name*). ``to_dict().of_type()`` matches it by the secret's
72
+ connector-serialized ``type`` field — no ``get()`` (which would register a
73
+ pending lookup and trigger the unsupported two-phase retry).
74
+ """
75
+ secret = next(iter(params.secrets.to_dict().of_type("vgi_example")), {})
76
+ use_ssl = secret.get("use_ssl")
77
+ as_double = bool(use_ssl.as_py()) if use_ssl is not None else False
78
+ result_type = pa.float64() if as_double else pa.int64()
79
+ return BindResponse(output_schema=schema(result=result_type))
80
+
81
+ @classmethod
82
+ def initial_state(cls, params: ProcessParams[None]) -> SumState:
83
+ """Identity element for the sum."""
84
+ return SumState(total=0)
85
+
86
+ @classmethod
87
+ def update(
88
+ cls,
89
+ states: dict[int, SumState],
90
+ group_ids: pa.Int64Array,
91
+ value: Annotated[pa.Int64Array, Param(doc="Integer column to sum")],
92
+ ) -> None:
93
+ """Accumulate integer values into per-group totals."""
94
+ for i in range(len(group_ids)):
95
+ gid: int = group_ids[i].as_py()
96
+ v = value[i].as_py()
97
+ if v is not None:
98
+ states[gid] = SumState(total=states[gid].total + v)
99
+
100
+ @classmethod
101
+ def combine(cls, source: SumState, target: SumState, params: ProcessParams[None]) -> SumState:
102
+ """Merge two partial sums."""
103
+ return SumState(total=target.total + source.total)
104
+
105
+ @classmethod
106
+ def finalize(
107
+ cls,
108
+ group_ids: pa.Int64Array,
109
+ states: dict[int, SumState],
110
+ params: ProcessParams[None],
111
+ ) -> Annotated[pa.RecordBatch, Returns()]:
112
+ """Emit each group's sum, cast to the bind-time (secret-chosen) type."""
113
+ result_field = params.output_schema.field(0)
114
+ results = [s.total if (s := states[gid.as_py()]) is not None else None for gid in group_ids]
115
+ return pa.record_batch({result_field.name: pa.array(results, type=result_field.type)})