vgi-python 0.35.0__tar.gz → 0.36.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.35.0 → vgi_python-0.36.0}/PKG-INFO +1 -1
  2. {vgi_python-0.35.0 → vgi_python-0.36.0}/pyproject.toml +7 -2
  3. {vgi_python-0.35.0 → vgi_python-0.36.0}/tests/client/test_stop_force.py +9 -3
  4. {vgi_python-0.35.0 → vgi_python-0.36.0}/tests/conftest.py +63 -3
  5. {vgi_python-0.35.0 → vgi_python-0.36.0}/tests/scalar/test_client.py +24 -7
  6. {vgi_python-0.35.0 → vgi_python-0.36.0}/tests/table_in_out/test_client.py +23 -7
  7. vgi_python-0.36.0/tests/test_dynamic_filter_http_turns.py +199 -0
  8. {vgi_python-0.35.0 → vgi_python-0.36.0}/uv.lock +1 -1
  9. {vgi_python-0.35.0 → vgi_python-0.36.0}/vgi/_test_fixtures/table/filters.py +4 -1
  10. {vgi_python-0.35.0 → vgi_python-0.36.0}/vgi/_test_fixtures/table/sequence.py +4 -1
  11. {vgi_python-0.35.0 → vgi_python-0.36.0}/vgi/_test_fixtures/table/splits.py +10 -5
  12. vgi_python-0.36.0/vgi/auth.py +132 -0
  13. {vgi_python-0.35.0 → vgi_python-0.36.0}/vgi/catalog/catalog_interface.py +40 -20
  14. {vgi_python-0.35.0 → vgi_python-0.36.0}/vgi/client/client.py +153 -98
  15. {vgi_python-0.35.0 → vgi_python-0.36.0}/vgi/filter_v2.py +62 -2
  16. {vgi_python-0.35.0 → vgi_python-0.36.0}/vgi/protocol.py +140 -25
  17. {vgi_python-0.35.0 → vgi_python-0.36.0}/vgi/scalar_function.py +3 -2
  18. {vgi_python-0.35.0 → vgi_python-0.36.0}/vgi/table_filter_pushdown.py +36 -0
  19. vgi_python-0.35.0/vgi/auth.py +0 -76
  20. {vgi_python-0.35.0 → vgi_python-0.36.0}/.dockerignore +0 -0
  21. {vgi_python-0.35.0 → vgi_python-0.36.0}/.gitattributes +0 -0
  22. {vgi_python-0.35.0 → vgi_python-0.36.0}/.github/dependabot.yml +0 -0
  23. {vgi_python-0.35.0 → vgi_python-0.36.0}/.github/styles/config/vocabularies/VGI/accept.txt +0 -0
  24. {vgi_python-0.35.0 → vgi_python-0.36.0}/.github/workflows/ci.yml +0 -0
  25. {vgi_python-0.35.0 → vgi_python-0.36.0}/.github/workflows/docs.yml +0 -0
  26. {vgi_python-0.35.0 → vgi_python-0.36.0}/.github/workflows/integration.yml +0 -0
  27. {vgi_python-0.35.0 → vgi_python-0.36.0}/.github/workflows/release.yml +0 -0
  28. {vgi_python-0.35.0 → vgi_python-0.36.0}/.github/workflows/tailnet-integration.yml +0 -0
  29. {vgi_python-0.35.0 → vgi_python-0.36.0}/.gitignore +0 -0
  30. {vgi_python-0.35.0 → vgi_python-0.36.0}/.python-version +0 -0
  31. {vgi_python-0.35.0 → vgi_python-0.36.0}/.vale.ini +0 -0
  32. {vgi_python-0.35.0 → vgi_python-0.36.0}/CLAUDE.md +0 -0
  33. {vgi_python-0.35.0 → vgi_python-0.36.0}/DOCS_ACCEPTANCE_CRITERIA.md +0 -0
  34. {vgi_python-0.35.0 → vgi_python-0.36.0}/DOCS_REVIEW_RUBRIC.md +0 -0
  35. {vgi_python-0.35.0 → vgi_python-0.36.0}/DOCS_USABILITY_TEST.md +0 -0
  36. {vgi_python-0.35.0 → vgi_python-0.36.0}/LICENSE +0 -0
  37. {vgi_python-0.35.0 → vgi_python-0.36.0}/PROTOCOL.md +0 -0
  38. {vgi_python-0.35.0 → vgi_python-0.36.0}/README.md +0 -0
  39. {vgi_python-0.35.0 → vgi_python-0.36.0}/RELEASE-RUNBOOK.md +0 -0
  40. {vgi_python-0.35.0 → vgi_python-0.36.0}/SECURITY.md +0 -0
  41. {vgi_python-0.35.0 → vgi_python-0.36.0}/ci/README.md +0 -0
  42. {vgi_python-0.35.0 → vgi_python-0.36.0}/ci/preprocess-require.awk +0 -0
  43. {vgi_python-0.35.0 → vgi_python-0.36.0}/ci/run-integration.sh +0 -0
  44. {vgi_python-0.35.0 → vgi_python-0.36.0}/conformance/filter-v2/README.md +0 -0
  45. {vgi_python-0.35.0 → vgi_python-0.36.0}/conformance/filter-v2/cases/negative/and-too-few-children.json +0 -0
  46. {vgi_python-0.35.0 → vgi_python-0.36.0}/conformance/filter-v2/cases/negative/delta-required-upsert.json +0 -0
  47. {vgi_python-0.35.0 → vgi_python-0.36.0}/conformance/filter-v2/cases/negative/nested-runtime-filter.json +0 -0
  48. {vgi_python-0.35.0 → vgi_python-0.36.0}/conformance/filter-v2/cases/negative/remove-with-expression.json +0 -0
  49. {vgi_python-0.35.0 → vgi_python-0.36.0}/conformance/filter-v2/cases/negative/required-runtime-filter.json +0 -0
  50. {vgi_python-0.35.0 → vgi_python-0.36.0}/conformance/filter-v2/cases/negative/snapshot-nonzero-revision.json +0 -0
  51. {vgi_python-0.35.0 → vgi_python-0.36.0}/conformance/filter-v2/cases/negative/unknown-document-property.json +0 -0
  52. {vgi_python-0.35.0 → vgi_python-0.36.0}/conformance/filter-v2/cases/negative/unknown-node.json +0 -0
  53. {vgi_python-0.35.0 → vgi_python-0.36.0}/conformance/filter-v2/cases/positive/advisory-upsert-delta.json +0 -0
  54. {vgi_python-0.35.0 → vgi_python-0.36.0}/conformance/filter-v2/cases/positive/empty-snapshot.json +0 -0
  55. {vgi_python-0.35.0 → vgi_python-0.36.0}/conformance/filter-v2/cases/positive/nested-required-snapshot.json +0 -0
  56. {vgi_python-0.35.0 → vgi_python-0.36.0}/conformance/filter-v2/cases/positive/remove-delta.json +0 -0
  57. {vgi_python-0.35.0 → vgi_python-0.36.0}/conformance/filter-v2/cases/positive/runtime-filter-snapshot.json +0 -0
  58. {vgi_python-0.35.0 → vgi_python-0.36.0}/conformance/filter-v2/filter-v2.schema.json +0 -0
  59. {vgi_python-0.35.0 → vgi_python-0.36.0}/conformance/filter-v2/generate_runtime.py +0 -0
  60. {vgi_python-0.35.0 → vgi_python-0.36.0}/conformance/filter-v2/manifest.json +0 -0
  61. {vgi_python-0.35.0 → vgi_python-0.36.0}/conformance/filter-v2/run_worker.py +0 -0
  62. {vgi_python-0.35.0 → vgi_python-0.36.0}/conformance/filter-v2/runtime/arithmetic-add/expected.arrow +0 -0
  63. {vgi_python-0.35.0 → vgi_python-0.36.0}/conformance/filter-v2/runtime/arithmetic-add/filter.arrow +0 -0
  64. {vgi_python-0.35.0 → vgi_python-0.36.0}/conformance/filter-v2/runtime/arithmetic-add/input.arrow +0 -0
  65. {vgi_python-0.35.0 → vgi_python-0.36.0}/conformance/filter-v2/runtime/arithmetic-multiply/expected.arrow +0 -0
  66. {vgi_python-0.35.0 → vgi_python-0.36.0}/conformance/filter-v2/runtime/arithmetic-multiply/filter.arrow +0 -0
  67. {vgi_python-0.35.0 → vgi_python-0.36.0}/conformance/filter-v2/runtime/arithmetic-multiply/input.arrow +0 -0
  68. {vgi_python-0.35.0 → vgi_python-0.36.0}/conformance/filter-v2/runtime/arithmetic-negate/expected.arrow +0 -0
  69. {vgi_python-0.35.0 → vgi_python-0.36.0}/conformance/filter-v2/runtime/arithmetic-negate/filter.arrow +0 -0
  70. {vgi_python-0.35.0 → vgi_python-0.36.0}/conformance/filter-v2/runtime/arithmetic-negate/input.arrow +0 -0
  71. {vgi_python-0.35.0 → vgi_python-0.36.0}/conformance/filter-v2/runtime/arithmetic-subtract/expected.arrow +0 -0
  72. {vgi_python-0.35.0 → vgi_python-0.36.0}/conformance/filter-v2/runtime/arithmetic-subtract/filter.arrow +0 -0
  73. {vgi_python-0.35.0 → vgi_python-0.36.0}/conformance/filter-v2/runtime/arithmetic-subtract/input.arrow +0 -0
  74. {vgi_python-0.35.0 → vgi_python-0.36.0}/conformance/filter-v2/runtime/cast-integer-to-double/expected.arrow +0 -0
  75. {vgi_python-0.35.0 → vgi_python-0.36.0}/conformance/filter-v2/runtime/cast-integer-to-double/filter.arrow +0 -0
  76. {vgi_python-0.35.0 → vgi_python-0.36.0}/conformance/filter-v2/runtime/cast-integer-to-double/input.arrow +0 -0
  77. {vgi_python-0.35.0 → vgi_python-0.36.0}/conformance/filter-v2/runtime/comparison-distinct_from/expected.arrow +0 -0
  78. {vgi_python-0.35.0 → vgi_python-0.36.0}/conformance/filter-v2/runtime/comparison-distinct_from/filter.arrow +0 -0
  79. {vgi_python-0.35.0 → vgi_python-0.36.0}/conformance/filter-v2/runtime/comparison-distinct_from/input.arrow +0 -0
  80. {vgi_python-0.35.0 → vgi_python-0.36.0}/conformance/filter-v2/runtime/comparison-distinct_from/worker-expected.arrow +0 -0
  81. {vgi_python-0.35.0 → vgi_python-0.36.0}/conformance/filter-v2/runtime/comparison-eq/expected.arrow +0 -0
  82. {vgi_python-0.35.0 → vgi_python-0.36.0}/conformance/filter-v2/runtime/comparison-eq/filter.arrow +0 -0
  83. {vgi_python-0.35.0 → vgi_python-0.36.0}/conformance/filter-v2/runtime/comparison-eq/input.arrow +0 -0
  84. {vgi_python-0.35.0 → vgi_python-0.36.0}/conformance/filter-v2/runtime/comparison-eq/worker-expected.arrow +0 -0
  85. {vgi_python-0.35.0 → vgi_python-0.36.0}/conformance/filter-v2/runtime/comparison-ge/expected.arrow +0 -0
  86. {vgi_python-0.35.0 → vgi_python-0.36.0}/conformance/filter-v2/runtime/comparison-ge/filter.arrow +0 -0
  87. {vgi_python-0.35.0 → vgi_python-0.36.0}/conformance/filter-v2/runtime/comparison-ge/input.arrow +0 -0
  88. {vgi_python-0.35.0 → vgi_python-0.36.0}/conformance/filter-v2/runtime/comparison-ge/worker-expected.arrow +0 -0
  89. {vgi_python-0.35.0 → vgi_python-0.36.0}/conformance/filter-v2/runtime/comparison-gt/expected.arrow +0 -0
  90. {vgi_python-0.35.0 → vgi_python-0.36.0}/conformance/filter-v2/runtime/comparison-gt/filter.arrow +0 -0
  91. {vgi_python-0.35.0 → vgi_python-0.36.0}/conformance/filter-v2/runtime/comparison-gt/input.arrow +0 -0
  92. {vgi_python-0.35.0 → vgi_python-0.36.0}/conformance/filter-v2/runtime/comparison-gt/worker-expected.arrow +0 -0
  93. {vgi_python-0.35.0 → vgi_python-0.36.0}/conformance/filter-v2/runtime/comparison-le/expected.arrow +0 -0
  94. {vgi_python-0.35.0 → vgi_python-0.36.0}/conformance/filter-v2/runtime/comparison-le/filter.arrow +0 -0
  95. {vgi_python-0.35.0 → vgi_python-0.36.0}/conformance/filter-v2/runtime/comparison-le/input.arrow +0 -0
  96. {vgi_python-0.35.0 → vgi_python-0.36.0}/conformance/filter-v2/runtime/comparison-le/worker-expected.arrow +0 -0
  97. {vgi_python-0.35.0 → vgi_python-0.36.0}/conformance/filter-v2/runtime/comparison-lt/expected.arrow +0 -0
  98. {vgi_python-0.35.0 → vgi_python-0.36.0}/conformance/filter-v2/runtime/comparison-lt/filter.arrow +0 -0
  99. {vgi_python-0.35.0 → vgi_python-0.36.0}/conformance/filter-v2/runtime/comparison-lt/input.arrow +0 -0
  100. {vgi_python-0.35.0 → vgi_python-0.36.0}/conformance/filter-v2/runtime/comparison-lt/worker-expected.arrow +0 -0
  101. {vgi_python-0.35.0 → vgi_python-0.36.0}/conformance/filter-v2/runtime/comparison-ne/expected.arrow +0 -0
  102. {vgi_python-0.35.0 → vgi_python-0.36.0}/conformance/filter-v2/runtime/comparison-ne/filter.arrow +0 -0
  103. {vgi_python-0.35.0 → vgi_python-0.36.0}/conformance/filter-v2/runtime/comparison-ne/input.arrow +0 -0
  104. {vgi_python-0.35.0 → vgi_python-0.36.0}/conformance/filter-v2/runtime/comparison-ne/worker-expected.arrow +0 -0
  105. {vgi_python-0.35.0 → vgi_python-0.36.0}/conformance/filter-v2/runtime/comparison-not_distinct_from/expected.arrow +0 -0
  106. {vgi_python-0.35.0 → vgi_python-0.36.0}/conformance/filter-v2/runtime/comparison-not_distinct_from/filter.arrow +0 -0
  107. {vgi_python-0.35.0 → vgi_python-0.36.0}/conformance/filter-v2/runtime/comparison-not_distinct_from/input.arrow +0 -0
  108. {vgi_python-0.35.0 → vgi_python-0.36.0}/conformance/filter-v2/runtime/comparison-not_distinct_from/worker-expected.arrow +0 -0
  109. {vgi_python-0.35.0 → vgi_python-0.36.0}/conformance/filter-v2/runtime/delta-atomic-multi-update/delta-0.arrow +0 -0
  110. {vgi_python-0.35.0 → vgi_python-0.36.0}/conformance/filter-v2/runtime/delta-atomic-multi-update/expected.arrow +0 -0
  111. {vgi_python-0.35.0 → vgi_python-0.36.0}/conformance/filter-v2/runtime/delta-atomic-multi-update/filter.arrow +0 -0
  112. {vgi_python-0.35.0 → vgi_python-0.36.0}/conformance/filter-v2/runtime/delta-atomic-multi-update/input.arrow +0 -0
  113. {vgi_python-0.35.0 → vgi_python-0.36.0}/conformance/filter-v2/runtime/delta-empty-noop/delta-0.arrow +0 -0
  114. {vgi_python-0.35.0 → vgi_python-0.36.0}/conformance/filter-v2/runtime/delta-empty-noop/expected.arrow +0 -0
  115. {vgi_python-0.35.0 → vgi_python-0.36.0}/conformance/filter-v2/runtime/delta-empty-noop/filter.arrow +0 -0
  116. {vgi_python-0.35.0 → vgi_python-0.36.0}/conformance/filter-v2/runtime/delta-empty-noop/input.arrow +0 -0
  117. {vgi_python-0.35.0 → vgi_python-0.36.0}/conformance/filter-v2/runtime/delta-upsert-remove-stale/delta-0.arrow +0 -0
  118. {vgi_python-0.35.0 → vgi_python-0.36.0}/conformance/filter-v2/runtime/delta-upsert-remove-stale/delta-1.arrow +0 -0
  119. {vgi_python-0.35.0 → vgi_python-0.36.0}/conformance/filter-v2/runtime/delta-upsert-remove-stale/delta-2.arrow +0 -0
  120. {vgi_python-0.35.0 → vgi_python-0.36.0}/conformance/filter-v2/runtime/delta-upsert-remove-stale/expected.arrow +0 -0
  121. {vgi_python-0.35.0 → vgi_python-0.36.0}/conformance/filter-v2/runtime/delta-upsert-remove-stale/filter.arrow +0 -0
  122. {vgi_python-0.35.0 → vgi_python-0.36.0}/conformance/filter-v2/runtime/delta-upsert-remove-stale/input.arrow +0 -0
  123. {vgi_python-0.35.0 → vgi_python-0.36.0}/conformance/filter-v2/runtime/empty-snapshot/expected.arrow +0 -0
  124. {vgi_python-0.35.0 → vgi_python-0.36.0}/conformance/filter-v2/runtime/empty-snapshot/filter.arrow +0 -0
  125. {vgi_python-0.35.0 → vgi_python-0.36.0}/conformance/filter-v2/runtime/empty-snapshot/input.arrow +0 -0
  126. {vgi_python-0.35.0 → vgi_python-0.36.0}/conformance/filter-v2/runtime/empty-snapshot/worker-expected.arrow +0 -0
  127. {vgi_python-0.35.0 → vgi_python-0.36.0}/conformance/filter-v2/runtime/error-cast-type-not-null/filter.arrow +0 -0
  128. {vgi_python-0.35.0 → vgi_python-0.36.0}/conformance/filter-v2/runtime/error-cast-type-not-null/input.arrow +0 -0
  129. {vgi_python-0.35.0 → vgi_python-0.36.0}/conformance/filter-v2/runtime/error-column-index/filter.arrow +0 -0
  130. {vgi_python-0.35.0 → vgi_python-0.36.0}/conformance/filter-v2/runtime/error-column-index/input.arrow +0 -0
  131. {vgi_python-0.35.0 → vgi_python-0.36.0}/conformance/filter-v2/runtime/error-column-name/filter.arrow +0 -0
  132. {vgi_python-0.35.0 → vgi_python-0.36.0}/conformance/filter-v2/runtime/error-column-name/input.arrow +0 -0
  133. {vgi_python-0.35.0 → vgi_python-0.36.0}/conformance/filter-v2/runtime/error-contextual-cast-without-session/filter.arrow +0 -0
  134. {vgi_python-0.35.0 → vgi_python-0.36.0}/conformance/filter-v2/runtime/error-contextual-cast-without-session/input.arrow +0 -0
  135. {vgi_python-0.35.0 → vgi_python-0.36.0}/conformance/filter-v2/runtime/error-duplicate-predicate-id/filter.arrow +0 -0
  136. {vgi_python-0.35.0 → vgi_python-0.36.0}/conformance/filter-v2/runtime/error-duplicate-predicate-id/input.arrow +0 -0
  137. {vgi_python-0.35.0 → vgi_python-0.36.0}/conformance/filter-v2/runtime/error-external-column-index/filter.arrow +0 -0
  138. {vgi_python-0.35.0 → vgi_python-0.36.0}/conformance/filter-v2/runtime/error-external-column-index/input.arrow +0 -0
  139. {vgi_python-0.35.0 → vgi_python-0.36.0}/conformance/filter-v2/runtime/error-external-column-index/join-keys-0.arrow +0 -0
  140. {vgi_python-0.35.0 → vgi_python-0.36.0}/conformance/filter-v2/runtime/error-external-column-name/filter.arrow +0 -0
  141. {vgi_python-0.35.0 → vgi_python-0.36.0}/conformance/filter-v2/runtime/error-external-column-name/input.arrow +0 -0
  142. {vgi_python-0.35.0 → vgi_python-0.36.0}/conformance/filter-v2/runtime/error-external-column-name/join-keys-0.arrow +0 -0
  143. {vgi_python-0.35.0 → vgi_python-0.36.0}/conformance/filter-v2/runtime/error-field-non-struct/filter.arrow +0 -0
  144. {vgi_python-0.35.0 → vgi_python-0.36.0}/conformance/filter-v2/runtime/error-field-non-struct/input.arrow +0 -0
  145. {vgi_python-0.35.0 → vgi_python-0.36.0}/conformance/filter-v2/runtime/error-in-payload-not-list/filter.arrow +0 -0
  146. {vgi_python-0.35.0 → vgi_python-0.36.0}/conformance/filter-v2/runtime/error-in-payload-not-list/input.arrow +0 -0
  147. {vgi_python-0.35.0 → vgi_python-0.36.0}/conformance/filter-v2/runtime/error-in-payload-null-list/filter.arrow +0 -0
  148. {vgi_python-0.35.0 → vgi_python-0.36.0}/conformance/filter-v2/runtime/error-in-payload-null-list/input.arrow +0 -0
  149. {vgi_python-0.35.0 → vgi_python-0.36.0}/conformance/filter-v2/runtime/error-invalid-overload/filter.arrow +0 -0
  150. {vgi_python-0.35.0 → vgi_python-0.36.0}/conformance/filter-v2/runtime/error-invalid-overload/input.arrow +0 -0
  151. {vgi_python-0.35.0 → vgi_python-0.36.0}/conformance/filter-v2/runtime/error-missing-literal/filter.arrow +0 -0
  152. {vgi_python-0.35.0 → vgi_python-0.36.0}/conformance/filter-v2/runtime/error-missing-literal/input.arrow +0 -0
  153. {vgi_python-0.35.0 → vgi_python-0.36.0}/conformance/filter-v2/runtime/error-non-boolean-root/filter.arrow +0 -0
  154. {vgi_python-0.35.0 → vgi_python-0.36.0}/conformance/filter-v2/runtime/error-non-boolean-root/input.arrow +0 -0
  155. {vgi_python-0.35.0 → vgi_python-0.36.0}/conformance/filter-v2/runtime/error-unknown-standard-function/filter.arrow +0 -0
  156. {vgi_python-0.35.0 → vgi_python-0.36.0}/conformance/filter-v2/runtime/error-unknown-standard-function/input.arrow +0 -0
  157. {vgi_python-0.35.0 → vgi_python-0.36.0}/conformance/filter-v2/runtime/external-in-nonzero-column/expected.arrow +0 -0
  158. {vgi_python-0.35.0 → vgi_python-0.36.0}/conformance/filter-v2/runtime/external-in-nonzero-column/filter.arrow +0 -0
  159. {vgi_python-0.35.0 → vgi_python-0.36.0}/conformance/filter-v2/runtime/external-in-nonzero-column/input.arrow +0 -0
  160. {vgi_python-0.35.0 → vgi_python-0.36.0}/conformance/filter-v2/runtime/external-in-nonzero-column/join-keys-0.arrow +0 -0
  161. {vgi_python-0.35.0 → vgi_python-0.36.0}/conformance/filter-v2/runtime/external-in-nonzero-column/worker-expected.arrow +0 -0
  162. {vgi_python-0.35.0 → vgi_python-0.36.0}/conformance/filter-v2/runtime/function-contains/expected.arrow +0 -0
  163. {vgi_python-0.35.0 → vgi_python-0.36.0}/conformance/filter-v2/runtime/function-contains/filter.arrow +0 -0
  164. {vgi_python-0.35.0 → vgi_python-0.36.0}/conformance/filter-v2/runtime/function-contains/input.arrow +0 -0
  165. {vgi_python-0.35.0 → vgi_python-0.36.0}/conformance/filter-v2/runtime/function-ends-with/expected.arrow +0 -0
  166. {vgi_python-0.35.0 → vgi_python-0.36.0}/conformance/filter-v2/runtime/function-ends-with/filter.arrow +0 -0
  167. {vgi_python-0.35.0 → vgi_python-0.36.0}/conformance/filter-v2/runtime/function-ends-with/input.arrow +0 -0
  168. {vgi_python-0.35.0 → vgi_python-0.36.0}/conformance/filter-v2/runtime/function-list-contains/expected.arrow +0 -0
  169. {vgi_python-0.35.0 → vgi_python-0.36.0}/conformance/filter-v2/runtime/function-list-contains/filter.arrow +0 -0
  170. {vgi_python-0.35.0 → vgi_python-0.36.0}/conformance/filter-v2/runtime/function-list-contains/input.arrow +0 -0
  171. {vgi_python-0.35.0 → vgi_python-0.36.0}/conformance/filter-v2/runtime/function-starts-with/expected.arrow +0 -0
  172. {vgi_python-0.35.0 → vgi_python-0.36.0}/conformance/filter-v2/runtime/function-starts-with/filter.arrow +0 -0
  173. {vgi_python-0.35.0 → vgi_python-0.36.0}/conformance/filter-v2/runtime/function-starts-with/input.arrow +0 -0
  174. {vgi_python-0.35.0 → vgi_python-0.36.0}/conformance/filter-v2/runtime/in-empty/expected.arrow +0 -0
  175. {vgi_python-0.35.0 → vgi_python-0.36.0}/conformance/filter-v2/runtime/in-empty/filter.arrow +0 -0
  176. {vgi_python-0.35.0 → vgi_python-0.36.0}/conformance/filter-v2/runtime/in-empty/input.arrow +0 -0
  177. {vgi_python-0.35.0 → vgi_python-0.36.0}/conformance/filter-v2/runtime/in-empty/worker-expected.arrow +0 -0
  178. {vgi_python-0.35.0 → vgi_python-0.36.0}/conformance/filter-v2/runtime/in-with-null/expected.arrow +0 -0
  179. {vgi_python-0.35.0 → vgi_python-0.36.0}/conformance/filter-v2/runtime/in-with-null/filter.arrow +0 -0
  180. {vgi_python-0.35.0 → vgi_python-0.36.0}/conformance/filter-v2/runtime/in-with-null/input.arrow +0 -0
  181. {vgi_python-0.35.0 → vgi_python-0.36.0}/conformance/filter-v2/runtime/in-with-null/worker-expected.arrow +0 -0
  182. {vgi_python-0.35.0 → vgi_python-0.36.0}/conformance/filter-v2/runtime/is-not-null/expected.arrow +0 -0
  183. {vgi_python-0.35.0 → vgi_python-0.36.0}/conformance/filter-v2/runtime/is-not-null/filter.arrow +0 -0
  184. {vgi_python-0.35.0 → vgi_python-0.36.0}/conformance/filter-v2/runtime/is-not-null/input.arrow +0 -0
  185. {vgi_python-0.35.0 → vgi_python-0.36.0}/conformance/filter-v2/runtime/is-not-null/worker-expected.arrow +0 -0
  186. {vgi_python-0.35.0 → vgi_python-0.36.0}/conformance/filter-v2/runtime/is-null/expected.arrow +0 -0
  187. {vgi_python-0.35.0 → vgi_python-0.36.0}/conformance/filter-v2/runtime/is-null/filter.arrow +0 -0
  188. {vgi_python-0.35.0 → vgi_python-0.36.0}/conformance/filter-v2/runtime/is-null/input.arrow +0 -0
  189. {vgi_python-0.35.0 → vgi_python-0.36.0}/conformance/filter-v2/runtime/is-null/worker-expected.arrow +0 -0
  190. {vgi_python-0.35.0 → vgi_python-0.36.0}/conformance/filter-v2/runtime/kleene-and/expected.arrow +0 -0
  191. {vgi_python-0.35.0 → vgi_python-0.36.0}/conformance/filter-v2/runtime/kleene-and/filter.arrow +0 -0
  192. {vgi_python-0.35.0 → vgi_python-0.36.0}/conformance/filter-v2/runtime/kleene-and/input.arrow +0 -0
  193. {vgi_python-0.35.0 → vgi_python-0.36.0}/conformance/filter-v2/runtime/kleene-not/expected.arrow +0 -0
  194. {vgi_python-0.35.0 → vgi_python-0.36.0}/conformance/filter-v2/runtime/kleene-not/filter.arrow +0 -0
  195. {vgi_python-0.35.0 → vgi_python-0.36.0}/conformance/filter-v2/runtime/kleene-not/input.arrow +0 -0
  196. {vgi_python-0.35.0 → vgi_python-0.36.0}/conformance/filter-v2/runtime/kleene-or/expected.arrow +0 -0
  197. {vgi_python-0.35.0 → vgi_python-0.36.0}/conformance/filter-v2/runtime/kleene-or/filter.arrow +0 -0
  198. {vgi_python-0.35.0 → vgi_python-0.36.0}/conformance/filter-v2/runtime/kleene-or/input.arrow +0 -0
  199. {vgi_python-0.35.0 → vgi_python-0.36.0}/conformance/filter-v2/runtime/nan-comparison/expected.arrow +0 -0
  200. {vgi_python-0.35.0 → vgi_python-0.36.0}/conformance/filter-v2/runtime/nan-comparison/filter.arrow +0 -0
  201. {vgi_python-0.35.0 → vgi_python-0.36.0}/conformance/filter-v2/runtime/nan-comparison/input.arrow +0 -0
  202. {vgi_python-0.35.0 → vgi_python-0.36.0}/conformance/filter-v2/runtime/negative-zero-membership/expected.arrow +0 -0
  203. {vgi_python-0.35.0 → vgi_python-0.36.0}/conformance/filter-v2/runtime/negative-zero-membership/filter.arrow +0 -0
  204. {vgi_python-0.35.0 → vgi_python-0.36.0}/conformance/filter-v2/runtime/negative-zero-membership/input.arrow +0 -0
  205. {vgi_python-0.35.0 → vgi_python-0.36.0}/conformance/filter-v2/runtime/nested-null-propagation/expected.arrow +0 -0
  206. {vgi_python-0.35.0 → vgi_python-0.36.0}/conformance/filter-v2/runtime/nested-null-propagation/filter.arrow +0 -0
  207. {vgi_python-0.35.0 → vgi_python-0.36.0}/conformance/filter-v2/runtime/nested-null-propagation/input.arrow +0 -0
  208. {vgi_python-0.35.0 → vgi_python-0.36.0}/conformance/filter-v2/runtime/not-in-empty/expected.arrow +0 -0
  209. {vgi_python-0.35.0 → vgi_python-0.36.0}/conformance/filter-v2/runtime/not-in-empty/filter.arrow +0 -0
  210. {vgi_python-0.35.0 → vgi_python-0.36.0}/conformance/filter-v2/runtime/not-in-empty/input.arrow +0 -0
  211. {vgi_python-0.35.0 → vgi_python-0.36.0}/conformance/filter-v2/runtime/not-in-empty/worker-expected.arrow +0 -0
  212. {vgi_python-0.35.0 → vgi_python-0.36.0}/conformance/filter-v2/runtime/not-in-with-null/expected.arrow +0 -0
  213. {vgi_python-0.35.0 → vgi_python-0.36.0}/conformance/filter-v2/runtime/not-in-with-null/filter.arrow +0 -0
  214. {vgi_python-0.35.0 → vgi_python-0.36.0}/conformance/filter-v2/runtime/not-in-with-null/input.arrow +0 -0
  215. {vgi_python-0.35.0 → vgi_python-0.36.0}/conformance/filter-v2/runtime/not-in-with-null/worker-expected.arrow +0 -0
  216. {vgi_python-0.35.0 → vgi_python-0.36.0}/conformance/filter-v2/runtime/session-integer-division/expected.arrow +0 -0
  217. {vgi_python-0.35.0 → vgi_python-0.36.0}/conformance/filter-v2/runtime/session-integer-division/filter.arrow +0 -0
  218. {vgi_python-0.35.0 → vgi_python-0.36.0}/conformance/filter-v2/runtime/session-integer-division/input.arrow +0 -0
  219. {vgi_python-0.35.0 → vgi_python-0.36.0}/conformance/filter-v2/runtime-manifest.json +0 -0
  220. {vgi_python-0.35.0 → vgi_python-0.36.0}/dist-vgi/.gitignore +0 -0
  221. {vgi_python-0.35.0 → vgi_python-0.36.0}/docs/aggregate-functions.md +0 -0
  222. {vgi_python-0.35.0 → vgi_python-0.36.0}/docs/api/arguments.md +0 -0
  223. {vgi_python-0.35.0 → vgi_python-0.36.0}/docs/api/auth.md +0 -0
  224. {vgi_python-0.35.0 → vgi_python-0.36.0}/docs/api/catalogs.md +0 -0
  225. {vgi_python-0.35.0 → vgi_python-0.36.0}/docs/api/client.md +0 -0
  226. {vgi_python-0.35.0 → vgi_python-0.36.0}/docs/api/exceptions.md +0 -0
  227. {vgi_python-0.35.0 → vgi_python-0.36.0}/docs/api/filters.md +0 -0
  228. {vgi_python-0.35.0 → vgi_python-0.36.0}/docs/api/functions.md +0 -0
  229. {vgi_python-0.35.0 → vgi_python-0.36.0}/docs/api/http.md +0 -0
  230. {vgi_python-0.35.0 → vgi_python-0.36.0}/docs/api/index.md +0 -0
  231. {vgi_python-0.35.0 → vgi_python-0.36.0}/docs/api/metadata.md +0 -0
  232. {vgi_python-0.35.0 → vgi_python-0.36.0}/docs/api/observability.md +0 -0
  233. {vgi_python-0.35.0 → vgi_python-0.36.0}/docs/api/storage.md +0 -0
  234. {vgi_python-0.35.0 → vgi_python-0.36.0}/docs/api/transactor.md +0 -0
  235. {vgi_python-0.35.0 → vgi_python-0.36.0}/docs/api/worker.md +0 -0
  236. {vgi_python-0.35.0 → vgi_python-0.36.0}/docs/argument-serialization.md +0 -0
  237. {vgi_python-0.35.0 → vgi_python-0.36.0}/docs/assets/apple-touch-icon.png +0 -0
  238. {vgi_python-0.35.0 → vgi_python-0.36.0}/docs/assets/favicon-16x16.png +0 -0
  239. {vgi_python-0.35.0 → vgi_python-0.36.0}/docs/assets/favicon-32x32.png +0 -0
  240. {vgi_python-0.35.0 → vgi_python-0.36.0}/docs/assets/favicon.ico +0 -0
  241. {vgi_python-0.35.0 → vgi_python-0.36.0}/docs/assets/kinds/aggregate.svg +0 -0
  242. {vgi_python-0.35.0 → vgi_python-0.36.0}/docs/assets/kinds/buffering.svg +0 -0
  243. {vgi_python-0.35.0 → vgi_python-0.36.0}/docs/assets/kinds/scalar.svg +0 -0
  244. {vgi_python-0.35.0 → vgi_python-0.36.0}/docs/assets/kinds/table-in-out.svg +0 -0
  245. {vgi_python-0.35.0 → vgi_python-0.36.0}/docs/assets/kinds/table.svg +0 -0
  246. {vgi_python-0.35.0 → vgi_python-0.36.0}/docs/assets/logo.png +0 -0
  247. {vgi_python-0.35.0 → vgi_python-0.36.0}/docs/assets/social-card.png +0 -0
  248. {vgi_python-0.35.0 → vgi_python-0.36.0}/docs/authentication.md +0 -0
  249. {vgi_python-0.35.0 → vgi_python-0.36.0}/docs/catalog-interface.md +0 -0
  250. {vgi_python-0.35.0 → vgi_python-0.36.0}/docs/cli.md +0 -0
  251. {vgi_python-0.35.0 → vgi_python-0.36.0}/docs/column-statistics.md +0 -0
  252. {vgi_python-0.35.0 → vgi_python-0.36.0}/docs/concepts/index.md +0 -0
  253. {vgi_python-0.35.0 → vgi_python-0.36.0}/docs/contributing-docs.md +0 -0
  254. {vgi_python-0.35.0 → vgi_python-0.36.0}/docs/filter-pushdown.md +0 -0
  255. {vgi_python-0.35.0 → vgi_python-0.36.0}/docs/generator-api.md +0 -0
  256. {vgi_python-0.35.0 → vgi_python-0.36.0}/docs/global-functions.md +0 -0
  257. {vgi_python-0.35.0 → vgi_python-0.36.0}/docs/how-to/catalogs.md +0 -0
  258. {vgi_python-0.35.0 → vgi_python-0.36.0}/docs/how-to/function-patterns.md +0 -0
  259. {vgi_python-0.35.0 → vgi_python-0.36.0}/docs/how-to/http-auth.md +0 -0
  260. {vgi_python-0.35.0 → vgi_python-0.36.0}/docs/how-to/index.md +0 -0
  261. {vgi_python-0.35.0 → vgi_python-0.36.0}/docs/how-to/iroh.md +0 -0
  262. {vgi_python-0.35.0 → vgi_python-0.36.0}/docs/how-to/pushdown-and-statistics.md +0 -0
  263. {vgi_python-0.35.0 → vgi_python-0.36.0}/docs/how-to/state-storage.md +0 -0
  264. {vgi_python-0.35.0 → vgi_python-0.36.0}/docs/how-to/tailnet.md +0 -0
  265. {vgi_python-0.35.0 → vgi_python-0.36.0}/docs/index.md +0 -0
  266. {vgi_python-0.35.0 → vgi_python-0.36.0}/docs/lifecycle.md +0 -0
  267. {vgi_python-0.35.0 → vgi_python-0.36.0}/docs/metadata.md +0 -0
  268. {vgi_python-0.35.0 → vgi_python-0.36.0}/docs/overrides/main.html +0 -0
  269. {vgi_python-0.35.0 → vgi_python-0.36.0}/docs/protocol/index.md +0 -0
  270. {vgi_python-0.35.0 → vgi_python-0.36.0}/docs/protocol/vgi-catalog-query-pushdown-design.md +0 -0
  271. {vgi_python-0.35.0 → vgi_python-0.36.0}/docs/protocol/vgi-duckdb-filter-adapter.md +0 -0
  272. {vgi_python-0.35.0 → vgi_python-0.36.0}/docs/protocol/vgi-filter-encoding-v2-spec.md +0 -0
  273. {vgi_python-0.35.0 → vgi_python-0.36.0}/docs/protocol/vgi-protocol-proposed-changes.md +0 -0
  274. {vgi_python-0.35.0 → vgi_python-0.36.0}/docs/protocol/vgi-runtime-filter-artifacts.md +0 -0
  275. {vgi_python-0.35.0 → vgi_python-0.36.0}/docs/robots.txt +0 -0
  276. {vgi_python-0.35.0 → vgi_python-0.36.0}/docs/shared-storage.md +0 -0
  277. {vgi_python-0.35.0 → vgi_python-0.36.0}/docs/stylesheets/extra.css +0 -0
  278. {vgi_python-0.35.0 → vgi_python-0.36.0}/docs/tutorial/index.md +0 -0
  279. {vgi_python-0.35.0 → vgi_python-0.36.0}/docs/tutorial/scalar.md +0 -0
  280. {vgi_python-0.35.0 → vgi_python-0.36.0}/docs/tutorial/table.md +0 -0
  281. {vgi_python-0.35.0 → vgi_python-0.36.0}/docs/vgi-logo.png +0 -0
  282. {vgi_python-0.35.0 → vgi_python-0.36.0}/examples/batch_index_worker.py +0 -0
  283. {vgi_python-0.35.0 → vgi_python-0.36.0}/examples/cache_worker.py +0 -0
  284. {vgi_python-0.35.0 → vgi_python-0.36.0}/examples/calc_scalar_worker.py +0 -0
  285. {vgi_python-0.35.0 → vgi_python-0.36.0}/examples/calc_worker.py +0 -0
  286. {vgi_python-0.35.0 → vgi_python-0.36.0}/examples/copy_format_worker.py +0 -0
  287. {vgi_python-0.35.0 → vgi_python-0.36.0}/examples/filter_worker.py +0 -0
  288. {vgi_python-0.35.0 → vgi_python-0.36.0}/examples/greeting_scalar_worker.py +0 -0
  289. {vgi_python-0.35.0 → vgi_python-0.36.0}/examples/row_count_worker.py +0 -0
  290. {vgi_python-0.35.0 → vgi_python-0.36.0}/examples/series_streaming_worker.py +0 -0
  291. {vgi_python-0.35.0 → vgi_python-0.36.0}/examples/sum_worker.py +0 -0
  292. {vgi_python-0.35.0 → vgi_python-0.36.0}/identity.png +0 -0
  293. {vgi_python-0.35.0 → vgi_python-0.36.0}/mkdocs.yml +0 -0
  294. {vgi_python-0.35.0 → vgi_python-0.36.0}/packages/vgi-fixtures/LICENSE +0 -0
  295. {vgi_python-0.35.0 → vgi_python-0.36.0}/packages/vgi-fixtures/README.md +0 -0
  296. {vgi_python-0.35.0 → vgi_python-0.36.0}/packages/vgi-fixtures/docker/Dockerfile +0 -0
  297. {vgi_python-0.35.0 → vgi_python-0.36.0}/packages/vgi-fixtures/docker/docker-entrypoint.sh +0 -0
  298. {vgi_python-0.35.0 → vgi_python-0.36.0}/packages/vgi-fixtures/pyproject.toml +0 -0
  299. {vgi_python-0.35.0 → vgi_python-0.36.0}/scripts/measure_startup.py +0 -0
  300. {vgi_python-0.35.0 → vgi_python-0.36.0}/scripts/regen_generated.py +0 -0
  301. {vgi_python-0.35.0 → vgi_python-0.36.0}/scripts/run_all_tests.sh +0 -0
  302. {vgi_python-0.35.0 → vgi_python-0.36.0}/test-data/generate.sh +0 -0
  303. {vgi_python-0.35.0 → vgi_python-0.36.0}/tests/__init__.py +0 -0
  304. {vgi_python-0.35.0 → vgi_python-0.36.0}/tests/_http_fixtures.py +0 -0
  305. {vgi_python-0.35.0 → vgi_python-0.36.0}/tests/catalog/__init__.py +0 -0
  306. {vgi_python-0.35.0 → vgi_python-0.36.0}/tests/catalog/test_attach_option.py +0 -0
  307. {vgi_python-0.35.0 → vgi_python-0.36.0}/tests/catalog/test_catalog_interface.py +0 -0
  308. {vgi_python-0.35.0 → vgi_python-0.36.0}/tests/catalog/test_client_catalog.py +0 -0
  309. {vgi_python-0.35.0 → vgi_python-0.36.0}/tests/catalog/test_column_statistics.py +0 -0
  310. {vgi_python-0.35.0 → vgi_python-0.36.0}/tests/catalog/test_declarative.py +0 -0
  311. {vgi_python-0.35.0 → vgi_python-0.36.0}/tests/catalog/test_example_worker_catalog.py +0 -0
  312. {vgi_python-0.35.0 → vgi_python-0.36.0}/tests/catalog/test_integration.py +0 -0
  313. {vgi_python-0.35.0 → vgi_python-0.36.0}/tests/catalog/test_required_filters.py +0 -0
  314. {vgi_python-0.35.0 → vgi_python-0.36.0}/tests/catalog/test_scan_branches.py +0 -0
  315. {vgi_python-0.35.0 → vgi_python-0.36.0}/tests/catalog/test_serialization.py +0 -0
  316. {vgi_python-0.35.0 → vgi_python-0.36.0}/tests/catalog/test_setting.py +0 -0
  317. {vgi_python-0.35.0 → vgi_python-0.36.0}/tests/catalog/test_storage.py +0 -0
  318. {vgi_python-0.35.0 → vgi_python-0.36.0}/tests/catalog/test_time_travel.py +0 -0
  319. {vgi_python-0.35.0 → vgi_python-0.36.0}/tests/catalog/test_writable_table.py +0 -0
  320. {vgi_python-0.35.0 → vgi_python-0.36.0}/tests/client/__init__.py +0 -0
  321. {vgi_python-0.35.0 → vgi_python-0.36.0}/tests/client/test_aggregate_client.py +0 -0
  322. {vgi_python-0.35.0 → vgi_python-0.36.0}/tests/client/test_batch_metadata_callback.py +0 -0
  323. {vgi_python-0.35.0 → vgi_python-0.36.0}/tests/client/test_bind_and_join_keys.py +0 -0
  324. {vgi_python-0.35.0 → vgi_python-0.36.0}/tests/client/test_broken_pipe.py +0 -0
  325. {vgi_python-0.35.0 → vgi_python-0.36.0}/tests/client/test_cli.py +0 -0
  326. {vgi_python-0.35.0 → vgi_python-0.36.0}/tests/client/test_cli_catalog_functions.py +0 -0
  327. {vgi_python-0.35.0 → vgi_python-0.36.0}/tests/client/test_copy_client.py +0 -0
  328. {vgi_python-0.35.0 → vgi_python-0.36.0}/tests/client/test_http_response_budget.py +0 -0
  329. {vgi_python-0.35.0 → vgi_python-0.36.0}/tests/client/test_iroh_client.py +0 -0
  330. {vgi_python-0.35.0 → vgi_python-0.36.0}/tests/client/test_scan_branches_client.py +0 -0
  331. {vgi_python-0.35.0 → vgi_python-0.36.0}/tests/client/test_split_client.py +0 -0
  332. {vgi_python-0.35.0 → vgi_python-0.36.0}/tests/client/test_table_column_statistics.py +0 -0
  333. {vgi_python-0.35.0 → vgi_python-0.36.0}/tests/client/test_time_travel_client.py +0 -0
  334. {vgi_python-0.35.0 → vgi_python-0.36.0}/tests/client/test_worker_debug.py +0 -0
  335. {vgi_python-0.35.0 → vgi_python-0.36.0}/tests/conformance/__init__.py +0 -0
  336. {vgi_python-0.35.0 → vgi_python-0.36.0}/tests/conformance/_stub.py +0 -0
  337. {vgi_python-0.35.0 → vgi_python-0.36.0}/tests/conformance/conftest.py +0 -0
  338. {vgi_python-0.35.0 → vgi_python-0.36.0}/tests/conformance/test_accumulate.py +0 -0
  339. {vgi_python-0.35.0 → vgi_python-0.36.0}/tests/conformance/test_aggregate.py +0 -0
  340. {vgi_python-0.35.0 → vgi_python-0.36.0}/tests/conformance/test_attach.py +0 -0
  341. {vgi_python-0.35.0 → vgi_python-0.36.0}/tests/conformance/test_bearer_auth.py +0 -0
  342. {vgi_python-0.35.0 → vgi_python-0.36.0}/tests/conformance/test_const_param_enforcement.py +0 -0
  343. {vgi_python-0.35.0 → vgi_python-0.36.0}/tests/conformance/test_container.py +0 -0
  344. {vgi_python-0.35.0 → vgi_python-0.36.0}/tests/conformance/test_copy_from.py +0 -0
  345. {vgi_python-0.35.0 → vgi_python-0.36.0}/tests/conformance/test_copy_to.py +0 -0
  346. {vgi_python-0.35.0 → vgi_python-0.36.0}/tests/conformance/test_directory_parity.py +0 -0
  347. {vgi_python-0.35.0 → vgi_python-0.36.0}/tests/conformance/test_function_inventory.py +0 -0
  348. {vgi_python-0.35.0 → vgi_python-0.36.0}/tests/conformance/test_github.py +0 -0
  349. {vgi_python-0.35.0 → vgi_python-0.36.0}/tests/conformance/test_http_client.py +0 -0
  350. {vgi_python-0.35.0 → vgi_python-0.36.0}/tests/conformance/test_http_external_location.py +0 -0
  351. {vgi_python-0.35.0 → vgi_python-0.36.0}/tests/conformance/test_http_upload_url.py +0 -0
  352. {vgi_python-0.35.0 → vgi_python-0.36.0}/tests/conformance/test_macro.py +0 -0
  353. {vgi_python-0.35.0 → vgi_python-0.36.0}/tests/conformance/test_overload.py +0 -0
  354. {vgi_python-0.35.0 → vgi_python-0.36.0}/tests/conformance/test_protocol_inventory.py +0 -0
  355. {vgi_python-0.35.0 → vgi_python-0.36.0}/tests/conformance/test_protocol_version.py +0 -0
  356. {vgi_python-0.35.0 → vgi_python-0.36.0}/tests/conformance/test_resumable_scan.py +0 -0
  357. {vgi_python-0.35.0 → vgi_python-0.36.0}/tests/conformance/test_scalar.py +0 -0
  358. {vgi_python-0.35.0 → vgi_python-0.36.0}/tests/conformance/test_scalar_attach_opaque_data.py +0 -0
  359. {vgi_python-0.35.0 → vgi_python-0.36.0}/tests/conformance/test_secret.py +0 -0
  360. {vgi_python-0.35.0 → vgi_python-0.36.0}/tests/conformance/test_settings.py +0 -0
  361. {vgi_python-0.35.0 → vgi_python-0.36.0}/tests/conformance/test_splits.py +0 -0
  362. {vgi_python-0.35.0 → vgi_python-0.36.0}/tests/conformance/test_table.py +0 -0
  363. {vgi_python-0.35.0 → vgi_python-0.36.0}/tests/conformance/test_table_in_out.py +0 -0
  364. {vgi_python-0.35.0 → vgi_python-0.36.0}/tests/conformance/test_view.py +0 -0
  365. {vgi_python-0.35.0 → vgi_python-0.36.0}/tests/conformance/test_writable.py +0 -0
  366. {vgi_python-0.35.0 → vgi_python-0.36.0}/tests/data/split_tokens/anchor_len_overrun.bin +0 -0
  367. {vgi_python-0.35.0 → vgi_python-0.36.0}/tests/data/split_tokens/bad_fingerprint.bin +0 -0
  368. {vgi_python-0.35.0 → vgi_python-0.36.0}/tests/data/split_tokens/bad_flags_unsealed_but_key_present.bin +0 -0
  369. {vgi_python-0.35.0 → vgi_python-0.36.0}/tests/data/split_tokens/bad_version.bin +0 -0
  370. {vgi_python-0.35.0 → vgi_python-0.36.0}/tests/data/split_tokens/generate.py +0 -0
  371. {vgi_python-0.35.0 → vgi_python-0.36.0}/tests/data/split_tokens/manifest.json +0 -0
  372. {vgi_python-0.35.0 → vgi_python-0.36.0}/tests/data/split_tokens/reserved_flag_bit.bin +0 -0
  373. {vgi_python-0.35.0 → vgi_python-0.36.0}/tests/data/split_tokens/stale_anchor.bin +0 -0
  374. {vgi_python-0.35.0 → vgi_python-0.36.0}/tests/data/split_tokens/truncated.bin +0 -0
  375. {vgi_python-0.35.0 → vgi_python-0.36.0}/tests/data/split_tokens/valid_sealed.bin +0 -0
  376. {vgi_python-0.35.0 → vgi_python-0.36.0}/tests/data/split_tokens/valid_unsealed.bin +0 -0
  377. {vgi_python-0.35.0 → vgi_python-0.36.0}/tests/scalar/__init__.py +0 -0
  378. {vgi_python-0.35.0 → vgi_python-0.36.0}/tests/scalar/test_bernoulli_function.py +0 -0
  379. {vgi_python-0.35.0 → vgi_python-0.36.0}/tests/scalar/test_binary_packet_function.py +0 -0
  380. {vgi_python-0.35.0 → vgi_python-0.36.0}/tests/scalar/test_conditional_message_function.py +0 -0
  381. {vgi_python-0.35.0 → vgi_python-0.36.0}/tests/scalar/test_hash_seed_function.py +0 -0
  382. {vgi_python-0.35.0 → vgi_python-0.36.0}/tests/scalar/test_multiply_by_setting_function.py +0 -0
  383. {vgi_python-0.35.0 → vgi_python-0.36.0}/tests/scalar/test_multiply_function.py +0 -0
  384. {vgi_python-0.35.0 → vgi_python-0.36.0}/tests/scalar/test_random_bytes_function.py +0 -0
  385. {vgi_python-0.35.0 → vgi_python-0.36.0}/tests/scalar/test_return_secret_value_function.py +0 -0
  386. {vgi_python-0.35.0 → vgi_python-0.36.0}/tests/table/__init__.py +0 -0
  387. {vgi_python-0.35.0 → vgi_python-0.36.0}/tests/table/generator/__init__.py +0 -0
  388. {vgi_python-0.35.0 → vgi_python-0.36.0}/tests/table/generator/test_constant_columns_function.py +0 -0
  389. {vgi_python-0.35.0 → vgi_python-0.36.0}/tests/table/generator/test_double_sequence_function.py +0 -0
  390. {vgi_python-0.35.0 → vgi_python-0.36.0}/tests/table/generator/test_exception_function.py +0 -0
  391. {vgi_python-0.35.0 → vgi_python-0.36.0}/tests/table/generator/test_filter_echo_function.py +0 -0
  392. {vgi_python-0.35.0 → vgi_python-0.36.0}/tests/table/generator/test_logging_function.py +0 -0
  393. {vgi_python-0.35.0 → vgi_python-0.36.0}/tests/table/generator/test_nested_sequence_function.py +0 -0
  394. {vgi_python-0.35.0 → vgi_python-0.36.0}/tests/table/generator/test_partitioned_function.py +0 -0
  395. {vgi_python-0.35.0 → vgi_python-0.36.0}/tests/table/generator/test_projected_data_function.py +0 -0
  396. {vgi_python-0.35.0 → vgi_python-0.36.0}/tests/table/generator/test_sequence_function.py +0 -0
  397. {vgi_python-0.35.0 → vgi_python-0.36.0}/tests/table/generator/test_settings_function.py +0 -0
  398. {vgi_python-0.35.0 → vgi_python-0.36.0}/tests/table/generator/test_struct_settings_function.py +0 -0
  399. {vgi_python-0.35.0 → vgi_python-0.36.0}/tests/table/generator/test_ten_thousand_function.py +0 -0
  400. {vgi_python-0.35.0 → vgi_python-0.36.0}/tests/table/test_wide_columns.py +0 -0
  401. {vgi_python-0.35.0 → vgi_python-0.36.0}/tests/table_in_out/__init__.py +0 -0
  402. {vgi_python-0.35.0 → vgi_python-0.36.0}/tests/table_in_out/generator/__init__.py +0 -0
  403. {vgi_python-0.35.0 → vgi_python-0.36.0}/tests/table_in_out/generator/test_buffer_input_function.py +0 -0
  404. {vgi_python-0.35.0 → vgi_python-0.36.0}/tests/table_in_out/generator/test_echo_function.py +0 -0
  405. {vgi_python-0.35.0 → vgi_python-0.36.0}/tests/table_in_out/generator/test_exception_functions.py +0 -0
  406. {vgi_python-0.35.0 → vgi_python-0.36.0}/tests/table_in_out/generator/test_filter_by_setting_function.py +0 -0
  407. {vgi_python-0.35.0 → vgi_python-0.36.0}/tests/table_in_out/generator/test_repeat_inputs_function.py +0 -0
  408. {vgi_python-0.35.0 → vgi_python-0.36.0}/tests/table_in_out/generator/test_substream_partial_sum_function.py +0 -0
  409. {vgi_python-0.35.0 → vgi_python-0.36.0}/tests/table_in_out/generator/test_sum_all_columns_function.py +0 -0
  410. {vgi_python-0.35.0 → vgi_python-0.36.0}/tests/table_in_out/test_blended_exchange.py +0 -0
  411. {vgi_python-0.35.0 → vgi_python-0.36.0}/tests/table_in_out/test_blended_metadata.py +0 -0
  412. {vgi_python-0.35.0 → vgi_python-0.36.0}/tests/tailnet/Dockerfile +0 -0
  413. {vgi_python-0.35.0 → vgi_python-0.36.0}/tests/tailnet/__init__.py +0 -0
  414. {vgi_python-0.35.0 → vgi_python-0.36.0}/tests/tailnet/compose.yaml +0 -0
  415. {vgi_python-0.35.0 → vgi_python-0.36.0}/tests/tailnet/probe.py +0 -0
  416. {vgi_python-0.35.0 → vgi_python-0.36.0}/tests/tailnet/run.sh +0 -0
  417. {vgi_python-0.35.0 → vgi_python-0.36.0}/tests/tailnet/test_worker.py +0 -0
  418. {vgi_python-0.35.0 → vgi_python-0.36.0}/tests/tailnet/worker.py +0 -0
  419. {vgi_python-0.35.0 → vgi_python-0.36.0}/tests/test_access_log_audit.py +0 -0
  420. {vgi_python-0.35.0 → vgi_python-0.36.0}/tests/test_aggregate_function.py +0 -0
  421. {vgi_python-0.35.0 → vgi_python-0.36.0}/tests/test_argument_spec.py +0 -0
  422. {vgi_python-0.35.0 → vgi_python-0.36.0}/tests/test_auth.py +0 -0
  423. {vgi_python-0.35.0 → vgi_python-0.36.0}/tests/test_bind_exceptions.py +0 -0
  424. {vgi_python-0.35.0 → vgi_python-0.36.0}/tests/test_bind_request_at_clause.py +0 -0
  425. {vgi_python-0.35.0 → vgi_python-0.36.0}/tests/test_bound_storage_conformance.py +0 -0
  426. {vgi_python-0.35.0 → vgi_python-0.36.0}/tests/test_cache_control.py +0 -0
  427. {vgi_python-0.35.0 → vgi_python-0.36.0}/tests/test_call_state_attach.py +0 -0
  428. {vgi_python-0.35.0 → vgi_python-0.36.0}/tests/test_catalog_auth_binding.py +0 -0
  429. {vgi_python-0.35.0 → vgi_python-0.36.0}/tests/test_client_oauth.py +0 -0
  430. {vgi_python-0.35.0 → vgi_python-0.36.0}/tests/test_codegen_request_inventory.py +0 -0
  431. {vgi_python-0.35.0 → vgi_python-0.36.0}/tests/test_copy_from_function.py +0 -0
  432. {vgi_python-0.35.0 → vgi_python-0.36.0}/tests/test_copy_to_function.py +0 -0
  433. {vgi_python-0.35.0 → vgi_python-0.36.0}/tests/test_docstrings.py +0 -0
  434. {vgi_python-0.35.0 → vgi_python-0.36.0}/tests/test_documentation_examples.py +0 -0
  435. {vgi_python-0.35.0 → vgi_python-0.36.0}/tests/test_example_function_arg_types.py +0 -0
  436. {vgi_python-0.35.0 → vgi_python-0.36.0}/tests/test_examples_workers.py +0 -0
  437. {vgi_python-0.35.0 → vgi_python-0.36.0}/tests/test_exception_handling.py +0 -0
  438. {vgi_python-0.35.0 → vgi_python-0.36.0}/tests/test_exceptions.py +0 -0
  439. {vgi_python-0.35.0 → vgi_python-0.36.0}/tests/test_filter_pushdown.py +0 -0
  440. {vgi_python-0.35.0 → vgi_python-0.36.0}/tests/test_filter_pushdown_extension.py +0 -0
  441. {vgi_python-0.35.0 → vgi_python-0.36.0}/tests/test_filter_v2.py +0 -0
  442. {vgi_python-0.35.0 → vgi_python-0.36.0}/tests/test_filter_v2_builder.py +0 -0
  443. {vgi_python-0.35.0 → vgi_python-0.36.0}/tests/test_filter_v2_runtime_corpus.py +0 -0
  444. {vgi_python-0.35.0 → vgi_python-0.36.0}/tests/test_filter_v2_spec_schema.py +0 -0
  445. {vgi_python-0.35.0 → vgi_python-0.36.0}/tests/test_fixture_catalog_parity.py +0 -0
  446. {vgi_python-0.35.0 → vgi_python-0.36.0}/tests/test_function_shape_mismatch.py +0 -0
  447. {vgi_python-0.35.0 → vgi_python-0.36.0}/tests/test_function_storage.py +0 -0
  448. {vgi_python-0.35.0 → vgi_python-0.36.0}/tests/test_function_storage_azure_sql.py +0 -0
  449. {vgi_python-0.35.0 → vgi_python-0.36.0}/tests/test_function_storage_cf_do.py +0 -0
  450. {vgi_python-0.35.0 → vgi_python-0.36.0}/tests/test_function_storage_cf_do_integration.py +0 -0
  451. {vgi_python-0.35.0 → vgi_python-0.36.0}/tests/test_function_storage_conformance.py +0 -0
  452. {vgi_python-0.35.0 → vgi_python-0.36.0}/tests/test_generated_cpp_constants.py +0 -0
  453. {vgi_python-0.35.0 → vgi_python-0.36.0}/tests/test_generated_cpp_protocol_name.py +0 -0
  454. {vgi_python-0.35.0 → vgi_python-0.36.0}/tests/test_generated_cpp_protocol_version.py +0 -0
  455. {vgi_python-0.35.0 → vgi_python-0.36.0}/tests/test_generated_cpp_request_builders.py +0 -0
  456. {vgi_python-0.35.0 → vgi_python-0.36.0}/tests/test_generated_cpp_schemas.py +0 -0
  457. {vgi_python-0.35.0 → vgi_python-0.36.0}/tests/test_generated_cpp_secret.py +0 -0
  458. {vgi_python-0.35.0 → vgi_python-0.36.0}/tests/test_generated_go_schemas.py +0 -0
  459. {vgi_python-0.35.0 → vgi_python-0.36.0}/tests/test_generated_java_schemas.py +0 -0
  460. {vgi_python-0.35.0 → vgi_python-0.36.0}/tests/test_generated_protocol_version.py +0 -0
  461. {vgi_python-0.35.0 → vgi_python-0.36.0}/tests/test_generated_rust_request_builders.py +0 -0
  462. {vgi_python-0.35.0 → vgi_python-0.36.0}/tests/test_generated_rust_schemas.py +0 -0
  463. {vgi_python-0.35.0 → vgi_python-0.36.0}/tests/test_generated_schemas_cross_lang.py +0 -0
  464. {vgi_python-0.35.0 → vgi_python-0.36.0}/tests/test_generated_ts_client.py +0 -0
  465. {vgi_python-0.35.0 → vgi_python-0.36.0}/tests/test_generated_ts_schemas.py +0 -0
  466. {vgi_python-0.35.0 → vgi_python-0.36.0}/tests/test_http_demo_storage.py +0 -0
  467. {vgi_python-0.35.0 → vgi_python-0.36.0}/tests/test_http_s3_offload_input.py +0 -0
  468. {vgi_python-0.35.0 → vgi_python-0.36.0}/tests/test_http_s3_offload_output.py +0 -0
  469. {vgi_python-0.35.0 → vgi_python-0.36.0}/tests/test_import_side_effects.py +0 -0
  470. {vgi_python-0.35.0 → vgi_python-0.36.0}/tests/test_launch_transport.py +0 -0
  471. {vgi_python-0.35.0 → vgi_python-0.36.0}/tests/test_metadata.py +0 -0
  472. {vgi_python-0.35.0 → vgi_python-0.36.0}/tests/test_mypy_consolidated.py +0 -0
  473. {vgi_python-0.35.0 → vgi_python-0.36.0}/tests/test_nest_tensor.py +0 -0
  474. {vgi_python-0.35.0 → vgi_python-0.36.0}/tests/test_otel.py +0 -0
  475. {vgi_python-0.35.0 → vgi_python-0.36.0}/tests/test_projection_enforcement.py +0 -0
  476. {vgi_python-0.35.0 → vgi_python-0.36.0}/tests/test_projection_repro.py +0 -0
  477. {vgi_python-0.35.0 → vgi_python-0.36.0}/tests/test_protocol_classes.py +0 -0
  478. {vgi_python-0.35.0 → vgi_python-0.36.0}/tests/test_resolved_secrets.py +0 -0
  479. {vgi_python-0.35.0 → vgi_python-0.36.0}/tests/test_schema_paths_v2.py +0 -0
  480. {vgi_python-0.35.0 → vgi_python-0.36.0}/tests/test_schema_scoped_functions.py +0 -0
  481. {vgi_python-0.35.0 → vgi_python-0.36.0}/tests/test_schema_utils.py +0 -0
  482. {vgi_python-0.35.0 → vgi_python-0.36.0}/tests/test_serve.py +0 -0
  483. {vgi_python-0.35.0 → vgi_python-0.36.0}/tests/test_setting_secret_annotations.py +0 -0
  484. {vgi_python-0.35.0 → vgi_python-0.36.0}/tests/test_signing_key.py +0 -0
  485. {vgi_python-0.35.0 → vgi_python-0.36.0}/tests/test_split_token.py +0 -0
  486. {vgi_python-0.35.0 → vgi_python-0.36.0}/tests/test_subprocess_transport.py +0 -0
  487. {vgi_python-0.35.0 → vgi_python-0.36.0}/tests/test_table_buffering_function.py +0 -0
  488. {vgi_python-0.35.0 → vgi_python-0.36.0}/tests/test_table_function_dynamic_to_string.py +0 -0
  489. {vgi_python-0.35.0 → vgi_python-0.36.0}/tests/test_tcp_transport.py +0 -0
  490. {vgi_python-0.35.0 → vgi_python-0.36.0}/tests/test_type_bounds.py +0 -0
  491. {vgi_python-0.35.0 → vgi_python-0.36.0}/tests/test_union_argument.py +0 -0
  492. {vgi_python-0.35.0 → vgi_python-0.36.0}/tests/test_wire_record_schema_parity.py +0 -0
  493. {vgi_python-0.35.0 → vgi_python-0.36.0}/tests/test_worker.py +0 -0
  494. {vgi_python-0.35.0 → vgi_python-0.36.0}/tests/test_worker_cli.py +0 -0
  495. {vgi_python-0.35.0 → vgi_python-0.36.0}/tests/test_worker_page.py +0 -0
  496. {vgi_python-0.35.0 → vgi_python-0.36.0}/tests/test_write_results.py +0 -0
  497. {vgi_python-0.35.0 → vgi_python-0.36.0}/tests/transactor/__init__.py +0 -0
  498. {vgi_python-0.35.0 → vgi_python-0.36.0}/tests/transactor/test_transactor.py +0 -0
  499. {vgi_python-0.35.0 → vgi_python-0.36.0}/vgi/__init__.py +0 -0
  500. {vgi_python-0.35.0 → vgi_python-0.36.0}/vgi/_duckdb.py +0 -0
  501. {vgi_python-0.35.0 → vgi_python-0.36.0}/vgi/_storage_profile.py +0 -0
  502. {vgi_python-0.35.0 → vgi_python-0.36.0}/vgi/_test_fixtures/__init__.py +0 -0
  503. {vgi_python-0.35.0 → vgi_python-0.36.0}/vgi/_test_fixtures/accumulate/__init__.py +0 -0
  504. {vgi_python-0.35.0 → vgi_python-0.36.0}/vgi/_test_fixtures/accumulate/worker.py +0 -0
  505. {vgi_python-0.35.0 → vgi_python-0.36.0}/vgi/_test_fixtures/aggregate/__init__.py +0 -0
  506. {vgi_python-0.35.0 → vgi_python-0.36.0}/vgi/_test_fixtures/aggregate/_common.py +0 -0
  507. {vgi_python-0.35.0 → vgi_python-0.36.0}/vgi/_test_fixtures/aggregate/basic.py +0 -0
  508. {vgi_python-0.35.0 → vgi_python-0.36.0}/vgi/_test_fixtures/aggregate/dynamic.py +0 -0
  509. {vgi_python-0.35.0 → vgi_python-0.36.0}/vgi/_test_fixtures/aggregate/generic.py +0 -0
  510. {vgi_python-0.35.0 → vgi_python-0.36.0}/vgi/_test_fixtures/aggregate/listagg.py +0 -0
  511. {vgi_python-0.35.0 → vgi_python-0.36.0}/vgi/_test_fixtures/aggregate/percentile.py +0 -0
  512. {vgi_python-0.35.0 → vgi_python-0.36.0}/vgi/_test_fixtures/aggregate/same_name.py +0 -0
  513. {vgi_python-0.35.0 → vgi_python-0.36.0}/vgi/_test_fixtures/aggregate/secret_typed.py +0 -0
  514. {vgi_python-0.35.0 → vgi_python-0.36.0}/vgi/_test_fixtures/aggregate/streaming.py +0 -0
  515. {vgi_python-0.35.0 → vgi_python-0.36.0}/vgi/_test_fixtures/aggregate/varargs.py +0 -0
  516. {vgi_python-0.35.0 → vgi_python-0.36.0}/vgi/_test_fixtures/aggregate/window.py +0 -0
  517. {vgi_python-0.35.0 → vgi_python-0.36.0}/vgi/_test_fixtures/attach_options.py +0 -0
  518. {vgi_python-0.35.0 → vgi_python-0.36.0}/vgi/_test_fixtures/bad_enum.py +0 -0
  519. {vgi_python-0.35.0 → vgi_python-0.36.0}/vgi/_test_fixtures/bad_protocol.py +0 -0
  520. {vgi_python-0.35.0 → vgi_python-0.36.0}/vgi/_test_fixtures/cancellable.py +0 -0
  521. {vgi_python-0.35.0 → vgi_python-0.36.0}/vgi/_test_fixtures/catalog.py +0 -0
  522. {vgi_python-0.35.0 → vgi_python-0.36.0}/vgi/_test_fixtures/companion.py +0 -0
  523. {vgi_python-0.35.0 → vgi_python-0.36.0}/vgi/_test_fixtures/copy_from.py +0 -0
  524. {vgi_python-0.35.0 → vgi_python-0.36.0}/vgi/_test_fixtures/copy_to.py +0 -0
  525. {vgi_python-0.35.0 → vgi_python-0.36.0}/vgi/_test_fixtures/global_functions.py +0 -0
  526. {vgi_python-0.35.0 → vgi_python-0.36.0}/vgi/_test_fixtures/http_server.py +0 -0
  527. {vgi_python-0.35.0 → vgi_python-0.36.0}/vgi/_test_fixtures/narrow_bind/__init__.py +0 -0
  528. {vgi_python-0.35.0 → vgi_python-0.36.0}/vgi/_test_fixtures/narrow_bind/worker.py +0 -0
  529. {vgi_python-0.35.0 → vgi_python-0.36.0}/vgi/_test_fixtures/nest_tensor.py +0 -0
  530. {vgi_python-0.35.0 → vgi_python-0.36.0}/vgi/_test_fixtures/orchard_catalog.py +0 -0
  531. {vgi_python-0.35.0 → vgi_python-0.36.0}/vgi/_test_fixtures/projection_repro/__init__.py +0 -0
  532. {vgi_python-0.35.0 → vgi_python-0.36.0}/vgi/_test_fixtures/projection_repro/worker.py +0 -0
  533. {vgi_python-0.35.0 → vgi_python-0.36.0}/vgi/_test_fixtures/scalar/__init__.py +0 -0
  534. {vgi_python-0.35.0 → vgi_python-0.36.0}/vgi/_test_fixtures/scalar/_common.py +0 -0
  535. {vgi_python-0.35.0 → vgi_python-0.36.0}/vgi/_test_fixtures/scalar/arithmetic.py +0 -0
  536. {vgi_python-0.35.0 → vgi_python-0.36.0}/vgi/_test_fixtures/scalar/bench_ladder.py +0 -0
  537. {vgi_python-0.35.0 → vgi_python-0.36.0}/vgi/_test_fixtures/scalar/binary.py +0 -0
  538. {vgi_python-0.35.0 → vgi_python-0.36.0}/vgi/_test_fixtures/scalar/formatting.py +0 -0
  539. {vgi_python-0.35.0 → vgi_python-0.36.0}/vgi/_test_fixtures/scalar/geo.py +0 -0
  540. {vgi_python-0.35.0 → vgi_python-0.36.0}/vgi/_test_fixtures/scalar/null_handling.py +0 -0
  541. {vgi_python-0.35.0 → vgi_python-0.36.0}/vgi/_test_fixtures/scalar/random_demo.py +0 -0
  542. {vgi_python-0.35.0 → vgi_python-0.36.0}/vgi/_test_fixtures/scalar/same_name.py +0 -0
  543. {vgi_python-0.35.0 → vgi_python-0.36.0}/vgi/_test_fixtures/scalar/settings_secrets.py +0 -0
  544. {vgi_python-0.35.0 → vgi_python-0.36.0}/vgi/_test_fixtures/scalar/type_info.py +0 -0
  545. {vgi_python-0.35.0 → vgi_python-0.36.0}/vgi/_test_fixtures/schema_reconcile/__init__.py +0 -0
  546. {vgi_python-0.35.0 → vgi_python-0.36.0}/vgi/_test_fixtures/schema_reconcile/worker.py +0 -0
  547. {vgi_python-0.35.0 → vgi_python-0.36.0}/vgi/_test_fixtures/simple_writable.py +0 -0
  548. {vgi_python-0.35.0 → vgi_python-0.36.0}/vgi/_test_fixtures/table/__init__.py +0 -0
  549. {vgi_python-0.35.0 → vgi_python-0.36.0}/vgi/_test_fixtures/table/_common.py +0 -0
  550. {vgi_python-0.35.0 → vgi_python-0.36.0}/vgi/_test_fixtures/table/batch_index.py +0 -0
  551. {vgi_python-0.35.0 → vgi_python-0.36.0}/vgi/_test_fixtures/table/batch_index_broken.py +0 -0
  552. {vgi_python-0.35.0 → vgi_python-0.36.0}/vgi/_test_fixtures/table/cache.py +0 -0
  553. {vgi_python-0.35.0 → vgi_python-0.36.0}/vgi/_test_fixtures/table/catalog_scans.py +0 -0
  554. {vgi_python-0.35.0 → vgi_python-0.36.0}/vgi/_test_fixtures/table/late_materialization.py +0 -0
  555. {vgi_python-0.35.0 → vgi_python-0.36.0}/vgi/_test_fixtures/table/make_series.py +0 -0
  556. {vgi_python-0.35.0 → vgi_python-0.36.0}/vgi/_test_fixtures/table/misc.py +0 -0
  557. {vgi_python-0.35.0 → vgi_python-0.36.0}/vgi/_test_fixtures/table/order_modes.py +0 -0
  558. {vgi_python-0.35.0 → vgi_python-0.36.0}/vgi/_test_fixtures/table/pairs.py +0 -0
  559. {vgi_python-0.35.0 → vgi_python-0.36.0}/vgi/_test_fixtures/table/partition_columns.py +0 -0
  560. {vgi_python-0.35.0 → vgi_python-0.36.0}/vgi/_test_fixtures/table/partition_columns_broken.py +0 -0
  561. {vgi_python-0.35.0 → vgi_python-0.36.0}/vgi/_test_fixtures/table/profiling_example.py +0 -0
  562. {vgi_python-0.35.0 → vgi_python-0.36.0}/vgi/_test_fixtures/table/required_filters.py +0 -0
  563. {vgi_python-0.35.0 → vgi_python-0.36.0}/vgi/_test_fixtures/table/same_name_cached.py +0 -0
  564. {vgi_python-0.35.0 → vgi_python-0.36.0}/vgi/_test_fixtures/table/same_name_schemas.py +0 -0
  565. {vgi_python-0.35.0 → vgi_python-0.36.0}/vgi/_test_fixtures/table/settings.py +0 -0
  566. {vgi_python-0.35.0 → vgi_python-0.36.0}/vgi/_test_fixtures/table/transaction_storage.py +0 -0
  567. {vgi_python-0.35.0 → vgi_python-0.36.0}/vgi/_test_fixtures/table/tt_pushdown.py +0 -0
  568. {vgi_python-0.35.0 → vgi_python-0.36.0}/vgi/_test_fixtures/table/typed_probe.py +0 -0
  569. {vgi_python-0.35.0 → vgi_python-0.36.0}/vgi/_test_fixtures/table/versioned.py +0 -0
  570. {vgi_python-0.35.0 → vgi_python-0.36.0}/vgi/_test_fixtures/table/wide.py +0 -0
  571. {vgi_python-0.35.0 → vgi_python-0.36.0}/vgi/_test_fixtures/table_in_out.py +0 -0
  572. {vgi_python-0.35.0 → vgi_python-0.36.0}/vgi/_test_fixtures/table_in_out_same_name.py +0 -0
  573. {vgi_python-0.35.0 → vgi_python-0.36.0}/vgi/_test_fixtures/twin_catalogs.py +0 -0
  574. {vgi_python-0.35.0 → vgi_python-0.36.0}/vgi/_test_fixtures/versioned.py +0 -0
  575. {vgi_python-0.35.0 → vgi_python-0.36.0}/vgi/_test_fixtures/versioned_tables.py +0 -0
  576. {vgi_python-0.35.0 → vgi_python-0.36.0}/vgi/_test_fixtures/worker.py +0 -0
  577. {vgi_python-0.35.0 → vgi_python-0.36.0}/vgi/_test_fixtures/writable/__init__.py +0 -0
  578. {vgi_python-0.35.0 → vgi_python-0.36.0}/vgi/_test_fixtures/writable/generic.py +0 -0
  579. {vgi_python-0.35.0 → vgi_python-0.36.0}/vgi/_test_fixtures/writable/table.py +0 -0
  580. {vgi_python-0.35.0 → vgi_python-0.36.0}/vgi/_test_fixtures/writable/worker.py +0 -0
  581. {vgi_python-0.35.0 → vgi_python-0.36.0}/vgi/aggregate_function.py +0 -0
  582. {vgi_python-0.35.0 → vgi_python-0.36.0}/vgi/argument_spec.py +0 -0
  583. {vgi_python-0.35.0 → vgi_python-0.36.0}/vgi/arguments.py +0 -0
  584. {vgi_python-0.35.0 → vgi_python-0.36.0}/vgi/attach_header.py +0 -0
  585. {vgi_python-0.35.0 → vgi_python-0.36.0}/vgi/cache_control.py +0 -0
  586. {vgi_python-0.35.0 → vgi_python-0.36.0}/vgi/catalog/__init__.py +0 -0
  587. {vgi_python-0.35.0 → vgi_python-0.36.0}/vgi/catalog/_descriptor_spec.py +0 -0
  588. {vgi_python-0.35.0 → vgi_python-0.36.0}/vgi/catalog/attach_option.py +0 -0
  589. {vgi_python-0.35.0 → vgi_python-0.36.0}/vgi/catalog/descriptors.py +0 -0
  590. {vgi_python-0.35.0 → vgi_python-0.36.0}/vgi/catalog/duckdb_statistics.py +0 -0
  591. {vgi_python-0.35.0 → vgi_python-0.36.0}/vgi/catalog/secret_type.py +0 -0
  592. {vgi_python-0.35.0 → vgi_python-0.36.0}/vgi/catalog/setting.py +0 -0
  593. {vgi_python-0.35.0 → vgi_python-0.36.0}/vgi/catalog/storage.py +0 -0
  594. {vgi_python-0.35.0 → vgi_python-0.36.0}/vgi/client/__init__.py +0 -0
  595. {vgi_python-0.35.0 → vgi_python-0.36.0}/vgi/client/aggregate.py +0 -0
  596. {vgi_python-0.35.0 → vgi_python-0.36.0}/vgi/client/catalog_mixin.py +0 -0
  597. {vgi_python-0.35.0 → vgi_python-0.36.0}/vgi/client/cli.py +0 -0
  598. {vgi_python-0.35.0 → vgi_python-0.36.0}/vgi/client/cli_catalog.py +0 -0
  599. {vgi_python-0.35.0 → vgi_python-0.36.0}/vgi/client/cli_schema.py +0 -0
  600. {vgi_python-0.35.0 → vgi_python-0.36.0}/vgi/client/cli_table.py +0 -0
  601. {vgi_python-0.35.0 → vgi_python-0.36.0}/vgi/client/cli_transaction.py +0 -0
  602. {vgi_python-0.35.0 → vgi_python-0.36.0}/vgi/client/cli_utils.py +0 -0
  603. {vgi_python-0.35.0 → vgi_python-0.36.0}/vgi/client/cli_view.py +0 -0
  604. {vgi_python-0.35.0 → vgi_python-0.36.0}/vgi/client/errors.py +0 -0
  605. {vgi_python-0.35.0 → vgi_python-0.36.0}/vgi/codegen/__init__.py +0 -0
  606. {vgi_python-0.35.0 → vgi_python-0.36.0}/vgi/codegen/_common.py +0 -0
  607. {vgi_python-0.35.0 → vgi_python-0.36.0}/vgi/codegen/cpp_constants.py +0 -0
  608. {vgi_python-0.35.0 → vgi_python-0.36.0}/vgi/codegen/cpp_protocol_name.py +0 -0
  609. {vgi_python-0.35.0 → vgi_python-0.36.0}/vgi/codegen/cpp_protocol_version.py +0 -0
  610. {vgi_python-0.35.0 → vgi_python-0.36.0}/vgi/codegen/cpp_request_builders.py +0 -0
  611. {vgi_python-0.35.0 → vgi_python-0.36.0}/vgi/codegen/cpp_schemas.py +0 -0
  612. {vgi_python-0.35.0 → vgi_python-0.36.0}/vgi/codegen/cpp_secret_protocol_version.py +0 -0
  613. {vgi_python-0.35.0 → vgi_python-0.36.0}/vgi/codegen/cpp_secret_request_builders.py +0 -0
  614. {vgi_python-0.35.0 → vgi_python-0.36.0}/vgi/codegen/cpp_secret_schemas.py +0 -0
  615. {vgi_python-0.35.0 → vgi_python-0.36.0}/vgi/codegen/go_schemas.py +0 -0
  616. {vgi_python-0.35.0 → vgi_python-0.36.0}/vgi/codegen/java_schemas.py +0 -0
  617. {vgi_python-0.35.0 → vgi_python-0.36.0}/vgi/codegen/protocol_version.py +0 -0
  618. {vgi_python-0.35.0 → vgi_python-0.36.0}/vgi/codegen/rust_request_builders.py +0 -0
  619. {vgi_python-0.35.0 → vgi_python-0.36.0}/vgi/codegen/rust_schemas.py +0 -0
  620. {vgi_python-0.35.0 → vgi_python-0.36.0}/vgi/codegen/ts_client.py +0 -0
  621. {vgi_python-0.35.0 → vgi_python-0.36.0}/vgi/codegen/ts_schemas.py +0 -0
  622. {vgi_python-0.35.0 → vgi_python-0.36.0}/vgi/copy_from_function.py +0 -0
  623. {vgi_python-0.35.0 → vgi_python-0.36.0}/vgi/copy_to_function.py +0 -0
  624. {vgi_python-0.35.0 → vgi_python-0.36.0}/vgi/exceptions.py +0 -0
  625. {vgi_python-0.35.0 → vgi_python-0.36.0}/vgi/filter_v2_builder.py +0 -0
  626. {vgi_python-0.35.0 → vgi_python-0.36.0}/vgi/function.py +0 -0
  627. {vgi_python-0.35.0 → vgi_python-0.36.0}/vgi/function_storage.py +0 -0
  628. {vgi_python-0.35.0 → vgi_python-0.36.0}/vgi/function_storage_azure_sql.py +0 -0
  629. {vgi_python-0.35.0 → vgi_python-0.36.0}/vgi/function_storage_cf_do.py +0 -0
  630. {vgi_python-0.35.0 → vgi_python-0.36.0}/vgi/http/__init__.py +0 -0
  631. {vgi_python-0.35.0 → vgi_python-0.36.0}/vgi/http/demo_storage.py +0 -0
  632. {vgi_python-0.35.0 → vgi_python-0.36.0}/vgi/http/landing.html +0 -0
  633. {vgi_python-0.35.0 → vgi_python-0.36.0}/vgi/http/landing_page.py +0 -0
  634. {vgi_python-0.35.0 → vgi_python-0.36.0}/vgi/http/vgi-client.js +0 -0
  635. {vgi_python-0.35.0 → vgi_python-0.36.0}/vgi/http/worker_page.py +0 -0
  636. {vgi_python-0.35.0 → vgi_python-0.36.0}/vgi/invocation.py +0 -0
  637. {vgi_python-0.35.0 → vgi_python-0.36.0}/vgi/logging_config.py +0 -0
  638. {vgi_python-0.35.0 → vgi_python-0.36.0}/vgi/meta_worker.py +0 -0
  639. {vgi_python-0.35.0 → vgi_python-0.36.0}/vgi/metadata.py +0 -0
  640. {vgi_python-0.35.0 → vgi_python-0.36.0}/vgi/otel.py +0 -0
  641. {vgi_python-0.35.0 → vgi_python-0.36.0}/vgi/profiling.py +0 -0
  642. {vgi_python-0.35.0 → vgi_python-0.36.0}/vgi/protocol_version.txt +0 -0
  643. {vgi_python-0.35.0 → vgi_python-0.36.0}/vgi/py.typed +0 -0
  644. {vgi_python-0.35.0 → vgi_python-0.36.0}/vgi/schema_path.py +0 -0
  645. {vgi_python-0.35.0 → vgi_python-0.36.0}/vgi/schema_utils.py +0 -0
  646. {vgi_python-0.35.0 → vgi_python-0.36.0}/vgi/secret_protocol.py +0 -0
  647. {vgi_python-0.35.0 → vgi_python-0.36.0}/vgi/secret_service.py +0 -0
  648. {vgi_python-0.35.0 → vgi_python-0.36.0}/vgi/serve.py +0 -0
  649. {vgi_python-0.35.0 → vgi_python-0.36.0}/vgi/split_token.py +0 -0
  650. {vgi_python-0.35.0 → vgi_python-0.36.0}/vgi/table_buffering_function.py +0 -0
  651. {vgi_python-0.35.0 → vgi_python-0.36.0}/vgi/table_function.py +0 -0
  652. {vgi_python-0.35.0 → vgi_python-0.36.0}/vgi/table_in_out_function.py +0 -0
  653. {vgi_python-0.35.0 → vgi_python-0.36.0}/vgi/transactor/__init__.py +0 -0
  654. {vgi_python-0.35.0 → vgi_python-0.36.0}/vgi/transactor/_duckdb_compat.py +0 -0
  655. {vgi_python-0.35.0 → vgi_python-0.36.0}/vgi/transactor/client.py +0 -0
  656. {vgi_python-0.35.0 → vgi_python-0.36.0}/vgi/transactor/protocol.py +0 -0
  657. {vgi_python-0.35.0 → vgi_python-0.36.0}/vgi/transactor/server.py +0 -0
  658. {vgi_python-0.35.0 → vgi_python-0.36.0}/vgi/worker.py +0 -0
  659. {vgi_python-0.35.0 → vgi_python-0.36.0}/vgi/write_results.py +0 -0
  660. {vgi_python-0.35.0 → vgi_python-0.36.0}/wrangler.jsonc +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: vgi-python
