vgi-python 0.23.0__tar.gz → 0.25.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 (408) hide show
  1. {vgi_python-0.23.0 → vgi_python-0.25.0}/.github/workflows/ci.yml +5 -5
  2. {vgi_python-0.23.0 → vgi_python-0.25.0}/.github/workflows/docs.yml +1 -1
  3. {vgi_python-0.23.0 → vgi_python-0.25.0}/.github/workflows/integration.yml +4 -4
  4. {vgi_python-0.23.0 → vgi_python-0.25.0}/CLAUDE.md +96 -0
  5. {vgi_python-0.23.0 → vgi_python-0.25.0}/PKG-INFO +6 -3
  6. vgi_python-0.25.0/docs/global-functions.md +88 -0
  7. {vgi_python-0.23.0 → vgi_python-0.25.0}/pyproject.toml +13 -3
  8. {vgi_python-0.23.0 → vgi_python-0.25.0}/tests/catalog/test_declarative.py +148 -0
  9. {vgi_python-0.23.0 → vgi_python-0.25.0}/tests/catalog/test_serialization.py +3 -1
  10. {vgi_python-0.23.0 → vgi_python-0.25.0}/tests/conformance/test_directory_parity.py +13 -0
  11. {vgi_python-0.23.0 → vgi_python-0.25.0}/tests/conformance/test_protocol_version.py +3 -3
  12. {vgi_python-0.23.0 → vgi_python-0.25.0}/tests/landing/describe.expected.json +39 -1
  13. vgi_python-0.25.0/tests/table/test_wide_columns.py +84 -0
  14. vgi_python-0.25.0/tests/test_call_state_attach.py +346 -0
  15. {vgi_python-0.23.0 → vgi_python-0.25.0}/tests/test_protocol_classes.py +90 -0
  16. {vgi_python-0.23.0 → vgi_python-0.25.0}/tests/test_serve.py +197 -0
  17. {vgi_python-0.23.0 → vgi_python-0.25.0}/tests/test_setting_secret_annotations.py +47 -2
  18. vgi_python-0.25.0/tests/test_signing_key.py +96 -0
  19. vgi_python-0.25.0/tests/test_worker_cli.py +200 -0
  20. {vgi_python-0.23.0 → vgi_python-0.25.0}/uv.lock +164 -32
  21. vgi_python-0.25.0/vgi/_test_fixtures/global_functions.py +316 -0
  22. {vgi_python-0.23.0 → vgi_python-0.25.0}/vgi/_test_fixtures/http_server.py +9 -0
  23. {vgi_python-0.23.0 → vgi_python-0.25.0}/vgi/_test_fixtures/table/_common.py +46 -3
  24. vgi_python-0.25.0/vgi/_test_fixtures/table/wide.py +113 -0
  25. {vgi_python-0.23.0 → vgi_python-0.25.0}/vgi/_test_fixtures/worker.py +27 -0
  26. {vgi_python-0.23.0 → vgi_python-0.25.0}/vgi/auth.py +13 -1
  27. {vgi_python-0.23.0 → vgi_python-0.25.0}/vgi/catalog/catalog_interface.py +39 -0
  28. {vgi_python-0.23.0 → vgi_python-0.25.0}/vgi/catalog/descriptors.py +79 -0
  29. {vgi_python-0.23.0 → vgi_python-0.25.0}/vgi/function.py +54 -0
  30. {vgi_python-0.23.0 → vgi_python-0.25.0}/vgi/function_storage.py +71 -1
  31. vgi_python-0.25.0/vgi/logging_config.py +319 -0
  32. {vgi_python-0.23.0 → vgi_python-0.25.0}/vgi/meta_worker.py +31 -0
  33. {vgi_python-0.23.0 → vgi_python-0.25.0}/vgi/protocol.py +261 -110
  34. vgi_python-0.25.0/vgi/protocol_version.txt +1 -0
  35. {vgi_python-0.23.0 → vgi_python-0.25.0}/vgi/serve.py +562 -18
  36. {vgi_python-0.23.0 → vgi_python-0.25.0}/vgi/table_function.py +147 -53
  37. {vgi_python-0.23.0 → vgi_python-0.25.0}/vgi/worker.py +221 -15
  38. vgi_python-0.23.0/tests/test_worker_cli.py +0 -112
  39. vgi_python-0.23.0/vgi/logging_config.py +0 -161
  40. vgi_python-0.23.0/vgi/protocol_version.txt +0 -1
  41. {vgi_python-0.23.0 → vgi_python-0.25.0}/.gitattributes +0 -0
  42. {vgi_python-0.23.0 → vgi_python-0.25.0}/.github/dependabot.yml +0 -0
  43. {vgi_python-0.23.0 → vgi_python-0.25.0}/.github/styles/config/vocabularies/VGI/accept.txt +0 -0
  44. {vgi_python-0.23.0 → vgi_python-0.25.0}/.github/workflows/release.yml +0 -0
  45. {vgi_python-0.23.0 → vgi_python-0.25.0}/.gitignore +0 -0
  46. {vgi_python-0.23.0 → vgi_python-0.25.0}/.python-version +0 -0
  47. {vgi_python-0.23.0 → vgi_python-0.25.0}/.vale.ini +0 -0
  48. {vgi_python-0.23.0 → vgi_python-0.25.0}/DOCS_ACCEPTANCE_CRITERIA.md +0 -0
  49. {vgi_python-0.23.0 → vgi_python-0.25.0}/DOCS_REVIEW_RUBRIC.md +0 -0
  50. {vgi_python-0.23.0 → vgi_python-0.25.0}/DOCS_USABILITY_TEST.md +0 -0
  51. {vgi_python-0.23.0 → vgi_python-0.25.0}/LICENSE +0 -0
  52. {vgi_python-0.23.0 → vgi_python-0.25.0}/README.md +0 -0
  53. {vgi_python-0.23.0 → vgi_python-0.25.0}/SECURITY.md +0 -0
  54. {vgi_python-0.23.0 → vgi_python-0.25.0}/ci/README.md +0 -0
  55. {vgi_python-0.23.0 → vgi_python-0.25.0}/ci/preprocess-require.awk +0 -0
  56. {vgi_python-0.23.0 → vgi_python-0.25.0}/ci/run-integration.sh +0 -0
  57. {vgi_python-0.23.0 → vgi_python-0.25.0}/dist-vgi/.gitignore +0 -0
  58. {vgi_python-0.23.0 → vgi_python-0.25.0}/docs/aggregate-functions.md +0 -0
  59. {vgi_python-0.23.0 → vgi_python-0.25.0}/docs/api/arguments.md +0 -0
  60. {vgi_python-0.23.0 → vgi_python-0.25.0}/docs/api/auth.md +0 -0
  61. {vgi_python-0.23.0 → vgi_python-0.25.0}/docs/api/catalogs.md +0 -0
  62. {vgi_python-0.23.0 → vgi_python-0.25.0}/docs/api/client.md +0 -0
  63. {vgi_python-0.23.0 → vgi_python-0.25.0}/docs/api/exceptions.md +0 -0
  64. {vgi_python-0.23.0 → vgi_python-0.25.0}/docs/api/filters.md +0 -0
  65. {vgi_python-0.23.0 → vgi_python-0.25.0}/docs/api/functions.md +0 -0
  66. {vgi_python-0.23.0 → vgi_python-0.25.0}/docs/api/http.md +0 -0
  67. {vgi_python-0.23.0 → vgi_python-0.25.0}/docs/api/index.md +0 -0
  68. {vgi_python-0.23.0 → vgi_python-0.25.0}/docs/api/metadata.md +0 -0
  69. {vgi_python-0.23.0 → vgi_python-0.25.0}/docs/api/observability.md +0 -0
  70. {vgi_python-0.23.0 → vgi_python-0.25.0}/docs/api/storage.md +0 -0
  71. {vgi_python-0.23.0 → vgi_python-0.25.0}/docs/api/transactor.md +0 -0
  72. {vgi_python-0.23.0 → vgi_python-0.25.0}/docs/api/worker.md +0 -0
  73. {vgi_python-0.23.0 → vgi_python-0.25.0}/docs/argument-serialization.md +0 -0
  74. {vgi_python-0.23.0 → vgi_python-0.25.0}/docs/assets/apple-touch-icon.png +0 -0
  75. {vgi_python-0.23.0 → vgi_python-0.25.0}/docs/assets/favicon-16x16.png +0 -0
  76. {vgi_python-0.23.0 → vgi_python-0.25.0}/docs/assets/favicon-32x32.png +0 -0
  77. {vgi_python-0.23.0 → vgi_python-0.25.0}/docs/assets/favicon.ico +0 -0
  78. {vgi_python-0.23.0 → vgi_python-0.25.0}/docs/assets/kinds/aggregate.svg +0 -0
  79. {vgi_python-0.23.0 → vgi_python-0.25.0}/docs/assets/kinds/buffering.svg +0 -0
  80. {vgi_python-0.23.0 → vgi_python-0.25.0}/docs/assets/kinds/scalar.svg +0 -0
  81. {vgi_python-0.23.0 → vgi_python-0.25.0}/docs/assets/kinds/table-in-out.svg +0 -0
  82. {vgi_python-0.23.0 → vgi_python-0.25.0}/docs/assets/kinds/table.svg +0 -0
  83. {vgi_python-0.23.0 → vgi_python-0.25.0}/docs/assets/logo.png +0 -0
  84. {vgi_python-0.23.0 → vgi_python-0.25.0}/docs/assets/social-card.png +0 -0
  85. {vgi_python-0.23.0 → vgi_python-0.25.0}/docs/authentication.md +0 -0
  86. {vgi_python-0.23.0 → vgi_python-0.25.0}/docs/catalog-interface.md +0 -0
  87. {vgi_python-0.23.0 → vgi_python-0.25.0}/docs/cli.md +0 -0
  88. {vgi_python-0.23.0 → vgi_python-0.25.0}/docs/column-statistics.md +0 -0
  89. {vgi_python-0.23.0 → vgi_python-0.25.0}/docs/concepts/index.md +0 -0
  90. {vgi_python-0.23.0 → vgi_python-0.25.0}/docs/contributing-docs.md +0 -0
  91. {vgi_python-0.23.0 → vgi_python-0.25.0}/docs/filter-pushdown.md +0 -0
  92. {vgi_python-0.23.0 → vgi_python-0.25.0}/docs/generator-api.md +0 -0
  93. {vgi_python-0.23.0 → vgi_python-0.25.0}/docs/how-to/catalogs.md +0 -0
  94. {vgi_python-0.23.0 → vgi_python-0.25.0}/docs/how-to/function-patterns.md +0 -0
  95. {vgi_python-0.23.0 → vgi_python-0.25.0}/docs/how-to/http-auth.md +0 -0
  96. {vgi_python-0.23.0 → vgi_python-0.25.0}/docs/how-to/index.md +0 -0
  97. {vgi_python-0.23.0 → vgi_python-0.25.0}/docs/how-to/pushdown-and-statistics.md +0 -0
  98. {vgi_python-0.23.0 → vgi_python-0.25.0}/docs/how-to/state-storage.md +0 -0
  99. {vgi_python-0.23.0 → vgi_python-0.25.0}/docs/index.md +0 -0
  100. {vgi_python-0.23.0 → vgi_python-0.25.0}/docs/lifecycle.md +0 -0
  101. {vgi_python-0.23.0 → vgi_python-0.25.0}/docs/metadata.md +0 -0
  102. {vgi_python-0.23.0 → vgi_python-0.25.0}/docs/overrides/main.html +0 -0
  103. {vgi_python-0.23.0 → vgi_python-0.25.0}/docs/robots.txt +0 -0
  104. {vgi_python-0.23.0 → vgi_python-0.25.0}/docs/shared-storage.md +0 -0
  105. {vgi_python-0.23.0 → vgi_python-0.25.0}/docs/stylesheets/extra.css +0 -0
  106. {vgi_python-0.23.0 → vgi_python-0.25.0}/docs/tutorial/index.md +0 -0
  107. {vgi_python-0.23.0 → vgi_python-0.25.0}/docs/tutorial/scalar.md +0 -0
  108. {vgi_python-0.23.0 → vgi_python-0.25.0}/docs/tutorial/table.md +0 -0
  109. {vgi_python-0.23.0 → vgi_python-0.25.0}/docs/vgi-logo.png +0 -0
  110. {vgi_python-0.23.0 → vgi_python-0.25.0}/examples/calc_scalar_worker.py +0 -0
  111. {vgi_python-0.23.0 → vgi_python-0.25.0}/examples/calc_worker.py +0 -0
  112. {vgi_python-0.23.0 → vgi_python-0.25.0}/examples/filter_worker.py +0 -0
  113. {vgi_python-0.23.0 → vgi_python-0.25.0}/examples/greeting_scalar_worker.py +0 -0
  114. {vgi_python-0.23.0 → vgi_python-0.25.0}/examples/row_count_worker.py +0 -0
  115. {vgi_python-0.23.0 → vgi_python-0.25.0}/examples/series_streaming_worker.py +0 -0
  116. {vgi_python-0.23.0 → vgi_python-0.25.0}/examples/sum_worker.py +0 -0
  117. {vgi_python-0.23.0 → vgi_python-0.25.0}/mkdocs.yml +0 -0
  118. {vgi_python-0.23.0 → vgi_python-0.25.0}/packages/vgi-fixtures/LICENSE +0 -0
  119. {vgi_python-0.23.0 → vgi_python-0.25.0}/packages/vgi-fixtures/README.md +0 -0
  120. {vgi_python-0.23.0 → vgi_python-0.25.0}/packages/vgi-fixtures/docker/Dockerfile +0 -0
  121. {vgi_python-0.23.0 → vgi_python-0.25.0}/packages/vgi-fixtures/docker/docker-entrypoint.sh +0 -0
  122. {vgi_python-0.23.0 → vgi_python-0.25.0}/packages/vgi-fixtures/pyproject.toml +0 -0
  123. {vgi_python-0.23.0 → vgi_python-0.25.0}/scripts/measure_startup.py +0 -0
  124. {vgi_python-0.23.0 → vgi_python-0.25.0}/scripts/run_all_tests.sh +0 -0
  125. {vgi_python-0.23.0 → vgi_python-0.25.0}/test-data/generate.sh +0 -0
  126. {vgi_python-0.23.0 → vgi_python-0.25.0}/tests/__init__.py +0 -0
  127. {vgi_python-0.23.0 → vgi_python-0.25.0}/tests/_http_fixtures.py +0 -0
  128. {vgi_python-0.23.0 → vgi_python-0.25.0}/tests/catalog/__init__.py +0 -0
  129. {vgi_python-0.23.0 → vgi_python-0.25.0}/tests/catalog/test_catalog_interface.py +0 -0
  130. {vgi_python-0.23.0 → vgi_python-0.25.0}/tests/catalog/test_client_catalog.py +0 -0
  131. {vgi_python-0.23.0 → vgi_python-0.25.0}/tests/catalog/test_column_statistics.py +0 -0
  132. {vgi_python-0.23.0 → vgi_python-0.25.0}/tests/catalog/test_example_worker_catalog.py +0 -0
  133. {vgi_python-0.23.0 → vgi_python-0.25.0}/tests/catalog/test_integration.py +0 -0
  134. {vgi_python-0.23.0 → vgi_python-0.25.0}/tests/catalog/test_required_filters.py +0 -0
  135. {vgi_python-0.23.0 → vgi_python-0.25.0}/tests/catalog/test_scan_branches.py +0 -0
  136. {vgi_python-0.23.0 → vgi_python-0.25.0}/tests/catalog/test_setting.py +0 -0
  137. {vgi_python-0.23.0 → vgi_python-0.25.0}/tests/catalog/test_storage.py +0 -0
  138. {vgi_python-0.23.0 → vgi_python-0.25.0}/tests/catalog/test_time_travel.py +0 -0
  139. {vgi_python-0.23.0 → vgi_python-0.25.0}/tests/catalog/test_writable_table.py +0 -0
  140. {vgi_python-0.23.0 → vgi_python-0.25.0}/tests/client/__init__.py +0 -0
  141. {vgi_python-0.23.0 → vgi_python-0.25.0}/tests/client/test_broken_pipe.py +0 -0
  142. {vgi_python-0.23.0 → vgi_python-0.25.0}/tests/client/test_cli.py +0 -0
  143. {vgi_python-0.23.0 → vgi_python-0.25.0}/tests/client/test_cli_catalog_functions.py +0 -0
  144. {vgi_python-0.23.0 → vgi_python-0.25.0}/tests/client/test_worker_debug.py +0 -0
  145. {vgi_python-0.23.0 → vgi_python-0.25.0}/tests/conformance/__init__.py +0 -0
  146. {vgi_python-0.23.0 → vgi_python-0.25.0}/tests/conformance/_stub.py +0 -0
  147. {vgi_python-0.23.0 → vgi_python-0.25.0}/tests/conformance/conftest.py +0 -0
  148. {vgi_python-0.23.0 → vgi_python-0.25.0}/tests/conformance/test_accumulate.py +0 -0
  149. {vgi_python-0.23.0 → vgi_python-0.25.0}/tests/conformance/test_aggregate.py +0 -0
  150. {vgi_python-0.23.0 → vgi_python-0.25.0}/tests/conformance/test_attach.py +0 -0
  151. {vgi_python-0.23.0 → vgi_python-0.25.0}/tests/conformance/test_bearer_auth.py +0 -0
  152. {vgi_python-0.23.0 → vgi_python-0.25.0}/tests/conformance/test_const_param_enforcement.py +0 -0
  153. {vgi_python-0.23.0 → vgi_python-0.25.0}/tests/conformance/test_container.py +0 -0
  154. {vgi_python-0.23.0 → vgi_python-0.25.0}/tests/conformance/test_copy_from.py +0 -0
  155. {vgi_python-0.23.0 → vgi_python-0.25.0}/tests/conformance/test_copy_to.py +0 -0
  156. {vgi_python-0.23.0 → vgi_python-0.25.0}/tests/conformance/test_function_inventory.py +0 -0
  157. {vgi_python-0.23.0 → vgi_python-0.25.0}/tests/conformance/test_github.py +0 -0
  158. {vgi_python-0.23.0 → vgi_python-0.25.0}/tests/conformance/test_http_client.py +0 -0
  159. {vgi_python-0.23.0 → vgi_python-0.25.0}/tests/conformance/test_http_external_location.py +0 -0
  160. {vgi_python-0.23.0 → vgi_python-0.25.0}/tests/conformance/test_http_upload_url.py +0 -0
  161. {vgi_python-0.23.0 → vgi_python-0.25.0}/tests/conformance/test_macro.py +0 -0
  162. {vgi_python-0.23.0 → vgi_python-0.25.0}/tests/conformance/test_overload.py +0 -0
  163. {vgi_python-0.23.0 → vgi_python-0.25.0}/tests/conformance/test_protocol_inventory.py +0 -0
  164. {vgi_python-0.23.0 → vgi_python-0.25.0}/tests/conformance/test_resumable_scan.py +0 -0
  165. {vgi_python-0.23.0 → vgi_python-0.25.0}/tests/conformance/test_scalar.py +0 -0
  166. {vgi_python-0.23.0 → vgi_python-0.25.0}/tests/conformance/test_scalar_attach_opaque_data.py +0 -0
  167. {vgi_python-0.23.0 → vgi_python-0.25.0}/tests/conformance/test_secret.py +0 -0
  168. {vgi_python-0.23.0 → vgi_python-0.25.0}/tests/conformance/test_settings.py +0 -0
  169. {vgi_python-0.23.0 → vgi_python-0.25.0}/tests/conformance/test_table.py +0 -0
  170. {vgi_python-0.23.0 → vgi_python-0.25.0}/tests/conformance/test_table_in_out.py +0 -0
  171. {vgi_python-0.23.0 → vgi_python-0.25.0}/tests/conformance/test_view.py +0 -0
  172. {vgi_python-0.23.0 → vgi_python-0.25.0}/tests/conformance/test_writable.py +0 -0
  173. {vgi_python-0.23.0 → vgi_python-0.25.0}/tests/conftest.py +0 -0
  174. {vgi_python-0.23.0 → vgi_python-0.25.0}/tests/landing/_checker.py +0 -0
  175. {vgi_python-0.23.0 → vgi_python-0.25.0}/tests/landing/describe.schema.json +0 -0
  176. {vgi_python-0.23.0 → vgi_python-0.25.0}/tests/scalar/__init__.py +0 -0
  177. {vgi_python-0.23.0 → vgi_python-0.25.0}/tests/scalar/test_bernoulli_function.py +0 -0
  178. {vgi_python-0.23.0 → vgi_python-0.25.0}/tests/scalar/test_binary_packet_function.py +0 -0
  179. {vgi_python-0.23.0 → vgi_python-0.25.0}/tests/scalar/test_client.py +0 -0
  180. {vgi_python-0.23.0 → vgi_python-0.25.0}/tests/scalar/test_conditional_message_function.py +0 -0
  181. {vgi_python-0.23.0 → vgi_python-0.25.0}/tests/scalar/test_hash_seed_function.py +0 -0
  182. {vgi_python-0.23.0 → vgi_python-0.25.0}/tests/scalar/test_multiply_by_setting_function.py +0 -0
  183. {vgi_python-0.23.0 → vgi_python-0.25.0}/tests/scalar/test_multiply_function.py +0 -0
  184. {vgi_python-0.23.0 → vgi_python-0.25.0}/tests/scalar/test_random_bytes_function.py +0 -0
  185. {vgi_python-0.23.0 → vgi_python-0.25.0}/tests/scalar/test_return_secret_value_function.py +0 -0
  186. {vgi_python-0.23.0 → vgi_python-0.25.0}/tests/table/__init__.py +0 -0
  187. {vgi_python-0.23.0 → vgi_python-0.25.0}/tests/table/generator/__init__.py +0 -0
  188. {vgi_python-0.23.0 → vgi_python-0.25.0}/tests/table/generator/test_constant_columns_function.py +0 -0
  189. {vgi_python-0.23.0 → vgi_python-0.25.0}/tests/table/generator/test_double_sequence_function.py +0 -0
  190. {vgi_python-0.23.0 → vgi_python-0.25.0}/tests/table/generator/test_exception_function.py +0 -0
  191. {vgi_python-0.23.0 → vgi_python-0.25.0}/tests/table/generator/test_filter_echo_function.py +0 -0
  192. {vgi_python-0.23.0 → vgi_python-0.25.0}/tests/table/generator/test_logging_function.py +0 -0
  193. {vgi_python-0.23.0 → vgi_python-0.25.0}/tests/table/generator/test_nested_sequence_function.py +0 -0
  194. {vgi_python-0.23.0 → vgi_python-0.25.0}/tests/table/generator/test_partitioned_function.py +0 -0
  195. {vgi_python-0.23.0 → vgi_python-0.25.0}/tests/table/generator/test_projected_data_function.py +0 -0
  196. {vgi_python-0.23.0 → vgi_python-0.25.0}/tests/table/generator/test_sequence_function.py +0 -0
  197. {vgi_python-0.23.0 → vgi_python-0.25.0}/tests/table/generator/test_settings_function.py +0 -0
  198. {vgi_python-0.23.0 → vgi_python-0.25.0}/tests/table/generator/test_struct_settings_function.py +0 -0
  199. {vgi_python-0.23.0 → vgi_python-0.25.0}/tests/table/generator/test_ten_thousand_function.py +0 -0
  200. {vgi_python-0.23.0 → vgi_python-0.25.0}/tests/table_in_out/__init__.py +0 -0
  201. {vgi_python-0.23.0 → vgi_python-0.25.0}/tests/table_in_out/generator/__init__.py +0 -0
  202. {vgi_python-0.23.0 → vgi_python-0.25.0}/tests/table_in_out/generator/test_buffer_input_function.py +0 -0
  203. {vgi_python-0.23.0 → vgi_python-0.25.0}/tests/table_in_out/generator/test_echo_function.py +0 -0
  204. {vgi_python-0.23.0 → vgi_python-0.25.0}/tests/table_in_out/generator/test_exception_functions.py +0 -0
  205. {vgi_python-0.23.0 → vgi_python-0.25.0}/tests/table_in_out/generator/test_filter_by_setting_function.py +0 -0
  206. {vgi_python-0.23.0 → vgi_python-0.25.0}/tests/table_in_out/generator/test_repeat_inputs_function.py +0 -0
  207. {vgi_python-0.23.0 → vgi_python-0.25.0}/tests/table_in_out/generator/test_substream_partial_sum_function.py +0 -0
  208. {vgi_python-0.23.0 → vgi_python-0.25.0}/tests/table_in_out/generator/test_sum_all_columns_function.py +0 -0
  209. {vgi_python-0.23.0 → vgi_python-0.25.0}/tests/table_in_out/test_blended_metadata.py +0 -0
  210. {vgi_python-0.23.0 → vgi_python-0.25.0}/tests/table_in_out/test_client.py +0 -0
  211. {vgi_python-0.23.0 → vgi_python-0.25.0}/tests/test_access_log_audit.py +0 -0
  212. {vgi_python-0.23.0 → vgi_python-0.25.0}/tests/test_aggregate_function.py +0 -0
  213. {vgi_python-0.23.0 → vgi_python-0.25.0}/tests/test_argument_spec.py +0 -0
  214. {vgi_python-0.23.0 → vgi_python-0.25.0}/tests/test_auth.py +0 -0
  215. {vgi_python-0.23.0 → vgi_python-0.25.0}/tests/test_bind_exceptions.py +0 -0
  216. {vgi_python-0.23.0 → vgi_python-0.25.0}/tests/test_bind_request_at_clause.py +0 -0
  217. {vgi_python-0.23.0 → vgi_python-0.25.0}/tests/test_bound_storage_conformance.py +0 -0
  218. {vgi_python-0.23.0 → vgi_python-0.25.0}/tests/test_cache_control.py +0 -0
  219. {vgi_python-0.23.0 → vgi_python-0.25.0}/tests/test_catalog_auth_binding.py +0 -0
  220. {vgi_python-0.23.0 → vgi_python-0.25.0}/tests/test_copy_from_function.py +0 -0
  221. {vgi_python-0.23.0 → vgi_python-0.25.0}/tests/test_copy_to_function.py +0 -0
  222. {vgi_python-0.23.0 → vgi_python-0.25.0}/tests/test_docstrings.py +0 -0
  223. {vgi_python-0.23.0 → vgi_python-0.25.0}/tests/test_documentation_examples.py +0 -0
  224. {vgi_python-0.23.0 → vgi_python-0.25.0}/tests/test_example_function_arg_types.py +0 -0
  225. {vgi_python-0.23.0 → vgi_python-0.25.0}/tests/test_examples_workers.py +0 -0
  226. {vgi_python-0.23.0 → vgi_python-0.25.0}/tests/test_exception_handling.py +0 -0
  227. {vgi_python-0.23.0 → vgi_python-0.25.0}/tests/test_exceptions.py +0 -0
  228. {vgi_python-0.23.0 → vgi_python-0.25.0}/tests/test_filter_pushdown.py +0 -0
  229. {vgi_python-0.23.0 → vgi_python-0.25.0}/tests/test_filter_pushdown_extension.py +0 -0
  230. {vgi_python-0.23.0 → vgi_python-0.25.0}/tests/test_function_storage.py +0 -0
  231. {vgi_python-0.23.0 → vgi_python-0.25.0}/tests/test_function_storage_azure_sql.py +0 -0
  232. {vgi_python-0.23.0 → vgi_python-0.25.0}/tests/test_function_storage_cf_do.py +0 -0
  233. {vgi_python-0.23.0 → vgi_python-0.25.0}/tests/test_function_storage_cf_do_integration.py +0 -0
  234. {vgi_python-0.23.0 → vgi_python-0.25.0}/tests/test_function_storage_conformance.py +0 -0
  235. {vgi_python-0.23.0 → vgi_python-0.25.0}/tests/test_generated_cpp_constants.py +0 -0
  236. {vgi_python-0.23.0 → vgi_python-0.25.0}/tests/test_generated_cpp_protocol_version.py +0 -0
  237. {vgi_python-0.23.0 → vgi_python-0.25.0}/tests/test_generated_cpp_request_builders.py +0 -0
  238. {vgi_python-0.23.0 → vgi_python-0.25.0}/tests/test_generated_cpp_schemas.py +0 -0
  239. {vgi_python-0.23.0 → vgi_python-0.25.0}/tests/test_generated_cpp_secret.py +0 -0
  240. {vgi_python-0.23.0 → vgi_python-0.25.0}/tests/test_generated_go_schemas.py +0 -0
  241. {vgi_python-0.23.0 → vgi_python-0.25.0}/tests/test_generated_protocol_version.py +0 -0
  242. {vgi_python-0.23.0 → vgi_python-0.25.0}/tests/test_generated_schemas_cross_lang.py +0 -0
  243. {vgi_python-0.23.0 → vgi_python-0.25.0}/tests/test_generated_ts_client.py +0 -0
  244. {vgi_python-0.23.0 → vgi_python-0.25.0}/tests/test_generated_ts_schemas.py +0 -0
  245. {vgi_python-0.23.0 → vgi_python-0.25.0}/tests/test_http_demo_storage.py +0 -0
  246. {vgi_python-0.23.0 → vgi_python-0.25.0}/tests/test_http_s3_offload_input.py +0 -0
  247. {vgi_python-0.23.0 → vgi_python-0.25.0}/tests/test_http_s3_offload_output.py +0 -0
  248. {vgi_python-0.23.0 → vgi_python-0.25.0}/tests/test_landing_conformance.py +0 -0
  249. {vgi_python-0.23.0 → vgi_python-0.25.0}/tests/test_metadata.py +0 -0
  250. {vgi_python-0.23.0 → vgi_python-0.25.0}/tests/test_mypy_consolidated.py +0 -0
  251. {vgi_python-0.23.0 → vgi_python-0.25.0}/tests/test_nest_tensor.py +0 -0
  252. {vgi_python-0.23.0 → vgi_python-0.25.0}/tests/test_otel.py +0 -0
  253. {vgi_python-0.23.0 → vgi_python-0.25.0}/tests/test_projection_enforcement.py +0 -0
  254. {vgi_python-0.23.0 → vgi_python-0.25.0}/tests/test_projection_repro.py +0 -0
  255. {vgi_python-0.23.0 → vgi_python-0.25.0}/tests/test_resolved_secrets.py +0 -0
  256. {vgi_python-0.23.0 → vgi_python-0.25.0}/tests/test_schema_scoped_functions.py +0 -0
  257. {vgi_python-0.23.0 → vgi_python-0.25.0}/tests/test_schema_utils.py +0 -0
  258. {vgi_python-0.23.0 → vgi_python-0.25.0}/tests/test_table_buffering_function.py +0 -0
  259. {vgi_python-0.23.0 → vgi_python-0.25.0}/tests/test_table_function_dynamic_to_string.py +0 -0
  260. {vgi_python-0.23.0 → vgi_python-0.25.0}/tests/test_tcp_transport.py +0 -0
  261. {vgi_python-0.23.0 → vgi_python-0.25.0}/tests/test_type_bounds.py +0 -0
  262. {vgi_python-0.23.0 → vgi_python-0.25.0}/tests/test_union_argument.py +0 -0
  263. {vgi_python-0.23.0 → vgi_python-0.25.0}/tests/test_worker.py +0 -0
  264. {vgi_python-0.23.0 → vgi_python-0.25.0}/tests/test_worker_page.py +0 -0
  265. {vgi_python-0.23.0 → vgi_python-0.25.0}/tests/transactor/__init__.py +0 -0
  266. {vgi_python-0.23.0 → vgi_python-0.25.0}/tests/transactor/test_transactor.py +0 -0
  267. {vgi_python-0.23.0 → vgi_python-0.25.0}/vgi/__init__.py +0 -0
  268. {vgi_python-0.23.0 → vgi_python-0.25.0}/vgi/_duckdb.py +0 -0
  269. {vgi_python-0.23.0 → vgi_python-0.25.0}/vgi/_storage_profile.py +0 -0
  270. {vgi_python-0.23.0 → vgi_python-0.25.0}/vgi/_test_fixtures/__init__.py +0 -0
  271. {vgi_python-0.23.0 → vgi_python-0.25.0}/vgi/_test_fixtures/accumulate/__init__.py +0 -0
  272. {vgi_python-0.23.0 → vgi_python-0.25.0}/vgi/_test_fixtures/accumulate/worker.py +0 -0
  273. {vgi_python-0.23.0 → vgi_python-0.25.0}/vgi/_test_fixtures/aggregate/__init__.py +0 -0
  274. {vgi_python-0.23.0 → vgi_python-0.25.0}/vgi/_test_fixtures/aggregate/_common.py +0 -0
  275. {vgi_python-0.23.0 → vgi_python-0.25.0}/vgi/_test_fixtures/aggregate/basic.py +0 -0
  276. {vgi_python-0.23.0 → vgi_python-0.25.0}/vgi/_test_fixtures/aggregate/dynamic.py +0 -0
  277. {vgi_python-0.23.0 → vgi_python-0.25.0}/vgi/_test_fixtures/aggregate/generic.py +0 -0
  278. {vgi_python-0.23.0 → vgi_python-0.25.0}/vgi/_test_fixtures/aggregate/listagg.py +0 -0
  279. {vgi_python-0.23.0 → vgi_python-0.25.0}/vgi/_test_fixtures/aggregate/percentile.py +0 -0
  280. {vgi_python-0.23.0 → vgi_python-0.25.0}/vgi/_test_fixtures/aggregate/same_name.py +0 -0
  281. {vgi_python-0.23.0 → vgi_python-0.25.0}/vgi/_test_fixtures/aggregate/secret_typed.py +0 -0
  282. {vgi_python-0.23.0 → vgi_python-0.25.0}/vgi/_test_fixtures/aggregate/streaming.py +0 -0
  283. {vgi_python-0.23.0 → vgi_python-0.25.0}/vgi/_test_fixtures/aggregate/varargs.py +0 -0
  284. {vgi_python-0.23.0 → vgi_python-0.25.0}/vgi/_test_fixtures/aggregate/window.py +0 -0
  285. {vgi_python-0.23.0 → vgi_python-0.25.0}/vgi/_test_fixtures/attach_options.py +0 -0
  286. {vgi_python-0.23.0 → vgi_python-0.25.0}/vgi/_test_fixtures/bad_enum.py +0 -0
  287. {vgi_python-0.23.0 → vgi_python-0.25.0}/vgi/_test_fixtures/bad_protocol.py +0 -0
  288. {vgi_python-0.23.0 → vgi_python-0.25.0}/vgi/_test_fixtures/cancellable.py +0 -0
  289. {vgi_python-0.23.0 → vgi_python-0.25.0}/vgi/_test_fixtures/catalog.py +0 -0
  290. {vgi_python-0.23.0 → vgi_python-0.25.0}/vgi/_test_fixtures/companion.py +0 -0
  291. {vgi_python-0.23.0 → vgi_python-0.25.0}/vgi/_test_fixtures/copy_from.py +0 -0
  292. {vgi_python-0.23.0 → vgi_python-0.25.0}/vgi/_test_fixtures/copy_to.py +0 -0
  293. {vgi_python-0.23.0 → vgi_python-0.25.0}/vgi/_test_fixtures/narrow_bind/__init__.py +0 -0
  294. {vgi_python-0.23.0 → vgi_python-0.25.0}/vgi/_test_fixtures/narrow_bind/worker.py +0 -0
  295. {vgi_python-0.23.0 → vgi_python-0.25.0}/vgi/_test_fixtures/nest_tensor.py +0 -0
  296. {vgi_python-0.23.0 → vgi_python-0.25.0}/vgi/_test_fixtures/orchard_catalog.py +0 -0
  297. {vgi_python-0.23.0 → vgi_python-0.25.0}/vgi/_test_fixtures/projection_repro/__init__.py +0 -0
  298. {vgi_python-0.23.0 → vgi_python-0.25.0}/vgi/_test_fixtures/projection_repro/worker.py +0 -0
  299. {vgi_python-0.23.0 → vgi_python-0.25.0}/vgi/_test_fixtures/scalar/__init__.py +0 -0
  300. {vgi_python-0.23.0 → vgi_python-0.25.0}/vgi/_test_fixtures/scalar/_common.py +0 -0
  301. {vgi_python-0.23.0 → vgi_python-0.25.0}/vgi/_test_fixtures/scalar/arithmetic.py +0 -0
  302. {vgi_python-0.23.0 → vgi_python-0.25.0}/vgi/_test_fixtures/scalar/bench_ladder.py +0 -0
  303. {vgi_python-0.23.0 → vgi_python-0.25.0}/vgi/_test_fixtures/scalar/binary.py +0 -0
  304. {vgi_python-0.23.0 → vgi_python-0.25.0}/vgi/_test_fixtures/scalar/formatting.py +0 -0
  305. {vgi_python-0.23.0 → vgi_python-0.25.0}/vgi/_test_fixtures/scalar/geo.py +0 -0
  306. {vgi_python-0.23.0 → vgi_python-0.25.0}/vgi/_test_fixtures/scalar/null_handling.py +0 -0
  307. {vgi_python-0.23.0 → vgi_python-0.25.0}/vgi/_test_fixtures/scalar/random_demo.py +0 -0
  308. {vgi_python-0.23.0 → vgi_python-0.25.0}/vgi/_test_fixtures/scalar/same_name.py +0 -0
  309. {vgi_python-0.23.0 → vgi_python-0.25.0}/vgi/_test_fixtures/scalar/settings_secrets.py +0 -0
  310. {vgi_python-0.23.0 → vgi_python-0.25.0}/vgi/_test_fixtures/scalar/type_info.py +0 -0
  311. {vgi_python-0.23.0 → vgi_python-0.25.0}/vgi/_test_fixtures/schema_reconcile/__init__.py +0 -0
  312. {vgi_python-0.23.0 → vgi_python-0.25.0}/vgi/_test_fixtures/schema_reconcile/worker.py +0 -0
  313. {vgi_python-0.23.0 → vgi_python-0.25.0}/vgi/_test_fixtures/simple_writable.py +0 -0
  314. {vgi_python-0.23.0 → vgi_python-0.25.0}/vgi/_test_fixtures/table/__init__.py +0 -0
  315. {vgi_python-0.23.0 → vgi_python-0.25.0}/vgi/_test_fixtures/table/batch_index.py +0 -0
  316. {vgi_python-0.23.0 → vgi_python-0.25.0}/vgi/_test_fixtures/table/batch_index_broken.py +0 -0
  317. {vgi_python-0.23.0 → vgi_python-0.25.0}/vgi/_test_fixtures/table/cache.py +0 -0
  318. {vgi_python-0.23.0 → vgi_python-0.25.0}/vgi/_test_fixtures/table/catalog_scans.py +0 -0
  319. {vgi_python-0.23.0 → vgi_python-0.25.0}/vgi/_test_fixtures/table/filters.py +0 -0
  320. {vgi_python-0.23.0 → vgi_python-0.25.0}/vgi/_test_fixtures/table/late_materialization.py +0 -0
  321. {vgi_python-0.23.0 → vgi_python-0.25.0}/vgi/_test_fixtures/table/make_series.py +0 -0
  322. {vgi_python-0.23.0 → vgi_python-0.25.0}/vgi/_test_fixtures/table/misc.py +0 -0
  323. {vgi_python-0.23.0 → vgi_python-0.25.0}/vgi/_test_fixtures/table/order_modes.py +0 -0
  324. {vgi_python-0.23.0 → vgi_python-0.25.0}/vgi/_test_fixtures/table/pairs.py +0 -0
  325. {vgi_python-0.23.0 → vgi_python-0.25.0}/vgi/_test_fixtures/table/partition_columns.py +0 -0
  326. {vgi_python-0.23.0 → vgi_python-0.25.0}/vgi/_test_fixtures/table/partition_columns_broken.py +0 -0
  327. {vgi_python-0.23.0 → vgi_python-0.25.0}/vgi/_test_fixtures/table/profiling_example.py +0 -0
  328. {vgi_python-0.23.0 → vgi_python-0.25.0}/vgi/_test_fixtures/table/required_filters.py +0 -0
  329. {vgi_python-0.23.0 → vgi_python-0.25.0}/vgi/_test_fixtures/table/same_name_cached.py +0 -0
  330. {vgi_python-0.23.0 → vgi_python-0.25.0}/vgi/_test_fixtures/table/sequence.py +0 -0
  331. {vgi_python-0.23.0 → vgi_python-0.25.0}/vgi/_test_fixtures/table/settings.py +0 -0
  332. {vgi_python-0.23.0 → vgi_python-0.25.0}/vgi/_test_fixtures/table/transaction_storage.py +0 -0
  333. {vgi_python-0.23.0 → vgi_python-0.25.0}/vgi/_test_fixtures/table/tt_pushdown.py +0 -0
  334. {vgi_python-0.23.0 → vgi_python-0.25.0}/vgi/_test_fixtures/table/typed_probe.py +0 -0
  335. {vgi_python-0.23.0 → vgi_python-0.25.0}/vgi/_test_fixtures/table/versioned.py +0 -0
  336. {vgi_python-0.23.0 → vgi_python-0.25.0}/vgi/_test_fixtures/table_in_out.py +0 -0
  337. {vgi_python-0.23.0 → vgi_python-0.25.0}/vgi/_test_fixtures/table_in_out_same_name.py +0 -0
  338. {vgi_python-0.23.0 → vgi_python-0.25.0}/vgi/_test_fixtures/twin_catalogs.py +0 -0
  339. {vgi_python-0.23.0 → vgi_python-0.25.0}/vgi/_test_fixtures/versioned.py +0 -0
  340. {vgi_python-0.23.0 → vgi_python-0.25.0}/vgi/_test_fixtures/versioned_tables.py +0 -0
  341. {vgi_python-0.23.0 → vgi_python-0.25.0}/vgi/_test_fixtures/writable/__init__.py +0 -0
  342. {vgi_python-0.23.0 → vgi_python-0.25.0}/vgi/_test_fixtures/writable/generic.py +0 -0
  343. {vgi_python-0.23.0 → vgi_python-0.25.0}/vgi/_test_fixtures/writable/table.py +0 -0
  344. {vgi_python-0.23.0 → vgi_python-0.25.0}/vgi/_test_fixtures/writable/worker.py +0 -0
  345. {vgi_python-0.23.0 → vgi_python-0.25.0}/vgi/aggregate_function.py +0 -0
  346. {vgi_python-0.23.0 → vgi_python-0.25.0}/vgi/argument_spec.py +0 -0
  347. {vgi_python-0.23.0 → vgi_python-0.25.0}/vgi/arguments.py +0 -0
  348. {vgi_python-0.23.0 → vgi_python-0.25.0}/vgi/attach_header.py +0 -0
  349. {vgi_python-0.23.0 → vgi_python-0.25.0}/vgi/cache_control.py +0 -0
  350. {vgi_python-0.23.0 → vgi_python-0.25.0}/vgi/catalog/__init__.py +0 -0
  351. {vgi_python-0.23.0 → vgi_python-0.25.0}/vgi/catalog/_descriptor_spec.py +0 -0
  352. {vgi_python-0.23.0 → vgi_python-0.25.0}/vgi/catalog/attach_option.py +0 -0
  353. {vgi_python-0.23.0 → vgi_python-0.25.0}/vgi/catalog/duckdb_statistics.py +0 -0
  354. {vgi_python-0.23.0 → vgi_python-0.25.0}/vgi/catalog/secret_type.py +0 -0
  355. {vgi_python-0.23.0 → vgi_python-0.25.0}/vgi/catalog/setting.py +0 -0
  356. {vgi_python-0.23.0 → vgi_python-0.25.0}/vgi/catalog/storage.py +0 -0
  357. {vgi_python-0.23.0 → vgi_python-0.25.0}/vgi/client/__init__.py +0 -0
  358. {vgi_python-0.23.0 → vgi_python-0.25.0}/vgi/client/catalog_mixin.py +0 -0
  359. {vgi_python-0.23.0 → vgi_python-0.25.0}/vgi/client/cli.py +0 -0
  360. {vgi_python-0.23.0 → vgi_python-0.25.0}/vgi/client/cli_catalog.py +0 -0
  361. {vgi_python-0.23.0 → vgi_python-0.25.0}/vgi/client/cli_schema.py +0 -0
  362. {vgi_python-0.23.0 → vgi_python-0.25.0}/vgi/client/cli_table.py +0 -0
  363. {vgi_python-0.23.0 → vgi_python-0.25.0}/vgi/client/cli_transaction.py +0 -0
  364. {vgi_python-0.23.0 → vgi_python-0.25.0}/vgi/client/cli_utils.py +0 -0
  365. {vgi_python-0.23.0 → vgi_python-0.25.0}/vgi/client/cli_view.py +0 -0
  366. {vgi_python-0.23.0 → vgi_python-0.25.0}/vgi/client/client.py +0 -0
  367. {vgi_python-0.23.0 → vgi_python-0.25.0}/vgi/codegen/__init__.py +0 -0
  368. {vgi_python-0.23.0 → vgi_python-0.25.0}/vgi/codegen/_common.py +0 -0
  369. {vgi_python-0.23.0 → vgi_python-0.25.0}/vgi/codegen/cpp_constants.py +0 -0
  370. {vgi_python-0.23.0 → vgi_python-0.25.0}/vgi/codegen/cpp_protocol_version.py +0 -0
  371. {vgi_python-0.23.0 → vgi_python-0.25.0}/vgi/codegen/cpp_request_builders.py +0 -0
  372. {vgi_python-0.23.0 → vgi_python-0.25.0}/vgi/codegen/cpp_schemas.py +0 -0
  373. {vgi_python-0.23.0 → vgi_python-0.25.0}/vgi/codegen/cpp_secret_protocol_version.py +0 -0
  374. {vgi_python-0.23.0 → vgi_python-0.25.0}/vgi/codegen/cpp_secret_request_builders.py +0 -0
  375. {vgi_python-0.23.0 → vgi_python-0.25.0}/vgi/codegen/cpp_secret_schemas.py +0 -0
  376. {vgi_python-0.23.0 → vgi_python-0.25.0}/vgi/codegen/go_schemas.py +0 -0
  377. {vgi_python-0.23.0 → vgi_python-0.25.0}/vgi/codegen/protocol_version.py +0 -0
  378. {vgi_python-0.23.0 → vgi_python-0.25.0}/vgi/codegen/ts_client.py +0 -0
  379. {vgi_python-0.23.0 → vgi_python-0.25.0}/vgi/codegen/ts_schemas.py +0 -0
  380. {vgi_python-0.23.0 → vgi_python-0.25.0}/vgi/copy_from_function.py +0 -0
  381. {vgi_python-0.23.0 → vgi_python-0.25.0}/vgi/copy_to_function.py +0 -0
  382. {vgi_python-0.23.0 → vgi_python-0.25.0}/vgi/exceptions.py +0 -0
  383. {vgi_python-0.23.0 → vgi_python-0.25.0}/vgi/function_storage_azure_sql.py +0 -0
  384. {vgi_python-0.23.0 → vgi_python-0.25.0}/vgi/function_storage_cf_do.py +0 -0
  385. {vgi_python-0.23.0 → vgi_python-0.25.0}/vgi/http/__init__.py +0 -0
  386. {vgi_python-0.23.0 → vgi_python-0.25.0}/vgi/http/demo_storage.py +0 -0
  387. {vgi_python-0.23.0 → vgi_python-0.25.0}/vgi/http/describe_json.py +0 -0
  388. {vgi_python-0.23.0 → vgi_python-0.25.0}/vgi/http/landing.html +0 -0
  389. {vgi_python-0.23.0 → vgi_python-0.25.0}/vgi/http/landing_page.py +0 -0
  390. {vgi_python-0.23.0 → vgi_python-0.25.0}/vgi/http/worker_page.py +0 -0
  391. {vgi_python-0.23.0 → vgi_python-0.25.0}/vgi/invocation.py +0 -0
  392. {vgi_python-0.23.0 → vgi_python-0.25.0}/vgi/metadata.py +0 -0
  393. {vgi_python-0.23.0 → vgi_python-0.25.0}/vgi/otel.py +0 -0
  394. {vgi_python-0.23.0 → vgi_python-0.25.0}/vgi/profiling.py +0 -0
  395. {vgi_python-0.23.0 → vgi_python-0.25.0}/vgi/py.typed +0 -0
  396. {vgi_python-0.23.0 → vgi_python-0.25.0}/vgi/scalar_function.py +0 -0
  397. {vgi_python-0.23.0 → vgi_python-0.25.0}/vgi/schema_utils.py +0 -0
  398. {vgi_python-0.23.0 → vgi_python-0.25.0}/vgi/secret_protocol.py +0 -0
  399. {vgi_python-0.23.0 → vgi_python-0.25.0}/vgi/secret_service.py +0 -0
  400. {vgi_python-0.23.0 → vgi_python-0.25.0}/vgi/table_buffering_function.py +0 -0
  401. {vgi_python-0.23.0 → vgi_python-0.25.0}/vgi/table_filter_pushdown.py +0 -0
  402. {vgi_python-0.23.0 → vgi_python-0.25.0}/vgi/table_in_out_function.py +0 -0
  403. {vgi_python-0.23.0 → vgi_python-0.25.0}/vgi/transactor/__init__.py +0 -0
  404. {vgi_python-0.23.0 → vgi_python-0.25.0}/vgi/transactor/_duckdb_compat.py +0 -0
  405. {vgi_python-0.23.0 → vgi_python-0.25.0}/vgi/transactor/client.py +0 -0
  406. {vgi_python-0.23.0 → vgi_python-0.25.0}/vgi/transactor/protocol.py +0 -0
  407. {vgi_python-0.23.0 → vgi_python-0.25.0}/vgi/transactor/server.py +0 -0
  408. {vgi_python-0.23.0 → vgi_python-0.25.0}/wrangler.jsonc +0 -0
