vgi-python 0.36.1__tar.gz → 0.37.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 (660) hide show
  1. {vgi_python-0.36.1 → vgi_python-0.37.0}/PKG-INFO +1 -1
  2. vgi_python-0.37.0/conformance/filter-v2/cases/positive/boolean-column-predicate.json +32 -0
  3. {vgi_python-0.36.1 → vgi_python-0.37.0}/conformance/filter-v2/manifest.json +5 -0
  4. {vgi_python-0.36.1 → vgi_python-0.37.0}/pyproject.toml +1 -1
  5. {vgi_python-0.36.1 → vgi_python-0.37.0}/tests/test_filter_v2.py +166 -1
  6. {vgi_python-0.36.1 → vgi_python-0.37.0}/tests/test_serve.py +157 -1
  7. {vgi_python-0.36.1 → vgi_python-0.37.0}/uv.lock +1 -1
  8. {vgi_python-0.36.1 → vgi_python-0.37.0}/vgi/_test_fixtures/table/__init__.py +2 -0
  9. {vgi_python-0.36.1 → vgi_python-0.37.0}/vgi/_test_fixtures/table/filters.py +123 -0
  10. {vgi_python-0.36.1 → vgi_python-0.37.0}/vgi/_test_fixtures/worker.py +2 -0
  11. {vgi_python-0.36.1 → vgi_python-0.37.0}/vgi/auth.py +12 -3
  12. {vgi_python-0.36.1 → vgi_python-0.37.0}/vgi/filter_v2.py +18 -5
  13. {vgi_python-0.36.1 → vgi_python-0.37.0}/vgi/serve.py +15 -7
  14. {vgi_python-0.36.1 → vgi_python-0.37.0}/vgi/table_filter_pushdown.py +79 -1
  15. {vgi_python-0.36.1 → vgi_python-0.37.0}/vgi/worker.py +75 -1
  16. {vgi_python-0.36.1 → vgi_python-0.37.0}/.dockerignore +0 -0
  17. {vgi_python-0.36.1 → vgi_python-0.37.0}/.gitattributes +0 -0
  18. {vgi_python-0.36.1 → vgi_python-0.37.0}/.github/dependabot.yml +0 -0
  19. {vgi_python-0.36.1 → vgi_python-0.37.0}/.github/styles/config/vocabularies/VGI/accept.txt +0 -0
  20. {vgi_python-0.36.1 → vgi_python-0.37.0}/.github/workflows/ci.yml +0 -0
  21. {vgi_python-0.36.1 → vgi_python-0.37.0}/.github/workflows/docs.yml +0 -0
  22. {vgi_python-0.36.1 → vgi_python-0.37.0}/.github/workflows/integration.yml +0 -0
  23. {vgi_python-0.36.1 → vgi_python-0.37.0}/.github/workflows/release.yml +0 -0
  24. {vgi_python-0.36.1 → vgi_python-0.37.0}/.github/workflows/tailnet-integration.yml +0 -0
  25. {vgi_python-0.36.1 → vgi_python-0.37.0}/.gitignore +0 -0
  26. {vgi_python-0.36.1 → vgi_python-0.37.0}/.python-version +0 -0
  27. {vgi_python-0.36.1 → vgi_python-0.37.0}/.vale.ini +0 -0
  28. {vgi_python-0.36.1 → vgi_python-0.37.0}/CLAUDE.md +0 -0
  29. {vgi_python-0.36.1 → vgi_python-0.37.0}/DOCS_ACCEPTANCE_CRITERIA.md +0 -0
  30. {vgi_python-0.36.1 → vgi_python-0.37.0}/DOCS_REVIEW_RUBRIC.md +0 -0
  31. {vgi_python-0.36.1 → vgi_python-0.37.0}/DOCS_USABILITY_TEST.md +0 -0
  32. {vgi_python-0.36.1 → vgi_python-0.37.0}/LICENSE +0 -0
  33. {vgi_python-0.36.1 → vgi_python-0.37.0}/PROTOCOL.md +0 -0
  34. {vgi_python-0.36.1 → vgi_python-0.37.0}/README.md +0 -0
  35. {vgi_python-0.36.1 → vgi_python-0.37.0}/RELEASE-RUNBOOK.md +0 -0
  36. {vgi_python-0.36.1 → vgi_python-0.37.0}/SECURITY.md +0 -0
  37. {vgi_python-0.36.1 → vgi_python-0.37.0}/ci/README.md +0 -0
  38. {vgi_python-0.36.1 → vgi_python-0.37.0}/ci/preprocess-require.awk +0 -0
  39. {vgi_python-0.36.1 → vgi_python-0.37.0}/ci/run-integration.sh +0 -0
  40. {vgi_python-0.36.1 → vgi_python-0.37.0}/conformance/filter-v2/README.md +0 -0
  41. {vgi_python-0.36.1 → vgi_python-0.37.0}/conformance/filter-v2/cases/negative/and-too-few-children.json +0 -0
  42. {vgi_python-0.36.1 → vgi_python-0.37.0}/conformance/filter-v2/cases/negative/delta-required-upsert.json +0 -0
  43. {vgi_python-0.36.1 → vgi_python-0.37.0}/conformance/filter-v2/cases/negative/nested-runtime-filter.json +0 -0
  44. {vgi_python-0.36.1 → vgi_python-0.37.0}/conformance/filter-v2/cases/negative/remove-with-expression.json +0 -0
  45. {vgi_python-0.36.1 → vgi_python-0.37.0}/conformance/filter-v2/cases/negative/required-runtime-filter.json +0 -0
  46. {vgi_python-0.36.1 → vgi_python-0.37.0}/conformance/filter-v2/cases/negative/snapshot-nonzero-revision.json +0 -0
  47. {vgi_python-0.36.1 → vgi_python-0.37.0}/conformance/filter-v2/cases/negative/unknown-document-property.json +0 -0
  48. {vgi_python-0.36.1 → vgi_python-0.37.0}/conformance/filter-v2/cases/negative/unknown-node.json +0 -0
  49. {vgi_python-0.36.1 → vgi_python-0.37.0}/conformance/filter-v2/cases/positive/advisory-upsert-delta.json +0 -0
  50. {vgi_python-0.36.1 → vgi_python-0.37.0}/conformance/filter-v2/cases/positive/empty-snapshot.json +0 -0
  51. {vgi_python-0.36.1 → vgi_python-0.37.0}/conformance/filter-v2/cases/positive/nested-required-snapshot.json +0 -0
  52. {vgi_python-0.36.1 → vgi_python-0.37.0}/conformance/filter-v2/cases/positive/remove-delta.json +0 -0
  53. {vgi_python-0.36.1 → vgi_python-0.37.0}/conformance/filter-v2/cases/positive/runtime-filter-snapshot.json +0 -0
  54. {vgi_python-0.36.1 → vgi_python-0.37.0}/conformance/filter-v2/filter-v2.schema.json +0 -0
  55. {vgi_python-0.36.1 → vgi_python-0.37.0}/conformance/filter-v2/generate_runtime.py +0 -0
  56. {vgi_python-0.36.1 → vgi_python-0.37.0}/conformance/filter-v2/run_worker.py +0 -0
  57. {vgi_python-0.36.1 → vgi_python-0.37.0}/conformance/filter-v2/runtime/arithmetic-add/expected.arrow +0 -0
  58. {vgi_python-0.36.1 → vgi_python-0.37.0}/conformance/filter-v2/runtime/arithmetic-add/filter.arrow +0 -0
  59. {vgi_python-0.36.1 → vgi_python-0.37.0}/conformance/filter-v2/runtime/arithmetic-add/input.arrow +0 -0
  60. {vgi_python-0.36.1 → vgi_python-0.37.0}/conformance/filter-v2/runtime/arithmetic-multiply/expected.arrow +0 -0
  61. {vgi_python-0.36.1 → vgi_python-0.37.0}/conformance/filter-v2/runtime/arithmetic-multiply/filter.arrow +0 -0
  62. {vgi_python-0.36.1 → vgi_python-0.37.0}/conformance/filter-v2/runtime/arithmetic-multiply/input.arrow +0 -0
  63. {vgi_python-0.36.1 → vgi_python-0.37.0}/conformance/filter-v2/runtime/arithmetic-negate/expected.arrow +0 -0
  64. {vgi_python-0.36.1 → vgi_python-0.37.0}/conformance/filter-v2/runtime/arithmetic-negate/filter.arrow +0 -0
  65. {vgi_python-0.36.1 → vgi_python-0.37.0}/conformance/filter-v2/runtime/arithmetic-negate/input.arrow +0 -0
  66. {vgi_python-0.36.1 → vgi_python-0.37.0}/conformance/filter-v2/runtime/arithmetic-subtract/expected.arrow +0 -0
  67. {vgi_python-0.36.1 → vgi_python-0.37.0}/conformance/filter-v2/runtime/arithmetic-subtract/filter.arrow +0 -0
  68. {vgi_python-0.36.1 → vgi_python-0.37.0}/conformance/filter-v2/runtime/arithmetic-subtract/input.arrow +0 -0
  69. {vgi_python-0.36.1 → vgi_python-0.37.0}/conformance/filter-v2/runtime/cast-integer-to-double/expected.arrow +0 -0
  70. {vgi_python-0.36.1 → vgi_python-0.37.0}/conformance/filter-v2/runtime/cast-integer-to-double/filter.arrow +0 -0
  71. {vgi_python-0.36.1 → vgi_python-0.37.0}/conformance/filter-v2/runtime/cast-integer-to-double/input.arrow +0 -0
  72. {vgi_python-0.36.1 → vgi_python-0.37.0}/conformance/filter-v2/runtime/comparison-distinct_from/expected.arrow +0 -0
  73. {vgi_python-0.36.1 → vgi_python-0.37.0}/conformance/filter-v2/runtime/comparison-distinct_from/filter.arrow +0 -0
  74. {vgi_python-0.36.1 → vgi_python-0.37.0}/conformance/filter-v2/runtime/comparison-distinct_from/input.arrow +0 -0
  75. {vgi_python-0.36.1 → vgi_python-0.37.0}/conformance/filter-v2/runtime/comparison-distinct_from/worker-expected.arrow +0 -0
  76. {vgi_python-0.36.1 → vgi_python-0.37.0}/conformance/filter-v2/runtime/comparison-eq/expected.arrow +0 -0
  77. {vgi_python-0.36.1 → vgi_python-0.37.0}/conformance/filter-v2/runtime/comparison-eq/filter.arrow +0 -0
  78. {vgi_python-0.36.1 → vgi_python-0.37.0}/conformance/filter-v2/runtime/comparison-eq/input.arrow +0 -0
  79. {vgi_python-0.36.1 → vgi_python-0.37.0}/conformance/filter-v2/runtime/comparison-eq/worker-expected.arrow +0 -0
  80. {vgi_python-0.36.1 → vgi_python-0.37.0}/conformance/filter-v2/runtime/comparison-ge/expected.arrow +0 -0
  81. {vgi_python-0.36.1 → vgi_python-0.37.0}/conformance/filter-v2/runtime/comparison-ge/filter.arrow +0 -0
  82. {vgi_python-0.36.1 → vgi_python-0.37.0}/conformance/filter-v2/runtime/comparison-ge/input.arrow +0 -0
  83. {vgi_python-0.36.1 → vgi_python-0.37.0}/conformance/filter-v2/runtime/comparison-ge/worker-expected.arrow +0 -0
  84. {vgi_python-0.36.1 → vgi_python-0.37.0}/conformance/filter-v2/runtime/comparison-gt/expected.arrow +0 -0
  85. {vgi_python-0.36.1 → vgi_python-0.37.0}/conformance/filter-v2/runtime/comparison-gt/filter.arrow +0 -0
  86. {vgi_python-0.36.1 → vgi_python-0.37.0}/conformance/filter-v2/runtime/comparison-gt/input.arrow +0 -0
  87. {vgi_python-0.36.1 → vgi_python-0.37.0}/conformance/filter-v2/runtime/comparison-gt/worker-expected.arrow +0 -0
  88. {vgi_python-0.36.1 → vgi_python-0.37.0}/conformance/filter-v2/runtime/comparison-le/expected.arrow +0 -0
  89. {vgi_python-0.36.1 → vgi_python-0.37.0}/conformance/filter-v2/runtime/comparison-le/filter.arrow +0 -0
  90. {vgi_python-0.36.1 → vgi_python-0.37.0}/conformance/filter-v2/runtime/comparison-le/input.arrow +0 -0
  91. {vgi_python-0.36.1 → vgi_python-0.37.0}/conformance/filter-v2/runtime/comparison-le/worker-expected.arrow +0 -0
  92. {vgi_python-0.36.1 → vgi_python-0.37.0}/conformance/filter-v2/runtime/comparison-lt/expected.arrow +0 -0
  93. {vgi_python-0.36.1 → vgi_python-0.37.0}/conformance/filter-v2/runtime/comparison-lt/filter.arrow +0 -0
  94. {vgi_python-0.36.1 → vgi_python-0.37.0}/conformance/filter-v2/runtime/comparison-lt/input.arrow +0 -0
  95. {vgi_python-0.36.1 → vgi_python-0.37.0}/conformance/filter-v2/runtime/comparison-lt/worker-expected.arrow +0 -0
  96. {vgi_python-0.36.1 → vgi_python-0.37.0}/conformance/filter-v2/runtime/comparison-ne/expected.arrow +0 -0
  97. {vgi_python-0.36.1 → vgi_python-0.37.0}/conformance/filter-v2/runtime/comparison-ne/filter.arrow +0 -0
  98. {vgi_python-0.36.1 → vgi_python-0.37.0}/conformance/filter-v2/runtime/comparison-ne/input.arrow +0 -0
  99. {vgi_python-0.36.1 → vgi_python-0.37.0}/conformance/filter-v2/runtime/comparison-ne/worker-expected.arrow +0 -0
  100. {vgi_python-0.36.1 → vgi_python-0.37.0}/conformance/filter-v2/runtime/comparison-not_distinct_from/expected.arrow +0 -0
  101. {vgi_python-0.36.1 → vgi_python-0.37.0}/conformance/filter-v2/runtime/comparison-not_distinct_from/filter.arrow +0 -0
  102. {vgi_python-0.36.1 → vgi_python-0.37.0}/conformance/filter-v2/runtime/comparison-not_distinct_from/input.arrow +0 -0
  103. {vgi_python-0.36.1 → vgi_python-0.37.0}/conformance/filter-v2/runtime/comparison-not_distinct_from/worker-expected.arrow +0 -0
  104. {vgi_python-0.36.1 → vgi_python-0.37.0}/conformance/filter-v2/runtime/delta-atomic-multi-update/delta-0.arrow +0 -0
  105. {vgi_python-0.36.1 → vgi_python-0.37.0}/conformance/filter-v2/runtime/delta-atomic-multi-update/expected.arrow +0 -0
  106. {vgi_python-0.36.1 → vgi_python-0.37.0}/conformance/filter-v2/runtime/delta-atomic-multi-update/filter.arrow +0 -0
  107. {vgi_python-0.36.1 → vgi_python-0.37.0}/conformance/filter-v2/runtime/delta-atomic-multi-update/input.arrow +0 -0
  108. {vgi_python-0.36.1 → vgi_python-0.37.0}/conformance/filter-v2/runtime/delta-empty-noop/delta-0.arrow +0 -0
  109. {vgi_python-0.36.1 → vgi_python-0.37.0}/conformance/filter-v2/runtime/delta-empty-noop/expected.arrow +0 -0
  110. {vgi_python-0.36.1 → vgi_python-0.37.0}/conformance/filter-v2/runtime/delta-empty-noop/filter.arrow +0 -0
  111. {vgi_python-0.36.1 → vgi_python-0.37.0}/conformance/filter-v2/runtime/delta-empty-noop/input.arrow +0 -0
  112. {vgi_python-0.36.1 → vgi_python-0.37.0}/conformance/filter-v2/runtime/delta-upsert-remove-stale/delta-0.arrow +0 -0
  113. {vgi_python-0.36.1 → vgi_python-0.37.0}/conformance/filter-v2/runtime/delta-upsert-remove-stale/delta-1.arrow +0 -0
  114. {vgi_python-0.36.1 → vgi_python-0.37.0}/conformance/filter-v2/runtime/delta-upsert-remove-stale/delta-2.arrow +0 -0
  115. {vgi_python-0.36.1 → vgi_python-0.37.0}/conformance/filter-v2/runtime/delta-upsert-remove-stale/expected.arrow +0 -0
  116. {vgi_python-0.36.1 → vgi_python-0.37.0}/conformance/filter-v2/runtime/delta-upsert-remove-stale/filter.arrow +0 -0
  117. {vgi_python-0.36.1 → vgi_python-0.37.0}/conformance/filter-v2/runtime/delta-upsert-remove-stale/input.arrow +0 -0
  118. {vgi_python-0.36.1 → vgi_python-0.37.0}/conformance/filter-v2/runtime/empty-snapshot/expected.arrow +0 -0
  119. {vgi_python-0.36.1 → vgi_python-0.37.0}/conformance/filter-v2/runtime/empty-snapshot/filter.arrow +0 -0
  120. {vgi_python-0.36.1 → vgi_python-0.37.0}/conformance/filter-v2/runtime/empty-snapshot/input.arrow +0 -0
  121. {vgi_python-0.36.1 → vgi_python-0.37.0}/conformance/filter-v2/runtime/empty-snapshot/worker-expected.arrow +0 -0
  122. {vgi_python-0.36.1 → vgi_python-0.37.0}/conformance/filter-v2/runtime/error-cast-type-not-null/filter.arrow +0 -0
  123. {vgi_python-0.36.1 → vgi_python-0.37.0}/conformance/filter-v2/runtime/error-cast-type-not-null/input.arrow +0 -0
  124. {vgi_python-0.36.1 → vgi_python-0.37.0}/conformance/filter-v2/runtime/error-column-index/filter.arrow +0 -0
  125. {vgi_python-0.36.1 → vgi_python-0.37.0}/conformance/filter-v2/runtime/error-column-index/input.arrow +0 -0
  126. {vgi_python-0.36.1 → vgi_python-0.37.0}/conformance/filter-v2/runtime/error-column-name/filter.arrow +0 -0
  127. {vgi_python-0.36.1 → vgi_python-0.37.0}/conformance/filter-v2/runtime/error-column-name/input.arrow +0 -0
  128. {vgi_python-0.36.1 → vgi_python-0.37.0}/conformance/filter-v2/runtime/error-contextual-cast-without-session/filter.arrow +0 -0
  129. {vgi_python-0.36.1 → vgi_python-0.37.0}/conformance/filter-v2/runtime/error-contextual-cast-without-session/input.arrow +0 -0
  130. {vgi_python-0.36.1 → vgi_python-0.37.0}/conformance/filter-v2/runtime/error-duplicate-predicate-id/filter.arrow +0 -0
  131. {vgi_python-0.36.1 → vgi_python-0.37.0}/conformance/filter-v2/runtime/error-duplicate-predicate-id/input.arrow +0 -0
  132. {vgi_python-0.36.1 → vgi_python-0.37.0}/conformance/filter-v2/runtime/error-external-column-index/filter.arrow +0 -0
  133. {vgi_python-0.36.1 → vgi_python-0.37.0}/conformance/filter-v2/runtime/error-external-column-index/input.arrow +0 -0
  134. {vgi_python-0.36.1 → vgi_python-0.37.0}/conformance/filter-v2/runtime/error-external-column-index/join-keys-0.arrow +0 -0
  135. {vgi_python-0.36.1 → vgi_python-0.37.0}/conformance/filter-v2/runtime/error-external-column-name/filter.arrow +0 -0
  136. {vgi_python-0.36.1 → vgi_python-0.37.0}/conformance/filter-v2/runtime/error-external-column-name/input.arrow +0 -0
  137. {vgi_python-0.36.1 → vgi_python-0.37.0}/conformance/filter-v2/runtime/error-external-column-name/join-keys-0.arrow +0 -0
  138. {vgi_python-0.36.1 → vgi_python-0.37.0}/conformance/filter-v2/runtime/error-field-non-struct/filter.arrow +0 -0
  139. {vgi_python-0.36.1 → vgi_python-0.37.0}/conformance/filter-v2/runtime/error-field-non-struct/input.arrow +0 -0
  140. {vgi_python-0.36.1 → vgi_python-0.37.0}/conformance/filter-v2/runtime/error-in-payload-not-list/filter.arrow +0 -0
  141. {vgi_python-0.36.1 → vgi_python-0.37.0}/conformance/filter-v2/runtime/error-in-payload-not-list/input.arrow +0 -0
  142. {vgi_python-0.36.1 → vgi_python-0.37.0}/conformance/filter-v2/runtime/error-in-payload-null-list/filter.arrow +0 -0
  143. {vgi_python-0.36.1 → vgi_python-0.37.0}/conformance/filter-v2/runtime/error-in-payload-null-list/input.arrow +0 -0
  144. {vgi_python-0.36.1 → vgi_python-0.37.0}/conformance/filter-v2/runtime/error-invalid-overload/filter.arrow +0 -0
  145. {vgi_python-0.36.1 → vgi_python-0.37.0}/conformance/filter-v2/runtime/error-invalid-overload/input.arrow +0 -0
  146. {vgi_python-0.36.1 → vgi_python-0.37.0}/conformance/filter-v2/runtime/error-missing-literal/filter.arrow +0 -0
  147. {vgi_python-0.36.1 → vgi_python-0.37.0}/conformance/filter-v2/runtime/error-missing-literal/input.arrow +0 -0
  148. {vgi_python-0.36.1 → vgi_python-0.37.0}/conformance/filter-v2/runtime/error-non-boolean-root/filter.arrow +0 -0
  149. {vgi_python-0.36.1 → vgi_python-0.37.0}/conformance/filter-v2/runtime/error-non-boolean-root/input.arrow +0 -0
  150. {vgi_python-0.36.1 → vgi_python-0.37.0}/conformance/filter-v2/runtime/error-unknown-standard-function/filter.arrow +0 -0
  151. {vgi_python-0.36.1 → vgi_python-0.37.0}/conformance/filter-v2/runtime/error-unknown-standard-function/input.arrow +0 -0
  152. {vgi_python-0.36.1 → vgi_python-0.37.0}/conformance/filter-v2/runtime/external-in-nonzero-column/expected.arrow +0 -0
  153. {vgi_python-0.36.1 → vgi_python-0.37.0}/conformance/filter-v2/runtime/external-in-nonzero-column/filter.arrow +0 -0
  154. {vgi_python-0.36.1 → vgi_python-0.37.0}/conformance/filter-v2/runtime/external-in-nonzero-column/input.arrow +0 -0
  155. {vgi_python-0.36.1 → vgi_python-0.37.0}/conformance/filter-v2/runtime/external-in-nonzero-column/join-keys-0.arrow +0 -0
  156. {vgi_python-0.36.1 → vgi_python-0.37.0}/conformance/filter-v2/runtime/external-in-nonzero-column/worker-expected.arrow +0 -0
  157. {vgi_python-0.36.1 → vgi_python-0.37.0}/conformance/filter-v2/runtime/function-contains/expected.arrow +0 -0
  158. {vgi_python-0.36.1 → vgi_python-0.37.0}/conformance/filter-v2/runtime/function-contains/filter.arrow +0 -0
  159. {vgi_python-0.36.1 → vgi_python-0.37.0}/conformance/filter-v2/runtime/function-contains/input.arrow +0 -0
  160. {vgi_python-0.36.1 → vgi_python-0.37.0}/conformance/filter-v2/runtime/function-ends-with/expected.arrow +0 -0
  161. {vgi_python-0.36.1 → vgi_python-0.37.0}/conformance/filter-v2/runtime/function-ends-with/filter.arrow +0 -0
  162. {vgi_python-0.36.1 → vgi_python-0.37.0}/conformance/filter-v2/runtime/function-ends-with/input.arrow +0 -0
  163. {vgi_python-0.36.1 → vgi_python-0.37.0}/conformance/filter-v2/runtime/function-list-contains/expected.arrow +0 -0
  164. {vgi_python-0.36.1 → vgi_python-0.37.0}/conformance/filter-v2/runtime/function-list-contains/filter.arrow +0 -0
  165. {vgi_python-0.36.1 → vgi_python-0.37.0}/conformance/filter-v2/runtime/function-list-contains/input.arrow +0 -0
  166. {vgi_python-0.36.1 → vgi_python-0.37.0}/conformance/filter-v2/runtime/function-starts-with/expected.arrow +0 -0
  167. {vgi_python-0.36.1 → vgi_python-0.37.0}/conformance/filter-v2/runtime/function-starts-with/filter.arrow +0 -0
  168. {vgi_python-0.36.1 → vgi_python-0.37.0}/conformance/filter-v2/runtime/function-starts-with/input.arrow +0 -0
  169. {vgi_python-0.36.1 → vgi_python-0.37.0}/conformance/filter-v2/runtime/in-empty/expected.arrow +0 -0
  170. {vgi_python-0.36.1 → vgi_python-0.37.0}/conformance/filter-v2/runtime/in-empty/filter.arrow +0 -0
  171. {vgi_python-0.36.1 → vgi_python-0.37.0}/conformance/filter-v2/runtime/in-empty/input.arrow +0 -0
  172. {vgi_python-0.36.1 → vgi_python-0.37.0}/conformance/filter-v2/runtime/in-empty/worker-expected.arrow +0 -0
  173. {vgi_python-0.36.1 → vgi_python-0.37.0}/conformance/filter-v2/runtime/in-with-null/expected.arrow +0 -0
  174. {vgi_python-0.36.1 → vgi_python-0.37.0}/conformance/filter-v2/runtime/in-with-null/filter.arrow +0 -0
  175. {vgi_python-0.36.1 → vgi_python-0.37.0}/conformance/filter-v2/runtime/in-with-null/input.arrow +0 -0
  176. {vgi_python-0.36.1 → vgi_python-0.37.0}/conformance/filter-v2/runtime/in-with-null/worker-expected.arrow +0 -0
  177. {vgi_python-0.36.1 → vgi_python-0.37.0}/conformance/filter-v2/runtime/is-not-null/expected.arrow +0 -0
  178. {vgi_python-0.36.1 → vgi_python-0.37.0}/conformance/filter-v2/runtime/is-not-null/filter.arrow +0 -0
  179. {vgi_python-0.36.1 → vgi_python-0.37.0}/conformance/filter-v2/runtime/is-not-null/input.arrow +0 -0
  180. {vgi_python-0.36.1 → vgi_python-0.37.0}/conformance/filter-v2/runtime/is-not-null/worker-expected.arrow +0 -0
  181. {vgi_python-0.36.1 → vgi_python-0.37.0}/conformance/filter-v2/runtime/is-null/expected.arrow +0 -0
  182. {vgi_python-0.36.1 → vgi_python-0.37.0}/conformance/filter-v2/runtime/is-null/filter.arrow +0 -0
  183. {vgi_python-0.36.1 → vgi_python-0.37.0}/conformance/filter-v2/runtime/is-null/input.arrow +0 -0
  184. {vgi_python-0.36.1 → vgi_python-0.37.0}/conformance/filter-v2/runtime/is-null/worker-expected.arrow +0 -0
  185. {vgi_python-0.36.1 → vgi_python-0.37.0}/conformance/filter-v2/runtime/kleene-and/expected.arrow +0 -0
  186. {vgi_python-0.36.1 → vgi_python-0.37.0}/conformance/filter-v2/runtime/kleene-and/filter.arrow +0 -0
  187. {vgi_python-0.36.1 → vgi_python-0.37.0}/conformance/filter-v2/runtime/kleene-and/input.arrow +0 -0
  188. {vgi_python-0.36.1 → vgi_python-0.37.0}/conformance/filter-v2/runtime/kleene-not/expected.arrow +0 -0
  189. {vgi_python-0.36.1 → vgi_python-0.37.0}/conformance/filter-v2/runtime/kleene-not/filter.arrow +0 -0
  190. {vgi_python-0.36.1 → vgi_python-0.37.0}/conformance/filter-v2/runtime/kleene-not/input.arrow +0 -0
  191. {vgi_python-0.36.1 → vgi_python-0.37.0}/conformance/filter-v2/runtime/kleene-or/expected.arrow +0 -0
  192. {vgi_python-0.36.1 → vgi_python-0.37.0}/conformance/filter-v2/runtime/kleene-or/filter.arrow +0 -0
  193. {vgi_python-0.36.1 → vgi_python-0.37.0}/conformance/filter-v2/runtime/kleene-or/input.arrow +0 -0
  194. {vgi_python-0.36.1 → vgi_python-0.37.0}/conformance/filter-v2/runtime/nan-comparison/expected.arrow +0 -0
  195. {vgi_python-0.36.1 → vgi_python-0.37.0}/conformance/filter-v2/runtime/nan-comparison/filter.arrow +0 -0
  196. {vgi_python-0.36.1 → vgi_python-0.37.0}/conformance/filter-v2/runtime/nan-comparison/input.arrow +0 -0
  197. {vgi_python-0.36.1 → vgi_python-0.37.0}/conformance/filter-v2/runtime/negative-zero-membership/expected.arrow +0 -0
  198. {vgi_python-0.36.1 → vgi_python-0.37.0}/conformance/filter-v2/runtime/negative-zero-membership/filter.arrow +0 -0
  199. {vgi_python-0.36.1 → vgi_python-0.37.0}/conformance/filter-v2/runtime/negative-zero-membership/input.arrow +0 -0
  200. {vgi_python-0.36.1 → vgi_python-0.37.0}/conformance/filter-v2/runtime/nested-null-propagation/expected.arrow +0 -0
  201. {vgi_python-0.36.1 → vgi_python-0.37.0}/conformance/filter-v2/runtime/nested-null-propagation/filter.arrow +0 -0
  202. {vgi_python-0.36.1 → vgi_python-0.37.0}/conformance/filter-v2/runtime/nested-null-propagation/input.arrow +0 -0
  203. {vgi_python-0.36.1 → vgi_python-0.37.0}/conformance/filter-v2/runtime/not-in-empty/expected.arrow +0 -0
  204. {vgi_python-0.36.1 → vgi_python-0.37.0}/conformance/filter-v2/runtime/not-in-empty/filter.arrow +0 -0
  205. {vgi_python-0.36.1 → vgi_python-0.37.0}/conformance/filter-v2/runtime/not-in-empty/input.arrow +0 -0
  206. {vgi_python-0.36.1 → vgi_python-0.37.0}/conformance/filter-v2/runtime/not-in-empty/worker-expected.arrow +0 -0
  207. {vgi_python-0.36.1 → vgi_python-0.37.0}/conformance/filter-v2/runtime/not-in-with-null/expected.arrow +0 -0
  208. {vgi_python-0.36.1 → vgi_python-0.37.0}/conformance/filter-v2/runtime/not-in-with-null/filter.arrow +0 -0
  209. {vgi_python-0.36.1 → vgi_python-0.37.0}/conformance/filter-v2/runtime/not-in-with-null/input.arrow +0 -0
  210. {vgi_python-0.36.1 → vgi_python-0.37.0}/conformance/filter-v2/runtime/not-in-with-null/worker-expected.arrow +0 -0
  211. {vgi_python-0.36.1 → vgi_python-0.37.0}/conformance/filter-v2/runtime/session-integer-division/expected.arrow +0 -0
  212. {vgi_python-0.36.1 → vgi_python-0.37.0}/conformance/filter-v2/runtime/session-integer-division/filter.arrow +0 -0
  213. {vgi_python-0.36.1 → vgi_python-0.37.0}/conformance/filter-v2/runtime/session-integer-division/input.arrow +0 -0
  214. {vgi_python-0.36.1 → vgi_python-0.37.0}/conformance/filter-v2/runtime-manifest.json +0 -0
  215. {vgi_python-0.36.1 → vgi_python-0.37.0}/dist-vgi/.gitignore +0 -0
  216. {vgi_python-0.36.1 → vgi_python-0.37.0}/docs/aggregate-functions.md +0 -0
  217. {vgi_python-0.36.1 → vgi_python-0.37.0}/docs/api/arguments.md +0 -0
  218. {vgi_python-0.36.1 → vgi_python-0.37.0}/docs/api/auth.md +0 -0
  219. {vgi_python-0.36.1 → vgi_python-0.37.0}/docs/api/catalogs.md +0 -0
  220. {vgi_python-0.36.1 → vgi_python-0.37.0}/docs/api/client.md +0 -0
  221. {vgi_python-0.36.1 → vgi_python-0.37.0}/docs/api/exceptions.md +0 -0
  222. {vgi_python-0.36.1 → vgi_python-0.37.0}/docs/api/filters.md +0 -0
  223. {vgi_python-0.36.1 → vgi_python-0.37.0}/docs/api/functions.md +0 -0
  224. {vgi_python-0.36.1 → vgi_python-0.37.0}/docs/api/http.md +0 -0
  225. {vgi_python-0.36.1 → vgi_python-0.37.0}/docs/api/index.md +0 -0
  226. {vgi_python-0.36.1 → vgi_python-0.37.0}/docs/api/metadata.md +0 -0
  227. {vgi_python-0.36.1 → vgi_python-0.37.0}/docs/api/observability.md +0 -0
  228. {vgi_python-0.36.1 → vgi_python-0.37.0}/docs/api/storage.md +0 -0
  229. {vgi_python-0.36.1 → vgi_python-0.37.0}/docs/api/transactor.md +0 -0
  230. {vgi_python-0.36.1 → vgi_python-0.37.0}/docs/api/worker.md +0 -0
  231. {vgi_python-0.36.1 → vgi_python-0.37.0}/docs/argument-serialization.md +0 -0
  232. {vgi_python-0.36.1 → vgi_python-0.37.0}/docs/assets/apple-touch-icon.png +0 -0
  233. {vgi_python-0.36.1 → vgi_python-0.37.0}/docs/assets/favicon-16x16.png +0 -0
  234. {vgi_python-0.36.1 → vgi_python-0.37.0}/docs/assets/favicon-32x32.png +0 -0
  235. {vgi_python-0.36.1 → vgi_python-0.37.0}/docs/assets/favicon.ico +0 -0
  236. {vgi_python-0.36.1 → vgi_python-0.37.0}/docs/assets/kinds/aggregate.svg +0 -0
  237. {vgi_python-0.36.1 → vgi_python-0.37.0}/docs/assets/kinds/buffering.svg +0 -0
  238. {vgi_python-0.36.1 → vgi_python-0.37.0}/docs/assets/kinds/scalar.svg +0 -0
  239. {vgi_python-0.36.1 → vgi_python-0.37.0}/docs/assets/kinds/table-in-out.svg +0 -0
  240. {vgi_python-0.36.1 → vgi_python-0.37.0}/docs/assets/kinds/table.svg +0 -0
  241. {vgi_python-0.36.1 → vgi_python-0.37.0}/docs/assets/logo.png +0 -0
  242. {vgi_python-0.36.1 → vgi_python-0.37.0}/docs/assets/social-card.png +0 -0
  243. {vgi_python-0.36.1 → vgi_python-0.37.0}/docs/authentication.md +0 -0
  244. {vgi_python-0.36.1 → vgi_python-0.37.0}/docs/catalog-interface.md +0 -0
  245. {vgi_python-0.36.1 → vgi_python-0.37.0}/docs/cli.md +0 -0
  246. {vgi_python-0.36.1 → vgi_python-0.37.0}/docs/column-statistics.md +0 -0
  247. {vgi_python-0.36.1 → vgi_python-0.37.0}/docs/concepts/index.md +0 -0
  248. {vgi_python-0.36.1 → vgi_python-0.37.0}/docs/contributing-docs.md +0 -0
  249. {vgi_python-0.36.1 → vgi_python-0.37.0}/docs/filter-pushdown.md +0 -0
  250. {vgi_python-0.36.1 → vgi_python-0.37.0}/docs/generator-api.md +0 -0
  251. {vgi_python-0.36.1 → vgi_python-0.37.0}/docs/global-functions.md +0 -0
  252. {vgi_python-0.36.1 → vgi_python-0.37.0}/docs/how-to/catalogs.md +0 -0
  253. {vgi_python-0.36.1 → vgi_python-0.37.0}/docs/how-to/function-patterns.md +0 -0
  254. {vgi_python-0.36.1 → vgi_python-0.37.0}/docs/how-to/http-auth.md +0 -0
  255. {vgi_python-0.36.1 → vgi_python-0.37.0}/docs/how-to/index.md +0 -0
  256. {vgi_python-0.36.1 → vgi_python-0.37.0}/docs/how-to/iroh.md +0 -0
  257. {vgi_python-0.36.1 → vgi_python-0.37.0}/docs/how-to/pushdown-and-statistics.md +0 -0
  258. {vgi_python-0.36.1 → vgi_python-0.37.0}/docs/how-to/state-storage.md +0 -0
  259. {vgi_python-0.36.1 → vgi_python-0.37.0}/docs/how-to/tailnet.md +0 -0
  260. {vgi_python-0.36.1 → vgi_python-0.37.0}/docs/index.md +0 -0
  261. {vgi_python-0.36.1 → vgi_python-0.37.0}/docs/lifecycle.md +0 -0
  262. {vgi_python-0.36.1 → vgi_python-0.37.0}/docs/metadata.md +0 -0
  263. {vgi_python-0.36.1 → vgi_python-0.37.0}/docs/overrides/main.html +0 -0
  264. {vgi_python-0.36.1 → vgi_python-0.37.0}/docs/protocol/index.md +0 -0
  265. {vgi_python-0.36.1 → vgi_python-0.37.0}/docs/protocol/vgi-catalog-query-pushdown-design.md +0 -0
  266. {vgi_python-0.36.1 → vgi_python-0.37.0}/docs/protocol/vgi-duckdb-filter-adapter.md +0 -0
  267. {vgi_python-0.36.1 → vgi_python-0.37.0}/docs/protocol/vgi-filter-encoding-v2-spec.md +0 -0
  268. {vgi_python-0.36.1 → vgi_python-0.37.0}/docs/protocol/vgi-protocol-proposed-changes.md +0 -0
  269. {vgi_python-0.36.1 → vgi_python-0.37.0}/docs/protocol/vgi-runtime-filter-artifacts.md +0 -0
  270. {vgi_python-0.36.1 → vgi_python-0.37.0}/docs/robots.txt +0 -0
  271. {vgi_python-0.36.1 → vgi_python-0.37.0}/docs/shared-storage.md +0 -0
  272. {vgi_python-0.36.1 → vgi_python-0.37.0}/docs/stylesheets/extra.css +0 -0
  273. {vgi_python-0.36.1 → vgi_python-0.37.0}/docs/tutorial/index.md +0 -0
  274. {vgi_python-0.36.1 → vgi_python-0.37.0}/docs/tutorial/scalar.md +0 -0
  275. {vgi_python-0.36.1 → vgi_python-0.37.0}/docs/tutorial/table.md +0 -0
  276. {vgi_python-0.36.1 → vgi_python-0.37.0}/docs/vgi-logo.png +0 -0
  277. {vgi_python-0.36.1 → vgi_python-0.37.0}/examples/batch_index_worker.py +0 -0
  278. {vgi_python-0.36.1 → vgi_python-0.37.0}/examples/cache_worker.py +0 -0
  279. {vgi_python-0.36.1 → vgi_python-0.37.0}/examples/calc_scalar_worker.py +0 -0
  280. {vgi_python-0.36.1 → vgi_python-0.37.0}/examples/calc_worker.py +0 -0
  281. {vgi_python-0.36.1 → vgi_python-0.37.0}/examples/copy_format_worker.py +0 -0
  282. {vgi_python-0.36.1 → vgi_python-0.37.0}/examples/filter_worker.py +0 -0
  283. {vgi_python-0.36.1 → vgi_python-0.37.0}/examples/greeting_scalar_worker.py +0 -0
  284. {vgi_python-0.36.1 → vgi_python-0.37.0}/examples/row_count_worker.py +0 -0
  285. {vgi_python-0.36.1 → vgi_python-0.37.0}/examples/series_streaming_worker.py +0 -0
  286. {vgi_python-0.36.1 → vgi_python-0.37.0}/examples/sum_worker.py +0 -0
  287. {vgi_python-0.36.1 → vgi_python-0.37.0}/identity.png +0 -0
  288. {vgi_python-0.36.1 → vgi_python-0.37.0}/mkdocs.yml +0 -0
  289. {vgi_python-0.36.1 → vgi_python-0.37.0}/packages/vgi-fixtures/LICENSE +0 -0
  290. {vgi_python-0.36.1 → vgi_python-0.37.0}/packages/vgi-fixtures/README.md +0 -0
  291. {vgi_python-0.36.1 → vgi_python-0.37.0}/packages/vgi-fixtures/docker/Dockerfile +0 -0
  292. {vgi_python-0.36.1 → vgi_python-0.37.0}/packages/vgi-fixtures/docker/docker-entrypoint.sh +0 -0
  293. {vgi_python-0.36.1 → vgi_python-0.37.0}/packages/vgi-fixtures/pyproject.toml +0 -0
  294. {vgi_python-0.36.1 → vgi_python-0.37.0}/scripts/measure_startup.py +0 -0
  295. {vgi_python-0.36.1 → vgi_python-0.37.0}/scripts/regen_generated.py +0 -0
  296. {vgi_python-0.36.1 → vgi_python-0.37.0}/scripts/run_all_tests.sh +0 -0
  297. {vgi_python-0.36.1 → vgi_python-0.37.0}/test-data/generate.sh +0 -0
  298. {vgi_python-0.36.1 → vgi_python-0.37.0}/tests/__init__.py +0 -0
  299. {vgi_python-0.36.1 → vgi_python-0.37.0}/tests/_http_fixtures.py +0 -0
  300. {vgi_python-0.36.1 → vgi_python-0.37.0}/tests/catalog/__init__.py +0 -0
  301. {vgi_python-0.36.1 → vgi_python-0.37.0}/tests/catalog/test_attach_option.py +0 -0
  302. {vgi_python-0.36.1 → vgi_python-0.37.0}/tests/catalog/test_catalog_interface.py +0 -0
  303. {vgi_python-0.36.1 → vgi_python-0.37.0}/tests/catalog/test_client_catalog.py +0 -0
  304. {vgi_python-0.36.1 → vgi_python-0.37.0}/tests/catalog/test_column_statistics.py +0 -0
  305. {vgi_python-0.36.1 → vgi_python-0.37.0}/tests/catalog/test_declarative.py +0 -0
  306. {vgi_python-0.36.1 → vgi_python-0.37.0}/tests/catalog/test_example_worker_catalog.py +0 -0
  307. {vgi_python-0.36.1 → vgi_python-0.37.0}/tests/catalog/test_integration.py +0 -0
  308. {vgi_python-0.36.1 → vgi_python-0.37.0}/tests/catalog/test_required_filters.py +0 -0
  309. {vgi_python-0.36.1 → vgi_python-0.37.0}/tests/catalog/test_scan_branches.py +0 -0
  310. {vgi_python-0.36.1 → vgi_python-0.37.0}/tests/catalog/test_serialization.py +0 -0
  311. {vgi_python-0.36.1 → vgi_python-0.37.0}/tests/catalog/test_setting.py +0 -0
  312. {vgi_python-0.36.1 → vgi_python-0.37.0}/tests/catalog/test_storage.py +0 -0
  313. {vgi_python-0.36.1 → vgi_python-0.37.0}/tests/catalog/test_time_travel.py +0 -0
  314. {vgi_python-0.36.1 → vgi_python-0.37.0}/tests/catalog/test_writable_table.py +0 -0
  315. {vgi_python-0.36.1 → vgi_python-0.37.0}/tests/client/__init__.py +0 -0
  316. {vgi_python-0.36.1 → vgi_python-0.37.0}/tests/client/test_aggregate_client.py +0 -0
  317. {vgi_python-0.36.1 → vgi_python-0.37.0}/tests/client/test_batch_metadata_callback.py +0 -0
  318. {vgi_python-0.36.1 → vgi_python-0.37.0}/tests/client/test_bind_and_join_keys.py +0 -0
  319. {vgi_python-0.36.1 → vgi_python-0.37.0}/tests/client/test_broken_pipe.py +0 -0
  320. {vgi_python-0.36.1 → vgi_python-0.37.0}/tests/client/test_cli.py +0 -0
  321. {vgi_python-0.36.1 → vgi_python-0.37.0}/tests/client/test_cli_catalog_functions.py +0 -0
  322. {vgi_python-0.36.1 → vgi_python-0.37.0}/tests/client/test_copy_client.py +0 -0
  323. {vgi_python-0.36.1 → vgi_python-0.37.0}/tests/client/test_http_response_budget.py +0 -0
  324. {vgi_python-0.36.1 → vgi_python-0.37.0}/tests/client/test_iroh_client.py +0 -0
  325. {vgi_python-0.36.1 → vgi_python-0.37.0}/tests/client/test_scan_branches_client.py +0 -0
  326. {vgi_python-0.36.1 → vgi_python-0.37.0}/tests/client/test_split_client.py +0 -0
  327. {vgi_python-0.36.1 → vgi_python-0.37.0}/tests/client/test_stop_force.py +0 -0
  328. {vgi_python-0.36.1 → vgi_python-0.37.0}/tests/client/test_table_column_statistics.py +0 -0
  329. {vgi_python-0.36.1 → vgi_python-0.37.0}/tests/client/test_time_travel_client.py +0 -0
  330. {vgi_python-0.36.1 → vgi_python-0.37.0}/tests/client/test_worker_debug.py +0 -0
  331. {vgi_python-0.36.1 → vgi_python-0.37.0}/tests/conformance/__init__.py +0 -0
  332. {vgi_python-0.36.1 → vgi_python-0.37.0}/tests/conformance/_stub.py +0 -0
  333. {vgi_python-0.36.1 → vgi_python-0.37.0}/tests/conformance/conftest.py +0 -0
  334. {vgi_python-0.36.1 → vgi_python-0.37.0}/tests/conformance/test_accumulate.py +0 -0
  335. {vgi_python-0.36.1 → vgi_python-0.37.0}/tests/conformance/test_aggregate.py +0 -0
  336. {vgi_python-0.36.1 → vgi_python-0.37.0}/tests/conformance/test_attach.py +0 -0
  337. {vgi_python-0.36.1 → vgi_python-0.37.0}/tests/conformance/test_bearer_auth.py +0 -0
  338. {vgi_python-0.36.1 → vgi_python-0.37.0}/tests/conformance/test_const_param_enforcement.py +0 -0
  339. {vgi_python-0.36.1 → vgi_python-0.37.0}/tests/conformance/test_container.py +0 -0
  340. {vgi_python-0.36.1 → vgi_python-0.37.0}/tests/conformance/test_copy_from.py +0 -0
  341. {vgi_python-0.36.1 → vgi_python-0.37.0}/tests/conformance/test_copy_to.py +0 -0
  342. {vgi_python-0.36.1 → vgi_python-0.37.0}/tests/conformance/test_directory_parity.py +0 -0
  343. {vgi_python-0.36.1 → vgi_python-0.37.0}/tests/conformance/test_function_inventory.py +0 -0
  344. {vgi_python-0.36.1 → vgi_python-0.37.0}/tests/conformance/test_github.py +0 -0
  345. {vgi_python-0.36.1 → vgi_python-0.37.0}/tests/conformance/test_http_client.py +0 -0
  346. {vgi_python-0.36.1 → vgi_python-0.37.0}/tests/conformance/test_http_external_location.py +0 -0
  347. {vgi_python-0.36.1 → vgi_python-0.37.0}/tests/conformance/test_http_upload_url.py +0 -0
  348. {vgi_python-0.36.1 → vgi_python-0.37.0}/tests/conformance/test_macro.py +0 -0
  349. {vgi_python-0.36.1 → vgi_python-0.37.0}/tests/conformance/test_overload.py +0 -0
  350. {vgi_python-0.36.1 → vgi_python-0.37.0}/tests/conformance/test_protocol_inventory.py +0 -0
  351. {vgi_python-0.36.1 → vgi_python-0.37.0}/tests/conformance/test_protocol_version.py +0 -0
  352. {vgi_python-0.36.1 → vgi_python-0.37.0}/tests/conformance/test_resumable_scan.py +0 -0
  353. {vgi_python-0.36.1 → vgi_python-0.37.0}/tests/conformance/test_scalar.py +0 -0
  354. {vgi_python-0.36.1 → vgi_python-0.37.0}/tests/conformance/test_scalar_attach_opaque_data.py +0 -0
  355. {vgi_python-0.36.1 → vgi_python-0.37.0}/tests/conformance/test_secret.py +0 -0
  356. {vgi_python-0.36.1 → vgi_python-0.37.0}/tests/conformance/test_settings.py +0 -0
  357. {vgi_python-0.36.1 → vgi_python-0.37.0}/tests/conformance/test_splits.py +0 -0
  358. {vgi_python-0.36.1 → vgi_python-0.37.0}/tests/conformance/test_table.py +0 -0
  359. {vgi_python-0.36.1 → vgi_python-0.37.0}/tests/conformance/test_table_in_out.py +0 -0
  360. {vgi_python-0.36.1 → vgi_python-0.37.0}/tests/conformance/test_view.py +0 -0
  361. {vgi_python-0.36.1 → vgi_python-0.37.0}/tests/conformance/test_writable.py +0 -0
  362. {vgi_python-0.36.1 → vgi_python-0.37.0}/tests/conftest.py +0 -0
  363. {vgi_python-0.36.1 → vgi_python-0.37.0}/tests/data/split_tokens/anchor_len_overrun.bin +0 -0
  364. {vgi_python-0.36.1 → vgi_python-0.37.0}/tests/data/split_tokens/bad_fingerprint.bin +0 -0
  365. {vgi_python-0.36.1 → vgi_python-0.37.0}/tests/data/split_tokens/bad_flags_unsealed_but_key_present.bin +0 -0
  366. {vgi_python-0.36.1 → vgi_python-0.37.0}/tests/data/split_tokens/bad_version.bin +0 -0
  367. {vgi_python-0.36.1 → vgi_python-0.37.0}/tests/data/split_tokens/generate.py +0 -0
  368. {vgi_python-0.36.1 → vgi_python-0.37.0}/tests/data/split_tokens/manifest.json +0 -0
  369. {vgi_python-0.36.1 → vgi_python-0.37.0}/tests/data/split_tokens/reserved_flag_bit.bin +0 -0
  370. {vgi_python-0.36.1 → vgi_python-0.37.0}/tests/data/split_tokens/stale_anchor.bin +0 -0
  371. {vgi_python-0.36.1 → vgi_python-0.37.0}/tests/data/split_tokens/truncated.bin +0 -0
  372. {vgi_python-0.36.1 → vgi_python-0.37.0}/tests/data/split_tokens/valid_sealed.bin +0 -0
  373. {vgi_python-0.36.1 → vgi_python-0.37.0}/tests/data/split_tokens/valid_unsealed.bin +0 -0
  374. {vgi_python-0.36.1 → vgi_python-0.37.0}/tests/scalar/__init__.py +0 -0
  375. {vgi_python-0.36.1 → vgi_python-0.37.0}/tests/scalar/test_bernoulli_function.py +0 -0
  376. {vgi_python-0.36.1 → vgi_python-0.37.0}/tests/scalar/test_binary_packet_function.py +0 -0
  377. {vgi_python-0.36.1 → vgi_python-0.37.0}/tests/scalar/test_client.py +0 -0
  378. {vgi_python-0.36.1 → vgi_python-0.37.0}/tests/scalar/test_conditional_message_function.py +0 -0
  379. {vgi_python-0.36.1 → vgi_python-0.37.0}/tests/scalar/test_hash_seed_function.py +0 -0
  380. {vgi_python-0.36.1 → vgi_python-0.37.0}/tests/scalar/test_multiply_by_setting_function.py +0 -0
  381. {vgi_python-0.36.1 → vgi_python-0.37.0}/tests/scalar/test_multiply_function.py +0 -0
  382. {vgi_python-0.36.1 → vgi_python-0.37.0}/tests/scalar/test_random_bytes_function.py +0 -0
  383. {vgi_python-0.36.1 → vgi_python-0.37.0}/tests/scalar/test_return_secret_value_function.py +0 -0
  384. {vgi_python-0.36.1 → vgi_python-0.37.0}/tests/table/__init__.py +0 -0
  385. {vgi_python-0.36.1 → vgi_python-0.37.0}/tests/table/generator/__init__.py +0 -0
  386. {vgi_python-0.36.1 → vgi_python-0.37.0}/tests/table/generator/test_constant_columns_function.py +0 -0
  387. {vgi_python-0.36.1 → vgi_python-0.37.0}/tests/table/generator/test_double_sequence_function.py +0 -0
  388. {vgi_python-0.36.1 → vgi_python-0.37.0}/tests/table/generator/test_exception_function.py +0 -0
  389. {vgi_python-0.36.1 → vgi_python-0.37.0}/tests/table/generator/test_filter_echo_function.py +0 -0
  390. {vgi_python-0.36.1 → vgi_python-0.37.0}/tests/table/generator/test_logging_function.py +0 -0
  391. {vgi_python-0.36.1 → vgi_python-0.37.0}/tests/table/generator/test_nested_sequence_function.py +0 -0
  392. {vgi_python-0.36.1 → vgi_python-0.37.0}/tests/table/generator/test_partitioned_function.py +0 -0
  393. {vgi_python-0.36.1 → vgi_python-0.37.0}/tests/table/generator/test_projected_data_function.py +0 -0
  394. {vgi_python-0.36.1 → vgi_python-0.37.0}/tests/table/generator/test_sequence_function.py +0 -0
  395. {vgi_python-0.36.1 → vgi_python-0.37.0}/tests/table/generator/test_settings_function.py +0 -0
  396. {vgi_python-0.36.1 → vgi_python-0.37.0}/tests/table/generator/test_struct_settings_function.py +0 -0
  397. {vgi_python-0.36.1 → vgi_python-0.37.0}/tests/table/generator/test_ten_thousand_function.py +0 -0
  398. {vgi_python-0.36.1 → vgi_python-0.37.0}/tests/table/test_wide_columns.py +0 -0
  399. {vgi_python-0.36.1 → vgi_python-0.37.0}/tests/table_in_out/__init__.py +0 -0
  400. {vgi_python-0.36.1 → vgi_python-0.37.0}/tests/table_in_out/generator/__init__.py +0 -0
  401. {vgi_python-0.36.1 → vgi_python-0.37.0}/tests/table_in_out/generator/test_buffer_input_function.py +0 -0
  402. {vgi_python-0.36.1 → vgi_python-0.37.0}/tests/table_in_out/generator/test_echo_function.py +0 -0
  403. {vgi_python-0.36.1 → vgi_python-0.37.0}/tests/table_in_out/generator/test_exception_functions.py +0 -0
  404. {vgi_python-0.36.1 → vgi_python-0.37.0}/tests/table_in_out/generator/test_filter_by_setting_function.py +0 -0
  405. {vgi_python-0.36.1 → vgi_python-0.37.0}/tests/table_in_out/generator/test_repeat_inputs_function.py +0 -0
  406. {vgi_python-0.36.1 → vgi_python-0.37.0}/tests/table_in_out/generator/test_substream_partial_sum_function.py +0 -0
  407. {vgi_python-0.36.1 → vgi_python-0.37.0}/tests/table_in_out/generator/test_sum_all_columns_function.py +0 -0
  408. {vgi_python-0.36.1 → vgi_python-0.37.0}/tests/table_in_out/test_blended_exchange.py +0 -0
  409. {vgi_python-0.36.1 → vgi_python-0.37.0}/tests/table_in_out/test_blended_metadata.py +0 -0
  410. {vgi_python-0.36.1 → vgi_python-0.37.0}/tests/table_in_out/test_client.py +0 -0
  411. {vgi_python-0.36.1 → vgi_python-0.37.0}/tests/tailnet/Dockerfile +0 -0
  412. {vgi_python-0.36.1 → vgi_python-0.37.0}/tests/tailnet/__init__.py +0 -0
  413. {vgi_python-0.36.1 → vgi_python-0.37.0}/tests/tailnet/compose.yaml +0 -0
  414. {vgi_python-0.36.1 → vgi_python-0.37.0}/tests/tailnet/probe.py +0 -0
  415. {vgi_python-0.36.1 → vgi_python-0.37.0}/tests/tailnet/run.sh +0 -0
  416. {vgi_python-0.36.1 → vgi_python-0.37.0}/tests/tailnet/test_worker.py +0 -0
  417. {vgi_python-0.36.1 → vgi_python-0.37.0}/tests/tailnet/worker.py +0 -0
  418. {vgi_python-0.36.1 → vgi_python-0.37.0}/tests/test_access_log_audit.py +0 -0
  419. {vgi_python-0.36.1 → vgi_python-0.37.0}/tests/test_aggregate_function.py +0 -0
  420. {vgi_python-0.36.1 → vgi_python-0.37.0}/tests/test_argument_spec.py +0 -0
  421. {vgi_python-0.36.1 → vgi_python-0.37.0}/tests/test_auth.py +0 -0
  422. {vgi_python-0.36.1 → vgi_python-0.37.0}/tests/test_bind_exceptions.py +0 -0
  423. {vgi_python-0.36.1 → vgi_python-0.37.0}/tests/test_bind_request_at_clause.py +0 -0
  424. {vgi_python-0.36.1 → vgi_python-0.37.0}/tests/test_bound_storage_conformance.py +0 -0
  425. {vgi_python-0.36.1 → vgi_python-0.37.0}/tests/test_cache_control.py +0 -0
  426. {vgi_python-0.36.1 → vgi_python-0.37.0}/tests/test_call_state_attach.py +0 -0
  427. {vgi_python-0.36.1 → vgi_python-0.37.0}/tests/test_catalog_auth_binding.py +0 -0
  428. {vgi_python-0.36.1 → vgi_python-0.37.0}/tests/test_client_oauth.py +0 -0
  429. {vgi_python-0.36.1 → vgi_python-0.37.0}/tests/test_codegen_request_inventory.py +0 -0
  430. {vgi_python-0.36.1 → vgi_python-0.37.0}/tests/test_copy_from_function.py +0 -0
  431. {vgi_python-0.36.1 → vgi_python-0.37.0}/tests/test_copy_to_function.py +0 -0
  432. {vgi_python-0.36.1 → vgi_python-0.37.0}/tests/test_docstrings.py +0 -0
  433. {vgi_python-0.36.1 → vgi_python-0.37.0}/tests/test_documentation_examples.py +0 -0
  434. {vgi_python-0.36.1 → vgi_python-0.37.0}/tests/test_dynamic_filter_http_turns.py +0 -0
  435. {vgi_python-0.36.1 → vgi_python-0.37.0}/tests/test_example_function_arg_types.py +0 -0
  436. {vgi_python-0.36.1 → vgi_python-0.37.0}/tests/test_examples_workers.py +0 -0
  437. {vgi_python-0.36.1 → vgi_python-0.37.0}/tests/test_exception_handling.py +0 -0
  438. {vgi_python-0.36.1 → vgi_python-0.37.0}/tests/test_exceptions.py +0 -0
  439. {vgi_python-0.36.1 → vgi_python-0.37.0}/tests/test_filter_pushdown.py +0 -0
  440. {vgi_python-0.36.1 → vgi_python-0.37.0}/tests/test_filter_pushdown_extension.py +0 -0
  441. {vgi_python-0.36.1 → vgi_python-0.37.0}/tests/test_filter_v2_builder.py +0 -0
  442. {vgi_python-0.36.1 → vgi_python-0.37.0}/tests/test_filter_v2_runtime_corpus.py +0 -0
  443. {vgi_python-0.36.1 → vgi_python-0.37.0}/tests/test_filter_v2_spec_schema.py +0 -0
  444. {vgi_python-0.36.1 → vgi_python-0.37.0}/tests/test_fixture_catalog_parity.py +0 -0
  445. {vgi_python-0.36.1 → vgi_python-0.37.0}/tests/test_function_shape_mismatch.py +0 -0
  446. {vgi_python-0.36.1 → vgi_python-0.37.0}/tests/test_function_storage.py +0 -0
  447. {vgi_python-0.36.1 → vgi_python-0.37.0}/tests/test_function_storage_azure_sql.py +0 -0
  448. {vgi_python-0.36.1 → vgi_python-0.37.0}/tests/test_function_storage_cf_do.py +0 -0
  449. {vgi_python-0.36.1 → vgi_python-0.37.0}/tests/test_function_storage_cf_do_integration.py +0 -0
  450. {vgi_python-0.36.1 → vgi_python-0.37.0}/tests/test_function_storage_conformance.py +0 -0
  451. {vgi_python-0.36.1 → vgi_python-0.37.0}/tests/test_generated_cpp_constants.py +0 -0
  452. {vgi_python-0.36.1 → vgi_python-0.37.0}/tests/test_generated_cpp_protocol_name.py +0 -0
  453. {vgi_python-0.36.1 → vgi_python-0.37.0}/tests/test_generated_cpp_protocol_version.py +0 -0
  454. {vgi_python-0.36.1 → vgi_python-0.37.0}/tests/test_generated_cpp_request_builders.py +0 -0
  455. {vgi_python-0.36.1 → vgi_python-0.37.0}/tests/test_generated_cpp_schemas.py +0 -0
  456. {vgi_python-0.36.1 → vgi_python-0.37.0}/tests/test_generated_cpp_secret.py +0 -0
  457. {vgi_python-0.36.1 → vgi_python-0.37.0}/tests/test_generated_go_schemas.py +0 -0
  458. {vgi_python-0.36.1 → vgi_python-0.37.0}/tests/test_generated_java_schemas.py +0 -0
  459. {vgi_python-0.36.1 → vgi_python-0.37.0}/tests/test_generated_protocol_version.py +0 -0
  460. {vgi_python-0.36.1 → vgi_python-0.37.0}/tests/test_generated_rust_request_builders.py +0 -0
  461. {vgi_python-0.36.1 → vgi_python-0.37.0}/tests/test_generated_rust_schemas.py +0 -0
  462. {vgi_python-0.36.1 → vgi_python-0.37.0}/tests/test_generated_schemas_cross_lang.py +0 -0
  463. {vgi_python-0.36.1 → vgi_python-0.37.0}/tests/test_generated_ts_client.py +0 -0
  464. {vgi_python-0.36.1 → vgi_python-0.37.0}/tests/test_generated_ts_schemas.py +0 -0
  465. {vgi_python-0.36.1 → vgi_python-0.37.0}/tests/test_http_demo_storage.py +0 -0
  466. {vgi_python-0.36.1 → vgi_python-0.37.0}/tests/test_http_s3_offload_input.py +0 -0
  467. {vgi_python-0.36.1 → vgi_python-0.37.0}/tests/test_http_s3_offload_output.py +0 -0
  468. {vgi_python-0.36.1 → vgi_python-0.37.0}/tests/test_import_side_effects.py +0 -0
  469. {vgi_python-0.36.1 → vgi_python-0.37.0}/tests/test_launch_transport.py +0 -0
  470. {vgi_python-0.36.1 → vgi_python-0.37.0}/tests/test_metadata.py +0 -0
  471. {vgi_python-0.36.1 → vgi_python-0.37.0}/tests/test_mypy_consolidated.py +0 -0
  472. {vgi_python-0.36.1 → vgi_python-0.37.0}/tests/test_nest_tensor.py +0 -0
  473. {vgi_python-0.36.1 → vgi_python-0.37.0}/tests/test_otel.py +0 -0
  474. {vgi_python-0.36.1 → vgi_python-0.37.0}/tests/test_projection_enforcement.py +0 -0
  475. {vgi_python-0.36.1 → vgi_python-0.37.0}/tests/test_projection_repro.py +0 -0
  476. {vgi_python-0.36.1 → vgi_python-0.37.0}/tests/test_protocol_classes.py +0 -0
  477. {vgi_python-0.36.1 → vgi_python-0.37.0}/tests/test_resolved_secrets.py +0 -0
  478. {vgi_python-0.36.1 → vgi_python-0.37.0}/tests/test_schema_paths_v2.py +0 -0
  479. {vgi_python-0.36.1 → vgi_python-0.37.0}/tests/test_schema_scoped_functions.py +0 -0
  480. {vgi_python-0.36.1 → vgi_python-0.37.0}/tests/test_schema_utils.py +0 -0
  481. {vgi_python-0.36.1 → vgi_python-0.37.0}/tests/test_setting_secret_annotations.py +0 -0
  482. {vgi_python-0.36.1 → vgi_python-0.37.0}/tests/test_signing_key.py +0 -0
  483. {vgi_python-0.36.1 → vgi_python-0.37.0}/tests/test_split_token.py +0 -0
  484. {vgi_python-0.36.1 → vgi_python-0.37.0}/tests/test_subprocess_transport.py +0 -0
  485. {vgi_python-0.36.1 → vgi_python-0.37.0}/tests/test_table_buffering_function.py +0 -0
  486. {vgi_python-0.36.1 → vgi_python-0.37.0}/tests/test_table_function_dynamic_to_string.py +0 -0
  487. {vgi_python-0.36.1 → vgi_python-0.37.0}/tests/test_tcp_transport.py +0 -0
  488. {vgi_python-0.36.1 → vgi_python-0.37.0}/tests/test_type_bounds.py +0 -0
  489. {vgi_python-0.36.1 → vgi_python-0.37.0}/tests/test_union_argument.py +0 -0
  490. {vgi_python-0.36.1 → vgi_python-0.37.0}/tests/test_wire_record_schema_parity.py +0 -0
  491. {vgi_python-0.36.1 → vgi_python-0.37.0}/tests/test_worker.py +0 -0
  492. {vgi_python-0.36.1 → vgi_python-0.37.0}/tests/test_worker_cli.py +0 -0
  493. {vgi_python-0.36.1 → vgi_python-0.37.0}/tests/test_worker_page.py +0 -0
  494. {vgi_python-0.36.1 → vgi_python-0.37.0}/tests/test_write_results.py +0 -0
  495. {vgi_python-0.36.1 → vgi_python-0.37.0}/tests/transactor/__init__.py +0 -0
  496. {vgi_python-0.36.1 → vgi_python-0.37.0}/tests/transactor/test_transactor.py +0 -0
  497. {vgi_python-0.36.1 → vgi_python-0.37.0}/vgi/__init__.py +0 -0
  498. {vgi_python-0.36.1 → vgi_python-0.37.0}/vgi/_duckdb.py +0 -0
  499. {vgi_python-0.36.1 → vgi_python-0.37.0}/vgi/_storage_profile.py +0 -0
  500. {vgi_python-0.36.1 → vgi_python-0.37.0}/vgi/_test_fixtures/__init__.py +0 -0
  501. {vgi_python-0.36.1 → vgi_python-0.37.0}/vgi/_test_fixtures/accumulate/__init__.py +0 -0
  502. {vgi_python-0.36.1 → vgi_python-0.37.0}/vgi/_test_fixtures/accumulate/worker.py +0 -0
  503. {vgi_python-0.36.1 → vgi_python-0.37.0}/vgi/_test_fixtures/aggregate/__init__.py +0 -0
  504. {vgi_python-0.36.1 → vgi_python-0.37.0}/vgi/_test_fixtures/aggregate/_common.py +0 -0
  505. {vgi_python-0.36.1 → vgi_python-0.37.0}/vgi/_test_fixtures/aggregate/basic.py +0 -0
  506. {vgi_python-0.36.1 → vgi_python-0.37.0}/vgi/_test_fixtures/aggregate/dynamic.py +0 -0
  507. {vgi_python-0.36.1 → vgi_python-0.37.0}/vgi/_test_fixtures/aggregate/generic.py +0 -0
  508. {vgi_python-0.36.1 → vgi_python-0.37.0}/vgi/_test_fixtures/aggregate/listagg.py +0 -0
  509. {vgi_python-0.36.1 → vgi_python-0.37.0}/vgi/_test_fixtures/aggregate/percentile.py +0 -0
  510. {vgi_python-0.36.1 → vgi_python-0.37.0}/vgi/_test_fixtures/aggregate/same_name.py +0 -0
  511. {vgi_python-0.36.1 → vgi_python-0.37.0}/vgi/_test_fixtures/aggregate/secret_typed.py +0 -0
  512. {vgi_python-0.36.1 → vgi_python-0.37.0}/vgi/_test_fixtures/aggregate/streaming.py +0 -0
  513. {vgi_python-0.36.1 → vgi_python-0.37.0}/vgi/_test_fixtures/aggregate/varargs.py +0 -0
  514. {vgi_python-0.36.1 → vgi_python-0.37.0}/vgi/_test_fixtures/aggregate/window.py +0 -0
  515. {vgi_python-0.36.1 → vgi_python-0.37.0}/vgi/_test_fixtures/attach_options.py +0 -0
  516. {vgi_python-0.36.1 → vgi_python-0.37.0}/vgi/_test_fixtures/bad_enum.py +0 -0
  517. {vgi_python-0.36.1 → vgi_python-0.37.0}/vgi/_test_fixtures/bad_protocol.py +0 -0
  518. {vgi_python-0.36.1 → vgi_python-0.37.0}/vgi/_test_fixtures/cancellable.py +0 -0
  519. {vgi_python-0.36.1 → vgi_python-0.37.0}/vgi/_test_fixtures/catalog.py +0 -0
  520. {vgi_python-0.36.1 → vgi_python-0.37.0}/vgi/_test_fixtures/companion.py +0 -0
  521. {vgi_python-0.36.1 → vgi_python-0.37.0}/vgi/_test_fixtures/copy_from.py +0 -0
  522. {vgi_python-0.36.1 → vgi_python-0.37.0}/vgi/_test_fixtures/copy_to.py +0 -0
  523. {vgi_python-0.36.1 → vgi_python-0.37.0}/vgi/_test_fixtures/global_functions.py +0 -0
  524. {vgi_python-0.36.1 → vgi_python-0.37.0}/vgi/_test_fixtures/http_server.py +0 -0
  525. {vgi_python-0.36.1 → vgi_python-0.37.0}/vgi/_test_fixtures/narrow_bind/__init__.py +0 -0
  526. {vgi_python-0.36.1 → vgi_python-0.37.0}/vgi/_test_fixtures/narrow_bind/worker.py +0 -0
  527. {vgi_python-0.36.1 → vgi_python-0.37.0}/vgi/_test_fixtures/nest_tensor.py +0 -0
  528. {vgi_python-0.36.1 → vgi_python-0.37.0}/vgi/_test_fixtures/orchard_catalog.py +0 -0
  529. {vgi_python-0.36.1 → vgi_python-0.37.0}/vgi/_test_fixtures/projection_repro/__init__.py +0 -0
  530. {vgi_python-0.36.1 → vgi_python-0.37.0}/vgi/_test_fixtures/projection_repro/worker.py +0 -0
  531. {vgi_python-0.36.1 → vgi_python-0.37.0}/vgi/_test_fixtures/scalar/__init__.py +0 -0
  532. {vgi_python-0.36.1 → vgi_python-0.37.0}/vgi/_test_fixtures/scalar/_common.py +0 -0
  533. {vgi_python-0.36.1 → vgi_python-0.37.0}/vgi/_test_fixtures/scalar/arithmetic.py +0 -0
  534. {vgi_python-0.36.1 → vgi_python-0.37.0}/vgi/_test_fixtures/scalar/bench_ladder.py +0 -0
  535. {vgi_python-0.36.1 → vgi_python-0.37.0}/vgi/_test_fixtures/scalar/binary.py +0 -0
  536. {vgi_python-0.36.1 → vgi_python-0.37.0}/vgi/_test_fixtures/scalar/formatting.py +0 -0
  537. {vgi_python-0.36.1 → vgi_python-0.37.0}/vgi/_test_fixtures/scalar/geo.py +0 -0
  538. {vgi_python-0.36.1 → vgi_python-0.37.0}/vgi/_test_fixtures/scalar/null_handling.py +0 -0
  539. {vgi_python-0.36.1 → vgi_python-0.37.0}/vgi/_test_fixtures/scalar/random_demo.py +0 -0
  540. {vgi_python-0.36.1 → vgi_python-0.37.0}/vgi/_test_fixtures/scalar/same_name.py +0 -0
  541. {vgi_python-0.36.1 → vgi_python-0.37.0}/vgi/_test_fixtures/scalar/settings_secrets.py +0 -0
  542. {vgi_python-0.36.1 → vgi_python-0.37.0}/vgi/_test_fixtures/scalar/type_info.py +0 -0
  543. {vgi_python-0.36.1 → vgi_python-0.37.0}/vgi/_test_fixtures/schema_reconcile/__init__.py +0 -0
  544. {vgi_python-0.36.1 → vgi_python-0.37.0}/vgi/_test_fixtures/schema_reconcile/worker.py +0 -0
  545. {vgi_python-0.36.1 → vgi_python-0.37.0}/vgi/_test_fixtures/simple_writable.py +0 -0
  546. {vgi_python-0.36.1 → vgi_python-0.37.0}/vgi/_test_fixtures/table/_common.py +0 -0
  547. {vgi_python-0.36.1 → vgi_python-0.37.0}/vgi/_test_fixtures/table/batch_index.py +0 -0
  548. {vgi_python-0.36.1 → vgi_python-0.37.0}/vgi/_test_fixtures/table/batch_index_broken.py +0 -0
  549. {vgi_python-0.36.1 → vgi_python-0.37.0}/vgi/_test_fixtures/table/cache.py +0 -0
  550. {vgi_python-0.36.1 → vgi_python-0.37.0}/vgi/_test_fixtures/table/catalog_scans.py +0 -0
  551. {vgi_python-0.36.1 → vgi_python-0.37.0}/vgi/_test_fixtures/table/late_materialization.py +0 -0
  552. {vgi_python-0.36.1 → vgi_python-0.37.0}/vgi/_test_fixtures/table/make_series.py +0 -0
  553. {vgi_python-0.36.1 → vgi_python-0.37.0}/vgi/_test_fixtures/table/misc.py +0 -0
  554. {vgi_python-0.36.1 → vgi_python-0.37.0}/vgi/_test_fixtures/table/order_modes.py +0 -0
  555. {vgi_python-0.36.1 → vgi_python-0.37.0}/vgi/_test_fixtures/table/pairs.py +0 -0
  556. {vgi_python-0.36.1 → vgi_python-0.37.0}/vgi/_test_fixtures/table/partition_columns.py +0 -0
  557. {vgi_python-0.36.1 → vgi_python-0.37.0}/vgi/_test_fixtures/table/partition_columns_broken.py +0 -0
  558. {vgi_python-0.36.1 → vgi_python-0.37.0}/vgi/_test_fixtures/table/profiling_example.py +0 -0
  559. {vgi_python-0.36.1 → vgi_python-0.37.0}/vgi/_test_fixtures/table/required_filters.py +0 -0
  560. {vgi_python-0.36.1 → vgi_python-0.37.0}/vgi/_test_fixtures/table/same_name_cached.py +0 -0
  561. {vgi_python-0.36.1 → vgi_python-0.37.0}/vgi/_test_fixtures/table/same_name_schemas.py +0 -0
  562. {vgi_python-0.36.1 → vgi_python-0.37.0}/vgi/_test_fixtures/table/sequence.py +0 -0
  563. {vgi_python-0.36.1 → vgi_python-0.37.0}/vgi/_test_fixtures/table/settings.py +0 -0
  564. {vgi_python-0.36.1 → vgi_python-0.37.0}/vgi/_test_fixtures/table/splits.py +0 -0
  565. {vgi_python-0.36.1 → vgi_python-0.37.0}/vgi/_test_fixtures/table/transaction_storage.py +0 -0
  566. {vgi_python-0.36.1 → vgi_python-0.37.0}/vgi/_test_fixtures/table/tt_pushdown.py +0 -0
  567. {vgi_python-0.36.1 → vgi_python-0.37.0}/vgi/_test_fixtures/table/typed_probe.py +0 -0
  568. {vgi_python-0.36.1 → vgi_python-0.37.0}/vgi/_test_fixtures/table/versioned.py +0 -0
  569. {vgi_python-0.36.1 → vgi_python-0.37.0}/vgi/_test_fixtures/table/wide.py +0 -0
  570. {vgi_python-0.36.1 → vgi_python-0.37.0}/vgi/_test_fixtures/table_in_out.py +0 -0
  571. {vgi_python-0.36.1 → vgi_python-0.37.0}/vgi/_test_fixtures/table_in_out_same_name.py +0 -0
  572. {vgi_python-0.36.1 → vgi_python-0.37.0}/vgi/_test_fixtures/twin_catalogs.py +0 -0
  573. {vgi_python-0.36.1 → vgi_python-0.37.0}/vgi/_test_fixtures/versioned.py +0 -0
  574. {vgi_python-0.36.1 → vgi_python-0.37.0}/vgi/_test_fixtures/versioned_tables.py +0 -0
  575. {vgi_python-0.36.1 → vgi_python-0.37.0}/vgi/_test_fixtures/writable/__init__.py +0 -0
  576. {vgi_python-0.36.1 → vgi_python-0.37.0}/vgi/_test_fixtures/writable/generic.py +0 -0
  577. {vgi_python-0.36.1 → vgi_python-0.37.0}/vgi/_test_fixtures/writable/table.py +0 -0
  578. {vgi_python-0.36.1 → vgi_python-0.37.0}/vgi/_test_fixtures/writable/worker.py +0 -0
  579. {vgi_python-0.36.1 → vgi_python-0.37.0}/vgi/aggregate_function.py +0 -0
  580. {vgi_python-0.36.1 → vgi_python-0.37.0}/vgi/argument_spec.py +0 -0
  581. {vgi_python-0.36.1 → vgi_python-0.37.0}/vgi/arguments.py +0 -0
  582. {vgi_python-0.36.1 → vgi_python-0.37.0}/vgi/attach_header.py +0 -0
  583. {vgi_python-0.36.1 → vgi_python-0.37.0}/vgi/cache_control.py +0 -0
  584. {vgi_python-0.36.1 → vgi_python-0.37.0}/vgi/catalog/__init__.py +0 -0
  585. {vgi_python-0.36.1 → vgi_python-0.37.0}/vgi/catalog/_descriptor_spec.py +0 -0
  586. {vgi_python-0.36.1 → vgi_python-0.37.0}/vgi/catalog/attach_option.py +0 -0
  587. {vgi_python-0.36.1 → vgi_python-0.37.0}/vgi/catalog/catalog_interface.py +0 -0
  588. {vgi_python-0.36.1 → vgi_python-0.37.0}/vgi/catalog/descriptors.py +0 -0
  589. {vgi_python-0.36.1 → vgi_python-0.37.0}/vgi/catalog/duckdb_statistics.py +0 -0
  590. {vgi_python-0.36.1 → vgi_python-0.37.0}/vgi/catalog/secret_type.py +0 -0
  591. {vgi_python-0.36.1 → vgi_python-0.37.0}/vgi/catalog/setting.py +0 -0
  592. {vgi_python-0.36.1 → vgi_python-0.37.0}/vgi/catalog/storage.py +0 -0
  593. {vgi_python-0.36.1 → vgi_python-0.37.0}/vgi/client/__init__.py +0 -0
  594. {vgi_python-0.36.1 → vgi_python-0.37.0}/vgi/client/aggregate.py +0 -0
  595. {vgi_python-0.36.1 → vgi_python-0.37.0}/vgi/client/catalog_mixin.py +0 -0
  596. {vgi_python-0.36.1 → vgi_python-0.37.0}/vgi/client/cli.py +0 -0
  597. {vgi_python-0.36.1 → vgi_python-0.37.0}/vgi/client/cli_catalog.py +0 -0
  598. {vgi_python-0.36.1 → vgi_python-0.37.0}/vgi/client/cli_schema.py +0 -0
  599. {vgi_python-0.36.1 → vgi_python-0.37.0}/vgi/client/cli_table.py +0 -0
  600. {vgi_python-0.36.1 → vgi_python-0.37.0}/vgi/client/cli_transaction.py +0 -0
  601. {vgi_python-0.36.1 → vgi_python-0.37.0}/vgi/client/cli_utils.py +0 -0
  602. {vgi_python-0.36.1 → vgi_python-0.37.0}/vgi/client/cli_view.py +0 -0
  603. {vgi_python-0.36.1 → vgi_python-0.37.0}/vgi/client/client.py +0 -0
  604. {vgi_python-0.36.1 → vgi_python-0.37.0}/vgi/client/errors.py +0 -0
  605. {vgi_python-0.36.1 → vgi_python-0.37.0}/vgi/codegen/__init__.py +0 -0
  606. {vgi_python-0.36.1 → vgi_python-0.37.0}/vgi/codegen/_common.py +0 -0
  607. {vgi_python-0.36.1 → vgi_python-0.37.0}/vgi/codegen/cpp_constants.py +0 -0
  608. {vgi_python-0.36.1 → vgi_python-0.37.0}/vgi/codegen/cpp_protocol_name.py +0 -0
  609. {vgi_python-0.36.1 → vgi_python-0.37.0}/vgi/codegen/cpp_protocol_version.py +0 -0
  610. {vgi_python-0.36.1 → vgi_python-0.37.0}/vgi/codegen/cpp_request_builders.py +0 -0
  611. {vgi_python-0.36.1 → vgi_python-0.37.0}/vgi/codegen/cpp_schemas.py +0 -0
  612. {vgi_python-0.36.1 → vgi_python-0.37.0}/vgi/codegen/cpp_secret_protocol_version.py +0 -0
  613. {vgi_python-0.36.1 → vgi_python-0.37.0}/vgi/codegen/cpp_secret_request_builders.py +0 -0
  614. {vgi_python-0.36.1 → vgi_python-0.37.0}/vgi/codegen/cpp_secret_schemas.py +0 -0
  615. {vgi_python-0.36.1 → vgi_python-0.37.0}/vgi/codegen/go_schemas.py +0 -0
  616. {vgi_python-0.36.1 → vgi_python-0.37.0}/vgi/codegen/java_schemas.py +0 -0
  617. {vgi_python-0.36.1 → vgi_python-0.37.0}/vgi/codegen/protocol_version.py +0 -0
  618. {vgi_python-0.36.1 → vgi_python-0.37.0}/vgi/codegen/rust_request_builders.py +0 -0
  619. {vgi_python-0.36.1 → vgi_python-0.37.0}/vgi/codegen/rust_schemas.py +0 -0
  620. {vgi_python-0.36.1 → vgi_python-0.37.0}/vgi/codegen/ts_client.py +0 -0
  621. {vgi_python-0.36.1 → vgi_python-0.37.0}/vgi/codegen/ts_schemas.py +0 -0
  622. {vgi_python-0.36.1 → vgi_python-0.37.0}/vgi/copy_from_function.py +0 -0
  623. {vgi_python-0.36.1 → vgi_python-0.37.0}/vgi/copy_to_function.py +0 -0
  624. {vgi_python-0.36.1 → vgi_python-0.37.0}/vgi/exceptions.py +0 -0
  625. {vgi_python-0.36.1 → vgi_python-0.37.0}/vgi/filter_v2_builder.py +0 -0
  626. {vgi_python-0.36.1 → vgi_python-0.37.0}/vgi/function.py +0 -0
  627. {vgi_python-0.36.1 → vgi_python-0.37.0}/vgi/function_storage.py +0 -0
  628. {vgi_python-0.36.1 → vgi_python-0.37.0}/vgi/function_storage_azure_sql.py +0 -0
  629. {vgi_python-0.36.1 → vgi_python-0.37.0}/vgi/function_storage_cf_do.py +0 -0
  630. {vgi_python-0.36.1 → vgi_python-0.37.0}/vgi/http/__init__.py +0 -0
  631. {vgi_python-0.36.1 → vgi_python-0.37.0}/vgi/http/demo_storage.py +0 -0
  632. {vgi_python-0.36.1 → vgi_python-0.37.0}/vgi/http/landing.html +0 -0
  633. {vgi_python-0.36.1 → vgi_python-0.37.0}/vgi/http/landing_page.py +0 -0
  634. {vgi_python-0.36.1 → vgi_python-0.37.0}/vgi/http/vgi-client.js +0 -0
  635. {vgi_python-0.36.1 → vgi_python-0.37.0}/vgi/http/worker_page.py +0 -0
  636. {vgi_python-0.36.1 → vgi_python-0.37.0}/vgi/invocation.py +0 -0
  637. {vgi_python-0.36.1 → vgi_python-0.37.0}/vgi/logging_config.py +0 -0
  638. {vgi_python-0.36.1 → vgi_python-0.37.0}/vgi/meta_worker.py +0 -0
  639. {vgi_python-0.36.1 → vgi_python-0.37.0}/vgi/metadata.py +0 -0
  640. {vgi_python-0.36.1 → vgi_python-0.37.0}/vgi/otel.py +0 -0
  641. {vgi_python-0.36.1 → vgi_python-0.37.0}/vgi/profiling.py +0 -0
  642. {vgi_python-0.36.1 → vgi_python-0.37.0}/vgi/protocol.py +0 -0
  643. {vgi_python-0.36.1 → vgi_python-0.37.0}/vgi/protocol_version.txt +0 -0
  644. {vgi_python-0.36.1 → vgi_python-0.37.0}/vgi/py.typed +0 -0
  645. {vgi_python-0.36.1 → vgi_python-0.37.0}/vgi/scalar_function.py +0 -0
  646. {vgi_python-0.36.1 → vgi_python-0.37.0}/vgi/schema_path.py +0 -0
  647. {vgi_python-0.36.1 → vgi_python-0.37.0}/vgi/schema_utils.py +0 -0
  648. {vgi_python-0.36.1 → vgi_python-0.37.0}/vgi/secret_protocol.py +0 -0
  649. {vgi_python-0.36.1 → vgi_python-0.37.0}/vgi/secret_service.py +0 -0
  650. {vgi_python-0.36.1 → vgi_python-0.37.0}/vgi/split_token.py +0 -0
  651. {vgi_python-0.36.1 → vgi_python-0.37.0}/vgi/table_buffering_function.py +0 -0
  652. {vgi_python-0.36.1 → vgi_python-0.37.0}/vgi/table_function.py +0 -0
  653. {vgi_python-0.36.1 → vgi_python-0.37.0}/vgi/table_in_out_function.py +0 -0
  654. {vgi_python-0.36.1 → vgi_python-0.37.0}/vgi/transactor/__init__.py +0 -0
  655. {vgi_python-0.36.1 → vgi_python-0.37.0}/vgi/transactor/_duckdb_compat.py +0 -0
  656. {vgi_python-0.36.1 → vgi_python-0.37.0}/vgi/transactor/client.py +0 -0
  657. {vgi_python-0.36.1 → vgi_python-0.37.0}/vgi/transactor/protocol.py +0 -0
  658. {vgi_python-0.36.1 → vgi_python-0.37.0}/vgi/transactor/server.py +0 -0
  659. {vgi_python-0.36.1 → vgi_python-0.37.0}/vgi/write_results.py +0 -0
  660. {vgi_python-0.36.1 → vgi_python-0.37.0}/wrangler.jsonc +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: vgi-python
3
- Version: 0.36.1
3
+ Version: 0.37.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
@@ -0,0 +1,32 @@
1
+ {
2
+ "encoding": "vgi.filters.v2",
3
+ "semantics": "vgi.duckdb.standard.v1",
4
+ "kind": "snapshot",
5
+ "predicates": [
6
+ {
7
+ "id": "query:bare-boolean-column",
8
+ "revision": 0,
9
+ "mode": "required",
10
+ "source": "query",
11
+ "expression": {
12
+ "node": "column_ref",
13
+ "column_index": 0,
14
+ "column_name": "flag"
15
+ }
16
+ },
17
+ {
18
+ "id": "query:negated-boolean-column",
19
+ "revision": 0,
20
+ "mode": "required",
21
+ "source": "query",
22
+ "expression": {
23
+ "node": "not",
24
+ "expression": {
25
+ "node": "column_ref",
26
+ "column_index": 1,
27
+ "column_name": "other_flag"
28
+ }
29
+ }
30
+ }
31
+ ]
32
+ }
@@ -30,6 +30,11 @@
30
30
  "document": "cases/positive/runtime-filter-snapshot.json",
31
31
  "expected": "valid"
32
32
  },
33
+ {
34
+ "id": "structural.boolean-column-predicate",
35
+ "document": "cases/positive/boolean-column-predicate.json",
36
+ "expected": "valid"
37
+ },
33
38
  {
34
39
  "id": "structural.and-too-few-children",
35
40
  "document": "cases/negative/and-too-few-children.json",
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "vgi-python"
3
- version = "0.36.1"
3
+ version = "0.37.0"
4
4
  description = "Vector Gateway Interface - Connect DuckDB to external programs via Apache Arrow"
5
5
  readme = "README.md"
6
6
  keywords = [
@@ -6,7 +6,7 @@ from __future__ import annotations
6
6
 
7
7
  import json
8
8
  from collections.abc import Mapping
9
- from typing import cast
9
+ from typing import Any, cast
10
10
 
11
11
  import pyarrow as pa
12
12
  import pytest
@@ -531,3 +531,168 @@ def test_unknown_arrow_extension_metadata_is_rejected() -> None:
531
531
  _batch(_document([_predicate(_comparison())]), (extension_field, b"opaque")),
532
532
  output_schema=pa.schema([("n", pa.int64())]),
533
533
  )
534
+
535
+
536
+ # ---------------------------------------------------------------------------
537
+ # A boolean column is a predicate on its own
538
+ #
539
+ # `WHERE flag` / `WHERE NOT flag` is idiomatic SQL, and DuckDB pushes it down as
540
+ # a bare `column_ref` rather than rewriting it to `flag = true`. The schema
541
+ # admits that -- `coreExpression` lists `columnRef` first -- but the decoder's
542
+ # boolean gate used to enumerate node *kinds* instead of asking for the resolved
543
+ # *type*, so it refused every one of them: "predicate root must resolve to
544
+ # BOOLEAN", on a node whose type it had already resolved to BOOLEAN and stored.
545
+ # ---------------------------------------------------------------------------
546
+
547
+ _BOOL_FIELDS: list[pa.Field[Any]] = [pa.field("flag", pa.bool_()), pa.field("n", pa.int64())]
548
+ _BOOL_SCHEMA = pa.schema(_BOOL_FIELDS)
549
+
550
+
551
+ def _flag(index: int = 0) -> dict[str, object]:
552
+ return {"node": "column_ref", "column_index": index, "column_name": "flag"}
553
+
554
+
555
+ def test_bare_boolean_column_is_a_valid_predicate_root() -> None:
556
+ """`WHERE flag` -- the column itself is the predicate."""
557
+ filters = deserialize_filters(
558
+ _batch(_document([_predicate(_flag())])),
559
+ output_schema=_BOOL_SCHEMA,
560
+ )
561
+ batch = pa.RecordBatch.from_pydict(
562
+ {"flag": [True, False, None, True], "n": [1, 2, 3, 4]},
563
+ schema=_BOOL_SCHEMA,
564
+ )
565
+ # evaluate() is the raw three-valued predicate: NULL stays NULL.
566
+ assert filters.evaluate(batch).to_pylist() == [True, False, None, True]
567
+ # apply() is what selects rows, and there a NULL predicate is not satisfied
568
+ # -- the same rows `flag = true` would keep, which is what makes the SQL
569
+ # rewrite below a projection rather than a change of meaning.
570
+ assert filters.apply(batch).to_pydict()["n"] == [1, 4]
571
+
572
+
573
+ def test_negated_boolean_column_is_a_valid_predicate_root() -> None:
574
+ """`WHERE NOT flag` -- `not` over a bare column, which the gate also refused."""
575
+ filters = deserialize_filters(
576
+ _batch(_document([_predicate({"node": "not", "expression": _flag()})])),
577
+ output_schema=_BOOL_SCHEMA,
578
+ )
579
+ batch = pa.RecordBatch.from_pydict(
580
+ {"flag": [True, False, None, True], "n": [1, 2, 3, 4]},
581
+ schema=_BOOL_SCHEMA,
582
+ )
583
+ assert filters.evaluate(batch).to_pylist() == [False, True, None, False]
584
+ # NOT NULL is NULL, so row 3 is not kept -- exactly `flag = false`.
585
+ assert filters.apply(batch).to_pydict()["n"] == [2]
586
+
587
+
588
+ def test_boolean_column_predicates_render_as_sql() -> None:
589
+ """They must reach SQL, not just the evaluator.
590
+
591
+ Left as a generic v2 expression a bare column renders no SQL at all, so a
592
+ SQL-backed worker loses pushdown on the commonest boolean predicate there
593
+ is -- and DuckDB does not re-apply what it pushed down, so that is a wrong
594
+ answer, not a slow one.
595
+ """
596
+ positive = deserialize_filters(_batch(_document([_predicate(_flag())])), output_schema=_BOOL_SCHEMA)
597
+ where, params = positive.to_sql()
598
+ assert where == '"flag" = ?'
599
+ assert params == [True]
600
+
601
+ negative = deserialize_filters(
602
+ _batch(_document([_predicate({"node": "not", "expression": _flag()})])),
603
+ output_schema=_BOOL_SCHEMA,
604
+ )
605
+ where, params = negative.to_sql()
606
+ assert where == '"flag" = ?'
607
+ assert params == [False]
608
+
609
+
610
+ def test_boolean_column_inside_a_conjunction_still_pushes_down() -> None:
611
+ """The shape that actually showed up: `WHERE other = x AND NOT flag`.
612
+
613
+ One unrenderable child used to cost the whole conjunction its pushdown.
614
+ """
615
+ document = _document(
616
+ [
617
+ _predicate(
618
+ {
619
+ "node": "and",
620
+ "children": [
621
+ {
622
+ "node": "comparison",
623
+ "op": "gt",
624
+ "left": _column(name="n", index=1),
625
+ "right": {"node": "literal", "value_ref": 0},
626
+ },
627
+ {"node": "not", "expression": _flag()},
628
+ ],
629
+ }
630
+ )
631
+ ]
632
+ )
633
+ filters = deserialize_filters(
634
+ _batch(document, (pa.field("value_0", pa.int64()), 2)),
635
+ output_schema=_BOOL_SCHEMA,
636
+ )
637
+ where, params = filters.to_sql()
638
+ assert where == '("n" > ? AND "flag" = ?)'
639
+ assert params == [2, False]
640
+
641
+
642
+ def test_an_unresolved_column_is_not_assumed_boolean() -> None:
643
+ """Without a bind schema the column's type is unknown -- refuse, don't guess."""
644
+ with pytest.raises(FilterDeserializationError, match="predicate root"):
645
+ deserialize_filters(_batch(_document([_predicate(_flag())])))
646
+
647
+
648
+ def test_a_non_boolean_column_is_still_refused() -> None:
649
+ """`WHERE n` where n is BIGINT is not a predicate."""
650
+ with pytest.raises(FilterDeserializationError, match="predicate root"):
651
+ deserialize_filters(
652
+ _batch(_document([_predicate(_column(name="n", index=1))])),
653
+ output_schema=_BOOL_SCHEMA,
654
+ )
655
+
656
+
657
+ def test_an_unrenderable_filter_raises_rather_than_vanishing() -> None:
658
+ """`to_sql()` must never quietly drop a predicate it cannot render.
659
+
660
+ DuckDB does not re-apply a filter it pushed into a table function, so the
661
+ worker's WHERE clause is the only thing standing between the caller and
662
+ rows the predicate excludes. A skipped filter is therefore a wrong answer,
663
+ not a slow one -- which is why this raises instead of degrading.
664
+ """
665
+ from vgi.table_filter_pushdown import FilterSQLUnsupportedError
666
+
667
+ # `n + 1 > 2` -- arithmetic has no legacy leaf shape and no SQL rendering.
668
+ document = _document(
669
+ [
670
+ _predicate(
671
+ {
672
+ "node": "comparison",
673
+ "op": "gt",
674
+ "left": {
675
+ "node": "arithmetic",
676
+ "op": "add",
677
+ "left": _column(name="n", index=1),
678
+ "right": {"node": "literal", "value_ref": 0},
679
+ },
680
+ "right": {"node": "literal", "value_ref": 1},
681
+ }
682
+ )
683
+ ]
684
+ )
685
+ filters = deserialize_filters(
686
+ _batch(
687
+ document,
688
+ (pa.field("value_0", pa.int64()), 1),
689
+ (pa.field("value_1", pa.int64()), 2),
690
+ ),
691
+ output_schema=_BOOL_SCHEMA,
692
+ )
693
+ # It evaluates correctly -- there is simply no SQL for it.
694
+ batch = pa.RecordBatch.from_pydict({"flag": [True, True, True], "n": [0, 2, 5]}, schema=_BOOL_SCHEMA)
695
+ assert filters.apply(batch).to_pydict()["n"] == [2, 5]
696
+
697
+ with pytest.raises(FilterSQLUnsupportedError, match="no SQL rendering"):
698
+ filters.to_sql()
@@ -24,7 +24,7 @@ from vgi_rpc import (
24
24
  from vgi_rpc.rpc import AuthContext, PeerResolutionContext, peer_identity_primary
25
25
 
26
26
  from vgi.arguments import Arguments, Auth, Param, Returns
27
- from vgi.auth import TokenIdentity
27
+ from vgi.auth import IssuedGrant, TokenIdentity
28
28
  from vgi.client import Client
29
29
  from vgi.scalar_function import ScalarFunction
30
30
  from vgi.serve import (
@@ -486,6 +486,32 @@ class _IntrospectingWorker(Worker):
486
486
  return None
487
487
 
488
488
 
489
+ class _MintingWorker(Worker):
490
+ """Worker that implements only the optional grant-minting hook."""
491
+
492
+ functions = [_DoubleFunc]
493
+
494
+ @classmethod
495
+ def mint_grant(cls, principal: str, purpose: str, scopes: list[str], ttl_seconds: int) -> IssuedGrant:
496
+ # A sealed self-contained credential: the worker owns the format and
497
+ # the framework never parses it. Capped TTL, to pin that a worker may
498
+ # issue SHORTER than asked.
499
+ ttl = min(ttl_seconds, 3600)
500
+ return IssuedGrant(
501
+ token=f"sealed:{principal}:{':'.join(scopes)}:{purpose}",
502
+ expires_at=1_000_000.0 + ttl,
503
+ grant_id="grant-1",
504
+ )
505
+
506
+
507
+ class _BothWorker(_IntrospectingWorker):
508
+ """Worker that both resolves credentials and mints grants."""
509
+
510
+ @classmethod
511
+ def mint_grant(cls, principal: str, purpose: str, scopes: list[str], ttl_seconds: int) -> IssuedGrant:
512
+ return IssuedGrant(token=f"sealed:{principal}", expires_at=1_000_000.0, grant_id="g")
513
+
514
+
489
515
  class TestIntrospectResolverDetection:
490
516
  """``resolve_token`` presence is detected by override, not by a flag."""
491
517
 
@@ -516,6 +542,31 @@ def _introspector_ctx(principal: str) -> object:
516
542
  )
517
543
 
518
544
 
545
+ def _minting_ctx(principal: str, *, auth_age_s: float = 0.0) -> object:
546
+ """Build a ``CallContext`` for a caller who authenticated *auth_age_s* ago.
547
+
548
+ Minting reads ``auth_time`` off the credential's claims, and a credential
549
+ without one cannot mint at all. That single rule is what stops a grant
550
+ minting another grant — a grant is not IdP-issued, so it carries no
551
+ ``auth_time`` — and what makes a static bearer token, which proves a
552
+ machine holds a secret rather than that a human just authenticated,
553
+ fail closed here.
554
+ """
555
+ import time
556
+
557
+ from vgi_rpc.rpc import AuthContext, CallContext
558
+
559
+ return CallContext(
560
+ auth=AuthContext(
561
+ domain="test",
562
+ authenticated=True,
563
+ principal=principal,
564
+ claims={"auth_time": time.time() - auth_age_s},
565
+ ),
566
+ emit_client_log=lambda *a, **k: None,
567
+ )
568
+
569
+
519
570
  def _hosted_protocols(worker_cls: type[Worker]) -> frozenset[str]:
520
571
  """Return the protocol names the server built for *worker_cls* hosts.
521
572
 
@@ -655,6 +706,111 @@ class TestTokenIntrospection:
655
706
  create_app(_IntrospectingWorker, prefix="/vgi", describe=False)
656
707
 
657
708
 
709
+ class TestGrantMinting:
710
+ """``issue_grant`` — the other half of ``vgi_rpc.Identity.v1``.
711
+
712
+ Guarded very differently from ``introspect_token``, and deliberately so.
713
+ Introspection answers a question about *somebody else's* credential, so it
714
+ needs an allowlist. Minting produces a credential for the *caller* — there
715
+ is no subject on the wire, so cross-subject minting is closed by
716
+ construction and no allowlist applies. What this repo owns is the wiring:
717
+ a ``mint_grant`` override becomes an ``IdentityImpl`` that offers the
718
+ method, and a worker that never wrote one does not host it.
719
+ """
720
+
721
+ @staticmethod
722
+ def _identity(worker_cls: type[Worker], **env: str) -> object:
723
+ from vgi.serve import _build_identity
724
+
725
+ with pytest.MonkeyPatch.context() as mp:
726
+ mp.delenv("VGI_INTROSPECT_PRINCIPALS", raising=False)
727
+ for key, value in env.items():
728
+ mp.setenv(key, value)
729
+ return _build_identity(worker_cls, None)
730
+
731
+ def test_base_worker_has_no_minter(self) -> None:
732
+ """A worker that never wrote the minting gets no issuer."""
733
+ assert _SingleWorker._grant_minter() is None
734
+
735
+ def test_override_is_detected(self) -> None:
736
+ """Implementing the hook is what enables it."""
737
+ minter = _MintingWorker._grant_minter()
738
+ assert minter is not None
739
+
740
+ def test_minting_alone_hosts_the_protocol(self) -> None:
741
+ """A worker may mint without resolving — the two are independent."""
742
+ assert "vgi_rpc.Identity.v1" in _hosted_protocols(_MintingWorker)
743
+
744
+ def test_minting_alone_offers_only_issue_grant(self) -> None:
745
+ """The protocol describes what the worker does, not what it could do."""
746
+ identity = self._identity(_MintingWorker)
747
+ assert identity is not None
748
+ assert identity.offered_methods() == frozenset({"issue_grant"}) # type: ignore[attr-defined]
749
+
750
+ def test_minting_alone_needs_no_introspect_allowlist(self) -> None:
751
+ """No allowlist is required to mint: a grant is not an oracle.
752
+
753
+ Requiring one would be a startup error for a worker that never exposes
754
+ anybody else's identity — the exact opposite of the guard's purpose.
755
+ """
756
+ with pytest.MonkeyPatch.context() as mp:
757
+ mp.delenv("VGI_INTROSPECT_PRINCIPALS", raising=False)
758
+ create_app(_MintingWorker, prefix="/vgi", describe=False)
759
+
760
+ def test_both_hooks_offer_both_methods(self) -> None:
761
+ """Resolving and minting compose."""
762
+ identity = self._identity(_BothWorker, VGI_INTROSPECT_PRINCIPALS="proxy-a")
763
+ assert identity is not None
764
+ assert identity.offered_methods() == frozenset({"introspect_token", "issue_grant"}) # type: ignore[attr-defined]
765
+
766
+ def test_the_caller_is_the_subject(self) -> None:
767
+ """The framework supplies the principal; the wire method has no subject field.
768
+
769
+ This is the property that makes an allowlist unnecessary, so pin it
770
+ here rather than trusting the signature to stay that way.
771
+ """
772
+ identity = self._identity(_MintingWorker)
773
+ assert identity is not None
774
+ grant = identity.issue_grant( # type: ignore[attr-defined]
775
+ "nightly-etl", ["read"], 600, _minting_ctx("alice")
776
+ )
777
+ assert grant.token.startswith("sealed:alice:")
778
+ assert grant.grant_id == "grant-1"
779
+
780
+ def test_a_worker_may_issue_a_shorter_ttl_than_asked(self) -> None:
781
+ """A worker may narrow the request; it must never widen it."""
782
+ identity = self._identity(_MintingWorker)
783
+ assert identity is not None
784
+ grant = identity.issue_grant( # type: ignore[attr-defined]
785
+ "long", [], 86_400, _minting_ctx("alice")
786
+ )
787
+ assert grant.expires_at == 1_000_000.0 + 3600
788
+
789
+ def test_stale_authentication_cannot_mint(self) -> None:
790
+ """Minting while the user is present is enforced, not just documented."""
791
+ from vgi_rpc.rpc._token_identity import StaleAuthError
792
+
793
+ identity = self._identity(_MintingWorker)
794
+ assert identity is not None
795
+ with pytest.raises(StaleAuthError):
796
+ identity.issue_grant("x", [], 60, _minting_ctx("alice", auth_age_s=86_400)) # type: ignore[attr-defined]
797
+
798
+ def test_a_credential_with_no_auth_time_cannot_mint(self) -> None:
799
+ """A grant cannot mint another grant, and a static bearer cannot mint at all.
800
+
801
+ Neither carries ``auth_time`` — only an IdP-issued credential does — so
802
+ the lineage cannot escape the identity provider. This is the rule that
803
+ makes delegation accountable to a human login rather than to whoever
804
+ currently holds a machine secret.
805
+ """
806
+ from vgi_rpc.rpc._token_identity import StaleAuthError
807
+
808
+ identity = self._identity(_MintingWorker)
809
+ assert identity is not None
810
+ with pytest.raises(StaleAuthError):
811
+ identity.issue_grant("x", [], 60, _introspector_ctx("etl-service")) # type: ignore[attr-defined]
812
+
813
+
658
814
  class TestAuthUnavailableReExport:
659
815
  """``AuthUnavailableError`` is reachable without naming a vgi_rpc module."""
660
816
 
@@ -2580,7 +2580,7 @@ requires-dist = [
2580
2580
 
2581
2581
  [[package]]
2582
2582
  name = "vgi-python"
2583
- version = "0.36.1"
2583
+ version = "0.37.0"
2584
2584
  source = { editable = "." }
2585
2585
  dependencies = [
2586
2586
  { name = "click" },
@@ -65,6 +65,7 @@ from vgi._test_fixtures.table.catalog_scans import (
65
65
  ProjectsScanFunction,
66
66
  )
67
67
  from vgi._test_fixtures.table.filters import (
68
+ BoolFilterEchoFunction,
68
69
  DictFilterEchoFunction,
69
70
  DynamicFilterEchoFunction,
70
71
  ExpressionFilterTestFunction,
@@ -216,6 +217,7 @@ __all__ = [
216
217
  "ConstantColumnsFunction",
217
218
  "CountryPartitionedSalesFunction",
218
219
  "DepartmentsScanFunction",
220
+ "BoolFilterEchoFunction",
219
221
  "DictFilterEchoFunction",
220
222
  "DisjointRangePartitionedFunction",
221
223
  "DoubleSequenceFunction",
@@ -191,6 +191,129 @@ class FilterEchoFunction(TableFunctionGenerator[FilterEchoFunctionArgs, FilterEc
191
191
  state.remaining -= size
192
192
 
193
193
 
194
+ # ============================================================================
195
+ # BoolFilterEchoFunction — a table function with a BOOLEAN column, so the
196
+ # bare-column predicate shapes (`WHERE flag`, `WHERE NOT flag`) can be driven
197
+ # end to end.
198
+ #
199
+ # filter_echo cannot cover these: its schema has no boolean column, so the
200
+ # predicate cannot even be written. The table-in-out `echo` path cannot either
201
+ # — DuckDB does not hand it a bare boolean column as a pushed predicate, so a
202
+ # test written there passes whether or not the worker can decode one. It takes
203
+ # a TABLE FUNCTION with a boolean column to see the shape at all, which is why
204
+ # a decoder that refused every one of them ("predicate root must resolve to
205
+ # BOOLEAN", vgi-python < 0.36.2) went unnoticed by a filter-pushdown suite of
206
+ # 348 files including one dedicated to booleans.
207
+ #
208
+ # `pushed_filters` echoes the SQL rendering, so this covers both halves: the
209
+ # decode (the rows are auto-applied and must be right) and `to_sql()` (a shape
210
+ # that parses but renders nothing would show up here as "(none)").
211
+ # ============================================================================
212
+
213
+
214
+ @dataclass(slots=True, frozen=True)
215
+ class _BoolFilterEchoArgs:
216
+ """Arguments for BoolFilterEchoFunction."""
217
+
218
+ count: Annotated[int, Arg(0, doc="Number of rows to generate", ge=0)]
219
+
220
+
221
+ @dataclass(kw_only=True)
222
+ class _BoolFilterEchoState(ArrowSerializableDataclass):
223
+ """Remaining rows plus the echoed SQL rendering of the pushed filters."""
224
+
225
+ remaining: int
226
+ current_index: int = 0
227
+ filter_str: str = "(none)"
228
+
229
+
230
+ @init_single_worker
231
+ @bind_fixed_schema
232
+ @_cardinality_from_count
233
+ class BoolFilterEchoFunction(TableFunctionGenerator[_BoolFilterEchoArgs, _BoolFilterEchoState]):
234
+ """Rows with a nullable BOOLEAN column, echoing the pushed-down filters.
235
+
236
+ SCHEMA
237
+ ------
238
+ Output: {"n": int64, "flag": bool, "pushed_filters": string}
239
+
240
+ ``flag`` cycles TRUE, FALSE, NULL so every predicate is exercised against
241
+ all three truth values -- the NULL row is what distinguishes ``WHERE flag``
242
+ from ``WHERE flag IS NOT FALSE``, and ``WHERE NOT flag`` from
243
+ ``WHERE flag IS NOT TRUE``.
244
+
245
+ Attributes:
246
+ FIXED_SCHEMA: The fixed Arrow output schema this function always produces.
247
+
248
+ """
249
+
250
+ class Meta:
251
+ """Metadata for BoolFilterEchoFunction."""
252
+
253
+ name = "bool_filter_echo"
254
+ description = "Rows with a nullable BOOLEAN column, echoing pushed-down filters"
255
+ categories = ["generator", "diagnostic"]
256
+ filter_pushdown = True
257
+ auto_apply_filters = True
258
+ projection_pushdown = True
259
+ examples = [
260
+ FunctionExample(
261
+ sql="SELECT * FROM bool_filter_echo(6) WHERE flag",
262
+ description="A boolean column is a predicate on its own",
263
+ ),
264
+ ]
265
+
266
+ FIXED_SCHEMA: ClassVar[pa.Schema] = schema({"n": pa.int64(), "flag": pa.bool_(), "pushed_filters": pa.utf8()})
267
+
268
+ @classmethod
269
+ def initial_state(cls, params: ProcessParams[_BoolFilterEchoArgs]) -> _BoolFilterEchoState:
270
+ """Create initial state, caching the SQL rendering of the pushed filters."""
271
+ assert params.init_call is not None
272
+ pf = params.init_call.pushdown_filters
273
+ filters = (
274
+ cls.pushdown_filters(
275
+ pf,
276
+ join_keys=params.init_call.join_keys,
277
+ output_schema=params.init_call.output_schema,
278
+ )
279
+ if pf is not None
280
+ else None
281
+ )
282
+ return _BoolFilterEchoState(
283
+ remaining=params.args.count,
284
+ filter_str=_format_pushed_filters(filters),
285
+ )
286
+
287
+ @classmethod
288
+ def process(
289
+ cls,
290
+ params: ProcessParams[_BoolFilterEchoArgs],
291
+ state: _BoolFilterEchoState,
292
+ out: OutputCollector,
293
+ ) -> None:
294
+ """Emit rows whose ``flag`` cycles TRUE, FALSE, NULL."""
295
+ if state.remaining <= 0:
296
+ out.finish()
297
+ return
298
+
299
+ n_values = list(range(state.current_index, state.current_index + state.remaining))
300
+ flags: list[bool | None] = [(True, False, None)[i % 3] for i in n_values]
301
+
302
+ out.emit(
303
+ pa.RecordBatch.from_pydict(
304
+ {
305
+ "n": n_values,
306
+ "flag": flags,
307
+ "pushed_filters": [state.filter_str] * len(n_values),
308
+ },
309
+ schema=params.output_schema,
310
+ )
311
+ )
312
+
313
+ state.current_index += state.remaining
314
+ state.remaining = 0
315
+
316
+
194
317
  # ============================================================================
195
318
  # ValuePruneFunction — exercises PushdownFilters.get_column_values('n'), the
196
319
  # partition-pruning idiom (resolve the discrete value set up front, fetch only
@@ -140,6 +140,7 @@ from vgi._test_fixtures.table import (
140
140
  RFF_SIMPLE_COLUMNS,
141
141
  RFF_STRUCT_COLUMNS,
142
142
  BatchIndexOverflowFunction,
143
+ BoolFilterEchoFunction,
143
144
  BrokenMissingPartitionValuesFunction,
144
145
  BrokenPartitionColumnAbsentFromBatchFunction,
145
146
  BrokenPartitionMinNeqMaxFunction,
@@ -486,6 +487,7 @@ _EXAMPLE_CATALOG = Catalog(
486
487
  # TableFunctionGenerator - generate output without input
487
488
  ConstantColumnsFunction,
488
489
  SlowCancellableFunction,
490
+ BoolFilterEchoFunction,
489
491
  FilterEchoFunction,
490
492
  FilterEchoPartitionedFunction,
491
493
  FilterEchoTableScanFunction,
@@ -9,8 +9,8 @@ HTTP auth factories (require ``vgi[http]``):
9
9
  bearer_authenticate, bearer_authenticate_static, chain_authenticate,
10
10
  OAuthResourceMetadata, AuthUnavailableError
11
11
 
12
- Token introspection (always available):
13
- TokenIdentity, TokenResolver
12
+ Token introspection and delegation (always available):
13
+ TokenIdentity, TokenResolver, IssuedGrant, GrantMinter
14
14
 
15
15
  JWT auth (requires ``vgi[oauth]``):
16
16
  jwt_authenticate
@@ -30,16 +30,25 @@ from vgi_rpc.rpc import AuthContext, CallContext
30
30
  # on the ``http`` extra. Still not re-exported by ``vgi_rpc.rpc`` itself, so
31
31
  # the private module remains the only import path; re-exported here so a worker
32
32
  # that implements ``resolve_token`` never has to name one.
33
- from vgi_rpc.rpc._token_identity import TokenIdentity
33
+ from vgi_rpc.rpc._token_identity import IssuedGrant, TokenIdentity
34
34
 
35
35
  #: What :meth:`vgi.worker.Worker.resolve_token` is. Upstream dropped its own
36
36
  #: alias when identity moved to the RPC layer; it is spelled out here so the
37
37
  #: name ``vgi.auth.TokenResolver`` keeps working.
38
38
  TokenResolver = Callable[[str], "TokenIdentity | None"]
39
39
 
40
+ #: What :meth:`vgi.worker.Worker.mint_grant` is: ``(principal, purpose, scopes,
41
+ #: ttl_seconds) -> IssuedGrant``. The subject is a *parameter of the call the
42
+ #: framework makes*, never of the wire method — ``issue_grant`` has no subject
43
+ #: field, so a worker is handed the caller's own principal and cannot be asked
44
+ #: to mint for anybody else.
45
+ GrantMinter = Callable[[str, str, list[str], int], "IssuedGrant"]
46
+
40
47
  __all__ = [
41
48
  "AuthContext",
42
49
  "CallContext",
50
+ "GrantMinter",
51
+ "IssuedGrant",
43
52
  "TokenIdentity",
44
53
  "TokenResolver",
45
54
  ]
@@ -740,11 +740,24 @@ class _Parser:
740
740
 
741
741
  @staticmethod
742
742
  def _is_boolean(expression: FilterExpression) -> bool:
743
- if isinstance(expression, Literal):
744
- return pa.types.is_boolean(expression.field.type)
745
- if isinstance(expression, (Comparison, BooleanExpression, Not, IsNull, In, RuntimeFilter)):
746
- return True
747
- return isinstance(expression, Call)
743
+ """Whether *expression* resolves to BOOLEAN.
744
+
745
+ Ask the type, never the node kind. The two agree for every node whose
746
+ type is structurally fixed -- a comparison is BOOLEAN whatever its
747
+ operands -- and that is exactly why enumerating kinds looked sufficient.
748
+ It is not: ``column_ref``, ``field_ref``, ``cast`` and ``arithmetic``
749
+ are BOOLEAN or not depending on a type resolved from elsewhere (the
750
+ bind output schema, or a parent expression), and the schema admits all
751
+ four as a predicate root -- ``coreExpression`` lists ``columnRef``
752
+ first. Enumerating kinds rejected the lot, so the idiomatic
753
+ ``WHERE flag`` / ``WHERE NOT flag`` -- which DuckDB pushes down as a
754
+ bare column reference rather than rewriting to ``flag = true`` -- was
755
+ refused as "predicate root must resolve to BOOLEAN" even though the
756
+ parser had already resolved the column to BOOLEAN and stored it on the
757
+ node.
758
+ """
759
+ data_type = expression_type(expression)
760
+ return data_type is not None and pa.types.is_boolean(data_type)
748
761
 
749
762
  def _payload(self, prefix: str, ref: object) -> tuple[pa.Field[Any], pa.Scalar[Any]]:
750
763
  index = _uint(ref, f"{prefix}_ref")