3
- Version: 0.35.0
3
+ Version: 0.36.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
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "vgi-python"
3
- version = "0.35.0"
3
+ version = "0.36.0"
4
4
  description = "Vector Gateway Interface - Connect DuckDB to external programs via Apache Arrow"
5
5
  readme = "README.md"
6
6
  keywords = [
@@ -223,7 +223,12 @@ warn_unused_ignores = false
223
223
  python-version = "3.13"
224
224
 
225
225
  [tool.pytest.ini_options]
226
- addopts = "--ruff"
226
+ # worksteal: xdist's default "load" hands each worker a contiguous slice of the
227
+ # collection up front, so tests/catalog/test_integration.py (30 tests that each
228
+ # start a fresh catalog worker process, ~0.7 s apiece) all landed on one xdist
229
+ # worker, which then ran for 20 s after the rest had finished. worksteal lets
230
+ # idle workers take queued tests from busy ones. Ignored without -n.
231
+ addopts = "--ruff --dist worksteal"
227
232
  testpaths = ["tests"]
228
233
 
229
234
  [tool.coverage.run]
@@ -26,8 +26,11 @@ import pytest
26
26
  from vgi.arguments import Arguments
27
27
  from vgi.client.client import Client, _default_pool
28
28
 
29
- # Long enough that a graceful teardown would have to wait on it if the worker were stuck.
30
- _SLEEP_MS = 5_000
29
+ # How long the worker sleeps before each row. The first row alone costs this
30
+ # much, so it is kept short; the forced stop is held to half of it (see
31
+ # test_force_returns_promptly_mid_stream), which a teardown that waited out the
32
+ # sleep would miss by a wide margin, and a kill (milliseconds) clears.
33
+ _SLEEP_MS = 2_000
31
34
 
32
35
 
33
36
  def _started_client(**kwargs: Any) -> Client:
@@ -65,10 +68,13 @@ def test_force_returns_promptly_mid_stream(tmp_path: Any) -> None:
65
68
  )
