vgi-python 0.29.5__tar.gz → 0.30.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 (442) hide show
  1. {vgi_python-0.29.5 → vgi_python-0.30.0}/PKG-INFO +2 -2
  2. {vgi_python-0.29.5 → vgi_python-0.30.0}/pyproject.toml +2 -2
  3. {vgi_python-0.29.5 → vgi_python-0.30.0}/tests/client/test_batch_metadata_callback.py +1 -1
  4. {vgi_python-0.29.5 → vgi_python-0.30.0}/tests/client/test_scan_branches_client.py +8 -5
  5. {vgi_python-0.29.5 → vgi_python-0.30.0}/tests/client/test_time_travel_client.py +1 -1
  6. {vgi_python-0.29.5 → vgi_python-0.30.0}/tests/table_in_out/test_blended_exchange.py +42 -0
  7. vgi_python-0.30.0/tests/test_client_oauth.py +204 -0
  8. {vgi_python-0.29.5 → vgi_python-0.30.0}/uv.lock +5 -5
  9. {vgi_python-0.29.5 → vgi_python-0.30.0}/vgi/client/client.py +135 -12
  10. {vgi_python-0.29.5 → vgi_python-0.30.0}/vgi/codegen/cpp_request_builders.py +1 -1
  11. {vgi_python-0.29.5 → vgi_python-0.30.0}/vgi/worker.py +44 -15
  12. {vgi_python-0.29.5 → vgi_python-0.30.0}/.gitattributes +0 -0
  13. {vgi_python-0.29.5 → vgi_python-0.30.0}/.github/dependabot.yml +0 -0
  14. {vgi_python-0.29.5 → vgi_python-0.30.0}/.github/styles/config/vocabularies/VGI/accept.txt +0 -0
  15. {vgi_python-0.29.5 → vgi_python-0.30.0}/.github/workflows/ci.yml +0 -0
  16. {vgi_python-0.29.5 → vgi_python-0.30.0}/.github/workflows/docs.yml +0 -0
  17. {vgi_python-0.29.5 → vgi_python-0.30.0}/.github/workflows/integration.yml +0 -0
  18. {vgi_python-0.29.5 → vgi_python-0.30.0}/.github/workflows/release.yml +0 -0
  19. {vgi_python-0.29.5 → vgi_python-0.30.0}/.gitignore +0 -0
  20. {vgi_python-0.29.5 → vgi_python-0.30.0}/.python-version +0 -0
  21. {vgi_python-0.29.5 → vgi_python-0.30.0}/.vale.ini +0 -0
  22. {vgi_python-0.29.5 → vgi_python-0.30.0}/CLAUDE.md +0 -0
  23. {vgi_python-0.29.5 → vgi_python-0.30.0}/DOCS_ACCEPTANCE_CRITERIA.md +0 -0
  24. {vgi_python-0.29.5 → vgi_python-0.30.0}/DOCS_REVIEW_RUBRIC.md +0 -0
  25. {vgi_python-0.29.5 → vgi_python-0.30.0}/DOCS_USABILITY_TEST.md +0 -0
  26. {vgi_python-0.29.5 → vgi_python-0.30.0}/LICENSE +0 -0
  27. {vgi_python-0.29.5 → vgi_python-0.30.0}/README.md +0 -0
  28. {vgi_python-0.29.5 → vgi_python-0.30.0}/RELEASE-RUNBOOK.md +0 -0
  29. {vgi_python-0.29.5 → vgi_python-0.30.0}/SECURITY.md +0 -0
  30. {vgi_python-0.29.5 → vgi_python-0.30.0}/ci/README.md +0 -0
  31. {vgi_python-0.29.5 → vgi_python-0.30.0}/ci/preprocess-require.awk +0 -0
  32. {vgi_python-0.29.5 → vgi_python-0.30.0}/ci/run-integration.sh +0 -0
  33. {vgi_python-0.29.5 → vgi_python-0.30.0}/dist-vgi/.gitignore +0 -0
  34. {vgi_python-0.29.5 → vgi_python-0.30.0}/docs/aggregate-functions.md +0 -0
  35. {vgi_python-0.29.5 → vgi_python-0.30.0}/docs/api/arguments.md +0 -0
  36. {vgi_python-0.29.5 → vgi_python-0.30.0}/docs/api/auth.md +0 -0
  37. {vgi_python-0.29.5 → vgi_python-0.30.0}/docs/api/catalogs.md +0 -0
  38. {vgi_python-0.29.5 → vgi_python-0.30.0}/docs/api/client.md +0 -0
  39. {vgi_python-0.29.5 → vgi_python-0.30.0}/docs/api/exceptions.md +0 -0
  40. {vgi_python-0.29.5 → vgi_python-0.30.0}/docs/api/filters.md +0 -0
  41. {vgi_python-0.29.5 → vgi_python-0.30.0}/docs/api/functions.md +0 -0
  42. {vgi_python-0.29.5 → vgi_python-0.30.0}/docs/api/http.md +0 -0
  43. {vgi_python-0.29.5 → vgi_python-0.30.0}/docs/api/index.md +0 -0
  44. {vgi_python-0.29.5 → vgi_python-0.30.0}/docs/api/metadata.md +0 -0
  45. {vgi_python-0.29.5 → vgi_python-0.30.0}/docs/api/observability.md +0 -0
  46. {vgi_python-0.29.5 → vgi_python-0.30.0}/docs/api/storage.md +0 -0
  47. {vgi_python-0.29.5 → vgi_python-0.30.0}/docs/api/transactor.md +0 -0
  48. {vgi_python-0.29.5 → vgi_python-0.30.0}/docs/api/worker.md +0 -0
  49. {vgi_python-0.29.5 → vgi_python-0.30.0}/docs/argument-serialization.md +0 -0
  50. {vgi_python-0.29.5 → vgi_python-0.30.0}/docs/assets/apple-touch-icon.png +0 -0
  51. {vgi_python-0.29.5 → vgi_python-0.30.0}/docs/assets/favicon-16x16.png +0 -0
  52. {vgi_python-0.29.5 → vgi_python-0.30.0}/docs/assets/favicon-32x32.png +0 -0
  53. {vgi_python-0.29.5 → vgi_python-0.30.0}/docs/assets/favicon.ico +0 -0
  54. {vgi_python-0.29.5 → vgi_python-0.30.0}/docs/assets/kinds/aggregate.svg +0 -0
  55. {vgi_python-0.29.5 → vgi_python-0.30.0}/docs/assets/kinds/buffering.svg +0 -0
  56. {vgi_python-0.29.5 → vgi_python-0.30.0}/docs/assets/kinds/scalar.svg +0 -0
  57. {vgi_python-0.29.5 → vgi_python-0.30.0}/docs/assets/kinds/table-in-out.svg +0 -0
  58. {vgi_python-0.29.5 → vgi_python-0.30.0}/docs/assets/kinds/table.svg +0 -0
  59. {vgi_python-0.29.5 → vgi_python-0.30.0}/docs/assets/logo.png +0 -0
  60. {vgi_python-0.29.5 → vgi_python-0.30.0}/docs/assets/social-card.png +0 -0
  61. {vgi_python-0.29.5 → vgi_python-0.30.0}/docs/authentication.md +0 -0
  62. {vgi_python-0.29.5 → vgi_python-0.30.0}/docs/catalog-interface.md +0 -0
  63. {vgi_python-0.29.5 → vgi_python-0.30.0}/docs/cli.md +0 -0
  64. {vgi_python-0.29.5 → vgi_python-0.30.0}/docs/column-statistics.md +0 -0
  65. {vgi_python-0.29.5 → vgi_python-0.30.0}/docs/concepts/index.md +0 -0
  66. {vgi_python-0.29.5 → vgi_python-0.30.0}/docs/contributing-docs.md +0 -0
  67. {vgi_python-0.29.5 → vgi_python-0.30.0}/docs/filter-pushdown.md +0 -0
  68. {vgi_python-0.29.5 → vgi_python-0.30.0}/docs/generator-api.md +0 -0
  69. {vgi_python-0.29.5 → vgi_python-0.30.0}/docs/global-functions.md +0 -0
  70. {vgi_python-0.29.5 → vgi_python-0.30.0}/docs/how-to/catalogs.md +0 -0
  71. {vgi_python-0.29.5 → vgi_python-0.30.0}/docs/how-to/function-patterns.md +0 -0
  72. {vgi_python-0.29.5 → vgi_python-0.30.0}/docs/how-to/http-auth.md +0 -0
  73. {vgi_python-0.29.5 → vgi_python-0.30.0}/docs/how-to/index.md +0 -0
  74. {vgi_python-0.29.5 → vgi_python-0.30.0}/docs/how-to/pushdown-and-statistics.md +0 -0
  75. {vgi_python-0.29.5 → vgi_python-0.30.0}/docs/how-to/state-storage.md +0 -0
  76. {vgi_python-0.29.5 → vgi_python-0.30.0}/docs/index.md +0 -0
  77. {vgi_python-0.29.5 → vgi_python-0.30.0}/docs/lifecycle.md +0 -0
  78. {vgi_python-0.29.5 → vgi_python-0.30.0}/docs/metadata.md +0 -0
  79. {vgi_python-0.29.5 → vgi_python-0.30.0}/docs/overrides/main.html +0 -0
  80. {vgi_python-0.29.5 → vgi_python-0.30.0}/docs/robots.txt +0 -0
  81. {vgi_python-0.29.5 → vgi_python-0.30.0}/docs/shared-storage.md +0 -0
  82. {vgi_python-0.29.5 → vgi_python-0.30.0}/docs/stylesheets/extra.css +0 -0
  83. {vgi_python-0.29.5 → vgi_python-0.30.0}/docs/tutorial/index.md +0 -0
  84. {vgi_python-0.29.5 → vgi_python-0.30.0}/docs/tutorial/scalar.md +0 -0
  85. {vgi_python-0.29.5 → vgi_python-0.30.0}/docs/tutorial/table.md +0 -0
  86. {vgi_python-0.29.5 → vgi_python-0.30.0}/docs/vgi-logo.png +0 -0
  87. {vgi_python-0.29.5 → vgi_python-0.30.0}/examples/batch_index_worker.py +0 -0
  88. {vgi_python-0.29.5 → vgi_python-0.30.0}/examples/cache_worker.py +0 -0
  89. {vgi_python-0.29.5 → vgi_python-0.30.0}/examples/calc_scalar_worker.py +0 -0
  90. {vgi_python-0.29.5 → vgi_python-0.30.0}/examples/calc_worker.py +0 -0
  91. {vgi_python-0.29.5 → vgi_python-0.30.0}/examples/copy_format_worker.py +0 -0
  92. {vgi_python-0.29.5 → vgi_python-0.30.0}/examples/filter_worker.py +0 -0
  93. {vgi_python-0.29.5 → vgi_python-0.30.0}/examples/greeting_scalar_worker.py +0 -0
  94. {vgi_python-0.29.5 → vgi_python-0.30.0}/examples/row_count_worker.py +0 -0
  95. {vgi_python-0.29.5 → vgi_python-0.30.0}/examples/series_streaming_worker.py +0 -0
  96. {vgi_python-0.29.5 → vgi_python-0.30.0}/examples/sum_worker.py +0 -0
  97. {vgi_python-0.29.5 → vgi_python-0.30.0}/mkdocs.yml +0 -0
  98. {vgi_python-0.29.5 → vgi_python-0.30.0}/packages/vgi-fixtures/LICENSE +0 -0
  99. {vgi_python-0.29.5 → vgi_python-0.30.0}/packages/vgi-fixtures/README.md +0 -0
  100. {vgi_python-0.29.5 → vgi_python-0.30.0}/packages/vgi-fixtures/docker/Dockerfile +0 -0
  101. {vgi_python-0.29.5 → vgi_python-0.30.0}/packages/vgi-fixtures/docker/docker-entrypoint.sh +0 -0
  102. {vgi_python-0.29.5 → vgi_python-0.30.0}/packages/vgi-fixtures/pyproject.toml +0 -0
  103. {vgi_python-0.29.5 → vgi_python-0.30.0}/scripts/measure_startup.py +0 -0
  104. {vgi_python-0.29.5 → vgi_python-0.30.0}/scripts/run_all_tests.sh +0 -0
  105. {vgi_python-0.29.5 → vgi_python-0.30.0}/test-data/generate.sh +0 -0
  106. {vgi_python-0.29.5 → vgi_python-0.30.0}/tests/__init__.py +0 -0
  107. {vgi_python-0.29.5 → vgi_python-0.30.0}/tests/_http_fixtures.py +0 -0
  108. {vgi_python-0.29.5 → vgi_python-0.30.0}/tests/catalog/__init__.py +0 -0
  109. {vgi_python-0.29.5 → vgi_python-0.30.0}/tests/catalog/test_attach_option.py +0 -0
  110. {vgi_python-0.29.5 → vgi_python-0.30.0}/tests/catalog/test_catalog_interface.py +0 -0
  111. {vgi_python-0.29.5 → vgi_python-0.30.0}/tests/catalog/test_client_catalog.py +0 -0
  112. {vgi_python-0.29.5 → vgi_python-0.30.0}/tests/catalog/test_column_statistics.py +0 -0
  113. {vgi_python-0.29.5 → vgi_python-0.30.0}/tests/catalog/test_declarative.py +0 -0
  114. {vgi_python-0.29.5 → vgi_python-0.30.0}/tests/catalog/test_example_worker_catalog.py +0 -0
  115. {vgi_python-0.29.5 → vgi_python-0.30.0}/tests/catalog/test_integration.py +0 -0
  116. {vgi_python-0.29.5 → vgi_python-0.30.0}/tests/catalog/test_required_filters.py +0 -0
  117. {vgi_python-0.29.5 → vgi_python-0.30.0}/tests/catalog/test_scan_branches.py +0 -0
  118. {vgi_python-0.29.5 → vgi_python-0.30.0}/tests/catalog/test_serialization.py +0 -0
  119. {vgi_python-0.29.5 → vgi_python-0.30.0}/tests/catalog/test_setting.py +0 -0
  120. {vgi_python-0.29.5 → vgi_python-0.30.0}/tests/catalog/test_storage.py +0 -0
  121. {vgi_python-0.29.5 → vgi_python-0.30.0}/tests/catalog/test_time_travel.py +0 -0
  122. {vgi_python-0.29.5 → vgi_python-0.30.0}/tests/catalog/test_writable_table.py +0 -0
  123. {vgi_python-0.29.5 → vgi_python-0.30.0}/tests/client/__init__.py +0 -0
  124. {vgi_python-0.29.5 → vgi_python-0.30.0}/tests/client/test_aggregate_client.py +0 -0
  125. {vgi_python-0.29.5 → vgi_python-0.30.0}/tests/client/test_broken_pipe.py +0 -0
  126. {vgi_python-0.29.5 → vgi_python-0.30.0}/tests/client/test_cli.py +0 -0
  127. {vgi_python-0.29.5 → vgi_python-0.30.0}/tests/client/test_cli_catalog_functions.py +0 -0
  128. {vgi_python-0.29.5 → vgi_python-0.30.0}/tests/client/test_copy_client.py +0 -0
  129. {vgi_python-0.29.5 → vgi_python-0.30.0}/tests/client/test_split_client.py +0 -0
  130. {vgi_python-0.29.5 → vgi_python-0.30.0}/tests/client/test_stop_force.py +0 -0
  131. {vgi_python-0.29.5 → vgi_python-0.30.0}/tests/client/test_table_column_statistics.py +0 -0
  132. {vgi_python-0.29.5 → vgi_python-0.30.0}/tests/client/test_worker_debug.py +0 -0
  133. {vgi_python-0.29.5 → vgi_python-0.30.0}/tests/conformance/__init__.py +0 -0
  134. {vgi_python-0.29.5 → vgi_python-0.30.0}/tests/conformance/_stub.py +0 -0
  135. {vgi_python-0.29.5 → vgi_python-0.30.0}/tests/conformance/conftest.py +0 -0
  136. {vgi_python-0.29.5 → vgi_python-0.30.0}/tests/conformance/test_accumulate.py +0 -0
  137. {vgi_python-0.29.5 → vgi_python-0.30.0}/tests/conformance/test_aggregate.py +0 -0
  138. {vgi_python-0.29.5 → vgi_python-0.30.0}/tests/conformance/test_attach.py +0 -0
  139. {vgi_python-0.29.5 → vgi_python-0.30.0}/tests/conformance/test_bearer_auth.py +0 -0
  140. {vgi_python-0.29.5 → vgi_python-0.30.0}/tests/conformance/test_const_param_enforcement.py +0 -0
  141. {vgi_python-0.29.5 → vgi_python-0.30.0}/tests/conformance/test_container.py +0 -0
  142. {vgi_python-0.29.5 → vgi_python-0.30.0}/tests/conformance/test_copy_from.py +0 -0
  143. {vgi_python-0.29.5 → vgi_python-0.30.0}/tests/conformance/test_copy_to.py +0 -0
  144. {vgi_python-0.29.5 → vgi_python-0.30.0}/tests/conformance/test_directory_parity.py +0 -0
  145. {vgi_python-0.29.5 → vgi_python-0.30.0}/tests/conformance/test_function_inventory.py +0 -0
  146. {vgi_python-0.29.5 → vgi_python-0.30.0}/tests/conformance/test_github.py +0 -0
  147. {vgi_python-0.29.5 → vgi_python-0.30.0}/tests/conformance/test_http_client.py +0 -0
  148. {vgi_python-0.29.5 → vgi_python-0.30.0}/tests/conformance/test_http_external_location.py +0 -0
  149. {vgi_python-0.29.5 → vgi_python-0.30.0}/tests/conformance/test_http_upload_url.py +0 -0
  150. {vgi_python-0.29.5 → vgi_python-0.30.0}/tests/conformance/test_macro.py +0 -0
  151. {vgi_python-0.29.5 → vgi_python-0.30.0}/tests/conformance/test_overload.py +0 -0
  152. {vgi_python-0.29.5 → vgi_python-0.30.0}/tests/conformance/test_protocol_inventory.py +0 -0
  153. {vgi_python-0.29.5 → vgi_python-0.30.0}/tests/conformance/test_protocol_version.py +0 -0
  154. {vgi_python-0.29.5 → vgi_python-0.30.0}/tests/conformance/test_resumable_scan.py +0 -0
  155. {vgi_python-0.29.5 → vgi_python-0.30.0}/tests/conformance/test_scalar.py +0 -0
  156. {vgi_python-0.29.5 → vgi_python-0.30.0}/tests/conformance/test_scalar_attach_opaque_data.py +0 -0
  157. {vgi_python-0.29.5 → vgi_python-0.30.0}/tests/conformance/test_secret.py +0 -0
  158. {vgi_python-0.29.5 → vgi_python-0.30.0}/tests/conformance/test_settings.py +0 -0
  159. {vgi_python-0.29.5 → vgi_python-0.30.0}/tests/conformance/test_splits.py +0 -0
  160. {vgi_python-0.29.5 → vgi_python-0.30.0}/tests/conformance/test_table.py +0 -0
  161. {vgi_python-0.29.5 → vgi_python-0.30.0}/tests/conformance/test_table_in_out.py +0 -0
  162. {vgi_python-0.29.5 → vgi_python-0.30.0}/tests/conformance/test_view.py +0 -0
  163. {vgi_python-0.29.5 → vgi_python-0.30.0}/tests/conformance/test_writable.py +0 -0
  164. {vgi_python-0.29.5 → vgi_python-0.30.0}/tests/conftest.py +0 -0
  165. {vgi_python-0.29.5 → vgi_python-0.30.0}/tests/data/split_tokens/anchor_len_overrun.bin +0 -0
  166. {vgi_python-0.29.5 → vgi_python-0.30.0}/tests/data/split_tokens/bad_fingerprint.bin +0 -0
  167. {vgi_python-0.29.5 → vgi_python-0.30.0}/tests/data/split_tokens/bad_flags_unsealed_but_key_present.bin +0 -0
  168. {vgi_python-0.29.5 → vgi_python-0.30.0}/tests/data/split_tokens/bad_version.bin +0 -0
  169. {vgi_python-0.29.5 → vgi_python-0.30.0}/tests/data/split_tokens/generate.py +0 -0
  170. {vgi_python-0.29.5 → vgi_python-0.30.0}/tests/data/split_tokens/manifest.json +0 -0
  171. {vgi_python-0.29.5 → vgi_python-0.30.0}/tests/data/split_tokens/reserved_flag_bit.bin +0 -0
  172. {vgi_python-0.29.5 → vgi_python-0.30.0}/tests/data/split_tokens/stale_anchor.bin +0 -0
  173. {vgi_python-0.29.5 → vgi_python-0.30.0}/tests/data/split_tokens/truncated.bin +0 -0
  174. {vgi_python-0.29.5 → vgi_python-0.30.0}/tests/data/split_tokens/valid_sealed.bin +0 -0
  175. {vgi_python-0.29.5 → vgi_python-0.30.0}/tests/data/split_tokens/valid_unsealed.bin +0 -0
  176. {vgi_python-0.29.5 → vgi_python-0.30.0}/tests/scalar/__init__.py +0 -0
  177. {vgi_python-0.29.5 → vgi_python-0.30.0}/tests/scalar/test_bernoulli_function.py +0 -0
  178. {vgi_python-0.29.5 → vgi_python-0.30.0}/tests/scalar/test_binary_packet_function.py +0 -0
  179. {vgi_python-0.29.5 → vgi_python-0.30.0}/tests/scalar/test_client.py +0 -0
  180. {vgi_python-0.29.5 → vgi_python-0.30.0}/tests/scalar/test_conditional_message_function.py +0 -0
  181. {vgi_python-0.29.5 → vgi_python-0.30.0}/tests/scalar/test_hash_seed_function.py +0 -0
  182. {vgi_python-0.29.5 → vgi_python-0.30.0}/tests/scalar/test_multiply_by_setting_function.py +0 -0
  183. {vgi_python-0.29.5 → vgi_python-0.30.0}/tests/scalar/test_multiply_function.py +0 -0
  184. {vgi_python-0.29.5 → vgi_python-0.30.0}/tests/scalar/test_random_bytes_function.py +0 -0
  185. {vgi_python-0.29.5 → vgi_python-0.30.0}/tests/scalar/test_return_secret_value_function.py +0 -0
  186. {vgi_python-0.29.5 → vgi_python-0.30.0}/tests/table/__init__.py +0 -0
  187. {vgi_python-0.29.5 → vgi_python-0.30.0}/tests/table/generator/__init__.py +0 -0
  188. {vgi_python-0.29.5 → vgi_python-0.30.0}/tests/table/generator/test_constant_columns_function.py +0 -0
  189. {vgi_python-0.29.5 → vgi_python-0.30.0}/tests/table/generator/test_double_sequence_function.py +0 -0
  190. {vgi_python-0.29.5 → vgi_python-0.30.0}/tests/table/generator/test_exception_function.py +0 -0
  191. {vgi_python-0.29.5 → vgi_python-0.30.0}/tests/table/generator/test_filter_echo_function.py +0 -0
  192. {vgi_python-0.29.5 → vgi_python-0.30.0}/tests/table/generator/test_logging_function.py +0 -0
  193. {vgi_python-0.29.5 → vgi_python-0.30.0}/tests/table/generator/test_nested_sequence_function.py +0 -0
  194. {vgi_python-0.29.5 → vgi_python-0.30.0}/tests/table/generator/test_partitioned_function.py +0 -0
  195. {vgi_python-0.29.5 → vgi_python-0.30.0}/tests/table/generator/test_projected_data_function.py +0 -0
  196. {vgi_python-0.29.5 → vgi_python-0.30.0}/tests/table/generator/test_sequence_function.py +0 -0
  197. {vgi_python-0.29.5 → vgi_python-0.30.0}/tests/table/generator/test_settings_function.py +0 -0
  198. {vgi_python-0.29.5 → vgi_python-0.30.0}/tests/table/generator/test_struct_settings_function.py +0 -0
  199. {vgi_python-0.29.5 → vgi_python-0.30.0}/tests/table/generator/test_ten_thousand_function.py +0 -0
  200. {vgi_python-0.29.5 → vgi_python-0.30.0}/tests/table/test_wide_columns.py +0 -0
  201. {vgi_python-0.29.5 → vgi_python-0.30.0}/tests/table_in_out/__init__.py +0 -0
  202. {vgi_python-0.29.5 → vgi_python-0.30.0}/tests/table_in_out/generator/__init__.py +0 -0
  203. {vgi_python-0.29.5 → vgi_python-0.30.0}/tests/table_in_out/generator/test_buffer_input_function.py +0 -0
  204. {vgi_python-0.29.5 → vgi_python-0.30.0}/tests/table_in_out/generator/test_echo_function.py +0 -0
  205. {vgi_python-0.29.5 → vgi_python-0.30.0}/tests/table_in_out/generator/test_exception_functions.py +0 -0
  206. {vgi_python-0.29.5 → vgi_python-0.30.0}/tests/table_in_out/generator/test_filter_by_setting_function.py +0 -0
  207. {vgi_python-0.29.5 → vgi_python-0.30.0}/tests/table_in_out/generator/test_repeat_inputs_function.py +0 -0
  208. {vgi_python-0.29.5 → vgi_python-0.30.0}/tests/table_in_out/generator/test_substream_partial_sum_function.py +0 -0
  209. {vgi_python-0.29.5 → vgi_python-0.30.0}/tests/table_in_out/generator/test_sum_all_columns_function.py +0 -0
  210. {vgi_python-0.29.5 → vgi_python-0.30.0}/tests/table_in_out/test_blended_metadata.py +0 -0
  211. {vgi_python-0.29.5 → vgi_python-0.30.0}/tests/table_in_out/test_client.py +0 -0
  212. {vgi_python-0.29.5 → vgi_python-0.30.0}/tests/test_access_log_audit.py +0 -0
  213. {vgi_python-0.29.5 → vgi_python-0.30.0}/tests/test_aggregate_function.py +0 -0
  214. {vgi_python-0.29.5 → vgi_python-0.30.0}/tests/test_argument_spec.py +0 -0
  215. {vgi_python-0.29.5 → vgi_python-0.30.0}/tests/test_auth.py +0 -0
  216. {vgi_python-0.29.5 → vgi_python-0.30.0}/tests/test_bind_exceptions.py +0 -0
  217. {vgi_python-0.29.5 → vgi_python-0.30.0}/tests/test_bind_request_at_clause.py +0 -0
  218. {vgi_python-0.29.5 → vgi_python-0.30.0}/tests/test_bound_storage_conformance.py +0 -0
  219. {vgi_python-0.29.5 → vgi_python-0.30.0}/tests/test_cache_control.py +0 -0
  220. {vgi_python-0.29.5 → vgi_python-0.30.0}/tests/test_call_state_attach.py +0 -0
  221. {vgi_python-0.29.5 → vgi_python-0.30.0}/tests/test_catalog_auth_binding.py +0 -0
  222. {vgi_python-0.29.5 → vgi_python-0.30.0}/tests/test_copy_from_function.py +0 -0
  223. {vgi_python-0.29.5 → vgi_python-0.30.0}/tests/test_copy_to_function.py +0 -0
  224. {vgi_python-0.29.5 → vgi_python-0.30.0}/tests/test_docstrings.py +0 -0
  225. {vgi_python-0.29.5 → vgi_python-0.30.0}/tests/test_documentation_examples.py +0 -0
  226. {vgi_python-0.29.5 → vgi_python-0.30.0}/tests/test_example_function_arg_types.py +0 -0
  227. {vgi_python-0.29.5 → vgi_python-0.30.0}/tests/test_examples_workers.py +0 -0
  228. {vgi_python-0.29.5 → vgi_python-0.30.0}/tests/test_exception_handling.py +0 -0
  229. {vgi_python-0.29.5 → vgi_python-0.30.0}/tests/test_exceptions.py +0 -0
  230. {vgi_python-0.29.5 → vgi_python-0.30.0}/tests/test_filter_pushdown.py +0 -0
  231. {vgi_python-0.29.5 → vgi_python-0.30.0}/tests/test_filter_pushdown_extension.py +0 -0
  232. {vgi_python-0.29.5 → vgi_python-0.30.0}/tests/test_fixture_catalog_parity.py +0 -0
  233. {vgi_python-0.29.5 → vgi_python-0.30.0}/tests/test_function_storage.py +0 -0
  234. {vgi_python-0.29.5 → vgi_python-0.30.0}/tests/test_function_storage_azure_sql.py +0 -0
  235. {vgi_python-0.29.5 → vgi_python-0.30.0}/tests/test_function_storage_cf_do.py +0 -0
  236. {vgi_python-0.29.5 → vgi_python-0.30.0}/tests/test_function_storage_cf_do_integration.py +0 -0
  237. {vgi_python-0.29.5 → vgi_python-0.30.0}/tests/test_function_storage_conformance.py +0 -0
  238. {vgi_python-0.29.5 → vgi_python-0.30.0}/tests/test_generated_cpp_constants.py +0 -0
  239. {vgi_python-0.29.5 → vgi_python-0.30.0}/tests/test_generated_cpp_protocol_version.py +0 -0
  240. {vgi_python-0.29.5 → vgi_python-0.30.0}/tests/test_generated_cpp_request_builders.py +0 -0
  241. {vgi_python-0.29.5 → vgi_python-0.30.0}/tests/test_generated_cpp_schemas.py +0 -0
  242. {vgi_python-0.29.5 → vgi_python-0.30.0}/tests/test_generated_cpp_secret.py +0 -0
  243. {vgi_python-0.29.5 → vgi_python-0.30.0}/tests/test_generated_go_schemas.py +0 -0
  244. {vgi_python-0.29.5 → vgi_python-0.30.0}/tests/test_generated_java_schemas.py +0 -0
  245. {vgi_python-0.29.5 → vgi_python-0.30.0}/tests/test_generated_protocol_version.py +0 -0
  246. {vgi_python-0.29.5 → vgi_python-0.30.0}/tests/test_generated_rust_request_builders.py +0 -0
  247. {vgi_python-0.29.5 → vgi_python-0.30.0}/tests/test_generated_rust_schemas.py +0 -0
  248. {vgi_python-0.29.5 → vgi_python-0.30.0}/tests/test_generated_schemas_cross_lang.py +0 -0
  249. {vgi_python-0.29.5 → vgi_python-0.30.0}/tests/test_generated_ts_client.py +0 -0
  250. {vgi_python-0.29.5 → vgi_python-0.30.0}/tests/test_generated_ts_schemas.py +0 -0
  251. {vgi_python-0.29.5 → vgi_python-0.30.0}/tests/test_http_demo_storage.py +0 -0
  252. {vgi_python-0.29.5 → vgi_python-0.30.0}/tests/test_http_s3_offload_input.py +0 -0
  253. {vgi_python-0.29.5 → vgi_python-0.30.0}/tests/test_http_s3_offload_output.py +0 -0
  254. {vgi_python-0.29.5 → vgi_python-0.30.0}/tests/test_launch_transport.py +0 -0
  255. {vgi_python-0.29.5 → vgi_python-0.30.0}/tests/test_metadata.py +0 -0
  256. {vgi_python-0.29.5 → vgi_python-0.30.0}/tests/test_mypy_consolidated.py +0 -0
  257. {vgi_python-0.29.5 → vgi_python-0.30.0}/tests/test_nest_tensor.py +0 -0
  258. {vgi_python-0.29.5 → vgi_python-0.30.0}/tests/test_otel.py +0 -0
  259. {vgi_python-0.29.5 → vgi_python-0.30.0}/tests/test_projection_enforcement.py +0 -0
  260. {vgi_python-0.29.5 → vgi_python-0.30.0}/tests/test_projection_repro.py +0 -0
  261. {vgi_python-0.29.5 → vgi_python-0.30.0}/tests/test_protocol_classes.py +0 -0
  262. {vgi_python-0.29.5 → vgi_python-0.30.0}/tests/test_resolved_secrets.py +0 -0
  263. {vgi_python-0.29.5 → vgi_python-0.30.0}/tests/test_schema_scoped_functions.py +0 -0
  264. {vgi_python-0.29.5 → vgi_python-0.30.0}/tests/test_schema_utils.py +0 -0
  265. {vgi_python-0.29.5 → vgi_python-0.30.0}/tests/test_serve.py +0 -0
  266. {vgi_python-0.29.5 → vgi_python-0.30.0}/tests/test_setting_secret_annotations.py +0 -0
  267. {vgi_python-0.29.5 → vgi_python-0.30.0}/tests/test_signing_key.py +0 -0
  268. {vgi_python-0.29.5 → vgi_python-0.30.0}/tests/test_split_token.py +0 -0
  269. {vgi_python-0.29.5 → vgi_python-0.30.0}/tests/test_table_buffering_function.py +0 -0
  270. {vgi_python-0.29.5 → vgi_python-0.30.0}/tests/test_table_function_dynamic_to_string.py +0 -0
  271. {vgi_python-0.29.5 → vgi_python-0.30.0}/tests/test_tcp_transport.py +0 -0
  272. {vgi_python-0.29.5 → vgi_python-0.30.0}/tests/test_type_bounds.py +0 -0
  273. {vgi_python-0.29.5 → vgi_python-0.30.0}/tests/test_union_argument.py +0 -0
  274. {vgi_python-0.29.5 → vgi_python-0.30.0}/tests/test_wire_record_schema_parity.py +0 -0
  275. {vgi_python-0.29.5 → vgi_python-0.30.0}/tests/test_worker.py +0 -0
  276. {vgi_python-0.29.5 → vgi_python-0.30.0}/tests/test_worker_cli.py +0 -0
  277. {vgi_python-0.29.5 → vgi_python-0.30.0}/tests/test_worker_page.py +0 -0
  278. {vgi_python-0.29.5 → vgi_python-0.30.0}/tests/transactor/__init__.py +0 -0
  279. {vgi_python-0.29.5 → vgi_python-0.30.0}/tests/transactor/test_transactor.py +0 -0
  280. {vgi_python-0.29.5 → vgi_python-0.30.0}/vgi/__init__.py +0 -0
  281. {vgi_python-0.29.5 → vgi_python-0.30.0}/vgi/_duckdb.py +0 -0
  282. {vgi_python-0.29.5 → vgi_python-0.30.0}/vgi/_storage_profile.py +0 -0
  283. {vgi_python-0.29.5 → vgi_python-0.30.0}/vgi/_test_fixtures/__init__.py +0 -0
  284. {vgi_python-0.29.5 → vgi_python-0.30.0}/vgi/_test_fixtures/accumulate/__init__.py +0 -0
  285. {vgi_python-0.29.5 → vgi_python-0.30.0}/vgi/_test_fixtures/accumulate/worker.py +0 -0
  286. {vgi_python-0.29.5 → vgi_python-0.30.0}/vgi/_test_fixtures/aggregate/__init__.py +0 -0
  287. {vgi_python-0.29.5 → vgi_python-0.30.0}/vgi/_test_fixtures/aggregate/_common.py +0 -0
  288. {vgi_python-0.29.5 → vgi_python-0.30.0}/vgi/_test_fixtures/aggregate/basic.py +0 -0
  289. {vgi_python-0.29.5 → vgi_python-0.30.0}/vgi/_test_fixtures/aggregate/dynamic.py +0 -0
  290. {vgi_python-0.29.5 → vgi_python-0.30.0}/vgi/_test_fixtures/aggregate/generic.py +0 -0
  291. {vgi_python-0.29.5 → vgi_python-0.30.0}/vgi/_test_fixtures/aggregate/listagg.py +0 -0
  292. {vgi_python-0.29.5 → vgi_python-0.30.0}/vgi/_test_fixtures/aggregate/percentile.py +0 -0
  293. {vgi_python-0.29.5 → vgi_python-0.30.0}/vgi/_test_fixtures/aggregate/same_name.py +0 -0
  294. {vgi_python-0.29.5 → vgi_python-0.30.0}/vgi/_test_fixtures/aggregate/secret_typed.py +0 -0
  295. {vgi_python-0.29.5 → vgi_python-0.30.0}/vgi/_test_fixtures/aggregate/streaming.py +0 -0
  296. {vgi_python-0.29.5 → vgi_python-0.30.0}/vgi/_test_fixtures/aggregate/varargs.py +0 -0
  297. {vgi_python-0.29.5 → vgi_python-0.30.0}/vgi/_test_fixtures/aggregate/window.py +0 -0
  298. {vgi_python-0.29.5 → vgi_python-0.30.0}/vgi/_test_fixtures/attach_options.py +0 -0
  299. {vgi_python-0.29.5 → vgi_python-0.30.0}/vgi/_test_fixtures/bad_enum.py +0 -0
  300. {vgi_python-0.29.5 → vgi_python-0.30.0}/vgi/_test_fixtures/bad_protocol.py +0 -0
  301. {vgi_python-0.29.5 → vgi_python-0.30.0}/vgi/_test_fixtures/cancellable.py +0 -0
  302. {vgi_python-0.29.5 → vgi_python-0.30.0}/vgi/_test_fixtures/catalog.py +0 -0
  303. {vgi_python-0.29.5 → vgi_python-0.30.0}/vgi/_test_fixtures/companion.py +0 -0
  304. {vgi_python-0.29.5 → vgi_python-0.30.0}/vgi/_test_fixtures/copy_from.py +0 -0
  305. {vgi_python-0.29.5 → vgi_python-0.30.0}/vgi/_test_fixtures/copy_to.py +0 -0
  306. {vgi_python-0.29.5 → vgi_python-0.30.0}/vgi/_test_fixtures/global_functions.py +0 -0
  307. {vgi_python-0.29.5 → vgi_python-0.30.0}/vgi/_test_fixtures/http_server.py +0 -0
  308. {vgi_python-0.29.5 → vgi_python-0.30.0}/vgi/_test_fixtures/narrow_bind/__init__.py +0 -0
  309. {vgi_python-0.29.5 → vgi_python-0.30.0}/vgi/_test_fixtures/narrow_bind/worker.py +0 -0
  310. {vgi_python-0.29.5 → vgi_python-0.30.0}/vgi/_test_fixtures/nest_tensor.py +0 -0
  311. {vgi_python-0.29.5 → vgi_python-0.30.0}/vgi/_test_fixtures/orchard_catalog.py +0 -0
  312. {vgi_python-0.29.5 → vgi_python-0.30.0}/vgi/_test_fixtures/projection_repro/__init__.py +0 -0
  313. {vgi_python-0.29.5 → vgi_python-0.30.0}/vgi/_test_fixtures/projection_repro/worker.py +0 -0
  314. {vgi_python-0.29.5 → vgi_python-0.30.0}/vgi/_test_fixtures/scalar/__init__.py +0 -0
  315. {vgi_python-0.29.5 → vgi_python-0.30.0}/vgi/_test_fixtures/scalar/_common.py +0 -0
  316. {vgi_python-0.29.5 → vgi_python-0.30.0}/vgi/_test_fixtures/scalar/arithmetic.py +0 -0
  317. {vgi_python-0.29.5 → vgi_python-0.30.0}/vgi/_test_fixtures/scalar/bench_ladder.py +0 -0
  318. {vgi_python-0.29.5 → vgi_python-0.30.0}/vgi/_test_fixtures/scalar/binary.py +0 -0
  319. {vgi_python-0.29.5 → vgi_python-0.30.0}/vgi/_test_fixtures/scalar/formatting.py +0 -0
  320. {vgi_python-0.29.5 → vgi_python-0.30.0}/vgi/_test_fixtures/scalar/geo.py +0 -0
  321. {vgi_python-0.29.5 → vgi_python-0.30.0}/vgi/_test_fixtures/scalar/null_handling.py +0 -0
  322. {vgi_python-0.29.5 → vgi_python-0.30.0}/vgi/_test_fixtures/scalar/random_demo.py +0 -0
  323. {vgi_python-0.29.5 → vgi_python-0.30.0}/vgi/_test_fixtures/scalar/same_name.py +0 -0
  324. {vgi_python-0.29.5 → vgi_python-0.30.0}/vgi/_test_fixtures/scalar/settings_secrets.py +0 -0
  325. {vgi_python-0.29.5 → vgi_python-0.30.0}/vgi/_test_fixtures/scalar/type_info.py +0 -0
  326. {vgi_python-0.29.5 → vgi_python-0.30.0}/vgi/_test_fixtures/schema_reconcile/__init__.py +0 -0
  327. {vgi_python-0.29.5 → vgi_python-0.30.0}/vgi/_test_fixtures/schema_reconcile/worker.py +0 -0
  328. {vgi_python-0.29.5 → vgi_python-0.30.0}/vgi/_test_fixtures/simple_writable.py +0 -0
  329. {vgi_python-0.29.5 → vgi_python-0.30.0}/vgi/_test_fixtures/table/__init__.py +0 -0
  330. {vgi_python-0.29.5 → vgi_python-0.30.0}/vgi/_test_fixtures/table/_common.py +0 -0
  331. {vgi_python-0.29.5 → vgi_python-0.30.0}/vgi/_test_fixtures/table/batch_index.py +0 -0
  332. {vgi_python-0.29.5 → vgi_python-0.30.0}/vgi/_test_fixtures/table/batch_index_broken.py +0 -0
  333. {vgi_python-0.29.5 → vgi_python-0.30.0}/vgi/_test_fixtures/table/cache.py +0 -0
  334. {vgi_python-0.29.5 → vgi_python-0.30.0}/vgi/_test_fixtures/table/catalog_scans.py +0 -0
  335. {vgi_python-0.29.5 → vgi_python-0.30.0}/vgi/_test_fixtures/table/filters.py +0 -0
  336. {vgi_python-0.29.5 → vgi_python-0.30.0}/vgi/_test_fixtures/table/late_materialization.py +0 -0
  337. {vgi_python-0.29.5 → vgi_python-0.30.0}/vgi/_test_fixtures/table/make_series.py +0 -0
  338. {vgi_python-0.29.5 → vgi_python-0.30.0}/vgi/_test_fixtures/table/misc.py +0 -0
  339. {vgi_python-0.29.5 → vgi_python-0.30.0}/vgi/_test_fixtures/table/order_modes.py +0 -0
  340. {vgi_python-0.29.5 → vgi_python-0.30.0}/vgi/_test_fixtures/table/pairs.py +0 -0
  341. {vgi_python-0.29.5 → vgi_python-0.30.0}/vgi/_test_fixtures/table/partition_columns.py +0 -0
  342. {vgi_python-0.29.5 → vgi_python-0.30.0}/vgi/_test_fixtures/table/partition_columns_broken.py +0 -0
  343. {vgi_python-0.29.5 → vgi_python-0.30.0}/vgi/_test_fixtures/table/profiling_example.py +0 -0
  344. {vgi_python-0.29.5 → vgi_python-0.30.0}/vgi/_test_fixtures/table/required_filters.py +0 -0
  345. {vgi_python-0.29.5 → vgi_python-0.30.0}/vgi/_test_fixtures/table/same_name_cached.py +0 -0
  346. {vgi_python-0.29.5 → vgi_python-0.30.0}/vgi/_test_fixtures/table/sequence.py +0 -0
  347. {vgi_python-0.29.5 → vgi_python-0.30.0}/vgi/_test_fixtures/table/settings.py +0 -0
  348. {vgi_python-0.29.5 → vgi_python-0.30.0}/vgi/_test_fixtures/table/splits.py +0 -0
  349. {vgi_python-0.29.5 → vgi_python-0.30.0}/vgi/_test_fixtures/table/transaction_storage.py +0 -0
  350. {vgi_python-0.29.5 → vgi_python-0.30.0}/vgi/_test_fixtures/table/tt_pushdown.py +0 -0
  351. {vgi_python-0.29.5 → vgi_python-0.30.0}/vgi/_test_fixtures/table/typed_probe.py +0 -0
  352. {vgi_python-0.29.5 → vgi_python-0.30.0}/vgi/_test_fixtures/table/versioned.py +0 -0
  353. {vgi_python-0.29.5 → vgi_python-0.30.0}/vgi/_test_fixtures/table/wide.py +0 -0
  354. {vgi_python-0.29.5 → vgi_python-0.30.0}/vgi/_test_fixtures/table_in_out.py +0 -0
  355. {vgi_python-0.29.5 → vgi_python-0.30.0}/vgi/_test_fixtures/table_in_out_same_name.py +0 -0
  356. {vgi_python-0.29.5 → vgi_python-0.30.0}/vgi/_test_fixtures/twin_catalogs.py +0 -0
  357. {vgi_python-0.29.5 → vgi_python-0.30.0}/vgi/_test_fixtures/versioned.py +0 -0
  358. {vgi_python-0.29.5 → vgi_python-0.30.0}/vgi/_test_fixtures/versioned_tables.py +0 -0
  359. {vgi_python-0.29.5 → vgi_python-0.30.0}/vgi/_test_fixtures/worker.py +0 -0
  360. {vgi_python-0.29.5 → vgi_python-0.30.0}/vgi/_test_fixtures/writable/__init__.py +0 -0
  361. {vgi_python-0.29.5 → vgi_python-0.30.0}/vgi/_test_fixtures/writable/generic.py +0 -0
  362. {vgi_python-0.29.5 → vgi_python-0.30.0}/vgi/_test_fixtures/writable/table.py +0 -0
  363. {vgi_python-0.29.5 → vgi_python-0.30.0}/vgi/_test_fixtures/writable/worker.py +0 -0
  364. {vgi_python-0.29.5 → vgi_python-0.30.0}/vgi/aggregate_function.py +0 -0
  365. {vgi_python-0.29.5 → vgi_python-0.30.0}/vgi/argument_spec.py +0 -0
  366. {vgi_python-0.29.5 → vgi_python-0.30.0}/vgi/arguments.py +0 -0
  367. {vgi_python-0.29.5 → vgi_python-0.30.0}/vgi/attach_header.py +0 -0
  368. {vgi_python-0.29.5 → vgi_python-0.30.0}/vgi/auth.py +0 -0
  369. {vgi_python-0.29.5 → vgi_python-0.30.0}/vgi/cache_control.py +0 -0
  370. {vgi_python-0.29.5 → vgi_python-0.30.0}/vgi/catalog/__init__.py +0 -0
  371. {vgi_python-0.29.5 → vgi_python-0.30.0}/vgi/catalog/_descriptor_spec.py +0 -0
  372. {vgi_python-0.29.5 → vgi_python-0.30.0}/vgi/catalog/attach_option.py +0 -0
  373. {vgi_python-0.29.5 → vgi_python-0.30.0}/vgi/catalog/catalog_interface.py +0 -0
  374. {vgi_python-0.29.5 → vgi_python-0.30.0}/vgi/catalog/descriptors.py +0 -0
  375. {vgi_python-0.29.5 → vgi_python-0.30.0}/vgi/catalog/duckdb_statistics.py +0 -0
  376. {vgi_python-0.29.5 → vgi_python-0.30.0}/vgi/catalog/secret_type.py +0 -0
  377. {vgi_python-0.29.5 → vgi_python-0.30.0}/vgi/catalog/setting.py +0 -0
  378. {vgi_python-0.29.5 → vgi_python-0.30.0}/vgi/catalog/storage.py +0 -0
  379. {vgi_python-0.29.5 → vgi_python-0.30.0}/vgi/client/__init__.py +0 -0
  380. {vgi_python-0.29.5 → vgi_python-0.30.0}/vgi/client/aggregate.py +0 -0
  381. {vgi_python-0.29.5 → vgi_python-0.30.0}/vgi/client/catalog_mixin.py +0 -0
  382. {vgi_python-0.29.5 → vgi_python-0.30.0}/vgi/client/cli.py +0 -0
  383. {vgi_python-0.29.5 → vgi_python-0.30.0}/vgi/client/cli_catalog.py +0 -0
  384. {vgi_python-0.29.5 → vgi_python-0.30.0}/vgi/client/cli_schema.py +0 -0
  385. {vgi_python-0.29.5 → vgi_python-0.30.0}/vgi/client/cli_table.py +0 -0
  386. {vgi_python-0.29.5 → vgi_python-0.30.0}/vgi/client/cli_transaction.py +0 -0
  387. {vgi_python-0.29.5 → vgi_python-0.30.0}/vgi/client/cli_utils.py +0 -0
  388. {vgi_python-0.29.5 → vgi_python-0.30.0}/vgi/client/cli_view.py +0 -0
  389. {vgi_python-0.29.5 → vgi_python-0.30.0}/vgi/client/errors.py +0 -0
  390. {vgi_python-0.29.5 → vgi_python-0.30.0}/vgi/codegen/__init__.py +0 -0
  391. {vgi_python-0.29.5 → vgi_python-0.30.0}/vgi/codegen/_common.py +0 -0
  392. {vgi_python-0.29.5 → vgi_python-0.30.0}/vgi/codegen/cpp_constants.py +0 -0
  393. {vgi_python-0.29.5 → vgi_python-0.30.0}/vgi/codegen/cpp_protocol_version.py +0 -0
  394. {vgi_python-0.29.5 → vgi_python-0.30.0}/vgi/codegen/cpp_schemas.py +0 -0
  395. {vgi_python-0.29.5 → vgi_python-0.30.0}/vgi/codegen/cpp_secret_protocol_version.py +0 -0
  396. {vgi_python-0.29.5 → vgi_python-0.30.0}/vgi/codegen/cpp_secret_request_builders.py +0 -0
  397. {vgi_python-0.29.5 → vgi_python-0.30.0}/vgi/codegen/cpp_secret_schemas.py +0 -0
  398. {vgi_python-0.29.5 → vgi_python-0.30.0}/vgi/codegen/go_schemas.py +0 -0
  399. {vgi_python-0.29.5 → vgi_python-0.30.0}/vgi/codegen/java_schemas.py +0 -0
  400. {vgi_python-0.29.5 → vgi_python-0.30.0}/vgi/codegen/protocol_version.py +0 -0
  401. {vgi_python-0.29.5 → vgi_python-0.30.0}/vgi/codegen/rust_request_builders.py +0 -0
  402. {vgi_python-0.29.5 → vgi_python-0.30.0}/vgi/codegen/rust_schemas.py +0 -0
  403. {vgi_python-0.29.5 → vgi_python-0.30.0}/vgi/codegen/ts_client.py +0 -0
  404. {vgi_python-0.29.5 → vgi_python-0.30.0}/vgi/codegen/ts_schemas.py +0 -0
  405. {vgi_python-0.29.5 → vgi_python-0.30.0}/vgi/copy_from_function.py +0 -0
  406. {vgi_python-0.29.5 → vgi_python-0.30.0}/vgi/copy_to_function.py +0 -0
  407. {vgi_python-0.29.5 → vgi_python-0.30.0}/vgi/exceptions.py +0 -0
  408. {vgi_python-0.29.5 → vgi_python-0.30.0}/vgi/function.py +0 -0
  409. {vgi_python-0.29.5 → vgi_python-0.30.0}/vgi/function_storage.py +0 -0
  410. {vgi_python-0.29.5 → vgi_python-0.30.0}/vgi/function_storage_azure_sql.py +0 -0
  411. {vgi_python-0.29.5 → vgi_python-0.30.0}/vgi/function_storage_cf_do.py +0 -0
  412. {vgi_python-0.29.5 → vgi_python-0.30.0}/vgi/http/__init__.py +0 -0
  413. {vgi_python-0.29.5 → vgi_python-0.30.0}/vgi/http/demo_storage.py +0 -0
  414. {vgi_python-0.29.5 → vgi_python-0.30.0}/vgi/http/landing.html +0 -0
  415. {vgi_python-0.29.5 → vgi_python-0.30.0}/vgi/http/landing_page.py +0 -0
  416. {vgi_python-0.29.5 → vgi_python-0.30.0}/vgi/http/vgi-client.js +0 -0
  417. {vgi_python-0.29.5 → vgi_python-0.30.0}/vgi/http/worker_page.py +0 -0
  418. {vgi_python-0.29.5 → vgi_python-0.30.0}/vgi/invocation.py +0 -0
  419. {vgi_python-0.29.5 → vgi_python-0.30.0}/vgi/logging_config.py +0 -0
  420. {vgi_python-0.29.5 → vgi_python-0.30.0}/vgi/meta_worker.py +0 -0
  421. {vgi_python-0.29.5 → vgi_python-0.30.0}/vgi/metadata.py +0 -0
  422. {vgi_python-0.29.5 → vgi_python-0.30.0}/vgi/otel.py +0 -0
  423. {vgi_python-0.29.5 → vgi_python-0.30.0}/vgi/profiling.py +0 -0
  424. {vgi_python-0.29.5 → vgi_python-0.30.0}/vgi/protocol.py +0 -0
  425. {vgi_python-0.29.5 → vgi_python-0.30.0}/vgi/protocol_version.txt +0 -0
  426. {vgi_python-0.29.5 → vgi_python-0.30.0}/vgi/py.typed +0 -0
  427. {vgi_python-0.29.5 → vgi_python-0.30.0}/vgi/scalar_function.py +0 -0
  428. {vgi_python-0.29.5 → vgi_python-0.30.0}/vgi/schema_utils.py +0 -0
  429. {vgi_python-0.29.5 → vgi_python-0.30.0}/vgi/secret_protocol.py +0 -0
  430. {vgi_python-0.29.5 → vgi_python-0.30.0}/vgi/secret_service.py +0 -0
  431. {vgi_python-0.29.5 → vgi_python-0.30.0}/vgi/serve.py +0 -0
  432. {vgi_python-0.29.5 → vgi_python-0.30.0}/vgi/split_token.py +0 -0
  433. {vgi_python-0.29.5 → vgi_python-0.30.0}/vgi/table_buffering_function.py +0 -0
  434. {vgi_python-0.29.5 → vgi_python-0.30.0}/vgi/table_filter_pushdown.py +0 -0
  435. {vgi_python-0.29.5 → vgi_python-0.30.0}/vgi/table_function.py +0 -0
  436. {vgi_python-0.29.5 → vgi_python-0.30.0}/vgi/table_in_out_function.py +0 -0
  437. {vgi_python-0.29.5 → vgi_python-0.30.0}/vgi/transactor/__init__.py +0 -0
  438. {vgi_python-0.29.5 → vgi_python-0.30.0}/vgi/transactor/_duckdb_compat.py +0 -0
  439. {vgi_python-0.29.5 → vgi_python-0.30.0}/vgi/transactor/client.py +0 -0
  440. {vgi_python-0.29.5 → vgi_python-0.30.0}/vgi/transactor/protocol.py +0 -0
  441. {vgi_python-0.29.5 → vgi_python-0.30.0}/vgi/transactor/server.py +0 -0
  442. {vgi_python-0.29.5 → vgi_python-0.30.0}/wrangler.jsonc +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: vgi-python
