vgi-python 0.13.0__tar.gz → 0.14.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 (388) hide show
  1. {vgi_python-0.13.0 → vgi_python-0.14.0}/PKG-INFO +2 -2
  2. {vgi_python-0.13.0 → vgi_python-0.14.0}/ci/run-integration.sh +5 -0
  3. {vgi_python-0.13.0 → vgi_python-0.14.0}/pyproject.toml +2 -2
  4. {vgi_python-0.13.0 → vgi_python-0.14.0}/tests/conformance/test_directory_parity.py +9 -0
  5. {vgi_python-0.13.0 → vgi_python-0.14.0}/tests/landing/describe.expected.json +292 -2
  6. vgi_python-0.14.0/tests/test_cache_control.py +222 -0
  7. {vgi_python-0.13.0 → vgi_python-0.14.0}/uv.lock +5 -5
  8. {vgi_python-0.13.0 → vgi_python-0.14.0}/vgi/_test_fixtures/http_server.py +26 -0
  9. {vgi_python-0.13.0 → vgi_python-0.14.0}/vgi/_test_fixtures/table/__init__.py +40 -0
  10. vgi_python-0.14.0/vgi/_test_fixtures/table/cache.py +1525 -0
  11. {vgi_python-0.13.0 → vgi_python-0.14.0}/vgi/_test_fixtures/worker.py +149 -8
  12. vgi_python-0.14.0/vgi/cache_control.py +150 -0
  13. {vgi_python-0.13.0 → vgi_python-0.14.0}/vgi/protocol.py +54 -0
  14. {vgi_python-0.13.0 → vgi_python-0.14.0}/vgi/table_function.py +16 -0
  15. {vgi_python-0.13.0 → vgi_python-0.14.0}/.gitattributes +0 -0
  16. {vgi_python-0.13.0 → vgi_python-0.14.0}/.github/dependabot.yml +0 -0
  17. {vgi_python-0.13.0 → vgi_python-0.14.0}/.github/styles/config/vocabularies/VGI/accept.txt +0 -0
  18. {vgi_python-0.13.0 → vgi_python-0.14.0}/.github/workflows/ci.yml +0 -0
  19. {vgi_python-0.13.0 → vgi_python-0.14.0}/.github/workflows/docs.yml +0 -0
  20. {vgi_python-0.13.0 → vgi_python-0.14.0}/.github/workflows/integration.yml +0 -0
  21. {vgi_python-0.13.0 → vgi_python-0.14.0}/.github/workflows/release.yml +0 -0
  22. {vgi_python-0.13.0 → vgi_python-0.14.0}/.gitignore +0 -0
  23. {vgi_python-0.13.0 → vgi_python-0.14.0}/.python-version +0 -0
  24. {vgi_python-0.13.0 → vgi_python-0.14.0}/.vale.ini +0 -0
  25. {vgi_python-0.13.0 → vgi_python-0.14.0}/CLAUDE.md +0 -0
  26. {vgi_python-0.13.0 → vgi_python-0.14.0}/DOCS_ACCEPTANCE_CRITERIA.md +0 -0
  27. {vgi_python-0.13.0 → vgi_python-0.14.0}/DOCS_REVIEW_RUBRIC.md +0 -0
  28. {vgi_python-0.13.0 → vgi_python-0.14.0}/DOCS_USABILITY_TEST.md +0 -0
  29. {vgi_python-0.13.0 → vgi_python-0.14.0}/LICENSE +0 -0
  30. {vgi_python-0.13.0 → vgi_python-0.14.0}/README.md +0 -0
  31. {vgi_python-0.13.0 → vgi_python-0.14.0}/SECURITY.md +0 -0
  32. {vgi_python-0.13.0 → vgi_python-0.14.0}/ci/README.md +0 -0
  33. {vgi_python-0.13.0 → vgi_python-0.14.0}/ci/preprocess-require.awk +0 -0
  34. {vgi_python-0.13.0 → vgi_python-0.14.0}/dist-vgi/.gitignore +0 -0
  35. {vgi_python-0.13.0 → vgi_python-0.14.0}/docs/aggregate-functions.md +0 -0
  36. {vgi_python-0.13.0 → vgi_python-0.14.0}/docs/api/arguments.md +0 -0
  37. {vgi_python-0.13.0 → vgi_python-0.14.0}/docs/api/auth.md +0 -0
  38. {vgi_python-0.13.0 → vgi_python-0.14.0}/docs/api/catalogs.md +0 -0
  39. {vgi_python-0.13.0 → vgi_python-0.14.0}/docs/api/client.md +0 -0
  40. {vgi_python-0.13.0 → vgi_python-0.14.0}/docs/api/exceptions.md +0 -0
  41. {vgi_python-0.13.0 → vgi_python-0.14.0}/docs/api/filters.md +0 -0
  42. {vgi_python-0.13.0 → vgi_python-0.14.0}/docs/api/functions.md +0 -0
  43. {vgi_python-0.13.0 → vgi_python-0.14.0}/docs/api/http.md +0 -0
  44. {vgi_python-0.13.0 → vgi_python-0.14.0}/docs/api/index.md +0 -0
  45. {vgi_python-0.13.0 → vgi_python-0.14.0}/docs/api/metadata.md +0 -0
  46. {vgi_python-0.13.0 → vgi_python-0.14.0}/docs/api/observability.md +0 -0
  47. {vgi_python-0.13.0 → vgi_python-0.14.0}/docs/api/storage.md +0 -0
  48. {vgi_python-0.13.0 → vgi_python-0.14.0}/docs/api/transactor.md +0 -0
  49. {vgi_python-0.13.0 → vgi_python-0.14.0}/docs/api/worker.md +0 -0
  50. {vgi_python-0.13.0 → vgi_python-0.14.0}/docs/argument-serialization.md +0 -0
  51. {vgi_python-0.13.0 → vgi_python-0.14.0}/docs/assets/apple-touch-icon.png +0 -0
  52. {vgi_python-0.13.0 → vgi_python-0.14.0}/docs/assets/favicon-16x16.png +0 -0
  53. {vgi_python-0.13.0 → vgi_python-0.14.0}/docs/assets/favicon-32x32.png +0 -0
  54. {vgi_python-0.13.0 → vgi_python-0.14.0}/docs/assets/favicon.ico +0 -0
  55. {vgi_python-0.13.0 → vgi_python-0.14.0}/docs/assets/kinds/aggregate.svg +0 -0
  56. {vgi_python-0.13.0 → vgi_python-0.14.0}/docs/assets/kinds/buffering.svg +0 -0
  57. {vgi_python-0.13.0 → vgi_python-0.14.0}/docs/assets/kinds/scalar.svg +0 -0
  58. {vgi_python-0.13.0 → vgi_python-0.14.0}/docs/assets/kinds/table-in-out.svg +0 -0
  59. {vgi_python-0.13.0 → vgi_python-0.14.0}/docs/assets/kinds/table.svg +0 -0
  60. {vgi_python-0.13.0 → vgi_python-0.14.0}/docs/assets/logo.png +0 -0
  61. {vgi_python-0.13.0 → vgi_python-0.14.0}/docs/assets/social-card.png +0 -0
  62. {vgi_python-0.13.0 → vgi_python-0.14.0}/docs/authentication.md +0 -0
  63. {vgi_python-0.13.0 → vgi_python-0.14.0}/docs/catalog-interface.md +0 -0
  64. {vgi_python-0.13.0 → vgi_python-0.14.0}/docs/cli.md +0 -0
  65. {vgi_python-0.13.0 → vgi_python-0.14.0}/docs/column-statistics.md +0 -0
  66. {vgi_python-0.13.0 → vgi_python-0.14.0}/docs/concepts/index.md +0 -0
  67. {vgi_python-0.13.0 → vgi_python-0.14.0}/docs/contributing-docs.md +0 -0
  68. {vgi_python-0.13.0 → vgi_python-0.14.0}/docs/filter-pushdown.md +0 -0
  69. {vgi_python-0.13.0 → vgi_python-0.14.0}/docs/generator-api.md +0 -0
  70. {vgi_python-0.13.0 → vgi_python-0.14.0}/docs/how-to/catalogs.md +0 -0
  71. {vgi_python-0.13.0 → vgi_python-0.14.0}/docs/how-to/function-patterns.md +0 -0
  72. {vgi_python-0.13.0 → vgi_python-0.14.0}/docs/how-to/http-auth.md +0 -0
  73. {vgi_python-0.13.0 → vgi_python-0.14.0}/docs/how-to/index.md +0 -0
  74. {vgi_python-0.13.0 → vgi_python-0.14.0}/docs/how-to/pushdown-and-statistics.md +0 -0
  75. {vgi_python-0.13.0 → vgi_python-0.14.0}/docs/how-to/state-storage.md +0 -0
  76. {vgi_python-0.13.0 → vgi_python-0.14.0}/docs/index.md +0 -0
  77. {vgi_python-0.13.0 → vgi_python-0.14.0}/docs/lifecycle.md +0 -0
  78. {vgi_python-0.13.0 → vgi_python-0.14.0}/docs/metadata.md +0 -0
  79. {vgi_python-0.13.0 → vgi_python-0.14.0}/docs/overrides/main.html +0 -0
  80. {vgi_python-0.13.0 → vgi_python-0.14.0}/docs/robots.txt +0 -0
  81. {vgi_python-0.13.0 → vgi_python-0.14.0}/docs/shared-storage.md +0 -0
  82. {vgi_python-0.13.0 → vgi_python-0.14.0}/docs/stylesheets/extra.css +0 -0
  83. {vgi_python-0.13.0 → vgi_python-0.14.0}/docs/tutorial/index.md +0 -0
  84. {vgi_python-0.13.0 → vgi_python-0.14.0}/docs/tutorial/scalar.md +0 -0
  85. {vgi_python-0.13.0 → vgi_python-0.14.0}/docs/tutorial/table.md +0 -0
  86. {vgi_python-0.13.0 → vgi_python-0.14.0}/docs/vgi-logo.png +0 -0
  87. {vgi_python-0.13.0 → vgi_python-0.14.0}/examples/calc_scalar_worker.py +0 -0
  88. {vgi_python-0.13.0 → vgi_python-0.14.0}/examples/calc_worker.py +0 -0
  89. {vgi_python-0.13.0 → vgi_python-0.14.0}/examples/filter_worker.py +0 -0
  90. {vgi_python-0.13.0 → vgi_python-0.14.0}/examples/greeting_scalar_worker.py +0 -0
  91. {vgi_python-0.13.0 → vgi_python-0.14.0}/examples/row_count_worker.py +0 -0
  92. {vgi_python-0.13.0 → vgi_python-0.14.0}/examples/series_streaming_worker.py +0 -0
  93. {vgi_python-0.13.0 → vgi_python-0.14.0}/examples/sum_worker.py +0 -0
  94. {vgi_python-0.13.0 → vgi_python-0.14.0}/mkdocs.yml +0 -0
  95. {vgi_python-0.13.0 → vgi_python-0.14.0}/packages/vgi-fixtures/LICENSE +0 -0
  96. {vgi_python-0.13.0 → vgi_python-0.14.0}/packages/vgi-fixtures/README.md +0 -0
  97. {vgi_python-0.13.0 → vgi_python-0.14.0}/packages/vgi-fixtures/docker/Dockerfile +0 -0
  98. {vgi_python-0.13.0 → vgi_python-0.14.0}/packages/vgi-fixtures/docker/docker-entrypoint.sh +0 -0
  99. {vgi_python-0.13.0 → vgi_python-0.14.0}/packages/vgi-fixtures/pyproject.toml +0 -0
  100. {vgi_python-0.13.0 → vgi_python-0.14.0}/scripts/measure_startup.py +0 -0
  101. {vgi_python-0.13.0 → vgi_python-0.14.0}/scripts/run_all_tests.sh +0 -0
  102. {vgi_python-0.13.0 → vgi_python-0.14.0}/test-data/generate.sh +0 -0
  103. {vgi_python-0.13.0 → vgi_python-0.14.0}/tests/__init__.py +0 -0
  104. {vgi_python-0.13.0 → vgi_python-0.14.0}/tests/_http_fixtures.py +0 -0
  105. {vgi_python-0.13.0 → vgi_python-0.14.0}/tests/catalog/__init__.py +0 -0
  106. {vgi_python-0.13.0 → vgi_python-0.14.0}/tests/catalog/test_catalog_interface.py +0 -0
  107. {vgi_python-0.13.0 → vgi_python-0.14.0}/tests/catalog/test_client_catalog.py +0 -0
  108. {vgi_python-0.13.0 → vgi_python-0.14.0}/tests/catalog/test_column_statistics.py +0 -0
  109. {vgi_python-0.13.0 → vgi_python-0.14.0}/tests/catalog/test_declarative.py +0 -0
  110. {vgi_python-0.13.0 → vgi_python-0.14.0}/tests/catalog/test_example_worker_catalog.py +0 -0
  111. {vgi_python-0.13.0 → vgi_python-0.14.0}/tests/catalog/test_integration.py +0 -0
  112. {vgi_python-0.13.0 → vgi_python-0.14.0}/tests/catalog/test_required_field_filter_paths.py +0 -0
  113. {vgi_python-0.13.0 → vgi_python-0.14.0}/tests/catalog/test_scan_branches.py +0 -0
  114. {vgi_python-0.13.0 → vgi_python-0.14.0}/tests/catalog/test_serialization.py +0 -0
  115. {vgi_python-0.13.0 → vgi_python-0.14.0}/tests/catalog/test_setting.py +0 -0
  116. {vgi_python-0.13.0 → vgi_python-0.14.0}/tests/catalog/test_storage.py +0 -0
  117. {vgi_python-0.13.0 → vgi_python-0.14.0}/tests/catalog/test_time_travel.py +0 -0
  118. {vgi_python-0.13.0 → vgi_python-0.14.0}/tests/catalog/test_writable_table.py +0 -0
  119. {vgi_python-0.13.0 → vgi_python-0.14.0}/tests/client/__init__.py +0 -0
  120. {vgi_python-0.13.0 → vgi_python-0.14.0}/tests/client/test_broken_pipe.py +0 -0
  121. {vgi_python-0.13.0 → vgi_python-0.14.0}/tests/client/test_cli.py +0 -0
  122. {vgi_python-0.13.0 → vgi_python-0.14.0}/tests/client/test_cli_catalog_functions.py +0 -0
  123. {vgi_python-0.13.0 → vgi_python-0.14.0}/tests/client/test_worker_debug.py +0 -0
  124. {vgi_python-0.13.0 → vgi_python-0.14.0}/tests/conformance/__init__.py +0 -0
  125. {vgi_python-0.13.0 → vgi_python-0.14.0}/tests/conformance/_stub.py +0 -0
  126. {vgi_python-0.13.0 → vgi_python-0.14.0}/tests/conformance/conftest.py +0 -0
  127. {vgi_python-0.13.0 → vgi_python-0.14.0}/tests/conformance/test_accumulate.py +0 -0
  128. {vgi_python-0.13.0 → vgi_python-0.14.0}/tests/conformance/test_aggregate.py +0 -0
  129. {vgi_python-0.13.0 → vgi_python-0.14.0}/tests/conformance/test_attach.py +0 -0
  130. {vgi_python-0.13.0 → vgi_python-0.14.0}/tests/conformance/test_bearer_auth.py +0 -0
  131. {vgi_python-0.13.0 → vgi_python-0.14.0}/tests/conformance/test_const_param_enforcement.py +0 -0
  132. {vgi_python-0.13.0 → vgi_python-0.14.0}/tests/conformance/test_container.py +0 -0
  133. {vgi_python-0.13.0 → vgi_python-0.14.0}/tests/conformance/test_copy_from.py +0 -0
  134. {vgi_python-0.13.0 → vgi_python-0.14.0}/tests/conformance/test_copy_to.py +0 -0
  135. {vgi_python-0.13.0 → vgi_python-0.14.0}/tests/conformance/test_function_inventory.py +0 -0
  136. {vgi_python-0.13.0 → vgi_python-0.14.0}/tests/conformance/test_github.py +0 -0
  137. {vgi_python-0.13.0 → vgi_python-0.14.0}/tests/conformance/test_http_client.py +0 -0
  138. {vgi_python-0.13.0 → vgi_python-0.14.0}/tests/conformance/test_http_external_location.py +0 -0
  139. {vgi_python-0.13.0 → vgi_python-0.14.0}/tests/conformance/test_http_upload_url.py +0 -0
  140. {vgi_python-0.13.0 → vgi_python-0.14.0}/tests/conformance/test_macro.py +0 -0
  141. {vgi_python-0.13.0 → vgi_python-0.14.0}/tests/conformance/test_overload.py +0 -0
  142. {vgi_python-0.13.0 → vgi_python-0.14.0}/tests/conformance/test_protocol_inventory.py +0 -0
  143. {vgi_python-0.13.0 → vgi_python-0.14.0}/tests/conformance/test_protocol_version.py +0 -0
  144. {vgi_python-0.13.0 → vgi_python-0.14.0}/tests/conformance/test_resumable_scan.py +0 -0
  145. {vgi_python-0.13.0 → vgi_python-0.14.0}/tests/conformance/test_scalar.py +0 -0
  146. {vgi_python-0.13.0 → vgi_python-0.14.0}/tests/conformance/test_scalar_attach_opaque_data.py +0 -0
  147. {vgi_python-0.13.0 → vgi_python-0.14.0}/tests/conformance/test_secret.py +0 -0
  148. {vgi_python-0.13.0 → vgi_python-0.14.0}/tests/conformance/test_settings.py +0 -0
  149. {vgi_python-0.13.0 → vgi_python-0.14.0}/tests/conformance/test_table.py +0 -0
  150. {vgi_python-0.13.0 → vgi_python-0.14.0}/tests/conformance/test_table_in_out.py +0 -0
  151. {vgi_python-0.13.0 → vgi_python-0.14.0}/tests/conformance/test_view.py +0 -0
  152. {vgi_python-0.13.0 → vgi_python-0.14.0}/tests/conformance/test_writable.py +0 -0
  153. {vgi_python-0.13.0 → vgi_python-0.14.0}/tests/conftest.py +0 -0
  154. {vgi_python-0.13.0 → vgi_python-0.14.0}/tests/landing/_checker.py +0 -0
  155. {vgi_python-0.13.0 → vgi_python-0.14.0}/tests/landing/describe.schema.json +0 -0
  156. {vgi_python-0.13.0 → vgi_python-0.14.0}/tests/scalar/__init__.py +0 -0
  157. {vgi_python-0.13.0 → vgi_python-0.14.0}/tests/scalar/test_bernoulli_function.py +0 -0
  158. {vgi_python-0.13.0 → vgi_python-0.14.0}/tests/scalar/test_binary_packet_function.py +0 -0
  159. {vgi_python-0.13.0 → vgi_python-0.14.0}/tests/scalar/test_client.py +0 -0
  160. {vgi_python-0.13.0 → vgi_python-0.14.0}/tests/scalar/test_conditional_message_function.py +0 -0
  161. {vgi_python-0.13.0 → vgi_python-0.14.0}/tests/scalar/test_hash_seed_function.py +0 -0
  162. {vgi_python-0.13.0 → vgi_python-0.14.0}/tests/scalar/test_multiply_by_setting_function.py +0 -0
  163. {vgi_python-0.13.0 → vgi_python-0.14.0}/tests/scalar/test_multiply_function.py +0 -0
  164. {vgi_python-0.13.0 → vgi_python-0.14.0}/tests/scalar/test_random_bytes_function.py +0 -0
  165. {vgi_python-0.13.0 → vgi_python-0.14.0}/tests/scalar/test_return_secret_value_function.py +0 -0
  166. {vgi_python-0.13.0 → vgi_python-0.14.0}/tests/table/__init__.py +0 -0
  167. {vgi_python-0.13.0 → vgi_python-0.14.0}/tests/table/generator/__init__.py +0 -0
  168. {vgi_python-0.13.0 → vgi_python-0.14.0}/tests/table/generator/test_constant_columns_function.py +0 -0
  169. {vgi_python-0.13.0 → vgi_python-0.14.0}/tests/table/generator/test_double_sequence_function.py +0 -0
  170. {vgi_python-0.13.0 → vgi_python-0.14.0}/tests/table/generator/test_exception_function.py +0 -0
  171. {vgi_python-0.13.0 → vgi_python-0.14.0}/tests/table/generator/test_filter_echo_function.py +0 -0
  172. {vgi_python-0.13.0 → vgi_python-0.14.0}/tests/table/generator/test_logging_function.py +0 -0
  173. {vgi_python-0.13.0 → vgi_python-0.14.0}/tests/table/generator/test_nested_sequence_function.py +0 -0
  174. {vgi_python-0.13.0 → vgi_python-0.14.0}/tests/table/generator/test_partitioned_function.py +0 -0
  175. {vgi_python-0.13.0 → vgi_python-0.14.0}/tests/table/generator/test_projected_data_function.py +0 -0
  176. {vgi_python-0.13.0 → vgi_python-0.14.0}/tests/table/generator/test_sequence_function.py +0 -0
  177. {vgi_python-0.13.0 → vgi_python-0.14.0}/tests/table/generator/test_settings_function.py +0 -0
  178. {vgi_python-0.13.0 → vgi_python-0.14.0}/tests/table/generator/test_struct_settings_function.py +0 -0
  179. {vgi_python-0.13.0 → vgi_python-0.14.0}/tests/table/generator/test_ten_thousand_function.py +0 -0
  180. {vgi_python-0.13.0 → vgi_python-0.14.0}/tests/table_in_out/__init__.py +0 -0
  181. {vgi_python-0.13.0 → vgi_python-0.14.0}/tests/table_in_out/generator/__init__.py +0 -0
  182. {vgi_python-0.13.0 → vgi_python-0.14.0}/tests/table_in_out/generator/test_buffer_input_function.py +0 -0
  183. {vgi_python-0.13.0 → vgi_python-0.14.0}/tests/table_in_out/generator/test_echo_function.py +0 -0
  184. {vgi_python-0.13.0 → vgi_python-0.14.0}/tests/table_in_out/generator/test_exception_functions.py +0 -0
  185. {vgi_python-0.13.0 → vgi_python-0.14.0}/tests/table_in_out/generator/test_filter_by_setting_function.py +0 -0
  186. {vgi_python-0.13.0 → vgi_python-0.14.0}/tests/table_in_out/generator/test_repeat_inputs_function.py +0 -0
  187. {vgi_python-0.13.0 → vgi_python-0.14.0}/tests/table_in_out/generator/test_sum_all_columns_function.py +0 -0
  188. {vgi_python-0.13.0 → vgi_python-0.14.0}/tests/table_in_out/test_client.py +0 -0
  189. {vgi_python-0.13.0 → vgi_python-0.14.0}/tests/test_access_log_audit.py +0 -0
  190. {vgi_python-0.13.0 → vgi_python-0.14.0}/tests/test_aggregate_function.py +0 -0
  191. {vgi_python-0.13.0 → vgi_python-0.14.0}/tests/test_argument_spec.py +0 -0
  192. {vgi_python-0.13.0 → vgi_python-0.14.0}/tests/test_auth.py +0 -0
  193. {vgi_python-0.13.0 → vgi_python-0.14.0}/tests/test_bind_exceptions.py +0 -0
  194. {vgi_python-0.13.0 → vgi_python-0.14.0}/tests/test_bind_request_at_clause.py +0 -0
  195. {vgi_python-0.13.0 → vgi_python-0.14.0}/tests/test_bound_storage_conformance.py +0 -0
  196. {vgi_python-0.13.0 → vgi_python-0.14.0}/tests/test_catalog_auth_binding.py +0 -0
  197. {vgi_python-0.13.0 → vgi_python-0.14.0}/tests/test_copy_from_function.py +0 -0
  198. {vgi_python-0.13.0 → vgi_python-0.14.0}/tests/test_copy_to_function.py +0 -0
  199. {vgi_python-0.13.0 → vgi_python-0.14.0}/tests/test_docstrings.py +0 -0
  200. {vgi_python-0.13.0 → vgi_python-0.14.0}/tests/test_documentation_examples.py +0 -0
  201. {vgi_python-0.13.0 → vgi_python-0.14.0}/tests/test_example_function_arg_types.py +0 -0
  202. {vgi_python-0.13.0 → vgi_python-0.14.0}/tests/test_examples_workers.py +0 -0
  203. {vgi_python-0.13.0 → vgi_python-0.14.0}/tests/test_exception_handling.py +0 -0
  204. {vgi_python-0.13.0 → vgi_python-0.14.0}/tests/test_exceptions.py +0 -0
  205. {vgi_python-0.13.0 → vgi_python-0.14.0}/tests/test_filter_pushdown.py +0 -0
  206. {vgi_python-0.13.0 → vgi_python-0.14.0}/tests/test_filter_pushdown_extension.py +0 -0
  207. {vgi_python-0.13.0 → vgi_python-0.14.0}/tests/test_function_storage.py +0 -0
  208. {vgi_python-0.13.0 → vgi_python-0.14.0}/tests/test_function_storage_azure_sql.py +0 -0
  209. {vgi_python-0.13.0 → vgi_python-0.14.0}/tests/test_function_storage_cf_do.py +0 -0
  210. {vgi_python-0.13.0 → vgi_python-0.14.0}/tests/test_function_storage_cf_do_integration.py +0 -0
  211. {vgi_python-0.13.0 → vgi_python-0.14.0}/tests/test_function_storage_conformance.py +0 -0
  212. {vgi_python-0.13.0 → vgi_python-0.14.0}/tests/test_generated_cpp_constants.py +0 -0
  213. {vgi_python-0.13.0 → vgi_python-0.14.0}/tests/test_generated_cpp_protocol_version.py +0 -0
  214. {vgi_python-0.13.0 → vgi_python-0.14.0}/tests/test_generated_cpp_request_builders.py +0 -0
  215. {vgi_python-0.13.0 → vgi_python-0.14.0}/tests/test_generated_cpp_schemas.py +0 -0
  216. {vgi_python-0.13.0 → vgi_python-0.14.0}/tests/test_generated_cpp_secret.py +0 -0
  217. {vgi_python-0.13.0 → vgi_python-0.14.0}/tests/test_generated_go_schemas.py +0 -0
  218. {vgi_python-0.13.0 → vgi_python-0.14.0}/tests/test_generated_protocol_version.py +0 -0
  219. {vgi_python-0.13.0 → vgi_python-0.14.0}/tests/test_generated_schemas_cross_lang.py +0 -0
  220. {vgi_python-0.13.0 → vgi_python-0.14.0}/tests/test_generated_ts_client.py +0 -0
  221. {vgi_python-0.13.0 → vgi_python-0.14.0}/tests/test_generated_ts_schemas.py +0 -0
  222. {vgi_python-0.13.0 → vgi_python-0.14.0}/tests/test_http_demo_storage.py +0 -0
  223. {vgi_python-0.13.0 → vgi_python-0.14.0}/tests/test_http_s3_offload_input.py +0 -0
  224. {vgi_python-0.13.0 → vgi_python-0.14.0}/tests/test_http_s3_offload_output.py +0 -0
  225. {vgi_python-0.13.0 → vgi_python-0.14.0}/tests/test_landing_conformance.py +0 -0
  226. {vgi_python-0.13.0 → vgi_python-0.14.0}/tests/test_metadata.py +0 -0
  227. {vgi_python-0.13.0 → vgi_python-0.14.0}/tests/test_mypy_consolidated.py +0 -0
  228. {vgi_python-0.13.0 → vgi_python-0.14.0}/tests/test_nest_tensor.py +0 -0
  229. {vgi_python-0.13.0 → vgi_python-0.14.0}/tests/test_otel.py +0 -0
  230. {vgi_python-0.13.0 → vgi_python-0.14.0}/tests/test_projection_enforcement.py +0 -0
  231. {vgi_python-0.13.0 → vgi_python-0.14.0}/tests/test_projection_repro.py +0 -0
  232. {vgi_python-0.13.0 → vgi_python-0.14.0}/tests/test_protocol_classes.py +0 -0
  233. {vgi_python-0.13.0 → vgi_python-0.14.0}/tests/test_resolved_secrets.py +0 -0
  234. {vgi_python-0.13.0 → vgi_python-0.14.0}/tests/test_schema_utils.py +0 -0
  235. {vgi_python-0.13.0 → vgi_python-0.14.0}/tests/test_serve.py +0 -0
  236. {vgi_python-0.13.0 → vgi_python-0.14.0}/tests/test_setting_secret_annotations.py +0 -0
  237. {vgi_python-0.13.0 → vgi_python-0.14.0}/tests/test_table_buffering_function.py +0 -0
  238. {vgi_python-0.13.0 → vgi_python-0.14.0}/tests/test_table_function_dynamic_to_string.py +0 -0
  239. {vgi_python-0.13.0 → vgi_python-0.14.0}/tests/test_tcp_transport.py +0 -0
  240. {vgi_python-0.13.0 → vgi_python-0.14.0}/tests/test_type_bounds.py +0 -0
  241. {vgi_python-0.13.0 → vgi_python-0.14.0}/tests/test_union_argument.py +0 -0
  242. {vgi_python-0.13.0 → vgi_python-0.14.0}/tests/test_worker.py +0 -0
  243. {vgi_python-0.13.0 → vgi_python-0.14.0}/tests/test_worker_cli.py +0 -0
  244. {vgi_python-0.13.0 → vgi_python-0.14.0}/tests/test_worker_page.py +0 -0
  245. {vgi_python-0.13.0 → vgi_python-0.14.0}/tests/transactor/__init__.py +0 -0
  246. {vgi_python-0.13.0 → vgi_python-0.14.0}/tests/transactor/test_transactor.py +0 -0
  247. {vgi_python-0.13.0 → vgi_python-0.14.0}/vgi/__init__.py +0 -0
  248. {vgi_python-0.13.0 → vgi_python-0.14.0}/vgi/_duckdb.py +0 -0
  249. {vgi_python-0.13.0 → vgi_python-0.14.0}/vgi/_storage_profile.py +0 -0
  250. {vgi_python-0.13.0 → vgi_python-0.14.0}/vgi/_test_fixtures/__init__.py +0 -0
  251. {vgi_python-0.13.0 → vgi_python-0.14.0}/vgi/_test_fixtures/accumulate/__init__.py +0 -0
  252. {vgi_python-0.13.0 → vgi_python-0.14.0}/vgi/_test_fixtures/accumulate/worker.py +0 -0
  253. {vgi_python-0.13.0 → vgi_python-0.14.0}/vgi/_test_fixtures/aggregate/__init__.py +0 -0
  254. {vgi_python-0.13.0 → vgi_python-0.14.0}/vgi/_test_fixtures/aggregate/_common.py +0 -0
  255. {vgi_python-0.13.0 → vgi_python-0.14.0}/vgi/_test_fixtures/aggregate/basic.py +0 -0
  256. {vgi_python-0.13.0 → vgi_python-0.14.0}/vgi/_test_fixtures/aggregate/dynamic.py +0 -0
  257. {vgi_python-0.13.0 → vgi_python-0.14.0}/vgi/_test_fixtures/aggregate/generic.py +0 -0
  258. {vgi_python-0.13.0 → vgi_python-0.14.0}/vgi/_test_fixtures/aggregate/listagg.py +0 -0
  259. {vgi_python-0.13.0 → vgi_python-0.14.0}/vgi/_test_fixtures/aggregate/percentile.py +0 -0
  260. {vgi_python-0.13.0 → vgi_python-0.14.0}/vgi/_test_fixtures/aggregate/secret_typed.py +0 -0
  261. {vgi_python-0.13.0 → vgi_python-0.14.0}/vgi/_test_fixtures/aggregate/streaming.py +0 -0
  262. {vgi_python-0.13.0 → vgi_python-0.14.0}/vgi/_test_fixtures/aggregate/varargs.py +0 -0
  263. {vgi_python-0.13.0 → vgi_python-0.14.0}/vgi/_test_fixtures/aggregate/window.py +0 -0
  264. {vgi_python-0.13.0 → vgi_python-0.14.0}/vgi/_test_fixtures/attach_options.py +0 -0
  265. {vgi_python-0.13.0 → vgi_python-0.14.0}/vgi/_test_fixtures/bad_enum.py +0 -0
  266. {vgi_python-0.13.0 → vgi_python-0.14.0}/vgi/_test_fixtures/bad_protocol.py +0 -0
  267. {vgi_python-0.13.0 → vgi_python-0.14.0}/vgi/_test_fixtures/cancellable.py +0 -0
  268. {vgi_python-0.13.0 → vgi_python-0.14.0}/vgi/_test_fixtures/catalog.py +0 -0
  269. {vgi_python-0.13.0 → vgi_python-0.14.0}/vgi/_test_fixtures/companion.py +0 -0
  270. {vgi_python-0.13.0 → vgi_python-0.14.0}/vgi/_test_fixtures/copy_from.py +0 -0
  271. {vgi_python-0.13.0 → vgi_python-0.14.0}/vgi/_test_fixtures/copy_to.py +0 -0
  272. {vgi_python-0.13.0 → vgi_python-0.14.0}/vgi/_test_fixtures/narrow_bind/__init__.py +0 -0
  273. {vgi_python-0.13.0 → vgi_python-0.14.0}/vgi/_test_fixtures/narrow_bind/worker.py +0 -0
  274. {vgi_python-0.13.0 → vgi_python-0.14.0}/vgi/_test_fixtures/nest_tensor.py +0 -0
  275. {vgi_python-0.13.0 → vgi_python-0.14.0}/vgi/_test_fixtures/orchard_catalog.py +0 -0
  276. {vgi_python-0.13.0 → vgi_python-0.14.0}/vgi/_test_fixtures/projection_repro/__init__.py +0 -0
  277. {vgi_python-0.13.0 → vgi_python-0.14.0}/vgi/_test_fixtures/projection_repro/worker.py +0 -0
  278. {vgi_python-0.13.0 → vgi_python-0.14.0}/vgi/_test_fixtures/scalar/__init__.py +0 -0
  279. {vgi_python-0.13.0 → vgi_python-0.14.0}/vgi/_test_fixtures/scalar/_common.py +0 -0
  280. {vgi_python-0.13.0 → vgi_python-0.14.0}/vgi/_test_fixtures/scalar/arithmetic.py +0 -0
  281. {vgi_python-0.13.0 → vgi_python-0.14.0}/vgi/_test_fixtures/scalar/binary.py +0 -0
  282. {vgi_python-0.13.0 → vgi_python-0.14.0}/vgi/_test_fixtures/scalar/formatting.py +0 -0
  283. {vgi_python-0.13.0 → vgi_python-0.14.0}/vgi/_test_fixtures/scalar/geo.py +0 -0
  284. {vgi_python-0.13.0 → vgi_python-0.14.0}/vgi/_test_fixtures/scalar/null_handling.py +0 -0
  285. {vgi_python-0.13.0 → vgi_python-0.14.0}/vgi/_test_fixtures/scalar/random_demo.py +0 -0
  286. {vgi_python-0.13.0 → vgi_python-0.14.0}/vgi/_test_fixtures/scalar/settings_secrets.py +0 -0
  287. {vgi_python-0.13.0 → vgi_python-0.14.0}/vgi/_test_fixtures/scalar/type_info.py +0 -0
  288. {vgi_python-0.13.0 → vgi_python-0.14.0}/vgi/_test_fixtures/schema_reconcile/__init__.py +0 -0
  289. {vgi_python-0.13.0 → vgi_python-0.14.0}/vgi/_test_fixtures/schema_reconcile/worker.py +0 -0
  290. {vgi_python-0.13.0 → vgi_python-0.14.0}/vgi/_test_fixtures/simple_writable.py +0 -0
  291. {vgi_python-0.13.0 → vgi_python-0.14.0}/vgi/_test_fixtures/table/_common.py +0 -0
  292. {vgi_python-0.13.0 → vgi_python-0.14.0}/vgi/_test_fixtures/table/batch_index.py +0 -0
  293. {vgi_python-0.13.0 → vgi_python-0.14.0}/vgi/_test_fixtures/table/batch_index_broken.py +0 -0
  294. {vgi_python-0.13.0 → vgi_python-0.14.0}/vgi/_test_fixtures/table/catalog_scans.py +0 -0
  295. {vgi_python-0.13.0 → vgi_python-0.14.0}/vgi/_test_fixtures/table/filters.py +0 -0
  296. {vgi_python-0.13.0 → vgi_python-0.14.0}/vgi/_test_fixtures/table/late_materialization.py +0 -0
  297. {vgi_python-0.13.0 → vgi_python-0.14.0}/vgi/_test_fixtures/table/make_series.py +0 -0
  298. {vgi_python-0.13.0 → vgi_python-0.14.0}/vgi/_test_fixtures/table/misc.py +0 -0
  299. {vgi_python-0.13.0 → vgi_python-0.14.0}/vgi/_test_fixtures/table/order_modes.py +0 -0
  300. {vgi_python-0.13.0 → vgi_python-0.14.0}/vgi/_test_fixtures/table/pairs.py +0 -0
  301. {vgi_python-0.13.0 → vgi_python-0.14.0}/vgi/_test_fixtures/table/partition_columns.py +0 -0
  302. {vgi_python-0.13.0 → vgi_python-0.14.0}/vgi/_test_fixtures/table/partition_columns_broken.py +0 -0
  303. {vgi_python-0.13.0 → vgi_python-0.14.0}/vgi/_test_fixtures/table/profiling_example.py +0 -0
  304. {vgi_python-0.13.0 → vgi_python-0.14.0}/vgi/_test_fixtures/table/required_filters.py +0 -0
  305. {vgi_python-0.13.0 → vgi_python-0.14.0}/vgi/_test_fixtures/table/sequence.py +0 -0
  306. {vgi_python-0.13.0 → vgi_python-0.14.0}/vgi/_test_fixtures/table/settings.py +0 -0
  307. {vgi_python-0.13.0 → vgi_python-0.14.0}/vgi/_test_fixtures/table/transaction_storage.py +0 -0
  308. {vgi_python-0.13.0 → vgi_python-0.14.0}/vgi/_test_fixtures/table/tt_pushdown.py +0 -0
  309. {vgi_python-0.13.0 → vgi_python-0.14.0}/vgi/_test_fixtures/table/typed_probe.py +0 -0
  310. {vgi_python-0.13.0 → vgi_python-0.14.0}/vgi/_test_fixtures/table/versioned.py +0 -0
  311. {vgi_python-0.13.0 → vgi_python-0.14.0}/vgi/_test_fixtures/table_in_out.py +0 -0
  312. {vgi_python-0.13.0 → vgi_python-0.14.0}/vgi/_test_fixtures/versioned.py +0 -0
  313. {vgi_python-0.13.0 → vgi_python-0.14.0}/vgi/_test_fixtures/versioned_tables.py +0 -0
  314. {vgi_python-0.13.0 → vgi_python-0.14.0}/vgi/_test_fixtures/writable/__init__.py +0 -0
  315. {vgi_python-0.13.0 → vgi_python-0.14.0}/vgi/_test_fixtures/writable/generic.py +0 -0
  316. {vgi_python-0.13.0 → vgi_python-0.14.0}/vgi/_test_fixtures/writable/table.py +0 -0
  317. {vgi_python-0.13.0 → vgi_python-0.14.0}/vgi/_test_fixtures/writable/worker.py +0 -0
  318. {vgi_python-0.13.0 → vgi_python-0.14.0}/vgi/aggregate_function.py +0 -0
  319. {vgi_python-0.13.0 → vgi_python-0.14.0}/vgi/argument_spec.py +0 -0
  320. {vgi_python-0.13.0 → vgi_python-0.14.0}/vgi/arguments.py +0 -0
  321. {vgi_python-0.13.0 → vgi_python-0.14.0}/vgi/auth.py +0 -0
  322. {vgi_python-0.13.0 → vgi_python-0.14.0}/vgi/catalog/__init__.py +0 -0
  323. {vgi_python-0.13.0 → vgi_python-0.14.0}/vgi/catalog/_descriptor_spec.py +0 -0
  324. {vgi_python-0.13.0 → vgi_python-0.14.0}/vgi/catalog/attach_option.py +0 -0
  325. {vgi_python-0.13.0 → vgi_python-0.14.0}/vgi/catalog/catalog_interface.py +0 -0
  326. {vgi_python-0.13.0 → vgi_python-0.14.0}/vgi/catalog/descriptors.py +0 -0
  327. {vgi_python-0.13.0 → vgi_python-0.14.0}/vgi/catalog/duckdb_statistics.py +0 -0
  328. {vgi_python-0.13.0 → vgi_python-0.14.0}/vgi/catalog/secret_type.py +0 -0
  329. {vgi_python-0.13.0 → vgi_python-0.14.0}/vgi/catalog/setting.py +0 -0
  330. {vgi_python-0.13.0 → vgi_python-0.14.0}/vgi/catalog/storage.py +0 -0
  331. {vgi_python-0.13.0 → vgi_python-0.14.0}/vgi/client/__init__.py +0 -0
  332. {vgi_python-0.13.0 → vgi_python-0.14.0}/vgi/client/catalog_mixin.py +0 -0
  333. {vgi_python-0.13.0 → vgi_python-0.14.0}/vgi/client/cli.py +0 -0
  334. {vgi_python-0.13.0 → vgi_python-0.14.0}/vgi/client/cli_catalog.py +0 -0
  335. {vgi_python-0.13.0 → vgi_python-0.14.0}/vgi/client/cli_schema.py +0 -0
  336. {vgi_python-0.13.0 → vgi_python-0.14.0}/vgi/client/cli_table.py +0 -0
  337. {vgi_python-0.13.0 → vgi_python-0.14.0}/vgi/client/cli_transaction.py +0 -0
  338. {vgi_python-0.13.0 → vgi_python-0.14.0}/vgi/client/cli_utils.py +0 -0
  339. {vgi_python-0.13.0 → vgi_python-0.14.0}/vgi/client/cli_view.py +0 -0
  340. {vgi_python-0.13.0 → vgi_python-0.14.0}/vgi/client/client.py +0 -0
  341. {vgi_python-0.13.0 → vgi_python-0.14.0}/vgi/codegen/__init__.py +0 -0
  342. {vgi_python-0.13.0 → vgi_python-0.14.0}/vgi/codegen/_common.py +0 -0
  343. {vgi_python-0.13.0 → vgi_python-0.14.0}/vgi/codegen/cpp_constants.py +0 -0
  344. {vgi_python-0.13.0 → vgi_python-0.14.0}/vgi/codegen/cpp_protocol_version.py +0 -0
  345. {vgi_python-0.13.0 → vgi_python-0.14.0}/vgi/codegen/cpp_request_builders.py +0 -0
  346. {vgi_python-0.13.0 → vgi_python-0.14.0}/vgi/codegen/cpp_schemas.py +0 -0
  347. {vgi_python-0.13.0 → vgi_python-0.14.0}/vgi/codegen/cpp_secret_protocol_version.py +0 -0
  348. {vgi_python-0.13.0 → vgi_python-0.14.0}/vgi/codegen/cpp_secret_request_builders.py +0 -0
  349. {vgi_python-0.13.0 → vgi_python-0.14.0}/vgi/codegen/cpp_secret_schemas.py +0 -0
  350. {vgi_python-0.13.0 → vgi_python-0.14.0}/vgi/codegen/go_schemas.py +0 -0
  351. {vgi_python-0.13.0 → vgi_python-0.14.0}/vgi/codegen/protocol_version.py +0 -0
  352. {vgi_python-0.13.0 → vgi_python-0.14.0}/vgi/codegen/ts_client.py +0 -0
  353. {vgi_python-0.13.0 → vgi_python-0.14.0}/vgi/codegen/ts_schemas.py +0 -0
  354. {vgi_python-0.13.0 → vgi_python-0.14.0}/vgi/copy_from_function.py +0 -0
  355. {vgi_python-0.13.0 → vgi_python-0.14.0}/vgi/copy_to_function.py +0 -0
  356. {vgi_python-0.13.0 → vgi_python-0.14.0}/vgi/exceptions.py +0 -0
  357. {vgi_python-0.13.0 → vgi_python-0.14.0}/vgi/function.py +0 -0
  358. {vgi_python-0.13.0 → vgi_python-0.14.0}/vgi/function_storage.py +0 -0
  359. {vgi_python-0.13.0 → vgi_python-0.14.0}/vgi/function_storage_azure_sql.py +0 -0
  360. {vgi_python-0.13.0 → vgi_python-0.14.0}/vgi/function_storage_cf_do.py +0 -0
  361. {vgi_python-0.13.0 → vgi_python-0.14.0}/vgi/http/__init__.py +0 -0
  362. {vgi_python-0.13.0 → vgi_python-0.14.0}/vgi/http/demo_storage.py +0 -0
  363. {vgi_python-0.13.0 → vgi_python-0.14.0}/vgi/http/describe_json.py +0 -0
  364. {vgi_python-0.13.0 → vgi_python-0.14.0}/vgi/http/landing.html +0 -0
  365. {vgi_python-0.13.0 → vgi_python-0.14.0}/vgi/http/landing_page.py +0 -0
  366. {vgi_python-0.13.0 → vgi_python-0.14.0}/vgi/http/worker_page.py +0 -0
  367. {vgi_python-0.13.0 → vgi_python-0.14.0}/vgi/invocation.py +0 -0
  368. {vgi_python-0.13.0 → vgi_python-0.14.0}/vgi/logging_config.py +0 -0
  369. {vgi_python-0.13.0 → vgi_python-0.14.0}/vgi/meta_worker.py +0 -0
  370. {vgi_python-0.13.0 → vgi_python-0.14.0}/vgi/metadata.py +0 -0
  371. {vgi_python-0.13.0 → vgi_python-0.14.0}/vgi/otel.py +0 -0
  372. {vgi_python-0.13.0 → vgi_python-0.14.0}/vgi/protocol_version.txt +0 -0
  373. {vgi_python-0.13.0 → vgi_python-0.14.0}/vgi/py.typed +0 -0
  374. {vgi_python-0.13.0 → vgi_python-0.14.0}/vgi/scalar_function.py +0 -0
  375. {vgi_python-0.13.0 → vgi_python-0.14.0}/vgi/schema_utils.py +0 -0
  376. {vgi_python-0.13.0 → vgi_python-0.14.0}/vgi/secret_protocol.py +0 -0
  377. {vgi_python-0.13.0 → vgi_python-0.14.0}/vgi/secret_service.py +0 -0
  378. {vgi_python-0.13.0 → vgi_python-0.14.0}/vgi/serve.py +0 -0
  379. {vgi_python-0.13.0 → vgi_python-0.14.0}/vgi/table_buffering_function.py +0 -0
  380. {vgi_python-0.13.0 → vgi_python-0.14.0}/vgi/table_filter_pushdown.py +0 -0
  381. {vgi_python-0.13.0 → vgi_python-0.14.0}/vgi/table_in_out_function.py +0 -0
  382. {vgi_python-0.13.0 → vgi_python-0.14.0}/vgi/transactor/__init__.py +0 -0
  383. {vgi_python-0.13.0 → vgi_python-0.14.0}/vgi/transactor/_duckdb_compat.py +0 -0
  384. {vgi_python-0.13.0 → vgi_python-0.14.0}/vgi/transactor/client.py +0 -0
  385. {vgi_python-0.13.0 → vgi_python-0.14.0}/vgi/transactor/protocol.py +0 -0
  386. {vgi_python-0.13.0 → vgi_python-0.14.0}/vgi/transactor/server.py +0 -0
  387. {vgi_python-0.13.0 → vgi_python-0.14.0}/vgi/worker.py +0 -0
  388. {vgi_python-0.13.0 → vgi_python-0.14.0}/wrangler.jsonc +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: vgi-python