66
69
  next(gen) # worker is now mid-stream, sleeping between batches
67
70
 
71
+ # The client's reader thread asks for the next row as soon as it has the
72
+ # first, so the worker is now inside that row's sleep. A stop that waited
73
+ # it out would take nearly the whole sleep; hold the kill to half of it.
68
74
  started = time.monotonic()
69
75
  client.stop(force=True)
70
76
  elapsed = time.monotonic() - started
71
- assert elapsed < _SLEEP_MS / 1000.0, f"forced stop waited {elapsed:.2f}s on a sleeping worker"
77
+ assert elapsed < _SLEEP_MS / 2000.0, f"forced stop waited {elapsed:.2f}s on a sleeping worker"
72
78
 
73
79
 
74
80
  def test_graceful_stop_is_unchanged() -> None:
@@ -2,19 +2,29 @@
2
2
 
3
3
  """Shared fixtures for VGI tests."""
4
4
 
5
+ import contextlib
5
6
  import logging
6
7
  import os
7
8
  import shlex
8
9
  import shutil
9
10
  import subprocess
10
11
  import sys
12
+ import threading
11
13
  import uuid
12
14
  from typing import Any
13
15
 
14
- import pyarrow as pa
15
- import pytest
16
+ # pyarrow imports numpy, and numpy's OpenBLAS starts one thread per core at
17
+ # import and busy-waits them: about 2.7 CPU-seconds per process on a 48-core
18
+ # machine. No test does linear algebra. This module is loaded before xdist
19
+ # starts its workers, so every process of the session inherits the setting:
20
+ # xdist workers, fixture and example workers, HTTP servers, CLI runs. On
21
+ # 48 cores it cut the suite's CPU time from 363 s to 208 s.
22
+ os.environ.setdefault("OPENBLAS_NUM_THREADS", "1")
16
23
 