@@ -83,8 +83,8 @@ jobs:
83
83
  - name: Install uv
84
84
  uses: astral-sh/setup-uv@v8.2.0
85
85
 
86
- - name: Set up Python 3.13
87
- run: uv python install 3.13
86
+ - name: Set up Python 3.14
87
+ run: uv python install 3.14
88
88
 
89
89
  - name: Install dependencies
90
90
  run: uv sync --all-extras --group docs
@@ -141,8 +141,8 @@ jobs:
141
141
  - name: Install uv
142
142
  uses: astral-sh/setup-uv@v8.2.0
143
143
 
144
- - name: Set up Python 3.13
145
- run: uv python install 3.13
144
+ - name: Set up Python 3.14
145
+ run: uv python install 3.14
146
146
 
147
147
  - name: Install test dependencies
148
148
  run: |
@@ -150,7 +150,7 @@ jobs:
150
150
  # local vgi-rpc checkout with the s3/external extras plus boto3.
151
151
  # Subsequent uv run calls must pass --no-sync or uv re-syncs the
152
152
  # env to the lockfile and drops the overlay.
153
- uv sync --all-extras --python 3.13
153
+ uv sync --all-extras --python 3.14
154
154
  uv pip install './vgi-rpc[http,s3,external]' boto3
155
155
 
