vgi-python 0.20.0__tar.gz → 0.22.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 (398) hide show
  1. {vgi_python-0.20.0 → vgi_python-0.22.0}/PKG-INFO +2 -2
  2. {vgi_python-0.20.0 → vgi_python-0.22.0}/pyproject.toml +8 -2
  3. {vgi_python-0.20.0 → vgi_python-0.22.0}/tests/catalog/test_serialization.py +12 -6
  4. {vgi_python-0.20.0 → vgi_python-0.22.0}/tests/test_protocol_classes.py +58 -0
  5. {vgi_python-0.20.0 → vgi_python-0.22.0}/uv.lock +26 -26
  6. {vgi_python-0.20.0 → vgi_python-0.22.0}/vgi/_test_fixtures/http_server.py +14 -4
  7. {vgi_python-0.20.0 → vgi_python-0.22.0}/vgi/catalog/catalog_interface.py +4 -3
  8. {vgi_python-0.20.0 → vgi_python-0.22.0}/vgi/protocol.py +4 -4
  9. {vgi_python-0.20.0 → vgi_python-0.22.0}/vgi/serve.py +80 -6
  10. {vgi_python-0.20.0 → vgi_python-0.22.0}/.gitattributes +0 -0
  11. {vgi_python-0.20.0 → vgi_python-0.22.0}/.github/dependabot.yml +0 -0
  12. {vgi_python-0.20.0 → vgi_python-0.22.0}/.github/styles/config/vocabularies/VGI/accept.txt +0 -0
  13. {vgi_python-0.20.0 → vgi_python-0.22.0}/.github/workflows/ci.yml +0 -0
  14. {vgi_python-0.20.0 → vgi_python-0.22.0}/.github/workflows/docs.yml +0 -0
  15. {vgi_python-0.20.0 → vgi_python-0.22.0}/.github/workflows/integration.yml +0 -0
  16. {vgi_python-0.20.0 → vgi_python-0.22.0}/.github/workflows/release.yml +0 -0
  17. {vgi_python-0.20.0 → vgi_python-0.22.0}/.gitignore +0 -0
  18. {vgi_python-0.20.0 → vgi_python-0.22.0}/.python-version +0 -0
  19. {vgi_python-0.20.0 → vgi_python-0.22.0}/.vale.ini +0 -0
  20. {vgi_python-0.20.0 → vgi_python-0.22.0}/CLAUDE.md +0 -0
  21. {vgi_python-0.20.0 → vgi_python-0.22.0}/DOCS_ACCEPTANCE_CRITERIA.md +0 -0
  22. {vgi_python-0.20.0 → vgi_python-0.22.0}/DOCS_REVIEW_RUBRIC.md +0 -0
  23. {vgi_python-0.20.0 → vgi_python-0.22.0}/DOCS_USABILITY_TEST.md +0 -0
  24. {vgi_python-0.20.0 → vgi_python-0.22.0}/LICENSE +0 -0
  25. {vgi_python-0.20.0 → vgi_python-0.22.0}/README.md +0 -0
  26. {vgi_python-0.20.0 → vgi_python-0.22.0}/SECURITY.md +0 -0
  27. {vgi_python-0.20.0 → vgi_python-0.22.0}/ci/README.md +0 -0
  28. {vgi_python-0.20.0 → vgi_python-0.22.0}/ci/preprocess-require.awk +0 -0
  29. {vgi_python-0.20.0 → vgi_python-0.22.0}/ci/run-integration.sh +0 -0
  30. {vgi_python-0.20.0 → vgi_python-0.22.0}/dist-vgi/.gitignore +0 -0
  31. {vgi_python-0.20.0 → vgi_python-0.22.0}/docs/aggregate-functions.md +0 -0
  32. {vgi_python-0.20.0 → vgi_python-0.22.0}/docs/api/arguments.md +0 -0
  33. {vgi_python-0.20.0 → vgi_python-0.22.0}/docs/api/auth.md +0 -0
  34. {vgi_python-0.20.0 → vgi_python-0.22.0}/docs/api/catalogs.md +0 -0
  35. {vgi_python-0.20.0 → vgi_python-0.22.0}/docs/api/client.md +0 -0
  36. {vgi_python-0.20.0 → vgi_python-0.22.0}/docs/api/exceptions.md +0 -0
  37. {vgi_python-0.20.0 → vgi_python-0.22.0}/docs/api/filters.md +0 -0
  38. {vgi_python-0.20.0 → vgi_python-0.22.0}/docs/api/functions.md +0 -0
  39. {vgi_python-0.20.0 → vgi_python-0.22.0}/docs/api/http.md +0 -0
  40. {vgi_python-0.20.0 → vgi_python-0.22.0}/docs/api/index.md +0 -0
  41. {vgi_python-0.20.0 → vgi_python-0.22.0}/docs/api/metadata.md +0 -0
  42. {vgi_python-0.20.0 → vgi_python-0.22.0}/docs/api/observability.md +0 -0
  43. {vgi_python-0.20.0 → vgi_python-0.22.0}/docs/api/storage.md +0 -0
  44. {vgi_python-0.20.0 → vgi_python-0.22.0}/docs/api/transactor.md +0 -0
  45. {vgi_python-0.20.0 → vgi_python-0.22.0}/docs/api/worker.md +0 -0
  46. {vgi_python-0.20.0 → vgi_python-0.22.0}/docs/argument-serialization.md +0 -0
  47. {vgi_python-0.20.0 → vgi_python-0.22.0}/docs/assets/apple-touch-icon.png +0 -0
  48. {vgi_python-0.20.0 → vgi_python-0.22.0}/docs/assets/favicon-16x16.png +0 -0
  49. {vgi_python-0.20.0 → vgi_python-0.22.0}/docs/assets/favicon-32x32.png +0 -0
  50. {vgi_python-0.20.0 → vgi_python-0.22.0}/docs/assets/favicon.ico +0 -0
  51. {vgi_python-0.20.0 → vgi_python-0.22.0}/docs/assets/kinds/aggregate.svg +0 -0
  52. {vgi_python-0.20.0 → vgi_python-0.22.0}/docs/assets/kinds/buffering.svg +0 -0
  53. {vgi_python-0.20.0 → vgi_python-0.22.0}/docs/assets/kinds/scalar.svg +0 -0
  54. {vgi_python-0.20.0 → vgi_python-0.22.0}/docs/assets/kinds/table-in-out.svg +0 -0
  55. {vgi_python-0.20.0 → vgi_python-0.22.0}/docs/assets/kinds/table.svg +0 -0
  56. {vgi_python-0.20.0 → vgi_python-0.22.0}/docs/assets/logo.png +0 -0
  57. {vgi_python-0.20.0 → vgi_python-0.22.0}/docs/assets/social-card.png +0 -0
  58. {vgi_python-0.20.0 → vgi_python-0.22.0}/docs/authentication.md +0 -0
  59. {vgi_python-0.20.0 → vgi_python-0.22.0}/docs/catalog-interface.md +0 -0
  60. {vgi_python-0.20.0 → vgi_python-0.22.0}/docs/cli.md +0 -0
  61. {vgi_python-0.20.0 → vgi_python-0.22.0}/docs/column-statistics.md +0 -0
  62. {vgi_python-0.20.0 → vgi_python-0.22.0}/docs/concepts/index.md +0 -0
  63. {vgi_python-0.20.0 → vgi_python-0.22.0}/docs/contributing-docs.md +0 -0
  64. {vgi_python-0.20.0 → vgi_python-0.22.0}/docs/filter-pushdown.md +0 -0
  65. {vgi_python-0.20.0 → vgi_python-0.22.0}/docs/generator-api.md +0 -0
  66. {vgi_python-0.20.0 → vgi_python-0.22.0}/docs/how-to/catalogs.md +0 -0
  67. {vgi_python-0.20.0 → vgi_python-0.22.0}/docs/how-to/function-patterns.md +0 -0
  68. {vgi_python-0.20.0 → vgi_python-0.22.0}/docs/how-to/http-auth.md +0 -0
  69. {vgi_python-0.20.0 → vgi_python-0.22.0}/docs/how-to/index.md +0 -0
  70. {vgi_python-0.20.0 → vgi_python-0.22.0}/docs/how-to/pushdown-and-statistics.md +0 -0
  71. {vgi_python-0.20.0 → vgi_python-0.22.0}/docs/how-to/state-storage.md +0 -0
  72. {vgi_python-0.20.0 → vgi_python-0.22.0}/docs/index.md +0 -0
  73. {vgi_python-0.20.0 → vgi_python-0.22.0}/docs/lifecycle.md +0 -0
  74. {vgi_python-0.20.0 → vgi_python-0.22.0}/docs/metadata.md +0 -0
  75. {vgi_python-0.20.0 → vgi_python-0.22.0}/docs/overrides/main.html +0 -0
  76. {vgi_python-0.20.0 → vgi_python-0.22.0}/docs/robots.txt +0 -0
  77. {vgi_python-0.20.0 → vgi_python-0.22.0}/docs/shared-storage.md +0 -0
  78. {vgi_python-0.20.0 → vgi_python-0.22.0}/docs/stylesheets/extra.css +0 -0
  79. {vgi_python-0.20.0 → vgi_python-0.22.0}/docs/tutorial/index.md +0 -0
  80. {vgi_python-0.20.0 → vgi_python-0.22.0}/docs/tutorial/scalar.md +0 -0
  81. {vgi_python-0.20.0 → vgi_python-0.22.0}/docs/tutorial/table.md +0 -0
  82. {vgi_python-0.20.0 → vgi_python-0.22.0}/docs/vgi-logo.png +0 -0
  83. {vgi_python-0.20.0 → vgi_python-0.22.0}/examples/calc_scalar_worker.py +0 -0
  84. {vgi_python-0.20.0 → vgi_python-0.22.0}/examples/calc_worker.py +0 -0
  85. {vgi_python-0.20.0 → vgi_python-0.22.0}/examples/filter_worker.py +0 -0
  86. {vgi_python-0.20.0 → vgi_python-0.22.0}/examples/greeting_scalar_worker.py +0 -0
  87. {vgi_python-0.20.0 → vgi_python-0.22.0}/examples/row_count_worker.py +0 -0
  88. {vgi_python-0.20.0 → vgi_python-0.22.0}/examples/series_streaming_worker.py +0 -0
  89. {vgi_python-0.20.0 → vgi_python-0.22.0}/examples/sum_worker.py +0 -0
  90. {vgi_python-0.20.0 → vgi_python-0.22.0}/mkdocs.yml +0 -0
  91. {vgi_python-0.20.0 → vgi_python-0.22.0}/packages/vgi-fixtures/LICENSE +0 -0
  92. {vgi_python-0.20.0 → vgi_python-0.22.0}/packages/vgi-fixtures/README.md +0 -0
  93. {vgi_python-0.20.0 → vgi_python-0.22.0}/packages/vgi-fixtures/docker/Dockerfile +0 -0
  94. {vgi_python-0.20.0 → vgi_python-0.22.0}/packages/vgi-fixtures/docker/docker-entrypoint.sh +0 -0
  95. {vgi_python-0.20.0 → vgi_python-0.22.0}/packages/vgi-fixtures/pyproject.toml +0 -0
  96. {vgi_python-0.20.0 → vgi_python-0.22.0}/scripts/measure_startup.py +0 -0
  97. {vgi_python-0.20.0 → vgi_python-0.22.0}/scripts/run_all_tests.sh +0 -0
  98. {vgi_python-0.20.0 → vgi_python-0.22.0}/test-data/generate.sh +0 -0
  99. {vgi_python-0.20.0 → vgi_python-0.22.0}/tests/__init__.py +0 -0
  100. {vgi_python-0.20.0 → vgi_python-0.22.0}/tests/_http_fixtures.py +0 -0
  101. {vgi_python-0.20.0 → vgi_python-0.22.0}/tests/catalog/__init__.py +0 -0
  102. {vgi_python-0.20.0 → vgi_python-0.22.0}/tests/catalog/test_catalog_interface.py +0 -0
  103. {vgi_python-0.20.0 → vgi_python-0.22.0}/tests/catalog/test_client_catalog.py +0 -0
  104. {vgi_python-0.20.0 → vgi_python-0.22.0}/tests/catalog/test_column_statistics.py +0 -0
  105. {vgi_python-0.20.0 → vgi_python-0.22.0}/tests/catalog/test_declarative.py +0 -0
  106. {vgi_python-0.20.0 → vgi_python-0.22.0}/tests/catalog/test_example_worker_catalog.py +0 -0
  107. {vgi_python-0.20.0 → vgi_python-0.22.0}/tests/catalog/test_integration.py +0 -0
  108. {vgi_python-0.20.0 → vgi_python-0.22.0}/tests/catalog/test_required_filters.py +0 -0
  109. {vgi_python-0.20.0 → vgi_python-0.22.0}/tests/catalog/test_scan_branches.py +0 -0
  110. {vgi_python-0.20.0 → vgi_python-0.22.0}/tests/catalog/test_setting.py +0 -0
  111. {vgi_python-0.20.0 → vgi_python-0.22.0}/tests/catalog/test_storage.py +0 -0
  112. {vgi_python-0.20.0 → vgi_python-0.22.0}/tests/catalog/test_time_travel.py +0 -0
  113. {vgi_python-0.20.0 → vgi_python-0.22.0}/tests/catalog/test_writable_table.py +0 -0
  114. {vgi_python-0.20.0 → vgi_python-0.22.0}/tests/client/__init__.py +0 -0
  115. {vgi_python-0.20.0 → vgi_python-0.22.0}/tests/client/test_broken_pipe.py +0 -0
  116. {vgi_python-0.20.0 → vgi_python-0.22.0}/tests/client/test_cli.py +0 -0
  117. {vgi_python-0.20.0 → vgi_python-0.22.0}/tests/client/test_cli_catalog_functions.py +0 -0
  118. {vgi_python-0.20.0 → vgi_python-0.22.0}/tests/client/test_worker_debug.py +0 -0
  119. {vgi_python-0.20.0 → vgi_python-0.22.0}/tests/conformance/__init__.py +0 -0
  120. {vgi_python-0.20.0 → vgi_python-0.22.0}/tests/conformance/_stub.py +0 -0
  121. {vgi_python-0.20.0 → vgi_python-0.22.0}/tests/conformance/conftest.py +0 -0
  122. {vgi_python-0.20.0 → vgi_python-0.22.0}/tests/conformance/test_accumulate.py +0 -0
  123. {vgi_python-0.20.0 → vgi_python-0.22.0}/tests/conformance/test_aggregate.py +0 -0
  124. {vgi_python-0.20.0 → vgi_python-0.22.0}/tests/conformance/test_attach.py +0 -0
  125. {vgi_python-0.20.0 → vgi_python-0.22.0}/tests/conformance/test_bearer_auth.py +0 -0
  126. {vgi_python-0.20.0 → vgi_python-0.22.0}/tests/conformance/test_const_param_enforcement.py +0 -0
  127. {vgi_python-0.20.0 → vgi_python-0.22.0}/tests/conformance/test_container.py +0 -0
  128. {vgi_python-0.20.0 → vgi_python-0.22.0}/tests/conformance/test_copy_from.py +0 -0
  129. {vgi_python-0.20.0 → vgi_python-0.22.0}/tests/conformance/test_copy_to.py +0 -0
  130. {vgi_python-0.20.0 → vgi_python-0.22.0}/tests/conformance/test_directory_parity.py +0 -0
  131. {vgi_python-0.20.0 → vgi_python-0.22.0}/tests/conformance/test_function_inventory.py +0 -0
  132. {vgi_python-0.20.0 → vgi_python-0.22.0}/tests/conformance/test_github.py +0 -0
  133. {vgi_python-0.20.0 → vgi_python-0.22.0}/tests/conformance/test_http_client.py +0 -0
  134. {vgi_python-0.20.0 → vgi_python-0.22.0}/tests/conformance/test_http_external_location.py +0 -0
  135. {vgi_python-0.20.0 → vgi_python-0.22.0}/tests/conformance/test_http_upload_url.py +0 -0
  136. {vgi_python-0.20.0 → vgi_python-0.22.0}/tests/conformance/test_macro.py +0 -0
  137. {vgi_python-0.20.0 → vgi_python-0.22.0}/tests/conformance/test_overload.py +0 -0
  138. {vgi_python-0.20.0 → vgi_python-0.22.0}/tests/conformance/test_protocol_inventory.py +0 -0
  139. {vgi_python-0.20.0 → vgi_python-0.22.0}/tests/conformance/test_protocol_version.py +0 -0
  140. {vgi_python-0.20.0 → vgi_python-0.22.0}/tests/conformance/test_resumable_scan.py +0 -0
  141. {vgi_python-0.20.0 → vgi_python-0.22.0}/tests/conformance/test_scalar.py +0 -0
  142. {vgi_python-0.20.0 → vgi_python-0.22.0}/tests/conformance/test_scalar_attach_opaque_data.py +0 -0
  143. {vgi_python-0.20.0 → vgi_python-0.22.0}/tests/conformance/test_secret.py +0 -0
  144. {vgi_python-0.20.0 → vgi_python-0.22.0}/tests/conformance/test_settings.py +0 -0
  145. {vgi_python-0.20.0 → vgi_python-0.22.0}/tests/conformance/test_table.py +0 -0
  146. {vgi_python-0.20.0 → vgi_python-0.22.0}/tests/conformance/test_table_in_out.py +0 -0
  147. {vgi_python-0.20.0 → vgi_python-0.22.0}/tests/conformance/test_view.py +0 -0
  148. {vgi_python-0.20.0 → vgi_python-0.22.0}/tests/conformance/test_writable.py +0 -0
  149. {vgi_python-0.20.0 → vgi_python-0.22.0}/tests/conftest.py +0 -0
  150. {vgi_python-0.20.0 → vgi_python-0.22.0}/tests/landing/_checker.py +0 -0
  151. {vgi_python-0.20.0 → vgi_python-0.22.0}/tests/landing/describe.expected.json +0 -0
  152. {vgi_python-0.20.0 → vgi_python-0.22.0}/tests/landing/describe.schema.json +0 -0
  153. {vgi_python-0.20.0 → vgi_python-0.22.0}/tests/scalar/__init__.py +0 -0
  154. {vgi_python-0.20.0 → vgi_python-0.22.0}/tests/scalar/test_bernoulli_function.py +0 -0
  155. {vgi_python-0.20.0 → vgi_python-0.22.0}/tests/scalar/test_binary_packet_function.py +0 -0
  156. {vgi_python-0.20.0 → vgi_python-0.22.0}/tests/scalar/test_client.py +0 -0
  157. {vgi_python-0.20.0 → vgi_python-0.22.0}/tests/scalar/test_conditional_message_function.py +0 -0
  158. {vgi_python-0.20.0 → vgi_python-0.22.0}/tests/scalar/test_hash_seed_function.py +0 -0
  159. {vgi_python-0.20.0 → vgi_python-0.22.0}/tests/scalar/test_multiply_by_setting_function.py +0 -0
  160. {vgi_python-0.20.0 → vgi_python-0.22.0}/tests/scalar/test_multiply_function.py +0 -0
  161. {vgi_python-0.20.0 → vgi_python-0.22.0}/tests/scalar/test_random_bytes_function.py +0 -0
  162. {vgi_python-0.20.0 → vgi_python-0.22.0}/tests/scalar/test_return_secret_value_function.py +0 -0
  163. {vgi_python-0.20.0 → vgi_python-0.22.0}/tests/table/__init__.py +0 -0
  164. {vgi_python-0.20.0 → vgi_python-0.22.0}/tests/table/generator/__init__.py +0 -0
  165. {vgi_python-0.20.0 → vgi_python-0.22.0}/tests/table/generator/test_constant_columns_function.py +0 -0
  166. {vgi_python-0.20.0 → vgi_python-0.22.0}/tests/table/generator/test_double_sequence_function.py +0 -0
  167. {vgi_python-0.20.0 → vgi_python-0.22.0}/tests/table/generator/test_exception_function.py +0 -0
  168. {vgi_python-0.20.0 → vgi_python-0.22.0}/tests/table/generator/test_filter_echo_function.py +0 -0
  169. {vgi_python-0.20.0 → vgi_python-0.22.0}/tests/table/generator/test_logging_function.py +0 -0
  170. {vgi_python-0.20.0 → vgi_python-0.22.0}/tests/table/generator/test_nested_sequence_function.py +0 -0
  171. {vgi_python-0.20.0 → vgi_python-0.22.0}/tests/table/generator/test_partitioned_function.py +0 -0
  172. {vgi_python-0.20.0 → vgi_python-0.22.0}/tests/table/generator/test_projected_data_function.py +0 -0
  173. {vgi_python-0.20.0 → vgi_python-0.22.0}/tests/table/generator/test_sequence_function.py +0 -0
  174. {vgi_python-0.20.0 → vgi_python-0.22.0}/tests/table/generator/test_settings_function.py +0 -0
  175. {vgi_python-0.20.0 → vgi_python-0.22.0}/tests/table/generator/test_struct_settings_function.py +0 -0
  176. {vgi_python-0.20.0 → vgi_python-0.22.0}/tests/table/generator/test_ten_thousand_function.py +0 -0
  177. {vgi_python-0.20.0 → vgi_python-0.22.0}/tests/table_in_out/__init__.py +0 -0
  178. {vgi_python-0.20.0 → vgi_python-0.22.0}/tests/table_in_out/generator/__init__.py +0 -0
  179. {vgi_python-0.20.0 → vgi_python-0.22.0}/tests/table_in_out/generator/test_buffer_input_function.py +0 -0
  180. {vgi_python-0.20.0 → vgi_python-0.22.0}/tests/table_in_out/generator/test_echo_function.py +0 -0
  181. {vgi_python-0.20.0 → vgi_python-0.22.0}/tests/table_in_out/generator/test_exception_functions.py +0 -0
  182. {vgi_python-0.20.0 → vgi_python-0.22.0}/tests/table_in_out/generator/test_filter_by_setting_function.py +0 -0
  183. {vgi_python-0.20.0 → vgi_python-0.22.0}/tests/table_in_out/generator/test_repeat_inputs_function.py +0 -0
  184. {vgi_python-0.20.0 → vgi_python-0.22.0}/tests/table_in_out/generator/test_substream_partial_sum_function.py +0 -0
  185. {vgi_python-0.20.0 → vgi_python-0.22.0}/tests/table_in_out/generator/test_sum_all_columns_function.py +0 -0
  186. {vgi_python-0.20.0 → vgi_python-0.22.0}/tests/table_in_out/test_blended_metadata.py +0 -0
  187. {vgi_python-0.20.0 → vgi_python-0.22.0}/tests/table_in_out/test_client.py +0 -0
  188. {vgi_python-0.20.0 → vgi_python-0.22.0}/tests/test_access_log_audit.py +0 -0
  189. {vgi_python-0.20.0 → vgi_python-0.22.0}/tests/test_aggregate_function.py +0 -0
  190. {vgi_python-0.20.0 → vgi_python-0.22.0}/tests/test_argument_spec.py +0 -0
  191. {vgi_python-0.20.0 → vgi_python-0.22.0}/tests/test_auth.py +0 -0
  192. {vgi_python-0.20.0 → vgi_python-0.22.0}/tests/test_bind_exceptions.py +0 -0
  193. {vgi_python-0.20.0 → vgi_python-0.22.0}/tests/test_bind_request_at_clause.py +0 -0
  194. {vgi_python-0.20.0 → vgi_python-0.22.0}/tests/test_bound_storage_conformance.py +0 -0
  195. {vgi_python-0.20.0 → vgi_python-0.22.0}/tests/test_cache_control.py +0 -0
  196. {vgi_python-0.20.0 → vgi_python-0.22.0}/tests/test_catalog_auth_binding.py +0 -0
  197. {vgi_python-0.20.0 → vgi_python-0.22.0}/tests/test_copy_from_function.py +0 -0
  198. {vgi_python-0.20.0 → vgi_python-0.22.0}/tests/test_copy_to_function.py +0 -0
  199. {vgi_python-0.20.0 → vgi_python-0.22.0}/tests/test_docstrings.py +0 -0
  200. {vgi_python-0.20.0 → vgi_python-0.22.0}/tests/test_documentation_examples.py +0 -0
  201. {vgi_python-0.20.0 → vgi_python-0.22.0}/tests/test_example_function_arg_types.py +0 -0
  202. {vgi_python-0.20.0 → vgi_python-0.22.0}/tests/test_examples_workers.py +0 -0
  203. {vgi_python-0.20.0 → vgi_python-0.22.0}/tests/test_exception_handling.py +0 -0
  204. {vgi_python-0.20.0 → vgi_python-0.22.0}/tests/test_exceptions.py +0 -0
  205. {vgi_python-0.20.0 → vgi_python-0.22.0}/tests/test_filter_pushdown.py +0 -0
  206. {vgi_python-0.20.0 → vgi_python-0.22.0}/tests/test_filter_pushdown_extension.py +0 -0
  207. {vgi_python-0.20.0 → vgi_python-0.22.0}/tests/test_function_storage.py +0 -0
  208. {vgi_python-0.20.0 → vgi_python-0.22.0}/tests/test_function_storage_azure_sql.py +0 -0
  209. {vgi_python-0.20.0 → vgi_python-0.22.0}/tests/test_function_storage_cf_do.py +0 -0
  210. {vgi_python-0.20.0 → vgi_python-0.22.0}/tests/test_function_storage_cf_do_integration.py +0 -0
  211. {vgi_python-0.20.0 → vgi_python-0.22.0}/tests/test_function_storage_conformance.py +0 -0
  212. {vgi_python-0.20.0 → vgi_python-0.22.0}/tests/test_generated_cpp_constants.py +0 -0
  213. {vgi_python-0.20.0 → vgi_python-0.22.0}/tests/test_generated_cpp_protocol_version.py +0 -0
  214. {vgi_python-0.20.0 → vgi_python-0.22.0}/tests/test_generated_cpp_request_builders.py +0 -0
  215. {vgi_python-0.20.0 → vgi_python-0.22.0}/tests/test_generated_cpp_schemas.py +0 -0
  216. {vgi_python-0.20.0 → vgi_python-0.22.0}/tests/test_generated_cpp_secret.py +0 -0
  217. {vgi_python-0.20.0 → vgi_python-0.22.0}/tests/test_generated_go_schemas.py +0 -0
  218. {vgi_python-0.20.0 → vgi_python-0.22.0}/tests/test_generated_protocol_version.py +0 -0
  219. {vgi_python-0.20.0 → vgi_python-0.22.0}/tests/test_generated_schemas_cross_lang.py +0 -0
  220. {vgi_python-0.20.0 → vgi_python-0.22.0}/tests/test_generated_ts_client.py +0 -0
  221. {vgi_python-0.20.0 → vgi_python-0.22.0}/tests/test_generated_ts_schemas.py +0 -0
  222. {vgi_python-0.20.0 → vgi_python-0.22.0}/tests/test_http_demo_storage.py +0 -0
  223. {vgi_python-0.20.0 → vgi_python-0.22.0}/tests/test_http_s3_offload_input.py +0 -0
  224. {vgi_python-0.20.0 → vgi_python-0.22.0}/tests/test_http_s3_offload_output.py +0 -0
  225. {vgi_python-0.20.0 → vgi_python-0.22.0}/tests/test_landing_conformance.py +0 -0
  226. {vgi_python-0.20.0 → vgi_python-0.22.0}/tests/test_metadata.py +0 -0
  227. {vgi_python-0.20.0 → vgi_python-0.22.0}/tests/test_mypy_consolidated.py +0 -0
  228. {vgi_python-0.20.0 → vgi_python-0.22.0}/tests/test_nest_tensor.py +0 -0
  229. {vgi_python-0.20.0 → vgi_python-0.22.0}/tests/test_otel.py +0 -0
  230. {vgi_python-0.20.0 → vgi_python-0.22.0}/tests/test_projection_enforcement.py +0 -0
  231. {vgi_python-0.20.0 → vgi_python-0.22.0}/tests/test_projection_repro.py +0 -0
  232. {vgi_python-0.20.0 → vgi_python-0.22.0}/tests/test_resolved_secrets.py +0 -0
  233. {vgi_python-0.20.0 → vgi_python-0.22.0}/tests/test_schema_scoped_functions.py +0 -0
  234. {vgi_python-0.20.0 → vgi_python-0.22.0}/tests/test_schema_utils.py +0 -0
  235. {vgi_python-0.20.0 → vgi_python-0.22.0}/tests/test_serve.py +0 -0
  236. {vgi_python-0.20.0 → vgi_python-0.22.0}/tests/test_setting_secret_annotations.py +0 -0
  237. {vgi_python-0.20.0 → vgi_python-0.22.0}/tests/test_table_buffering_function.py +0 -0
  238. {vgi_python-0.20.0 → vgi_python-0.22.0}/tests/test_table_function_dynamic_to_string.py +0 -0
  239. {vgi_python-0.20.0 → vgi_python-0.22.0}/tests/test_tcp_transport.py +0 -0
  240. {vgi_python-0.20.0 → vgi_python-0.22.0}/tests/test_type_bounds.py +0 -0
  241. {vgi_python-0.20.0 → vgi_python-0.22.0}/tests/test_union_argument.py +0 -0
  242. {vgi_python-0.20.0 → vgi_python-0.22.0}/tests/test_worker.py +0 -0
  243. {vgi_python-0.20.0 → vgi_python-0.22.0}/tests/test_worker_cli.py +0 -0
  244. {vgi_python-0.20.0 → vgi_python-0.22.0}/tests/test_worker_page.py +0 -0
  245. {vgi_python-0.20.0 → vgi_python-0.22.0}/tests/transactor/__init__.py +0 -0
  246. {vgi_python-0.20.0 → vgi_python-0.22.0}/tests/transactor/test_transactor.py +0 -0
  247. {vgi_python-0.20.0 → vgi_python-0.22.0}/vgi/__init__.py +0 -0
  248. {vgi_python-0.20.0 → vgi_python-0.22.0}/vgi/_duckdb.py +0 -0
  249. {vgi_python-0.20.0 → vgi_python-0.22.0}/vgi/_storage_profile.py +0 -0
  250. {vgi_python-0.20.0 → vgi_python-0.22.0}/vgi/_test_fixtures/__init__.py +0 -0
  251. {vgi_python-0.20.0 → vgi_python-0.22.0}/vgi/_test_fixtures/accumulate/__init__.py +0 -0
  252. {vgi_python-0.20.0 → vgi_python-0.22.0}/vgi/_test_fixtures/accumulate/worker.py +0 -0
  253. {vgi_python-0.20.0 → vgi_python-0.22.0}/vgi/_test_fixtures/aggregate/__init__.py +0 -0
  254. {vgi_python-0.20.0 → vgi_python-0.22.0}/vgi/_test_fixtures/aggregate/_common.py +0 -0
  255. {vgi_python-0.20.0 → vgi_python-0.22.0}/vgi/_test_fixtures/aggregate/basic.py +0 -0
  256. {vgi_python-0.20.0 → vgi_python-0.22.0}/vgi/_test_fixtures/aggregate/dynamic.py +0 -0
  257. {vgi_python-0.20.0 → vgi_python-0.22.0}/vgi/_test_fixtures/aggregate/generic.py +0 -0
  258. {vgi_python-0.20.0 → vgi_python-0.22.0}/vgi/_test_fixtures/aggregate/listagg.py +0 -0
  259. {vgi_python-0.20.0 → vgi_python-0.22.0}/vgi/_test_fixtures/aggregate/percentile.py +0 -0
  260. {vgi_python-0.20.0 → vgi_python-0.22.0}/vgi/_test_fixtures/aggregate/same_name.py +0 -0
  261. {vgi_python-0.20.0 → vgi_python-0.22.0}/vgi/_test_fixtures/aggregate/secret_typed.py +0 -0
  262. {vgi_python-0.20.0 → vgi_python-0.22.0}/vgi/_test_fixtures/aggregate/streaming.py +0 -0
  263. {vgi_python-0.20.0 → vgi_python-0.22.0}/vgi/_test_fixtures/aggregate/varargs.py +0 -0
  264. {vgi_python-0.20.0 → vgi_python-0.22.0}/vgi/_test_fixtures/aggregate/window.py +0 -0
  265. {vgi_python-0.20.0 → vgi_python-0.22.0}/vgi/_test_fixtures/attach_options.py +0 -0
  266. {vgi_python-0.20.0 → vgi_python-0.22.0}/vgi/_test_fixtures/bad_enum.py +0 -0
  267. {vgi_python-0.20.0 → vgi_python-0.22.0}/vgi/_test_fixtures/bad_protocol.py +0 -0
  268. {vgi_python-0.20.0 → vgi_python-0.22.0}/vgi/_test_fixtures/cancellable.py +0 -0
  269. {vgi_python-0.20.0 → vgi_python-0.22.0}/vgi/_test_fixtures/catalog.py +0 -0
  270. {vgi_python-0.20.0 → vgi_python-0.22.0}/vgi/_test_fixtures/companion.py +0 -0
  271. {vgi_python-0.20.0 → vgi_python-0.22.0}/vgi/_test_fixtures/copy_from.py +0 -0
  272. {vgi_python-0.20.0 → vgi_python-0.22.0}/vgi/_test_fixtures/copy_to.py +0 -0
  273. {vgi_python-0.20.0 → vgi_python-0.22.0}/vgi/_test_fixtures/narrow_bind/__init__.py +0 -0
  274. {vgi_python-0.20.0 → vgi_python-0.22.0}/vgi/_test_fixtures/narrow_bind/worker.py +0 -0
  275. {vgi_python-0.20.0 → vgi_python-0.22.0}/vgi/_test_fixtures/nest_tensor.py +0 -0
  276. {vgi_python-0.20.0 → vgi_python-0.22.0}/vgi/_test_fixtures/orchard_catalog.py +0 -0
  277. {vgi_python-0.20.0 → vgi_python-0.22.0}/vgi/_test_fixtures/projection_repro/__init__.py +0 -0
  278. {vgi_python-0.20.0 → vgi_python-0.22.0}/vgi/_test_fixtures/projection_repro/worker.py +0 -0
  279. {vgi_python-0.20.0 → vgi_python-0.22.0}/vgi/_test_fixtures/scalar/__init__.py +0 -0
  280. {vgi_python-0.20.0 → vgi_python-0.22.0}/vgi/_test_fixtures/scalar/_common.py +0 -0
  281. {vgi_python-0.20.0 → vgi_python-0.22.0}/vgi/_test_fixtures/scalar/arithmetic.py +0 -0
  282. {vgi_python-0.20.0 → vgi_python-0.22.0}/vgi/_test_fixtures/scalar/bench_ladder.py +0 -0
  283. {vgi_python-0.20.0 → vgi_python-0.22.0}/vgi/_test_fixtures/scalar/binary.py +0 -0
  284. {vgi_python-0.20.0 → vgi_python-0.22.0}/vgi/_test_fixtures/scalar/formatting.py +0 -0
  285. {vgi_python-0.20.0 → vgi_python-0.22.0}/vgi/_test_fixtures/scalar/geo.py +0 -0
  286. {vgi_python-0.20.0 → vgi_python-0.22.0}/vgi/_test_fixtures/scalar/null_handling.py +0 -0
  287. {vgi_python-0.20.0 → vgi_python-0.22.0}/vgi/_test_fixtures/scalar/random_demo.py +0 -0
  288. {vgi_python-0.20.0 → vgi_python-0.22.0}/vgi/_test_fixtures/scalar/same_name.py +0 -0
  289. {vgi_python-0.20.0 → vgi_python-0.22.0}/vgi/_test_fixtures/scalar/settings_secrets.py +0 -0
  290. {vgi_python-0.20.0 → vgi_python-0.22.0}/vgi/_test_fixtures/scalar/type_info.py +0 -0
  291. {vgi_python-0.20.0 → vgi_python-0.22.0}/vgi/_test_fixtures/schema_reconcile/__init__.py +0 -0
  292. {vgi_python-0.20.0 → vgi_python-0.22.0}/vgi/_test_fixtures/schema_reconcile/worker.py +0 -0
  293. {vgi_python-0.20.0 → vgi_python-0.22.0}/vgi/_test_fixtures/simple_writable.py +0 -0
  294. {vgi_python-0.20.0 → vgi_python-0.22.0}/vgi/_test_fixtures/table/__init__.py +0 -0
  295. {vgi_python-0.20.0 → vgi_python-0.22.0}/vgi/_test_fixtures/table/_common.py +0 -0
  296. {vgi_python-0.20.0 → vgi_python-0.22.0}/vgi/_test_fixtures/table/batch_index.py +0 -0
  297. {vgi_python-0.20.0 → vgi_python-0.22.0}/vgi/_test_fixtures/table/batch_index_broken.py +0 -0
  298. {vgi_python-0.20.0 → vgi_python-0.22.0}/vgi/_test_fixtures/table/cache.py +0 -0
  299. {vgi_python-0.20.0 → vgi_python-0.22.0}/vgi/_test_fixtures/table/catalog_scans.py +0 -0
  300. {vgi_python-0.20.0 → vgi_python-0.22.0}/vgi/_test_fixtures/table/filters.py +0 -0
  301. {vgi_python-0.20.0 → vgi_python-0.22.0}/vgi/_test_fixtures/table/late_materialization.py +0 -0
  302. {vgi_python-0.20.0 → vgi_python-0.22.0}/vgi/_test_fixtures/table/make_series.py +0 -0
  303. {vgi_python-0.20.0 → vgi_python-0.22.0}/vgi/_test_fixtures/table/misc.py +0 -0
  304. {vgi_python-0.20.0 → vgi_python-0.22.0}/vgi/_test_fixtures/table/order_modes.py +0 -0
  305. {vgi_python-0.20.0 → vgi_python-0.22.0}/vgi/_test_fixtures/table/pairs.py +0 -0
  306. {vgi_python-0.20.0 → vgi_python-0.22.0}/vgi/_test_fixtures/table/partition_columns.py +0 -0
  307. {vgi_python-0.20.0 → vgi_python-0.22.0}/vgi/_test_fixtures/table/partition_columns_broken.py +0 -0
  308. {vgi_python-0.20.0 → vgi_python-0.22.0}/vgi/_test_fixtures/table/profiling_example.py +0 -0
  309. {vgi_python-0.20.0 → vgi_python-0.22.0}/vgi/_test_fixtures/table/required_filters.py +0 -0
  310. {vgi_python-0.20.0 → vgi_python-0.22.0}/vgi/_test_fixtures/table/same_name_cached.py +0 -0
  311. {vgi_python-0.20.0 → vgi_python-0.22.0}/vgi/_test_fixtures/table/sequence.py +0 -0
  312. {vgi_python-0.20.0 → vgi_python-0.22.0}/vgi/_test_fixtures/table/settings.py +0 -0
  313. {vgi_python-0.20.0 → vgi_python-0.22.0}/vgi/_test_fixtures/table/transaction_storage.py +0 -0
  314. {vgi_python-0.20.0 → vgi_python-0.22.0}/vgi/_test_fixtures/table/tt_pushdown.py +0 -0
  315. {vgi_python-0.20.0 → vgi_python-0.22.0}/vgi/_test_fixtures/table/typed_probe.py +0 -0
  316. {vgi_python-0.20.0 → vgi_python-0.22.0}/vgi/_test_fixtures/table/versioned.py +0 -0
  317. {vgi_python-0.20.0 → vgi_python-0.22.0}/vgi/_test_fixtures/table_in_out.py +0 -0
  318. {vgi_python-0.20.0 → vgi_python-0.22.0}/vgi/_test_fixtures/table_in_out_same_name.py +0 -0
  319. {vgi_python-0.20.0 → vgi_python-0.22.0}/vgi/_test_fixtures/twin_catalogs.py +0 -0
  320. {vgi_python-0.20.0 → vgi_python-0.22.0}/vgi/_test_fixtures/versioned.py +0 -0
  321. {vgi_python-0.20.0 → vgi_python-0.22.0}/vgi/_test_fixtures/versioned_tables.py +0 -0
  322. {vgi_python-0.20.0 → vgi_python-0.22.0}/vgi/_test_fixtures/worker.py +0 -0
  323. {vgi_python-0.20.0 → vgi_python-0.22.0}/vgi/_test_fixtures/writable/__init__.py +0 -0
  324. {vgi_python-0.20.0 → vgi_python-0.22.0}/vgi/_test_fixtures/writable/generic.py +0 -0
  325. {vgi_python-0.20.0 → vgi_python-0.22.0}/vgi/_test_fixtures/writable/table.py +0 -0
  326. {vgi_python-0.20.0 → vgi_python-0.22.0}/vgi/_test_fixtures/writable/worker.py +0 -0
  327. {vgi_python-0.20.0 → vgi_python-0.22.0}/vgi/aggregate_function.py +0 -0
  328. {vgi_python-0.20.0 → vgi_python-0.22.0}/vgi/argument_spec.py +0 -0
  329. {vgi_python-0.20.0 → vgi_python-0.22.0}/vgi/arguments.py +0 -0
  330. {vgi_python-0.20.0 → vgi_python-0.22.0}/vgi/attach_header.py +0 -0
  331. {vgi_python-0.20.0 → vgi_python-0.22.0}/vgi/auth.py +0 -0
  332. {vgi_python-0.20.0 → vgi_python-0.22.0}/vgi/cache_control.py +0 -0
  333. {vgi_python-0.20.0 → vgi_python-0.22.0}/vgi/catalog/__init__.py +0 -0
  334. {vgi_python-0.20.0 → vgi_python-0.22.0}/vgi/catalog/_descriptor_spec.py +0 -0
  335. {vgi_python-0.20.0 → vgi_python-0.22.0}/vgi/catalog/attach_option.py +0 -0
  336. {vgi_python-0.20.0 → vgi_python-0.22.0}/vgi/catalog/descriptors.py +0 -0
  337. {vgi_python-0.20.0 → vgi_python-0.22.0}/vgi/catalog/duckdb_statistics.py +0 -0
  338. {vgi_python-0.20.0 → vgi_python-0.22.0}/vgi/catalog/secret_type.py +0 -0
  339. {vgi_python-0.20.0 → vgi_python-0.22.0}/vgi/catalog/setting.py +0 -0
  340. {vgi_python-0.20.0 → vgi_python-0.22.0}/vgi/catalog/storage.py +0 -0
  341. {vgi_python-0.20.0 → vgi_python-0.22.0}/vgi/client/__init__.py +0 -0
  342. {vgi_python-0.20.0 → vgi_python-0.22.0}/vgi/client/catalog_mixin.py +0 -0
  343. {vgi_python-0.20.0 → vgi_python-0.22.0}/vgi/client/cli.py +0 -0
  344. {vgi_python-0.20.0 → vgi_python-0.22.0}/vgi/client/cli_catalog.py +0 -0
  345. {vgi_python-0.20.0 → vgi_python-0.22.0}/vgi/client/cli_schema.py +0 -0
  346. {vgi_python-0.20.0 → vgi_python-0.22.0}/vgi/client/cli_table.py +0 -0
  347. {vgi_python-0.20.0 → vgi_python-0.22.0}/vgi/client/cli_transaction.py +0 -0
  348. {vgi_python-0.20.0 → vgi_python-0.22.0}/vgi/client/cli_utils.py +0 -0
  349. {vgi_python-0.20.0 → vgi_python-0.22.0}/vgi/client/cli_view.py +0 -0
  350. {vgi_python-0.20.0 → vgi_python-0.22.0}/vgi/client/client.py +0 -0
  351. {vgi_python-0.20.0 → vgi_python-0.22.0}/vgi/codegen/__init__.py +0 -0
  352. {vgi_python-0.20.0 → vgi_python-0.22.0}/vgi/codegen/_common.py +0 -0
  353. {vgi_python-0.20.0 → vgi_python-0.22.0}/vgi/codegen/cpp_constants.py +0 -0
  354. {vgi_python-0.20.0 → vgi_python-0.22.0}/vgi/codegen/cpp_protocol_version.py +0 -0
  355. {vgi_python-0.20.0 → vgi_python-0.22.0}/vgi/codegen/cpp_request_builders.py +0 -0
  356. {vgi_python-0.20.0 → vgi_python-0.22.0}/vgi/codegen/cpp_schemas.py +0 -0
  357. {vgi_python-0.20.0 → vgi_python-0.22.0}/vgi/codegen/cpp_secret_protocol_version.py +0 -0
  358. {vgi_python-0.20.0 → vgi_python-0.22.0}/vgi/codegen/cpp_secret_request_builders.py +0 -0
  359. {vgi_python-0.20.0 → vgi_python-0.22.0}/vgi/codegen/cpp_secret_schemas.py +0 -0
  360. {vgi_python-0.20.0 → vgi_python-0.22.0}/vgi/codegen/go_schemas.py +0 -0
  361. {vgi_python-0.20.0 → vgi_python-0.22.0}/vgi/codegen/protocol_version.py +0 -0
  362. {vgi_python-0.20.0 → vgi_python-0.22.0}/vgi/codegen/ts_client.py +0 -0
  363. {vgi_python-0.20.0 → vgi_python-0.22.0}/vgi/codegen/ts_schemas.py +0 -0
  364. {vgi_python-0.20.0 → vgi_python-0.22.0}/vgi/copy_from_function.py +0 -0
  365. {vgi_python-0.20.0 → vgi_python-0.22.0}/vgi/copy_to_function.py +0 -0
  366. {vgi_python-0.20.0 → vgi_python-0.22.0}/vgi/exceptions.py +0 -0
  367. {vgi_python-0.20.0 → vgi_python-0.22.0}/vgi/function.py +0 -0
  368. {vgi_python-0.20.0 → vgi_python-0.22.0}/vgi/function_storage.py +0 -0
  369. {vgi_python-0.20.0 → vgi_python-0.22.0}/vgi/function_storage_azure_sql.py +0 -0
  370. {vgi_python-0.20.0 → vgi_python-0.22.0}/vgi/function_storage_cf_do.py +0 -0
  371. {vgi_python-0.20.0 → vgi_python-0.22.0}/vgi/http/__init__.py +0 -0
  372. {vgi_python-0.20.0 → vgi_python-0.22.0}/vgi/http/demo_storage.py +0 -0
  373. {vgi_python-0.20.0 → vgi_python-0.22.0}/vgi/http/describe_json.py +0 -0
  374. {vgi_python-0.20.0 → vgi_python-0.22.0}/vgi/http/landing.html +0 -0
  375. {vgi_python-0.20.0 → vgi_python-0.22.0}/vgi/http/landing_page.py +0 -0
  376. {vgi_python-0.20.0 → vgi_python-0.22.0}/vgi/http/worker_page.py +0 -0
  377. {vgi_python-0.20.0 → vgi_python-0.22.0}/vgi/invocation.py +0 -0
  378. {vgi_python-0.20.0 → vgi_python-0.22.0}/vgi/logging_config.py +0 -0
  379. {vgi_python-0.20.0 → vgi_python-0.22.0}/vgi/meta_worker.py +0 -0
  380. {vgi_python-0.20.0 → vgi_python-0.22.0}/vgi/metadata.py +0 -0
  381. {vgi_python-0.20.0 → vgi_python-0.22.0}/vgi/otel.py +0 -0
  382. {vgi_python-0.20.0 → vgi_python-0.22.0}/vgi/protocol_version.txt +0 -0
  383. {vgi_python-0.20.0 → vgi_python-0.22.0}/vgi/py.typed +0 -0
  384. {vgi_python-0.20.0 → vgi_python-0.22.0}/vgi/scalar_function.py +0 -0
  385. {vgi_python-0.20.0 → vgi_python-0.22.0}/vgi/schema_utils.py +0 -0
  386. {vgi_python-0.20.0 → vgi_python-0.22.0}/vgi/secret_protocol.py +0 -0
  387. {vgi_python-0.20.0 → vgi_python-0.22.0}/vgi/secret_service.py +0 -0
  388. {vgi_python-0.20.0 → vgi_python-0.22.0}/vgi/table_buffering_function.py +0 -0
  389. {vgi_python-0.20.0 → vgi_python-0.22.0}/vgi/table_filter_pushdown.py +0 -0
  390. {vgi_python-0.20.0 → vgi_python-0.22.0}/vgi/table_function.py +0 -0
  391. {vgi_python-0.20.0 → vgi_python-0.22.0}/vgi/table_in_out_function.py +0 -0
  392. {vgi_python-0.20.0 → vgi_python-0.22.0}/vgi/transactor/__init__.py +0 -0
  393. {vgi_python-0.20.0 → vgi_python-0.22.0}/vgi/transactor/_duckdb_compat.py +0 -0
  394. {vgi_python-0.20.0 → vgi_python-0.22.0}/vgi/transactor/client.py +0 -0
  395. {vgi_python-0.20.0 → vgi_python-0.22.0}/vgi/transactor/protocol.py +0 -0
  396. {vgi_python-0.20.0 → vgi_python-0.22.0}/vgi/transactor/server.py +0 -0
  397. {vgi_python-0.20.0 → vgi_python-0.22.0}/vgi/worker.py +0 -0
  398. {vgi_python-0.20.0 → vgi_python-0.22.0}/wrangler.jsonc +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: vgi-python