17
- from vgi import schema
24
+ import pyarrow as pa # noqa: E402
25
+ import pytest # noqa: E402
26
+
27
+ from vgi import schema # noqa: E402
18
28
 
19
29
  # =============================================================================
20
30
  # Fixture-worker transport
@@ -66,6 +76,38 @@ CATALOG_WORKER = _fixture_command(sys.executable, "-m", "vgi._test_fixtures.cata
66
76
  SUBPROCESS_FIXTURE_WORKER = "vgi-fixture-worker"
67
77
 
68
78
 
79
+ def pytest_configure(config: pytest.Config) -> None:
80
+ """Start the shared fixture worker while the test processes collect.
81
+
82
+ Otherwise the first tests to reach it all wait for its start (about a
83
+ second of imports) and then for the first function listings, which build
84
+ and encode every function's metadata before it is cached; each costs
85
+ the one GIL-bound worker 0.2-0.3 s, and the early tests run them all at
86
+ once. Collection takes several seconds, so warming the worker in the
87
+ background here costs nothing. Only the controlling process does it.
88
+ """
89
+ if hasattr(config, "workerinput") or TEST_TRANSPORT != "launch":
90
+ return
91
+ threading.Thread(target=_warm_fixture_worker, name="warm-fixture-worker", daemon=True).start()
92
+
93
+
94
+ def _warm_fixture_worker() -> None:
95
+ """Launch the fixture worker and fill its function-listing caches."""
96
+ from vgi.catalog import SchemaObjectType
97
+ from vgi.client import Client
98
+
99
+ # Best effort: a worker that cannot start fails the tests that use it, with
100
+ # the real error.
101
+ with contextlib.suppress(Exception), Client(FIXTURE_WORKER) as client:
102
+ attach = client.catalog_attach(name="example", options={}, data_version_spec=None, implementation_version=None)
103
+ for kind in (
104
+ SchemaObjectType.TABLE_FUNCTION,
105
+ SchemaObjectType.SCALAR_FUNCTION,
106
+ SchemaObjectType.AGGREGATE_FUNCTION,
107
+ ):
108
+ list(client.schema_contents(attach_opaque_data=attach.attach_opaque_data, path=["main"], type=kind))
109
+
110
+
69
111
  def pytest_unconfigure(config: pytest.Config) -> None:
70
112
  """Stop this session's launched workers rather than leaving them to idle out.
71
113
 
@@ -132,6 +174,24 @@ def empty_batch_from_schema(schema: pa.Schema) -> pa.RecordBatch:
132
174
  return pa.RecordBatch.from_pydict({field.name: [] for field in schema}, schema=schema)
133
175
 
134
176
 
177
+ def record_opened_connections(client: Any) -> list[int]:
178
+ """Record the index of each worker connection a started ``client`` opens from now on.
179
+
180
+ The primary connection (index 0) is opened when the client starts, so call
181
+ this afterwards: the list then holds only secondary connections, which a
182
+ call opens for fan-out. Only records; each connection is opened for real.
183
+ """
184
+ opened: list[int] = []
185
+ spawn = client._spawn_worker
186
+
187
+ def recording_spawn(worker_index: int) -> Any:
188
+ opened.append(worker_index)
189
+ return spawn(worker_index)
190
+
191
+ client._spawn_worker = recording_spawn
192
+ return opened
193
+
194
+
135
195
  # =============================================================================
136
196
  # Fixtures
137
197
  # =============================================================================
@@ -4,12 +4,13 @@
4
4
 
5
5
  from __future__ import annotations
6
6
 
7
+ import os
7
8
  from typing import cast
8
9
 
9
10
  import pyarrow as pa
10
11
  import pytest
11
12
 
12
- from tests.conftest import assert_total_rows
13
+ from tests.conftest import assert_total_rows, record_opened_connections
13
14
  from vgi import schema
14
15
  from vgi.arguments import Arguments
15
16
  from vgi.client import Client
@@ -388,6 +389,7 @@ class TestScalarFunctionParallel:
388
389
  batches = [pa.RecordBatch.from_pydict({"x": list(range(i * 100, (i + 1) * 100))}, schema=s) for i in range(10)]
389
390
 
390
391
  with Client(fixture_worker, worker_limit=4) as client:
392
+ opened = record_opened_connections(client)
391
393
  outputs = list(
392
394
  client.scalar_function(
393
395
  function_name="double",
@@ -397,6 +399,11 @@ class TestScalarFunctionParallel:
397
399
  )
398
400
  )
399
401
 
402
+ # Ten batches dealt round-robin reach every connection the client
403
+ # allows: four, or one per core on a smaller machine (GitHub's macOS
404
+ # runners have three).
405
+ assert opened == list(range(1, min(4, os.cpu_count() or 1)))
406
+
400
407
  # Should get all 1000 rows back
401
408
  assert_total_rows(outputs, 1000)
402
409
 
@@ -675,9 +682,12 @@ class TestRandomIntFunction:
675
682
  class TestScalarMultiWorkerEdgeCases:
676
683
  """Tests for edge cases with multiple workers for scalar functions.
677
684
 
678
- These tests expose timeout/hang bugs when:
685
+ These tests exposed timeout/hang bugs when:
679
686
  - Processing parquet with one batch of zero rows
680
- - Additional workers spawned but don't receive batches
687
+ - Additional workers were spawned but received no batches
688
+
689
+ The client now opens a secondary connection only when a batch is dealt to
690
+ it, so no connection sits idle. The tests check that too.
681
691
  """
682
692
 
683
693
  def test_zero_row_batch_single_worker(self, fixture_worker: str) -> None:
@@ -704,8 +714,9 @@ class TestScalarMultiWorkerEdgeCases:
704
714
  s = schema(x=pa.int64())
705
715
  zero_row_batch = pa.RecordBatch.from_pydict({"x": []}, schema=s)
706
716
 
707
- # Force 4 workers even though there's only one batch with zero rows
717
+ # Allow 4 workers even though there's only one batch with zero rows
708
718
  with Client(fixture_worker, worker_limit=4) as client:
719
+ opened = record_opened_connections(client)
709
720
  outputs = list(
710
721
  client.scalar_function(
711
722
  function_name="double",
@@ -715,17 +726,19 @@ class TestScalarMultiWorkerEdgeCases:
715
726
  )
716
727
  )
717
728
 
718
- # Should complete without hanging
729
+ # Should complete without hanging, on the primary alone
719
730
  assert len(outputs) == 1
720
731
  assert outputs[0].num_rows == 0
732
+ assert opened == []
721
733
 
722
734
  def test_single_batch_multiple_workers(self, fixture_worker: str) -> None:
723
735
  """Single normal batch with max_workers=4 should complete without hanging."""
724
736
  s = schema(x=pa.int64())
725
737
  single_batch = pa.RecordBatch.from_pydict({"x": [1, 2, 3]}, schema=s)
726
738
 
727
- # Force 4 workers even though there's only 1 batch
739
+ # Allow 4 workers even though there's only 1 batch
728
740
  with Client(fixture_worker, worker_limit=4) as client:
741
+ opened = record_opened_connections(client)
729
742
  outputs = list(
730
743
  client.scalar_function(
731
744
  function_name="double",
@@ -737,6 +750,7 @@ class TestScalarMultiWorkerEdgeCases:
737
750
 
738
751
  # Should complete without hanging and return correct data
739
752
  assert_total_rows(outputs, 3)
753
+ assert opened == []
740
754
 
741
755
  def test_fewer_batches_than_workers(self, fixture_worker: str) -> None:
742
756
  """2 batches with max_workers=4 should complete without hanging."""
@@ -744,8 +758,9 @@ class TestScalarMultiWorkerEdgeCases:
744
758
  batch1 = pa.RecordBatch.from_pydict({"x": [1, 2]}, schema=s)
745
759
  batch2 = pa.RecordBatch.from_pydict({"x": [3, 4, 5]}, schema=s)
746
760
 
747
- # Force 4 workers even though there are only 2 batches
761
+ # Allow 4 workers even though there are only 2 batches
748
762
  with Client(fixture_worker, worker_limit=4) as client:
763
+ opened = record_opened_connections(client)
749
764
  outputs = list(
750
765
  client.scalar_function(
751
766
  function_name="double",
@@ -757,3 +772,5 @@ class TestScalarMultiWorkerEdgeCases:
757
772
 
758
773
  # Should complete without hanging and return correct data (5 rows total)
759
774
  assert_total_rows(outputs, 5)
775
+ # The second batch opened the one secondary connection it needed.
776
+ assert opened == [1]
@@ -10,7 +10,13 @@ import time
10
10
  import pyarrow as pa
11
11
  import pytest
12
12
 
13
- from tests.conftest import SUBPROCESS_FIXTURE_WORKER, assert_single_result, assert_total_rows, make_schema
13
+ from tests.conftest import (
14
+ SUBPROCESS_FIXTURE_WORKER,
15
+ assert_single_result,
16
+ assert_total_rows,
17
+ make_schema,
18
+ record_opened_connections,
19
+ )
14
20
  from vgi.client import Client
15
21
  from vgi.client.client import ClientError
16
22
 
@@ -146,9 +152,12 @@ class TestEdgeCases:
146
152
  class TestMultiWorkerEdgeCases:
147
153
  """Tests for edge cases with multiple workers.
148
154
 
149
- These tests expose timeout/hang bugs when:
155
+ These tests exposed timeout/hang bugs when:
150
156
  - Processing parquet with one batch of zero rows
151
- - Additional workers spawned but don't receive batches
157
+ - Additional workers were spawned but received no batches
158
+
159
+ The client now opens a secondary connection only when a batch is dealt to
160
+ it, so no connection sits idle. The tests check that too.
152
161
  """
153
162
 
154
163
  def test_zero_row_batch_single_worker(self, fixture_worker: str) -> None:
@@ -174,8 +183,9 @@ class TestMultiWorkerEdgeCases:
174
183
  schema = make_schema([pa.field("id", pa.int64()), pa.field("value", pa.int64())])
175
184
  zero_row_batch = pa.RecordBatch.from_pydict({"id": [], "value": []}, schema=schema)
176
185
 
177
- # Force 4 workers even though there's only one batch with zero rows
186
+ # Allow 4 workers even though there's only one batch with zero rows
178
187
  with Client(fixture_worker, worker_limit=4) as client:
188
+ opened = record_opened_connections(client)
179
189
  output_batches = list(
180
190
  client.table_in_out_function(
181
191
  function_name="echo",
@@ -184,17 +194,19 @@ class TestMultiWorkerEdgeCases:
184
194
  )
185
195
  )
186
196
 
187
- # Should complete without hanging
197
+ # Should complete without hanging, on the primary alone
188
198
  assert len(output_batches) >= 1
189
199
  assert_total_rows(output_batches, 0)
200
+ assert opened == []
190
201
 
191
202
  def test_single_batch_multiple_workers(self, fixture_worker: str) -> None:
192
203
  """Single normal batch with max_workers=4 should complete without hanging."""
193
204
  schema = make_schema([pa.field("id", pa.int64()), pa.field("value", pa.int64())])
194
205
  single_batch = pa.RecordBatch.from_pydict({"id": [1, 2, 3], "value": [10, 20, 30]}, schema=schema)
195
206
 
196
- # Force 4 workers even though there's only 1 batch
207
+ # Allow 4 workers even though there's only 1 batch
197
208
  with Client(fixture_worker, worker_limit=4) as client:
209
+ opened = record_opened_connections(client)
198
210
  output_batches = list(
199
211
  client.table_in_out_function(
200
212
  function_name="echo",
@@ -205,6 +217,7 @@ class TestMultiWorkerEdgeCases:
205
217
 
206
218
  # Should complete without hanging and return correct data
207
219
  assert_total_rows(output_batches, 3)
220
+ assert opened == []
208
221
 
209
222
  def test_fewer_batches_than_workers(self, fixture_worker: str) -> None:
210
223
  """2 batches with max_workers=4 should complete without hanging."""
@@ -212,8 +225,9 @@ class TestMultiWorkerEdgeCases:
212
225
  batch1 = pa.RecordBatch.from_pydict({"id": [1, 2], "value": [10, 20]}, schema=schema)
213
226
  batch2 = pa.RecordBatch.from_pydict({"id": [3, 4, 5], "value": [30, 40, 50]}, schema=schema)
214
227
 
215
- # Force 4 workers even though there are only 2 batches
228
+ # Allow 4 workers even though there are only 2 batches
216
229
  with Client(fixture_worker, worker_limit=4) as client:
230
+ opened = record_opened_connections(client)
217
231
  output_batches = list(
218
232
  client.table_in_out_function(
219
233
  function_name="echo",
@@ -224,6 +238,8 @@ class TestMultiWorkerEdgeCases:
224
238
 
225
239
  # Should complete without hanging and return correct data (5 rows total)
226
240
  assert_total_rows(output_batches, 5)
241
+ # The second batch opened the one secondary connection it needed.
242
+ assert opened == [1]
227
243
 
228
244
 
229
245
  class TestWorkerStderrCapture:
@@ -0,0 +1,199 @@
1
+ # Copyright 2026 Query Farm LLC - https://query.farm
2
+
3
+ """Dynamic-filter state across HTTP turns: bounded replay, exact reconstruction.
4
+
5
+ An HTTP producer rebuilds its filters from the call and cursor tokens on every
6
+ turn. The cursor used to carry every tick's delta and replay all of them, each
7
+ re-validated through the embedded DuckDB evaluator, so turn ``k`` did ``k``
8
+ parses: a 100-batch Top-N scan spent ~20 s there. These tests drive the real
9
+ ``dynamic_filter_echo`` fixture through the real HTTP stack, playing the client
10
+ (the requests are hand-built; every response is the worker's), and pin both
11
+ halves of the fix: a turn's parse work stays constant as ticks accumulate, and
12
+ the state rebuilt from the compacted history is the state the worker had.
13
+ """
14
+
15
+ from __future__ import annotations
16
+
17
+ import base64
18
+ import contextlib
19
+ import json
20
+ from collections.abc import Iterator
21
+ from typing import Any
22
+
23
+ import pyarrow as pa
24
+ import pytest
25
+ from vgi_rpc.rpc import RpcServer
26
+
27
+ from vgi import filter_v2
28
+ from vgi._test_fixtures.worker import ExampleWorker
29
+ from vgi.arguments import Arguments
30
+ from vgi.invocation import FunctionType
31
+ from vgi.protocol import BindRequest, InitRequest, VgiProtocol
32
+
33
+ _KEY = b"\x5a" * 32
34
+ _METADATA: dict[bytes | str, bytes | str] = {
35
+ b"vgi_filter_encoding": b"vgi.filters.v2",
36
+ b"vgi_filter_version": b"2",
37
+ b"vgi_evaluation_context": b"vgi.none.v1",
38
+ }
39
+
40
+
41
+ def _document_batch(document: dict[str, object], *values: int) -> pa.RecordBatch:
42
+ fields: list[pa.Field[Any]] = [pa.field("filter_spec", pa.string(), nullable=False)]
43
+ arrays: list[pa.Array[Any]] = [pa.array([json.dumps(document, separators=(",", ":"))])]
44
+ for index, value in enumerate(values):
45
+ fields.append(pa.field(f"value_{index}", pa.int64()))
46
+ arrays.append(pa.array([value], type=pa.int64()))
47
+ return pa.RecordBatch.from_arrays(arrays, schema=pa.schema(fields, metadata=_METADATA))
48
+
49
+
50
+ def _empty_snapshot() -> pa.RecordBatch:
51
+ return _document_batch(
52
+ {"encoding": "vgi.filters.v2", "semantics": "vgi.duckdb.standard.v1", "kind": "snapshot", "predicates": []}
53
+ )
54
+
55
+
56
+ def _upsert(predicate_id: str, revision: int, op: str, value_ref: int) -> dict[str, object]:
57
+ return {
58
+ "operation": "upsert",
59
+ "id": predicate_id,
60
+ "revision": revision,
61
+ "mode": "advisory",
62
+ "source": "top_n",
63
+ "expression": {
64
+ "node": "comparison",
65
+ "op": op,
66
+ "left": {"node": "column_ref", "column_index": 0, "column_name": "n"},
67
+ "right": {"node": "literal", "value_ref": value_ref},
68
+ },
69
+ }
70
+
71
+
72
+ def _remove(predicate_id: str, revision: int) -> dict[str, object]:
73
+ return {"operation": "remove", "id": predicate_id, "revision": revision}
74
+
75
+
76
+ def _tick(updates: list[dict[str, object]], *values: int) -> pa.KeyValueMetadata:
77
+ """Tick metadata carrying one delta, framed the way the C++ client frames it."""
78
+ batch = _document_batch(
79
+ {"encoding": "vgi.filters.v2", "semantics": "vgi.duckdb.standard.v1", "kind": "delta", "updates": updates},
80
+ *values,
81
+ )
82
+ sink = pa.BufferOutputStream()
83
+ with pa.ipc.new_stream(sink, batch.schema) as writer:
84
+ writer.write_batch(batch)
85
+ return pa.KeyValueMetadata({b"vgi_pushdown_filters": base64.b64encode(sink.getvalue().to_pybytes())})
86
+
87
+
88
+ @contextlib.contextmanager
89
+ def _echo_stream(count: int, batch_size: int) -> Iterator[Any]:
90
+ """Open a ``dynamic_filter_echo`` scan over the in-process HTTP stack."""
91
+ from vgi_rpc.http import http_connect, make_sync_client
92
+
93
+ worker = ExampleWorker(quiet=True)
94
+ worker._signing_key = _KEY
95
+ client = make_sync_client(RpcServer(VgiProtocol, worker, enable_describe=False), token_key=_KEY)
96
+ bind = BindRequest(
97
+ function_name="dynamic_filter_echo",
98
+ arguments=Arguments(positional=(pa.scalar(count),), named={"batch_size": pa.scalar(batch_size)}),
99
+ function_type=FunctionType.TABLE,
100
+ input_schema=None,
101
+ )
102
+ with http_connect(VgiProtocol, client=client, compression_level=None) as proxy: # type: ignore[type-abstract]
103
+ resp = proxy.bind(request=bind)
104
+ stream = proxy.init(
105
+ request=InitRequest(
106
+ bind_call=bind,
107
+ output_schema=resp.output_schema,
108
+ bind_opaque_data=resp.opaque_data,
109
+ pushdown_filters=_empty_snapshot(),
110
+ )
111
+ )
112
+ try:
113
+ yield stream
114
+ finally:
115
+ stream.close()
116
+
117
+
118
+ @pytest.fixture
119
+ def parse_count(monkeypatch: pytest.MonkeyPatch) -> list[int]:
120
+ """Count delta documents the worker parses (a spy: it records, never answers)."""
121
+ calls = [0]
122
+ original = filter_v2._Parser.parse_delta
123
+
124
+ def counting(self: Any) -> Any:
125
+ calls[0] += 1
126
+ return original(self)
127
+
128
+ monkeypatch.setattr(filter_v2._Parser, "parse_delta", counting)
129
+ return calls
130
+
131
+
132
+ def test_a_turn_parses_a_bounded_number_of_deltas(parse_count: list[int]) -> None:
133
+ """A tightening Top-N bound sends a delta every tick; no turn replays them all.
134
+
135
+ Rows descend from 999 in batches of 10 and each tick narrows ``n < bound``,
136
+ so every tick's delta changes the live predicate -- the case the C++ client
137
+ cannot skip. Before compaction turn ``k`` parsed ``k`` deltas.
138
+ """
139
+ ticks = 60
140
+ with _echo_stream(count=1000, batch_size=10) as stream:
141
+ first = stream.tick() # the init turn's batch; metadata rides continuations only
142
+ assert first.batch.num_rows == 10
143
+ per_turn: list[int] = []
144
+ for revision in range(1, ticks + 1):
145
+ bound = 1000 - 10 * revision # rows of this tick are [bound - 10, bound - 1]
146
+ before = parse_count[0]
147
+ batch = stream.tick(_tick([_upsert("top_n:0", revision, "lt", 0)], bound)).batch
148
+ per_turn.append(parse_count[0] - before)
149
+ assert batch.column("n").to_pylist() == list(range(bound - 1, bound - 11, -1))
150
+ assert batch.column("pushed_filters")[0].as_py().count("ConstantFilter(n < ") == 1
151
+ assert f"ConstantFilter(n < {bound})" in batch.column("pushed_filters")[0].as_py()
152
+
153
+ # One parse for the new delta, one to replay the single delta the cursor keeps.
154
+ assert max(per_turn) <= 2, per_turn
155
+
156
+
157
+ def test_a_resent_revision_is_stale_and_adds_no_replay(parse_count: list[int]) -> None:
158
+ """Resending a revision with another value is a stale no-op: nothing applies, nothing accumulates."""
159
+ with _echo_stream(count=1000, batch_size=10) as stream:
160
+ stream.tick()
161
+ stream.tick(_tick([_upsert("top_n:0", 1, "lt", 0)], 100000))
162
+ before = parse_count[0]
163
+ for _ in range(20):
164
+ batch = stream.tick(_tick([_upsert("top_n:0", 1, "lt", 0)], 5)).batch
165
+ assert batch.num_rows == 10 # n < 5 would have emptied it
166
+ assert "ConstantFilter(n < 100000)" in batch.column("pushed_filters")[0].as_py()
167
+ assert parse_count[0] - before <= 2 * 20
168
+
169
+
170
+ def test_rebuilt_state_keeps_the_order_the_worker_had() -> None:
171
+ """A removed-then-re-added predicate keeps its position across a turn boundary.
172
+
173
+ Deltas: {a:1, b:1} -> [a, b]; {remove a:2, b:1} -> [b]; {a:3, b:1} -> [b, a].
174
+ The compacted history is the deltas that first carried a:3 and b:1 -- the
175
+ third and the first -- and replaying those alone yields [a, b]. The turn
176
+ after the third delta has to show the order the third turn itself had.
177
+ """
178
+ with _echo_stream(count=1000, batch_size=10) as stream:
179
+ stream.tick()
180
+ stream.tick(_tick([_upsert("top_n:0", 1, "lt", 0), _upsert("top_n:1", 1, "gt", 1)], 100000, 5))
181
+ stream.tick(_tick([_remove("top_n:0", 2), _upsert("top_n:1", 1, "gt", 0)], 5))
182
+ applied = stream.tick(_tick([_upsert("top_n:0", 3, "lt", 0), _upsert("top_n:1", 1, "gt", 1)], 99999, 5)).batch
183
+ rebuilt = stream.tick().batch # no delta: filters come purely from the tokens
184
+ assert applied.num_rows == rebuilt.num_rows == 10
185
+ live = applied.column("pushed_filters")[0].as_py()
186
+ assert live.index("ConstantFilter(n > 5)") < live.index("ConstantFilter(n < 99999)"), live
187
+ assert rebuilt.column("pushed_filters")[0].as_py() == live
188
+
189
+
190
+ def test_a_tombstone_survives_compaction() -> None:
191
+ """A removal stays in force after its upsert is compacted away: a stale upsert cannot resurrect it."""
192
+ with _echo_stream(count=1000, batch_size=10) as stream:
193
+ stream.tick()
194
+ stream.tick(_tick([_upsert("top_n:0", 1, "lt", 0)], 100000))
195
+ stream.tick(_tick([_remove("top_n:0", 2)]))
196
+ stream.tick() # a turn rebuilt from the compacted tokens
197
+ stale = stream.tick(_tick([_upsert("top_n:0", 1, "lt", 0)], 5)).batch
198
+ assert stale.column("pushed_filters")[0].as_py() == "(none)"
199
+ assert stale.num_rows == 10
@@ -2580,7 +2580,7 @@ requires-dist = [
2580
2580
 
2581
2581
  [[package]]
2582
2582
  name = "vgi-python"
2583
- version = "0.35.0"
2583
+ version = "0.36.0"
2584
2584
  source = { editable = "." }
2585
2585
  dependencies = [
2586
2586
  { name = "click" },
@@ -1003,7 +1003,10 @@ class FilterEchoPartitionedFunction(TableFunctionGenerator[_FilterEchoPartitione
1003
1003
  end_idx = min(start_idx + chunk, params.args.count)
1004
1004
  work_items.append(struct.pack(">QQ", start_idx, end_idx))
1005
1005
  params.storage.queue_push(work_items)
1006
- return GlobalInitResponse()
1006
+ # No more readers than work items. Left at the default (unbounded) the
1007
+ # client opens one stream per DuckDB thread -- 48 on a 48-core host for at
1008
+ # most MAX_PARTITIONS items, every extra one an init plus an empty drain.
1009
+ return GlobalInitResponse(max_workers=max(1, len(work_items)))
1007
1010
 
1008
1011
  @classmethod
1009
1012
  def initial_state(cls, params: ProcessParams[_FilterEchoPartitionedArgs]) -> _FilterEchoPartitionedState:
@@ -516,7 +516,10 @@ class PartitionedSequenceFunction(
516
516
 
517
517
  # Always enqueue (even if empty) to register the invocation
518
518
  params.storage.queue_push(work_items)
519
- return GlobalInitResponse()
519
+ # No more readers than work items. Left at the default (unbounded) the
520
+ # client opens one stream per DuckDB thread -- 48 on a 48-core host for at
521
+ # most MAX_PARTITIONS items, every extra one an init plus an empty drain.
522
+ return GlobalInitResponse(max_workers=max(1, len(work_items)))
520
523
 
521
524
  @classmethod
522
525
  def initial_state(cls, params: ProcessParams[PartitionedSequenceFunctionArguments]) -> PartitionedSequenceState:
@@ -35,6 +35,7 @@ from vgi_rpc.rpc import OutputCollector
35
35
 
36
36
  from vgi.arguments import Arg
37
37
  from vgi.cache_control import CacheControl
38
+ from vgi.filter_v2 import replaying_accepted_state
38
39
  from vgi.metadata import FunctionExample, PartitionKind
39
40
  from vgi.protocol import PlanResponse, ScanSplit, VgiOutputCollector
40
41
  from vgi.schema_utils import partition_field, schema
@@ -1055,11 +1056,15 @@ class SplitDynamicFilterFunction(TableFunctionGenerator[SplitSequenceArgs, Split
1055
1056
  init = params.init_call
1056
1057
  merged = None
1057
1058
  if init is not None and init.pushdown_filters is not None:
1058
- merged = cls.pushdown_filters(
1059
- init.pushdown_filters,
1060
- join_keys=init.join_keys,
1061
- output_schema=init.output_schema,
1062
- )
1059
+ # The framework validated these at init; re-binding every
1060
+ # predicate through the evaluator on every tick is what made
1061
+ # this fixture cost ~10 ms a batch.
1062
+ with replaying_accepted_state():
1063
+ merged = cls.pushdown_filters(
1064
+ init.pushdown_filters,
1065
+ join_keys=init.join_keys,
1066
+ output_schema=init.output_schema,
1067
+ )
1063
1068
  if merged is None:
1064
1069
  merged = params.current_pushdown_filters
1065
1070
  filter_str = _render_filters_canonical(merged)