156
156
  - name: Create test bucket in LocalStack
@@ -21,7 +21,7 @@ jobs:
21
21
  uses: astral-sh/setup-uv@v8.2.0
22
22
 
23
23
  - name: Set up Python
24
- run: uv python install 3.13
24
+ run: uv python install 3.14
25
25
 
26
26
  - name: Install dependencies
27
27
  run: uv sync --group docs
@@ -32,7 +32,7 @@ env:
32
32
  VGI_REF: main
33
33
  # The Haybarn release providing the prebuilt haybarn-unittest binary. Must be
34
34
  # ABI-compatible with the community-published vgi extension.
35
- HAYBARN_RELEASE: haybarn-v1.5.4-rc3
35
+ HAYBARN_RELEASE: haybarn-v1.5.5-rc1
36
36
  # CI is not a user: its ATTACHes should not land in Query.Farm's adoption data.
37
37
  # The vgi extension fires a telemetry event per successful ATTACH, and this
38
38
  # suite performs several hundred of them per lane, so opting out keeps the
@@ -78,11 +78,11 @@ jobs:
78
78
  - name: Install uv
79
79
  uses: astral-sh/setup-uv@v8.2.0
80
80
 
81
- - name: Set up Python 3.13
82
- run: uv python install 3.13
81
+ - name: Set up Python 3.14
82
+ run: uv python install 3.14
83
83
 
84
84
  - name: Install dependencies (vgi + fixtures + all extras)
85
- run: uv sync --all-extras --python 3.13
85
+ run: uv sync --all-extras --python 3.14
86
86
 
87
87
  - name: Download haybarn-unittest
88
88
  run: |
@@ -297,6 +297,11 @@ vgi-client --input data.parquet --function sum_all_columns --worker vgi-fixture-
297
297
  | `VGI_OAUTH_DEVICE_CODE_CLIENT_ID` | Client ID for device-code flow (optional, URL-safe chars only) |
298
298
  | `VGI_OAUTH_DEVICE_CODE_CLIENT_SECRET` | Client secret for device-code flow (optional, URL-safe chars only) |
299
299
  | `VGI_OAUTH_USE_ID_TOKEN` | When `1`/`true`/`yes`, clients use OIDC `id_token` as Bearer instead of `access_token` |
300
+ | `VGI_INTROSPECT_PRINCIPALS` | Comma-separated principals permitted to call `__introspect_token__`. Required — no permissive default — whenever the worker implements `resolve_token()` (see below) |
301
+ | `VGI_INTROSPECT_RATE_LIMIT` | Introspection requests allowed per caller per second (default 20) |
302
+ | `VGI_WORKER_ACCESS_LOG_SAMPLE` | Fraction of *successful* calls to keep in the access log, `0.0`–`1.0`. Errors are always kept; the decision is per call, so every record of one stream shares a fate |
303
+ | `VGI_WORKER_ACCESS_LOG_ASYNC` | When `1`/`true`/`yes`, emit access-log records from a listener thread. Bounded queue; full means drop, and a crash loses whatever is queued |
304
+ | `VGI_WORKER_ACCESS_LOG_QUEUE_SIZE` | Bound on the async access-log queue (default 10000) |
300
305
  | `VGI_OTEL_ENABLED` | Enable OpenTelemetry instrumentation (`1`/`true`/`yes`) |