3
- Version: 0.29.5
3
+ Version: 0.30.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: httpx2>=2.9.1
162
162
  Requires-Dist: platformdirs
163
163
  Requires-Dist: pyarrow
164
164
  Requires-Dist: typer>=0.9
165
- Requires-Dist: vgi-rpc>=0.43.2
165
+ Requires-Dist: vgi-rpc>=0.44.1
166
166
  Provides-Extra: azure
167
167
  Requires-Dist: azure-identity>=1.16.0; extra == 'azure'
168
168
  Requires-Dist: pymssql>=2.3.0; extra == 'azure'
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "vgi-python"
3
- version = "0.29.5"
3
+ version = "0.30.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.43.2",
43
+ "vgi-rpc>=0.44.1",
44
44
  "httpx2>=2.9.1",
45
45
  ]
46
46
 
@@ -69,7 +69,7 @@ def test_callback_sees_none_for_a_batch_without_custom_metadata(client: Any) ->
69
69
  client.table_function(
70
70
  function_name="sequence",
71
71
  schema_name="main",
72
- arguments=Arguments(positional=[pa.scalar(4)]),
72
+ arguments=Arguments(positional=(pa.scalar(4),)),
73
73
  batch_metadata_callback=metas.append,
74
74
  )
75
75
  )
@@ -60,8 +60,11 @@ def test_single_branch_table_falls_back_to_legacy_rpc(client: Any) -> None:
60
60
  name="numbers",
61
61
  )
62
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
63
+ assert (
64
+ result.branches[0].function_name
65
+ == client.table_scan_function_get(
66
+ attach_opaque_data=_attach_opaque(client),
67
+ schema_name=DATA,
68
+ name="numbers",
69
+ ).function_name
70
+ )
@@ -79,7 +79,7 @@ def test_table_function_with_no_at_clause_is_unaffected(client: Any) -> None:
79
79
  """The new `at_unit`/`at_value` params default to `None` — unchanged behavior without them."""
80
80
  batches = list(
81
81
  client.table_function(
82
- function_name="sequence", schema_name="main", arguments=Arguments(positional=[pa.scalar(5)])
82
+ function_name="sequence", schema_name="main", arguments=Arguments(positional=(pa.scalar(5),))
83
83
  )
84
84
  )
85
85
  assert sum(b.num_rows for b in batches) == 5
@@ -238,3 +238,45 @@ class TestBlendedArityAndVarargs:
238
238
 
239
239
  assert len(results) == 1
240
240
  assert results[0].column("row_sum").to_pylist() == [3.0, 5.0]
241
+
242
+
243
+ class TestHasFinalizeSkip:
244
+ """`has_finalize=False` skips the FINALIZE `init()` entirely for a no-finalize function.
245
+
246
+ Real interop bug found live against a non-Python worker SDK: the client
247
+ unconditionally sent a FINALIZE-phase init() for every table-in-out call,
248
+ which the Python fixture worker happens to no-op gracefully but a
249
+ TypeScript-SDK worker rejects outright ("a blended row-transform function
250
+ has no FINALIZE phase"). `has_finalize=False` avoids sending that init()
251
+ at all rather than depending on every SDK tolerating an unexpected one.
252
+ Output must be identical either way for a function that has no finalize
253
+ stage (there is nothing to skip yielding) -- this is the equivalence this
254
+ suite can prove locally; the cross-SDK rejection itself is TypeScript-only.
255
+ """
256
+
257
+ def test_output_identical_with_and_without_has_finalize(self, client_transport: Any) -> None:
258
+ """Same output whether the FINALIZE init() is sent or skipped, both transports."""
259
+ input_schema = make_schema([pa.field("n", pa.int64())])
260
+ batch = pa.RecordBatch.from_pydict({"n": [0, 1, 3, 2]}, schema=input_schema)
261
+
262
+ with client_transport() as client:
263
+ with_finalize = list(
264
+ client.table_in_out_function(
265
+ function_name="blended_explode",
266
+ schema_name="main",
267
+ input=iter([batch]),
268
+ )
269
+ )
270
+ with client_transport() as client:
271
+ without_finalize = list(
272
+ client.table_in_out_function(
273
+ function_name="blended_explode",
274
+ schema_name="main",
275
+ input=iter([batch]),
276
+ has_finalize=False,
277
+ )
278
+ )
279
+
280
+ assert len(with_finalize) == 1
281
+ assert len(without_finalize) == 1
282
+ assert with_finalize[0].column("i").to_pylist() == without_finalize[0].column("i").to_pylist()
@@ -0,0 +1,204 @@
1
+ # Copyright 2025, 2026 Query Farm LLC - https://query.farm
2
+
3
+ """Tests for vgi.client.Client's OAuth wiring (oauth=/oauth_refresh_token=/oauth_flow=).
4
+
5
+ The device-code/PKCE flow logic itself is tested exhaustively in
6
+ vgi-rpc-python's tests/test_oauth_client.py (mock IdP, no network). These
7
+ tests cover the integration seam: does `Client` build a `VgiOAuthAuth` with
8
+ the right configuration, does construction-time validation reject bad
9
+ combinations, and does a full round trip actually work when driven through
10
+ `Client`'s real request path (via the `httpx_client=` escape hatch, wired to
11
+ a mock IdP the same way vgi-rpc-python's own tests are).
12
+ """
13
+
14
+ from __future__ import annotations
15
+
16
+ import httpx2
17
+ import pytest
18
+ from vgi_rpc.http import VgiOAuthAuth
19
+
20
+ from vgi.client.client import Client
21
+
22
+ RESOURCE_METADATA_URL = "https://api.example.com/.well-known/oauth-protected-resource"
23
+ DEVICE_AUTH_URL = "https://auth.example.com/device/code"
24
+ TOKEN_URL = "https://auth.example.com/token"
25
+
26
+
27
+ class _MockIdp:
28
+ """Minimal mock IdP + protected resource for one full device-code round trip."""
29
+
30
+ def __init__(self) -> None:
31
+ self.device_auth_calls = 0
32
+ self.granted_token = "mock-access-token"
33
+
34
+ def handler(self, request: httpx2.Request) -> httpx2.Response:
35
+ """Route a request to the matching mock endpoint by exact URL."""
36
+ url = str(request.url)
37
+ if url == RESOURCE_METADATA_URL:
38
+ return httpx2.Response(
39
+ 200,
40
+ json={
41
+ "resource": "https://api.example.com",
42
+ "authorization_servers": ["https://auth.example.com"],
43
+ "device_code_client_id": "device-client",
44
+ "device_code_client_secret": "device-secret",
45
+ },
46
+ )
47
+ if url == "https://auth.example.com/.well-known/openid-configuration":
48
+ return httpx2.Response(
49
+ 200,
50
+ json={
51
+ "token_endpoint": TOKEN_URL,
52
+ "device_authorization_endpoint": DEVICE_AUTH_URL,
53
+ "grant_types_supported": ["urn:ietf:params:oauth:grant-type:device_code"],
54
+ },
55
+ )
56
+ if url == DEVICE_AUTH_URL:
57
+ self.device_auth_calls += 1
58
+ return httpx2.Response(
59
+ 200,
60
+ json={
61
+ "device_code": "devcode-123",
62
+ "user_code": "ABCD-EFGH",
63
+ "verification_uri": "https://auth.example.com/activate",
64
+ "expires_in": 600,
65
+ "interval": 0,
66
+ },
67
+ )
68
+ if url == TOKEN_URL:
69
+ return httpx2.Response(200, json={"access_token": self.granted_token, "token_type": "Bearer"})
70
+ if url.endswith("/vgi/catalogs"):
71
+ token = request.headers.get("authorization", "")
72
+ if token:
73
+ return httpx2.Response(200, json={"authorization": token})
74
+ return httpx2.Response(
75
+ 401,
76
+ headers={"www-authenticate": f'Bearer resource_metadata="{RESOURCE_METADATA_URL}"'},
77
+ )
78
+ return httpx2.Response(404, json={"error": "not_found", "url": url}) # pragma: no cover
79
+
80
+
81
+ class TestConstructorValidation:
82
+ """Tests for the mutually-exclusive oauth/bearer_token/httpx_client combinations."""
83
+
84
+ def test_oauth_and_bearer_token_raises(self) -> None:
85
+ """Passing both oauth=True and bearer_token= raises ValueError."""
86
+ with pytest.raises(ValueError, match="mutually exclusive"):
87
+ Client(transport="http", base_url="https://example.com", oauth=True, bearer_token="tok")
88
+
89
+ def test_oauth_refresh_token_and_bearer_token_raises(self) -> None:
90
+ """oauth_refresh_token= (which implies oauth=True) also conflicts with bearer_token=."""
91
+ with pytest.raises(ValueError, match="mutually exclusive"):
92
+ Client(
93
+ transport="http",
94
+ base_url="https://example.com",
95
+ oauth_refresh_token="seed",
96
+ bearer_token="tok",
97
+ )
98
+
99
+ def test_oauth_and_httpx_client_raises(self) -> None:
100
+ """Passing both oauth=True and httpx_client= raises ValueError."""
101
+ with pytest.raises(ValueError, match="httpx_client"):
102
+ Client(
103
+ transport="http",
104
+ base_url="https://example.com",
105
+ oauth=True,
106
+ httpx_client=httpx2.Client(),
107
+ )
108
+
109
+ def test_invalid_oauth_flow_raises(self) -> None:
110
+ """An unrecognized oauth_flow value raises ValueError, not a silent no-op."""
111
+ with pytest.raises(ValueError, match="oauth_flow"):
112
+ Client(transport="http", base_url="https://example.com", oauth=True, oauth_flow="carrier-pigeon") # type: ignore[arg-type]
113
+
114
+ def test_invalid_oauth_prompt_raises(self) -> None:
115
+ """An unrecognized oauth_prompt value raises ValueError, not a silent no-op."""
116
+ with pytest.raises(ValueError, match="oauth_prompt"):
117
+ Client(transport="http", base_url="https://example.com", oauth=True, oauth_prompt="shout") # type: ignore[arg-type]
118
+
119
+ def test_bearer_token_alone_still_works(self) -> None:
120
+ """The existing bearer_token= path is unaffected by the new oauth params."""
121
+ client = Client(transport="http", base_url="https://example.com", bearer_token="tok")
122
+ assert client._bearer_token == "tok"
123
+ assert not client._use_oauth
124
+
125
+
126
+ class TestOAuthWiring:
127
+ """Tests that Client(oauth=...) builds a correctly-configured VgiOAuthAuth."""
128
+
129
+ def test_oauth_true_builds_vgi_oauth_auth(self) -> None:
130
+ """oauth=True lazily builds a VgiOAuthAuth with the client's own oauth_* settings."""
131
+ client = Client(
132
+ transport="http",
133
+ base_url="https://example.com",
134
+ oauth=True,
135
+ oauth_flow="device_code",
136
+ oauth_timeout_seconds=42.0,
137
+ oauth_prompt="consent",
138
+ )
139
+ assert client.oauth_identity() is None # nothing has authenticated yet
140
+ client._get_or_create_httpx_client()
141
+ assert isinstance(client._oauth_auth, VgiOAuthAuth)
142
+ assert client._oauth_auth._flow == "device_code" # noqa: SLF001 -- white-box wiring check
143
+ assert client._oauth_auth._timeout_seconds == 42.0 # noqa: SLF001
144
+ assert client._oauth_auth._prompt == "consent" # noqa: SLF001
145
+ client._oauth_auth.close()
146
+
147
+ def test_oauth_refresh_token_seeds_the_auth_object(self) -> None:
148
+ """oauth_refresh_token= implies oauth=True and seeds the refresh token."""
149
+ client = Client(
150
+ transport="http",
151
+ base_url="https://example.com",
152
+ oauth_refresh_token="pre-seeded-token",
153
+ )
154
+ assert client._use_oauth
155
+ client._get_or_create_httpx_client()
156
+ assert client._oauth_auth is not None
157
+ assert client._oauth_auth._token.refresh_token == "pre-seeded-token" # noqa: SLF001
158
+ client._oauth_auth.close()
159
+
160
+
161
+ class TestOAuthEndToEnd:
162
+ """A full device-code login round trip through the exact client Client would use.
163
+
164
+ Uses the httpx_client= escape hatch to wire a VgiOAuthAuth against a mock
165
+ IdP (httpx2.MockTransport) -- the same technique vgi-rpc-python's own
166
+ tests use. The device-code/PKCE flow mechanics are covered exhaustively
167
+ there (mock IdP, no network); this test's job is narrower: prove
168
+ ``Client`` actually issues its RPCs through the httpx2.Client it was
169
+ handed (so a real attach would carry the OAuth-obtained token), and that
170
+ a 401-triggered login on that client completes end to end.
171
+ """
172
+
173
+ def test_client_issues_requests_through_the_oauth_authed_httpx_client(self) -> None:
174
+ """A 401 on the client Client._get_or_create_httpx_client() returns triggers a real login."""
175
+ idp = _MockIdp()
176
+ auth = VgiOAuthAuth(
177
+ base_url="https://example.com",
178
+ flow="device_code",
179
+ timeout_seconds=5.0,
180
+ transport=httpx2.MockTransport(idp.handler),
181
+ )
182
+ httpx_client = httpx2.Client(
183
+ transport=httpx2.MockTransport(idp.handler), auth=auth, base_url="https://example.com"
184
+ )
185
+ # Not started (no worker spawned) -- this test only exercises the HTTP/OAuth
186
+ # plumbing, not a full RPC call, so client.stop() (which requires start())
187
+ # doesn't apply; the httpx_client/auth are closed directly instead.
188
+ client = Client(transport="http", base_url="https://example.com", httpx_client=httpx_client)
189
+ try:
190
+ # This is the exact client object Client's own RPC machinery sends
191
+ # every request through -- not a parallel one built just for the test.
192
+ assert client._get_or_create_httpx_client() is httpx_client
193
+
194
+ resp = httpx_client.get("/vgi/catalogs")
195
+ assert resp.status_code == 200
196
+ assert resp.json()["authorization"] == f"Bearer {idp.granted_token}"
197
+ assert idp.device_auth_calls == 1
198
+
199
+ # A second request reuses the cached token -- no second login.
200
+ httpx_client.get("/vgi/catalogs")
201
+ assert idp.device_auth_calls == 1
202
+ finally:
203
+ httpx_client.close()
204
+ auth.close()
@@ -2569,7 +2569,7 @@ requires-dist = [
2569
2569
 
2570
2570
  [[package]]
2571
2571
  name = "vgi-python"
2572
- version = "0.29.5"
2572
+ version = "0.30.0"
2573
2573
  source = { editable = "." }
2574
2574
  dependencies = [
2575
2575
  { name = "click" },
@@ -2686,7 +2686,7 @@ requires-dist = [
2686
2686
  { name = "vgi-python", extras = ["test-fixtures"], marker = "extra == 'test-fixtures-writable'" },
2687
2687
  { name = "vgi-python", extras = ["test-fixtures", "test-fixtures-writable", "http", "launch", "oauth", "otel", "sentry", "azure"], marker = "extra == 'dev'" },
2688
2688
  { name = "vgi-python", extras = ["transactor"], marker = "extra == 'test-fixtures-writable'" },
2689
- { name = "vgi-rpc", specifier = ">=0.43.2" },
2689
+ { name = "vgi-rpc", specifier = ">=0.44.1" },
2690
2690
  { name = "vgi-rpc", extras = ["cli"], marker = "extra == 'launch'" },
2691
2691
  { name = "vgi-rpc", extras = ["cli", "conformance", "external", "http", "oauth", "otel", "sentry"], marker = "extra == 'dev'" },
2692
2692
  { name = "vgi-rpc", extras = ["http"], marker = "extra == 'granian'" },
@@ -2716,7 +2716,7 @@ docs = [
2716
2716
 
2717
2717
  [[package]]
2718
2718
  name = "vgi-rpc"
2719
- version = "0.43.2"
2719
+ version = "0.44.1"
2720
2720
  source = { registry = "https://pypi.org/simple" }
2721
2721
  dependencies = [
2722
2722
  { name = "docstring-parser" },
@@ -2724,9 +2724,9 @@ dependencies = [
2724
2724
  { name = "pywin32", marker = "sys_platform == 'win32'" },
2725
2725
  { name = "tzdata", marker = "sys_platform == 'win32'" },
2726
2726
  ]
2727
- sdist = { url = "https://files.pythonhosted.org/packages/ce/04/efb99f0fb56535bcba110e6c12448c31b429e0861aae4bc2f7136299cfc2/vgi_rpc-0.43.2.tar.gz", hash = "sha256:6a06437af17442451bfe07186bc472a2efb57e030b0e5b38a28922034a814123", size = 1147340, upload-time = "2026-08-27T18:33:54.608Z" }
2727
+ sdist = { url = "https://files.pythonhosted.org/packages/1a/16/5a78053080117cac00a8945b70298d636a63d57801a33528bb63b14cdd95/vgi_rpc-0.44.1.tar.gz", hash = "sha256:37a54ae2cb7e5a7a2603aad69ece92c3c99a96906c96d2196806202ee4b70825", size = 1170809, upload-time = "2026-08-28T15:03:07.221Z" }
2728
2728
  wheels = [
2729
- { url = "https://files.pythonhosted.org/packages/ac/b9/33cdb4fe27ef3893e1cded63f396af8bc517e390615f34db6f4bd227ef4c/vgi_rpc-0.43.2-py3-none-any.whl", hash = "sha256:b112ab76828367176a41f1b9a4ceeaba8979629e4e5972f64bf769c94b3e36a4", size = 528134, upload-time = "2026-08-27T18:33:52.829Z" },
2729
+ { url = "https://files.pythonhosted.org/packages/8f/d6/3bfff42bd723ffcd0c2550d932e766aa65d39a886017cb9c002174e68196/vgi_rpc-0.44.1-py3-none-any.whl", hash = "sha256:e9785753bdb30e3f07f2bdbeafcddd09533cc014baa310e093a94fdeda6ad517", size = 545257, upload-time = "2026-08-28T15:03:05.268Z" },
2730
2730
  ]
2731
2731
 
2732
2732
  [package.optional-dependencies]
@@ -424,6 +424,11 @@ class Client(CatalogClientMixin, AggregateClientMixin):
424
424
  tcp_host: str | None = None,
425
425
  tcp_port: int | None = None,
426
426
  bearer_token: str | None = None,
427
+ oauth: bool = False,
428
+ oauth_refresh_token: str | None = None,
429
+ oauth_flow: Literal["auto", "device_code", "pkce"] = "auto",
430
+ oauth_timeout_seconds: float = 120.0,
431
+ oauth_prompt: Literal["none", "login", "select_account", "consent"] = "none",
427
432
  httpx_client: Any | None = None,
428
433
  external_location: Any | None = None,
429
434
  launch_argv: Sequence[str] | None = None,
@@ -472,12 +477,38 @@ class Client(CatalogClientMixin, AggregateClientMixin):
472
477
  ``"http://127.0.0.1:8765"``.
473
478
  tcp_host: TCP-only. Hostname or IP of the running worker.
474
479
  tcp_port: TCP-only. Port of the running worker.
475
- bearer_token: HTTP-only. When set, every request carries an
476
- ``Authorization: Bearer <token>`` header. Static token
477
- support onlyno JWT / OAuth flows.
480
+ bearer_token: HTTP-only. When set, every request carries a
481
+ static ``Authorization: Bearer <token>`` header. Mutually
482
+ exclusive with ``oauth``/``oauth_refresh_token`` for a
483
+ token that expires or needs a login flow, use those instead.
484
+ oauth: HTTP-only. When True, obtain and refresh bearer tokens
485
+ automatically via OAuth (device-code today; PKCE is not yet
486
+ implemented — see ``oauth_flow``) whenever the worker
487
+ answers 401 with an RFC 9728 challenge. Implied by passing
488
+ ``oauth_refresh_token``. The first call blocks and prints a
489
+ "Visit: ... Enter code: ..." prompt until login completes;
490
+ later calls reuse the cached token and refresh it silently.
491
+ See ``vgi_rpc.http.VgiOAuthAuth`` for the full mechanism
492
+ (RFC 8628 device-code polling, RFC 8414/9728 discovery,
493
+ silent refresh, the secret-less-proxy ``token_endpoint``
494
+ override).
495
+ oauth_refresh_token: HTTP-only. Pre-obtained refresh token,
496
+ seeded so the first request can silently refresh instead of
497
+ running an interactive login. Implies ``oauth=True``.
498
+ Mutually exclusive with ``bearer_token``.
499
+ oauth_flow: HTTP-only, OAuth-only. ``"auto"`` (default) picks
500
+ device-code when the server offers it; ``"device_code"``
501
+ forces it; ``"pkce"`` is not yet implemented and raises
502
+ ``NotImplementedError`` when actually needed.
503
+ oauth_timeout_seconds: HTTP-only, OAuth-only. How long an
504
+ interactive login may take before giving up (further capped
505
+ by the authorization server's own device-code expiry).
506
+ oauth_prompt: HTTP-only, OAuth-only. Reserved for the PKCE flow
507
+ (not yet implemented); has no effect on device-code logins.
478
508
  httpx_client: HTTP-only escape hatch. When provided, overrides
479
- ``bearer_token`` and is used verbatim; supply this when you
480
- need mTLS or a custom auth scheme. Not the canonical path.
509
+ ``bearer_token``/``oauth``/``oauth_refresh_token`` and is
510
+ used verbatim; supply this when you need mTLS or a custom
511
+ auth scheme. Not the canonical path.
481
512
  external_location: HTTP-only. ``ExternalLocationConfig`` that
482
513
  controls how the client fetches pointer batches (workers
483
514
  that externalize large outputs via demo storage / S3 return
@@ -535,12 +566,36 @@ class Client(CatalogClientMixin, AggregateClientMixin):
535
566
  else:
536
567
  raise ValueError(f"unknown transport {transport!r}")
537
568
 
569
+ use_oauth = oauth or oauth_refresh_token is not None
570
+ if use_oauth and bearer_token is not None:
571
+ raise ValueError("bearer_token is mutually exclusive with oauth/oauth_refresh_token")
572
+ if use_oauth and httpx_client is not None:
573
+ raise ValueError(
574
+ "oauth/oauth_refresh_token is mutually exclusive with httpx_client "
575
+ "(the escape hatch is verbatim-or-nothing — build your own VgiOAuthAuth "
576
+ "and pass it as httpx_client=httpx2.Client(auth=...) instead)"
577
+ )
578
+ if oauth_flow not in ("auto", "device_code", "pkce"):
579
+ raise ValueError(f"oauth_flow must be 'auto', 'device_code', or 'pkce', got {oauth_flow!r}")
580
+ if oauth_prompt not in ("none", "login", "select_account", "consent"):
581
+ raise ValueError(
582
+ f"oauth_prompt must be 'none', 'login', 'select_account', or 'consent', got {oauth_prompt!r}"
583
+ )
584
+
538
585
  self.server_path: str | Sequence[str] = server_path if server_path is not None else ""
539
586
  self._transport = transport
540
587
  self._base_url = base_url
541
588
  self._tcp_host = tcp_host
542
589
  self._tcp_port = tcp_port
543
590
  self._bearer_token = bearer_token
591
+ self._use_oauth = use_oauth
592
+ self._oauth_refresh_token = oauth_refresh_token
593
+ self._oauth_flow = oauth_flow
594
+ self._oauth_timeout_seconds = oauth_timeout_seconds
595
+ self._oauth_prompt = oauth_prompt
596
+ # Built lazily by _get_or_create_httpx_client when self._use_oauth; None otherwise
597
+ # (including when the caller supplied httpx_client= directly, which owns its own auth).
598
+ self._oauth_auth: Any | None = None
544
599
  self._httpx_client = httpx_client
545
600
  self._launch_argv = tuple(launch_argv) if launch_argv is not None else None
546
601
  self._launch_idle_timeout = launch_idle_timeout
@@ -581,6 +636,11 @@ class Client(CatalogClientMixin, AggregateClientMixin):
581
636
  base_url: str,
582
637
  *,
583
638
  bearer_token: str | None = None,
639
+ oauth: bool = False,
640
+ oauth_refresh_token: str | None = None,
641
+ oauth_flow: Literal["auto", "device_code", "pkce"] = "auto",
642
+ oauth_timeout_seconds: float = 120.0,
643
+ oauth_prompt: Literal["none", "login", "select_account", "consent"] = "none",
584
644
  httpx_client: Any | None = None,
585
645
  external_location: Any | None = None,
586
646
  worker_limit: int | None = None,
@@ -590,12 +650,18 @@ class Client(CatalogClientMixin, AggregateClientMixin):
590
650
 
591
651
  Canonical entry point for non-DuckDB callers (e.g. a TypeScript port
592
652
  browsing catalog contents). Subprocess-specific kwargs are not
593
- accepted; pool/stderr semantics do not apply.
653
+ accepted; pool/stderr semantics do not apply. See `[`Client.__init__`][]`
654
+ for what ``oauth``/``oauth_refresh_token``/``oauth_flow`` do.
594
655
  """
595
656
  return cls(
596
657
  transport="http",
597
658
  base_url=base_url,
598
659
  bearer_token=bearer_token,
660
+ oauth=oauth,
661
+ oauth_refresh_token=oauth_refresh_token,
662
+ oauth_flow=oauth_flow,
663
+ oauth_timeout_seconds=oauth_timeout_seconds,
664
+ oauth_prompt=oauth_prompt,
599
665
  httpx_client=httpx_client,
600
666
  external_location=external_location,
601
667
  worker_limit=worker_limit,
@@ -882,23 +948,39 @@ class Client(CatalogClientMixin, AggregateClientMixin):
882
948
  """Return the shared httpx2.Client for this Client's HTTP transport.
883
949
 
884
950
  Lazily constructs one bound to ``self._base_url`` (so RPC requests
885
- resolve against the remote worker) with an ``Authorization: Bearer
886
- <token>`` header when ``bearer_token`` was supplied. When the
887
- caller passes ``httpx_client=`` directly, they're responsible for
888
- configuring ``base_url`` and auth on itwe use it verbatim.
951
+ resolve against the remote worker) with either a static
952
+ ``Authorization: Bearer <token>`` header (``bearer_token``) or a
953
+ ``VgiOAuthAuth`` (``oauth``/``oauth_refresh_token``) that obtains and
954
+ refreshes tokens on demandnever both, enforced at construction.
955
+ When the caller passes ``httpx_client=`` directly, they're
956
+ responsible for configuring ``base_url`` and auth on it — we use it
957
+ verbatim.
889
958
  """
890
959
  if self._httpx_client is not None:
891
960
  return self._httpx_client
892
961
 
893
962
  import httpx2
894
963
 
964
+ auth = None
895
965
  headers: dict[str, str] = {}
896
- if self._bearer_token is not None:
966
+ if self._use_oauth:
967
+ from vgi_rpc.http import VgiOAuthAuth
968
+
969
+ self._oauth_auth = VgiOAuthAuth(
970
+ base_url=self._base_url or "",
971
+ flow=self._oauth_flow,
972
+ refresh_token=self._oauth_refresh_token,
973
+ timeout_seconds=self._oauth_timeout_seconds,
974
+ prompt=self._oauth_prompt,
975
+ )
976
+ auth = self._oauth_auth
977
+ elif self._bearer_token is not None:
897
978
  headers["Authorization"] = f"Bearer {self._bearer_token}"
898
979
  self._httpx_client = httpx2.Client(
899
980
  base_url=self._base_url or "",
900
981
  follow_redirects=True,
901
982
  headers=headers,
983
+ auth=auth,
902
984
  # httpx2's 5s default read timeout is too aggressive for RPC
903
985
  # calls that do real server-side work (scans, cold workers).
904
986
  timeout=httpx2.Timeout(60.0, connect=10.0),
@@ -906,6 +988,19 @@ class Client(CatalogClientMixin, AggregateClientMixin):
906
988
  self._httpx_client_owned = True
907
989
  return self._httpx_client
908
990
 
991
+ def oauth_identity(self) -> Any | None:
992
+ """Return the signed-in OAuth identity's parsed id_token claims.
993
+
994
+ Returns ``None`` when this client isn't using OAuth, or hasn't
995
+ completed a login yet (the identity is only known once a real
996
+ exchange has happened — calling this before the first request
997
+ never triggers one). See ``vgi_rpc.http.OAuthIdentity`` for the
998
+ fields (``sub``/``email``/``name``/``issuer``/``claims``).
999
+ """
1000
+ if self._oauth_auth is None:
1001
+ return None
1002
+ return self._oauth_auth.identity()
1003
+
909
1004
  def _spawn_subprocess_connection(self, worker_index: int) -> WorkerConnection:
910
1005
  """Spawn or borrow a subprocess worker and wrap it in an RPC proxy.
911
1006
 
@@ -1214,6 +1309,12 @@ class Client(CatalogClientMixin, AggregateClientMixin):
1214
1309
  finally:
1215
1310
  self._httpx_client = None
1216
1311
  self._httpx_client_owned = False
1312
+ # Close VgiOAuthAuth's own internal (unauthenticated) flow client, if one was built.
1313
+ if self._oauth_auth is not None:
1314
+ try:
1315
+ self._oauth_auth.close()
1316
+ finally:
1317
+ self._oauth_auth = None
1217
1318
 
1218
1319
  return returncode
1219
1320
 
@@ -1915,6 +2016,7 @@ class Client(CatalogClientMixin, AggregateClientMixin):
1915
2016
  settings: dict[str, Any] | None = None,
1916
2017
  transaction_opaque_data: bytes | None = None,
1917
2018
  parent_row_callback: Callable[[list[int]], None] | None = None,
2019
+ has_finalize: bool = True,
1918
2020
  ) -> Generator[pa.RecordBatch]:
1919
2021
  """Invoke a table-in-out function on the worker and stream results.
1920
2022
 
@@ -1956,6 +2058,20 @@ class Client(CatalogClientMixin, AggregateClientMixin):
1956
2058
  `FunctionInfo.input_from_args`); leave unset for ordinary
1957
2059
  table-in-out functions, which have no provenance concept and
1958
2060
  may legitimately change row count.
2061
+ has_finalize: Whether this function declares a FINALIZE stage
2062
+ (`FunctionInfo.has_finalize`). Defaults to `True` — every
2063
+ caller before this parameter existed got a FINALIZE-phase
2064
+ `init()` unconditionally, so this preserves that exactly.
2065
+ Pass `False` for a function known to have no finalize (every
2066
+ blended `RowTransformFunction` — `has_finalize` is always
2067
+ false for those, enforced at `resolve_metadata()`) to skip
2068
+ the FINALIZE `init()` entirely, not just send one expecting
2069
+ an empty reply. Confirmed load-bearing, not cosmetic: some
2070
+ worker SDKs (e.g. the TypeScript one) actively reject an
2071
+ unexpected FINALIZE `init()` for a function that never
2072
+ advertised `has_finalize`, rather than silently no-op'ing
2073
+ it — the C++ DuckDB extension avoids this the same way, by
2074
+ conditionally registering `in_out_function_final` at all.
1959
2075
 
1960
2076
  Yields:
1961
2077
  Output `RecordBatch`es from the function. In single-worker mode, output
@@ -2019,7 +2135,14 @@ class Client(CatalogClientMixin, AggregateClientMixin):
2019
2135
  # Close secondary workers
2020
2136
  self._close_secondary_workers()
2021
2137
 
2022
- # Finalize on primary worker
2138
+ # Finalize on primary worker — skipped entirely (not just
2139
+ # sent expecting an empty reply) when the function has no
2140
+ # finalize stage. See has_finalize's docstring: some worker
2141
+ # SDKs reject an unadvertised FINALIZE init() outright.
2142
+ if not has_finalize:
2143
+ _logger.debug("skipping_finalize_no_finalize_stage")
2144
+ return
2145
+
2023
2146
  _logger.debug("finalizing_primary_worker")
2024
2147
  yield from self._finalize_primary_worker(
2025
2148
  bind_request,
@@ -513,7 +513,7 @@ def main() -> None:
513
513
  "--exception-include",
514
514
  default='"duckdb/common/exception.hpp"',
515
515
  help=(
516
- "#include directive (with its own <> or \"\") for the exception "
516
+ '#include directive (with its own <> or "") for the exception '
517
517
  "type named by --exception-type (default: "
518
518
  '"duckdb/common/exception.hpp"). E.g. <stdexcept> for '
519
519
  "std::runtime_error."