3
- Version: 0.20.0
3
+ Version: 0.22.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.26.0
165
+ Requires-Dist: vgi-rpc>=0.28.2
166
166
  Provides-Extra: azure
167
167
  Requires-Dist: azure-identity>=1.16.0; extra == 'azure'
168
168
  Requires-Dist: pymssql>=2.3.0; extra == 'azure'
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "vgi-python"
3
- version = "0.20.0"
3
+ version = "0.22.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.26.0",
43
+ "vgi-rpc>=0.28.2",
44
44
  "httpx>=0.24",
45
45
  ]
46
46
 
@@ -142,6 +142,12 @@ convention = "google"
142
142
 
143
143
  [tool.ruff.format]
144
144
  quote-style = "double"
145
+ # ruff >=0.16 formats Python code blocks embedded in Markdown. Our docs use
146
+ # mkdocs `pymdownx.snippets` includes (`--8<-- "examples/foo.py"`) inside
147
+ # ```python fences; ruff parses those as Python and rewrites them to
148
+ # `--8 < --"..."`, breaking both the docs build and the doc-example tests.
149
+ # Keep Markdown out.
150
+ exclude = ["*.md"]
145
151
 
146
152
  [tool.pydoclint]
147
153
  # Docstring consistency gate (complements ruff's `D` rules, which only check
