Skip to content

Commit 8e694bf

Browse files
rustyconoverclaude
andcommitted
Move LLM examples out, drive mypy to zero, sweep schema_utils
- Relocated vgi/examples/{summarize,distill}.py to ~/Development/vgi-anthropic/ and dropped the [llm] extra; they were Anthropic-API experiments and the bulk of the prior mypy noise. - Added vgi/transactor/_duckdb_compat.py — Protocol+cast shim so the VGI fork's DuckDBPyConnection.subcursor() type-checks without polluting the upstream stubs. - Drove mypy vgi/ to zero errors: typed heterogeneous Field/Array lists with Any (matching house style in schema_utils/arguments), tightened None narrowings (mask: ChunkedArray[BooleanScalar] | BooleanArray), fixed varargs annotations in aggregate.py to list[pa.Array[Any]], added type:ignore[override] on the partial schema_contents override in versioned_tables. - Swept ~25 pa.schema([pa.field(...), ...]) literals to vgi.schema_utils schema(name=type, ...) — eliminates 7 # type: ignore[arg-type] comments and ~150 lines of boilerplate. Field-level metadata and comprehension-built schemas use the (type, metadata) tuple and schema(mapping) forms respectively. Skipped pa.schema([]) empty, pa.schema([field]) with dynamic name, and the one transactor site that combines a field prepend, schema spread, and schema-level metadata. - DRY follow-ups: shared _ON_CANCEL_CAVEATS docstring constant between TableFunctionGenerator and TableInOutGenerator; _append_cancel_probe helper in cancellable.py; start_http_worker helper in tests/_http_fixtures.py used by both http_worker and client_transport fixtures. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent 7ec877b commit 8e694bf

30 files changed

Lines changed: 883 additions & 1139 deletions

