vgi-python 0.29.0__tar.gz → 0.29.3__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 (440) hide show
  1. {vgi_python-0.29.0 → vgi_python-0.29.3}/PKG-INFO +10 -6
  2. {vgi_python-0.29.0 → vgi_python-0.29.3}/README.md +9 -5
  3. vgi_python-0.29.3/docs/vgi-logo.png +0 -0
  4. {vgi_python-0.29.0 → vgi_python-0.29.3}/pyproject.toml +1 -1
  5. vgi_python-0.29.3/tests/client/test_batch_metadata_callback.py +77 -0
  6. vgi_python-0.29.3/tests/client/test_scan_branches_client.py +67 -0
  7. vgi_python-0.29.3/tests/client/test_split_client.py +93 -0
  8. vgi_python-0.29.3/tests/client/test_time_travel_client.py +85 -0
  9. {vgi_python-0.29.0 → vgi_python-0.29.3}/uv.lock +10 -5
  10. {vgi_python-0.29.0 → vgi_python-0.29.3}/vgi/_test_fixtures/table_in_out.py +96 -1
  11. {vgi_python-0.29.0 → vgi_python-0.29.3}/vgi/_test_fixtures/worker.py +2 -0
  12. {vgi_python-0.29.0 → vgi_python-0.29.3}/vgi/client/catalog_mixin.py +86 -0
  13. {vgi_python-0.29.0 → vgi_python-0.29.3}/vgi/client/client.py +230 -9
  14. {vgi_python-0.29.0 → vgi_python-0.29.3}/vgi/codegen/cpp_request_builders.py +98 -12
  15. {vgi_python-0.29.0 → vgi_python-0.29.3}/vgi/worker.py +11 -0
  16. vgi_python-0.29.0/docs/vgi-logo.png +0 -0
  17. {vgi_python-0.29.0 → vgi_python-0.29.3}/.gitattributes +0 -0
  18. {vgi_python-0.29.0 → vgi_python-0.29.3}/.github/dependabot.yml +0 -0
  19. {vgi_python-0.29.0 → vgi_python-0.29.3}/.github/styles/config/vocabularies/VGI/accept.txt +0 -0
  20. {vgi_python-0.29.0 → vgi_python-0.29.3}/.github/workflows/ci.yml +0 -0
  21. {vgi_python-0.29.0 → vgi_python-0.29.3}/.github/workflows/docs.yml +0 -0
  22. {vgi_python-0.29.0 → vgi_python-0.29.3}/.github/workflows/integration.yml +0 -0
  23. {vgi_python-0.29.0 → vgi_python-0.29.3}/.github/workflows/release.yml +0 -0
  24. {vgi_python-0.29.0 → vgi_python-0.29.3}/.gitignore +0 -0
  25. {vgi_python-0.29.0 → vgi_python-0.29.3}/.python-version +0 -0
  26. {vgi_python-0.29.0 → vgi_python-0.29.3}/.vale.ini +0 -0
  27. {vgi_python-0.29.0 → vgi_python-0.29.3}/CLAUDE.md +0 -0
  28. {vgi_python-0.29.0 → vgi_python-0.29.3}/DOCS_ACCEPTANCE_CRITERIA.md +0 -0
  29. {vgi_python-0.29.0 → vgi_python-0.29.3}/DOCS_REVIEW_RUBRIC.md +0 -0
  30. {vgi_python-0.29.0 → vgi_python-0.29.3}/DOCS_USABILITY_TEST.md +0 -0
  31. {vgi_python-0.29.0 → vgi_python-0.29.3}/LICENSE +0 -0
  32. {vgi_python-0.29.0 → vgi_python-0.29.3}/RELEASE-RUNBOOK.md +0 -0
  33. {vgi_python-0.29.0 → vgi_python-0.29.3}/SECURITY.md +0 -0
  34. {vgi_python-0.29.0 → vgi_python-0.29.3}/ci/README.md +0 -0
  35. {vgi_python-0.29.0 → vgi_python-0.29.3}/ci/preprocess-require.awk +0 -0
  36. {vgi_python-0.29.0 → vgi_python-0.29.3}/ci/run-integration.sh +0 -0
  37. {vgi_python-0.29.0 → vgi_python-0.29.3}/dist-vgi/.gitignore +0 -0
  38. {vgi_python-0.29.0 → vgi_python-0.29.3}/docs/aggregate-functions.md +0 -0
  39. {vgi_python-0.29.0 → vgi_python-0.29.3}/docs/api/arguments.md +0 -0
  40. {vgi_python-0.29.0 → vgi_python-0.29.3}/docs/api/auth.md +0 -0
  41. {vgi_python-0.29.0 → vgi_python-0.29.3}/docs/api/catalogs.md +0 -0
  42. {vgi_python-0.29.0 → vgi_python-0.29.3}/docs/api/client.md +0 -0
  43. {vgi_python-0.29.0 → vgi_python-0.29.3}/docs/api/exceptions.md +0 -0
  44. {vgi_python-0.29.0 → vgi_python-0.29.3}/docs/api/filters.md +0 -0
  45. {vgi_python-0.29.0 → vgi_python-0.29.3}/docs/api/functions.md +0 -0
  46. {vgi_python-0.29.0 → vgi_python-0.29.3}/docs/api/http.md +0 -0
  47. {vgi_python-0.29.0 → vgi_python-0.29.3}/docs/api/index.md +0 -0
  48. {vgi_python-0.29.0 → vgi_python-0.29.3}/docs/api/metadata.md +0 -0
  49. {vgi_python-0.29.0 → vgi_python-0.29.3}/docs/api/observability.md +0 -0
  50. {vgi_python-0.29.0 → vgi_python-0.29.3}/docs/api/storage.md +0 -0
  51. {vgi_python-0.29.0 → vgi_python-0.29.3}/docs/api/transactor.md +0 -0
  52. {vgi_python-0.29.0 → vgi_python-0.29.3}/docs/api/worker.md +0 -0
  53. {vgi_python-0.29.0 → vgi_python-0.29.3}/docs/argument-serialization.md +0 -0
  54. {vgi_python-0.29.0 → vgi_python-0.29.3}/docs/assets/apple-touch-icon.png +0 -0
  55. {vgi_python-0.29.0 → vgi_python-0.29.3}/docs/assets/favicon-16x16.png +0 -0
  56. {vgi_python-0.29.0 → vgi_python-0.29.3}/docs/assets/favicon-32x32.png +0 -0
  57. {vgi_python-0.29.0 → vgi_python-0.29.3}/docs/assets/favicon.ico +0 -0
  58. {vgi_python-0.29.0 → vgi_python-0.29.3}/docs/assets/kinds/aggregate.svg +0 -0
  59. {vgi_python-0.29.0 → vgi_python-0.29.3}/docs/assets/kinds/buffering.svg +0 -0
  60. {vgi_python-0.29.0 → vgi_python-0.29.3}/docs/assets/kinds/scalar.svg +0 -0
  61. {vgi_python-0.29.0 → vgi_python-0.29.3}/docs/assets/kinds/table-in-out.svg +0 -0
  62. {vgi_python-0.29.0 → vgi_python-0.29.3}/docs/assets/kinds/table.svg +0 -0
  63. {vgi_python-0.29.0 → vgi_python-0.29.3}/docs/assets/logo.png +0 -0
  64. {vgi_python-0.29.0 → vgi_python-0.29.3}/docs/assets/social-card.png +0 -0
  65. {vgi_python-0.29.0 → vgi_python-0.29.3}/docs/authentication.md +0 -0
  66. {vgi_python-0.29.0 → vgi_python-0.29.3}/docs/catalog-interface.md +0 -0
  67. {vgi_python-0.29.0 → vgi_python-0.29.3}/docs/cli.md +0 -0
  68. {vgi_python-0.29.0 → vgi_python-0.29.3}/docs/column-statistics.md +0 -0
  69. {vgi_python-0.29.0 → vgi_python-0.29.3}/docs/concepts/index.md +0 -0
  70. {vgi_python-0.29.0 → vgi_python-0.29.3}/docs/contributing-docs.md +0 -0
  71. {vgi_python-0.29.0 → vgi_python-0.29.3}/docs/filter-pushdown.md +0 -0
  72. {vgi_python-0.29.0 → vgi_python-0.29.3}/docs/generator-api.md +0 -0
  73. {vgi_python-0.29.0 → vgi_python-0.29.3}/docs/global-functions.md +0 -0
  74. {vgi_python-0.29.0 → vgi_python-0.29.3}/docs/how-to/catalogs.md +0 -0
  75. {vgi_python-0.29.0 → vgi_python-0.29.3}/docs/how-to/function-patterns.md +0 -0
  76. {vgi_python-0.29.0 → vgi_python-0.29.3}/docs/how-to/http-auth.md +0 -0
  77. {vgi_python-0.29.0 → vgi_python-0.29.3}/docs/how-to/index.md +0 -0
  78. {vgi_python-0.29.0 → vgi_python-0.29.3}/docs/how-to/pushdown-and-statistics.md +0 -0
  79. {vgi_python-0.29.0 → vgi_python-0.29.3}/docs/how-to/state-storage.md +0 -0
  80. {vgi_python-0.29.0 → vgi_python-0.29.3}/docs/index.md +0 -0
  81. {vgi_python-0.29.0 → vgi_python-0.29.3}/docs/lifecycle.md +0 -0
  82. {vgi_python-0.29.0 → vgi_python-0.29.3}/docs/metadata.md +0 -0
  83. {vgi_python-0.29.0 → vgi_python-0.29.3}/docs/overrides/main.html +0 -0
  84. {vgi_python-0.29.0 → vgi_python-0.29.3}/docs/robots.txt +0 -0
  85. {vgi_python-0.29.0 → vgi_python-0.29.3}/docs/shared-storage.md +0 -0
  86. {vgi_python-0.29.0 → vgi_python-0.29.3}/docs/stylesheets/extra.css +0 -0
  87. {vgi_python-0.29.0 → vgi_python-0.29.3}/docs/tutorial/index.md +0 -0
  88. {vgi_python-0.29.0 → vgi_python-0.29.3}/docs/tutorial/scalar.md +0 -0
  89. {vgi_python-0.29.0 → vgi_python-0.29.3}/docs/tutorial/table.md +0 -0
  90. {vgi_python-0.29.0 → vgi_python-0.29.3}/examples/batch_index_worker.py +0 -0
  91. {vgi_python-0.29.0 → vgi_python-0.29.3}/examples/cache_worker.py +0 -0
  92. {vgi_python-0.29.0 → vgi_python-0.29.3}/examples/calc_scalar_worker.py +0 -0
  93. {vgi_python-0.29.0 → vgi_python-0.29.3}/examples/calc_worker.py +0 -0
  94. {vgi_python-0.29.0 → vgi_python-0.29.3}/examples/copy_format_worker.py +0 -0
  95. {vgi_python-0.29.0 → vgi_python-0.29.3}/examples/filter_worker.py +0 -0
  96. {vgi_python-0.29.0 → vgi_python-0.29.3}/examples/greeting_scalar_worker.py +0 -0
  97. {vgi_python-0.29.0 → vgi_python-0.29.3}/examples/row_count_worker.py +0 -0
  98. {vgi_python-0.29.0 → vgi_python-0.29.3}/examples/series_streaming_worker.py +0 -0
  99. {vgi_python-0.29.0 → vgi_python-0.29.3}/examples/sum_worker.py +0 -0
  100. {vgi_python-0.29.0 → vgi_python-0.29.3}/mkdocs.yml +0 -0
  101. {vgi_python-0.29.0 → vgi_python-0.29.3}/packages/vgi-fixtures/LICENSE +0 -0
  102. {vgi_python-0.29.0 → vgi_python-0.29.3}/packages/vgi-fixtures/README.md +0 -0
  103. {vgi_python-0.29.0 → vgi_python-0.29.3}/packages/vgi-fixtures/docker/Dockerfile +0 -0
  104. {vgi_python-0.29.0 → vgi_python-0.29.3}/packages/vgi-fixtures/docker/docker-entrypoint.sh +0 -0
  105. {vgi_python-0.29.0 → vgi_python-0.29.3}/packages/vgi-fixtures/pyproject.toml +0 -0
  106. {vgi_python-0.29.0 → vgi_python-0.29.3}/scripts/measure_startup.py +0 -0
  107. {vgi_python-0.29.0 → vgi_python-0.29.3}/scripts/run_all_tests.sh +0 -0
  108. {vgi_python-0.29.0 → vgi_python-0.29.3}/test-data/generate.sh +0 -0
  109. {vgi_python-0.29.0 → vgi_python-0.29.3}/tests/__init__.py +0 -0
  110. {vgi_python-0.29.0 → vgi_python-0.29.3}/tests/_http_fixtures.py +0 -0
  111. {vgi_python-0.29.0 → vgi_python-0.29.3}/tests/catalog/__init__.py +0 -0
  112. {vgi_python-0.29.0 → vgi_python-0.29.3}/tests/catalog/test_attach_option.py +0 -0
  113. {vgi_python-0.29.0 → vgi_python-0.29.3}/tests/catalog/test_catalog_interface.py +0 -0
  114. {vgi_python-0.29.0 → vgi_python-0.29.3}/tests/catalog/test_client_catalog.py +0 -0
  115. {vgi_python-0.29.0 → vgi_python-0.29.3}/tests/catalog/test_column_statistics.py +0 -0
  116. {vgi_python-0.29.0 → vgi_python-0.29.3}/tests/catalog/test_declarative.py +0 -0
  117. {vgi_python-0.29.0 → vgi_python-0.29.3}/tests/catalog/test_example_worker_catalog.py +0 -0
  118. {vgi_python-0.29.0 → vgi_python-0.29.3}/tests/catalog/test_integration.py +0 -0
  119. {vgi_python-0.29.0 → vgi_python-0.29.3}/tests/catalog/test_required_filters.py +0 -0
  120. {vgi_python-0.29.0 → vgi_python-0.29.3}/tests/catalog/test_scan_branches.py +0 -0
  121. {vgi_python-0.29.0 → vgi_python-0.29.3}/tests/catalog/test_serialization.py +0 -0
  122. {vgi_python-0.29.0 → vgi_python-0.29.3}/tests/catalog/test_setting.py +0 -0
  123. {vgi_python-0.29.0 → vgi_python-0.29.3}/tests/catalog/test_storage.py +0 -0
  124. {vgi_python-0.29.0 → vgi_python-0.29.3}/tests/catalog/test_time_travel.py +0 -0
  125. {vgi_python-0.29.0 → vgi_python-0.29.3}/tests/catalog/test_writable_table.py +0 -0
  126. {vgi_python-0.29.0 → vgi_python-0.29.3}/tests/client/__init__.py +0 -0
  127. {vgi_python-0.29.0 → vgi_python-0.29.3}/tests/client/test_aggregate_client.py +0 -0
  128. {vgi_python-0.29.0 → vgi_python-0.29.3}/tests/client/test_broken_pipe.py +0 -0
  129. {vgi_python-0.29.0 → vgi_python-0.29.3}/tests/client/test_cli.py +0 -0
  130. {vgi_python-0.29.0 → vgi_python-0.29.3}/tests/client/test_cli_catalog_functions.py +0 -0
  131. {vgi_python-0.29.0 → vgi_python-0.29.3}/tests/client/test_copy_client.py +0 -0
  132. {vgi_python-0.29.0 → vgi_python-0.29.3}/tests/client/test_stop_force.py +0 -0
  133. {vgi_python-0.29.0 → vgi_python-0.29.3}/tests/client/test_table_column_statistics.py +0 -0
  134. {vgi_python-0.29.0 → vgi_python-0.29.3}/tests/client/test_worker_debug.py +0 -0
  135. {vgi_python-0.29.0 → vgi_python-0.29.3}/tests/conformance/__init__.py +0 -0
  136. {vgi_python-0.29.0 → vgi_python-0.29.3}/tests/conformance/_stub.py +0 -0
  137. {vgi_python-0.29.0 → vgi_python-0.29.3}/tests/conformance/conftest.py +0 -0
  138. {vgi_python-0.29.0 → vgi_python-0.29.3}/tests/conformance/test_accumulate.py +0 -0
  139. {vgi_python-0.29.0 → vgi_python-0.29.3}/tests/conformance/test_aggregate.py +0 -0
  140. {vgi_python-0.29.0 → vgi_python-0.29.3}/tests/conformance/test_attach.py +0 -0
  141. {vgi_python-0.29.0 → vgi_python-0.29.3}/tests/conformance/test_bearer_auth.py +0 -0
  142. {vgi_python-0.29.0 → vgi_python-0.29.3}/tests/conformance/test_const_param_enforcement.py +0 -0
  143. {vgi_python-0.29.0 → vgi_python-0.29.3}/tests/conformance/test_container.py +0 -0
  144. {vgi_python-0.29.0 → vgi_python-0.29.3}/tests/conformance/test_copy_from.py +0 -0
  145. {vgi_python-0.29.0 → vgi_python-0.29.3}/tests/conformance/test_copy_to.py +0 -0
  146. {vgi_python-0.29.0 → vgi_python-0.29.3}/tests/conformance/test_directory_parity.py +0 -0
  147. {vgi_python-0.29.0 → vgi_python-0.29.3}/tests/conformance/test_function_inventory.py +0 -0
  148. {vgi_python-0.29.0 → vgi_python-0.29.3}/tests/conformance/test_github.py +0 -0
  149. {vgi_python-0.29.0 → vgi_python-0.29.3}/tests/conformance/test_http_client.py +0 -0
  150. {vgi_python-0.29.0 → vgi_python-0.29.3}/tests/conformance/test_http_external_location.py +0 -0
  151. {vgi_python-0.29.0 → vgi_python-0.29.3}/tests/conformance/test_http_upload_url.py +0 -0
  152. {vgi_python-0.29.0 → vgi_python-0.29.3}/tests/conformance/test_macro.py +0 -0
  153. {vgi_python-0.29.0 → vgi_python-0.29.3}/tests/conformance/test_overload.py +0 -0
  154. {vgi_python-0.29.0 → vgi_python-0.29.3}/tests/conformance/test_protocol_inventory.py +0 -0
  155. {vgi_python-0.29.0 → vgi_python-0.29.3}/tests/conformance/test_protocol_version.py +0 -0
  156. {vgi_python-0.29.0 → vgi_python-0.29.3}/tests/conformance/test_resumable_scan.py +0 -0
  157. {vgi_python-0.29.0 → vgi_python-0.29.3}/tests/conformance/test_scalar.py +0 -0
  158. {vgi_python-0.29.0 → vgi_python-0.29.3}/tests/conformance/test_scalar_attach_opaque_data.py +0 -0
  159. {vgi_python-0.29.0 → vgi_python-0.29.3}/tests/conformance/test_secret.py +0 -0
  160. {vgi_python-0.29.0 → vgi_python-0.29.3}/tests/conformance/test_settings.py +0 -0
  161. {vgi_python-0.29.0 → vgi_python-0.29.3}/tests/conformance/test_splits.py +0 -0
  162. {vgi_python-0.29.0 → vgi_python-0.29.3}/tests/conformance/test_table.py +0 -0
  163. {vgi_python-0.29.0 → vgi_python-0.29.3}/tests/conformance/test_table_in_out.py +0 -0
  164. {vgi_python-0.29.0 → vgi_python-0.29.3}/tests/conformance/test_view.py +0 -0
  165. {vgi_python-0.29.0 → vgi_python-0.29.3}/tests/conformance/test_writable.py +0 -0
  166. {vgi_python-0.29.0 → vgi_python-0.29.3}/tests/conftest.py +0 -0
  167. {vgi_python-0.29.0 → vgi_python-0.29.3}/tests/data/split_tokens/anchor_len_overrun.bin +0 -0
  168. {vgi_python-0.29.0 → vgi_python-0.29.3}/tests/data/split_tokens/bad_fingerprint.bin +0 -0
  169. {vgi_python-0.29.0 → vgi_python-0.29.3}/tests/data/split_tokens/bad_flags_unsealed_but_key_present.bin +0 -0
  170. {vgi_python-0.29.0 → vgi_python-0.29.3}/tests/data/split_tokens/bad_version.bin +0 -0
  171. {vgi_python-0.29.0 → vgi_python-0.29.3}/tests/data/split_tokens/generate.py +0 -0
  172. {vgi_python-0.29.0 → vgi_python-0.29.3}/tests/data/split_tokens/manifest.json +0 -0
  173. {vgi_python-0.29.0 → vgi_python-0.29.3}/tests/data/split_tokens/reserved_flag_bit.bin +0 -0
  174. {vgi_python-0.29.0 → vgi_python-0.29.3}/tests/data/split_tokens/stale_anchor.bin +0 -0
  175. {vgi_python-0.29.0 → vgi_python-0.29.3}/tests/data/split_tokens/truncated.bin +0 -0
  176. {vgi_python-0.29.0 → vgi_python-0.29.3}/tests/data/split_tokens/valid_sealed.bin +0 -0
  177. {vgi_python-0.29.0 → vgi_python-0.29.3}/tests/data/split_tokens/valid_unsealed.bin +0 -0
  178. {vgi_python-0.29.0 → vgi_python-0.29.3}/tests/scalar/__init__.py +0 -0
  179. {vgi_python-0.29.0 → vgi_python-0.29.3}/tests/scalar/test_bernoulli_function.py +0 -0
  180. {vgi_python-0.29.0 → vgi_python-0.29.3}/tests/scalar/test_binary_packet_function.py +0 -0
  181. {vgi_python-0.29.0 → vgi_python-0.29.3}/tests/scalar/test_client.py +0 -0
  182. {vgi_python-0.29.0 → vgi_python-0.29.3}/tests/scalar/test_conditional_message_function.py +0 -0
  183. {vgi_python-0.29.0 → vgi_python-0.29.3}/tests/scalar/test_hash_seed_function.py +0 -0
  184. {vgi_python-0.29.0 → vgi_python-0.29.3}/tests/scalar/test_multiply_by_setting_function.py +0 -0
  185. {vgi_python-0.29.0 → vgi_python-0.29.3}/tests/scalar/test_multiply_function.py +0 -0
  186. {vgi_python-0.29.0 → vgi_python-0.29.3}/tests/scalar/test_random_bytes_function.py +0 -0
  187. {vgi_python-0.29.0 → vgi_python-0.29.3}/tests/scalar/test_return_secret_value_function.py +0 -0
  188. {vgi_python-0.29.0 → vgi_python-0.29.3}/tests/table/__init__.py +0 -0
  189. {vgi_python-0.29.0 → vgi_python-0.29.3}/tests/table/generator/__init__.py +0 -0
  190. {vgi_python-0.29.0 → vgi_python-0.29.3}/tests/table/generator/test_constant_columns_function.py +0 -0
  191. {vgi_python-0.29.0 → vgi_python-0.29.3}/tests/table/generator/test_double_sequence_function.py +0 -0
  192. {vgi_python-0.29.0 → vgi_python-0.29.3}/tests/table/generator/test_exception_function.py +0 -0
  193. {vgi_python-0.29.0 → vgi_python-0.29.3}/tests/table/generator/test_filter_echo_function.py +0 -0
  194. {vgi_python-0.29.0 → vgi_python-0.29.3}/tests/table/generator/test_logging_function.py +0 -0
  195. {vgi_python-0.29.0 → vgi_python-0.29.3}/tests/table/generator/test_nested_sequence_function.py +0 -0
  196. {vgi_python-0.29.0 → vgi_python-0.29.3}/tests/table/generator/test_partitioned_function.py +0 -0
  197. {vgi_python-0.29.0 → vgi_python-0.29.3}/tests/table/generator/test_projected_data_function.py +0 -0
  198. {vgi_python-0.29.0 → vgi_python-0.29.3}/tests/table/generator/test_sequence_function.py +0 -0
  199. {vgi_python-0.29.0 → vgi_python-0.29.3}/tests/table/generator/test_settings_function.py +0 -0
  200. {vgi_python-0.29.0 → vgi_python-0.29.3}/tests/table/generator/test_struct_settings_function.py +0 -0
  201. {vgi_python-0.29.0 → vgi_python-0.29.3}/tests/table/generator/test_ten_thousand_function.py +0 -0
  202. {vgi_python-0.29.0 → vgi_python-0.29.3}/tests/table/test_wide_columns.py +0 -0
  203. {vgi_python-0.29.0 → vgi_python-0.29.3}/tests/table_in_out/__init__.py +0 -0
  204. {vgi_python-0.29.0 → vgi_python-0.29.3}/tests/table_in_out/generator/__init__.py +0 -0
  205. {vgi_python-0.29.0 → vgi_python-0.29.3}/tests/table_in_out/generator/test_buffer_input_function.py +0 -0
  206. {vgi_python-0.29.0 → vgi_python-0.29.3}/tests/table_in_out/generator/test_echo_function.py +0 -0
  207. {vgi_python-0.29.0 → vgi_python-0.29.3}/tests/table_in_out/generator/test_exception_functions.py +0 -0
  208. {vgi_python-0.29.0 → vgi_python-0.29.3}/tests/table_in_out/generator/test_filter_by_setting_function.py +0 -0
  209. {vgi_python-0.29.0 → vgi_python-0.29.3}/tests/table_in_out/generator/test_repeat_inputs_function.py +0 -0
  210. {vgi_python-0.29.0 → vgi_python-0.29.3}/tests/table_in_out/generator/test_substream_partial_sum_function.py +0 -0
  211. {vgi_python-0.29.0 → vgi_python-0.29.3}/tests/table_in_out/generator/test_sum_all_columns_function.py +0 -0
  212. {vgi_python-0.29.0 → vgi_python-0.29.3}/tests/table_in_out/test_blended_metadata.py +0 -0
  213. {vgi_python-0.29.0 → vgi_python-0.29.3}/tests/table_in_out/test_client.py +0 -0
  214. {vgi_python-0.29.0 → vgi_python-0.29.3}/tests/test_access_log_audit.py +0 -0
  215. {vgi_python-0.29.0 → vgi_python-0.29.3}/tests/test_aggregate_function.py +0 -0
  216. {vgi_python-0.29.0 → vgi_python-0.29.3}/tests/test_argument_spec.py +0 -0
  217. {vgi_python-0.29.0 → vgi_python-0.29.3}/tests/test_auth.py +0 -0
  218. {vgi_python-0.29.0 → vgi_python-0.29.3}/tests/test_bind_exceptions.py +0 -0
  219. {vgi_python-0.29.0 → vgi_python-0.29.3}/tests/test_bind_request_at_clause.py +0 -0
  220. {vgi_python-0.29.0 → vgi_python-0.29.3}/tests/test_bound_storage_conformance.py +0 -0
  221. {vgi_python-0.29.0 → vgi_python-0.29.3}/tests/test_cache_control.py +0 -0
  222. {vgi_python-0.29.0 → vgi_python-0.29.3}/tests/test_call_state_attach.py +0 -0
  223. {vgi_python-0.29.0 → vgi_python-0.29.3}/tests/test_catalog_auth_binding.py +0 -0
  224. {vgi_python-0.29.0 → vgi_python-0.29.3}/tests/test_copy_from_function.py +0 -0
  225. {vgi_python-0.29.0 → vgi_python-0.29.3}/tests/test_copy_to_function.py +0 -0
  226. {vgi_python-0.29.0 → vgi_python-0.29.3}/tests/test_docstrings.py +0 -0
  227. {vgi_python-0.29.0 → vgi_python-0.29.3}/tests/test_documentation_examples.py +0 -0
  228. {vgi_python-0.29.0 → vgi_python-0.29.3}/tests/test_example_function_arg_types.py +0 -0
  229. {vgi_python-0.29.0 → vgi_python-0.29.3}/tests/test_examples_workers.py +0 -0
  230. {vgi_python-0.29.0 → vgi_python-0.29.3}/tests/test_exception_handling.py +0 -0
  231. {vgi_python-0.29.0 → vgi_python-0.29.3}/tests/test_exceptions.py +0 -0
  232. {vgi_python-0.29.0 → vgi_python-0.29.3}/tests/test_filter_pushdown.py +0 -0
  233. {vgi_python-0.29.0 → vgi_python-0.29.3}/tests/test_filter_pushdown_extension.py +0 -0
  234. {vgi_python-0.29.0 → vgi_python-0.29.3}/tests/test_fixture_catalog_parity.py +0 -0
  235. {vgi_python-0.29.0 → vgi_python-0.29.3}/tests/test_function_storage.py +0 -0
  236. {vgi_python-0.29.0 → vgi_python-0.29.3}/tests/test_function_storage_azure_sql.py +0 -0
  237. {vgi_python-0.29.0 → vgi_python-0.29.3}/tests/test_function_storage_cf_do.py +0 -0
  238. {vgi_python-0.29.0 → vgi_python-0.29.3}/tests/test_function_storage_cf_do_integration.py +0 -0
  239. {vgi_python-0.29.0 → vgi_python-0.29.3}/tests/test_function_storage_conformance.py +0 -0
  240. {vgi_python-0.29.0 → vgi_python-0.29.3}/tests/test_generated_cpp_constants.py +0 -0
  241. {vgi_python-0.29.0 → vgi_python-0.29.3}/tests/test_generated_cpp_protocol_version.py +0 -0
  242. {vgi_python-0.29.0 → vgi_python-0.29.3}/tests/test_generated_cpp_request_builders.py +0 -0
  243. {vgi_python-0.29.0 → vgi_python-0.29.3}/tests/test_generated_cpp_schemas.py +0 -0
  244. {vgi_python-0.29.0 → vgi_python-0.29.3}/tests/test_generated_cpp_secret.py +0 -0
  245. {vgi_python-0.29.0 → vgi_python-0.29.3}/tests/test_generated_go_schemas.py +0 -0
  246. {vgi_python-0.29.0 → vgi_python-0.29.3}/tests/test_generated_java_schemas.py +0 -0
  247. {vgi_python-0.29.0 → vgi_python-0.29.3}/tests/test_generated_protocol_version.py +0 -0
  248. {vgi_python-0.29.0 → vgi_python-0.29.3}/tests/test_generated_rust_request_builders.py +0 -0
  249. {vgi_python-0.29.0 → vgi_python-0.29.3}/tests/test_generated_rust_schemas.py +0 -0
  250. {vgi_python-0.29.0 → vgi_python-0.29.3}/tests/test_generated_schemas_cross_lang.py +0 -0
  251. {vgi_python-0.29.0 → vgi_python-0.29.3}/tests/test_generated_ts_client.py +0 -0
  252. {vgi_python-0.29.0 → vgi_python-0.29.3}/tests/test_generated_ts_schemas.py +0 -0
  253. {vgi_python-0.29.0 → vgi_python-0.29.3}/tests/test_http_demo_storage.py +0 -0
  254. {vgi_python-0.29.0 → vgi_python-0.29.3}/tests/test_http_s3_offload_input.py +0 -0
  255. {vgi_python-0.29.0 → vgi_python-0.29.3}/tests/test_http_s3_offload_output.py +0 -0
  256. {vgi_python-0.29.0 → vgi_python-0.29.3}/tests/test_metadata.py +0 -0
  257. {vgi_python-0.29.0 → vgi_python-0.29.3}/tests/test_mypy_consolidated.py +0 -0
  258. {vgi_python-0.29.0 → vgi_python-0.29.3}/tests/test_nest_tensor.py +0 -0
  259. {vgi_python-0.29.0 → vgi_python-0.29.3}/tests/test_otel.py +0 -0
  260. {vgi_python-0.29.0 → vgi_python-0.29.3}/tests/test_projection_enforcement.py +0 -0
  261. {vgi_python-0.29.0 → vgi_python-0.29.3}/tests/test_projection_repro.py +0 -0
  262. {vgi_python-0.29.0 → vgi_python-0.29.3}/tests/test_protocol_classes.py +0 -0
  263. {vgi_python-0.29.0 → vgi_python-0.29.3}/tests/test_resolved_secrets.py +0 -0
  264. {vgi_python-0.29.0 → vgi_python-0.29.3}/tests/test_schema_scoped_functions.py +0 -0
  265. {vgi_python-0.29.0 → vgi_python-0.29.3}/tests/test_schema_utils.py +0 -0
  266. {vgi_python-0.29.0 → vgi_python-0.29.3}/tests/test_serve.py +0 -0
  267. {vgi_python-0.29.0 → vgi_python-0.29.3}/tests/test_setting_secret_annotations.py +0 -0
  268. {vgi_python-0.29.0 → vgi_python-0.29.3}/tests/test_signing_key.py +0 -0
  269. {vgi_python-0.29.0 → vgi_python-0.29.3}/tests/test_split_token.py +0 -0
  270. {vgi_python-0.29.0 → vgi_python-0.29.3}/tests/test_table_buffering_function.py +0 -0
  271. {vgi_python-0.29.0 → vgi_python-0.29.3}/tests/test_table_function_dynamic_to_string.py +0 -0
  272. {vgi_python-0.29.0 → vgi_python-0.29.3}/tests/test_tcp_transport.py +0 -0
  273. {vgi_python-0.29.0 → vgi_python-0.29.3}/tests/test_type_bounds.py +0 -0
  274. {vgi_python-0.29.0 → vgi_python-0.29.3}/tests/test_union_argument.py +0 -0
  275. {vgi_python-0.29.0 → vgi_python-0.29.3}/tests/test_wire_record_schema_parity.py +0 -0
  276. {vgi_python-0.29.0 → vgi_python-0.29.3}/tests/test_worker.py +0 -0
  277. {vgi_python-0.29.0 → vgi_python-0.29.3}/tests/test_worker_cli.py +0 -0
  278. {vgi_python-0.29.0 → vgi_python-0.29.3}/tests/test_worker_page.py +0 -0
  279. {vgi_python-0.29.0 → vgi_python-0.29.3}/tests/transactor/__init__.py +0 -0
  280. {vgi_python-0.29.0 → vgi_python-0.29.3}/tests/transactor/test_transactor.py +0 -0
  281. {vgi_python-0.29.0 → vgi_python-0.29.3}/vgi/__init__.py +0 -0
  282. {vgi_python-0.29.0 → vgi_python-0.29.3}/vgi/_duckdb.py +0 -0
  283. {vgi_python-0.29.0 → vgi_python-0.29.3}/vgi/_storage_profile.py +0 -0
  284. {vgi_python-0.29.0 → vgi_python-0.29.3}/vgi/_test_fixtures/__init__.py +0 -0
  285. {vgi_python-0.29.0 → vgi_python-0.29.3}/vgi/_test_fixtures/accumulate/__init__.py +0 -0
  286. {vgi_python-0.29.0 → vgi_python-0.29.3}/vgi/_test_fixtures/accumulate/worker.py +0 -0
  287. {vgi_python-0.29.0 → vgi_python-0.29.3}/vgi/_test_fixtures/aggregate/__init__.py +0 -0
  288. {vgi_python-0.29.0 → vgi_python-0.29.3}/vgi/_test_fixtures/aggregate/_common.py +0 -0
  289. {vgi_python-0.29.0 → vgi_python-0.29.3}/vgi/_test_fixtures/aggregate/basic.py +0 -0
  290. {vgi_python-0.29.0 → vgi_python-0.29.3}/vgi/_test_fixtures/aggregate/dynamic.py +0 -0
  291. {vgi_python-0.29.0 → vgi_python-0.29.3}/vgi/_test_fixtures/aggregate/generic.py +0 -0
  292. {vgi_python-0.29.0 → vgi_python-0.29.3}/vgi/_test_fixtures/aggregate/listagg.py +0 -0
  293. {vgi_python-0.29.0 → vgi_python-0.29.3}/vgi/_test_fixtures/aggregate/percentile.py +0 -0
  294. {vgi_python-0.29.0 → vgi_python-0.29.3}/vgi/_test_fixtures/aggregate/same_name.py +0 -0
  295. {vgi_python-0.29.0 → vgi_python-0.29.3}/vgi/_test_fixtures/aggregate/secret_typed.py +0 -0
  296. {vgi_python-0.29.0 → vgi_python-0.29.3}/vgi/_test_fixtures/aggregate/streaming.py +0 -0
  297. {vgi_python-0.29.0 → vgi_python-0.29.3}/vgi/_test_fixtures/aggregate/varargs.py +0 -0
  298. {vgi_python-0.29.0 → vgi_python-0.29.3}/vgi/_test_fixtures/aggregate/window.py +0 -0
  299. {vgi_python-0.29.0 → vgi_python-0.29.3}/vgi/_test_fixtures/attach_options.py +0 -0
  300. {vgi_python-0.29.0 → vgi_python-0.29.3}/vgi/_test_fixtures/bad_enum.py +0 -0
  301. {vgi_python-0.29.0 → vgi_python-0.29.3}/vgi/_test_fixtures/bad_protocol.py +0 -0
  302. {vgi_python-0.29.0 → vgi_python-0.29.3}/vgi/_test_fixtures/cancellable.py +0 -0
  303. {vgi_python-0.29.0 → vgi_python-0.29.3}/vgi/_test_fixtures/catalog.py +0 -0
  304. {vgi_python-0.29.0 → vgi_python-0.29.3}/vgi/_test_fixtures/companion.py +0 -0
  305. {vgi_python-0.29.0 → vgi_python-0.29.3}/vgi/_test_fixtures/copy_from.py +0 -0
  306. {vgi_python-0.29.0 → vgi_python-0.29.3}/vgi/_test_fixtures/copy_to.py +0 -0
  307. {vgi_python-0.29.0 → vgi_python-0.29.3}/vgi/_test_fixtures/global_functions.py +0 -0
  308. {vgi_python-0.29.0 → vgi_python-0.29.3}/vgi/_test_fixtures/http_server.py +0 -0
  309. {vgi_python-0.29.0 → vgi_python-0.29.3}/vgi/_test_fixtures/narrow_bind/__init__.py +0 -0
  310. {vgi_python-0.29.0 → vgi_python-0.29.3}/vgi/_test_fixtures/narrow_bind/worker.py +0 -0
  311. {vgi_python-0.29.0 → vgi_python-0.29.3}/vgi/_test_fixtures/nest_tensor.py +0 -0
  312. {vgi_python-0.29.0 → vgi_python-0.29.3}/vgi/_test_fixtures/orchard_catalog.py +0 -0
  313. {vgi_python-0.29.0 → vgi_python-0.29.3}/vgi/_test_fixtures/projection_repro/__init__.py +0 -0
  314. {vgi_python-0.29.0 → vgi_python-0.29.3}/vgi/_test_fixtures/projection_repro/worker.py +0 -0
  315. {vgi_python-0.29.0 → vgi_python-0.29.3}/vgi/_test_fixtures/scalar/__init__.py +0 -0
  316. {vgi_python-0.29.0 → vgi_python-0.29.3}/vgi/_test_fixtures/scalar/_common.py +0 -0
  317. {vgi_python-0.29.0 → vgi_python-0.29.3}/vgi/_test_fixtures/scalar/arithmetic.py +0 -0
  318. {vgi_python-0.29.0 → vgi_python-0.29.3}/vgi/_test_fixtures/scalar/bench_ladder.py +0 -0
  319. {vgi_python-0.29.0 → vgi_python-0.29.3}/vgi/_test_fixtures/scalar/binary.py +0 -0
  320. {vgi_python-0.29.0 → vgi_python-0.29.3}/vgi/_test_fixtures/scalar/formatting.py +0 -0
  321. {vgi_python-0.29.0 → vgi_python-0.29.3}/vgi/_test_fixtures/scalar/geo.py +0 -0
  322. {vgi_python-0.29.0 → vgi_python-0.29.3}/vgi/_test_fixtures/scalar/null_handling.py +0 -0
  323. {vgi_python-0.29.0 → vgi_python-0.29.3}/vgi/_test_fixtures/scalar/random_demo.py +0 -0
  324. {vgi_python-0.29.0 → vgi_python-0.29.3}/vgi/_test_fixtures/scalar/same_name.py +0 -0
  325. {vgi_python-0.29.0 → vgi_python-0.29.3}/vgi/_test_fixtures/scalar/settings_secrets.py +0 -0
  326. {vgi_python-0.29.0 → vgi_python-0.29.3}/vgi/_test_fixtures/scalar/type_info.py +0 -0
  327. {vgi_python-0.29.0 → vgi_python-0.29.3}/vgi/_test_fixtures/schema_reconcile/__init__.py +0 -0
  328. {vgi_python-0.29.0 → vgi_python-0.29.3}/vgi/_test_fixtures/schema_reconcile/worker.py +0 -0
  329. {vgi_python-0.29.0 → vgi_python-0.29.3}/vgi/_test_fixtures/simple_writable.py +0 -0
  330. {vgi_python-0.29.0 → vgi_python-0.29.3}/vgi/_test_fixtures/table/__init__.py +0 -0
  331. {vgi_python-0.29.0 → vgi_python-0.29.3}/vgi/_test_fixtures/table/_common.py +0 -0
  332. {vgi_python-0.29.0 → vgi_python-0.29.3}/vgi/_test_fixtures/table/batch_index.py +0 -0
  333. {vgi_python-0.29.0 → vgi_python-0.29.3}/vgi/_test_fixtures/table/batch_index_broken.py +0 -0
  334. {vgi_python-0.29.0 → vgi_python-0.29.3}/vgi/_test_fixtures/table/cache.py +0 -0
  335. {vgi_python-0.29.0 → vgi_python-0.29.3}/vgi/_test_fixtures/table/catalog_scans.py +0 -0
  336. {vgi_python-0.29.0 → vgi_python-0.29.3}/vgi/_test_fixtures/table/filters.py +0 -0
  337. {vgi_python-0.29.0 → vgi_python-0.29.3}/vgi/_test_fixtures/table/late_materialization.py +0 -0
  338. {vgi_python-0.29.0 → vgi_python-0.29.3}/vgi/_test_fixtures/table/make_series.py +0 -0
  339. {vgi_python-0.29.0 → vgi_python-0.29.3}/vgi/_test_fixtures/table/misc.py +0 -0
  340. {vgi_python-0.29.0 → vgi_python-0.29.3}/vgi/_test_fixtures/table/order_modes.py +0 -0
  341. {vgi_python-0.29.0 → vgi_python-0.29.3}/vgi/_test_fixtures/table/pairs.py +0 -0
  342. {vgi_python-0.29.0 → vgi_python-0.29.3}/vgi/_test_fixtures/table/partition_columns.py +0 -0
  343. {vgi_python-0.29.0 → vgi_python-0.29.3}/vgi/_test_fixtures/table/partition_columns_broken.py +0 -0
  344. {vgi_python-0.29.0 → vgi_python-0.29.3}/vgi/_test_fixtures/table/profiling_example.py +0 -0
  345. {vgi_python-0.29.0 → vgi_python-0.29.3}/vgi/_test_fixtures/table/required_filters.py +0 -0
  346. {vgi_python-0.29.0 → vgi_python-0.29.3}/vgi/_test_fixtures/table/same_name_cached.py +0 -0
  347. {vgi_python-0.29.0 → vgi_python-0.29.3}/vgi/_test_fixtures/table/sequence.py +0 -0
  348. {vgi_python-0.29.0 → vgi_python-0.29.3}/vgi/_test_fixtures/table/settings.py +0 -0
  349. {vgi_python-0.29.0 → vgi_python-0.29.3}/vgi/_test_fixtures/table/splits.py +0 -0
  350. {vgi_python-0.29.0 → vgi_python-0.29.3}/vgi/_test_fixtures/table/transaction_storage.py +0 -0
  351. {vgi_python-0.29.0 → vgi_python-0.29.3}/vgi/_test_fixtures/table/tt_pushdown.py +0 -0
  352. {vgi_python-0.29.0 → vgi_python-0.29.3}/vgi/_test_fixtures/table/typed_probe.py +0 -0
  353. {vgi_python-0.29.0 → vgi_python-0.29.3}/vgi/_test_fixtures/table/versioned.py +0 -0
  354. {vgi_python-0.29.0 → vgi_python-0.29.3}/vgi/_test_fixtures/table/wide.py +0 -0
  355. {vgi_python-0.29.0 → vgi_python-0.29.3}/vgi/_test_fixtures/table_in_out_same_name.py +0 -0
  356. {vgi_python-0.29.0 → vgi_python-0.29.3}/vgi/_test_fixtures/twin_catalogs.py +0 -0
  357. {vgi_python-0.29.0 → vgi_python-0.29.3}/vgi/_test_fixtures/versioned.py +0 -0
  358. {vgi_python-0.29.0 → vgi_python-0.29.3}/vgi/_test_fixtures/versioned_tables.py +0 -0
  359. {vgi_python-0.29.0 → vgi_python-0.29.3}/vgi/_test_fixtures/writable/__init__.py +0 -0
  360. {vgi_python-0.29.0 → vgi_python-0.29.3}/vgi/_test_fixtures/writable/generic.py +0 -0
  361. {vgi_python-0.29.0 → vgi_python-0.29.3}/vgi/_test_fixtures/writable/table.py +0 -0
  362. {vgi_python-0.29.0 → vgi_python-0.29.3}/vgi/_test_fixtures/writable/worker.py +0 -0
  363. {vgi_python-0.29.0 → vgi_python-0.29.3}/vgi/aggregate_function.py +0 -0
  364. {vgi_python-0.29.0 → vgi_python-0.29.3}/vgi/argument_spec.py +0 -0
  365. {vgi_python-0.29.0 → vgi_python-0.29.3}/vgi/arguments.py +0 -0
  366. {vgi_python-0.29.0 → vgi_python-0.29.3}/vgi/attach_header.py +0 -0
  367. {vgi_python-0.29.0 → vgi_python-0.29.3}/vgi/auth.py +0 -0
  368. {vgi_python-0.29.0 → vgi_python-0.29.3}/vgi/cache_control.py +0 -0
  369. {vgi_python-0.29.0 → vgi_python-0.29.3}/vgi/catalog/__init__.py +0 -0
  370. {vgi_python-0.29.0 → vgi_python-0.29.3}/vgi/catalog/_descriptor_spec.py +0 -0
  371. {vgi_python-0.29.0 → vgi_python-0.29.3}/vgi/catalog/attach_option.py +0 -0
  372. {vgi_python-0.29.0 → vgi_python-0.29.3}/vgi/catalog/catalog_interface.py +0 -0
  373. {vgi_python-0.29.0 → vgi_python-0.29.3}/vgi/catalog/descriptors.py +0 -0
  374. {vgi_python-0.29.0 → vgi_python-0.29.3}/vgi/catalog/duckdb_statistics.py +0 -0
  375. {vgi_python-0.29.0 → vgi_python-0.29.3}/vgi/catalog/secret_type.py +0 -0
  376. {vgi_python-0.29.0 → vgi_python-0.29.3}/vgi/catalog/setting.py +0 -0
  377. {vgi_python-0.29.0 → vgi_python-0.29.3}/vgi/catalog/storage.py +0 -0
  378. {vgi_python-0.29.0 → vgi_python-0.29.3}/vgi/client/__init__.py +0 -0
  379. {vgi_python-0.29.0 → vgi_python-0.29.3}/vgi/client/aggregate.py +0 -0
  380. {vgi_python-0.29.0 → vgi_python-0.29.3}/vgi/client/cli.py +0 -0
  381. {vgi_python-0.29.0 → vgi_python-0.29.3}/vgi/client/cli_catalog.py +0 -0
  382. {vgi_python-0.29.0 → vgi_python-0.29.3}/vgi/client/cli_schema.py +0 -0
  383. {vgi_python-0.29.0 → vgi_python-0.29.3}/vgi/client/cli_table.py +0 -0
  384. {vgi_python-0.29.0 → vgi_python-0.29.3}/vgi/client/cli_transaction.py +0 -0
  385. {vgi_python-0.29.0 → vgi_python-0.29.3}/vgi/client/cli_utils.py +0 -0
  386. {vgi_python-0.29.0 → vgi_python-0.29.3}/vgi/client/cli_view.py +0 -0
  387. {vgi_python-0.29.0 → vgi_python-0.29.3}/vgi/client/errors.py +0 -0
  388. {vgi_python-0.29.0 → vgi_python-0.29.3}/vgi/codegen/__init__.py +0 -0
  389. {vgi_python-0.29.0 → vgi_python-0.29.3}/vgi/codegen/_common.py +0 -0
  390. {vgi_python-0.29.0 → vgi_python-0.29.3}/vgi/codegen/cpp_constants.py +0 -0
  391. {vgi_python-0.29.0 → vgi_python-0.29.3}/vgi/codegen/cpp_protocol_version.py +0 -0
  392. {vgi_python-0.29.0 → vgi_python-0.29.3}/vgi/codegen/cpp_schemas.py +0 -0
  393. {vgi_python-0.29.0 → vgi_python-0.29.3}/vgi/codegen/cpp_secret_protocol_version.py +0 -0
  394. {vgi_python-0.29.0 → vgi_python-0.29.3}/vgi/codegen/cpp_secret_request_builders.py +0 -0
  395. {vgi_python-0.29.0 → vgi_python-0.29.3}/vgi/codegen/cpp_secret_schemas.py +0 -0
  396. {vgi_python-0.29.0 → vgi_python-0.29.3}/vgi/codegen/go_schemas.py +0 -0
  397. {vgi_python-0.29.0 → vgi_python-0.29.3}/vgi/codegen/java_schemas.py +0 -0
  398. {vgi_python-0.29.0 → vgi_python-0.29.3}/vgi/codegen/protocol_version.py +0 -0
  399. {vgi_python-0.29.0 → vgi_python-0.29.3}/vgi/codegen/rust_request_builders.py +0 -0
  400. {vgi_python-0.29.0 → vgi_python-0.29.3}/vgi/codegen/rust_schemas.py +0 -0
  401. {vgi_python-0.29.0 → vgi_python-0.29.3}/vgi/codegen/ts_client.py +0 -0
  402. {vgi_python-0.29.0 → vgi_python-0.29.3}/vgi/codegen/ts_schemas.py +0 -0
  403. {vgi_python-0.29.0 → vgi_python-0.29.3}/vgi/copy_from_function.py +0 -0
  404. {vgi_python-0.29.0 → vgi_python-0.29.3}/vgi/copy_to_function.py +0 -0
  405. {vgi_python-0.29.0 → vgi_python-0.29.3}/vgi/exceptions.py +0 -0
  406. {vgi_python-0.29.0 → vgi_python-0.29.3}/vgi/function.py +0 -0
  407. {vgi_python-0.29.0 → vgi_python-0.29.3}/vgi/function_storage.py +0 -0
  408. {vgi_python-0.29.0 → vgi_python-0.29.3}/vgi/function_storage_azure_sql.py +0 -0
  409. {vgi_python-0.29.0 → vgi_python-0.29.3}/vgi/function_storage_cf_do.py +0 -0
  410. {vgi_python-0.29.0 → vgi_python-0.29.3}/vgi/http/__init__.py +0 -0
  411. {vgi_python-0.29.0 → vgi_python-0.29.3}/vgi/http/demo_storage.py +0 -0
  412. {vgi_python-0.29.0 → vgi_python-0.29.3}/vgi/http/landing.html +0 -0
  413. {vgi_python-0.29.0 → vgi_python-0.29.3}/vgi/http/landing_page.py +0 -0
  414. {vgi_python-0.29.0 → vgi_python-0.29.3}/vgi/http/vgi-client.js +0 -0
  415. {vgi_python-0.29.0 → vgi_python-0.29.3}/vgi/http/worker_page.py +0 -0
  416. {vgi_python-0.29.0 → vgi_python-0.29.3}/vgi/invocation.py +0 -0
  417. {vgi_python-0.29.0 → vgi_python-0.29.3}/vgi/logging_config.py +0 -0
  418. {vgi_python-0.29.0 → vgi_python-0.29.3}/vgi/meta_worker.py +0 -0
  419. {vgi_python-0.29.0 → vgi_python-0.29.3}/vgi/metadata.py +0 -0
  420. {vgi_python-0.29.0 → vgi_python-0.29.3}/vgi/otel.py +0 -0
  421. {vgi_python-0.29.0 → vgi_python-0.29.3}/vgi/profiling.py +0 -0
  422. {vgi_python-0.29.0 → vgi_python-0.29.3}/vgi/protocol.py +0 -0
  423. {vgi_python-0.29.0 → vgi_python-0.29.3}/vgi/protocol_version.txt +0 -0
  424. {vgi_python-0.29.0 → vgi_python-0.29.3}/vgi/py.typed +0 -0
  425. {vgi_python-0.29.0 → vgi_python-0.29.3}/vgi/scalar_function.py +0 -0
  426. {vgi_python-0.29.0 → vgi_python-0.29.3}/vgi/schema_utils.py +0 -0
  427. {vgi_python-0.29.0 → vgi_python-0.29.3}/vgi/secret_protocol.py +0 -0
  428. {vgi_python-0.29.0 → vgi_python-0.29.3}/vgi/secret_service.py +0 -0
  429. {vgi_python-0.29.0 → vgi_python-0.29.3}/vgi/serve.py +0 -0
  430. {vgi_python-0.29.0 → vgi_python-0.29.3}/vgi/split_token.py +0 -0
  431. {vgi_python-0.29.0 → vgi_python-0.29.3}/vgi/table_buffering_function.py +0 -0
  432. {vgi_python-0.29.0 → vgi_python-0.29.3}/vgi/table_filter_pushdown.py +0 -0
  433. {vgi_python-0.29.0 → vgi_python-0.29.3}/vgi/table_function.py +0 -0
  434. {vgi_python-0.29.0 → vgi_python-0.29.3}/vgi/table_in_out_function.py +0 -0
  435. {vgi_python-0.29.0 → vgi_python-0.29.3}/vgi/transactor/__init__.py +0 -0
  436. {vgi_python-0.29.0 → vgi_python-0.29.3}/vgi/transactor/_duckdb_compat.py +0 -0
  437. {vgi_python-0.29.0 → vgi_python-0.29.3}/vgi/transactor/client.py +0 -0
  438. {vgi_python-0.29.0 → vgi_python-0.29.3}/vgi/transactor/protocol.py +0 -0
  439. {vgi_python-0.29.0 → vgi_python-0.29.3}/vgi/transactor/server.py +0 -0
  440. {vgi_python-0.29.0 → vgi_python-0.29.3}/wrangler.jsonc +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: vgi-python
3
- Version: 0.29.0
3
+ Version: 0.29.3
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
@@ -212,18 +212,22 @@ Provides-Extra: transactor
212
212
  Requires-Dist: sqlglot; extra == 'transactor'
213
213
  Description-Content-Type: text/markdown
214
214
 
215
- # VGI (Vector Gateway Interface)
216
-
217
215
  <p align="center">
218
- <img src="https://raw.githubusercontent.com/Query-farm/vgi-python/main/docs/vgi-logo.png" alt="VGI Logo" width="480">
216
+ <img src="https://raw.githubusercontent.com/Query-farm/vgi-python/main/docs/vgi-logo.png?v=2" alt="Vector Gateway Interface logo" width="320">
219
217
  </p>
220
218
 
219
+ <h1 align="center">VGI</h1>
220
+
221
221
  <p align="center">
222
- <strong>Apache Arrow-based protocol for extending DuckDB using any language.</strong>
222
+ Apache Arrow-based protocol for extending DuckDB using any language — the Python reference implementation.<br>
223
+ Built by <a href="https://query.farm">🚜 Query.Farm</a>
223
224
  </p>
224
225
 
225
226
  <p align="center">
226
- Created by <a href="https://query.farm">Query.Farm</a>
227
+ <a href="https://github.com/Query-farm/vgi-python/actions/workflows/ci.yml"><img src="https://github.com/Query-farm/vgi-python/actions/workflows/ci.yml/badge.svg" alt="CI"></a>
228
+ <a href="https://pypi.org/project/vgi-python/"><img src="https://img.shields.io/pypi/v/vgi-python" alt="PyPI"></a>
229
+ <a href="https://pypi.org/project/vgi-python/"><img src="https://img.shields.io/pypi/pyversions/vgi-python" alt="Python versions"></a>
230
+ <a href="LICENSE"><img src="https://img.shields.io/pypi/l/vgi-python" alt="License"></a>
227
231
  </p>
228
232
 
229
233
  ---
@@ -1,15 +1,19 @@
1
- # VGI (Vector Gateway Interface)
2
-
3
1
  <p align="center">
4
- <img src="https://raw.githubusercontent.com/Query-farm/vgi-python/main/docs/vgi-logo.png" alt="VGI Logo" width="480">
2
+ <img src="https://raw.githubusercontent.com/Query-farm/vgi-python/main/docs/vgi-logo.png?v=2" alt="Vector Gateway Interface logo" width="320">
5
3
  </p>
6
4
 
5
+ <h1 align="center">VGI</h1>
6
+
7
7
  <p align="center">
8
- <strong>Apache Arrow-based protocol for extending DuckDB using any language.</strong>
8
+ Apache Arrow-based protocol for extending DuckDB using any language — the Python reference implementation.<br>
9
+ Built by <a href="https://query.farm">🚜 Query.Farm</a>
9
10
  </p>
10
11
 
11
12
  <p align="center">
12
- Created by <a href="https://query.farm">Query.Farm</a>
13
+ <a href="https://github.com/Query-farm/vgi-python/actions/workflows/ci.yml"><img src="https://github.com/Query-farm/vgi-python/actions/workflows/ci.yml/badge.svg" alt="CI"></a>
14
+ <a href="https://pypi.org/project/vgi-python/"><img src="https://img.shields.io/pypi/v/vgi-python" alt="PyPI"></a>
15
+ <a href="https://pypi.org/project/vgi-python/"><img src="https://img.shields.io/pypi/pyversions/vgi-python" alt="Python versions"></a>
16
+ <a href="LICENSE"><img src="https://img.shields.io/pypi/l/vgi-python" alt="License"></a>
13
17
  </p>