@@ -1275,16 +1275,22 @@ class TestScanBranchSerialization:
1275
1275
  assert restored.branches[1].function_name == "iceberg_scan"
1276
1276
  assert restored.required_extensions == ["iceberg", "httpfs"]
1277
1277
 
1278
- def test_scan_branches_result_empty_branches_rejected(self) -> None:
1279
- """Empty branches list is rejected at deserialize — workers must return >=1 branch."""
1280
- import pytest
1281
-
1278
+ def test_scan_branches_result_empty_branches_tolerated(self) -> None:
1279
+ """Empty branches list round-trips cleanly.
1280
+
1281
+ Lenient producers (the Rust/Go/Java SDKs, tolerated by the DuckDB C++
1282
+ client) omit the IPC stream for an empty nested list, so a strict
1283
+ consumer must accept a zero-branch result rather than raising — otherwise
1284
+ the Cedar proxy (the only strict Python consumer in the path) fails
1285
+ closed on a legitimate response.
1286
+ """
1282
1287
  from vgi.catalog import ScanBranchesResult
1283
1288
 
1284
1289
  empty = ScanBranchesResult(branches=[], required_extensions=[])
1285
1290
  batch, _ = deserialize_record_batch(empty.serialize())
1286
- with pytest.raises(ValueError, match="branches list must not be empty"):
1287
- ScanBranchesResult.deserialize(batch)
1291
+ restored = ScanBranchesResult.deserialize(batch)
1292
+ assert restored.branches == []
1293
+ assert restored.required_extensions == []
1288
1294
 