301
306
  | `VGI_OTEL_CUSTOM_ATTRIBUTES` | Comma-separated `key=value` pairs for custom span/metric attributes |
302
307
  | `VGI_OTEL_CLAIM_ATTRIBUTES` | Comma-separated `claim_key=span_attr_name` pairs for claim extraction |
@@ -392,6 +397,96 @@ Set `SENTRY_DSN` (and install `vgi[sentry]`) to forward unhandled exceptions to
392
397
 
393
398
  The same enrichment applies to OTel spans when `VGI_OTEL_ENABLED=1` — both backends read from the same `VgiTracer.set_current_span_attributes()` call sites in `vgi/otel.py`. Either, neither, or both can be active in a process.
394
399
 
400
+ ### Serving Behind a Load Balancer
401
+
402
+ `--max-externalized-response-bytes` caps a single *externalized* response — the
403
+ payload uploaded to blob storage and replaced on the wire by a pointer. Set it
404
+ to whatever the load balancer, API gateway, or object-store policy in front of
405
+ the worker will actually carry.
406
+
407
+ ```bash
408
+ vgi-serve my.worker:MyWorker --http --max-externalized-response-bytes 67108864
409
+ ```
410
+
411
+ Unlike `--max-stream-response-bytes`, which governs the wire and is *soft* for
412
+ producer streams (a continuation token carries the overshoot to the next turn),
413
+ this cap is **hard on every method type with no continuation escape** — bytes
414
+ already uploaded cannot be un-uploaded. Default is no cap. When set, the value
415
+ is advertised as `VGI-Max-Externalized-Response-Bytes` so clients can size their
416
+ own expectations.
417
+
418
+ Also available on `Worker.main --http` and the fixture server. Under
419
+ `--server granian` it travels to worker processes through `export_serve_config`.
420
+
421
+ ### Token Introspection (`resolve_token`)
422
+
423
+ A worker may optionally expose `POST {prefix}/__introspect_token__`, which
424
+ resolves an opaque bearer credential to a principal — for a reverse proxy that
425
+ terminates the only public listener and must know the caller's identity before
426
+ it can authorize anything.
427
+
428
+ ```python
429
+ from vgi.auth import AuthUnavailableError, TokenIdentity
430
+ from vgi.worker import Worker
431
+
432
+ class MyWorker(Worker):
433
+ functions = [...]
434
+
435
+ @classmethod
436
+ def resolve_token(cls, token: str) -> TokenIdentity | None:
437
+ try:
438
+ row = api_keys.lookup(token) # your own store
439
+ except ConnectionError as exc:
440
+ # "I could not find out" — 503 + Retry-After, not 401.
441
+ raise AuthUnavailableError(str(exc)) from exc
442
+ if row is None:
443
+ return None # "the credential is unknown"
444
+ return TokenIdentity(principal=row.principal, token_name=row.label)
445
+ ```
446
+
447
+ **The route does not exist until `resolve_token` is overridden** — absent, not
448
+ routed-and-refusing. That is what keeps a dependency upgrade from growing a
449
+ credential-to-identity oracle on every existing worker.
450
+
451
+ Enabling it also requires an allowlist of principals permitted to ask, via
452
+ `--introspect-principals` or `VGI_INTROSPECT_PRINCIPALS`. There is no permissive
453
+ default and a worker that overrides the hook without one **refuses to start**:
454
+ authenticating and introspecting are different capabilities, and "any
455
+ authenticated caller" lets any user resolve any other user's credential to its
456
+ owner. `--introspect-rate-limit` (default 20/caller/second) bounds, rather than
457
+ closes, the oracle an allowlisted-but-compromised caller still has.
458
+
459
+ Return `None` for "the store answered and this credential is unknown"; raise
460
+ `AuthUnavailableError` for "the answer is not knowable". A caller that
461
+ negative-caches the first must not cache the second. Never return claims — a
462
+ pass-through claims field would let a worker choose its caller's tenant routing
463
+ and policy branch.
464
+
465
+ `AuthUnavailableError` is worth reaching for in any custom `authenticate`
466
+ callback too, not just here: it is deliberately **not** a `ValueError`, because
467
+ `chain_authenticate` advances to the next authenticator on `ValueError` — so a
468
+ sidecar outage raised as one is read as "not my credential, try the next" and
469
+ ends up a 401 from the end of the chain, restarting every session in the fleet
470
+ over a thirty-second blip.
471
+
472
+ ### Access Log Sampling and Async Emission
473
+
474
+ `--access-log-sample 0.05` keeps 5% of *successful* calls. Errors are always
475
+ kept, and the decision is made per call so every record belonging to one stream
476
+ shares a fate. `--access-log-async` moves formatting and writing to a listener
477
+ thread so disk latency stays off the request path; the queue is bounded
478
+ (`--access-log-queue-size`, default 10000), full means drop, and the next record
479
+ through carries `dropped_records` so a gap is never silent. A crash loses
480
+ whatever is still queued — that is the trade.
481
+
482
+ Both apply only to `vgi_rpc.access`, which gets its own handler for the purpose.
483
+ They are deliberately not applied to the diagnostic loggers: dropping half of a
484
+ traceback is not a saving.
485
+
486
+ **Trace correlation needs no configuration.** vgi-rpc reads whatever span is
487
+ current when it emits a record, so `trace_id` / `span_id` appear on every access
488
+ record as soon as `VGI_OTEL_ENABLED=1`.
489
+
395
490
  ### Key Constraints for Scalar Functions:
