vgi-python 0.8.0__py3-none-any.whl

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 (124) hide show
  1. vgi/__init__.py +152 -0
  2. vgi/_duckdb.py +62 -0
  3. vgi/_storage_profile.py +132 -0
  4. vgi/_test_fixtures/__init__.py +20 -0
  5. vgi/_test_fixtures/accumulate/__init__.py +19 -0
  6. vgi/_test_fixtures/accumulate/worker.py +762 -0
  7. vgi/_test_fixtures/aggregate/__init__.py +62 -0
  8. vgi/_test_fixtures/aggregate/_common.py +21 -0
  9. vgi/_test_fixtures/aggregate/basic.py +232 -0
  10. vgi/_test_fixtures/aggregate/dynamic.py +409 -0
  11. vgi/_test_fixtures/aggregate/generic.py +86 -0
  12. vgi/_test_fixtures/aggregate/listagg.py +71 -0
  13. vgi/_test_fixtures/aggregate/percentile.py +107 -0
  14. vgi/_test_fixtures/aggregate/streaming.py +192 -0
  15. vgi/_test_fixtures/aggregate/varargs.py +75 -0
  16. vgi/_test_fixtures/aggregate/window.py +380 -0
  17. vgi/_test_fixtures/attach_options.py +308 -0
  18. vgi/_test_fixtures/bad_protocol.py +62 -0
  19. vgi/_test_fixtures/cancellable.py +336 -0
  20. vgi/_test_fixtures/catalog.py +813 -0
  21. vgi/_test_fixtures/http_server.py +394 -0
  22. vgi/_test_fixtures/nest_tensor.py +614 -0
  23. vgi/_test_fixtures/orchard_catalog.py +47 -0
  24. vgi/_test_fixtures/projection_repro/__init__.py +6 -0
  25. vgi/_test_fixtures/projection_repro/worker.py +454 -0
  26. vgi/_test_fixtures/scalar/__init__.py +116 -0
  27. vgi/_test_fixtures/scalar/_common.py +69 -0
  28. vgi/_test_fixtures/scalar/arithmetic.py +321 -0
  29. vgi/_test_fixtures/scalar/binary.py +120 -0
  30. vgi/_test_fixtures/scalar/formatting.py +176 -0
  31. vgi/_test_fixtures/scalar/geo.py +300 -0
  32. vgi/_test_fixtures/scalar/null_handling.py +107 -0
  33. vgi/_test_fixtures/scalar/random_demo.py +171 -0
  34. vgi/_test_fixtures/scalar/settings_secrets.py +102 -0
  35. vgi/_test_fixtures/scalar/type_info.py +219 -0
  36. vgi/_test_fixtures/schema_reconcile/__init__.py +29 -0
  37. vgi/_test_fixtures/schema_reconcile/worker.py +653 -0
  38. vgi/_test_fixtures/simple_writable.py +793 -0
  39. vgi/_test_fixtures/table/__init__.py +221 -0
  40. vgi/_test_fixtures/table/_common.py +162 -0
  41. vgi/_test_fixtures/table/batch_index.py +283 -0
  42. vgi/_test_fixtures/table/batch_index_broken.py +200 -0
  43. vgi/_test_fixtures/table/catalog_scans.py +162 -0
  44. vgi/_test_fixtures/table/filters.py +1005 -0
  45. vgi/_test_fixtures/table/late_materialization.py +249 -0
  46. vgi/_test_fixtures/table/make_series.py +273 -0
  47. vgi/_test_fixtures/table/misc.py +499 -0
  48. vgi/_test_fixtures/table/order_modes.py +164 -0
  49. vgi/_test_fixtures/table/pairs.py +437 -0
  50. vgi/_test_fixtures/table/partition_columns.py +472 -0
  51. vgi/_test_fixtures/table/partition_columns_broken.py +304 -0
  52. vgi/_test_fixtures/table/profiling_example.py +195 -0
  53. vgi/_test_fixtures/table/required_filters.py +234 -0
  54. vgi/_test_fixtures/table/sequence.py +710 -0
  55. vgi/_test_fixtures/table/settings.py +426 -0
  56. vgi/_test_fixtures/table/transaction_storage.py +162 -0
  57. vgi/_test_fixtures/table/tt_pushdown.py +191 -0
  58. vgi/_test_fixtures/table/versioned.py +230 -0
  59. vgi/_test_fixtures/table_in_out.py +1392 -0
  60. vgi/_test_fixtures/versioned.py +155 -0
  61. vgi/_test_fixtures/versioned_tables.py +595 -0
  62. vgi/_test_fixtures/worker.py +1631 -0
  63. vgi/_test_fixtures/writable/__init__.py +8 -0
  64. vgi/_test_fixtures/writable/generic.py +236 -0
  65. vgi/_test_fixtures/writable/table.py +149 -0
  66. vgi/_test_fixtures/writable/worker.py +1148 -0
  67. vgi/aggregate_function.py +607 -0
  68. vgi/argument_spec.py +472 -0
  69. vgi/arguments.py +1747 -0
  70. vgi/auth.py +55 -0
  71. vgi/catalog/__init__.py +88 -0
  72. vgi/catalog/attach_option.py +206 -0
  73. vgi/catalog/catalog_interface.py +2767 -0
  74. vgi/catalog/descriptors.py +870 -0
  75. vgi/catalog/duckdb_statistics.py +377 -0
  76. vgi/catalog/secret_type.py +96 -0
  77. vgi/catalog/setting.py +253 -0
  78. vgi/catalog/storage.py +372 -0
  79. vgi/client/__init__.py +67 -0
  80. vgi/client/catalog_mixin.py +1251 -0
  81. vgi/client/cli.py +582 -0
  82. vgi/client/cli_catalog.py +182 -0
  83. vgi/client/cli_schema.py +270 -0
  84. vgi/client/cli_table.py +907 -0
  85. vgi/client/cli_transaction.py +97 -0
  86. vgi/client/cli_utils.py +441 -0
  87. vgi/client/cli_view.py +303 -0
  88. vgi/client/client.py +2183 -0
  89. vgi/exceptions.py +205 -0
  90. vgi/function.py +245 -0
  91. vgi/function_storage.py +1636 -0
  92. vgi/function_storage_azure_sql.py +922 -0
  93. vgi/function_storage_cf_do.py +740 -0
  94. vgi/http/__init__.py +25 -0
  95. vgi/http/demo_storage.py +212 -0
  96. vgi/http/worker_page.py +1252 -0
  97. vgi/invocation.py +154 -0
  98. vgi/logging_config.py +93 -0
  99. vgi/meta_worker.py +661 -0
  100. vgi/metadata.py +1403 -0
  101. vgi/otel.py +406 -0
  102. vgi/protocol.py +2418 -0
  103. vgi/protocol_version.txt +1 -0
  104. vgi/py.typed +0 -0
  105. vgi/scalar_function.py +1211 -0
  106. vgi/schema_utils.py +234 -0
  107. vgi/secret_protocol.py +124 -0
  108. vgi/secret_service.py +238 -0
  109. vgi/serve.py +769 -0
  110. vgi/table_buffering_function.py +443 -0
  111. vgi/table_filter_pushdown.py +1528 -0
  112. vgi/table_function.py +1130 -0
  113. vgi/table_in_out_function.py +383 -0
  114. vgi/transactor/__init__.py +24 -0
  115. vgi/transactor/_duckdb_compat.py +27 -0
  116. vgi/transactor/client.py +137 -0
  117. vgi/transactor/protocol.py +149 -0
  118. vgi/transactor/server.py +740 -0
  119. vgi/worker.py +4761 -0
  120. vgi_python-0.8.0.dist-info/METADATA +735 -0
  121. vgi_python-0.8.0.dist-info/RECORD +124 -0
  122. vgi_python-0.8.0.dist-info/WHEEL +4 -0
  123. vgi_python-0.8.0.dist-info/entry_points.txt +5 -0
  124. vgi_python-0.8.0.dist-info/licenses/LICENSE +134 -0