1289
1295
 
1290
1296
  class TestSecretTypeSpecSerialization:
@@ -1149,3 +1149,61 @@ class TestAnyArrow:
1149
1149
  assert obj.data.value == {"key": "value"}
1150
1150
  assert obj.data.position == "data"
1151
1151
  assert obj.data.name == "data"
1152
+
1153
+
1154
+ class TestBindCallWireFormat:
1155
+ """The embedded ``bind_call`` must serialize as an opaque binary IPC blob.
1156
+
1157
+ Every non-Python VGI implementation (the DuckDB C++ client, the Rust/Go/Java
1158
+ SDKs) encodes ``bind_call`` as ``Bytes`` — an IPC-serialized ``BindRequest``
1159
+ (Rust: ``ipc::read_batch(&dto.bind_call.0)``). If Python serializes it as an
1160
+ inline Arrow *struct* instead, those workers reject the request with
1161
+ "expected Binary array". This regression-anchors the ``bind_call`` field
1162
+ being ``Annotated[BindRequest, ArrowType(pa.binary())]`` on every request
1163
+ that carries one, so the Cedar proxy's re-serialized bind stays wire-
1164
+ compatible with a non-Python backend.
1165
+ """
1166
+
1167
+ @staticmethod
1168
+ def _bind_call_arrow_type(obj: object) -> str:
1169
+ batch = pa.ipc.open_stream(obj.serialize_to_bytes()).read_next_batch() # type: ignore[attr-defined]
1170
+ return str(dict((f.name, f.type) for f in batch.schema)["bind_call"])
1171
+
1172
+ def _make_bind(self) -> object:
1173
+ """Build a minimal ``BindRequest`` to embed as ``bind_call``."""
1174
+ from vgi.protocol import BindRequest, FunctionType
1175
+
1176
+ return BindRequest(
1177
+ function_name="f",
1178
+ arguments=Arguments(positional=[], named=None),
1179
+ function_type=FunctionType.TABLE,
1180
+ )
1181
+
1182
+ def test_init_request_bind_call_is_binary(self) -> None:
1183
+ """``InitRequest.bind_call`` serializes as binary and round-trips."""
1184
+ from vgi.protocol import InitRequest
1185
+
1186
+ ir = InitRequest(bind_call=self._make_bind(), output_schema=pa.schema([pa.field("x", pa.int64())]))
1187
+ assert self._bind_call_arrow_type(ir) == "binary"
1188
+ # round-trips back into a BindRequest
1189
+ restored = InitRequest.deserialize_from_bytes(ir.serialize_to_bytes())
1190
+ assert restored.bind_call.function_name == "f"
1191
+
1192
+ def test_table_function_requests_bind_call_is_binary(self) -> None:
1193
+ """The ``table_function_*`` requests also serialize ``bind_call`` as binary."""
1194
+ from vgi.protocol import (
1195
+ TableFunctionCardinalityRequest,
1196
+ TableFunctionDynamicToStringRequest,
1197
+ TableFunctionStatisticsRequest,
1198
+ )
1199
+
1200
+ cases = [
1201
+ (TableFunctionCardinalityRequest, {}),
1202
+ (TableFunctionStatisticsRequest, {}),
1203
+ (TableFunctionDynamicToStringRequest, {"global_execution_id": b"exec"}),
1204
+ ]
1205
+ for cls, extra in cases:
1206
+ obj = cls(bind_call=self._make_bind(), **extra)
1207
+ assert self._bind_call_arrow_type(obj) == "binary", cls.__name__
1208
+ restored = cls.deserialize_from_bytes(obj.serialize_to_bytes())
1209
+ assert restored.bind_call.function_name == "f", cls.__name__
@@ -2061,27 +2061,27 @@ wheels = [
2061
2061
 
2062
2062
  [[package]]
2063
2063
  name = "ruff"
2064
- version = "0.15.20"
2065
- source = { registry = "https://pypi.org/simple" }
2066
- sdist = { url = "https://files.pythonhosted.org/packages/43/dc/35b341fc554ba02f217fc10da57d1a75168cfbcf75b0ef2202176d4c4f2d/ruff-0.15.20.tar.gz", hash = "sha256:1416eb04349192646b54de98f146c4f59afe37d0decfc02c3cbbf396f3a28566", size = 4755489, upload-time = "2026-06-25T17:20:37.578Z" }
2067
- wheels = [
2068
- { url = "https://files.pythonhosted.org/packages/94/d9/2d5014f0253ba541d2061d9fa7193f48e941c8b21bb88a7ff9bbe0bd0596/ruff-0.15.20-py3-none-linux_armv6l.whl", hash = "sha256:00e188c53e499c3c1637f73c91dcf2fb56d576cab76ce1be50a27c4e80e37078", size = 10839665, upload-time = "2026-06-25T17:19:44.702Z" },
2069
- { url = "https://files.pythonhosted.org/packages/c6/d3/ac1798ba64f670698867fcfc591d50e7e421bef137db564858f619a30fcf/ruff-0.15.20-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:9ebd1fd9b9c95fc0bd7b2761aebec1f030013d2e193a2901b224af68fe47251b", size = 11208649, upload-time = "2026-06-25T17:19:48.787Z" },
2070
- { url = "https://files.pythonhosted.org/packages/47/47/d3ac899991202095dfcf3d5176be4272642be3cf981a2f1a30f72a2afb95/ruff-0.15.20-py3-none-macosx_11_0_arm64.whl", hash = "sha256:c5b16cdd67ca108185cd36dce98c576350c03b1660a751de725fb049193a0632", size = 10622638, upload-time = "2026-06-25T17:19:51.354Z" },
2071
- { url = "https://files.pythonhosted.org/packages/33/13/4e043fe30aa94d4ff5213a9881fc296d12960f5971b234a5263fdc225312/ruff-0.15.20-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3413bb3c3d2ca6a8208f1f4809cd2dca3c6de6d0b491c0e70847672bde6e6efd", size = 10984227, upload-time = "2026-06-25T17:19:54.044Z" },
2072
- { url = "https://files.pythonhosted.org/packages/76/e6/92e7bf40388bc5800073b96564f56264f7e48bfd1a498f5ced6ae6d5a769/ruff-0.15.20-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:bd7ec42b3bb3da066488db093308a69c4ac5ee6d2af333a86ba6e2eb2e7dd44b", size = 10622882, upload-time = "2026-06-25T17:19:57.037Z" },
2073
- { url = "https://files.pythonhosted.org/packages/13/7a/43460be3f24495a3aa46d4b16873e2c4941b3b5f0b00cf88c03b7b94b339/ruff-0.15.20-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e1a36ad0eb77fba9aabfb69ede54de6f376d04ac18ebea022847046d340a8267", size = 11474808, upload-time = "2026-06-25T17:20:00.357Z" },
2074
- { url = "https://files.pythonhosted.org/packages/27/a0/f37077884873221c6b33b4ab49eb18f9f88e54a16a25a5bca59bef46dd66/ruff-0.15.20-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b6df3b1e4610432f0386dba04d853b5f08cbbc903410c6fcc02f620f05aff53c", size = 12293094, upload-time = "2026-06-25T17:20:03.446Z" },
2075
- { url = "https://files.pythonhosted.org/packages/a6/74/165545b60256a9704c21ac0ec4a0d07933b320812f9584836c9f4aca4292/ruff-0.15.20-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e89f198a1ea6ef0d727c1cf16088bc91a6cb0ab947dedc966715691647186eae", size = 11526176, upload-time = "2026-06-25T17:20:06.301Z" },
2076
- { url = "https://files.pythonhosted.org/packages/86/b1/a976a136d40ade83ce743578399865f57001003a409acadc0ecbb3051082/ruff-0.15.20-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:309809086c2acb67624950a3c8133e80f32d0d3e27106c0cd60ff26657c9f24b", size = 11520767, upload-time = "2026-06-25T17:20:09.191Z" },
2077
- { url = "https://files.pythonhosted.org/packages/19/0f/f032696cb01c9b54c0263fa393474d7758f1cdc021a01b04e3cbc2500999/ruff-0.15.20-py3-none-manylinux_2_31_riscv64.whl", hash = "sha256:2d2374caa2f2c2f9e2b7da0a50802cfb8b79f55a9b5e49379f564544fbf56487", size = 11500132, upload-time = "2026-06-25T17:20:13.602Z" },
2078
- { url = "https://files.pythonhosted.org/packages/4b/f4/51b1a14bc69e8c224b15dab9cce8e99b425e0455d462caa2b3c9be2b6a8e/ruff-0.15.20-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:a1ed17b65293e0c2f22fc387bc13198a5de94bf4429589b0ff6946b0feaf21a3", size = 10943828, upload-time = "2026-06-25T17:20:16.635Z" },
2079
- { url = "https://files.pythonhosted.org/packages/71/4b/fe267640783cd02bf6c5cc290b1df1051be2ec294c678b5c15fe19e52343/ruff-0.15.20-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:f701305e66b38ea6c91882490eb73459796808e4c6362a1b765255e0cdcd4053", size = 10645418, upload-time = "2026-06-25T17:20:19.4Z" },
2080
- { url = "https://files.pythonhosted.org/packages/b0/c0/a65aa4ec2f5e87a1df32dc3ec1fede434fe3dfd5cbcf3b503cafc676ab54/ruff-0.15.20-py3-none-musllinux_1_2_i686.whl", hash = "sha256:5b9c0c367ad8e5d0d5b5b8537864c469a0a0e55417aadfbeca41fa61333be9f4", size = 11211770, upload-time = "2026-06-25T17:20:22.033Z" },
2081
- { url = "https://files.pythonhosted.org/packages/5a/a4/0caa331d954ae2723d729d351c989cb4ca8b6077d5c6c2cb6de75e98c041/ruff-0.15.20-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:01cc00dd58f0df339d0e902219dd53990ea99996a0344e5d9cc8d45d5307e460", size = 11618698, upload-time = "2026-06-25T17:20:25.259Z" },
2082
- { url = "https://files.pythonhosted.org/packages/10/9b/5f14927848d2fd4aa891fd88d883788c5a7baba561c7874732364045708c/ruff-0.15.20-py3-none-win32.whl", hash = "sha256:ed65ef510e43a137207e0f01cfcf998aeddb1aeeda5c9d35023e910284d7cf21", size = 10857322, upload-time = "2026-06-25T17:20:28.612Z" },
2083
- { url = "https://files.pythonhosted.org/packages/fa/f0/fe47c501f9dea92a26d788ff98bb5d92ed4cb4c88792c5c88af6b697dc8e/ruff-0.15.20-py3-none-win_amd64.whl", hash = "sha256:a525c81c70fb0380344dd1d8745d8cc1c890b7fc94a58d5a07bd8eb9557b8415", size = 11993274, upload-time = "2026-06-25T17:20:31.871Z" },
2084
- { url = "https://files.pythonhosted.org/packages/d7/2b/9555445e1201d92b3195f45cdb153a0b68f24e0a4273f6e3d5ab46e212bb/ruff-0.15.20-py3-none-win_arm64.whl", hash = "sha256:2f5b2a6d614e8700388806a14996c40fab2c47b819ef57d790a34878858ed9ca", size = 11343498, upload-time = "2026-06-25T17:20:35.03Z" },
2064
+ version = "0.16.0"
2065
+ source = { registry = "https://pypi.org/simple" }
2066
+ sdist = { url = "https://files.pythonhosted.org/packages/4d/94/1e5e4967626faf12fa56999cd6222dff6992ceb086ad7945756baf70c7a7/ruff-0.16.0.tar.gz", hash = "sha256:e460aafd5495ec89efaa6ced2e4a9a581116451e1c88b9d37ef497e0f8e93982", size = 4790557, upload-time = "2026-07-23T19:11:30.981Z" }
2067
+ wheels = [
2068
+ { url = "https://files.pythonhosted.org/packages/4b/81/1c8818fee7ce1a04cd7d1b3172e0a8f8e4f1dc4feb7fc390e16daa8af323/ruff-0.16.0-py3-none-linux_armv6l.whl", hash = "sha256:e5115729eb08c585e5121978ba5d5b60caeae394ce21b9fb5e6cd33a1c6c9b1e", size = 10754633, upload-time = "2026-07-23T19:10:46.415Z" },
2069
+ { url = "https://files.pythonhosted.org/packages/23/df/beaf59c09d68db84304d555f188b276a77132a5d5b0b67a5c762aa143628/ruff-0.16.0-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:3c954b1d580bfa035b41654f7858cc7e71d5fc3ac5b723dd62bd9133830ed522", size = 10969164, upload-time = "2026-07-23T19:10:50.271Z" },
2070
+ { url = "https://files.pythonhosted.org/packages/42/ce/741cd197496a1abbf51352710fd15ed995d2a2be87189c1da26a450d6e83/ruff-0.16.0-py3-none-macosx_11_0_arm64.whl", hash = "sha256:e01c21d10eb1b29f47b7454e1f4056db9a3f0260c646aa88457c610291db9f81", size = 10488846, upload-time = "2026-07-23T19:10:52.639Z" },
2071
+ { url = "https://files.pythonhosted.org/packages/52/2a/a2db8e88cade358f5cdcb05674a917751074109315d014eb6352d9a893f7/ruff-0.16.0-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6e364e5ed22ed8dc05082fd78e35308618260907ac2d3c1d637b2e682415b6c9", size = 10889729, upload-time = "2026-07-23T19:10:54.89Z" },
2072
+ { url = "https://files.pythonhosted.org/packages/42/65/62a771694ebd63029dc953e27dbad40e1588bd4860ff9fe881018fddaa49/ruff-0.16.0-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:d327b8fc113a1d4421a04f3839d3752057c8dd1ee320223a6f3f52d04ada462a", size = 10568275, upload-time = "2026-07-23T19:10:56.993Z" },
2073
+ { url = "https://files.pythonhosted.org/packages/3f/e2/ced249fe8af5f086c5c58cc21cc3356d50f32f7401c5df87050c999620a7/ruff-0.16.0-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a9b50c55e263103586b3dcf5f73d479eb8cb5fdb6098fec59a62891dab653717", size = 11385112, upload-time = "2026-07-23T19:10:59.615Z" },
2074
+ { url = "https://files.pythonhosted.org/packages/87/0b/05154977a8fd69eeb6c103271f55403bfd8711f5c0f8ed07489d95a504e7/ruff-0.16.0-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:0ff4a79ce3ec0172f3241943835de1c4cb4e2dcd07f0f8c2d02603dbbbee4b17", size = 12207008, upload-time = "2026-07-23T19:11:02.154Z" },
2075
+ { url = "https://files.pythonhosted.org/packages/fb/29/98225831a3a1eab0e02f4acc6ca6559a98611dcc68b6965ff4b7234627c1/ruff-0.16.0-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e95c448fca1fb2a18372a9440926c5a6ee789639bb975c72e7ae6d0b04218ab4", size = 11650842, upload-time = "2026-07-23T19:11:04.557Z" },
2076
+ { url = "https://files.pythonhosted.org/packages/91/66/6bd3cf90500653d55dc0ffc8507aa8300bd49d0214b2e8cb4d3fef2943ba/ruff-0.16.0-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4f11a8d11010301d0a398a2fdef67691feca7294da6aef55e2150e8fa2cd520b", size = 11400718, upload-time = "2026-07-23T19:11:09.233Z" },
2077
+ { url = "https://files.pythonhosted.org/packages/8e/a2/a54eb4eae05d66364050a5d3b8a9c5ef88196531b3cbe7109d873f87f819/ruff-0.16.0-py3-none-manylinux_2_31_riscv64.whl", hash = "sha256:48044c678e9cb8698246c99b14aaccfa6601dea7379eb48a6f8f73f7a6d86cd0", size = 11426177, upload-time = "2026-07-23T19:11:11.994Z" },
2078
+ { url = "https://files.pythonhosted.org/packages/1a/be/16e3eea4b2a478a496919f5e36f17c4559e54620bd3bbac5d6affa068006/ruff-0.16.0-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:7aa0959bad8eb8bef50340154fc9b58678dae31fa4293afa38b44b6e552c0213", size = 10856126, upload-time = "2026-07-23T19:11:14.221Z" },
2079
+ { url = "https://files.pythonhosted.org/packages/a2/84/252eb8b868a16eec7257c14f504f77537e734b2d69c762e639e588e304a3/ruff-0.16.0-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:28ea2b7df8ebf7f9da6b7d47b230ab48f387c0a29be3b474c4d0740e197bb9af", size = 10571208, upload-time = "2026-07-23T19:11:16.378Z" },
2080
+ { url = "https://files.pythonhosted.org/packages/21/09/817a482f542f7570cbb4554b26e896610c7114f539b1d9e2d2145bf6bef6/ruff-0.16.0-py3-none-musllinux_1_2_i686.whl", hash = "sha256:33a3dfac8c35f81498dea9181bccc2f4c4bc8f1521a1dd9406e77643e0f0fb09", size = 11063329, upload-time = "2026-07-23T19:11:19.173Z" },
2081
+ { url = "https://files.pythonhosted.org/packages/2e/23/9403c180ca1cb9b1f7335f5c3e5305c09d49ea5b345196682a36028bde4a/ruff-0.16.0-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:a5237a0bda500d30d81b8e07a6973a5cbc772864cbf746ae2f4e8a2e01c9f4ed", size = 11489751, upload-time = "2026-07-23T19:11:21.74Z" },
2082
+ { url = "https://files.pythonhosted.org/packages/b2/1d/1b2ef7bcde851c78d7f17f1cca13fd6dc695fc4b3d6197941e72cae5b132/ruff-0.16.0-py3-none-win32.whl", hash = "sha256:7fab76fa065c873f41ff744347c6e77bcc3dfec4bcc754dc26b63d23c0f7f5fb", size = 10785885, upload-time = "2026-07-23T19:11:23.947Z" },
2083
+ { url = "https://files.pythonhosted.org/packages/b2/a3/d5e4ef7a56be3f928ffb90b94c25ba7d3cb9c7fe0736aeaaedf361770712/ruff-0.16.0-py3-none-win_amd64.whl", hash = "sha256:429c117f022bf481fabd9d551e7a3952b24c65e6ef44337ea09d90bebef14472", size = 11923141, upload-time = "2026-07-23T19:11:26.409Z" },
2084
+ { url = "https://files.pythonhosted.org/packages/cb/9a/8415f2657cbe200f41a4531ccededf135505a92d4a012229121f885b26f9/ruff-0.16.0-py3-none-win_arm64.whl", hash = "sha256:14296fedcd2705c77ab8235439278bbb38f285cf7da5528b00b3e330c3d4872d", size = 11273407, upload-time = "2026-07-23T19:11:28.705Z" },
2085
2085
  ]
2086
2086
 
2087
2087
  [[package]]
@@ -2228,7 +2228,7 @@ requires-dist = [
2228
2228
 
2229
2229
  [[package]]
2230
2230
  name = "vgi-python"
2231
- version = "0.19.0"
2231
+ version = "0.22.0"
2232
2232
  source = { editable = "." }
2233
2233
  dependencies = [
2234
2234
  { name = "click" },
@@ -2338,7 +2338,7 @@ requires-dist = [
2338
2338
  { name = "vgi-python", extras = ["test-fixtures"], marker = "extra == 'test-fixtures-writable'" },
2339
2339
  { name = "vgi-python", extras = ["test-fixtures", "test-fixtures-writable", "http", "oauth", "otel", "sentry", "azure"], marker = "extra == 'dev'" },
2340
2340
  { name = "vgi-python", extras = ["transactor"], marker = "extra == 'test-fixtures-writable'" },
2341
- { name = "vgi-rpc", specifier = ">=0.26.0" },
2341
+ { name = "vgi-rpc", specifier = ">=0.28.2" },
2342
2342
  { name = "vgi-rpc", extras = ["conformance", "external", "http", "oauth", "otel", "sentry"], marker = "extra == 'dev'" },
2343
2343
  { name = "vgi-rpc", extras = ["http"], marker = "extra == 'http'" },
2344
2344
  { name = "vgi-rpc", extras = ["oauth"], marker = "extra == 'oauth'" },
@@ -2367,7 +2367,7 @@ docs = [
2367
2367
 
2368
2368
  [[package]]
2369
2369
  name = "vgi-rpc"
2370
- version = "0.26.0"
2370
+ version = "0.28.2"
2371
2371
  source = { registry = "https://pypi.org/simple" }
2372
2372
  dependencies = [
2373
2373
  { name = "docstring-parser" },
@@ -2375,9 +2375,9 @@ dependencies = [
2375
2375
  { name = "pywin32", marker = "sys_platform == 'win32'" },
2376
2376
  { name = "tzdata", marker = "sys_platform == 'win32'" },
2377
2377
  ]
2378
- sdist = { url = "https://files.pythonhosted.org/packages/b5/51/86d4c4466cf5311e80db28f535c02b92961f3d5160a0aae348112a03f7d5/vgi_rpc-0.26.0.tar.gz", hash = "sha256:c0966c99e087f923b228b2211877a8695bf42052d9cde05ce9a4bf077047cb78", size = 869625, upload-time = "2026-07-21T17:39:12.871Z" }
2378
+ sdist = { url = "https://files.pythonhosted.org/packages/89/a0/00252e2d6986094c13bf35b7f7e1e95b0a3b0497c210b2c88cc72b82b3c7/vgi_rpc-0.28.2.tar.gz", hash = "sha256:4fcfcd5c42a0242aee9d1f40e16fab6559f6401feccf44fe50ad91ee473dc5f4", size = 905341, upload-time = "2026-07-27T13:56:23.482Z" }
2379
2379
  wheels = [
2380
- { url = "https://files.pythonhosted.org/packages/57/51/d86efc32aef03d69d197916f9d18d0f3719ebd843424cfb9a782ced041c9/vgi_rpc-0.26.0-py3-none-any.whl", hash = "sha256:2c455edb517831867342ce2f105386b73b1fa23137477916c5e5d7a14b66e0fc", size = 386786, upload-time = "2026-07-21T17:39:11.142Z" },
2380
+ { url = "https://files.pythonhosted.org/packages/3c/1d/0a34b627d4f6d3bf83e61a5897fb32e5bf1543708380ee1a6eaeeb56a8d7/vgi_rpc-0.28.2-py3-none-any.whl", hash = "sha256:dc96d11b2ced0fa36e653ed475c653f4124748b2372da1866028da4975eb9b8f", size = 404897, upload-time = "2026-07-27T13:56:21.549Z" },
2381
2381
  ]
2382
2382
 
2383
2383
  [package.optional-dependencies]
@@ -330,13 +330,23 @@ def main() -> None:
330
330
 
331
331
  authenticate = _optional_bearer
332
332
 
333
- from vgi.worker import _get_vgi_version
334
-
335
333
  # Match vgi-fixture-worker (subprocess transport): always serve the
336
334
  # base ExampleWorker plus the projection_repro, schema_reconcile,
337
335
  # and accumulate fixture catalogs. Add the writable catalog when its
338
- # extra is installed.
339
- worker_classes: list[type] = [ExampleWorker, ProjReproWorker, SchemaReconcileWorker, AccumulateWorker]
336
+ # extra is installed. The twin_a/twin_b catalogs (same worker, one
337
+ # function name colliding across two catalogs) back
338
+ # scalar/same_name_catalogs.test — catalog-qualified dispatch.
339
+ from vgi._test_fixtures.twin_catalogs import TwinAWorker, TwinBWorker
340
+ from vgi.worker import _get_vgi_version
341
+
342
+ worker_classes: list[type] = [
343
+ ExampleWorker,
344
+ ProjReproWorker,
345
+ SchemaReconcileWorker,
346
+ AccumulateWorker,
347
+ TwinAWorker,
348
+ TwinBWorker,
349
+ ]
340
350
  try:
341
351
  from vgi._test_fixtures.writable.worker import WritableWorker
342
352
  except ImportError:
@@ -1188,9 +1188,10 @@ class ScanBranchesResult:
1188
1188
  )
1189
1189
 
1190
1190
  branch_blobs = cast("list[bytes]", row["branches"])
1191
- if not branch_blobs:
1192
- raise ValueError(f"{cls.__name__}: branches list must not be empty")
1193
-
1191
+ # An empty branch list is valid: a multi-branch scan can prune to zero
1192
+ # branches (see catalog/multi_branch_empty_branches) it scans nothing.
1193
+ # Lenient producers (the Rust/Go/Java SDKs, tolerated by the DuckDB C++
1194
+ # client) send it; don't reject.
1194
1195
  branches: list[ScanBranch] = []
1195
1196
  for blob in branch_blobs:
1196
1197
  branch_batch, _ = deserialize_record_batch(blob)
@@ -288,7 +288,7 @@ class InitRequest(ArrowSerializableDataclass):
288
288
  """
289
289
 
290
290
  # Core (always present)
291
- bind_call: BindRequest
291
+ bind_call: Annotated[BindRequest, ArrowType(pa.binary())]
292
292
  output_schema: Annotated[pa.Schema, ArrowType(pa.binary())]
293
293
  bind_opaque_data: Annotated[bytes | None, ArrowType(pa.binary())] = None
294
294
 
@@ -348,7 +348,7 @@ class TableFunctionCardinalityRequest(ArrowSerializableDataclass):
348
348
  ``InitRequest.bind_opaque_data``).
349
349
  """
350
350
 
351
- bind_call: BindRequest
351
+ bind_call: Annotated[BindRequest, ArrowType(pa.binary())]
352
352
  bind_opaque_data: Annotated[bytes | None, ArrowType(pa.binary())] = None
353
353
 
354
354
 
@@ -368,7 +368,7 @@ class TableFunctionStatisticsRequest(ArrowSerializableDataclass):
368
368
  ``InitRequest.bind_opaque_data``).
369
369
  """
370
370
 
371
- bind_call: BindRequest
371
+ bind_call: Annotated[BindRequest, ArrowType(pa.binary())]
372
372
  bind_opaque_data: Annotated[bytes | None, ArrowType(pa.binary())] = None
373
373
 
374
374
 
@@ -392,7 +392,7 @@ class TableFunctionDynamicToStringRequest(ArrowSerializableDataclass):
392
392
  persisted the diagnostics this RPC retrieves.
393
393
  """
394
394
 
395
- bind_call: BindRequest
395
+ bind_call: Annotated[BindRequest, ArrowType(pa.binary())]
396
396
  bind_opaque_data: Annotated[bytes | None, ArrowType(pa.binary())] = None
397
397
  global_execution_id: bytes
398
398
 
@@ -32,7 +32,7 @@ import os
32
32
  import sys
33
33
  from collections.abc import Callable
34
34
  from types import ModuleType
35
- from typing import TYPE_CHECKING, Any
35
+ from typing import TYPE_CHECKING, Any, Literal
36
36
 
37
37
  from vgi.logging_config import LogFormat, LogLevel
38
38
 
@@ -429,6 +429,10 @@ def _resolve_authenticate() -> Callable[..., Any] | None:
429
429
  - ``VGI_JWT_ISSUER`` + ``VGI_JWT_AUDIENCE``: JWT/JWKS auth
430
430
  (requires ``vgi[oauth]`` extra). Optional ``VGI_JWT_JWKS_URI``.
431
431
  - When both bearer and JWT are set, they are chained (JWT first).
432
+ - ``VGI_PROXY_PROOF_MODE``: ``allow`` or ``require`` gates every request
433
+ on proof that it arrived through a trusted proxy. This is a
434
+ precondition ANDed with whichever credential above is configured, not
435
+ an alternative to one.
432
436
 
433
437
  Returns:
434
438
  An authenticate callback, or None if no auth env vars are set.
@@ -438,14 +442,84 @@ def _resolve_authenticate() -> Callable[..., Any] | None:
438
442
  JWT issuer without audience).
439
443
 
440
444
  """
441
- bearer_auth = _resolve_bearer_authenticate()
442
- jwt_auth = _resolve_jwt_authenticate()
445
+ # Ordered by cost: JWT resolves a signature, bearer does a constant-time
446
+ # scan over the token set, so the cheaper one goes last.
447
+ candidates = [fn for fn in (_resolve_jwt_authenticate(), _resolve_bearer_authenticate()) if fn is not None]
443
448
 
444
- if bearer_auth is not None and jwt_auth is not None:
449
+ inner: Callable[..., Any] | None
450
+ if len(candidates) > 1:
445
451
  from vgi_rpc.http import chain_authenticate
446
452
 
447
- return chain_authenticate(jwt_auth, bearer_auth)
448
- return jwt_auth or bearer_auth
453
+ inner = chain_authenticate(*candidates)
454
+ else:
455
+ inner = candidates[0] if candidates else None
456
+
457
+ gate = _resolve_proxy_proof_gate()
458
+ if gate is None:
459
+ return inner
460
+
461
+ # AND, not OR: chaining the gate would let any later credential satisfy
462
+ # the request on its own, which is exactly the bypass the gate exists to
463
+ # close. `inner` may be None — proof alone means "only my proxy may call
464
+ # this worker", with user identity handled upstream.
465
+ from vgi_rpc.http import require_all
466
+
467
+ return require_all(gate, inner)
468
+
469
+
470
+ def _resolve_proxy_proof_gate() -> Any | None:
471
+ """Build a proxy-proof gate from ``VGI_PROXY_PROOF_*`` environment variables.
472
+
473
+ Env vars:
474
+
475
+ - ``VGI_PROXY_PROOF_MODE``: ``off`` (default), ``allow`` or ``require``.
476
+ - ``VGI_PROXY_PROOF_ORIGIN_ID``: this worker's identifier. Folded into
477
+ every MAC but never transmitted, so it must match what the proxy is
478
+ configured to prove to.
479
+ - ``VGI_PROXY_PROOF_SECRETS``: ``kid:hex`` pairs, comma-separated. The
480
+ ``kid`` doubles as the proxy's label in the audit trail.
481
+ - ``VGI_PROXY_PROOF_SKEW``: acceptance half-window in seconds (default 30).
482
+
483
+ Returns:
484
+ A gate for ``require_all``, or None when the feature is off.
485
+
486
+ Raises:
487
+ SystemExit: On any malformed value. Deliberately fail-closed: the
488
+ secret is shared with an independently-deployed proxy, so a typo
489
+ would otherwise silently reject every request with no diagnostic.
490
+
491
+ """
492
+ raw_mode = (os.environ.get("VGI_PROXY_PROOF_MODE") or "off").strip().lower()
493
+ if raw_mode == "off":
494
+ return None
495
+ if raw_mode not in ("allow", "require"):
496
+ sys.stderr.write(
497
+ f"Error: VGI_PROXY_PROOF_MODE must be 'off', 'allow' or 'require', got {raw_mode!r}\n",
498
+ )
499
+ sys.exit(1)
500
+ mode: Literal["allow", "require"] = "allow" if raw_mode == "allow" else "require"
501
+
502
+ from vgi_rpc.http import ProxyProofConfig, parse_secrets, proxy_proof_gate
503
+
504
+ raw_secrets = os.environ.get("VGI_PROXY_PROOF_SECRETS") or ""
505
+ skew_raw = os.environ.get("VGI_PROXY_PROOF_SKEW") or "30"
506
+ try:
507
+ secrets = parse_secrets(raw_secrets)
508
+ config = ProxyProofConfig(
509
+ mode=mode,
510
+ origin_id=os.environ.get("VGI_PROXY_PROOF_ORIGIN_ID") or "",
511
+ secrets=secrets,
512
+ skew_seconds=int(skew_raw),
513
+ )
514
+ except ValueError as exc:
515
+ sys.stderr.write(
516
+ f"Error: invalid proxy-proof configuration: {exc}\n"
517
+ "Set VGI_PROXY_PROOF_MODE=off to disable, or fix "
518
+ "VGI_PROXY_PROOF_ORIGIN_ID / VGI_PROXY_PROOF_SECRETS "
519
+ "(kid:hex pairs, 64 hex chars each; generate with 'openssl rand -hex 32').\n",
520
+ )
521
+ sys.exit(1)
522
+ return proxy_proof_gate(config)
449
523
 
450
524
 
451
525
  def _resolve_bearer_authenticate() -> Callable[..., Any] | None:
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes