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
vgi/auth.py ADDED
@@ -0,0 +1,55 @@
1
+ # Copyright 2025, 2026 Query Farm LLC - https://query.farm
2
+
3
+ """Convenience re-exports of authentication types from vgi-rpc.
4
+
5
+ Core types (always available):
6
+ AuthContext, CallContext
7
+
8
+ HTTP auth factories (require ``vgi[http]``):
9
+ bearer_authenticate, bearer_authenticate_static, chain_authenticate,
10
+ OAuthResourceMetadata
11
+
12
+ JWT auth (requires ``vgi[oauth]``):
13
+ jwt_authenticate
14
+ """
15
+
16
+ from __future__ import annotations
17
+
18
+ import contextlib
19
+
20
+ from vgi_rpc.rpc import AuthContext, CallContext
21
+
22
+ __all__ = [
23
+ "AuthContext",
24
+ "CallContext",
25
+ ]
26
+
27
+ # HTTP auth helpers — available when vgi[http] is installed.
28
+ with contextlib.suppress(ImportError):
29
+ from vgi_rpc.http import ( # noqa: F401
30
+ OAuthResourceMetadata,
31
+ bearer_authenticate,
32
+ bearer_authenticate_static,
33
+ chain_authenticate,
34
+ parse_client_id,
35
+ parse_client_secret,
36
+ parse_device_code_client_id,
37
+ parse_device_code_client_secret,
38
+ )
39
+
40
+ __all__ += [
41
+ "OAuthResourceMetadata",
42
+ "bearer_authenticate",
43
+ "bearer_authenticate_static",
44
+ "chain_authenticate",
45
+ "parse_client_id",
46
+ "parse_client_secret",
47
+ "parse_device_code_client_id",
48
+ "parse_device_code_client_secret",
49
+ ]
50
+
51
+ # JWT auth — available when vgi[oauth] is installed (requires authlib).
52
+ with contextlib.suppress(ImportError):
53
+ from vgi_rpc.http._oauth_jwt import jwt_authenticate # noqa: F401
54
+
55
+ __all__ += ["jwt_authenticate"]
@@ -0,0 +1,88 @@
1
+ # Copyright 2025, 2026 Query Farm LLC - https://query.farm
2
+
3
+ """VGI Catalog Interface for exposing catalogs, schemas, tables, and views.
4
+
5
+ This module provides the abstract base class and data types for implementing
6
+ catalog interfaces in VGI workers, enabling DuckDB ATTACH support.
7
+ """
8
+
9
+ from vgi.catalog.catalog_interface import (
10
+ AttachOpaqueData,
11
+ CatalogAttachResult,
12
+ CatalogDataVersionRelease,
13
+ CatalogExample,
14
+ CatalogInfo,
15
+ CatalogInterface,
16
+ CatalogObject,
17
+ CatalogSchemaObject,
18
+ FunctionInfo,
19
+ FunctionType,
20
+ IndexConstraintType,
21
+ IndexInfo,
22
+ MacroInfo,
23
+ MacroType,
24
+ OnConflict,
25
+ ReadOnlyCatalogInterface,
26
+ ScanBranch,
27
+ ScanBranchesResult,
28
+ ScanFunctionResult,
29
+ SchemaInfo,
30
+ SchemaObjectType,
31
+ SerializedSchema,
32
+ SqlExpression,
33
+ TableInfo,
34
+ TransactionOpaqueData,
35
+ ViewInfo,
36
+ )
37
+ from vgi.catalog.descriptors import Catalog, ForeignKeyDef, Index, Macro, Schema, Sql, Table, View
38
+ from vgi.catalog.secret_type import SecretTypeSpec
39
+ from vgi.catalog.setting import Setting, SettingSpec
40
+ from vgi.catalog.storage import CatalogStorage, CatalogStorageSqlite
41
+
42
+ __all__ = [
43
+ # Type aliases
44
+ "AttachOpaqueData",
45
+ "TransactionOpaqueData",
46
+ "SerializedSchema",
47
+ "SqlExpression",
48
+ # Enums
49
+ "FunctionType",
50
+ "IndexConstraintType",
51
+ "MacroType",
52
+ "OnConflict",
53
+ "SchemaObjectType",
54
+ # Data classes
55
+ "CatalogAttachResult",
56
+ "CatalogDataVersionRelease",
57
+ "CatalogExample",
58
+ "CatalogInfo",
59
+ "CatalogObject",
60
+ "CatalogSchemaObject",
61
+ "IndexInfo",
62
+ "MacroInfo",
63
+ "SchemaInfo",
64
+ "SecretTypeSpec",
65
+ "Setting",
66
+ "SettingSpec",
67
+ "TableInfo",
68
+ "ViewInfo",
69
+ "FunctionInfo",
70
+ "ScanBranch",
71
+ "ScanBranchesResult",
72
+ "ScanFunctionResult",
73
+ # Declarative descriptors
74
+ "Catalog",
75
+ "ForeignKeyDef",
76
+ "Index",
77
+ "Macro",
78
+ "Schema",
79
+ "Sql",
80
+ "Table",
81
+ "View",
82
+ # Interfaces
83
+ "CatalogInterface",
84
+ "ReadOnlyCatalogInterface",
85
+ # Storage
86
+ "CatalogStorage",
87
+ "CatalogStorageSqlite",
88
+ ]
@@ -0,0 +1,206 @@
1
+ # Copyright 2025, 2026 Query Farm LLC - https://query.farm
2
+
3
+ """AttachOption descriptor for declarative worker attach-time options.
4
+
5
+ This module provides the AttachOption descriptor class for declaring options
6
+ that workers accept at ATTACH time (delivered once via catalog_attach, distinct
7
+ from session-level Settings resent on every call).
8
+
9
+ The declaration mirrors ``vgi.catalog.setting.Setting`` almost verbatim — same
10
+ Arrow IPC spec format, same Python type → Arrow mapping, same extractor shape.
11
+ """
12
+
13
+ from dataclasses import dataclass, field
14
+ from typing import (
15
+ TYPE_CHECKING,
16
+ Annotated,
17
+ Any,
18
+ ClassVar,
19
+ cast,
20
+ get_args,
21
+ get_origin,
22
+ get_type_hints,
23
+ )
24
+
25
+ import pyarrow as pa
26
+ from vgi_rpc.utils import deserialize_record_batch, serialize_record_batch_bytes
27
+
28
+ from vgi.schema_utils import schema
29
+
30
+ if TYPE_CHECKING:
31
+ from typing import Self
32
+
33
+ __all__ = [
34
+ "AttachOption",
35
+ "AttachOptionSpec",
36
+ "extract_attach_option_specs",
37
+ ]
38
+
39
+
40
+ @dataclass(frozen=True)
41
+ class AttachOptionSpec:
42
+ """Extracted attach-option metadata for catalog discovery serialization.
43
+
44
+ Attributes:
45
+ name: The option name (from the class attribute name).
46
+ desc: Human-readable description.
47
+ type: The Arrow data type for this option.
48
+ default: The default value (Python object) or ``None`` if unset.
49
+
50
+ """
51
+
52
+ name: str
53
+ desc: str
54
+ type: pa.DataType
55
+ default: Any
56
+
57
+ ARROW_SCHEMA: ClassVar[pa.Schema] = pa.schema(
58
+ [
59
+ pa.field("name", pa.string(), nullable=False),
60
+ pa.field("description", pa.string(), nullable=False),
61
+ pa.field("type", pa.binary(), nullable=False),
62
+ pa.field("default_value", pa.binary(), nullable=True),
63
+ ] # type: ignore[arg-type]
64
+ )
65
+
66
+ def serialize(self) -> bytes:
67
+ """Serialize to Arrow IPC bytes."""
68
+ type_schema = schema(value=self.type)
69
+ type_bytes = type_schema.serialize().to_pybytes()
70
+
71
+ default_bytes: bytes | None = None
72
+ if self.default is not None:
73
+ default_batch = pa.RecordBatch.from_pydict({"value": [self.default]}, schema=type_schema)
74
+ default_bytes = serialize_record_batch_bytes(default_batch)
75
+
76
+ batch = pa.RecordBatch.from_pylist(
77
+ [
78
+ {
79
+ "name": self.name,
80
+ "description": self.desc,
81
+ "type": type_bytes,
82
+ "default_value": default_bytes,
83
+ }
84
+ ],
85
+ schema=self.ARROW_SCHEMA,
86
+ )
87
+ return serialize_record_batch_bytes(batch)
88
+
89
+ @classmethod
90
+ def deserialize(cls, batch: pa.RecordBatch) -> "Self":
91
+ """Deserialize from Arrow RecordBatch."""
92
+ from vgi_rpc.utils import _validate_single_row_batch
93
+
94
+ row = _validate_single_row_batch(
95
+ batch,
96
+ cls.__name__,
97
+ required_fields=["name", "description", "type"],
98
+ )
99
+ type_schema = pa.ipc.read_schema(pa.py_buffer(cast(bytes, row["type"])))
100
+ data_type = type_schema.field("value").type
101
+
102
+ default: Any = None
103
+ if row["default_value"] is not None:
104
+ default_batch, _ = deserialize_record_batch(cast(bytes, row["default_value"]))
105
+ default = default_batch.column("value")[0].as_py()
106
+
107
+ return cls(
108
+ name=cast(str, row["name"]),
109
+ desc=cast(str, row["description"]),
110
+ type=data_type,
111
+ default=default,
112
+ )
113
+
114
+
115
+ _PYTHON_TO_ARROW: dict[type, pa.DataType] = {
116
+ bool: pa.bool_(),
117
+ int: pa.int64(),
118
+ float: pa.float64(),
119
+ str: pa.string(),
120
+ bytes: pa.binary(),
121
+ }
122
+
123
+
124
+ def _resolve_arrow_type(type_hint: type | pa.DataType) -> pa.DataType:
125
+ """Resolve Arrow type from either a Python type or an Arrow DataType."""
126
+ if isinstance(type_hint, pa.DataType):
127
+ return type_hint
128
+ if type_hint in _PYTHON_TO_ARROW:
129
+ return _PYTHON_TO_ARROW[type_hint]
130
+ raise TypeError(
131
+ f"Cannot resolve Arrow type from: {type_hint}. "
132
+ "Use a Python type (bool, int, float, str, bytes) or Arrow DataType."
133
+ )
134
+
135
+
136
+ @dataclass
137
+ class AttachOption:
138
+ """Descriptor for declarative attach-option definitions using Annotated.
139
+
140
+ Use with Annotated type hints to declare options in a Worker's
141
+ AttachOptions inner class. The Arrow type is resolved from the base type
142
+ in the Annotated hint.
143
+
144
+ Attributes:
145
+ desc: Human-readable description of the option.
146
+ arrow_type: Optional explicit Arrow type (overrides inference).
147
+
148
+ """
149
+
150
+ desc: str = ""
151
+ arrow_type: pa.DataType | None = None
152
+
153
+ _name: str = field(default="", init=False, repr=False)
154
+
155
+ def __set_name__(self, owner: type, name: str) -> None:
156
+ """Capture the attribute name when bound to a class."""
157
+ self._name = name
158
+
159
+ def __get__(self, obj: object | None, objtype: type | None = None) -> Any:
160
+ """Return the descriptor itself on class access; the bound value on instance access."""
161
+ if obj is None:
162
+ return self
163
+ return getattr(type(obj), self._name, None)
164
+
165
+
166
+ def extract_attach_option_specs(options_cls: type) -> list[AttachOptionSpec]:
167
+ """Extract AttachOptionSpec objects from an AttachOptions class."""
168
+ specs: list[AttachOptionSpec] = []
169
+
170
+ try:
171
+ hints = get_type_hints(options_cls, include_extras=True)
172
+ except Exception:
173
+ return specs
174
+
175
+ for name, hint in hints.items():
176
+ if get_origin(hint) is not Annotated:
177
+ continue
178
+
179
+ args = get_args(hint)
180
+ if len(args) < 2:
181
+ continue
182
+
183
+ base_type = args[0]
184
+
185
+ opt: AttachOption | None = None
186
+ for arg in args[1:]:
187
+ if isinstance(arg, AttachOption):
188
+ opt = arg
189
+ break
190
+
191
+ if opt is None:
192
+ continue
193
+
194
+ default = getattr(options_cls, name, None)
195
+ arrow_type = opt.arrow_type if opt.arrow_type is not None else _resolve_arrow_type(base_type)
196
+
197
+ specs.append(
198
+ AttachOptionSpec(
199
+ name=name,
200
+ desc=opt.desc,
201
+ type=arrow_type,
202
+ default=default,
203
+ )
204
+ )
205
+
206
+ return specs