3
- Version: 0.13.0
3
+ Version: 0.14.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.23.0
165
+ Requires-Dist: vgi-rpc>=0.24.0
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'
@@ -73,6 +73,11 @@ if [ "$TRANSPORT" = "http" ]; then
73
73
  # * buffer_input/sizes.test — input buffering semantics differ over HTTP
74
74
  # (same known limitation). (scale.test_slow is a .test_slow file and is
75
75
  # never staged below, which only finds *.test.)
76
+ # cache/revalidate.test now runs on http too: HTTP conditional revalidation is
77
+ # implemented (C++ /init-request validators + vgi-rpc >=0.24.0 surfacing them to
78
+ # the producer's first process()). It needs a community vgi extension carrying
79
+ # that C++ change; if the http lane fails on it, the community extension predates
80
+ # the change and needs republishing.
76
81
  EXTRA_SKIP=(
77
82
  -not -name 'projection_pushdown_repro.test'
78
83
  -not -name 'dynamic_filter.test'
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "vgi-python"
3
- version = "0.13.0"
3
+ version = "0.14.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.23.0",
43
+ "vgi-rpc>=0.24.0",
44
44
  "httpx>=0.24",
45
45
  ]
46
46
 
@@ -33,6 +33,15 @@ _EXEMPTIONS: dict[str, str] = {
33
33
  "lifecycle/schema/table surfaces are mirrored by test_attach.py, "
34
34
  "test_table.py, test_view.py, and test_macro.py."
35
35
  ),
36
+ "cache": (
37
+ "The table-function result cache lives entirely in the C++ extension "
38
+ "(key/eligibility, in-memory + content-addressed disk tiers, serve/"
39
+ "capture, conditional revalidation). The Python worker's only role is "
40
+ "advertising vgi.cache.* metadata + answering 304 not_modified, which is "
41
+ "unit-tested by tests/test_cache_control.py (rendering, the emit merge "
42
+ "path, ProcessParams.if_none_match threading, and the revalidatable "
43
+ "fixture's 304 behavior)."
44
+ ),
36
45
  "filter_pushdown": (
37
46
  "Per-type filter-pushdown coverage is mirrored by tests/test_filter_pushdown.py "
38
47
  "and tests/test_filter_pushdown_extension.py, which drive the same predicate "
@@ -3,9 +3,9 @@
3
3
  {
4
4
  "attach_options": [],
5
5
  "counts": {
6
- "functions": 165,
6
+ "functions": 183,
7
7
  "schemas": 2,
8
- "tables": 44,
8
+ "tables": 58,
9
9
  "views": 3
10
10
  },
11
11
  "data_version_spec": null,
@@ -18,6 +18,76 @@
18
18
  "functions": [],
19
19
  "name": "data",
20
20
  "tables": [
21
+ {
22
+ "cols": 1,
23
+ "comment": "Large multi-batch cacheable result (advertises vgi.cache.ttl)",
24
+ "name": "cache_big"
25
+ },
26
+ {
27
+ "cols": 1,
28
+ "comment": "Cacheable first batch then an unresolvable external-location pointer",
29
+ "name": "cache_external_fail"
30
+ },
31
+ {
32
+ "cols": 1,
33
+ "comment": "Cacheable sequence with static filter pushdown (filter_bytes keying)",
34
+ "name": "cache_filtered"
35
+ },
36
+ {
37
+ "cols": 3,
38
+ "comment": "Multi-column cacheable result (projection-coverage reuse)",
39
+ "name": "cache_multicol"
40
+ },
41
+ {
42
+ "cols": 1,
43
+ "comment": "Advertises vgi.cache.no_store — must never be cached",
44
+ "name": "cache_no_store"
45
+ },
46
+ {
47
+ "cols": 1,
48
+ "comment": "One-row cacheable result whose value changes per real invocation",
49
+ "name": "cache_nonce"
50
+ },
51
+ {
52
+ "cols": 1,
53
+ "comment": "Multi-worker order-sensitive cacheable result (batch_index; parallel capture, ordered serve)",
54
+ "name": "cache_ordered"
55
+ },
56
+ {
57
+ "cols": 1,
58
+ "comment": "Cacheable first batch then a mid-stream error (never-partial check)",
59
+ "name": "cache_poison"
60
+ },
61
+ {
62
+ "cols": 3,
63
+ "comment": "Projection-pushdown cacheable result (SELECT a vs b are distinct keys)",
64
+ "name": "cache_projection"
65
+ },
66
+ {
67
+ "cols": 1,
68
+ "comment": "Always-revalidate result (304 not_modified reuses stored bytes)",
69
+ "name": "cache_revalidatable"
70
+ },
71
+ {
72
+ "cols": 2,
73
+ "comment": "Advertises vgi.cache.scope=transaction",
74
+ "name": "cache_scoped_txn"
75
+ },
76
+ {
77
+ "cols": 1,
78
+ "comment": "Version-specific cacheable rows (AT-keyed cache isolation)",
79
+ "name": "cache_versioned"
80
+ },
81
+ {
82
+ "cols": 1,
83
+ "comment": "Cacheable result echoing the caller's auth principal (identity-scoped)",
84
+ "name": "cache_whoami"
85
+ },
86
+ {
87
+ "cols": 1,
88
+ "comment": "Cacheable 10-row result advertising vgi.cache.ttl",
89
+ "name": "cacheable_numbers"
90
+ },
21
91
  {
22
92
  "cols": 1,
23
93
  "comment": "Function-backed table with inlined cardinality (10000 rows)",
@@ -1256,6 +1326,226 @@
1256
1326
  "name": "broken_partition_values_no_annotation",
1257
1327
  "type": "table"
1258
1328
  },
1329
+ {
1330
+ "args": [
1331
+ {
1332
+ "desc": "Number of rows to generate",
1333
+ "name": "rows",
1334
+ "type": "int64"
1335
+ }
1336
+ ],
1337
+ "doc": "Emits `rows` int64 rows (positional arg); cacheable — scaling bench fixture",
1338
+ "name": "cache_bench",
1339
+ "type": "table"
1340
+ },
1341
+ {
1342
+ "args": [
1343
+ {
1344
+ "default": "5000",
1345
+ "desc": "Number of rows to generate",
1346
+ "name": "rows",
1347
+ "named": true,
1348
+ "type": "int64"
1349
+ }
1350
+ ],
1351
+ "doc": "Emits many small batches totaling `rows` rows; cacheable",
1352
+ "name": "cache_big",
1353
+ "type": "table"
1354
+ },
1355
+ {
1356
+ "args": [],
1357
+ "doc": "Cacheable first batch then an unresolvable external-location pointer",
1358
+ "name": "cache_external_fail",
1359
+ "type": "table"
1360
+ },
1361
+ {
1362
+ "args": [
1363
+ {
1364
+ "default": "100",
1365
+ "desc": "Total number of rows to generate",
1366
+ "name": "rows",
1367
+ "named": true,
1368
+ "type": "int64"
1369
+ }
1370
+ ],
1371
+ "doc": "Cacheable sequence with static filter pushdown (filter_bytes keying)",
1372
+ "name": "cache_filtered",
1373
+ "type": "table"
1374
+ },
1375
+ {
1376
+ "args": [
1377
+ {
1378
+ "desc": "Total number of rows to generate",
1379
+ "name": "rows",
1380
+ "type": "int64"
1381
+ },
1382
+ {
1383
+ "default": "20000",
1384
+ "desc": "Rows per partition",
1385
+ "name": "chunk_size",
1386
+ "named": true,
1387
+ "type": "int64"
1388
+ }
1389
+ ],
1390
+ "doc": "Parallel batch_index-tagged cacheable sequence; cache serve reassembles order",
1391
+ "name": "cache_interleaved",
1392
+ "type": "table"
1393
+ },
1394
+ {
1395
+ "args": [
1396
+ {
1397
+ "default": "10",
1398
+ "desc": "Number of rows to generate",
1399
+ "name": "n",
1400
+ "named": true,
1401
+ "type": "int64"
1402
+ }
1403
+ ],
1404
+ "doc": "Emits n rows but advertises no_store (never cached)",
1405
+ "name": "cache_no_store",
1406
+ "type": "table"
1407
+ },
1408
+ {
1409
+ "args": [],
1410
+ "doc": "Emits one row with a per-invocation nonce; cacheable",
1411
+ "name": "cache_nonce",
1412
+ "type": "table"
1413
+ },
1414
+ {
1415
+ "args": [
1416
+ {
1417
+ "default": "1000",
1418
+ "desc": "Rows per partition",
1419
+ "name": "chunk_size",
1420
+ "named": true,
1421
+ "type": "int64"
1422
+ },
1423
+ {
1424
+ "default": "200000",
1425
+ "desc": "Total number of rows to generate",
1426
+ "name": "rows",
1427
+ "named": true,
1428
+ "type": "int64"
1429
+ }
1430
+ ],
1431
+ "doc": "Multi-worker order-sensitive cacheable sequence (batch_index); order-preservation cache fixture",
1432
+ "name": "cache_ordered",
1433
+ "type": "table"
1434
+ },
1435
+ {
1436
+ "args": [
1437
+ {
1438
+ "desc": "Total number of rows to generate",
1439
+ "name": "rows",
1440
+ "type": "int64"
1441
+ },
1442
+ {
1443
+ "default": "24000",
1444
+ "desc": "Rows per output batch",
1445
+ "name": "batch_size",
1446
+ "named": true,
1447
+ "type": "int64"
1448
+ }
1449
+ ],
1450
+ "doc": "Multi-worker cacheable sequence (one substream per worker); parallel-capture fixture",
1451
+ "name": "cache_parallel",
1452
+ "type": "table"
1453
+ },
1454
+ {
1455
+ "args": [
1456
+ {
1457
+ "desc": "Rows per country partition",
1458
+ "name": "rows_per_country",
1459
+ "type": "int64"
1460
+ }
1461
+ ],
1462
+ "doc": "Cacheable single-value-partitioned result (partition_values through the spill blob)",
1463
+ "name": "cache_partitioned",
1464
+ "type": "table"
1465
+ },
1466
+ {
1467
+ "args": [],
1468
+ "doc": "Cacheable first batch then a mid-stream error (never-partial check)",
1469
+ "name": "cache_poison",
1470
+ "type": "table"
1471
+ },
1472
+ {
1473
+ "args": [],
1474
+ "doc": "3-column projection-pushdown generator; cacheable",
1475
+ "name": "cache_projection",
1476
+ "type": "table"
1477
+ },
1478
+ {
1479
+ "args": [],
1480
+ "doc": "Emits one nonce row; always-revalidate (304 not_modified)",
1481
+ "name": "cache_revalidatable",
1482
+ "type": "table"
1483
+ },
1484
+ {
1485
+ "args": [
1486
+ {
1487
+ "default": "10",
1488
+ "desc": "Number of rows to generate",
1489
+ "name": "n",
1490
+ "named": true,
1491
+ "type": "int64"
1492
+ }
1493
+ ],
1494
+ "doc": "Emits n rows and advertises scope=transaction",
1495
+ "name": "cache_scoped_txn",
1496
+ "type": "table"
1497
+ },
1498
+ {
1499
+ "args": [
1500
+ {
1501
+ "desc": "Total number of rows to generate",
1502
+ "name": "rows",
1503
+ "type": "int64"
1504
+ }
1505
+ ],
1506
+ "doc": "Nested/wide/NULL cacheable result (STRUCT/LIST/DECIMAL/TIMESTAMP + NULLs)",
1507
+ "name": "cache_types",
1508
+ "type": "table"
1509
+ },
1510
+ {
1511
+ "args": [
1512
+ {
1513
+ "desc": "Data version, resolved from the AT clause by the catalog",
1514
+ "name": "version",
1515
+ "type": "int64"
1516
+ }
1517
+ ],
1518
+ "doc": "Version-specific rows; cacheable (AT-keyed)",
1519
+ "name": "cache_versioned_scan",
1520
+ "type": "table"
1521
+ },
1522
+ {
1523
+ "args": [],
1524
+ "doc": "Emits the caller's auth principal; cacheable (identity-scoped)",
1525
+ "name": "cache_whoami",
1526
+ "type": "table"
1527
+ },
1528
+ {
1529
+ "args": [
1530
+ {
1531
+ "default": "10",
1532
+ "desc": "Number of rows to generate",
1533
+ "name": "n",
1534
+ "named": true,
1535
+ "type": "int64"
1536
+ },
1537
+ {
1538
+ "default": "300",
1539
+ "desc": "Cache TTL in seconds",
1540
+ "name": "ttl",
1541
+ "named": true,
1542
+ "type": "int64"
1543
+ }
1544
+ ],
1545
+ "doc": "Emits n rows [0..n) and advertises a cache TTL",
1546
+ "name": "cacheable_numbers",
1547
+ "type": "table"
1548
+ },
1259
1549
  {
1260
1550
  "args": [],
1261
1551
  "doc": "Scan colors table (ENUM column)",
@@ -0,0 +1,222 @@
1
+ # Copyright 2025, 2026 Query Farm LLC - https://query.farm
2
+
3
+ """Unit tests for CacheControl rendering and the _merge_cache_control emit path."""
4
+
5
+ from __future__ import annotations
6
+
7
+ import pyarrow as pa
8
+ import pytest
9
+
10
+ from vgi.cache_control import (
11
+ CACHE_ETAG_KEY,
12
+ CACHE_EXPIRES_KEY,
13
+ CACHE_LAST_MODIFIED_KEY,
14
+ CACHE_NO_STORE_KEY,
15
+ CACHE_REVALIDATABLE_KEY,
16
+ CACHE_SCOPE_CATALOG,
17
+ CACHE_SCOPE_KEY,
18
+ CACHE_SCOPE_TRANSACTION,
19
+ CACHE_STALE_IF_ERROR_KEY,
20
+ CACHE_STALE_WHILE_REVALIDATE_KEY,
21
+ CACHE_TTL_KEY,
22
+ CacheControl,
23
+ )
24
+ from vgi.protocol import _TrackingOutputCollector
25
+
26
+
27
+ class _RecordingCollector:
28
+ """Minimal inner OutputCollector that records (batch, metadata) per emit."""
29
+
30
+ def __init__(self) -> None:
31
+ """Initialize the recorded-calls list."""
32
+ self.calls: list[tuple[pa.RecordBatch, dict[str, str] | None]] = []
33
+
34
+ def emit(self, batch: pa.RecordBatch, metadata: dict[str, str] | None = None) -> None:
35
+ """Record the emitted batch and its metadata."""
36
+ self.calls.append((batch, metadata))
37
+
38
+
39
+ def _batch(value: int = 0) -> pa.RecordBatch:
40
+ """Build a one-row single-column batch for emit testing."""
41
+ return pa.RecordBatch.from_pydict({"n": [value]})
42
+
43
+
44
+ class TestCacheControlRendering:
45
+ """CacheControl.to_metadata() renders the vgi.cache.* key/value dict."""
46
+
47
+ def test_ttl_only(self) -> None:
48
+ """ttl-only advertisement renders ttl + the always-present scope."""
49
+ md = CacheControl(ttl=300).to_metadata()
50
+ assert md[CACHE_TTL_KEY] == "300"
51
+ # scope is always emitted so the client never infers the default.
52
+ assert md[CACHE_SCOPE_KEY] == CACHE_SCOPE_CATALOG
53
+ # Nothing else set.
54
+ assert set(md) == {CACHE_TTL_KEY, CACHE_SCOPE_KEY}
55
+
56
+ def test_all_fields(self) -> None:
57
+ """Every field renders to its documented vgi.cache.* key."""
58
+ md = CacheControl(
59
+ ttl=60,
60
+ expires="2026-01-01T00:00:00Z",
61
+ scope=CACHE_SCOPE_TRANSACTION,
62
+ etag='"abc"',
63
+ last_modified="2025-12-31T00:00:00Z",
64
+ revalidatable=True,
65
+ stale_while_revalidate=10,
66
+ stale_if_error=20,
67
+ ).to_metadata()
68
+ assert md == {
69
+ CACHE_TTL_KEY: "60",
70
+ CACHE_EXPIRES_KEY: "2026-01-01T00:00:00Z",
71
+ CACHE_SCOPE_KEY: CACHE_SCOPE_TRANSACTION,
72
+ CACHE_ETAG_KEY: '"abc"',
73
+ CACHE_LAST_MODIFIED_KEY: "2025-12-31T00:00:00Z",
74
+ CACHE_REVALIDATABLE_KEY: "1",
75
+ CACHE_STALE_WHILE_REVALIDATE_KEY: "10",
76
+ CACHE_STALE_IF_ERROR_KEY: "20",
77
+ }
78
+
79
+ def test_no_store_renders_one_and_omits_when_false(self) -> None:
80
+ """no_store renders "1" when true and is omitted when false."""
81
+ assert CacheControl(no_store=True).to_metadata()[CACHE_NO_STORE_KEY] == "1"
82
+ assert CACHE_NO_STORE_KEY not in CacheControl(ttl=1).to_metadata()
83
+
84
+ def test_booleans_omitted_when_false(self) -> None:
85
+ """Boolean fields left false do not emit any key."""
86
+ md = CacheControl(ttl=1).to_metadata()
87
+ assert CACHE_REVALIDATABLE_KEY not in md
88
+ assert CACHE_NO_STORE_KEY not in md
89
+
90
+ def test_invalid_scope_rejected(self) -> None:
91
+ """An unknown scope value is rejected at construction."""
92
+ with pytest.raises(ValueError, match="scope"):
93
+ CacheControl(scope="bogus")
94
+
95
+ def test_negative_duration_rejected(self) -> None:
96
+ """A negative duration field is rejected at construction."""
97
+ with pytest.raises(ValueError, match="ttl"):
98
+ CacheControl(ttl=-1)
99
+
100
+ def test_not_modified_renders_one_and_omits_when_false(self) -> None:
101
+ """not_modified renders "1" when true (a 304) and is omitted when false."""
102
+ from vgi.cache_control import CACHE_NOT_MODIFIED_KEY
103
+
104
+ md = CacheControl(not_modified=True, ttl=0, etag='"v1"', revalidatable=True).to_metadata()
105
+ assert md[CACHE_NOT_MODIFIED_KEY] == "1"
106
+ assert CACHE_NOT_MODIFIED_KEY not in CacheControl(ttl=1).to_metadata()
107
+
108
+
109
+ class TestMergeCacheControlEmitPath:
110
+ """_TrackingOutputCollector folds CacheControl onto the FIRST emitted batch."""
111
+
112
+ def test_first_batch_carries_keys(self) -> None:
113
+ """The first emitted batch carries the rendered vgi.cache.* keys."""
114
+ inner = _RecordingCollector()
115
+ out = _TrackingOutputCollector(inner) # type: ignore[arg-type]
116
+ out.emit(_batch(0), cache_control=CacheControl(ttl=300))
117
+
118
+ (_, metadata) = inner.calls[0]
119
+ assert metadata is not None
120
+ assert metadata[CACHE_TTL_KEY] == "300"
121
+ assert metadata[CACHE_SCOPE_KEY] == CACHE_SCOPE_CATALOG
122
+
123
+ def test_subsequent_batches_get_no_cache_keys(self) -> None:
124
+ """Only the first batch carries cache keys; later batches carry none."""
125
+ inner = _RecordingCollector()
126
+ out = _TrackingOutputCollector(inner) # type: ignore[arg-type]
127
+ out.emit(_batch(0), cache_control=CacheControl(ttl=300))
128
+ out.emit(_batch(1))
129
+ out.emit(_batch(2))
130
+
131
+ # First batch carries keys; later batches carry no metadata at all
132
+ # (so no duplicated/conflicting vgi.cache.* keys downstream).
133
+ assert inner.calls[0][1] is not None
134
+ assert inner.calls[0][1][CACHE_TTL_KEY] == "300"
135
+ assert inner.calls[1][1] is None
136
+ assert inner.calls[2][1] is None
137
+
138
+ def test_cache_control_on_later_batch_raises(self) -> None:
139
+ """Passing cache_control after the first batch is a programming error."""
140
+ inner = _RecordingCollector()
141
+ out = _TrackingOutputCollector(inner) # type: ignore[arg-type]
142
+ out.emit(_batch(0))
143
+ with pytest.raises(RuntimeError, match="first emitted batch"):
144
+ out.emit(_batch(1), cache_control=CacheControl(ttl=300))
145
+
146
+ def test_no_cache_control_leaves_metadata_untouched(self) -> None:
147
+ """Without cache_control the emitted metadata stays None."""
148
+ inner = _RecordingCollector()
149
+ out = _TrackingOutputCollector(inner) # type: ignore[arg-type]
150
+ out.emit(_batch(0))
151
+ assert inner.calls[0][1] is None
152
+
153
+ def test_explicit_metadata_preserved_alongside_cache_control(self) -> None:
154
+ """Explicit metadata keys survive alongside the cache_control keys."""
155
+ inner = _RecordingCollector()
156
+ out = _TrackingOutputCollector(inner) # type: ignore[arg-type]
157
+ out.emit(_batch(0), metadata={"custom.key": "v"}, cache_control=CacheControl(ttl=5))
158
+
159
+ (_, metadata) = inner.calls[0]
160
+ assert metadata is not None
161
+ assert metadata["custom.key"] == "v"
162
+ assert metadata[CACHE_TTL_KEY] == "5"
163
+
164
+ def test_no_store_flows_through_emit(self) -> None:
165
+ """A no_store advertisement reaches the emitted batch metadata."""
166
+ inner = _RecordingCollector()
167
+ out = _TrackingOutputCollector(inner) # type: ignore[arg-type]
168
+ out.emit(_batch(0), cache_control=CacheControl(no_store=True))
169
+
170
+ (_, metadata) = inner.calls[0]
171
+ assert metadata is not None
172
+ assert metadata[CACHE_NO_STORE_KEY] == "1"
173
+
174
+
175
+ class TestRevalidatableFixture:
176
+ """CacheRevalidatableFunction answers 304 when if_none_match matches (M6)."""
177
+
178
+ @staticmethod
179
+ def _run(if_none_match: str | None):
180
+ """Drive the fixture's process() with a duck-typed params stub."""
181
+ import types
182
+
183
+ from vgi._test_fixtures.table.cache import (
184
+ CacheRevalidatableFunction,
185
+ _CacheNonceState,
186
+ )
187
+ from vgi.cache_control import CACHE_NOT_MODIFIED_KEY
188
+
189
+ inner = _RecordingCollector()
190
+ # The fixture emits via VgiOutputCollector.emit(..., cache_control=...);
191
+ # _TrackingOutputCollector folds cache_control into the recorded metadata.
192
+ out = _TrackingOutputCollector(inner) # type: ignore[arg-type]
193
+ params = types.SimpleNamespace(
194
+ if_none_match=if_none_match,
195
+ output_schema=CacheRevalidatableFunction.FIXED_SCHEMA,
196
+ )
197
+ state = _CacheNonceState(nonce=42)
198
+ CacheRevalidatableFunction.process(params, state, out) # type: ignore[arg-type]
199
+ return inner, state, CACHE_NOT_MODIFIED_KEY
200
+
201
+ def test_matching_validator_yields_not_modified(self) -> None:
202
+ """A matching if_none_match yields a 0-row not_modified batch (no data)."""
203
+ from vgi._test_fixtures.table.cache import CacheRevalidatableFunction
204
+
205
+ collector, _state, not_modified_key = self._run(if_none_match=CacheRevalidatableFunction.ETAG)
206
+
207
+ assert len(collector.calls) == 1
208
+ batch, metadata = collector.calls[0]
209
+ assert batch.num_rows == 0 # 304: no data re-streamed
210
+ assert metadata is not None
211
+ assert metadata[not_modified_key] == "1"
212
+
213
+ def test_no_validator_yields_fresh_data(self) -> None:
214
+ """No conditional request → the fixture emits its nonce row (fresh)."""
215
+ collector, state, not_modified_key = self._run(if_none_match=None)
216
+
217
+ assert len(collector.calls) == 1
218
+ batch, metadata = collector.calls[0]
219
+ assert batch.num_rows == 1
220
+ assert batch.column(0)[0].as_py() == state.nonce
221
+ assert metadata is not None
222
+ assert not_modified_key not in metadata
@@ -2228,7 +2228,7 @@ requires-dist = [
2228
2228
 
2229
2229
  [[package]]
2230
2230
  name = "vgi-python"
2231
- version = "0.13.0"
2231
+ version = "0.14.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.23.0" },
2341
+ { name = "vgi-rpc", specifier = ">=0.24.0" },
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.23.0"
2370
+ version = "0.24.0"
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/ac/82/e1d8391c64ebc0f7f928f49837608c1ff50b5398cfd674aed3552d3f51d5/vgi_rpc-0.23.0.tar.gz", hash = "sha256:5874c73ddb36d2305432696a97339735ef150b095bbddabe417d7406ff026a6b", size = 860239, upload-time = "2026-07-07T22:25:32.584Z" }
2378
+ sdist = { url = "https://files.pythonhosted.org/packages/63/53/d24648965748f26008dd71495e0330f536ce69f9ddffac431df25bbd3f78/vgi_rpc-0.24.0.tar.gz", hash = "sha256:dac1fd161c04a473f6c4309e94d18f22c8b1476d140be9a789ed710cf6339956", size = 860740, upload-time = "2026-07-09T21:35:44.26Z" }
2379
2379
  wheels = [
2380
- { url = "https://files.pythonhosted.org/packages/74/34/1c50fe244b7cfc8774957064d76c9d72f866e320754dc24cfc71ce87b3f1/vgi_rpc-0.23.0-py3-none-any.whl", hash = "sha256:9095a4962172459489d4d65d6398b3ccfe17f4b868ad5fed2740099d4003d66c", size = 379578, upload-time = "2026-07-07T22:25:31.059Z" },
2380
+ { url = "https://files.pythonhosted.org/packages/13/1c/04654c95249e936bd027bb58abd0a36b3989c28b1e7aba891e9651eb0323/vgi_rpc-0.24.0-py3-none-any.whl", hash = "sha256:46caf719bc27b156cd30115c790e00c3ad67f3238ed51a7dc7dbe4dffe794391", size = 380110, upload-time = "2026-07-09T21:35:42.65Z" },
2381
2381
  ]
2382
2382
 
2383
2383
  [package.optional-dependencies]
@@ -304,6 +304,32 @@ def main() -> None:
304
304
  authenticate = _resolve_authenticate()
305
305
  oauth_metadata = _resolve_oauth_resource_metadata()
306
306
 
307
+ if authenticate is None:
308
+ # Test-only OPTIONAL bearer auth. Lets the cache identity-isolation
309
+ # test attach the same worker under different principals (alice/bob)
310
+ # while every other test on this shared server stays anonymous:
311
+ # no/blank/unknown bearer → anonymous (existing behaviour), a known
312
+ # token → its principal. Never 401s, so no anonymous test breaks.
313
+ from vgi_rpc.http import bearer_authenticate_static
314
+ from vgi_rpc.rpc import AuthContext
315
+
316
+ _test_tokens = {
317
+ "vgi-test-alice": AuthContext(principal="alice", authenticated=True, domain="bearer"),
318
+ "vgi-test-bob": AuthContext(principal="bob", authenticated=True, domain="bearer"),
319
+ }
320
+ _bearer_validate = bearer_authenticate_static(tokens=_test_tokens)
321
+
322
+ def _optional_bearer(req: Any) -> AuthContext:
323
+ header = req.get_header("Authorization") or ""
324
+ if not header.startswith("Bearer "):
325
+ return AuthContext.anonymous()
326
+ try:
327
+ return _bearer_validate(req)
328
+ except Exception:
329
+ return AuthContext.anonymous()
330
+
331
+ authenticate = _optional_bearer
332
+
307
333
  from vgi.worker import _get_vgi_version
308
334
 
309
335
  # Match vgi-fixture-worker (subprocess transport): always serve the