396
491
  - **1:1 row mapping**: Output must have exactly the same number of rows as input
397
492
  - **Single column output**: Output schema has exactly one column named "result"
@@ -508,4 +603,5 @@ The table schema is automatically derived from the function's `output_schema`:
508
603
  - **Function lifecycle**: `docs/lifecycle.md`
509
604
  - **Generator API (advanced)**: `docs/generator-api.md`
510
605
  - **Catalog interface**: `docs/catalog-interface.md`
606
+ - **Global functions (system.main)**: `docs/global-functions.md`
511
607
  - **Shared storage backends**: `docs/shared-storage.md`
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: vgi-python
3
- Version: 0.23.0
3
+ Version: 0.25.0
4
4
  Summary: Vector Gateway Interface - Connect DuckDB to external programs via Apache Arrow
5
5
  Project-URL: Homepage, https://query.farm
6
6
  Project-URL: Repository, https://github.com/Query-farm/vgi-python
@@ -162,7 +162,7 @@ Requires-Dist: httpx>=0.24
162
162
  Requires-Dist: platformdirs
163
163
  Requires-Dist: pyarrow
164
164
  Requires-Dist: typer>=0.9
165
- Requires-Dist: vgi-rpc>=0.28.3
165
+ Requires-Dist: vgi-rpc>=0.39.1
166
166
  Provides-Extra: azure
167
167
  Requires-Dist: azure-identity>=1.16.0; extra == 'azure'
168
168
  Requires-Dist: pymssql>=2.3.0; extra == 'azure'
@@ -190,8 +190,11 @@ Provides-Extra: duckdb
190
190
  Requires-Dist: duckdb>=1.5.3; extra == 'duckdb'
191
191
  Provides-Extra: fixtures
192
192
  Requires-Dist: vgi-fixtures; extra == 'fixtures'
193
+ Provides-Extra: granian
194
+ Requires-Dist: granian>=2.7; extra == 'granian'
195
+ Requires-Dist: vgi-rpc[http]; extra == 'granian'
193
196
  Provides-Extra: haybarn
194
- Requires-Dist: haybarn>=1.5.3rc10; extra == 'haybarn'
197
+ Requires-Dist: haybarn>=1.5.5rc1; extra == 'haybarn'
195
198
  Provides-Extra: http