@@ -0,0 +1,155 @@
1
+ # Copyright 2025, 2026 Query Farm LLC - https://query.farm
2
+
3
+ """Example VGI worker that validates data_version_spec / implementation_version.
4
+
5
+ Demonstrates the ATTACH-time versioning protocol end-to-end:
6
+
7
+ * :meth:`VersionedCatalog.catalogs` advertises per-catalog
8
+ ``implementation_version`` and ``data_version_spec`` discovery metadata.
9
+ * :meth:`VersionedCatalog.catalog_attach` validates the client's requested
10
+ versions against :data:`SUPPORTED_DATA_VERSIONS` and
11
+ :data:`IMPLEMENTATION_VERSION`. Unsatisfiable requests raise ``ValueError``;
12
+ the client surfaces this as the ATTACH failure. Successful attaches set
13
+ ``ctx.set_cookie("vgi_sticky", ...)`` so any upstream HTTP proxy can pin
14
+ the session.
15
+ * :meth:`VersionedCatalog.catalog_version` asserts that subsequent requests
16
+ echo the ``vgi_sticky`` cookie — this proves the extension's HTTP cookie
17
+ jar plumbs Set-Cookie → Cookie round trips. For subprocess transport
18
+ ``ctx.cookies`` is empty and the check is skipped.
19
+
20
+ Registered as the ``vgi-fixture-versioned-worker`` entry point.
21
+ """
22
+
23
+ from __future__ import annotations
24
+
25
+ import contextlib
26
+ import uuid
27
+ from typing import TYPE_CHECKING, Any
28
+
29
+ from vgi.catalog import (
30
+ AttachOpaqueData,
31
+ CatalogAttachResult,
32
+ CatalogInfo,
33
+ ReadOnlyCatalogInterface,
34
+ TransactionOpaqueData,
35
+ )
36
+ from vgi.catalog.descriptors import Catalog, Schema
37
+ from vgi.worker import Worker
38
+
39
+ if TYPE_CHECKING:
40
+ from vgi_rpc.rpc import CallContext
41
+
42
+
43
+ IMPLEMENTATION_VERSION = "1.0.0"
44
+ DATA_VERSION_SPEC = ">=1.0.0,<2.0.0"
45
+ SUPPORTED_DATA_VERSIONS: frozenset[str] = frozenset({"1.0.0", "1.1.0", "1.2.0"})
46
+ DEFAULT_DATA_VERSION = "1.2.0"
47
+ STICKY_COOKIE_NAME = "vgi_sticky"
48
+
49
+
50
+ _VERSIONED_CATALOG = Catalog(
51
+ name="versioned",
52
+ default_schema="main",
53
+ comment="Example catalog demonstrating data_version_spec validation and cookie stickiness",
54
+ tags={},
55
+ schemas=[Schema(name="main", tables=[])],
56
+ )
57
+
58
+
59
+ class VersionedCatalog(ReadOnlyCatalogInterface):
60
+ """Catalog interface that validates versions and exercises HTTP cookies."""
61
+
62
+ catalog = _VERSIONED_CATALOG
63
+
64
+ def catalogs(self) -> list[CatalogInfo]:
65
+ """Advertise a single catalog with its implementation version and data-version range."""
66
+ return [
67
+ CatalogInfo(
68
+ name=_VERSIONED_CATALOG.name,
69
+ implementation_version=IMPLEMENTATION_VERSION,
70
+ data_version_spec=DATA_VERSION_SPEC,
71
+ ),
72
+ ]
73
+
74
+ def catalog_attach(
75
+ self,
76
+ *,
77
+ name: str,
78
+ options: dict[str, Any],
79
+ data_version_spec: str | None,
80
+ implementation_version: str | None,
81
+ ctx: CallContext | None = None,
82
+ ) -> CatalogAttachResult:
83
+ """Validate requested versions and pin an HTTP session."""
84
+ del options
85
+ if name != _VERSIONED_CATALOG.name:
86
+ raise ValueError(f"Unknown catalog: {name!r}. Available: {_VERSIONED_CATALOG.name}")
87
+
88
+ if implementation_version is not None and implementation_version != IMPLEMENTATION_VERSION:
89
+ raise ValueError(
90
+ f"Unsupported implementation_version {implementation_version!r}; "
91
+ f"this worker serves {IMPLEMENTATION_VERSION!r}",
92
+ )
93
+
94
+ if data_version_spec is not None and data_version_spec not in SUPPORTED_DATA_VERSIONS:
95
+ # Exact-match only — production workers would parse the range; this
96
+ # example keeps the matcher trivial so failures are unambiguous.
97
+ raise ValueError(
98
+ f"Unsupported data_version_spec {data_version_spec!r}; "
99
+ f"this worker serves one of {sorted(SUPPORTED_DATA_VERSIONS)}",
100
+ )
101
+ resolved_data_version = data_version_spec if data_version_spec is not None else DEFAULT_DATA_VERSION
102
+
103
+ # Pin the session for HTTP routing. On subprocess transport set_cookie
104
+ # raises RuntimeError — ignore it silently so the same worker works
105
+ # under both transports.
106
+ if ctx is not None:
107
+ with contextlib.suppress(RuntimeError):
108
+ ctx.set_cookie(STICKY_COOKIE_NAME, uuid.uuid4().hex)
109
+
110
+ return CatalogAttachResult(
111
+ attach_opaque_data=AttachOpaqueData(uuid.uuid4().bytes),
112
+ supports_transactions=False,
113
+ supports_time_travel=False,
114
+ catalog_version_frozen=True,
115
+ catalog_version=1,
116
+ attach_opaque_data_required=False,
117
+ default_schema=_VERSIONED_CATALOG.default_schema,
118
+ comment=_VERSIONED_CATALOG.comment,
119
+ tags=dict(_VERSIONED_CATALOG.tags),
120
+ resolved_data_version=resolved_data_version,
121
+ resolved_implementation_version=IMPLEMENTATION_VERSION,
122
+ )
123
+
124
+ def catalog_version(
125
+ self,
126
+ *,
127
+ attach_opaque_data: AttachOpaqueData,
128
+ transaction_opaque_data: TransactionOpaqueData | None,
129
+ ctx: CallContext | None = None,
130
+ ) -> int:
131
+ """Assert that the routing cookie we set at ATTACH is echoed back."""
132
+ del attach_opaque_data, transaction_opaque_data
133
+ if ctx is not None and ctx.cookies and STICKY_COOKIE_NAME not in ctx.cookies:
134
+ # Over HTTP, missing the sticky cookie means the client's cookie jar
135
+ # is broken. Bail loudly so the test catches the regression.
136
+ raise ValueError(
137
+ f"expected cookie {STICKY_COOKIE_NAME!r} on follow-up request; got {sorted(ctx.cookies)}",
138
+ )
139
+ return 1
140
+
141
+
142
+ class VersionedWorker(Worker):
143
+ """Worker exposing :class:`VersionedCatalog`."""
144
+
145
+ catalog_interface = VersionedCatalog
146
+ catalog = _VERSIONED_CATALOG
147
+
148
+
149
+ def main() -> None:
150
+ """Run the versioned-example worker process."""
151
+ VersionedWorker.main()
152
+
153
+
154
+ if __name__ == "__main__":
155
+ main()