14
18
 
15
19
  ---
Binary file
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "vgi-python"
3
- version = "0.29.0"
3
+ version = "0.29.3"
4
4
  description = "Vector Gateway Interface - Connect DuckDB to external programs via Apache Arrow"
5
5
  readme = "README.md"
6
6
  keywords = [
@@ -0,0 +1,77 @@
1
+ # Copyright 2026 Query Farm LLC - https://query.farm
2
+
3
+ # ruff: noqa: S101, D101, D102, D103
4
+ """`Client.table_function(batch_metadata_callback=...)`.
5
+
6
+ `_table_function_parallel` previously discarded `AnnotatedBatch.custom_metadata`
7
+ unconditionally (`if output.batch.num_rows > 0: output_queue.put(output.batch)`)
8
+ and only forwarded the bare `pa.RecordBatch` — so a worker's `vgi.cache.*`
9
+ cacheability advertisement (`vgi/cache_control.py`), which rides
10
+ `custom_metadata`, was structurally unreachable through the public
11
+ `table_function()` generator. `batch_metadata_callback` mirrors the existing
12
+ `bind_result_callback` pattern to fix that additively, with no change to the
13
+ generator's yield type. Exercised against `cacheable_numbers`
14
+ (`vgi/_test_fixtures/table/cache.py`), which advertises `vgi.cache.ttl` on its
15
+ first batch.
16
+ """
17
+
18
+ from __future__ import annotations
19
+
20
+ from typing import Any
21
+
22
+ import pyarrow as pa
23
+ import pytest
24
+
25
+ from vgi.arguments import Arguments
26
+
27
+ DATA = "data"
28
+
29
+
30
+ @pytest.fixture
31
+ def client(client_transport: Any) -> Any:
32
+ with client_transport() as c:
33
+ c.catalog_attach(name="example", data_version_spec=None, implementation_version=None)
34
+ yield c
35
+
36
+
37
+ def test_callback_receives_cache_control_metadata(client: Any) -> None:
38
+ metas: list[pa.KeyValueMetadata | None] = []
39
+ batches = list(
40
+ client.table_function(
41
+ function_name="cacheable_numbers",
42
+ schema_name=DATA,
43
+ arguments=Arguments(named={"n": pa.scalar(5)}),
44
+ batch_metadata_callback=metas.append,
45
+ )
46
+ )
47
+ assert sum(b.num_rows for b in batches) == 5
48
+ assert len(metas) == len(batches)
49
+ assert metas[0] is not None
50
+ assert dict(metas[0])[b"vgi.cache.ttl"] == b"300"
51
+
52
+
53
+ def test_callback_is_optional_and_defaults_to_none(client: Any) -> None:
54
+ """No `batch_metadata_callback` -> unchanged behavior, no crash."""
55
+ batches = list(
56
+ client.table_function(
57
+ function_name="cacheable_numbers",
58
+ schema_name=DATA,
59
+ arguments=Arguments(named={"n": pa.scalar(3)}),
60
+ )
61
+ )
62
+ assert sum(b.num_rows for b in batches) == 3
63
+
64
+
65
+ def test_callback_sees_none_for_a_batch_without_custom_metadata(client: Any) -> None:
66
+ """A function that never advertises cache control still drives the callback once per batch, with `None`."""
67
+ metas: list[pa.KeyValueMetadata | None] = []
68
+ list(
69
+ client.table_function(
70
+ function_name="sequence",
71
+ schema_name="main",
72
+ arguments=Arguments(positional=[pa.scalar(4)]),
73
+ batch_metadata_callback=metas.append,
74
+ )
75
+ )
76
+ assert metas
77
+ assert all(m is None for m in metas)
@@ -0,0 +1,67 @@
1
+ # Copyright 2026 Query Farm LLC - https://query.farm
2
+
3
+ # ruff: noqa: S101, D101, D102, D103
4
+ """`Client.table_scan_branches_get`.
5
+
6
+ `Client` had no wrapper for `catalog_table_scan_branches_get` at all —
7
+ grepped the whole `vgi/client/` package for "branch" and the only hit was an
8
+ unrelated code comment ("skip the subprocess branch"). A multi-branch table
9
+ was therefore invisible to any non-DuckDB caller, not just unsupported by a
10
+ higher-level connector. Exercised against `data.multi_branch_numbers` (two
11
+ `sequence(50)` arms — `vgi/_test_fixtures/worker.py`) and, for the legacy
12
+ fallback, `data.numbers` (an ordinary single-branch table whose worker only
13
+ implements the older `table_scan_function_get`).
14
+ """
15
+
16
+ from __future__ import annotations
17
+
18
+ from typing import Any
19
+
20
+ import pytest
21
+
22
+ from vgi.catalog import ScanBranch, ScanBranchesResult
23
+
24
+ DATA = "data"
25
+
26
+
27
+ @pytest.fixture
28
+ def client(client_transport: Any) -> Any:
29
+ with client_transport() as c:
30
+ c.catalog_attach(name="example", data_version_spec=None, implementation_version=None)
31
+ yield c
32
+
33
+
34
+ def _attach_opaque(client: Any) -> Any:
35
+ # catalog_attach() was already called by the fixture above (its return
36
+ # value discarded) — re-attach here to get the opaque data this method
37
+ # needs, mirroring how CatalogClientMixin methods are used standalone.
38
+ return client.catalog_attach(name="example", data_version_spec=None, implementation_version=None).attach_opaque_data
39
+
40
+
41
+ def test_multi_branch_table_returns_all_branches(client: Any) -> None:
42
+ result = client.table_scan_branches_get(
43
+ attach_opaque_data=_attach_opaque(client),
44
+ schema_name=DATA,
45
+ name="multi_branch_numbers",
46
+ )
47
+ assert isinstance(result, ScanBranchesResult)
48
+ assert len(result.branches) == 2
49
+ for branch in result.branches:
50
+ assert isinstance(branch, ScanBranch)
51
+ assert branch.function_name == "sequence"
52
+ assert branch.source_table is None # function branch, not catalog-table
53
+
54
+
55
+ def test_single_branch_table_falls_back_to_legacy_rpc(client: Any) -> None:
56
+ """`data.numbers` only implements `table_scan_function_get` — the fallback wraps it as one branch."""
57
+ result = client.table_scan_branches_get(
58
+ attach_opaque_data=_attach_opaque(client),
59
+ schema_name=DATA,
60
+ name="numbers",
61
+ )
62
+ assert len(result.branches) == 1
63
+ assert result.branches[0].function_name == client.table_scan_function_get(
64
+ attach_opaque_data=_attach_opaque(client),
65
+ schema_name=DATA,
66
+ name="numbers",
67
+ ).function_name
@@ -0,0 +1,93 @@
1
+ # Copyright 2026 Query Farm LLC - https://query.farm
2
+
3
+ # ruff: noqa: S101, D101, D102, D103
4
+ """`Client.table_function_plan` + `Client.table_function(split_tokens=...)`.
5
+
6
+ Splits were previously entirely unreachable from `Client` — no wrapper for
7
+ `on_plan()` existed at all, and `table_function()`/`_do_init` had no
8
+ `split_tokens` parameter to redeem one, even though the wire protocol
9
+ (`TableFunctionPlanRequest`/`PlanResponse`/`InitRequest.split_tokens`) and the
10
+ `VgiProtocol.table_function_plan` RPC already supported it — the DuckDB C++
11
+ extension drives this today, but the reference Python client never grew the
12
+ equivalent. Exercised against `split_sequence` (the split-capable twin of
13
+ `sequence`, `vgi/_test_fixtures/table/splits.py`) over every client transport.
14
+ """
15
+
16
+ from __future__ import annotations
17
+
18
+ from typing import Any
19
+
20
+ import pyarrow as pa
21
+ import pytest
22
+
23
+ from vgi.arguments import Arguments
24
+ from vgi.protocol import ScanSplit
25
+
26
+ MAIN = "main"
27
+
28
+
29
+ @pytest.fixture
30
+ def client(client_transport: Any) -> Any:
31
+ with client_transport() as c:
32
+ c.catalog_attach(name="example", data_version_spec=None, implementation_version=None)
33
+ yield c
34
+
35
+
36
+ def test_plan_returns_typed_scan_splits(client: Any) -> None:
37
+ args = Arguments(named={"n": pa.scalar(20), "splits": pa.scalar(4)})
38
+ plan = client.table_function_plan(function_name="split_sequence", schema_name=MAIN, arguments=args)
39
+ assert len(plan.splits) == 4
40
+ for split in plan.splits:
41
+ assert isinstance(split, ScanSplit)
42
+ assert split.token # framework-stamped, non-empty
43
+ assert split.estimated_rows == 5
44
+
45
+
46
+ def test_redeeming_each_split_in_order_reproduces_the_whole_scan(client: Any) -> None:
47
+ """split_sequence redeemed split-by-split must equal sequence(n)'s output.
48
+
49
+ Also threads ``split_execution_id``/``split_init_opaque_data`` from the
50
+ plan on every redemption — this fixture doesn't need cross-split shared
51
+ state to be correct, but this proves the wire path accepts and round-trips
52
+ them without erroring, for workers that do.
53
+ """
54
+ args = Arguments(named={"n": pa.scalar(37), "splits": pa.scalar(5)})
55
+ plan = client.table_function_plan(function_name="split_sequence", schema_name=MAIN, arguments=args)
56
+
57
+ all_rows: list[int] = []
58
+ for split in plan.splits:
59
+ batches = list(
60
+ client.table_function(
61
+ function_name="split_sequence",
62
+ schema_name=MAIN,
63
+ arguments=args,
64
+ split_tokens=[split.token],
65
+ split_execution_id=plan.execution_id,
66
+ split_init_opaque_data=plan.init_opaque_data,
67
+ )
68
+ )
69
+ for batch in batches:
70
+ all_rows.extend(batch.column("n").to_pylist())
71
+
72
+ assert sorted(all_rows) == list(range(37))
73
+
74
+
75
+ def test_split_zero_yields_no_splits_and_no_rows(client: Any) -> None:
76
+ args = Arguments(named={"n": pa.scalar(10), "splits": pa.scalar(4)})
77
+ plan = client.table_function_plan(function_name="split_zero", schema_name=MAIN, arguments=args)
78
+ assert plan.splits == []
79
+
80
+
81
+ def test_redeeming_a_split_forces_single_worker(client: Any) -> None:
82
+ """`split_tokens` bypasses `_spawn_additional_workers` — no additional worker connections open."""
83
+ args = Arguments(named={"n": pa.scalar(8), "splits": pa.scalar(2)})
84
+ plan = client.table_function_plan(function_name="split_sequence", schema_name=MAIN, arguments=args)
85
+ list(
86
+ client.table_function(
87
+ function_name="split_sequence",
88
+ schema_name=MAIN,
89
+ arguments=args,
90
+ split_tokens=[plan.splits[0].token],
91
+ )
92
+ )
93
+ assert client._additional_workers == []
@@ -0,0 +1,85 @@
1
+ # Copyright 2026 Query Farm LLC - https://query.farm
2
+
3
+ # ruff: noqa: S101, D101, D102, D103
4
+ """`Client.table_get`/`table_function(at_unit=..., at_value=...)`.
5
+
6
+ Both methods previously dropped `at_unit`/`at_value` on the floor even though
7
+ the underlying wire RPCs (`catalog_table_get`, `BindRequest.at_unit`/
8
+ `.at_value`) already carried them — `table_scan_function_get` was the only
9
+ `Client` method that exposed time travel at all. Two distinct worker
10
+ patterns are exercised, both real fixtures, proving this isn't just plumbing
11
+ that happens to compile:
12
+
13
+ * `data.versioned_data` reads its version through a pre-resolved bind
14
+ argument (`table_scan_function_get(at_unit=...)` bakes it into the
15
+ returned `ScanFunctionResult.arguments`) — `table_get(at_unit=...)` is
16
+ what needed fixing here, to see the schema at that version at all.
17
+ * `data.tt_pushdown_fn` (`tt_pushdown_scan`) reads `at_unit`/`at_value`
18
+ **directly off the init request** (`ProcessParams.at_unit`/`.at_value`,
19
+ see `vgi/_test_fixtures/table/tt_pushdown.py`) — this is the pattern that
20
+ needed `table_function(at_unit=...)` specifically; no amount of
21
+ pre-resolved arguments would reach it.
22
+ """
23
+
24
+ from __future__ import annotations
25
+
26
+ from typing import Any
27
+
28
+ import pyarrow as pa
29
+ import pytest
30
+
31
+ from vgi.arguments import Arguments
32
+
33
+ DATA = "data"
34
+
35
+
36
+ @pytest.fixture
37
+ def client(client_transport: Any) -> Any:
38
+ with client_transport() as c:
39
+ c.catalog_attach(name="example", data_version_spec=None, implementation_version=None)
40
+ yield c
41
+
42
+
43
+ def _attach_opaque(client: Any) -> Any:
44
+ result = client.catalog_attach(name="example", data_version_spec=None, implementation_version=None)
45
+ return result.attach_opaque_data
46
+
47
+
48
+ def test_table_get_at_unit_returns_the_versioned_schema(client: Any) -> None:
49
+ opaque = _attach_opaque(client)
50
+ v1 = client.table_get(
51
+ attach_opaque_data=opaque, schema_name=DATA, name="versioned_data", at_unit="VERSION", at_value="1"
52
+ )
53
+ live = client.table_get(attach_opaque_data=opaque, schema_name=DATA, name="versioned_data")
54
+
55
+ v1_schema = pa.ipc.read_schema(pa.py_buffer(v1.columns))
56
+ live_schema = pa.ipc.read_schema(pa.py_buffer(live.columns))
57
+ assert v1_schema.names == ["id"] # version 1: (id int64) only
58
+ assert live_schema.names == ["id", "score"] # current: version 3
59
+
60
+
61
+ def test_table_get_with_no_at_clause_is_unaffected(client: Any) -> None:
62
+ """The new `at_unit`/`at_value` params default to `None` — unchanged behavior without them."""
63
+ info = client.table_get(attach_opaque_data=_attach_opaque(client), schema_name=DATA, name="numbers")
64
+ assert info is not None
65
+
66
+
67
+ def test_table_function_at_unit_reaches_a_worker_that_reads_it_from_init(client: Any) -> None:
68
+ """`tt_pushdown_scan` reads `at_unit`/`at_value` off the init request, not a resolved bind arg."""
69
+ v1_batches = list(
70
+ client.table_function(function_name="tt_pushdown_scan", schema_name=DATA, at_unit="VERSION", at_value="1")
71
+ )
72
+ live_batches = list(client.table_function(function_name="tt_pushdown_scan", schema_name=DATA))
73
+
74
+ assert sum(b.num_rows for b in v1_batches) == 5
75
+ assert sum(b.num_rows for b in live_batches) == 10
76
+
77
+
78
+ def test_table_function_with_no_at_clause_is_unaffected(client: Any) -> None:
79
+ """The new `at_unit`/`at_value` params default to `None` — unchanged behavior without them."""
80
+ batches = list(
81
+ client.table_function(
82
+ function_name="sequence", schema_name="main", arguments=Arguments(positional=[pa.scalar(5)])
83
+ )
84
+ )
85
+ assert sum(b.num_rows for b in batches) == 5
@@ -929,6 +929,11 @@ wheels = [
929
929
  { url = "https://files.pythonhosted.org/packages/b9/6d/a637d52449d98a6892d9a4dc0262587afdb6a66f201871842dce5a97b1c1/httpx2-2.10.0-py3-none-any.whl", hash = "sha256:5e3194a432701e1cc6f69a8b1b2fa199ef907013fede8d9a09a2c5b7b8141a18", size = 94355, upload-time = "2026-08-09T09:11:30.882Z" },
930
930
  ]
931
931
 
932
+ [package.optional-dependencies]
933
+ zstd = [
934
+ { name = "zstandard", marker = "python_full_version < '3.14'" },
935
+ ]
936
+
932
937
  [[package]]
933
938
  name = "httpx2-jsfetch"
934
939
  version = "1.0"
@@ -2555,7 +2560,7 @@ requires-dist = [
2555
2560
 
2556
2561
  [[package]]
2557
2562
  name = "vgi-python"
2558
- version = "0.28.1"
2563
+ version = "0.29.2"
2559
2564
  source = { editable = "." }
2560
2565
  dependencies = [
2561
2566
  { name = "click" },
@@ -2698,7 +2703,7 @@ docs = [
2698
2703
 
2699
2704
  [[package]]
2700
2705
  name = "vgi-rpc"
2701
- version = "0.43.0"
2706
+ version = "0.43.1"
2702
2707
  source = { registry = "https://pypi.org/simple" }
2703
2708
  dependencies = [
2704
2709
  { name = "docstring-parser" },
@@ -2706,9 +2711,9 @@ dependencies = [
2706
2711
  { name = "pywin32", marker = "sys_platform == 'win32'" },
2707
2712
  { name = "tzdata", marker = "sys_platform == 'win32'" },
2708
2713
  ]
2709
- sdist = { url = "https://files.pythonhosted.org/packages/e6/ee/94a47d89eaebcd2ad433b86b0c6017131f5b15ef1d7f02c60fbab4906dbc/vgi_rpc-0.43.0.tar.gz", hash = "sha256:abae616414353cbc18467d4c325369adb5acf0cab36332a35c2a7d463692885b", size = 1142865, upload-time = "2026-08-24T00:43:51.796Z" }
2714
+ sdist = { url = "https://files.pythonhosted.org/packages/27/a0/b308cc62cde38fe2a7bc7a2c57bbb8e956084dd04134a4b0d805378daf16/vgi_rpc-0.43.1.tar.gz", hash = "sha256:d94a3c2cfcf90e1122b2b7ec23a47912f1b3e2d265267aa6704bd64c3a7f2a55", size = 1145519, upload-time = "2026-08-27T14:51:14.923Z" }
2710
2715
  wheels = [
2711
- { url = "https://files.pythonhosted.org/packages/5c/03/680bc346a6335451f97618e5432ddae3b976e1ff6682ee1e736540980f20/vgi_rpc-0.43.0-py3-none-any.whl", hash = "sha256:227fac13e0053caa73b2d75e62eab155d36dcb457a165d215f7817fdae865fb0", size = 526747, upload-time = "2026-08-24T00:43:50.055Z" },
2716
+ { url = "https://files.pythonhosted.org/packages/96/f2/15bd8a76ee3534c4d911b0f76c948378db4c175a40ceeb30325e6ab994a6/vgi_rpc-0.43.1-py3-none-any.whl", hash = "sha256:1eecd6c17f06d6fadae332be33998d22cdd01e5caaaae7889b747f0c1eaac498", size = 526753, upload-time = "2026-08-27T14:51:12.975Z" },
2712
2717
  ]
2713
2718
 
2714
2719
  [package.optional-dependencies]
@@ -2723,7 +2728,7 @@ external = [
2723
2728
  ]
2724
2729
  http = [
2725
2730
  { name = "falcon" },
2726
- { name = "httpx2" },
2731
+ { name = "httpx2", extra = ["zstd"] },
2727
2732
  { name = "msgpack" },
2728
2733
  { name = "pycryptodome" },
2729
2734
  { name = "pynacl", marker = "sys_platform == 'linux'" },
@@ -95,6 +95,7 @@ __all__ = [
95
95
  "RowSumFunction",
96
96
  "BlendedDropFunction",
97
97
  "SubstreamPartialSumFunction",
98
+ "MultiBatchFinishFunction",
98
99
  "SumAllColumnsFunction",
99
100
  "SumAllColumnsSimpleDistributed",
100
101
  "ExceptionProcessFunction",
@@ -195,6 +196,88 @@ class SubstreamPartialSumFunction(TableInOutFunction[SingleTableArguments, Subst
195
196
  return [pa.RecordBatch.from_pydict({name: [total]}, schema=params.output_schema)]
196
197
 
197
198
 
199
+ @dataclass(kw_only=True)
200
+ class MultiBatchFinishState(ArrowSerializableDataclass):
201
+ """This substream's running total and the number of rows it saw."""
202
+
203
+ total: int = 0
204
+ rows: int = 0
205
+
206
+
207
+ class MultiBatchFinishFunction(TableInOutFunction[SingleTableArguments, MultiBatchFinishState]):
208
+ """Streaming FINALIZE that emits MANY batches — the shape no SDK had a fixture for.
209
+
210
+ Every other finalize fixture returns a single batch, and one batch is the
211
+ easy case: over HTTP a producer is strictly lock-step (one batch per
212
+ response), so a single-batch flush completes in one turn and never needs a
213
+ continuation. A flush of TWO OR MORE batches does, and in vgi-rust that path
214
+ was a hard error rather than a pagination — invisible for as long as nothing
215
+ exercised it.
216
+
217
+ So this emits one batch per input row the substream saw: ``rows`` batches,
218
+ the first carrying that substream's ``total`` and the rest carrying 0. The
219
+ split is deliberate — it makes the two failure modes distinguishable:
220
+
221
+ * ``SUM(n)`` wrong → a batch's CONTENTS were lost, duplicated or reordered.
222
+ * ``COUNT(*)`` wrong → a BATCH was lost or repeated. This is the one that
223
+ catches a broken continuation: a flush truncated after its first batch
224
+ still sums correctly and only the count betrays it.
225
+
226
+ Both invariants hold regardless of how DuckDB fans the input across
227
+ substreams (each substream's partials sum to the whole, and its batch count
228
+ equals its row count), so the test needs no assumption about thread count.
229
+ """
230
+
231
+ class Meta:
232
+ name = "multi_batch_finish"
233
+ description = "Streaming finalize that emits one batch per input row (multi-batch flush)"
234
+ categories = ["testing", "aggregation"]
235
+
236
+ @classmethod
237
+ def cardinality(cls, params: BindParams[SingleTableArguments]) -> TableCardinality:
238
+ # One output row per input row, but the input size is unknown up-front.
239
+ return TableCardinality(estimate=1, max=None)
240
+
241
+ @classmethod
242
+ def on_bind(cls, params: BindParams[SingleTableArguments]) -> BindResponse:
243
+ assert params.bind_call.input_schema is not None
244
+ field = params.bind_call.input_schema.field(0)
245
+ return BindResponse(output_schema=schema({field.name: pa.int64()}))
246
+
247
+ @classmethod
248
+ def initial_state(cls, params: ProcessParams[SingleTableArguments]) -> MultiBatchFinishState:
249
+ return MultiBatchFinishState(total=0, rows=0)
250
+
251
+ @classmethod
252
+ def transform(
253
+ cls,
254
+ batch: pa.RecordBatch,
255
+ params: ProcessParams[SingleTableArguments],
256
+ state: MultiBatchFinishState | None,
257
+ ) -> list[pa.RecordBatch]:
258
+ if state is None:
259
+ raise ValueError("State must not be None in transform()")
260
+ col_sum = pc.sum(batch.column(0))
261
+ if col_sum.is_valid:
262
+ state.total += col_sum.as_py()
263
+ state.rows += batch.num_rows
264
+ return [] # accumulate only; the whole point is the flush
265
+
266
+ @classmethod
267
+ def finish(
268
+ cls,
269
+ params: ProcessParams[SingleTableArguments],
270
+ states: list[MultiBatchFinishState],
271
+ ) -> list[pa.RecordBatch]:
272
+ total = sum(st.total for st in states)
273
+ rows = sum(st.rows for st in states)
274
+ name = params.output_schema.names[0]
275
+ return [
276
+ pa.RecordBatch.from_pydict({name: [total if i == 0 else 0]}, schema=params.output_schema)
277
+ for i in range(rows)
278
+ ]
279
+
280
+
198
281
  class EchoFunction(TableInOutGenerator[SingleTableArguments]):
199
282
  """Passthrough function that emits each input batch unchanged.
200
283
 
@@ -1097,7 +1180,19 @@ class CrashOnProcessFunction(BufferInputFunction):
1097
1180
  os.kill(os.getpid(), signal.SIGABRT)
1098
1181
  else:
1099
1182
  os.kill(os.getpid(), signal.SIGKILL)
1100
- return params.execution_id # unreachable
1183
+ # Killing YOURSELF is not synchronous: kill(2) returns on the calling
1184
+ # thread and the kernel tears the task down asynchronously. RETURNING
1185
+ # here hands that window to the framework, which then races to serialize
1186
+ # and write the process response — and how many bytes escape before the
1187
+ # process actually dies decides what the client sees: nothing (the
1188
+ # "RPC response stream EOF" these tests assert), a schema only, a
1189
+ # truncated batch message, or the whole response, in which case the
1190
+ # query SUCCEEDS with zero rows. Measured in the Go SDK, whose fixture
1191
+ # had the identical shape, that was a 23% failure rate — see
1192
+ # vgi-go 41f18d1. CPython's slower interpreter makes it rarer here, not
1193
+ # impossible. Park instead, so this worker can never write another byte.
1194
+ time.sleep(5)
1195
+ raise AssertionError("crash_on_process: SIGKILL did not terminate the worker")
1101
1196
 
1102
1197
 
1103
1198
  class CrashOnCombineFunction(BufferInputFunction):
@@ -286,6 +286,7 @@ from vgi._test_fixtures.table_in_out import (
286
286
  HangOnProcessFunction,
287
287
  HostileProvenanceFunction,
288
288
  LargeStateFunction,
289
+ MultiBatchFinishFunction,
289
290
  OrderedBufferInputFunction,
290
291
  OrderedSourceFunction,
291
292
  ProjectableBlendedFunction,
@@ -441,6 +442,7 @@ _EXAMPLE_CATALOG = Catalog(
441
442
  SecretInOutFunction,
442
443
  RepeatInputsFunction,
443
444
  SlowCancellableInOutFunction,
445
+ MultiBatchFinishFunction,
444
446
  SubstreamPartialSumFunction,
445
447
  SumAllColumnsFunction,
446
448
  SumAllColumnsSimpleDistributed,