196
199
  Requires-Dist: vgi-rpc[http]; extra == 'http'
197
200
  Provides-Extra: oauth
@@ -0,0 +1,88 @@
1
+ # Global functions
2
+
3
+ A VGI catalog normally exposes its functions under its own name — `mycat.main.my_func()`.
4
+ Some functions aren't *about* the attached catalog at all: diagnostics, converters, format
5
+ helpers. For those, a worker can ask the client to also publish them into the **global**
6
+ function namespace (DuckDB's `system.main`), so they can be called unqualified:
7
+
8
+ ```sql
9
+ ATTACH 'acme' AS acme (TYPE vgi, LOCATION 'acme-worker');
10
+ SELECT * FROM acme_table_info('acme'); -- no catalog qualifier
11
+ ```
12
+
13
+ This mirrors how `ducklake_table_info` is reachable after `LOAD ducklake`, except that a VGI
14
+ worker's globals appear at `ATTACH` time rather than at extension load.
15
+
16
+ ## Declaring globals
17
+
18
+ Add the function classes to `Catalog.global_functions` and pick a prefix:
19
+
20
+ ```python
21
+ from vgi.catalog import Catalog, Schema
22
+
23
+ CATALOG = Catalog(
24
+ name="acme",
25
+ global_function_prefix="acme",
26
+ global_functions=[TableInfoFunction, ChecksumFunction],
27
+ schemas=[
28
+ Schema(name="main", functions=[TableInfoFunction, ChecksumFunction, ...]),
29
+ ],
30
+ )
31
+ ```
32
+
33
+ All four function types are supported: scalar, aggregate, table, and table-buffering.
34
+
35
+ **Every global must also appear in exactly one `Schema.functions`.** This is enforced in
36
+ `Catalog.__post_init__`. Bind dispatch is keyed on `(schema_name, name)`, so a function listed
37
+ only in `global_functions` would be registered by the client but never dispatchable. Keeping it
38
+ schema-resident also means the qualified name (`acme.main.table_info()`) keeps working, which is
39
+ the unambiguous fallback if the global name is unavailable.
40
+
41
+ ### The prefix
42
+
43
+ `global_function_prefix` is applied by the client to form the globally visible name:
44
+
45
+ | prefix | function name | published as |
46
+ |---|---|---|
47
+ | `"acme"` | `table_info` | `acme_table_info` |
48
+ | `None` | `table_info` | `table_info` |
49
+
50
+ The prefix must match `[a-z_][a-z0-9_]*` — it is concatenated into a SQL identifier.
51
+
52
+ **Prefer a prefix.** `system.main` is shared by every extension and every attached VGI worker in
53
+ the process. An unprefixed name like `table_info` is very likely to be claimed by someone else,
54
+ in which case yours is silently skipped (see below). A prefix that identifies your worker makes
55
+ collisions essentially impossible.
56
+
57
+ ## What the client does with them
58
+
59
+ Registration is **best-effort and advisory**. Do not build anything that requires a global name
60
+ to resolve — treat it as an ergonomic alias for the schema-qualified name, which is the one with
61
+ guarantees.
62
+
63
+ Specifically, on the DuckDB side:
64
+
65
+ - **First attach wins.** If the name is already owned by a different worker, yours is skipped and
66
+ logged; your `ATTACH` still succeeds and the function stays reachable at its qualified path.
67
+ - **Re-`ATTACH` is idempotent.** Attaching the same worker again reuses the existing registration
68
+ and refreshes its connection state.
69
+ - **The user can turn it off.** `ATTACH ... (TYPE vgi, global_functions false)` suppresses
70
+ publishing entirely for that attach.
71
+ - **Registration outlives `DETACH`.** DuckDB has no API to unregister a function, so the entry
72
+ persists for the life of the process. Calling it after `DETACH` raises an error telling the user
73
+ to re-`ATTACH` rather than silently reconnecting to a detached catalog.
74
+
75
+ Use `vgi_global_functions()` to see what is currently published, who owns it, and whether it is
76
+ still live.
77
+
78
+ ## Protocol
79
+
80
+ Globals ride on the existing attach response — there is no extra round trip and no separate RPC.
81
+ `CatalogAttachResult` carries:
82
+
83
+ - `global_functions: list[bytes]` — IPC-serialized `FunctionInfo` records. `name` and
84
+ `schema_name` are the real dispatch coordinates; the prefix is *not* baked into `name`.
85
+ - `global_function_prefix: str` — empty string means publish bare names.
86
+
87
+ Both fields are additive and default to empty, so a worker that doesn't set them advertises
88
+ nothing. Introduced in protocol version 1.3.0.
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "vgi-python"
3
- version = "0.23.0"
3
+ version = "0.25.0"
4
4
  description = "Vector Gateway Interface - Connect DuckDB to external programs via Apache Arrow"
5
5
  readme = "README.md"
6
6
  keywords = [
@@ -40,7 +40,7 @@ dependencies = [
40
40
  "pyarrow",
41
41
  "typer>=0.9",
42
42
  "platformdirs",
43
- "vgi-rpc>=0.28.3",
43
+ "vgi-rpc>=0.39.1",
44
44
  "httpx>=0.24",
45
45
  ]
46
46
 
@@ -49,9 +49,13 @@ dependencies = [
49
49
  # evaluation, the transactor, and the statistics fixtures. It is resolved
50
50
  # lazily in vgi/_duckdb.py: haybarn is preferred, stock duckdb is the
51
51
  # fallback. Neither is a hard dependency — install one via these extras.
52
- haybarn = ["haybarn>=1.5.3rc10"]
52
+ haybarn = ["haybarn>=1.5.5rc1"]
53
53
  duckdb = ["duckdb>=1.5.3"]
54
54
  http = ["vgi-rpc[http]"]
55
+ # Alternative HTTP server: granian moves socket I/O and HTTP parsing into Rust,
56
+ # off the GIL. Optional because it is a compiled extension where waitress is
57
+ # pure Python; select it with `vgi-serve --http --server granian`.
58
+ granian = ["vgi-rpc[http]", "granian>=2.7"]
55
59
  oauth = ["vgi-rpc[oauth]"]
56
60
  otel = ["vgi-rpc[otel]"]
57
61
  sentry = ["vgi-rpc[sentry]"]
@@ -187,6 +191,12 @@ warn_unused_ignores = true
187
191
  module = "typer.*"
188
192
  ignore_missing_imports = true
189
193
 
194
+ [[tool.mypy.overrides]]
195
+ # granian ships no stubs, and is an optional extra used only behind
196
+ # `--server granian`.
197
+ module = "granian.*"
198
+ ignore_missing_imports = true
199
+
190
200
  [[tool.mypy.overrides]]
191
201
  # These files have type: ignore comments for ty that mypy doesn't need
192
202
  module = ["vgi._test_fixtures.scalar.null_handling", "vgi.table_function"]
@@ -26,6 +26,7 @@ from vgi.catalog import (
26
26
  Catalog,
27
27
  CatalogAttachResult,
28
28
  ForeignKeyDef,
29
+ FunctionInfo,
29
30
  Macro,
30
31
  MacroInfo,
31
32
  MacroType,
@@ -41,6 +42,7 @@ from vgi.catalog import (
41
42
  View,
42
43
  ViewInfo,
43
44
  )
45
+ from vgi.catalog.catalog_interface import FunctionType as CatalogInterfaceFunctionType
44
46
  from vgi.invocation import BindResponse
45
47
  from vgi.schema_utils import schema
46
48
  from vgi.table_function import (
@@ -1394,6 +1396,152 @@ class TestCatalogValidation:
1394
1396
  Catalog(name="myapp", schemas=[s1, s2])
1395
1397
 
1396
1398
 
1399
+ class TestGlobalFunctionsValidation:
1400
+ """Validation for ``Catalog.global_functions`` / ``global_function_prefix``."""
1401
+
1402
+ def test_defaults_are_empty(self) -> None:
1403
+ """A catalog publishes nothing globally unless it asks to."""
1404
+ catalog = Catalog(name="myapp", schemas=[Schema(name="main")])
1405
+ assert catalog.global_functions == ()
1406
+ assert catalog.global_function_prefix is None
1407
+
1408
+ def test_accepts_schema_resident_function(self) -> None:
1409
+ """The happy path: listed once globally, resident in exactly one schema."""
1410
+ catalog = Catalog(
1411
+ name="myapp",
1412
+ schemas=[Schema(name="main", functions=[UsersFunction])],
1413
+ global_functions=[UsersFunction],
1414
+ global_function_prefix="myapp",
1415
+ )
1416
+ assert list(catalog.global_functions) == [UsersFunction]
1417
+ assert catalog.global_function_prefix == "myapp"
1418
+
1419
+ def test_rejects_function_absent_from_every_schema(self) -> None:
1420
+ """A global function that isn't schema-resident would never dispatch."""
1421
+ with pytest.raises(ValueError, match="does not appear in any Schema.functions"):
1422
+ Catalog(
1423
+ name="myapp",
1424
+ schemas=[Schema(name="main")],
1425
+ global_functions=[UsersFunction],
1426
+ )
1427
+
1428
+ def test_rejects_function_resident_in_multiple_schemas(self) -> None:
1429
+ """Two homes make the global registration ambiguous about dispatch."""
1430
+ with pytest.raises(ValueError, match="appears in multiple schemas"):
1431
+ Catalog(
1432
+ name="myapp",
1433
+ schemas=[
1434
+ Schema(name="main", functions=[UsersFunction]),
1435
+ Schema(name="other", functions=[UsersFunction]),
1436
+ ],
1437
+ global_functions=[UsersFunction],
1438
+ )
1439
+
1440
+ def test_rejects_duplicate_global_entries(self) -> None:
1441
+ """Listing a class twice would publish the same name twice."""
1442
+ with pytest.raises(ValueError, match="duplicate entry UsersFunction"):
1443
+ Catalog(
1444
+ name="myapp",
1445
+ schemas=[Schema(name="main", functions=[UsersFunction])],
1446
+ global_functions=[UsersFunction, UsersFunction],
1447
+ )
1448
+
1449
+ @pytest.mark.parametrize("prefix", ["9bad", "Bad", "has-dash", "has space", "", "trailing;"])
1450
+ def test_rejects_non_identifier_prefix(self, prefix: str) -> None:
1451
+ """The prefix is concatenated into a SQL identifier, so it must be safe."""
1452
+ with pytest.raises(ValueError, match="not a valid SQL identifier prefix"):
1453
+ Catalog(
1454
+ name="myapp",
1455
+ schemas=[Schema(name="main", functions=[UsersFunction])],
1456
+ global_functions=[UsersFunction],
1457
+ global_function_prefix=prefix,
1458
+ )
1459
+
1460
+ def test_prefix_validated_even_without_global_functions(self) -> None:
1461
+ """A bad prefix is a bug worth reporting even if nothing uses it yet."""
1462
+ with pytest.raises(ValueError, match="not a valid SQL identifier prefix"):
1463
+ Catalog(name="myapp", schemas=[Schema(name="main")], global_function_prefix="Bad")
1464
+
1465
+
1466
+ class TestGlobalFunctionsAttachResult:
1467
+ """``catalog_attach`` advertises globals so the client can publish them."""
1468
+
1469
+ @staticmethod
1470
+ def _attach(catalog_obj: Catalog) -> CatalogAttachResult:
1471
+ class _TestCatalog(ReadOnlyCatalogInterface):
1472
+ catalog = catalog_obj
1473
+
1474
+ return _TestCatalog().catalog_attach(
1475
+ name=catalog_obj.name,
1476
+ options={},
1477
+ data_version_spec=None,
1478
+ implementation_version=None,
1479
+ )
1480
+
1481
+ def test_absent_when_not_declared(self) -> None:
1482
+ """Catalogs that declare nothing advertise an empty list and no prefix."""
1483
+ result = self._attach(Catalog(name="myapp", schemas=[Schema(name="main", functions=[UsersFunction])]))
1484
+ assert result.global_functions == []
1485
+ assert result.global_function_prefix == ""
1486
+
1487
+ def test_carries_serialized_function_info(self) -> None:
1488
+ """Each global arrives as a FunctionInfo with real dispatch coordinates.
1489
+
1490
+ ``name``/``schema_name`` must stay the values bind dispatches on — the
1491
+ prefix is applied client-side, not baked into the name here.
1492
+ """
1493
+ result = self._attach(
1494
+ Catalog(
1495
+ name="myapp",
1496
+ schemas=[Schema(name="analytics", functions=[UsersFunction])],
1497
+ default_schema="analytics",
1498
+ global_functions=[UsersFunction],
1499
+ global_function_prefix="myapp",
1500
+ )
1501
+ )
1502
+ assert result.global_function_prefix == "myapp"
1503
+ assert len(result.global_functions) == 1
1504
+
1505
+ info = FunctionInfo.deserialize_from_bytes(result.global_functions[0])
1506
+ assert info.name == "users"
1507
+ assert info.schema_name == "analytics"
1508
+ assert info.function_type == CatalogInterfaceFunctionType.TABLE
1509
+
1510
+ def test_prefix_empty_string_when_unset(self) -> None:
1511
+ """``None`` prefix serializes as empty string — the wire type is str."""
1512
+ result = self._attach(
1513
+ Catalog(
1514
+ name="myapp",
1515
+ schemas=[Schema(name="main", functions=[UsersFunction])],
1516
+ global_functions=[UsersFunction],
1517
+ )
1518
+ )
1519
+ assert result.global_function_prefix == ""
1520
+ assert len(result.global_functions) == 1
1521
+
1522
+ def test_example_fixture_publishes_one_of_each_function_type(self) -> None:
1523
+ """The shipped fixture covers all four types for the C++ integration suite."""
1524
+ from vgi._test_fixtures.worker import ExampleCatalog
1525
+
1526
+ result = ExampleCatalog().catalog_attach(
1527
+ name="example",
1528
+ options={},
1529
+ data_version_spec=None,
1530
+ implementation_version=None,
1531
+ )
1532
+ assert result.global_function_prefix == "vgi_example"
1533
+ infos = [FunctionInfo.deserialize_from_bytes(b) for b in result.global_functions]
1534
+ assert {i.function_type for i in infos} == {
1535
+ CatalogInterfaceFunctionType.SCALAR,
1536
+ CatalogInterfaceFunctionType.TABLE,
1537
+ CatalogInterfaceFunctionType.AGGREGATE,
1538
+ CatalogInterfaceFunctionType.TABLE_BUFFERING,
1539
+ }
1540
+ # Every advertised global must be schema-resident, or it could never
1541
+ # be dispatched after the client registers it.
1542
+ assert all(i.schema_name == "main" for i in infos)
1543
+
1544
+
1397
1545
  # =============================================================================
1398
1546
  # ReadOnlyCatalogInterface with Catalog Object Tests
1399
1547
  # =============================================================================
@@ -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) == 15
1113
+ assert len(schema) == 17
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_()
@@ -1121,6 +1121,8 @@ class TestArrowSchemaCorrectness:
1121
1121
  assert schema.field("settings").type == pa.list_(pa.binary())
1122
1122
  assert schema.field("secret_types").type == pa.list_(pa.binary())
1123
1123
  assert schema.field("attach_catalogs").type == pa.list_(pa.binary())
1124
+ assert schema.field("global_functions").type == pa.list_(pa.binary())
1125
+ assert schema.field("global_function_prefix").type == pa.string()
1124
1126
  assert schema.field("resolved_data_version").type == pa.string()
1125
1127
  assert schema.field("resolved_implementation_version").type == pa.string()
1126
1128
 
@@ -42,6 +42,19 @@ _EXEMPTIONS: dict[str, str] = {
42
42
  "path, ProcessParams.if_none_match threading, and the revalidatable "
43
43
  "fixture's 304 behavior)."
44
44
  ),
45
+ "global_functions": (
46
+ "Publishing worker-declared functions into DuckDB's system.main is "
47
+ "entirely a C++-extension concern: the registry, prefix application, "
48
+ "first-attach-wins collision policy, post-DETACH liveness, and the "
49
+ "vgi_global_functions() introspection surface all live in the "
50
+ "extension. The Python worker's only role is advertising "
51
+ "global_functions/global_function_prefix on the attach response, which "
52
+ "tests/catalog/test_declarative.py covers directly (descriptor "
53
+ "validation + the serialized FunctionInfo payload). The observable "
54
+ "behaviour is cross-language by construction and is covered by "
55
+ "vgi/test/sql/integration/global_functions/, which any worker "
56
+ "implementation runs via VGI_TEST_WORKER."
57
+ ),
45
58
  "filter_pushdown": (
46
59
  "Per-type filter-pushdown coverage is mirrored by tests/test_filter_pushdown.py "
47
60
  "and tests/test_filter_pushdown_extension.py, which drive the same predicate "
@@ -32,14 +32,14 @@ CLIENT_PROTOCOL_VERSION = VgiProtocol.protocol_version
32
32
 
33
33
  def test_client_protocol_version_is_canonical() -> None:
34
34
  """Sanity-check the constants this test reasons about haven't drifted apart."""
35
- assert CLIENT_PROTOCOL_VERSION == "1.2.0"
35
+ assert CLIENT_PROTOCOL_VERSION == "1.3.0"
36
36
  # The fixture must be a genuine mismatch in the major/minor that the
37
37
  # framework compares; a patch-only difference would (correctly) pass.
38
38
  assert BAD_PROTOCOL_VERSION.split(".")[:2] != CLIENT_PROTOCOL_VERSION.split(".")[:2]
39
39
 
40
40
 
41
41
  def test_mismatched_worker_protocol_version_raises() -> None:
42
- """A worker enforcing 99.0.0 must reject the 1.2.0 client at dispatch."""
42
+ """A worker enforcing 99.0.0 must reject the 1.3.0 client at dispatch."""
43
43
  with Client("vgi-fixture-bad-protocol-worker") as client, pytest.raises(ClientError) as exc_info:
44
44
  list(
45
45
  client.table_function(
@@ -54,5 +54,5 @@ def test_mismatched_worker_protocol_version_raises() -> None:
54
54
  assert "protocol_version mismatch" in message
55
55
  assert CLIENT_PROTOCOL_VERSION in message
56
56
  assert BAD_PROTOCOL_VERSION in message
57
- # Directional hint: the client (1.2.0) is older than the worker (99.0.0).
57
+ # Directional hint: the client (1.3.0) is older than the worker (99.0.0).
58
58
  assert "upgrade the VGI extension/client" in message
@@ -3,7 +3,7 @@
3
3
  {
4
4
  "attach_options": [],
5
5
  "counts": {
6
- "functions": 217,
6
+ "functions": 221,
7
7
  "schemas": 2,
8
8
  "tables": 59,
9
9
  "views": 3
@@ -371,6 +371,19 @@
371
371
  {
372
372
  "doc": "Example functions for testing VGI",
373
373
  "functions": [
374
+ {
375
+ "args": [
376
+ {
377
+ "desc": "Column to sum",
378
+ "name": "value",
379
+ "type": "int64"
380
+ }
381
+ ],
382
+ "doc": "Global-registration probe (aggregate)",
383
+ "name": "global_agg",
384
+ "returns": "int64",
385
+ "type": "aggregate"
386
+ },
374
387
  {
375
388
  "args": [
376
389
  {
@@ -979,6 +992,19 @@
979
992
  "returns": "double",
980
993
  "type": "scalar"
981
994
  },
995
+ {
996
+ "args": [
997
+ {
998
+ "desc": "Value to label",
999
+ "name": "value",
1000
+ "type": "int64"
1001
+ }
1002
+ ],
1003
+ "doc": "Global-registration probe (scalar)",
1004
+ "name": "global_scalar",
1005
+ "returns": "string",
1006
+ "type": "scalar"
1007
+ },
982
1008
  {
983
1009
  "args": [
984
1010
  {
@@ -2146,6 +2172,12 @@
2146
2172
  "name": "geo_encode",
2147
2173
  "type": "table"
2148
2174
  },
2175
+ {
2176
+ "args": [],
2177
+ "doc": "Global-registration probe (table)",
2178
+ "name": "global_table",
2179
+ "type": "table"
2180
+ },
2149
2181
  {
2150
2182
  "args": [
2151
2183
  {
@@ -3281,6 +3313,12 @@
3281
3313
  "name": "exception_process",
3282
3314
  "type": "table_in_out"
3283
3315
  },
3316
+ {
3317
+ "args": [],
3318
+ "doc": "Global-registration probe (table-buffering)",
3319
+ "name": "global_buffered",
3320
+ "type": "table_in_out"
3321
+ },
3284
3322
  {
3285
3323
  "args": [],
3286
3324
  "doc": "Worker sleeps in process (manual cancel test)",