vgi-python 0.29.6__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.6 → vgi_python-0.30.0}/PKG-INFO +2 -2
  2. {vgi_python-0.29.6 → vgi_python-0.30.0}/pyproject.toml +2 -2
  3. {vgi_python-0.29.6 → vgi_python-0.30.0}/tests/client/test_batch_metadata_callback.py +1 -1
  4. {vgi_python-0.29.6 → vgi_python-0.30.0}/tests/client/test_scan_branches_client.py +8 -5
  5. {vgi_python-0.29.6 → vgi_python-0.30.0}/tests/client/test_time_travel_client.py +1 -1
  6. vgi_python-0.30.0/tests/test_client_oauth.py +204 -0
  7. {vgi_python-0.29.6 → vgi_python-0.30.0}/uv.lock +5 -5
  8. {vgi_python-0.29.6 → vgi_python-0.30.0}/vgi/client/client.py +112 -11
  9. {vgi_python-0.29.6 → vgi_python-0.30.0}/vgi/codegen/cpp_request_builders.py +1 -1
  10. {vgi_python-0.29.6 → vgi_python-0.30.0}/vgi/worker.py +44 -15
  11. {vgi_python-0.29.6 → vgi_python-0.30.0}/.gitattributes +0 -0
  12. {vgi_python-0.29.6 → vgi_python-0.30.0}/.github/dependabot.yml +0 -0
  13. {vgi_python-0.29.6 → vgi_python-0.30.0}/.github/styles/config/vocabularies/VGI/accept.txt +0 -0
  14. {vgi_python-0.29.6 → vgi_python-0.30.0}/.github/workflows/ci.yml +0 -0
  15. {vgi_python-0.29.6 → vgi_python-0.30.0}/.github/workflows/docs.yml +0 -0
  16. {vgi_python-0.29.6 → vgi_python-0.30.0}/.github/workflows/integration.yml +0 -0
  17. {vgi_python-0.29.6 → vgi_python-0.30.0}/.github/workflows/release.yml +0 -0
  18. {vgi_python-0.29.6 → vgi_python-0.30.0}/.gitignore +0 -0
  19. {vgi_python-0.29.6 → vgi_python-0.30.0}/.python-version +0 -0
  20. {vgi_python-0.29.6 → vgi_python-0.30.0}/.vale.ini +0 -0
  21. {vgi_python-0.29.6 → vgi_python-0.30.0}/CLAUDE.md +0 -0
  22. {vgi_python-0.29.6 → vgi_python-0.30.0}/DOCS_ACCEPTANCE_CRITERIA.md +0 -0
  23. {vgi_python-0.29.6 → vgi_python-0.30.0}/DOCS_REVIEW_RUBRIC.md +0 -0
  24. {vgi_python-0.29.6 → vgi_python-0.30.0}/DOCS_USABILITY_TEST.md +0 -0
  25. {vgi_python-0.29.6 → vgi_python-0.30.0}/LICENSE +0 -0
  26. {vgi_python-0.29.6 → vgi_python-0.30.0}/README.md +0 -0
  27. {vgi_python-0.29.6 → vgi_python-0.30.0}/RELEASE-RUNBOOK.md +0 -0
  28. {vgi_python-0.29.6 → vgi_python-0.30.0}/SECURITY.md +0 -0
  29. {vgi_python-0.29.6 → vgi_python-0.30.0}/ci/README.md +0 -0
  30. {vgi_python-0.29.6 → vgi_python-0.30.0}/ci/preprocess-require.awk +0 -0
  31. {vgi_python-0.29.6 → vgi_python-0.30.0}/ci/run-integration.sh +0 -0
  32. {vgi_python-0.29.6 → vgi_python-0.30.0}/dist-vgi/.gitignore +0 -0
  33. {vgi_python-0.29.6 → vgi_python-0.30.0}/docs/aggregate-functions.md +0 -0
  34. {vgi_python-0.29.6 → vgi_python-0.30.0}/docs/api/arguments.md +0 -0
  35. {vgi_python-0.29.6 → vgi_python-0.30.0}/docs/api/auth.md +0 -0
  36. {vgi_python-0.29.6 → vgi_python-0.30.0}/docs/api/catalogs.md +0 -0
  37. {vgi_python-0.29.6 → vgi_python-0.30.0}/docs/api/client.md +0 -0
  38. {vgi_python-0.29.6 → vgi_python-0.30.0}/docs/api/exceptions.md +0 -0
  39. {vgi_python-0.29.6 → vgi_python-0.30.0}/docs/api/filters.md +0 -0
  40. {vgi_python-0.29.6 → vgi_python-0.30.0}/docs/api/functions.md +0 -0
  41. {vgi_python-0.29.6 → vgi_python-0.30.0}/docs/api/http.md +0 -0
  42. {vgi_python-0.29.6 → vgi_python-0.30.0}/docs/api/index.md +0 -0
  43. {vgi_python-0.29.6 → vgi_python-0.30.0}/docs/api/metadata.md +0 -0
  44. {vgi_python-0.29.6 → vgi_python-0.30.0}/docs/api/observability.md +0 -0
  45. {vgi_python-0.29.6 → vgi_python-0.30.0}/docs/api/storage.md +0 -0
  46. {vgi_python-0.29.6 → vgi_python-0.30.0}/docs/api/transactor.md +0 -0
  47. {vgi_python-0.29.6 → vgi_python-0.30.0}/docs/api/worker.md +0 -0
  48. {vgi_python-0.29.6 → vgi_python-0.30.0}/docs/argument-serialization.md +0 -0
  49. {vgi_python-0.29.6 → vgi_python-0.30.0}/docs/assets/apple-touch-icon.png +0 -0
  50. {vgi_python-0.29.6 → vgi_python-0.30.0}/docs/assets/favicon-16x16.png +0 -0
  51. {vgi_python-0.29.6 → vgi_python-0.30.0}/docs/assets/favicon-32x32.png +0 -0
  52. {vgi_python-0.29.6 → vgi_python-0.30.0}/docs/assets/favicon.ico +0 -0
  53. {vgi_python-0.29.6 → vgi_python-0.30.0}/docs/assets/kinds/aggregate.svg +0 -0
  54. {vgi_python-0.29.6 → vgi_python-0.30.0}/docs/assets/kinds/buffering.svg +0 -0
  55. {vgi_python-0.29.6 → vgi_python-0.30.0}/docs/assets/kinds/scalar.svg +0 -0
  56. {vgi_python-0.29.6 → vgi_python-0.30.0}/docs/assets/kinds/table-in-out.svg +0 -0
  57. {vgi_python-0.29.6 → vgi_python-0.30.0}/docs/assets/kinds/table.svg +0 -0
  58. {vgi_python-0.29.6 → vgi_python-0.30.0}/docs/assets/logo.png +0 -0
  59. {vgi_python-0.29.6 → vgi_python-0.30.0}/docs/assets/social-card.png +0 -0
  60. {vgi_python-0.29.6 → vgi_python-0.30.0}/docs/authentication.md +0 -0
  61. {vgi_python-0.29.6 → vgi_python-0.30.0}/docs/catalog-interface.md +0 -0
  62. {vgi_python-0.29.6 → vgi_python-0.30.0}/docs/cli.md +0 -0
  63. {vgi_python-0.29.6 → vgi_python-0.30.0}/docs/column-statistics.md +0 -0
  64. {vgi_python-0.29.6 → vgi_python-0.30.0}/docs/concepts/index.md +0 -0
  65. {vgi_python-0.29.6 → vgi_python-0.30.0}/docs/contributing-docs.md +0 -0
  66. {vgi_python-0.29.6 → vgi_python-0.30.0}/docs/filter-pushdown.md +0 -0
  67. {vgi_python-0.29.6 → vgi_python-0.30.0}/docs/generator-api.md +0 -0
  68. {vgi_python-0.29.6 → vgi_python-0.30.0}/docs/global-functions.md +0 -0
  69. {vgi_python-0.29.6 → vgi_python-0.30.0}/docs/how-to/catalogs.md +0 -0
  70. {vgi_python-0.29.6 → vgi_python-0.30.0}/docs/how-to/function-patterns.md +0 -0
  71. {vgi_python-0.29.6 → vgi_python-0.30.0}/docs/how-to/http-auth.md +0 -0
  72. {vgi_python-0.29.6 → vgi_python-0.30.0}/docs/how-to/index.md +0 -0
  73. {vgi_python-0.29.6 → vgi_python-0.30.0}/docs/how-to/pushdown-and-statistics.md +0 -0
  74. {vgi_python-0.29.6 → vgi_python-0.30.0}/docs/how-to/state-storage.md +0 -0
  75. {vgi_python-0.29.6 → vgi_python-0.30.0}/docs/index.md +0 -0
  76. {vgi_python-0.29.6 → vgi_python-0.30.0}/docs/lifecycle.md +0 -0
  77. {vgi_python-0.29.6 → vgi_python-0.30.0}/docs/metadata.md +0 -0
  78. {vgi_python-0.29.6 → vgi_python-0.30.0}/docs/overrides/main.html +0 -0
  79. {vgi_python-0.29.6 → vgi_python-0.30.0}/docs/robots.txt +0 -0
  80. {vgi_python-0.29.6 → vgi_python-0.30.0}/docs/shared-storage.md +0 -0
  81. {vgi_python-0.29.6 → vgi_python-0.30.0}/docs/stylesheets/extra.css +0 -0
  82. {vgi_python-0.29.6 → vgi_python-0.30.0}/docs/tutorial/index.md +0 -0
  83. {vgi_python-0.29.6 → vgi_python-0.30.0}/docs/tutorial/scalar.md +0 -0
  84. {vgi_python-0.29.6 → vgi_python-0.30.0}/docs/tutorial/table.md +0 -0
  85. {vgi_python-0.29.6 → vgi_python-0.30.0}/docs/vgi-logo.png +0 -0
  86. {vgi_python-0.29.6 → vgi_python-0.30.0}/examples/batch_index_worker.py +0 -0
  87. {vgi_python-0.29.6 → vgi_python-0.30.0}/examples/cache_worker.py +0 -0
  88. {vgi_python-0.29.6 → vgi_python-0.30.0}/examples/calc_scalar_worker.py +0 -0
  89. {vgi_python-0.29.6 → vgi_python-0.30.0}/examples/calc_worker.py +0 -0
  90. {vgi_python-0.29.6 → vgi_python-0.30.0}/examples/copy_format_worker.py +0 -0
  91. {vgi_python-0.29.6 → vgi_python-0.30.0}/examples/filter_worker.py +0 -0
  92. {vgi_python-0.29.6 → vgi_python-0.30.0}/examples/greeting_scalar_worker.py +0 -0
  93. {vgi_python-0.29.6 → vgi_python-0.30.0}/examples/row_count_worker.py +0 -0
  94. {vgi_python-0.29.6 → vgi_python-0.30.0}/examples/series_streaming_worker.py +0 -0
  95. {vgi_python-0.29.6 → vgi_python-0.30.0}/examples/sum_worker.py +0 -0
  96. {vgi_python-0.29.6 → vgi_python-0.30.0}/mkdocs.yml +0 -0
  97. {vgi_python-0.29.6 → vgi_python-0.30.0}/packages/vgi-fixtures/LICENSE +0 -0
  98. {vgi_python-0.29.6 → vgi_python-0.30.0}/packages/vgi-fixtures/README.md +0 -0
  99. {vgi_python-0.29.6 → vgi_python-0.30.0}/packages/vgi-fixtures/docker/Dockerfile +0 -0
  100. {vgi_python-0.29.6 → vgi_python-0.30.0}/packages/vgi-fixtures/docker/docker-entrypoint.sh +0 -0
  101. {vgi_python-0.29.6 → vgi_python-0.30.0}/packages/vgi-fixtures/pyproject.toml +0 -0
  102. {vgi_python-0.29.6 → vgi_python-0.30.0}/scripts/measure_startup.py +0 -0
  103. {vgi_python-0.29.6 → vgi_python-0.30.0}/scripts/run_all_tests.sh +0 -0
  104. {vgi_python-0.29.6 → vgi_python-0.30.0}/test-data/generate.sh +0 -0
  105. {vgi_python-0.29.6 → vgi_python-0.30.0}/tests/__init__.py +0 -0
  106. {vgi_python-0.29.6 → vgi_python-0.30.0}/tests/_http_fixtures.py +0 -0
  107. {vgi_python-0.29.6 → vgi_python-0.30.0}/tests/catalog/__init__.py +0 -0
  108. {vgi_python-0.29.6 → vgi_python-0.30.0}/tests/catalog/test_attach_option.py +0 -0
  109. {vgi_python-0.29.6 → vgi_python-0.30.0}/tests/catalog/test_catalog_interface.py +0 -0
  110. {vgi_python-0.29.6 → vgi_python-0.30.0}/tests/catalog/test_client_catalog.py +0 -0
  111. {vgi_python-0.29.6 → vgi_python-0.30.0}/tests/catalog/test_column_statistics.py +0 -0
  112. {vgi_python-0.29.6 → vgi_python-0.30.0}/tests/catalog/test_declarative.py +0 -0
  113. {vgi_python-0.29.6 → vgi_python-0.30.0}/tests/catalog/test_example_worker_catalog.py +0 -0
  114. {vgi_python-0.29.6 → vgi_python-0.30.0}/tests/catalog/test_integration.py +0 -0
  115. {vgi_python-0.29.6 → vgi_python-0.30.0}/tests/catalog/test_required_filters.py +0 -0
  116. {vgi_python-0.29.6 → vgi_python-0.30.0}/tests/catalog/test_scan_branches.py +0 -0
  117. {vgi_python-0.29.6 → vgi_python-0.30.0}/tests/catalog/test_serialization.py +0 -0
  118. {vgi_python-0.29.6 → vgi_python-0.30.0}/tests/catalog/test_setting.py +0 -0
  119. {vgi_python-0.29.6 → vgi_python-0.30.0}/tests/catalog/test_storage.py +0 -0
  120. {vgi_python-0.29.6 → vgi_python-0.30.0}/tests/catalog/test_time_travel.py +0 -0
  121. {vgi_python-0.29.6 → vgi_python-0.30.0}/tests/catalog/test_writable_table.py +0 -0
  122. {vgi_python-0.29.6 → vgi_python-0.30.0}/tests/client/__init__.py +0 -0
  123. {vgi_python-0.29.6 → vgi_python-0.30.0}/tests/client/test_aggregate_client.py +0 -0
  124. {vgi_python-0.29.6 → vgi_python-0.30.0}/tests/client/test_broken_pipe.py +0 -0
  125. {vgi_python-0.29.6 → vgi_python-0.30.0}/tests/client/test_cli.py +0 -0
  126. {vgi_python-0.29.6 → vgi_python-0.30.0}/tests/client/test_cli_catalog_functions.py +0 -0
  127. {vgi_python-0.29.6 → vgi_python-0.30.0}/tests/client/test_copy_client.py +0 -0
  128. {vgi_python-0.29.6 → vgi_python-0.30.0}/tests/client/test_split_client.py +0 -0
  129. {vgi_python-0.29.6 → vgi_python-0.30.0}/tests/client/test_stop_force.py +0 -0
  130. {vgi_python-0.29.6 → vgi_python-0.30.0}/tests/client/test_table_column_statistics.py +0 -0
  131. {vgi_python-0.29.6 → vgi_python-0.30.0}/tests/client/test_worker_debug.py +0 -0
  132. {vgi_python-0.29.6 → vgi_python-0.30.0}/tests/conformance/__init__.py +0 -0
  133. {vgi_python-0.29.6 → vgi_python-0.30.0}/tests/conformance/_stub.py +0 -0
  134. {vgi_python-0.29.6 → vgi_python-0.30.0}/tests/conformance/conftest.py +0 -0
  135. {vgi_python-0.29.6 → vgi_python-0.30.0}/tests/conformance/test_accumulate.py +0 -0
  136. {vgi_python-0.29.6 → vgi_python-0.30.0}/tests/conformance/test_aggregate.py +0 -0
  137. {vgi_python-0.29.6 → vgi_python-0.30.0}/tests/conformance/test_attach.py +0 -0
  138. {vgi_python-0.29.6 → vgi_python-0.30.0}/tests/conformance/test_bearer_auth.py +0 -0
  139. {vgi_python-0.29.6 → vgi_python-0.30.0}/tests/conformance/test_const_param_enforcement.py +0 -0
  140. {vgi_python-0.29.6 → vgi_python-0.30.0}/tests/conformance/test_container.py +0 -0
  141. {vgi_python-0.29.6 → vgi_python-0.30.0}/tests/conformance/test_copy_from.py +0 -0
  142. {vgi_python-0.29.6 → vgi_python-0.30.0}/tests/conformance/test_copy_to.py +0 -0
  143. {vgi_python-0.29.6 → vgi_python-0.30.0}/tests/conformance/test_directory_parity.py +0 -0
  144. {vgi_python-0.29.6 → vgi_python-0.30.0}/tests/conformance/test_function_inventory.py +0 -0
  145. {vgi_python-0.29.6 → vgi_python-0.30.0}/tests/conformance/test_github.py +0 -0
  146. {vgi_python-0.29.6 → vgi_python-0.30.0}/tests/conformance/test_http_client.py +0 -0
  147. {vgi_python-0.29.6 → vgi_python-0.30.0}/tests/conformance/test_http_external_location.py +0 -0
  148. {vgi_python-0.29.6 → vgi_python-0.30.0}/tests/conformance/test_http_upload_url.py +0 -0
  149. {vgi_python-0.29.6 → vgi_python-0.30.0}/tests/conformance/test_macro.py +0 -0
  150. {vgi_python-0.29.6 → vgi_python-0.30.0}/tests/conformance/test_overload.py +0 -0
  151. {vgi_python-0.29.6 → vgi_python-0.30.0}/tests/conformance/test_protocol_inventory.py +0 -0
  152. {vgi_python-0.29.6 → vgi_python-0.30.0}/tests/conformance/test_protocol_version.py +0 -0
  153. {vgi_python-0.29.6 → vgi_python-0.30.0}/tests/conformance/test_resumable_scan.py +0 -0
  154. {vgi_python-0.29.6 → vgi_python-0.30.0}/tests/conformance/test_scalar.py +0 -0
  155. {vgi_python-0.29.6 → vgi_python-0.30.0}/tests/conformance/test_scalar_attach_opaque_data.py +0 -0
  156. {vgi_python-0.29.6 → vgi_python-0.30.0}/tests/conformance/test_secret.py +0 -0
  157. {vgi_python-0.29.6 → vgi_python-0.30.0}/tests/conformance/test_settings.py +0 -0
  158. {vgi_python-0.29.6 → vgi_python-0.30.0}/tests/conformance/test_splits.py +0 -0
  159. {vgi_python-0.29.6 → vgi_python-0.30.0}/tests/conformance/test_table.py +0 -0
  160. {vgi_python-0.29.6 → vgi_python-0.30.0}/tests/conformance/test_table_in_out.py +0 -0
  161. {vgi_python-0.29.6 → vgi_python-0.30.0}/tests/conformance/test_view.py +0 -0
  162. {vgi_python-0.29.6 → vgi_python-0.30.0}/tests/conformance/test_writable.py +0 -0
  163. {vgi_python-0.29.6 → vgi_python-0.30.0}/tests/conftest.py +0 -0
  164. {vgi_python-0.29.6 → vgi_python-0.30.0}/tests/data/split_tokens/anchor_len_overrun.bin +0 -0
  165. {vgi_python-0.29.6 → vgi_python-0.30.0}/tests/data/split_tokens/bad_fingerprint.bin +0 -0
  166. {vgi_python-0.29.6 → vgi_python-0.30.0}/tests/data/split_tokens/bad_flags_unsealed_but_key_present.bin +0 -0
  167. {vgi_python-0.29.6 → vgi_python-0.30.0}/tests/data/split_tokens/bad_version.bin +0 -0
  168. {vgi_python-0.29.6 → vgi_python-0.30.0}/tests/data/split_tokens/generate.py +0 -0
  169. {vgi_python-0.29.6 → vgi_python-0.30.0}/tests/data/split_tokens/manifest.json +0 -0
  170. {vgi_python-0.29.6 → vgi_python-0.30.0}/tests/data/split_tokens/reserved_flag_bit.bin +0 -0
  171. {vgi_python-0.29.6 → vgi_python-0.30.0}/tests/data/split_tokens/stale_anchor.bin +0 -0
  172. {vgi_python-0.29.6 → vgi_python-0.30.0}/tests/data/split_tokens/truncated.bin +0 -0
  173. {vgi_python-0.29.6 → vgi_python-0.30.0}/tests/data/split_tokens/valid_sealed.bin +0 -0
  174. {vgi_python-0.29.6 → vgi_python-0.30.0}/tests/data/split_tokens/valid_unsealed.bin +0 -0
  175. {vgi_python-0.29.6 → vgi_python-0.30.0}/tests/scalar/__init__.py +0 -0
  176. {vgi_python-0.29.6 → vgi_python-0.30.0}/tests/scalar/test_bernoulli_function.py +0 -0
  177. {vgi_python-0.29.6 → vgi_python-0.30.0}/tests/scalar/test_binary_packet_function.py +0 -0
  178. {vgi_python-0.29.6 → vgi_python-0.30.0}/tests/scalar/test_client.py +0 -0
  179. {vgi_python-0.29.6 → vgi_python-0.30.0}/tests/scalar/test_conditional_message_function.py +0 -0
  180. {vgi_python-0.29.6 → vgi_python-0.30.0}/tests/scalar/test_hash_seed_function.py +0 -0
  181. {vgi_python-0.29.6 → vgi_python-0.30.0}/tests/scalar/test_multiply_by_setting_function.py +0 -0
  182. {vgi_python-0.29.6 → vgi_python-0.30.0}/tests/scalar/test_multiply_function.py +0 -0
  183. {vgi_python-0.29.6 → vgi_python-0.30.0}/tests/scalar/test_random_bytes_function.py +0 -0
  184. {vgi_python-0.29.6 → vgi_python-0.30.0}/tests/scalar/test_return_secret_value_function.py +0 -0
  185. {vgi_python-0.29.6 → vgi_python-0.30.0}/tests/table/__init__.py +0 -0
  186. {vgi_python-0.29.6 → vgi_python-0.30.0}/tests/table/generator/__init__.py +0 -0
  187. {vgi_python-0.29.6 → vgi_python-0.30.0}/tests/table/generator/test_constant_columns_function.py +0 -0
  188. {vgi_python-0.29.6 → vgi_python-0.30.0}/tests/table/generator/test_double_sequence_function.py +0 -0
  189. {vgi_python-0.29.6 → vgi_python-0.30.0}/tests/table/generator/test_exception_function.py +0 -0
  190. {vgi_python-0.29.6 → vgi_python-0.30.0}/tests/table/generator/test_filter_echo_function.py +0 -0
  191. {vgi_python-0.29.6 → vgi_python-0.30.0}/tests/table/generator/test_logging_function.py +0 -0
  192. {vgi_python-0.29.6 → vgi_python-0.30.0}/tests/table/generator/test_nested_sequence_function.py +0 -0
  193. {vgi_python-0.29.6 → vgi_python-0.30.0}/tests/table/generator/test_partitioned_function.py +0 -0
  194. {vgi_python-0.29.6 → vgi_python-0.30.0}/tests/table/generator/test_projected_data_function.py +0 -0
  195. {vgi_python-0.29.6 → vgi_python-0.30.0}/tests/table/generator/test_sequence_function.py +0 -0
  196. {vgi_python-0.29.6 → vgi_python-0.30.0}/tests/table/generator/test_settings_function.py +0 -0
  197. {vgi_python-0.29.6 → vgi_python-0.30.0}/tests/table/generator/test_struct_settings_function.py +0 -0
  198. {vgi_python-0.29.6 → vgi_python-0.30.0}/tests/table/generator/test_ten_thousand_function.py +0 -0
  199. {vgi_python-0.29.6 → vgi_python-0.30.0}/tests/table/test_wide_columns.py +0 -0
  200. {vgi_python-0.29.6 → vgi_python-0.30.0}/tests/table_in_out/__init__.py +0 -0
  201. {vgi_python-0.29.6 → vgi_python-0.30.0}/tests/table_in_out/generator/__init__.py +0 -0
  202. {vgi_python-0.29.6 → vgi_python-0.30.0}/tests/table_in_out/generator/test_buffer_input_function.py +0 -0
  203. {vgi_python-0.29.6 → vgi_python-0.30.0}/tests/table_in_out/generator/test_echo_function.py +0 -0
  204. {vgi_python-0.29.6 → vgi_python-0.30.0}/tests/table_in_out/generator/test_exception_functions.py +0 -0
  205. {vgi_python-0.29.6 → vgi_python-0.30.0}/tests/table_in_out/generator/test_filter_by_setting_function.py +0 -0
  206. {vgi_python-0.29.6 → vgi_python-0.30.0}/tests/table_in_out/generator/test_repeat_inputs_function.py +0 -0
  207. {vgi_python-0.29.6 → vgi_python-0.30.0}/tests/table_in_out/generator/test_substream_partial_sum_function.py +0 -0
  208. {vgi_python-0.29.6 → vgi_python-0.30.0}/tests/table_in_out/generator/test_sum_all_columns_function.py +0 -0
  209. {vgi_python-0.29.6 → vgi_python-0.30.0}/tests/table_in_out/test_blended_exchange.py +0 -0
  210. {vgi_python-0.29.6 → vgi_python-0.30.0}/tests/table_in_out/test_blended_metadata.py +0 -0
  211. {vgi_python-0.29.6 → vgi_python-0.30.0}/tests/table_in_out/test_client.py +0 -0
  212. {vgi_python-0.29.6 → vgi_python-0.30.0}/tests/test_access_log_audit.py +0 -0
  213. {vgi_python-0.29.6 → vgi_python-0.30.0}/tests/test_aggregate_function.py +0 -0
  214. {vgi_python-0.29.6 → vgi_python-0.30.0}/tests/test_argument_spec.py +0 -0
  215. {vgi_python-0.29.6 → vgi_python-0.30.0}/tests/test_auth.py +0 -0
  216. {vgi_python-0.29.6 → vgi_python-0.30.0}/tests/test_bind_exceptions.py +0 -0
  217. {vgi_python-0.29.6 → vgi_python-0.30.0}/tests/test_bind_request_at_clause.py +0 -0
  218. {vgi_python-0.29.6 → vgi_python-0.30.0}/tests/test_bound_storage_conformance.py +0 -0
  219. {vgi_python-0.29.6 → vgi_python-0.30.0}/tests/test_cache_control.py +0 -0
  220. {vgi_python-0.29.6 → vgi_python-0.30.0}/tests/test_call_state_attach.py +0 -0
  221. {vgi_python-0.29.6 → vgi_python-0.30.0}/tests/test_catalog_auth_binding.py +0 -0
  222. {vgi_python-0.29.6 → vgi_python-0.30.0}/tests/test_copy_from_function.py +0 -0
  223. {vgi_python-0.29.6 → vgi_python-0.30.0}/tests/test_copy_to_function.py +0 -0
  224. {vgi_python-0.29.6 → vgi_python-0.30.0}/tests/test_docstrings.py +0 -0
  225. {vgi_python-0.29.6 → vgi_python-0.30.0}/tests/test_documentation_examples.py +0 -0
  226. {vgi_python-0.29.6 → vgi_python-0.30.0}/tests/test_example_function_arg_types.py +0 -0
  227. {vgi_python-0.29.6 → vgi_python-0.30.0}/tests/test_examples_workers.py +0 -0
  228. {vgi_python-0.29.6 → vgi_python-0.30.0}/tests/test_exception_handling.py +0 -0
  229. {vgi_python-0.29.6 → vgi_python-0.30.0}/tests/test_exceptions.py +0 -0
  230. {vgi_python-0.29.6 → vgi_python-0.30.0}/tests/test_filter_pushdown.py +0 -0
  231. {vgi_python-0.29.6 → vgi_python-0.30.0}/tests/test_filter_pushdown_extension.py +0 -0
  232. {vgi_python-0.29.6 → vgi_python-0.30.0}/tests/test_fixture_catalog_parity.py +0 -0
  233. {vgi_python-0.29.6 → vgi_python-0.30.0}/tests/test_function_storage.py +0 -0
  234. {vgi_python-0.29.6 → vgi_python-0.30.0}/tests/test_function_storage_azure_sql.py +0 -0
  235. {vgi_python-0.29.6 → vgi_python-0.30.0}/tests/test_function_storage_cf_do.py +0 -0
  236. {vgi_python-0.29.6 → vgi_python-0.30.0}/tests/test_function_storage_cf_do_integration.py +0 -0
  237. {vgi_python-0.29.6 → vgi_python-0.30.0}/tests/test_function_storage_conformance.py +0 -0
  238. {vgi_python-0.29.6 → vgi_python-0.30.0}/tests/test_generated_cpp_constants.py +0 -0
  239. {vgi_python-0.29.6 → vgi_python-0.30.0}/tests/test_generated_cpp_protocol_version.py +0 -0
  240. {vgi_python-0.29.6 → vgi_python-0.30.0}/tests/test_generated_cpp_request_builders.py +0 -0
  241. {vgi_python-0.29.6 → vgi_python-0.30.0}/tests/test_generated_cpp_schemas.py +0 -0
  242. {vgi_python-0.29.6 → vgi_python-0.30.0}/tests/test_generated_cpp_secret.py +0 -0
  243. {vgi_python-0.29.6 → vgi_python-0.30.0}/tests/test_generated_go_schemas.py +0 -0
  244. {vgi_python-0.29.6 → vgi_python-0.30.0}/tests/test_generated_java_schemas.py +0 -0
  245. {vgi_python-0.29.6 → vgi_python-0.30.0}/tests/test_generated_protocol_version.py +0 -0
  246. {vgi_python-0.29.6 → vgi_python-0.30.0}/tests/test_generated_rust_request_builders.py +0 -0
  247. {vgi_python-0.29.6 → vgi_python-0.30.0}/tests/test_generated_rust_schemas.py +0 -0
  248. {vgi_python-0.29.6 → vgi_python-0.30.0}/tests/test_generated_schemas_cross_lang.py +0 -0
  249. {vgi_python-0.29.6 → vgi_python-0.30.0}/tests/test_generated_ts_client.py +0 -0
  250. {vgi_python-0.29.6 → vgi_python-0.30.0}/tests/test_generated_ts_schemas.py +0 -0
  251. {vgi_python-0.29.6 → vgi_python-0.30.0}/tests/test_http_demo_storage.py +0 -0
  252. {vgi_python-0.29.6 → vgi_python-0.30.0}/tests/test_http_s3_offload_input.py +0 -0
  253. {vgi_python-0.29.6 → vgi_python-0.30.0}/tests/test_http_s3_offload_output.py +0 -0
  254. {vgi_python-0.29.6 → vgi_python-0.30.0}/tests/test_launch_transport.py +0 -0
  255. {vgi_python-0.29.6 → vgi_python-0.30.0}/tests/test_metadata.py +0 -0
  256. {vgi_python-0.29.6 → vgi_python-0.30.0}/tests/test_mypy_consolidated.py +0 -0
  257. {vgi_python-0.29.6 → vgi_python-0.30.0}/tests/test_nest_tensor.py +0 -0
  258. {vgi_python-0.29.6 → vgi_python-0.30.0}/tests/test_otel.py +0 -0
  259. {vgi_python-0.29.6 → vgi_python-0.30.0}/tests/test_projection_enforcement.py +0 -0
  260. {vgi_python-0.29.6 → vgi_python-0.30.0}/tests/test_projection_repro.py +0 -0
  261. {vgi_python-0.29.6 → vgi_python-0.30.0}/tests/test_protocol_classes.py +0 -0
  262. {vgi_python-0.29.6 → vgi_python-0.30.0}/tests/test_resolved_secrets.py +0 -0
  263. {vgi_python-0.29.6 → vgi_python-0.30.0}/tests/test_schema_scoped_functions.py +0 -0
  264. {vgi_python-0.29.6 → vgi_python-0.30.0}/tests/test_schema_utils.py +0 -0
  265. {vgi_python-0.29.6 → vgi_python-0.30.0}/tests/test_serve.py +0 -0
  266. {vgi_python-0.29.6 → vgi_python-0.30.0}/tests/test_setting_secret_annotations.py +0 -0
  267. {vgi_python-0.29.6 → vgi_python-0.30.0}/tests/test_signing_key.py +0 -0
  268. {vgi_python-0.29.6 → vgi_python-0.30.0}/tests/test_split_token.py +0 -0
  269. {vgi_python-0.29.6 → vgi_python-0.30.0}/tests/test_table_buffering_function.py +0 -0
  270. {vgi_python-0.29.6 → vgi_python-0.30.0}/tests/test_table_function_dynamic_to_string.py +0 -0
  271. {vgi_python-0.29.6 → vgi_python-0.30.0}/tests/test_tcp_transport.py +0 -0
  272. {vgi_python-0.29.6 → vgi_python-0.30.0}/tests/test_type_bounds.py +0 -0
  273. {vgi_python-0.29.6 → vgi_python-0.30.0}/tests/test_union_argument.py +0 -0
  274. {vgi_python-0.29.6 → vgi_python-0.30.0}/tests/test_wire_record_schema_parity.py +0 -0
  275. {vgi_python-0.29.6 → vgi_python-0.30.0}/tests/test_worker.py +0 -0
  276. {vgi_python-0.29.6 → vgi_python-0.30.0}/tests/test_worker_cli.py +0 -0
  277. {vgi_python-0.29.6 → vgi_python-0.30.0}/tests/test_worker_page.py +0 -0
  278. {vgi_python-0.29.6 → vgi_python-0.30.0}/tests/transactor/__init__.py +0 -0
  279. {vgi_python-0.29.6 → vgi_python-0.30.0}/tests/transactor/test_transactor.py +0 -0
  280. {vgi_python-0.29.6 → vgi_python-0.30.0}/vgi/__init__.py +0 -0
  281. {vgi_python-0.29.6 → vgi_python-0.30.0}/vgi/_duckdb.py +0 -0
  282. {vgi_python-0.29.6 → vgi_python-0.30.0}/vgi/_storage_profile.py +0 -0
  283. {vgi_python-0.29.6 → vgi_python-0.30.0}/vgi/_test_fixtures/__init__.py +0 -0
  284. {vgi_python-0.29.6 → vgi_python-0.30.0}/vgi/_test_fixtures/accumulate/__init__.py +0 -0
  285. {vgi_python-0.29.6 → vgi_python-0.30.0}/vgi/_test_fixtures/accumulate/worker.py +0 -0
  286. {vgi_python-0.29.6 → vgi_python-0.30.0}/vgi/_test_fixtures/aggregate/__init__.py +0 -0
  287. {vgi_python-0.29.6 → vgi_python-0.30.0}/vgi/_test_fixtures/aggregate/_common.py +0 -0
  288. {vgi_python-0.29.6 → vgi_python-0.30.0}/vgi/_test_fixtures/aggregate/basic.py +0 -0
  289. {vgi_python-0.29.6 → vgi_python-0.30.0}/vgi/_test_fixtures/aggregate/dynamic.py +0 -0
  290. {vgi_python-0.29.6 → vgi_python-0.30.0}/vgi/_test_fixtures/aggregate/generic.py +0 -0
  291. {vgi_python-0.29.6 → vgi_python-0.30.0}/vgi/_test_fixtures/aggregate/listagg.py +0 -0
  292. {vgi_python-0.29.6 → vgi_python-0.30.0}/vgi/_test_fixtures/aggregate/percentile.py +0 -0
  293. {vgi_python-0.29.6 → vgi_python-0.30.0}/vgi/_test_fixtures/aggregate/same_name.py +0 -0
  294. {vgi_python-0.29.6 → vgi_python-0.30.0}/vgi/_test_fixtures/aggregate/secret_typed.py +0 -0
  295. {vgi_python-0.29.6 → vgi_python-0.30.0}/vgi/_test_fixtures/aggregate/streaming.py +0 -0
  296. {vgi_python-0.29.6 → vgi_python-0.30.0}/vgi/_test_fixtures/aggregate/varargs.py +0 -0
  297. {vgi_python-0.29.6 → vgi_python-0.30.0}/vgi/_test_fixtures/aggregate/window.py +0 -0
  298. {vgi_python-0.29.6 → vgi_python-0.30.0}/vgi/_test_fixtures/attach_options.py +0 -0
  299. {vgi_python-0.29.6 → vgi_python-0.30.0}/vgi/_test_fixtures/bad_enum.py +0 -0
  300. {vgi_python-0.29.6 → vgi_python-0.30.0}/vgi/_test_fixtures/bad_protocol.py +0 -0
  301. {vgi_python-0.29.6 → vgi_python-0.30.0}/vgi/_test_fixtures/cancellable.py +0 -0
  302. {vgi_python-0.29.6 → vgi_python-0.30.0}/vgi/_test_fixtures/catalog.py +0 -0
  303. {vgi_python-0.29.6 → vgi_python-0.30.0}/vgi/_test_fixtures/companion.py +0 -0
  304. {vgi_python-0.29.6 → vgi_python-0.30.0}/vgi/_test_fixtures/copy_from.py +0 -0
  305. {vgi_python-0.29.6 → vgi_python-0.30.0}/vgi/_test_fixtures/copy_to.py +0 -0
  306. {vgi_python-0.29.6 → vgi_python-0.30.0}/vgi/_test_fixtures/global_functions.py +0 -0
  307. {vgi_python-0.29.6 → vgi_python-0.30.0}/vgi/_test_fixtures/http_server.py +0 -0
  308. {vgi_python-0.29.6 → vgi_python-0.30.0}/vgi/_test_fixtures/narrow_bind/__init__.py +0 -0
  309. {vgi_python-0.29.6 → vgi_python-0.30.0}/vgi/_test_fixtures/narrow_bind/worker.py +0 -0
  310. {vgi_python-0.29.6 → vgi_python-0.30.0}/vgi/_test_fixtures/nest_tensor.py +0 -0
  311. {vgi_python-0.29.6 → vgi_python-0.30.0}/vgi/_test_fixtures/orchard_catalog.py +0 -0
  312. {vgi_python-0.29.6 → vgi_python-0.30.0}/vgi/_test_fixtures/projection_repro/__init__.py +0 -0
  313. {vgi_python-0.29.6 → vgi_python-0.30.0}/vgi/_test_fixtures/projection_repro/worker.py +0 -0
  314. {vgi_python-0.29.6 → vgi_python-0.30.0}/vgi/_test_fixtures/scalar/__init__.py +0 -0
  315. {vgi_python-0.29.6 → vgi_python-0.30.0}/vgi/_test_fixtures/scalar/_common.py +0 -0
  316. {vgi_python-0.29.6 → vgi_python-0.30.0}/vgi/_test_fixtures/scalar/arithmetic.py +0 -0
  317. {vgi_python-0.29.6 → vgi_python-0.30.0}/vgi/_test_fixtures/scalar/bench_ladder.py +0 -0
  318. {vgi_python-0.29.6 → vgi_python-0.30.0}/vgi/_test_fixtures/scalar/binary.py +0 -0
  319. {vgi_python-0.29.6 → vgi_python-0.30.0}/vgi/_test_fixtures/scalar/formatting.py +0 -0
  320. {vgi_python-0.29.6 → vgi_python-0.30.0}/vgi/_test_fixtures/scalar/geo.py +0 -0
  321. {vgi_python-0.29.6 → vgi_python-0.30.0}/vgi/_test_fixtures/scalar/null_handling.py +0 -0
  322. {vgi_python-0.29.6 → vgi_python-0.30.0}/vgi/_test_fixtures/scalar/random_demo.py +0 -0
  323. {vgi_python-0.29.6 → vgi_python-0.30.0}/vgi/_test_fixtures/scalar/same_name.py +0 -0
  324. {vgi_python-0.29.6 → vgi_python-0.30.0}/vgi/_test_fixtures/scalar/settings_secrets.py +0 -0
  325. {vgi_python-0.29.6 → vgi_python-0.30.0}/vgi/_test_fixtures/scalar/type_info.py +0 -0
  326. {vgi_python-0.29.6 → vgi_python-0.30.0}/vgi/_test_fixtures/schema_reconcile/__init__.py +0 -0
  327. {vgi_python-0.29.6 → vgi_python-0.30.0}/vgi/_test_fixtures/schema_reconcile/worker.py +0 -0
  328. {vgi_python-0.29.6 → vgi_python-0.30.0}/vgi/_test_fixtures/simple_writable.py +0 -0
  329. {vgi_python-0.29.6 → vgi_python-0.30.0}/vgi/_test_fixtures/table/__init__.py +0 -0
  330. {vgi_python-0.29.6 → vgi_python-0.30.0}/vgi/_test_fixtures/table/_common.py +0 -0
  331. {vgi_python-0.29.6 → vgi_python-0.30.0}/vgi/_test_fixtures/table/batch_index.py +0 -0
  332. {vgi_python-0.29.6 → vgi_python-0.30.0}/vgi/_test_fixtures/table/batch_index_broken.py +0 -0
  333. {vgi_python-0.29.6 → vgi_python-0.30.0}/vgi/_test_fixtures/table/cache.py +0 -0
  334. {vgi_python-0.29.6 → vgi_python-0.30.0}/vgi/_test_fixtures/table/catalog_scans.py +0 -0
  335. {vgi_python-0.29.6 → vgi_python-0.30.0}/vgi/_test_fixtures/table/filters.py +0 -0
  336. {vgi_python-0.29.6 → vgi_python-0.30.0}/vgi/_test_fixtures/table/late_materialization.py +0 -0
  337. {vgi_python-0.29.6 → vgi_python-0.30.0}/vgi/_test_fixtures/table/make_series.py +0 -0
  338. {vgi_python-0.29.6 → vgi_python-0.30.0}/vgi/_test_fixtures/table/misc.py +0 -0
  339. {vgi_python-0.29.6 → vgi_python-0.30.0}/vgi/_test_fixtures/table/order_modes.py +0 -0
  340. {vgi_python-0.29.6 → vgi_python-0.30.0}/vgi/_test_fixtures/table/pairs.py +0 -0
  341. {vgi_python-0.29.6 → vgi_python-0.30.0}/vgi/_test_fixtures/table/partition_columns.py +0 -0
  342. {vgi_python-0.29.6 → vgi_python-0.30.0}/vgi/_test_fixtures/table/partition_columns_broken.py +0 -0
  343. {vgi_python-0.29.6 → vgi_python-0.30.0}/vgi/_test_fixtures/table/profiling_example.py +0 -0
  344. {vgi_python-0.29.6 → vgi_python-0.30.0}/vgi/_test_fixtures/table/required_filters.py +0 -0
  345. {vgi_python-0.29.6 → vgi_python-0.30.0}/vgi/_test_fixtures/table/same_name_cached.py +0 -0
  346. {vgi_python-0.29.6 → vgi_python-0.30.0}/vgi/_test_fixtures/table/sequence.py +0 -0
  347. {vgi_python-0.29.6 → vgi_python-0.30.0}/vgi/_test_fixtures/table/settings.py +0 -0
  348. {vgi_python-0.29.6 → vgi_python-0.30.0}/vgi/_test_fixtures/table/splits.py +0 -0
  349. {vgi_python-0.29.6 → vgi_python-0.30.0}/vgi/_test_fixtures/table/transaction_storage.py +0 -0
  350. {vgi_python-0.29.6 → vgi_python-0.30.0}/vgi/_test_fixtures/table/tt_pushdown.py +0 -0
  351. {vgi_python-0.29.6 → vgi_python-0.30.0}/vgi/_test_fixtures/table/typed_probe.py +0 -0
  352. {vgi_python-0.29.6 → vgi_python-0.30.0}/vgi/_test_fixtures/table/versioned.py +0 -0
  353. {vgi_python-0.29.6 → vgi_python-0.30.0}/vgi/_test_fixtures/table/wide.py +0 -0
  354. {vgi_python-0.29.6 → vgi_python-0.30.0}/vgi/_test_fixtures/table_in_out.py +0 -0
  355. {vgi_python-0.29.6 → vgi_python-0.30.0}/vgi/_test_fixtures/table_in_out_same_name.py +0 -0
  356. {vgi_python-0.29.6 → vgi_python-0.30.0}/vgi/_test_fixtures/twin_catalogs.py +0 -0
  357. {vgi_python-0.29.6 → vgi_python-0.30.0}/vgi/_test_fixtures/versioned.py +0 -0
  358. {vgi_python-0.29.6 → vgi_python-0.30.0}/vgi/_test_fixtures/versioned_tables.py +0 -0
  359. {vgi_python-0.29.6 → vgi_python-0.30.0}/vgi/_test_fixtures/worker.py +0 -0
  360. {vgi_python-0.29.6 → vgi_python-0.30.0}/vgi/_test_fixtures/writable/__init__.py +0 -0
  361. {vgi_python-0.29.6 → vgi_python-0.30.0}/vgi/_test_fixtures/writable/generic.py +0 -0
  362. {vgi_python-0.29.6 → vgi_python-0.30.0}/vgi/_test_fixtures/writable/table.py +0 -0
  363. {vgi_python-0.29.6 → vgi_python-0.30.0}/vgi/_test_fixtures/writable/worker.py +0 -0
  364. {vgi_python-0.29.6 → vgi_python-0.30.0}/vgi/aggregate_function.py +0 -0
  365. {vgi_python-0.29.6 → vgi_python-0.30.0}/vgi/argument_spec.py +0 -0
  366. {vgi_python-0.29.6 → vgi_python-0.30.0}/vgi/arguments.py +0 -0
  367. {vgi_python-0.29.6 → vgi_python-0.30.0}/vgi/attach_header.py +0 -0
  368. {vgi_python-0.29.6 → vgi_python-0.30.0}/vgi/auth.py +0 -0
  369. {vgi_python-0.29.6 → vgi_python-0.30.0}/vgi/cache_control.py +0 -0
  370. {vgi_python-0.29.6 → vgi_python-0.30.0}/vgi/catalog/__init__.py +0 -0
  371. {vgi_python-0.29.6 → vgi_python-0.30.0}/vgi/catalog/_descriptor_spec.py +0 -0
  372. {vgi_python-0.29.6 → vgi_python-0.30.0}/vgi/catalog/attach_option.py +0 -0
  373. {vgi_python-0.29.6 → vgi_python-0.30.0}/vgi/catalog/catalog_interface.py +0 -0
  374. {vgi_python-0.29.6 → vgi_python-0.30.0}/vgi/catalog/descriptors.py +0 -0
  375. {vgi_python-0.29.6 → vgi_python-0.30.0}/vgi/catalog/duckdb_statistics.py +0 -0
  376. {vgi_python-0.29.6 → vgi_python-0.30.0}/vgi/catalog/secret_type.py +0 -0
  377. {vgi_python-0.29.6 → vgi_python-0.30.0}/vgi/catalog/setting.py +0 -0
  378. {vgi_python-0.29.6 → vgi_python-0.30.0}/vgi/catalog/storage.py +0 -0
  379. {vgi_python-0.29.6 → vgi_python-0.30.0}/vgi/client/__init__.py +0 -0
  380. {vgi_python-0.29.6 → vgi_python-0.30.0}/vgi/client/aggregate.py +0 -0
  381. {vgi_python-0.29.6 → vgi_python-0.30.0}/vgi/client/catalog_mixin.py +0 -0
  382. {vgi_python-0.29.6 → vgi_python-0.30.0}/vgi/client/cli.py +0 -0
  383. {vgi_python-0.29.6 → vgi_python-0.30.0}/vgi/client/cli_catalog.py +0 -0
  384. {vgi_python-0.29.6 → vgi_python-0.30.0}/vgi/client/cli_schema.py +0 -0
  385. {vgi_python-0.29.6 → vgi_python-0.30.0}/vgi/client/cli_table.py +0 -0
  386. {vgi_python-0.29.6 → vgi_python-0.30.0}/vgi/client/cli_transaction.py +0 -0
  387. {vgi_python-0.29.6 → vgi_python-0.30.0}/vgi/client/cli_utils.py +0 -0
  388. {vgi_python-0.29.6 → vgi_python-0.30.0}/vgi/client/cli_view.py +0 -0
  389. {vgi_python-0.29.6 → vgi_python-0.30.0}/vgi/client/errors.py +0 -0
  390. {vgi_python-0.29.6 → vgi_python-0.30.0}/vgi/codegen/__init__.py +0 -0
  391. {vgi_python-0.29.6 → vgi_python-0.30.0}/vgi/codegen/_common.py +0 -0
  392. {vgi_python-0.29.6 → vgi_python-0.30.0}/vgi/codegen/cpp_constants.py +0 -0
  393. {vgi_python-0.29.6 → vgi_python-0.30.0}/vgi/codegen/cpp_protocol_version.py +0 -0
  394. {vgi_python-0.29.6 → vgi_python-0.30.0}/vgi/codegen/cpp_schemas.py +0 -0
  395. {vgi_python-0.29.6 → vgi_python-0.30.0}/vgi/codegen/cpp_secret_protocol_version.py +0 -0
  396. {vgi_python-0.29.6 → vgi_python-0.30.0}/vgi/codegen/cpp_secret_request_builders.py +0 -0
  397. {vgi_python-0.29.6 → vgi_python-0.30.0}/vgi/codegen/cpp_secret_schemas.py +0 -0
  398. {vgi_python-0.29.6 → vgi_python-0.30.0}/vgi/codegen/go_schemas.py +0 -0
  399. {vgi_python-0.29.6 → vgi_python-0.30.0}/vgi/codegen/java_schemas.py +0 -0
  400. {vgi_python-0.29.6 → vgi_python-0.30.0}/vgi/codegen/protocol_version.py +0 -0
  401. {vgi_python-0.29.6 → vgi_python-0.30.0}/vgi/codegen/rust_request_builders.py +0 -0
  402. {vgi_python-0.29.6 → vgi_python-0.30.0}/vgi/codegen/rust_schemas.py +0 -0
  403. {vgi_python-0.29.6 → vgi_python-0.30.0}/vgi/codegen/ts_client.py +0 -0
  404. {vgi_python-0.29.6 → vgi_python-0.30.0}/vgi/codegen/ts_schemas.py +0 -0
  405. {vgi_python-0.29.6 → vgi_python-0.30.0}/vgi/copy_from_function.py +0 -0
  406. {vgi_python-0.29.6 → vgi_python-0.30.0}/vgi/copy_to_function.py +0 -0
  407. {vgi_python-0.29.6 → vgi_python-0.30.0}/vgi/exceptions.py +0 -0
  408. {vgi_python-0.29.6 → vgi_python-0.30.0}/vgi/function.py +0 -0
  409. {vgi_python-0.29.6 → vgi_python-0.30.0}/vgi/function_storage.py +0 -0
  410. {vgi_python-0.29.6 → vgi_python-0.30.0}/vgi/function_storage_azure_sql.py +0 -0
  411. {vgi_python-0.29.6 → vgi_python-0.30.0}/vgi/function_storage_cf_do.py +0 -0
  412. {vgi_python-0.29.6 → vgi_python-0.30.0}/vgi/http/__init__.py +0 -0
  413. {vgi_python-0.29.6 → vgi_python-0.30.0}/vgi/http/demo_storage.py +0 -0
  414. {vgi_python-0.29.6 → vgi_python-0.30.0}/vgi/http/landing.html +0 -0
  415. {vgi_python-0.29.6 → vgi_python-0.30.0}/vgi/http/landing_page.py +0 -0
  416. {vgi_python-0.29.6 → vgi_python-0.30.0}/vgi/http/vgi-client.js +0 -0
  417. {vgi_python-0.29.6 → vgi_python-0.30.0}/vgi/http/worker_page.py +0 -0
  418. {vgi_python-0.29.6 → vgi_python-0.30.0}/vgi/invocation.py +0 -0
  419. {vgi_python-0.29.6 → vgi_python-0.30.0}/vgi/logging_config.py +0 -0
  420. {vgi_python-0.29.6 → vgi_python-0.30.0}/vgi/meta_worker.py +0 -0
  421. {vgi_python-0.29.6 → vgi_python-0.30.0}/vgi/metadata.py +0 -0
  422. {vgi_python-0.29.6 → vgi_python-0.30.0}/vgi/otel.py +0 -0
  423. {vgi_python-0.29.6 → vgi_python-0.30.0}/vgi/profiling.py +0 -0
  424. {vgi_python-0.29.6 → vgi_python-0.30.0}/vgi/protocol.py +0 -0
  425. {vgi_python-0.29.6 → vgi_python-0.30.0}/vgi/protocol_version.txt +0 -0
  426. {vgi_python-0.29.6 → vgi_python-0.30.0}/vgi/py.typed +0 -0
  427. {vgi_python-0.29.6 → vgi_python-0.30.0}/vgi/scalar_function.py +0 -0
  428. {vgi_python-0.29.6 → vgi_python-0.30.0}/vgi/schema_utils.py +0 -0
  429. {vgi_python-0.29.6 → vgi_python-0.30.0}/vgi/secret_protocol.py +0 -0
  430. {vgi_python-0.29.6 → vgi_python-0.30.0}/vgi/secret_service.py +0 -0
  431. {vgi_python-0.29.6 → vgi_python-0.30.0}/vgi/serve.py +0 -0
  432. {vgi_python-0.29.6 → vgi_python-0.30.0}/vgi/split_token.py +0 -0
  433. {vgi_python-0.29.6 → vgi_python-0.30.0}/vgi/table_buffering_function.py +0 -0
  434. {vgi_python-0.29.6 → vgi_python-0.30.0}/vgi/table_filter_pushdown.py +0 -0
  435. {vgi_python-0.29.6 → vgi_python-0.30.0}/vgi/table_function.py +0 -0
  436. {vgi_python-0.29.6 → vgi_python-0.30.0}/vgi/table_in_out_function.py +0 -0
  437. {vgi_python-0.29.6 → vgi_python-0.30.0}/vgi/transactor/__init__.py +0 -0
  438. {vgi_python-0.29.6 → vgi_python-0.30.0}/vgi/transactor/_duckdb_compat.py +0 -0
  439. {vgi_python-0.29.6 → vgi_python-0.30.0}/vgi/transactor/client.py +0 -0
  440. {vgi_python-0.29.6 → vgi_python-0.30.0}/vgi/transactor/protocol.py +0 -0
  441. {vgi_python-0.29.6 → vgi_python-0.30.0}/vgi/transactor/server.py +0 -0
  442. {vgi_python-0.29.6 → 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.6
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.6"
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
@@ -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.6"
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
 
@@ -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."
@@ -1613,10 +1613,23 @@ class Worker:
1613
1613
  max_externalized_response_bytes=max_externalized_response_bytes,
1614
1614
  )
1615
1615
  elif unix is not None:
1616
- # AF_UNIX launcher path. Bind to the requested socket,
1617
- # print UNIX:<abs_path> on stdout, idle-shutdown after
1618
- # idle_timeout seconds.
1619
- from vgi_rpc.rpc import serve_unix
1616
+ # AF_UNIX launcher path on POSIX; Windows has no
1617
+ # socket.AF_UNIX in this code path, so --unix there
1618
+ # carries a named-pipe name (\\.\pipe\...) instead - the
1619
+ # launcher constructs whichever one is appropriate for the
1620
+ # platform it's running on. Mirrors vgi_rpc.rpc.run_server's
1621
+ # own platform dispatch (vgi_rpc/rpc/__init__.py) exactly -
1622
+ # this classmethod has its own, separate serving path (not
1623
+ # a call to run_server) because it also handles Sentry/OTel
1624
+ # setup and cls-specific worker construction, but the
1625
+ # transport-level platform choice must stay identical
1626
+ # between the two, or a worker built against this
1627
+ # classmethod (e.g. any vgi.worker.Worker subclass) crashes
1628
+ # on Windows with "AttributeError: module 'socket' has no
1629
+ # attribute 'AF_UNIX'" while one built directly against
1630
+ # run_server works fine - confirmed as a real, live bug
1631
+ # this way, not theoretical.
1632
+ from vgi_rpc.rpc import serve_named_pipe, serve_unix
1620
1633
 
1621
1634
  from vgi.serve import _maybe_init_sentry, _resolve_otel_config
1622
1635
 
@@ -1629,20 +1642,36 @@ class Worker:
1629
1642
 
1630
1643
  instrument_server(server, otel_config)
1631
1644
  worker._vgi_tracer = VgiTracer.create(otel_config)
1632
- abs_path = os.path.abspath(unix)
1633
1645
  effective_idle = idle_timeout if idle_timeout > 0 else None
1634
1646
 
1635
- def _emit(bound: str) -> None:
1636
- print(f"UNIX:{bound}", flush=True)
1647
+ if sys.platform == "win32":
1648
+ pipe_name = unix
1637
1649
 
1638
- serve_unix(
1639
- server,
1640
- abs_path,
1641
- threaded=True,
1642
- max_connections=max_connections,
1643
- idle_timeout=effective_idle,
1644
- on_bound=_emit,
1645
- )
1650
+ def _emit(bound: str) -> None:
1651
+ print(f"PIPE:{bound}", flush=True)
1652
+
1653
+ serve_named_pipe(
1654
+ server,
1655
+ pipe_name,
1656
+ threaded=True,
1657
+ max_connections=max_connections,
1658
+ idle_timeout=effective_idle,
1659
+ on_bound=_emit,
1660
+ )
1661
+ else:
1662
+ abs_path = os.path.abspath(unix)
1663
+
1664
+ def _emit(bound: str) -> None:
1665
+ print(f"UNIX:{bound}", flush=True)
1666
+
1667
+ serve_unix(
1668
+ server,
1669
+ abs_path,
1670
+ threaded=True,
1671
+ max_connections=max_connections,
1672
+ idle_timeout=effective_idle,
1673
+ on_bound=_emit,
1674
+ )
1646
1675
  elif tcp is not None:
1647
1676
  # TCP launcher path. Bind to [HOST:]PORT, print
1648
1677
  # TCP:<host>:<port> on stdout (mirrors run_server's
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes