vgi-python 0.8.5__py3-none-any.whl → 0.8.7__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.
- vgi/_test_fixtures/catalog.py +2 -0
- vgi/_test_fixtures/worker.py +10 -0
- vgi/argument_spec.py +82 -0
- vgi/catalog/catalog_interface.py +28 -1
- vgi/catalog/descriptors.py +20 -1
- vgi/client/catalog_mixin.py +29 -7
- vgi/client/client.py +92 -6
- vgi/protocol.py +8 -0
- vgi/worker.py +60 -3
- {vgi_python-0.8.5.dist-info → vgi_python-0.8.7.dist-info}/METADATA +2 -2
- {vgi_python-0.8.5.dist-info → vgi_python-0.8.7.dist-info}/RECORD +14 -14
- {vgi_python-0.8.5.dist-info → vgi_python-0.8.7.dist-info}/WHEEL +0 -0
- {vgi_python-0.8.5.dist-info → vgi_python-0.8.7.dist-info}/entry_points.txt +0 -0
- {vgi_python-0.8.5.dist-info → vgi_python-0.8.7.dist-info}/licenses/LICENSE +0 -0
vgi/_test_fixtures/catalog.py
CHANGED
|
@@ -752,6 +752,7 @@ class InMemoryCatalog(CatalogInterface):
|
|
|
752
752
|
definition: str,
|
|
753
753
|
on_conflict: OnConflict,
|
|
754
754
|
parameter_default_values: pa.RecordBatch | None = None,
|
|
755
|
+
arguments_schema: pa.Schema | None = None,
|
|
755
756
|
) -> None:
|
|
756
757
|
"""Create a new macro."""
|
|
757
758
|
schema_data = self._get_schema(attach_opaque_data, schema_name)
|
|
@@ -773,6 +774,7 @@ class InMemoryCatalog(CatalogInterface):
|
|
|
773
774
|
definition=definition,
|
|
774
775
|
comment=None,
|
|
775
776
|
tags={},
|
|
777
|
+
arguments_schema=arguments_schema,
|
|
776
778
|
)
|
|
777
779
|
)
|
|
778
780
|
self._increment_version(attach_opaque_data)
|
vgi/_test_fixtures/worker.py
CHANGED
|
@@ -519,6 +519,10 @@ _EXAMPLE_CATALOG = Catalog(
|
|
|
519
519
|
parameters=["x", "y"],
|
|
520
520
|
definition="x * y",
|
|
521
521
|
comment="Multiply two values",
|
|
522
|
+
parameter_docs={
|
|
523
|
+
"x": "First factor",
|
|
524
|
+
"y": "Second factor",
|
|
525
|
+
},
|
|
522
526
|
),
|
|
523
527
|
Macro(
|
|
524
528
|
name="vgi_clamp",
|
|
@@ -530,6 +534,11 @@ _EXAMPLE_CATALOG = Catalog(
|
|
|
530
534
|
),
|
|
531
535
|
definition="GREATEST(lo, LEAST(hi, val))",
|
|
532
536
|
comment="Clamp a value between lo and hi (defaults: 0..100)",
|
|
537
|
+
parameter_docs={
|
|
538
|
+
"val": "Value to clamp",
|
|
539
|
+
"lo": "Lower bound (inclusive)",
|
|
540
|
+
"hi": "Upper bound (inclusive)",
|
|
541
|
+
},
|
|
533
542
|
),
|
|
534
543
|
Macro(
|
|
535
544
|
name="vgi_range_table",
|
|
@@ -537,6 +546,7 @@ _EXAMPLE_CATALOG = Catalog(
|
|
|
537
546
|
parameters=["n"],
|
|
538
547
|
definition="SELECT * FROM range(n)",
|
|
539
548
|
comment="Table macro returning range of values",
|
|
549
|
+
parameter_docs={"n": "Number of rows to generate"},
|
|
540
550
|
),
|
|
541
551
|
],
|
|
542
552
|
),
|
vgi/argument_spec.py
CHANGED
|
@@ -27,6 +27,8 @@ __all__ = [
|
|
|
27
27
|
"ArgumentSpec",
|
|
28
28
|
"argument_specs_to_schema",
|
|
29
29
|
"extract_argument_specs",
|
|
30
|
+
"macro_arguments_schema",
|
|
31
|
+
"macro_parameter_docs_from_schema",
|
|
30
32
|
"schema_to_argument_specs",
|
|
31
33
|
# Metadata constants for parsing schemas
|
|
32
34
|
"VGI_ARG_KEY",
|
|
@@ -280,6 +282,86 @@ def schema_to_argument_specs(schema: pa.Schema) -> list[ArgumentSpec]:
|
|
|
280
282
|
return specs
|
|
281
283
|
|
|
282
284
|
|
|
285
|
+
# =============================================================================
|
|
286
|
+
# Macro Argument Schemas
|
|
287
|
+
# =============================================================================
|
|
288
|
+
|
|
289
|
+
|
|
290
|
+
def macro_arguments_schema(
|
|
291
|
+
parameters: Sequence[str],
|
|
292
|
+
parameter_default_values: pa.RecordBatch | None = None,
|
|
293
|
+
parameter_docs: dict[str, str] | None = None,
|
|
294
|
+
) -> pa.Schema:
|
|
295
|
+
"""Build a macro ``arguments_schema`` describing macro parameters.
|
|
296
|
+
|
|
297
|
+
Mirrors the function ``arguments_schema`` mechanism: one Arrow field per
|
|
298
|
+
macro parameter, in ``parameters`` order, each nullable. The per-parameter
|
|
299
|
+
description is carried via the same ``vgi_doc`` field-metadata key functions
|
|
300
|
+
use (UTF-8, presence-only — the key is omitted entirely when there is no
|
|
301
|
+
doc). A parameter's field type is the type of its default value when one is
|
|
302
|
+
known (from ``parameter_default_values``), else ``pa.null()``.
|
|
303
|
+
|
|
304
|
+
Args:
|
|
305
|
+
parameters: Ordered list of macro parameter names.
|
|
306
|
+
parameter_default_values: Optional one-row ``RecordBatch`` whose columns
|
|
307
|
+
are parameter names with typed default values; used to infer each
|
|
308
|
+
parameter's field type.
|
|
309
|
+
parameter_docs: Optional mapping of parameter name to description. Empty
|
|
310
|
+
or missing descriptions yield no ``vgi_doc`` metadata on the field.
|
|
311
|
+
|
|
312
|
+
Returns:
|
|
313
|
+
Arrow schema with one nullable field per parameter, in order.
|
|
314
|
+
|
|
315
|
+
"""
|
|
316
|
+
docs = parameter_docs or {}
|
|
317
|
+
|
|
318
|
+
# Map parameter name -> Arrow type from the typed default values, if any.
|
|
319
|
+
default_types: dict[str, pa.DataType] = {}
|
|
320
|
+
if parameter_default_values is not None:
|
|
321
|
+
for default_field in parameter_default_values.schema:
|
|
322
|
+
default_types[default_field.name] = default_field.type
|
|
323
|
+
|
|
324
|
+
fields: list[pa.Field[Any]] = []
|
|
325
|
+
for name in parameters:
|
|
326
|
+
metadata: dict[bytes, bytes] = {}
|
|
327
|
+
doc = docs.get(name, "")
|
|
328
|
+
if doc:
|
|
329
|
+
metadata[VGI_DOC_KEY] = doc.encode("utf-8")
|
|
330
|
+
|
|
331
|
+
field = pa.field(
|
|
332
|
+
name,
|
|
333
|
+
default_types.get(name, pa.null()),
|
|
334
|
+
nullable=True,
|
|
335
|
+
metadata=metadata if metadata else None,
|
|
336
|
+
)
|
|
337
|
+
fields.append(field)
|
|
338
|
+
|
|
339
|
+
return pa.schema(fields)
|
|
340
|
+
|
|
341
|
+
|
|
342
|
+
def macro_parameter_docs_from_schema(schema: pa.Schema) -> dict[str, str]:
|
|
343
|
+
"""Extract per-parameter descriptions from a macro ``arguments_schema``.
|
|
344
|
+
|
|
345
|
+
Inverse of [`macro_arguments_schema`][]'s ``vgi_doc`` handling: reads the
|
|
346
|
+
``vgi_doc`` field metadata (UTF-8) for each field. Fields without the key
|
|
347
|
+
(undocumented) are omitted from the result.
|
|
348
|
+
|
|
349
|
+
Args:
|
|
350
|
+
schema: A macro ``arguments_schema`` (one field per parameter).
|
|
351
|
+
|
|
352
|
+
Returns:
|
|
353
|
+
Mapping of parameter name to description, for documented parameters only.
|
|
354
|
+
|
|
355
|
+
"""
|
|
356
|
+
docs: dict[str, str] = {}
|
|
357
|
+
for field in schema:
|
|
358
|
+
metadata = field.metadata or {}
|
|
359
|
+
doc_bytes = metadata.get(VGI_DOC_KEY)
|
|
360
|
+
if doc_bytes:
|
|
361
|
+
docs[field.name] = doc_bytes.decode("utf-8")
|
|
362
|
+
return docs
|
|
363
|
+
|
|
364
|
+
|
|
283
365
|
# =============================================================================
|
|
284
366
|
# Extraction from Function Classes
|
|
285
367
|
# =============================================================================
|
vgi/catalog/catalog_interface.py
CHANGED
|
@@ -435,6 +435,15 @@ class MacroInfo(CatalogSchemaObject, ArrowSerializableDataclass):
|
|
|
435
435
|
names and values are typed defaults. None if no defaults.
|
|
436
436
|
Serialized as IPC bytes over the wire.
|
|
437
437
|
definition: The SQL expression (scalar) or query (table).
|
|
438
|
+
arguments_schema: Optional Arrow schema (serialized as IPC bytes) with one
|
|
439
|
+
nullable field per parameter, in ``parameters`` order. Each field's type
|
|
440
|
+
is the parameter's default value type when known (else null), and the
|
|
441
|
+
``vgi_doc`` field metadata key carries the parameter's description (UTF-8,
|
|
442
|
+
presence-only — omitted when undocumented). Mirrors the per-argument doc
|
|
443
|
+
channel functions expose via ``FunctionInfo.arguments``. None means the
|
|
444
|
+
worker did not supply per-parameter docs (older workers); the extension
|
|
445
|
+
falls back to ``parameters`` for names. Built with
|
|
446
|
+
``vgi.argument_spec.macro_arguments_schema``.
|
|
438
447
|
|
|
439
448
|
"""
|
|
440
449
|
|
|
@@ -442,6 +451,7 @@ class MacroInfo(CatalogSchemaObject, ArrowSerializableDataclass):
|
|
|
442
451
|
parameters: list[str]
|
|
443
452
|
parameter_default_values: Annotated[pa.RecordBatch | None, ArrowType(pa.binary())] = None
|
|
444
453
|
definition: str = ""
|
|
454
|
+
arguments_schema: Annotated[pa.Schema | None, ArrowType(pa.binary())] = None
|
|
445
455
|
|
|
446
456
|
|
|
447
457
|
class FunctionType(Enum):
|
|
@@ -1979,8 +1989,25 @@ class CatalogInterface(ABC):
|
|
|
1979
1989
|
definition: str,
|
|
1980
1990
|
on_conflict: OnConflict,
|
|
1981
1991
|
parameter_default_values: pa.RecordBatch | None = None,
|
|
1992
|
+
arguments_schema: pa.Schema | None = None,
|
|
1982
1993
|
) -> None:
|
|
1983
|
-
"""Create a new macro with the given definition.
|
|
1994
|
+
"""Create a new macro with the given definition.
|
|
1995
|
+
|
|
1996
|
+
Args:
|
|
1997
|
+
attach_opaque_data: Per-attach catalog session token.
|
|
1998
|
+
transaction_opaque_data: Optional transaction handle.
|
|
1999
|
+
schema_name: Schema to create the macro in.
|
|
2000
|
+
name: Name for the new macro.
|
|
2001
|
+
macro_type: Whether this is a scalar or table macro.
|
|
2002
|
+
parameters: Ordered list of parameter names.
|
|
2003
|
+
definition: SQL expression (scalar) or query (table).
|
|
2004
|
+
on_conflict: Behavior if the macro already exists.
|
|
2005
|
+
parameter_default_values: One-row ``RecordBatch`` with typed defaults.
|
|
2006
|
+
arguments_schema: Optional Arrow schema (one nullable field per
|
|
2007
|
+
parameter, in ``parameters`` order) carrying per-parameter
|
|
2008
|
+
descriptions via the ``vgi_doc`` field metadata key. ``None`` when
|
|
2009
|
+
no per-parameter docs are supplied.
|
|
2010
|
+
"""
|
|
1984
2011
|
raise NotImplementedError("Macro create not implemented.")
|
|
1985
2012
|
|
|
1986
2013
|
def macro_drop(
|
vgi/catalog/descriptors.py
CHANGED
|
@@ -18,6 +18,7 @@ from typing import TYPE_CHECKING, Any, Union
|
|
|
18
18
|
|
|
19
19
|
import pyarrow as pa
|
|
20
20
|
|
|
21
|
+
from vgi.argument_spec import macro_arguments_schema
|
|
21
22
|
from vgi.arguments import Arguments
|
|
22
23
|
from vgi.catalog.catalog_interface import (
|
|
23
24
|
AttachOpaqueData,
|
|
@@ -695,6 +696,11 @@ class Macro:
|
|
|
695
696
|
parameter_default_values: One-row `RecordBatch` where columns are parameter
|
|
696
697
|
names and values are typed defaults. None if no defaults.
|
|
697
698
|
Example: pa.RecordBatch.from_pydict({"b": [5]}) for b := 5.
|
|
699
|
+
parameter_docs: Optional mapping of parameter name to a human/agent-facing
|
|
700
|
+
description. Keys must appear in ``parameters``. Descriptions flow over
|
|
701
|
+
the wire via the macro ``arguments_schema``'s ``vgi_doc`` field metadata
|
|
702
|
+
(the same channel functions use), so the DuckDB extension's
|
|
703
|
+
``vgi_function_arguments()`` can surface them. Empty/default = no docs.
|
|
698
704
|
definition: SQL expression (scalar) or query (table).
|
|
699
705
|
comment: Optional macro comment.
|
|
700
706
|
tags: Optional metadata tags.
|
|
@@ -705,12 +711,14 @@ class Macro:
|
|
|
705
711
|
macro_type: MacroType
|
|
706
712
|
parameters: list[str] = field(default_factory=list)
|
|
707
713
|
parameter_default_values: pa.RecordBatch | None = None
|
|
714
|
+
parameter_docs: dict[str, str] = field(default_factory=dict)
|
|
708
715
|
definition: str = ""
|
|
709
716
|
comment: str | None = None
|
|
710
717
|
tags: dict[str, str] = field(default_factory=dict)
|
|
711
718
|
|
|
712
719
|
def __post_init__(self) -> None:
|
|
713
720
|
"""Validate macro configuration."""
|
|
721
|
+
param_set = set(self.parameters)
|
|
714
722
|
if self.parameter_default_values is not None:
|
|
715
723
|
if self.parameter_default_values.num_rows != 1:
|
|
716
724
|
raise ValueError(
|
|
@@ -718,13 +726,19 @@ class Macro:
|
|
|
718
726
|
f"got {self.parameter_default_values.num_rows}"
|
|
719
727
|
)
|
|
720
728
|
# Validate that default param column names exist in parameters list
|
|
721
|
-
param_set = set(self.parameters)
|
|
722
729
|
for col_name in self.parameter_default_values.schema.names:
|
|
723
730
|
if col_name not in param_set:
|
|
724
731
|
raise ValueError(
|
|
725
732
|
f"Macro '{self.name}': default parameter '{col_name}' not found "
|
|
726
733
|
f"in parameters list {self.parameters}"
|
|
727
734
|
)
|
|
735
|
+
# Validate that documented parameter names exist in parameters list
|
|
736
|
+
for doc_name in self.parameter_docs:
|
|
737
|
+
if doc_name not in param_set:
|
|
738
|
+
raise ValueError(
|
|
739
|
+
f"Macro '{self.name}': documented parameter '{doc_name}' not found "
|
|
740
|
+
f"in parameters list {self.parameters}"
|
|
741
|
+
)
|
|
728
742
|
|
|
729
743
|
def to_macro_info(self, schema_name: str) -> MacroInfo:
|
|
730
744
|
"""Convert to [`MacroInfo`][] for catalog response."""
|
|
@@ -737,6 +751,11 @@ class Macro:
|
|
|
737
751
|
definition=self.definition,
|
|
738
752
|
comment=self.comment,
|
|
739
753
|
tags=dict(self.tags),
|
|
754
|
+
arguments_schema=macro_arguments_schema(
|
|
755
|
+
self.parameters,
|
|
756
|
+
self.parameter_default_values,
|
|
757
|
+
self.parameter_docs,
|
|
758
|
+
),
|
|
740
759
|
)
|
|
741
760
|
|
|
742
761
|
|
vgi/client/catalog_mixin.py
CHANGED
|
@@ -90,12 +90,14 @@ class CatalogClientMixin:
|
|
|
90
90
|
Catalog methods spawn ephemeral connections under the hood — for
|
|
91
91
|
subprocess transport a pooled subprocess worker; for HTTP transport a
|
|
92
92
|
short-lived ``http_connect`` session reusing the ``Client``'s shared
|
|
93
|
-
``httpx.Client`` (bearer token, headers)
|
|
94
|
-
|
|
93
|
+
``httpx.Client`` (bearer token, headers); for TCP transport a short-lived
|
|
94
|
+
``tcp_connect`` session. Browsing catalogs over HTTP is the canonical
|
|
95
|
+
non-DuckDB use case this mixin supports.
|
|
95
96
|
|
|
96
|
-
Other attributes expected from ``Client``: ``_transport`` (subprocess
|
|
97
|
-
http), ``_base_url`` (HTTP base URL),
|
|
98
|
-
(shared HTTP client
|
|
97
|
+
Other attributes expected from ``Client``: ``_transport`` (subprocess,
|
|
98
|
+
http, or tcp), ``_base_url`` (HTTP base URL), ``_tcp_host`` / ``_tcp_port``
|
|
99
|
+
(TCP endpoint), and ``_get_or_create_httpx_client()`` (shared HTTP client
|
|
100
|
+
factory).
|
|
99
101
|
|
|
100
102
|
Attributes:
|
|
101
103
|
server_path: Worker shell command used for subprocess transport.
|
|
@@ -103,8 +105,10 @@ class CatalogClientMixin:
|
|
|
103
105
|
|
|
104
106
|
# Type hints for attributes expected from Client
|
|
105
107
|
server_path: str
|
|
106
|
-
_transport: Literal["subprocess", "http"]
|
|
108
|
+
_transport: Literal["subprocess", "http", "tcp"]
|
|
107
109
|
_base_url: str | None
|
|
110
|
+
_tcp_host: str | None
|
|
111
|
+
_tcp_port: int | None
|
|
108
112
|
_external_location: Any | None
|
|
109
113
|
|
|
110
114
|
def _get_or_create_httpx_client(self) -> Any: # implemented by Client
|
|
@@ -128,7 +132,8 @@ class CatalogClientMixin:
|
|
|
128
132
|
A typed `[`VgiProtocol`][]` proxy bound to the active transport.
|
|
129
133
|
"""
|
|
130
134
|
try:
|
|
131
|
-
|
|
135
|
+
transport = getattr(self, "_transport", "subprocess")
|
|
136
|
+
if transport == "http":
|
|
132
137
|
from vgi_rpc.http import http_connect
|
|
133
138
|
|
|
134
139
|
httpx_client = self._get_or_create_httpx_client()
|
|
@@ -139,6 +144,17 @@ class CatalogClientMixin:
|
|
|
139
144
|
external_location=getattr(self, "_external_location", None),
|
|
140
145
|
) as proxy:
|
|
141
146
|
yield proxy
|
|
147
|
+
elif transport == "tcp":
|
|
148
|
+
from vgi_rpc.rpc import tcp_connect
|
|
149
|
+
|
|
150
|
+
assert self._tcp_host is not None and self._tcp_port is not None
|
|
151
|
+
with tcp_connect(
|
|
152
|
+
VgiProtocol, # type: ignore[type-abstract]
|
|
153
|
+
self._tcp_host,
|
|
154
|
+
self._tcp_port,
|
|
155
|
+
external_location=getattr(self, "_external_location", None),
|
|
156
|
+
) as proxy:
|
|
157
|
+
yield proxy
|
|
142
158
|
else:
|
|
143
159
|
cmd = shlex.split(self.server_path, posix=sys.platform != "win32")
|
|
144
160
|
with _catalog_pool.connect(VgiProtocol, cmd) as proxy: # type: ignore[type-abstract]
|
|
@@ -1196,6 +1212,7 @@ class CatalogClientMixin:
|
|
|
1196
1212
|
definition: str,
|
|
1197
1213
|
on_conflict: OnConflict = OnConflict.ERROR,
|
|
1198
1214
|
parameter_default_values: pa.RecordBatch | None = None,
|
|
1215
|
+
arguments_schema: pa.Schema | None = None,
|
|
1199
1216
|
) -> None:
|
|
1200
1217
|
"""Create a new macro.
|
|
1201
1218
|
|
|
@@ -1209,6 +1226,10 @@ class CatalogClientMixin:
|
|
|
1209
1226
|
definition: SQL expression (scalar) or query (table).
|
|
1210
1227
|
on_conflict: Behavior if macro already exists.
|
|
1211
1228
|
parameter_default_values: One-row `RecordBatch` with typed defaults.
|
|
1229
|
+
arguments_schema: Optional Arrow schema (one nullable field per
|
|
1230
|
+
parameter, in ``parameters`` order) carrying per-parameter
|
|
1231
|
+
descriptions via the ``vgi_doc`` field metadata key. Build with
|
|
1232
|
+
``vgi.argument_spec.macro_arguments_schema``.
|
|
1212
1233
|
|
|
1213
1234
|
"""
|
|
1214
1235
|
with self._catalog_connect() as proxy:
|
|
@@ -1222,6 +1243,7 @@ class CatalogClientMixin:
|
|
|
1222
1243
|
definition=definition,
|
|
1223
1244
|
on_conflict=on_conflict,
|
|
1224
1245
|
parameter_default_values=parameter_default_values,
|
|
1246
|
+
arguments_schema=arguments_schema,
|
|
1225
1247
|
transaction_opaque_data=transaction_opaque_data,
|
|
1226
1248
|
)
|
|
1227
1249
|
)
|
vgi/client/client.py
CHANGED
|
@@ -197,10 +197,10 @@ _HTTP_TRANSPORT_READY = True
|
|
|
197
197
|
|
|
198
198
|
@dataclass
|
|
199
199
|
class WorkerConnection:
|
|
200
|
-
"""Holds state for a single worker connection (subprocess or
|
|
200
|
+
"""Holds state for a single worker connection (subprocess, HTTP, or TCP).
|
|
201
201
|
|
|
202
|
-
Exactly one of {proc+connection, _pool_ctx, _http_ctx} is active
|
|
203
|
-
connection — transport-specific teardown inspects these fields.
|
|
202
|
+
Exactly one of {proc+connection, _pool_ctx, _http_ctx, _tcp_ctx} is active
|
|
203
|
+
per connection — transport-specific teardown inspects these fields.
|
|
204
204
|
|
|
205
205
|
Attributes:
|
|
206
206
|
proxy: The typed `[`VgiProtocol`][]` proxy used to invoke the worker.
|
|
@@ -220,6 +220,8 @@ class WorkerConnection:
|
|
|
220
220
|
_pool_ctx: AbstractContextManager[Any] | None = field(default=None, repr=False)
|
|
221
221
|
# HTTP transport: context manager from vgi_rpc.http.http_connect.
|
|
222
222
|
_http_ctx: AbstractContextManager[Any] | None = field(default=None, repr=False)
|
|
223
|
+
# TCP transport: context manager from vgi_rpc.rpc.tcp_connect.
|
|
224
|
+
_tcp_ctx: AbstractContextManager[Any] | None = field(default=None, repr=False)
|
|
223
225
|
|
|
224
226
|
|
|
225
227
|
class Client(CatalogClientMixin):
|
|
@@ -381,8 +383,10 @@ class Client(CatalogClientMixin):
|
|
|
381
383
|
attach_opaque_data: bytes | None = None,
|
|
382
384
|
pool: WorkerPool | None = _default_pool,
|
|
383
385
|
*,
|
|
384
|
-
transport: Literal["subprocess", "http"] = "subprocess",
|
|
386
|
+
transport: Literal["subprocess", "http", "tcp"] = "subprocess",
|
|
385
387
|
base_url: str | None = None,
|
|
388
|
+
tcp_host: str | None = None,
|
|
389
|
+
tcp_port: int | None = None,
|
|
386
390
|
bearer_token: str | None = None,
|
|
387
391
|
httpx_client: Any | None = None,
|
|
388
392
|
external_location: Any | None = None,
|
|
@@ -413,9 +417,14 @@ class Client(CatalogClientMixin):
|
|
|
413
417
|
management.
|
|
414
418
|
transport: Which transport to use. ``"subprocess"`` (default)
|
|
415
419
|
spawns a local subprocess per worker; ``"http"`` connects to
|
|
416
|
-
a running worker via ``vgi_rpc.http.http_connect
|
|
420
|
+
a running worker via ``vgi_rpc.http.http_connect``; ``"tcp"``
|
|
421
|
+
connects to a running worker via ``vgi_rpc.rpc.tcp_connect``
|
|
422
|
+
(raw Arrow-IPC framing, no auth/encryption — loopback /
|
|
423
|
+
trusted networks only; use ``Client.from_tcp(...)``).
|
|
417
424
|
base_url: HTTP-only. Base URL of the running worker, e.g.
|
|
418
425
|
``"http://127.0.0.1:8765"``.
|
|
426
|
+
tcp_host: TCP-only. Hostname or IP of the running worker.
|
|
427
|
+
tcp_port: TCP-only. Port of the running worker.
|
|
419
428
|
bearer_token: HTTP-only. When set, every request carries an
|
|
420
429
|
``Authorization: Bearer <token>`` header. Static token
|
|
421
430
|
support only — no JWT / OAuth flows.
|
|
@@ -446,12 +455,21 @@ class Client(CatalogClientMixin):
|
|
|
446
455
|
raise ValueError("transport='http' requires base_url")
|
|
447
456
|
if server_path is not None:
|
|
448
457
|
raise ValueError("server_path is only meaningful for transport='subprocess'")
|
|
458
|
+
elif transport == "tcp":
|
|
459
|
+
if tcp_host is None or tcp_port is None:
|
|
460
|
+
raise ValueError("transport='tcp' requires tcp_host and tcp_port")
|
|
461
|
+
if server_path is not None:
|
|
462
|
+
raise ValueError("server_path is only meaningful for transport='subprocess'")
|
|
463
|
+
if base_url is not None:
|
|
464
|
+
raise ValueError("base_url is only meaningful for transport='http'")
|
|
449
465
|
else:
|
|
450
466
|
raise ValueError(f"unknown transport {transport!r}")
|
|
451
467
|
|
|
452
468
|
self.server_path = server_path or ""
|
|
453
469
|
self._transport = transport
|
|
454
470
|
self._base_url = base_url
|
|
471
|
+
self._tcp_host = tcp_host
|
|
472
|
+
self._tcp_port = tcp_port
|
|
455
473
|
self._bearer_token = bearer_token
|
|
456
474
|
self._httpx_client = httpx_client
|
|
457
475
|
# True when ``_get_or_create_httpx_client`` constructed the client and
|
|
@@ -460,7 +478,7 @@ class Client(CatalogClientMixin):
|
|
|
460
478
|
self._httpx_client_owned = False
|
|
461
479
|
# Auto-enable pointer-batch resolution for HTTP unless the caller
|
|
462
480
|
# asked for something different. See ``external_location`` docs above.
|
|
463
|
-
if transport
|
|
481
|
+
if transport in ("http", "tcp") and external_location is None:
|
|
464
482
|
from vgi_rpc.external import ExternalLocationConfig
|
|
465
483
|
|
|
466
484
|
external_location = ExternalLocationConfig()
|
|
@@ -509,6 +527,34 @@ class Client(CatalogClientMixin):
|
|
|
509
527
|
pool=None,
|
|
510
528
|
)
|
|
511
529
|
|
|
530
|
+
@classmethod
|
|
531
|
+
def from_tcp(
|
|
532
|
+
cls,
|
|
533
|
+
host: str,
|
|
534
|
+
port: int,
|
|
535
|
+
*,
|
|
536
|
+
external_location: Any | None = None,
|
|
537
|
+
worker_limit: int | None = None,
|
|
538
|
+
attach_opaque_data: bytes | None = None,
|
|
539
|
+
) -> Client:
|
|
540
|
+
"""Create a `[`Client`][]` bound to a running TCP VGI worker.
|
|
541
|
+
|
|
542
|
+
Connects via ``vgi_rpc.rpc.tcp_connect`` (raw Arrow-IPC framing). The
|
|
543
|
+
framing carries **no authentication or encryption** — only connect to
|
|
544
|
+
trusted endpoints on loopback or a trusted network; use
|
|
545
|
+
``Client.from_http(...)`` for untrusted networks. Spin up a matching
|
|
546
|
+
worker with ``vgi-fixture-worker --tcp [HOST:]PORT``.
|
|
547
|
+
"""
|
|
548
|
+
return cls(
|
|
549
|
+
transport="tcp",
|
|
550
|
+
tcp_host=host,
|
|
551
|
+
tcp_port=port,
|
|
552
|
+
external_location=external_location,
|
|
553
|
+
worker_limit=worker_limit,
|
|
554
|
+
attach_opaque_data=attach_opaque_data,
|
|
555
|
+
pool=None,
|
|
556
|
+
)
|
|
557
|
+
|
|
512
558
|
def _drain_stderr(self, stderr: IO[bytes]) -> None:
|
|
513
559
|
"""Background thread that continuously reads stderr.
|
|
514
560
|
|
|
@@ -577,8 +623,40 @@ class Client(CatalogClientMixin):
|
|
|
577
623
|
"""
|
|
578
624
|
if self._transport == "http":
|
|
579
625
|
return self._spawn_http_connection(worker_index)
|
|
626
|
+
if self._transport == "tcp":
|
|
627
|
+
return self._spawn_tcp_connection(worker_index)
|
|
580
628
|
return self._spawn_subprocess_connection(worker_index)
|
|
581
629
|
|
|
630
|
+
def _spawn_tcp_connection(self, worker_index: int) -> WorkerConnection:
|
|
631
|
+
"""Connect to a running TCP worker via ``vgi_rpc.rpc.tcp_connect``.
|
|
632
|
+
|
|
633
|
+
Raw Arrow-IPC framing with no auth/encryption — see ``from_tcp``.
|
|
634
|
+
Multiple ``worker_index`` values open independent TCP connections to
|
|
635
|
+
the same ``host:port``.
|
|
636
|
+
"""
|
|
637
|
+
from vgi_rpc.rpc import tcp_connect
|
|
638
|
+
|
|
639
|
+
assert self._tcp_host is not None and self._tcp_port is not None # enforced in __init__
|
|
640
|
+
ctx: AbstractContextManager[VgiProtocol] = tcp_connect(
|
|
641
|
+
VgiProtocol, # type: ignore[type-abstract]
|
|
642
|
+
self._tcp_host,
|
|
643
|
+
self._tcp_port,
|
|
644
|
+
on_log=self._on_worker_log,
|
|
645
|
+
external_location=self._external_location,
|
|
646
|
+
)
|
|
647
|
+
proxy = ctx.__enter__()
|
|
648
|
+
_logger.debug(
|
|
649
|
+
"tcp_connection_opened worker_index=%s host=%s port=%s",
|
|
650
|
+
worker_index,
|
|
651
|
+
self._tcp_host,
|
|
652
|
+
self._tcp_port,
|
|
653
|
+
)
|
|
654
|
+
return WorkerConnection(
|
|
655
|
+
proxy=proxy,
|
|
656
|
+
worker_index=worker_index,
|
|
657
|
+
_tcp_ctx=ctx,
|
|
658
|
+
)
|
|
659
|
+
|
|
582
660
|
def _spawn_http_connection(self, worker_index: int) -> WorkerConnection:
|
|
583
661
|
"""Connect to a remote HTTP worker via ``vgi_rpc.http.http_connect``.
|
|
584
662
|
|
|
@@ -724,6 +802,12 @@ class Client(CatalogClientMixin):
|
|
|
724
802
|
_logger.debug("http_connection_closed worker_index=%s", worker.worker_index)
|
|
725
803
|
return 0
|
|
726
804
|
|
|
805
|
+
if worker._tcp_ctx is not None:
|
|
806
|
+
# TCP transport — close the RPC proxy (and its socket).
|
|
807
|
+
worker._tcp_ctx.__exit__(None, None, None)
|
|
808
|
+
_logger.debug("tcp_connection_closed worker_index=%s", worker.worker_index)
|
|
809
|
+
return 0
|
|
810
|
+
|
|
727
811
|
if worker._pool_ctx is not None:
|
|
728
812
|
# Return to pool — pool handles subprocess lifecycle
|
|
729
813
|
worker._pool_ctx.__exit__(None, None, None)
|
|
@@ -805,6 +889,8 @@ class Client(CatalogClientMixin):
|
|
|
805
889
|
id_repr: Any = self._primary.proc.pid
|
|
806
890
|
elif self._primary._http_ctx is not None:
|
|
807
891
|
id_repr = f"http({self._base_url})"
|
|
892
|
+
elif self._primary._tcp_ctx is not None:
|
|
893
|
+
id_repr = f"tcp({self._tcp_host}:{self._tcp_port})"
|
|
808
894
|
else:
|
|
809
895
|
id_repr = "pooled"
|
|
810
896
|
_logger.debug("server_started id=%s", id_repr)
|
vgi/protocol.py
CHANGED
|
@@ -562,6 +562,13 @@ class MacroCreateRequest(ArrowSerializableDataclass):
|
|
|
562
562
|
ERROR/IGNORE/REPLACE).
|
|
563
563
|
parameter_default_values: One-row `RecordBatch` where column names are
|
|
564
564
|
parameter names and values are typed defaults; ``None`` if no defaults.
|
|
565
|
+
arguments_schema: Optional Arrow schema (serialized as IPC bytes) with one
|
|
566
|
+
nullable field per parameter, in ``parameters`` order. Each field's type
|
|
567
|
+
is the parameter's default value type when known (else null), and the
|
|
568
|
+
``vgi_doc`` field metadata key carries the parameter's description (UTF-8,
|
|
569
|
+
presence-only — omitted when undocumented). Mirrors the per-argument doc
|
|
570
|
+
channel functions expose. ``None`` when no per-parameter docs are
|
|
571
|
+
supplied. Built with ``vgi.argument_spec.macro_arguments_schema``.
|
|
565
572
|
transaction_opaque_data: Opaque DuckDB transaction handle (bytes); ``None``
|
|
566
573
|
when not inside a transaction.
|
|
567
574
|
"""
|
|
@@ -574,6 +581,7 @@ class MacroCreateRequest(ArrowSerializableDataclass):
|
|
|
574
581
|
definition: str
|
|
575
582
|
on_conflict: OnConflict
|
|
576
583
|
parameter_default_values: Annotated[pa.RecordBatch | None, ArrowType(pa.binary())] = None
|
|
584
|
+
arguments_schema: Annotated[pa.Schema | None, ArrowType(pa.binary())] = None
|
|
577
585
|
transaction_opaque_data: bytes | None = None
|
|
578
586
|
|
|
579
587
|
|
vgi/worker.py
CHANGED
|
@@ -1276,10 +1276,25 @@ class Worker:
|
|
|
1276
1276
|
"--unix",
|
|
1277
1277
|
help="Bind to this AF_UNIX socket path instead of stdin/stdout (mutex with --http).",
|
|
1278
1278
|
),
|
|
1279
|
+
# TCP launcher contract — mutually exclusive with --http/--unix.
|
|
1280
|
+
# Accepts ``[HOST:]PORT``; host defaults to loopback (127.0.0.1)
|
|
1281
|
+
# and ``PORT`` may be 0 to auto-select a free port. After binding
|
|
1282
|
+
# the worker prints TCP:<host>:<port> to stdout and self-shuts-down
|
|
1283
|
+
# after --idle-timeout seconds with zero connected clients. The raw
|
|
1284
|
+
# framing carries no auth/encryption — bind loopback only; use
|
|
1285
|
+
# --http for untrusted networks.
|
|
1286
|
+
tcp: str | None = typer.Option(
|
|
1287
|
+
None,
|
|
1288
|
+
"--tcp",
|
|
1289
|
+
help=(
|
|
1290
|
+
"Bind a TCP socket ([HOST:]PORT, host defaults to 127.0.0.1, PORT 0 "
|
|
1291
|
+
"auto-selects) instead of stdin/stdout (mutex with --http/--unix)."
|
|
1292
|
+
),
|
|
1293
|
+
),
|
|
1279
1294
|
idle_timeout: float = typer.Option(
|
|
1280
1295
|
300.0,
|
|
1281
1296
|
"--idle-timeout",
|
|
1282
|
-
help="Self-shutdown after N seconds idle when serving --unix.",
|
|
1297
|
+
help="Self-shutdown after N seconds idle when serving --unix/--tcp.",
|
|
1283
1298
|
),
|
|
1284
1299
|
http_threads: int | None = typer.Option( # noqa: B008
|
|
1285
1300
|
None,
|
|
@@ -1300,8 +1315,8 @@ class Worker:
|
|
|
1300
1315
|
log_format=log_format,
|
|
1301
1316
|
)
|
|
1302
1317
|
|
|
1303
|
-
if http
|
|
1304
|
-
raise typer.BadParameter("--http and --
|
|
1318
|
+
if sum(x for x in (http, unix is not None, tcp is not None)) > 1:
|
|
1319
|
+
raise typer.BadParameter("--http, --unix, and --tcp are mutually exclusive")
|
|
1305
1320
|
|
|
1306
1321
|
if http:
|
|
1307
1322
|
from vgi.serve import (
|
|
@@ -1358,6 +1373,47 @@ class Worker:
|
|
|
1358
1373
|
idle_timeout=effective_idle,
|
|
1359
1374
|
on_bound=_emit,
|
|
1360
1375
|
)
|
|
1376
|
+
elif tcp is not None:
|
|
1377
|
+
# TCP launcher path. Bind to [HOST:]PORT, print
|
|
1378
|
+
# TCP:<host>:<port> on stdout (mirrors run_server's
|
|
1379
|
+
# cross-language discovery contract), idle-shutdown after
|
|
1380
|
+
# idle_timeout seconds.
|
|
1381
|
+
from vgi_rpc.rpc import serve_tcp
|
|
1382
|
+
|
|
1383
|
+
from vgi.serve import _maybe_init_sentry, _resolve_otel_config
|
|
1384
|
+
|
|
1385
|
+
if ":" in tcp:
|
|
1386
|
+
host_part, _, port_part = tcp.rpartition(":")
|
|
1387
|
+
tcp_host = host_part or "127.0.0.1"
|
|
1388
|
+
else:
|
|
1389
|
+
tcp_host, port_part = "127.0.0.1", tcp
|
|
1390
|
+
try:
|
|
1391
|
+
tcp_port = int(port_part)
|
|
1392
|
+
except ValueError:
|
|
1393
|
+
raise typer.BadParameter(f"--tcp expects [HOST:]PORT, got {tcp!r}") from None
|
|
1394
|
+
|
|
1395
|
+
_maybe_init_sentry()
|
|
1396
|
+
otel_config = _resolve_otel_config()
|
|
1397
|
+
worker = cls(quiet=quiet, log_level=effective_level)
|
|
1398
|
+
server = RpcServer(cls.protocol_class, worker, server_version=_get_vgi_version())
|
|
1399
|
+
if otel_config is not None:
|
|
1400
|
+
from vgi_rpc.otel import instrument_server
|
|
1401
|
+
|
|
1402
|
+
instrument_server(server, otel_config)
|
|
1403
|
+
worker._vgi_tracer = VgiTracer.create(otel_config)
|
|
1404
|
+
effective_idle = idle_timeout if idle_timeout > 0 else None
|
|
1405
|
+
|
|
1406
|
+
def _emit_tcp(bound_host: str, bound_port: int) -> None:
|
|
1407
|
+
print(f"TCP:{bound_host}:{bound_port}", flush=True)
|
|
1408
|
+
|
|
1409
|
+
serve_tcp(
|
|
1410
|
+
server,
|
|
1411
|
+
tcp_host,
|
|
1412
|
+
tcp_port,
|
|
1413
|
+
threaded=True,
|
|
1414
|
+
idle_timeout=effective_idle,
|
|
1415
|
+
on_bound=_emit_tcp,
|
|
1416
|
+
)
|
|
1361
1417
|
else:
|
|
1362
1418
|
from vgi.serve import _maybe_init_sentry, _resolve_otel_config
|
|
1363
1419
|
|
|
@@ -4438,6 +4494,7 @@ class Worker:
|
|
|
4438
4494
|
definition=request.definition,
|
|
4439
4495
|
on_conflict=request.on_conflict,
|
|
4440
4496
|
parameter_default_values=request.parameter_default_values,
|
|
4497
|
+
arguments_schema=request.arguments_schema,
|
|
4441
4498
|
)
|
|
4442
4499
|
|
|
4443
4500
|
def catalog_macro_drop(
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: vgi-python
|
|
3
|
-
Version: 0.8.
|
|
3
|
+
Version: 0.8.7
|
|
4
4
|
Summary: Vector Gateway Interface - Connect DuckDB to external programs via Apache Arrow
|
|
5
5
|
Project-URL: Homepage, https://query.farm
|
|
6
6
|
Project-URL: Repository, https://github.com/Query-farm/vgi-python
|
|
@@ -162,7 +162,7 @@ Requires-Dist: httpx>=0.24
|
|
|
162
162
|
Requires-Dist: platformdirs
|
|
163
163
|
Requires-Dist: pyarrow
|
|
164
164
|
Requires-Dist: typer>=0.9
|
|
165
|
-
Requires-Dist: vgi-rpc>=0.
|
|
165
|
+
Requires-Dist: vgi-rpc>=0.21.0
|
|
166
166
|
Provides-Extra: azure
|
|
167
167
|
Requires-Dist: azure-identity>=1.16.0; extra == 'azure'
|
|
168
168
|
Requires-Dist: pymssql>=2.3.0; extra == 'azure'
|
|
@@ -2,7 +2,7 @@ vgi/__init__.py,sha256=PRtFvXxhHEbY_0KVhyXIbGigZDYKHzMS-4gp0p6IJSQ,3414
|
|
|
2
2
|
vgi/_duckdb.py,sha256=YB5D7N3Bwg_xP6X8a5QlumtlAovSej1A1Go5XlNGVko,2162
|
|
3
3
|
vgi/_storage_profile.py,sha256=VkTsXojuE0tHEzurmteQSAiL1vI3CZSgYkL6D_h8GvE,5061
|
|
4
4
|
vgi/aggregate_function.py,sha256=vn9TjQEHxAKJl_xzQOzdj5TY_6LplcZjv06JkQMnUyo,25184
|
|
5
|
-
vgi/argument_spec.py,sha256=
|
|
5
|
+
vgi/argument_spec.py,sha256=i5VTJSVV5L-gqtyqXOJA_foLMRDo36WcMbcCjvnLyL0,21210
|
|
6
6
|
vgi/arguments.py,sha256=02tIMGIR_cRS73u-bsgpFERxhje-rnTokjBgGsm9pQA,67019
|
|
7
7
|
vgi/auth.py,sha256=3HD2zM-Mt0Ie-_HT5RorpND1OusUw2CPROjPNs7rgbo,1478
|
|
8
8
|
vgi/exceptions.py,sha256=oX_sZc9xGWi7Xf8cJQf89fX19i3ocDEj_V_76GINgBQ,7294
|
|
@@ -15,7 +15,7 @@ vgi/logging_config.py,sha256=zQdDuKL-bXwu0n6Pjyqga5SVIyQ25egL2xhV5hbv66k,3100
|
|
|
15
15
|
vgi/meta_worker.py,sha256=kG5USvnV58S7Wj_RR3W_xM0QlRhaN__m1zwCkA95QOo,29546
|
|
16
16
|
vgi/metadata.py,sha256=VTa625ang6lPgocY4voTOJ7IqET4gsKI4DS07Y53LiM,57914
|
|
17
17
|
vgi/otel.py,sha256=JlUDnk2c0UXSo_j1PJdS67Y--t55sXPg054ADuvHANc,15452
|
|
18
|
-
vgi/protocol.py,sha256
|
|
18
|
+
vgi/protocol.py,sha256=-SXv0vIj49wQ3uwwsnnm16yRp-5EweZpKNHwZgtEF5M,116761
|
|
19
19
|
vgi/protocol_version.txt,sha256=WYVJhIUxBN9cNT4vaBoV_HkkdC-aLkaMKa8kjc5FzgM,6
|
|
20
20
|
vgi/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
21
21
|
vgi/scalar_function.py,sha256=lPHidmcAo_AtItsGqU4wPJhWfa0r_vAjfY6ZjyaW2BQ,47888
|
|
@@ -27,13 +27,13 @@ vgi/table_buffering_function.py,sha256=O5TcIdqk8-YViCQCkb8bOevO-zhe3IoyzLgwXDO3C
|
|
|
27
27
|
vgi/table_filter_pushdown.py,sha256=zak3AuXLVw51vXew93i81fRReG1H8yr4XxCfRnnISj4,63961
|
|
28
28
|
vgi/table_function.py,sha256=_Ni1deyPaabnQJDQz9CUL4fXy79r_OVyN6ZuWTZ1lMQ,52215
|
|
29
29
|
vgi/table_in_out_function.py,sha256=Ouv02ubP-XsRdByIR0ZSagi6VbZfQ8G1e5QWpqlLqvY,15508
|
|
30
|
-
vgi/worker.py,sha256=
|
|
30
|
+
vgi/worker.py,sha256=t5OKx5mGU91zeV6ErOifeTQmOw16fTOc18jOSDbTDaA,198588
|
|
31
31
|
vgi/_test_fixtures/__init__.py,sha256=xQq-QQLk8USQ6TZHsPiPcZldNNUdcJ2gToXMPGzScLI,444
|
|
32
32
|
vgi/_test_fixtures/attach_options.py,sha256=YtNk1krDdKLnNVtX9yGkgS8XyzdOI0oXtNDbAV73Phg,11091
|
|
33
33
|
vgi/_test_fixtures/bad_enum.py,sha256=lIVemVWTM1JVOHut47Q71Czw-sEiMjfFiyZ15NDaWAk,2910
|
|
34
34
|
vgi/_test_fixtures/bad_protocol.py,sha256=L8kxafWZ-4Sd73F6EpCRo1kWVC-09qzof6OYRXazS_8,2495
|
|
35
35
|
vgi/_test_fixtures/cancellable.py,sha256=hetTRLyT4kkazPNcxAdfzj0pYzEmegMksamJbR0w3Ho,12151
|
|
36
|
-
vgi/_test_fixtures/catalog.py,sha256=
|
|
36
|
+
vgi/_test_fixtures/catalog.py,sha256=DuC9r0efwuG-uPdjFFGNMN-Egi2BP9bvDpc1f3uFffM,28106
|
|
37
37
|
vgi/_test_fixtures/http_server.py,sha256=GevITVo61H1Y8K6zWUJj5guB5Y_H6QFfgVtfzRB0EAA,16095
|
|
38
38
|
vgi/_test_fixtures/nest_tensor.py,sha256=UjjW9UwipYG3ehQpZOm4hdzsafMyvVc0ZKJCrqiZTPU,24471
|
|
39
39
|
vgi/_test_fixtures/orchard_catalog.py,sha256=xMknth9FsVs8-y6vQyIZqDfUhJ-susjpMSzOOhaZyxM,1638
|
|
@@ -41,7 +41,7 @@ vgi/_test_fixtures/simple_writable.py,sha256=CGmDBUY8kthauEm8eJN2lV72cJ9_TRxOAQC
|
|
|
41
41
|
vgi/_test_fixtures/table_in_out.py,sha256=7QckA3NJhYAYuSctcwZLul5yOM2V3KWvLuG_33K0B_w,50459
|
|
42
42
|
vgi/_test_fixtures/versioned.py,sha256=Itm-x_Zt9WDwLGT4Dl4VzU5GtFF4HkcaJEqg9ErB8As,5784
|
|
43
43
|
vgi/_test_fixtures/versioned_tables.py,sha256=KRllGGRrwH8JUtqH-tLHT1JL09rKN-EcEYZVeQdbaLs,22112
|
|
44
|
-
vgi/_test_fixtures/worker.py,sha256=
|
|
44
|
+
vgi/_test_fixtures/worker.py,sha256=m7y5C9meuiOR2iXKnpu7prlq8FX_Zx_b4_Y6b9cNN0I,71676
|
|
45
45
|
vgi/_test_fixtures/accumulate/__init__.py,sha256=4hYT8jqRoVHSjV9TB7v0Z1CMJtdLuPaDWSz4J2fvMDs,868
|
|
46
46
|
vgi/_test_fixtures/accumulate/worker.py,sha256=yal9m-GjKNKUdLOLtwkCyFkeHVv_nnpUjh8amwueT48,30163
|
|
47
47
|
vgi/_test_fixtures/aggregate/__init__.py,sha256=tjCVKdCuHlIAZL7uDi-o_q82oMieXsAyoKExesr-7a0,2156
|
|
@@ -98,14 +98,14 @@ vgi/_test_fixtures/writable/worker.py,sha256=nH8KSZqyKv1gqdKn-_OFVh3h02FbyE0NFQ2
|
|
|
98
98
|
vgi/catalog/__init__.py,sha256=SCpeP2TtPfhWhwaqK5qGmmtHCM2z-EL66OoCkyefy7c,2064
|
|
99
99
|
vgi/catalog/_descriptor_spec.py,sha256=iMqId2fSBqlZ9HU6ct5AkYUAxtRGG_MVTLClDC1WPUs,7673
|
|
100
100
|
vgi/catalog/attach_option.py,sha256=nLGxsfAFR_-NqDrw7v18dtkNNNQIYLr3fuhpVw4XhFc,1739
|
|
101
|
-
vgi/catalog/catalog_interface.py,sha256=
|
|
102
|
-
vgi/catalog/descriptors.py,sha256=
|
|
101
|
+
vgi/catalog/catalog_interface.py,sha256=J6eNB-TMIjakKp7wAPKGLubpjM0YwGeUteaYb3PF5dk,121950
|
|
102
|
+
vgi/catalog/descriptors.py,sha256=GrVrFwmyG7GVT4tF3yT7lr-ZcS-qrxFpnFHKw7khTBU,40437
|
|
103
103
|
vgi/catalog/duckdb_statistics.py,sha256=fARQupgq0fD46rDgxDXvdCFsgs-rvCOHhls7WXHmnFY,15615
|
|
104
104
|
vgi/catalog/secret_type.py,sha256=MKtAypBa3xXyr-NC5CHjdX1R00JEnuMtvgboFWC2T9o,3336
|
|
105
105
|
vgi/catalog/setting.py,sha256=06QfgaAR-0BKflIJ0du6PGqA5BPMdrkwr6u7f4nddII,1846
|
|
106
106
|
vgi/catalog/storage.py,sha256=DhngzywbhQUfLF7NjFyiPp4Sw2ovOhcUXAuW3rkBQD8,11935
|
|
107
107
|
vgi/client/__init__.py,sha256=6LPHqlcNFy77apDNXUntgOVLhuXfpJyZd6TI7R7QfbY,2122
|
|
108
|
-
vgi/client/catalog_mixin.py,sha256=
|
|
108
|
+
vgi/client/catalog_mixin.py,sha256=fH_D756rzQZHi6UKbeVbWCIScVUqcGw8Dfp8nD36dao,46600
|
|
109
109
|
vgi/client/cli.py,sha256=KfoqIiMXiUNAdYxRp-O6BOi3FA1IsesSBb_XeZGWFSo,22287
|
|
110
110
|
vgi/client/cli_catalog.py,sha256=twjlhHGl7n2mNN4jc7DnDRQr-Zj9KLAF2eATIQnITHQ,5577
|
|
111
111
|
vgi/client/cli_schema.py,sha256=FTkf1moDn_dWFMPDxJqaNFhc2oyrLEutP8xC60EbPIk,7556
|
|
@@ -113,7 +113,7 @@ vgi/client/cli_table.py,sha256=hxASTkLZy69z4qoYhpIqrV9ZmZdPLKIzhmHy-hB9qqE,26145
|
|
|
113
113
|
vgi/client/cli_transaction.py,sha256=TDW0ZrBy8XM_eYSkYk5ewEsnozfzDJOlopd66Fm7OOE,3142
|
|
114
114
|
vgi/client/cli_utils.py,sha256=kilyfxRgFdW63IYQU6xsVls1wIcRjR-ZP63qu0FdXLI,16223
|
|
115
115
|
vgi/client/cli_view.py,sha256=p2wiJAuaEv-8qEgWxiNKgzA9qLdYZ87XCJwkxx5c-YU,8353
|
|
116
|
-
vgi/client/client.py,sha256=
|
|
116
|
+
vgi/client/client.py,sha256=Pb5qLfydDEnrTW-yCUDSGkerGJesCeHQQbFNTZpxN24,97270
|
|
117
117
|
vgi/http/__init__.py,sha256=hlOwOVcoZqmEKVGk7ganOdr5ryRSpEhLBF9sRD7BkYc,608
|
|
118
118
|
vgi/http/demo_storage.py,sha256=830s-H61thozC3eEuqdnwCpYFfvoJRq9vjyuXa5OURo,8769
|
|
119
119
|
vgi/http/worker_page.py,sha256=Eq70-hPfG2PIuhFjEDMf-BxF7Fdjcb4dN2SploH2jWE,54577
|
|
@@ -122,8 +122,8 @@ vgi/transactor/_duckdb_compat.py,sha256=sXVZ9JLKAQyGR1BjWczSwdQEavtr-TcZPoVZZnTr
|
|
|
122
122
|
vgi/transactor/client.py,sha256=7DTeMksogsw6ANjQjGOPpKYrV76rg4_kGjktMJf54jg,4486
|
|
123
123
|
vgi/transactor/protocol.py,sha256=Mtmll3CdrLFL1B4NY4NZUTO_yi3PT0qhvMQnzapuBWU,4780
|
|
124
124
|
vgi/transactor/server.py,sha256=WpIqjzy2Mebw17Jui4-w7vyGEo9pD-pEZJG-3Ob1Sk8,29705
|
|
125
|
-
vgi_python-0.8.
|
|
126
|
-
vgi_python-0.8.
|
|
127
|
-
vgi_python-0.8.
|
|
128
|
-
vgi_python-0.8.
|
|
129
|
-
vgi_python-0.8.
|
|
125
|
+
vgi_python-0.8.7.dist-info/METADATA,sha256=tNHKhPZbF3jkRYNokolq5dGV1pj1iLcqN2AedbfdK2I,24725
|
|
126
|
+
vgi_python-0.8.7.dist-info/WHEEL,sha256=mffPy8wBnZQn2VnJUU5jE99KsxaSfiyMHV9Yt0aLVxs,87
|
|
127
|
+
vgi_python-0.8.7.dist-info/entry_points.txt,sha256=3Kz1vgodw3pOL_xjtSyDB55-ZRy-U2X-X_Bdr582x0Q,165
|
|
128
|
+
vgi_python-0.8.7.dist-info/licenses/LICENSE,sha256=pbJb4zZasP6n5ifEV81wFu017TarjydaYVmGbHcehtY,6103
|
|
129
|
+
vgi_python-0.8.7.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|