pyproject.toml

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -28,9 +28,6 @@ azure = [
2828
"pymssql>=2.3.0",
2929
"azure-identity>=1.16.0",
3030
]
31-
llm = [
32-
"anthropic>=0.40.0",
33-
]
3431
dev = [
3532
"mypy",
3633
"pyarrow-stubs",

tests/_http_fixtures.py

Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
"""Shared helpers for spawning ``vgi-example-http`` as a subprocess.
2+
3+
Lifted from ``tests/test_http_demo_storage.py`` so that conformance tests and
4+
other HTTP-dependent tests can reuse a single lifecycle.
5+
"""
6+
7+
from __future__ import annotations
8+
9+
import os
10+
import socket
11+
import subprocess
12+
import sys
13+
import time
14+
from collections.abc import Iterator, Sequence
15+
from contextlib import ExitStack, contextmanager
16+
17+
18+
def free_port() -> int:
19+
"""Allocate an available localhost TCP port."""
20+
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
21+
s.bind(("127.0.0.1", 0))
22+
return int(s.getsockname()[1])
23+
24+
25+
@contextmanager
26+
def run_example_http_server(
27+
*,
28+
port: int,
29+
extra_args: Sequence[str] = (),
30+
env: dict[str, str] | None = None,
31+
) -> Iterator[None]:
32+
"""Run ``vgi-example-http`` in a subprocess on ``port``.
33+
34+
``extra_args`` are appended verbatim — e.g. ``("--demo-storage",
35+
"--externalize-threshold-bytes", "4096")``.
36+
"""
37+
cmd = [
38+
sys.executable,
39+
"-m",
40+
"vgi.examples.http_server",
41+
"--host",
42+
"127.0.0.1",
43+
"--port",
44+
str(port),
45+
*extra_args,
46+
]
47+
proc_env = os.environ.copy()
48+
if env is not None:
49+
proc_env.update(env)
50+
proc = subprocess.Popen(
51+
cmd,
52+
env=proc_env,
53+
stdout=subprocess.PIPE,
54+
stderr=subprocess.PIPE,
55+
text=True,
56+
)
57+
try:
58+
yield
59+
finally:
60+
proc.terminate()
61+
try:
62+
proc.wait(timeout=10)
63+
except subprocess.TimeoutExpired:
64+
proc.kill()
65+
proc.wait(timeout=5)
66+
67+
if proc.returncode not in (0, -15):
68+
stderr = proc.stderr.read() if proc.stderr is not None else ""
69+
raise RuntimeError(f"example HTTP worker exited with code {proc.returncode}: {stderr}")
70+
71+
72+
def start_http_worker(
73+
stack: ExitStack,
74+
*,
75+
extra_args: Sequence[str] = (),
76+
env: dict[str, str] | None = None,
77+
) -> str:
78+
"""Allocate a port, start ``vgi-example-http`` under ``stack``, return base URL."""
79+
port = free_port()
80+
base_url = f"http://127.0.0.1:{port}"
81+
stack.enter_context(run_example_http_server(port=port, extra_args=tuple(extra_args), env=env))
82+
wait_for_http_server(base_url)
83+
return base_url
84+
85+
86+
def wait_for_http_server(base_url: str, timeout: float = 30.0) -> None:
87+
"""Block until the HTTP server responds to a capabilities probe."""
88+
from vgi_rpc.http import http_capabilities
89+
90+
deadline = time.time() + timeout
91+
while time.time() < deadline:
92+
try:
93+
http_capabilities(base_url=base_url)
94+
return
95+
except Exception:
96+
time.sleep(0.25)
97+
raise TimeoutError(f"Timed out waiting for HTTP server at {base_url}")

tests/conftest.py

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,91 @@ def example_worker() -> str:
7474
return "vgi-example-worker"
7575

7676

77+
@pytest.fixture
78+
def http_worker() -> Any:
79+
"""Start ``vgi-example-http`` on a free port, yield its base URL, tear it down.
80+
81+
Usage::
82+
83+
def test_something(http_worker):
84+
base_url = http_worker() # defaults
85+
base_url = http_worker(extra_args=[...]) # pass flags
86+
87+
Implemented as a factory so individual tests can request different server
88+
flags (e.g. ``--demo-storage``) without proliferating fixtures.
89+
"""
90+
from contextlib import ExitStack
91+
92+
from tests._http_fixtures import start_http_worker
93+
94+
pytest.importorskip("vgi_rpc.http")
95+
96+
stack = ExitStack()
97+
98+
def _start(*, extra_args: list[str] | None = None, env: dict[str, str] | None = None) -> str:
99+
return start_http_worker(stack, extra_args=tuple(extra_args or ()), env=env)
100+
101+
try:
102+
yield _start
103+
finally:
104+
stack.close()
105+
106+
107+
# Keys used to identify transport modes in conformance tests. Keeping the
108+
# literal values here (rather than inside the fixture) makes it easy for
109+
# individual tests to opt out with ``@pytest.mark.parametrize("client_transport",
110+
# ["subprocess-pooled"], indirect=True)``.
111+
_CLIENT_TRANSPORT_MODES = ["subprocess-pooled", "subprocess-direct", "http"]
112+
113+
114+
@pytest.fixture(params=_CLIENT_TRANSPORT_MODES)
115+
def client_transport(request: pytest.FixtureRequest, example_worker: str) -> Any:
116+
"""Parametrized factory that builds a configured ``Client`` for each transport.
117+
118+
Yields a callable ``make_client()`` -> ``Client``. Callers must enter the
119+
returned client as a context manager.
120+
121+
Modes:
122+
subprocess-pooled: Pool-backed subprocess (the default path).
123+
subprocess-direct: ``pool=None`` — direct Popen management.
124+
http: ``Client.from_http(base_url)`` backed by a per-test
125+
``vgi-example-http`` subprocess. Skips if the HTTP transport
126+
isn't wired yet.
127+
"""
128+
from vgi.client.client import _HTTP_TRANSPORT_READY, Client, _default_pool
129+
130+
mode = request.param
131+
132+
http_base_url: str | None = None
133+
http_stack: Any | None = None
134+
135+
def _make() -> Client:
136+
nonlocal http_base_url, http_stack
137+
if mode == "subprocess-pooled":
138+
return Client(example_worker, pool=_default_pool)
139+
if mode == "subprocess-direct":
140+
return Client(example_worker, pool=None)
141+
if mode == "http":
142+
if not _HTTP_TRANSPORT_READY:
143+
pytest.skip("Client HTTP transport arrives in Phase 2 of whimsical-mccarthy plan")
144+
pytest.importorskip("vgi_rpc.http")
145+
from contextlib import ExitStack
146+
147+
from tests._http_fixtures import start_http_worker
148+
149+
if http_base_url is None:
150+
http_stack = ExitStack()
151+
http_base_url = start_http_worker(http_stack)
152+
return Client.from_http(http_base_url)
153+
raise AssertionError(f"unknown transport mode {mode!r}")
154+
155+
try:
156+
yield _make
157+
finally:
158+
if http_stack is not None:
159+
http_stack.close()
160+
161+
77162
@pytest.fixture
78163
def simple_batches() -> list[pa.RecordBatch]:
79164
"""Create simple test batches with integer and string columns."""

0 commit comments

Comments
 (0)