From 55f7da3e74722635d637889e69e12310a2bce7ba Mon Sep 17 00:00:00 2001 From: Rusty Conover Date: Tue, 23 Jun 2026 21:41:17 -0400 Subject: [PATCH] ci: run SQL suite over subprocess + http + unix transports Parameterize ci/run-integration.sh by a TRANSPORT env (subprocess default, plus http and unix), and turn the integration job into a transport x os matrix so the haybarn SQL suite runs over all three VGI transports in CI. - run-integration.sh: keep the offline mocking (VGI_GOOGLE_MOCK=1 + a temp VGI_GOOGLE_DISCOVERY_DIR built from tests.mock_google) and export both so the booted worker inherits them for ALL transports. For http, inject `INSTALL httpfs FROM core; LOAD httpfs;` into the staged tests and boot the worker with `--http --port 0 --port-file`; for unix, boot with `--unix`. One cleanup() trap captures $? first, then removes the discovery dir AND kills the worker. Add a silent-skip guard (tee + PIPESTATUS) that fails the leg unless `All tests passed (N>0 assertions` and nothing was skipped. - pyproject.toml: add an `http` extra (vgi-python[http]) for waitress. - google_worker.py: PEP 723 header now depends on vgi-python[http]. - uv.lock: relocked with the http extra. - ci.yml: integration job is now transport: [subprocess, http, unix] x os: [ubuntu, macos], sets WORKER_CMD, `uv sync --frozen --extra http`. - ci/README.md: document the transport matrix, offline mocking across all transports, httpfs-on-http, the silent-skip guard, and the externalized pagination cursor (works over HTTP unchanged). The worker's externalized _ScanState cursor already round-trips over HTTP, so the full suite (including the pageToken page-boundary round-trip) is GREEN over all three transports with no worker changes. Co-Authored-By: Claude Opus 4.8 (1M context) --- .github/workflows/ci.yml | 28 ++++-- ci/README.md | 132 ++++++++++++++++++++----- ci/run-integration.sh | 208 ++++++++++++++++++++++++++++++++++++--- google_worker.py | 2 +- pyproject.toml | 7 ++ uv.lock | 131 +++++++++++++++++++++++- 6 files changed, 461 insertions(+), 47 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 32e96ad..44c1036 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -89,11 +89,22 @@ jobs: GH_TOKEN: ${{ github.token }} integration: - name: End-to-end SQL on ${{ matrix.os }} + name: SQL E2E (${{ matrix.transport }}) on ${{ matrix.os }} needs: resolve-haybarn strategy: fail-fast: false matrix: + # Run the SAME sqllogictest suite over every VGI transport. The vgi + # extension picks the transport from the ATTACH LOCATION string that + # run-integration.sh builds per $TRANSPORT. Offline mocking + # (VGI_GOOGLE_MOCK=1 + a temp VGI_GOOGLE_DISCOVERY_DIR) is exported by + # the script and inherited by the worker for ALL transports — no live + # Google, no separate mock server: + # subprocess : `.venv/bin/python google_worker.py` (stdio) + # http : `http://127.0.0.1:` (worker booted with --http) + # unix : `unix://` (worker booted with --unix) + os: [ubuntu-latest, macos-latest] + transport: [subprocess, http, unix] include: - { os: ubuntu-latest, asset: haybarn_unittest-linux-amd64.zip } - { os: macos-latest, asset: haybarn_unittest-osx-arm64.zip } @@ -101,6 +112,8 @@ jobs: defaults: run: shell: bash + env: + TRANSPORT: ${{ matrix.transport }} steps: - uses: actions/checkout@v6 @@ -110,8 +123,10 @@ jobs: - name: Set up Python 3.13 run: uv python install 3.13 - - name: Install the worker (from the lockfile) - run: uv sync --frozen --python 3.13 + - name: Install the worker (from the lockfile, with the http extra) + # The `http` extra pulls in waitress so the worker can serve `--http`. + # Harmless for the subprocess/unix legs; required for the http leg. + run: uv sync --frozen --python 3.13 --extra http - name: Download haybarn-unittest run: | @@ -130,11 +145,12 @@ jobs: # invoking the runner, so relative paths would not resolve. The worker # runs from the synced .venv (deps resolved from PyPI via the lockfile); # plain `.venv/bin/python` ignores the PEP 723 header. run-integration.sh - # enables the mock transport (VGI_GOOGLE_MOCK=1) + offline discovery dir. + # enables the mock transport (VGI_GOOGLE_MOCK=1) + offline discovery dir + # for every transport and (for http/unix) boots the worker from WORKER_CMD. UNITTEST="$PWD/$(find hb -name 'haybarn-unittest' -type f | head -1)" chmod +x "$UNITTEST" echo "HAYBARN_UNITTEST=$UNITTEST" >> "$GITHUB_ENV" - echo "VGI_GOOGLE_WORKER=$PWD/.venv/bin/python $PWD/google_worker.py" >> "$GITHUB_ENV" + echo "WORKER_CMD=$PWD/.venv/bin/python $PWD/google_worker.py" >> "$GITHUB_ENV" - - name: Run extension integration suite + - name: Run extension integration suite (${{ matrix.transport }}) run: ci/run-integration.sh diff --git a/ci/README.md b/ci/README.md index 7b1db87..c7e7e4c 100644 --- a/ci/README.md +++ b/ci/README.md @@ -1,7 +1,7 @@ -# CI: the vgi-calendar worker integration suite +# CI: the vgi-google worker integration suite [`.github/workflows/ci.yml`](../.github/workflows/ci.yml) runs the unit tests -and this repo's sqllogictest suite (`test/sql/*.test`) against the vgi-calendar +and this repo's sqllogictest suite (`test/sql/*.test`) against the vgi-google VGI worker through the **real DuckDB `vgi` extension** on every push / PR. ## How it works (no C++ build) @@ -11,33 +11,119 @@ Rather than building the vgi DuckDB extension from source, CI drives a runner, published in Haybarn's releases) and installs the **signed** `vgi` extension from the Haybarn community channel: -1. **Install the worker** — `uv sync --frozen` into a venv. `calendar_worker.py` - is a self-contained PEP 723 stdio worker the extension can spawn via - `uv run calendar_worker.py`. -2. **Download the runner** — the matching `haybarn_unittest-*` asset per - platform from the latest Haybarn release. -3. **Preprocess** — the standalone runner links none of the extensions the - tests gate on, so [`preprocess-require.awk`](preprocess-require.awk) rewrites +1. **Install the worker** — `uv sync --frozen --extra http` into a venv. + `google_worker.py` is a self-contained PEP 723 stdio worker the extension can + spawn via `uv run google_worker.py`. +2. **Download the runner** — the matching `haybarn_unittest-*` asset per platform + from the latest Haybarn release. +3. **Preprocess** — [`preprocess-require.awk`](preprocess-require.awk) rewrites each `require ` into an explicit signed `INSTALL FROM - {community,core}; LOAD ;`. These tests skip `require vgi` (haybarn - silently SKIPs it) and `LOAD vgi;` directly, so the awk also injects an - `INSTALL vgi FROM community;` right before each bare `LOAD vgi;`. `require-env` - and everything else pass through untouched. + {community,core}; LOAD ;`, and injects `INSTALL vgi FROM community;` + before each bare `LOAD vgi;` (haybarn silently SKIPs `require vgi`, so the + tests `LOAD vgi;` directly). `require-env` and everything else pass through. 4. **Run** — [`run-integration.sh`](run-integration.sh) stages the preprocessed - tree, points `VGI_CALENDAR_WORKER` at `uv run calendar_worker.py`, warms the - extension cache once, then runs the suite in a single `haybarn-unittest` - invocation. Any failed assertion exits non-zero and fails the job. + tree, resolves `VGI_GOOGLE_WORKER` (the ATTACH `LOCATION`) per `$TRANSPORT`, + warms the extension cache once, then runs the suite in a single + `haybarn-unittest` invocation. Any failed assertion fails the job. + +## Offline mocking (all transports) + +The worker is run with **`VGI_GOOGLE_MOCK=1`**, which installs the canned test +transport (`tests/mock_google.py`): its adapters build from static discovery +docs and are served deterministic, paginated responses — no live Google, no +credentials. `run-integration.sh` also builds a temp directory of static +discovery artifacts (`apis.list.json` + `drive.v3.json` from +`tests.mock_google.DRIVE_DOC`) and exports it via **`VGI_GOOGLE_DISCOVERY_DIR`** +so `google_apis` / `google_methods` resolve offline too. + +Crucially, both env vars are **exported by the script** before it boots the +worker, so they are inherited by the worker process for **every transport** +(subprocess, http, unix). No separate mock server is needed — the mock lives +inside the worker itself. The authoritative SQL suite therefore drives the +*real* worker end to end (real ATTACH, real bind/init/process, real pageToken +scan-state round-trips) against deterministic fixtures, with no keys, no cost, +and no real network egress. + +## Transport matrix (subprocess | http | unix) + +The same `test/sql/*.test` suite is run over all three VGI transports — the +extension picks the transport from the `LOCATION` string the `.test` files +`ATTACH`, and `run-integration.sh` builds that string from `$TRANSPORT`: + +| `TRANSPORT` | `VGI_GOOGLE_WORKER` (LOCATION) | How the worker is reached | +|--------------|-------------------------------------------|---------------------------| +| `subprocess` | `.venv/bin/python google_worker.py` | extension spawns the worker per query; Arrow IPC over stdin/stdout (default) | +| `http` | `http://127.0.0.1:` | harness boots `google_worker.py --http --port 0 --port-file `, waits for the port-file, then ATTACHes that URL | +| `unix` | `unix:///tmp/google-.sock` | harness boots `google_worker.py --unix `, waits for the socket, then ATTACHes it | + +The CI `integration` job is a `transport: [subprocess, http, unix]` × `os` +matrix; each leg runs `ci/run-integration.sh` with `TRANSPORT=`. Run a single +transport locally with e.g. `TRANSPORT=http ci/run-integration.sh`. + +### Port / readiness discovery + +- **http**: the worker writes its auto-selected port to `--port-file` + atomically, so the harness watches for that file (not stdout). Boot line: + `google_worker.py --http --port 0 --port-file `. +- **unix**: the worker binds the socket and prints `UNIX:`; the + harness polls for the socket file (`test -S`). Boot line: + `google_worker.py --unix `. + +Both out-of-band server processes run with cwd = the repo root (so the worker +resolves `tests.mock_google` / `vgi_google`), inherit the +`VGI_GOOGLE_MOCK`/`VGI_GOOGLE_DISCOVERY_DIR` exports, and are trap-killed on exit. + +### HTTP transport needs the `httpfs` extension (resolved, not gated) + +The vgi extension implements HTTP transport on top of DuckDB's **httpfs** +extension, so an `http://` ATTACH binds with `VGI HTTP transport requires the +httpfs extension` unless httpfs is loaded first. This is a **dependency**, not a +protocol limitation, so we resolve it: the http leg injects a signed `INSTALL +httpfs FROM core; LOAD httpfs;` into each staged `.test` (after the awk-injected +`LOAD vgi;`). The leg also needs the worker's `http` extra (waitress) — +`pyproject.toml` ships an `http` extra (`vgi-python[http]`), the PEP 723 header +in `google_worker.py` lists it, and CI runs `uv sync --frozen --extra http`. + +> **Sharp edge — the runner silently SKIPs HTTP errors.** The haybarn/DuckDB +> sqllogictest runner's default skip list skips any statement whose error +> contains `"HTTP"` or `"Unable to connect"`, so a broken http setup reports +> "All tests were skipped" — a green-looking **fake pass**. +> `run-integration.sh` fails the leg unless the runner reports `All tests passed +> (N assertions …)` with N > 0 and zero skips. + +### Pagination over HTTP (externalized cursor — no gate) + +The curated table functions (`google_drive`, `google_calendar`, +`google_youtube`, `google_sheet`) and the generic `google_call` are +streaming/paging: each tick fetches ONE Google page (following +`nextPageToken`), emits it, and advances. Streaming table functions run fine +over the **stateless** HTTP transport **because the cursor is externalized**: +the per-scan position lives in a plain-serializable +`_ScanState(ArrowSerializableDataclass)` (`cursor` = Google's `nextPageToken`, +plus `emitted`/`started`/`done`) that the framework round-trips through its +continuation token on every `process()` tick — and so across batch boundaries +under HTTP. So the http leg runs the **full** suite including the centerpiece +pageToken round-trip (`google_drive(count := 5, page_size := 1)` returning five +distinct `file0..file4` rows across five paged ticks) — nothing is gated. (This +is the same "externalize the scan position into the serialized state" pattern as +the vgi-cve cursor fix; the paged functions are also `@init_single_worker`, so +parallel scan instances never re-emit and duplicate rows.) + +### Per-transport status + +- **subprocess**: GREEN — 31 assertions. +- **http**: GREEN — 33 assertions (31 + the injected httpfs INSTALL/LOAD). Full + suite incl. the pageToken scan-state round-trip across page boundaries. +- **unix**: GREEN — 31 assertions. ## Run it locally ```bash -uv sync --python 3.13 # install the worker + deps -# point HAYBARN_UNITTEST at a haybarn-unittest binary (or a local DuckDB -# `unittest` built with the vgi extension), and the worker at the stdio command: +uv sync --python 3.13 --extra http HAYBARN_UNITTEST=/path/to/haybarn-unittest \ -VGI_CALENDAR_WORKER="uv run --python 3.13 calendar_worker.py" \ - ci/run-integration.sh +WORKER_CMD="uv run --python 3.13 google_worker.py" \ + TRANSPORT=subprocess ci/run-integration.sh # or TRANSPORT=http / TRANSPORT=unix ``` -Or use the Makefile target `make test-sql`, which installs `haybarn-unittest` -as a uv tool and points the worker at `uv run --python 3.13 calendar_worker.py`. +`TRANSPORT` defaults to `subprocess`, and `WORKER_CMD` defaults to +`uv run --python 3.13 /google_worker.py`. diff --git a/ci/run-integration.sh b/ci/run-integration.sh index 53a33a0..437fd82 100755 --- a/ci/run-integration.sh +++ b/ci/run-integration.sh @@ -5,25 +5,43 @@ # VGI worker, using a prebuilt standalone `haybarn-unittest` and the signed # community `vgi` extension — no C++ build from source. See ci/README.md. # -# The worker is launched with VGI_GOOGLE_MOCK=1 so its adapters build from static -# discovery docs and are served canned, paginated responses (tests/mock_google.py). -# A temp dir of static discovery artifacts is exported via VGI_GOOGLE_DISCOVERY_DIR -# so google_apis / google_methods also run offline — nothing touches a live -# Google API. +# OFFLINE MOCKING (all transports): the worker is run with VGI_GOOGLE_MOCK=1 so +# its adapters build from static discovery docs and are served canned, paginated +# responses (tests/mock_google.py). A temp dir of static discovery artifacts is +# exported via VGI_GOOGLE_DISCOVERY_DIR so google_apis / google_methods also run +# offline — nothing touches a live Google API. These two env exports are set by +# THIS script, so they are inherited by the worker process for EVERY transport +# (subprocess, http, unix) — no separate mock server is needed. +# +# The SAME suite is exercised over three VGI transports, selected by $TRANSPORT. +# The vgi extension picks the transport from the LOCATION string the .test files +# ATTACH (`${VGI_GOOGLE_WORKER}`): +# +# subprocess : a bare stdio command (the worker) — the extension spawns the +# worker per query, Arrow IPC over stdin/stdout. Default. +# http : the worker is started out-of-band in `--http` mode on an auto +# port; LOCATION becomes `http://127.0.0.1:`. +# unix : the worker is started out-of-band on an AF_UNIX socket; +# LOCATION becomes `unix://`. # # Required environment: -# HAYBARN_UNITTEST path to the haybarn-unittest binary -# VGI_GOOGLE_WORKER worker LOCATION the .test files ATTACH (a stdio command) +# HAYBARN_UNITTEST path to the haybarn-unittest binary +# TRANSPORT subprocess | http | unix (default: subprocess) +# WORKER_CMD the stdio command that runs the worker. Used directly as +# the LOCATION for subprocess, and as the process booted +# for http/unix. Defaults to +# `uv run --python 3.13 /google_worker.py`. # Optional: -# STAGE scratch dir for the preprocessed test tree (default: mktemp) +# STAGE scratch dir for the preprocessed test tree (default: mktemp) set -euo pipefail : "${HAYBARN_UNITTEST:?path to the haybarn-unittest binary}" -: "${VGI_GOOGLE_WORKER:?worker LOCATION (stdio command or http:// URL)}" HERE="$(cd "$(dirname "$0")" && pwd)" REPO="$(cd "$HERE/.." && pwd)" STAGE="${STAGE:-$(mktemp -d)}" +TRANSPORT="${TRANSPORT:-subprocess}" +WORKER_CMD="${WORKER_CMD:-uv run --python 3.13 $REPO/google_worker.py}" echo "Staging preprocessed tests into $STAGE ..." mkdir -p "$STAGE/test/sql" @@ -31,12 +49,13 @@ for f in "$REPO"/test/sql/*.test; do awk -f "$HERE/preprocess-require.awk" "$f" > "$STAGE/test/sql/$(basename "$f")" done +# --------------------------------------------------------------------------- # Build the static discovery dir the offline discovery helpers read (the same # artifacts scripts/run_sql_e2e.py writes), from the repo root so -# `tests.mock_google` imports. +# `tests.mock_google` imports. Exported (with VGI_GOOGLE_MOCK=1) for ALL +# transports — the worker we boot below inherits both. +# --------------------------------------------------------------------------- DISCO="$(mktemp -d)" -cleanup() { rm -rf "$DISCO"; } -trap cleanup EXIT ( cd "$REPO" && DISCO="$DISCO" uv run --no-sync python - <<'PY' import json, os from pathlib import Path @@ -57,6 +76,140 @@ PY export VGI_GOOGLE_MOCK=1 export VGI_GOOGLE_DISCOVERY_DIR="$DISCO" +# --------------------------------------------------------------------------- +# Per-transport: resolve VGI_GOOGLE_WORKER (the LOCATION) and, for the +# out-of-band transports, boot the worker server + arrange trap-cleanup. +# --------------------------------------------------------------------------- +SERVER_PID="" +SOCK="" +PORT_FILE="" + +cleanup() { + # Capture the real exit status FIRST: an EXIT trap whose last command returns + # non-zero (e.g. a short-circuited `[[ -n "" ]] && …` on the subprocess/unix + # legs where nothing needs cleaning) would otherwise become the script's exit + # status under `set -e` and fail an already-passing run. Then clean BOTH the + # discovery dir AND any out-of-band worker. + local rc=$? + if [[ -n "$SERVER_PID" ]]; then + kill "$SERVER_PID" 2>/dev/null || true + wait "$SERVER_PID" 2>/dev/null || true + fi + if [[ -n "$SOCK" ]]; then rm -f "$SOCK"; fi + if [[ -n "$PORT_FILE" ]]; then rm -f "$PORT_FILE"; fi + rm -rf "$DISCO" + return "$rc" +} +trap cleanup EXIT + +case "$TRANSPORT" in + subprocess) + export VGI_GOOGLE_WORKER="$WORKER_CMD" + ;; + + http) + # The vgi extension's HTTP transport is implemented on top of DuckDB's + # httpfs extension, so an `http://` ATTACH binds with + # "Binder Error: VGI HTTP transport requires the httpfs extension." + # unless httpfs is loaded first. (The haybarn sqllogictest runner's default + # skip list swallows any error containing "HTTP", so without this the whole + # suite would silently SKIP rather than fail — a fake pass.) The .test files + # are transport-agnostic; inject a signed `INSTALL httpfs FROM core; LOAD + # httpfs;` right after the awk-injected `LOAD vgi;` in each staged file, so + # httpfs is present only when we actually run over HTTP. + echo "Injecting httpfs load into staged tests (HTTP transport needs it) ..." + for sf in "$STAGE"/test/sql/*.test; do + awk ' + { print } + /^LOAD[ \t]+vgi[ \t]*;[ \t]*$/ && !done { + print ""; + print "statement ok"; + print "INSTALL httpfs FROM core;"; + print ""; + print "statement ok"; + print "LOAD httpfs;"; + done = 1 + } + ' "$sf" > "$sf.tmp" && mv "$sf.tmp" "$sf" + done + + # Boot the worker in HTTP mode on an auto-selected port. GoogleWorker.main() + # writes the chosen port to --port-file atomically (tmp + rename), so we + # watch for the file to appear rather than parsing stdout. HTTP mode needs + # the `http` extra (waitress); CI runs `uv sync --extra http` and the PEP 723 + # headers list `vgi-python[http]`. The worker inherits VGI_GOOGLE_MOCK=1 + + # VGI_GOOGLE_DISCOVERY_DIR exported above, so it serves the canned offline + # responses for the life of the process. + PORT_FILE="$(mktemp -u "${TMPDIR:-/tmp}/google-port.XXXXXX")" + LOG_FILE="${TMPDIR:-/tmp}/google-http-server.log" + echo "Starting HTTP worker: $WORKER_CMD --http --port 0 --port-file $PORT_FILE" + # cwd = repo root so the worker resolves tests.mock_google + vgi_google. + # shellcheck disable=SC2086 + ( cd "$REPO" && exec $WORKER_CMD --http --port 0 --port-file "$PORT_FILE" ) > "$LOG_FILE" 2>&1 & + SERVER_PID=$! + + PORT="" + for _ in $(seq 1 240); do + if ! kill -0 "$SERVER_PID" 2>/dev/null; then + echo "ERROR: HTTP worker exited before reporting a port. Log:" >&2 + cat "$LOG_FILE" >&2 + exit 1 + fi + if [[ -s "$PORT_FILE" ]]; then + PORT="$(tr -d '[:space:]' < "$PORT_FILE")" + [[ -n "$PORT" ]] && break + fi + sleep 0.5 + done + if [[ -z "$PORT" ]]; then + echo "ERROR: timed out waiting for HTTP worker port-file. Log:" >&2 + cat "$LOG_FILE" >&2 + exit 1 + fi + echo "HTTP worker ready on port $PORT (pid $SERVER_PID)" + export VGI_GOOGLE_WORKER="http://127.0.0.1:$PORT" + ;; + + unix) + # Boot the worker bound to an AF_UNIX socket. GoogleWorker.main() prints + # `UNIX:` once bound; we poll for the socket file to appear. The + # worker inherits VGI_GOOGLE_MOCK=1 + VGI_GOOGLE_DISCOVERY_DIR exported above. + SOCK="${TMPDIR:-/tmp}/google-$$.sock" + rm -f "$SOCK" + LOG_FILE="${TMPDIR:-/tmp}/google-unix-server.log" + echo "Starting unix worker: $WORKER_CMD --unix $SOCK" + # shellcheck disable=SC2086 + ( cd "$REPO" && exec $WORKER_CMD --unix "$SOCK" ) > "$LOG_FILE" 2>&1 & + SERVER_PID=$! + + READY="" + for _ in $(seq 1 240); do + if ! kill -0 "$SERVER_PID" 2>/dev/null; then + echo "ERROR: unix worker exited before binding the socket. Log:" >&2 + cat "$LOG_FILE" >&2 + exit 1 + fi + if [[ -S "$SOCK" ]]; then + READY=1 + break + fi + sleep 0.5 + done + if [[ -z "$READY" ]]; then + echo "ERROR: timed out waiting for unix worker socket. Log:" >&2 + cat "$LOG_FILE" >&2 + exit 1 + fi + echo "unix worker ready on $SOCK (pid $SERVER_PID)" + export VGI_GOOGLE_WORKER="unix://$SOCK" + ;; + + *) + echo "ERROR: unknown TRANSPORT '$TRANSPORT' (want subprocess|http|unix)" >&2 + exit 2 + ;; +esac + cd "$STAGE" # Warm the extension cache once: vgi from the signed community channel. A miss @@ -73,7 +226,30 @@ EOF "$HAYBARN_UNITTEST" "test/_warm.test" >/dev/null 2>&1 || echo "::warning::extension warm step did not fully succeed" rm -f "$STAGE/test/_warm.test" -# Run the whole suite in one invocation, streaming the runner's native -# sqllogictest report. Any failed assertion exits non-zero and fails the job. -echo "Running suite (worker: $VGI_GOOGLE_WORKER) ..." -"$HAYBARN_UNITTEST" "test/sql/*" +# Run the whole suite in one invocation, capturing the runner's native +# sqllogictest report so we can both stream it AND assert on the summary line. +echo "Running suite (transport: $TRANSPORT, worker: $VGI_GOOGLE_WORKER) ..." +RUN_LOG="$STAGE/run.log" +set +e +"$HAYBARN_UNITTEST" "test/sql/*" 2>&1 | tee "$RUN_LOG" +status=${PIPESTATUS[0]} +set -e + +# SILENT-SKIP GUARD (critical for the http leg). DuckDB's sqllogictest runner +# auto-SKIPS (exit 0!) any test whose error message contains "HTTP" or "Unable +# to connect" — so a broken http setup reports "All tests were skipped" and the +# job goes GREEN while testing nothing. Fail the leg unless the runner reports a +# real pass with N>0 assertions and reported zero skips. +if [[ $status -ne 0 ]]; then + echo "ERROR: haybarn-unittest exited $status" >&2 + exit "$status" +fi +if grep -Eqi 'were skipped|tests were skipped' "$RUN_LOG"; then + echo "ERROR: tests were SKIPPED (likely a masked $TRANSPORT transport error — see above)." >&2 + exit 1 +fi +if ! grep -Eq 'All tests passed \([1-9][0-9]* assertions' "$RUN_LOG"; then + echo "ERROR: did not find an 'All tests passed (N assertions ...)' summary with N>0." >&2 + exit 1 +fi +echo "Suite GREEN over transport: $TRANSPORT" diff --git a/google_worker.py b/google_worker.py index 0d8cfd1..78e70f7 100644 --- a/google_worker.py +++ b/google_worker.py @@ -1,7 +1,7 @@ # /// script # requires-python = ">=3.13" # dependencies = [ -# "vgi-python>=0.8.3", +# "vgi-python[http]>=0.8.3", # "google-api-python-client>=2.100", # "google-auth>=2.20", # ] diff --git a/pyproject.toml b/pyproject.toml index d5f37ed..58d829c 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -39,6 +39,13 @@ dev = [ "mypy>=1.10", "pydoclint>=0.5", ] +# HTTP transport: the worker can serve over HTTP (`google_worker.py --http`, and +# the HTTP entry `serve.py`) in addition to stdio/AF_UNIX. That path needs +# vgi-python's `http` extra (waitress). CI's http transport leg installs this via +# `uv sync --extra http`. +http = [ + "vgi-python[http]>=0.8.3", +] [project.urls] Homepage = "https://query.farm" diff --git a/uv.lock b/uv.lock index 556d2e8..95d6374 100644 --- a/uv.lock +++ b/uv.lock @@ -267,6 +267,33 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/bf/50/98b146aea0f1cd7531d25f12bea69fa9ce8d1662124f93fb30dc4511b65e/docstring_parser_fork-0.0.14-py3-none-any.whl", hash = "sha256:4c544f234ef2cc2749a3df32b70c437d77888b1099143a1ad5454452c574b9af", size = 43063, upload-time = "2025-09-07T17:27:37.012Z" }, ] +[[package]] +name = "falcon" +version = "4.3.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/a0/02/a51af369a4feded77801d744f2d4669c7fa0a294bc117acf6ee06439937b/falcon-4.3.1.tar.gz", hash = "sha256:b5081be62f1e2d4f5140f4bad6993fd2bf8b1e503ee7261f56d324b87e41a67a", size = 687415, upload-time = "2026-06-16T05:31:25.864Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ed/d1/9e5c219a283ac39f41d88ae5ea3951537d373c10f3f500049706cd3087d9/falcon-4.3.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:23ec85650482a719902321627258b8297c7ecc38227001ce602078d9a157481c", size = 425427, upload-time = "2026-06-16T05:42:30.251Z" }, + { url = "https://files.pythonhosted.org/packages/13/db/034e0929c5af463dc1b96fde707b1d6dd55ff5224ec53ccc4341180b80f8/falcon-4.3.1-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:0462c4f2125c5656826b4a4b4bbb262e77d9cdedfedfe03ababf2480e1a6f342", size = 870018, upload-time = "2026-06-16T05:42:31.699Z" }, + { url = "https://files.pythonhosted.org/packages/15/99/82fda8e5da5953454c174b9570f0e6ff9e9a3d7f818e39d43c2ae6f864d3/falcon-4.3.1-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:7b9462c55ee6b83f6897361b711649c3981d3cc31dc90b1efca18e16bba4c872", size = 909674, upload-time = "2026-06-16T05:42:33.324Z" }, + { url = "https://files.pythonhosted.org/packages/bb/f3/c930cf8309c4e46e50de8c29d5023d3fe8c307dbb9d146322e8ab9cab9c9/falcon-4.3.1-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ed2566579cda476dbceddc29d356c6bfd56501d9109ac4d3eacd1f994653b9ba", size = 880182, upload-time = "2026-06-16T05:42:34.853Z" }, + { url = "https://files.pythonhosted.org/packages/d0/13/6e15639ac0e0e20940fa66087411e3e4b964f6da9c72f8a684c65d3d0774/falcon-4.3.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:c99f7f8d50ac3240182ad2f5ef22dee1d1852762ba594c7029f7b65d804c2057", size = 859594, upload-time = "2026-06-16T05:42:36.395Z" }, + { url = "https://files.pythonhosted.org/packages/b8/50/16605e42475dc363ec74007bc017262dcd06660ca5a6c3110caf1af2bd06/falcon-4.3.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:2ed6e8e2a89ea1fc5cb9ecddd488ea0c89321f852390a1be31ef44034005b565", size = 875601, upload-time = "2026-06-16T05:42:38.201Z" }, + { url = "https://files.pythonhosted.org/packages/93/a0/f9f1d46d7ba5fa4de5bdb71fe1ca53690458a54909fdf1a98a97231c102c/falcon-4.3.1-cp313-cp313-win_amd64.whl", hash = "sha256:3648849d0a0426d571ad846aa20a5cb20718db3b040447ffc6c4436de728a9a7", size = 415648, upload-time = "2026-06-16T05:42:39.95Z" }, + { url = "https://files.pythonhosted.org/packages/99/54/68a589193349f7db5c25ccc0823b22e5395ad7325551e20590680eecbddf/falcon-4.3.1-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:7baf12d82e48998efdb6a270d384ac18bd3ec12665ca4356498c35a707e37359", size = 426480, upload-time = "2026-06-16T05:42:41.517Z" }, + { url = "https://files.pythonhosted.org/packages/9e/eb/7f711c2be80eb8a297727ab17ce5dfa013a3b6275c7d8a9b23a9a27e19f0/falcon-4.3.1-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:974a4f8efc0b33268ae56dd4379c4386bd7f7c8b3635c236a9289bea1e899c17", size = 872708, upload-time = "2026-06-16T05:42:43.174Z" }, + { url = "https://files.pythonhosted.org/packages/4c/70/72d281b4181851e8e9f4bb8d2fd8bf3b35c3ecc269358b67bf24cb8f0388/falcon-4.3.1-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:3504fa4c63d2ab892434b1375706b6f89d8ca73488cc1a69976562928d5a658f", size = 905775, upload-time = "2026-06-16T05:42:44.754Z" }, + { url = "https://files.pythonhosted.org/packages/21/73/68bfa5e7db8a039a71e7c0e99c067aa192c4eeddaad8427c38a1ec4bb584/falcon-4.3.1-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:761c79d34480e3f9fe4cd89bc82fa554b8d54a56810f796e5cddc5b8314780a4", size = 875880, upload-time = "2026-06-16T05:42:46.391Z" }, + { url = "https://files.pythonhosted.org/packages/0e/fa/fc02220e7ab96fb7fec86c72e5ba317732cebb3a088986d32584e64a0061/falcon-4.3.1-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:318837add4ec1ad04a28d507911985f2b08cfcb56b34b69eb87188bd98e017c0", size = 862812, upload-time = "2026-06-16T05:42:48.199Z" }, + { url = "https://files.pythonhosted.org/packages/eb/07/aa1e2be6c63306cba060cec3500f047b041b4f26129ed352ee5a02f3c86a/falcon-4.3.1-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:9449bc13e0f8ebaedf80a1ce2344d7935183d45680a9fd75057e40fa0ebc5409", size = 874413, upload-time = "2026-06-16T05:42:49.659Z" }, + { url = "https://files.pythonhosted.org/packages/11/21/a9b295702898c688d7c0f5aaed4d33dcd26ac1f47683d27f55dcaccc9e1d/falcon-4.3.1-cp314-cp314-win_amd64.whl", hash = "sha256:1d8d54db0fa01d232c05cc16e17dd69f76628789afac49beef85fcad61af1668", size = 417560, upload-time = "2026-06-16T05:42:51.248Z" }, + { url = "https://files.pythonhosted.org/packages/92/7d/d5dd88d6afcf5dade4090115635d34a78fdacede7c8deff6636e8d3aa6d0/falcon-4.3.1-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b76706dcede435bbf6dcbbde8e63ce223454e379f9f0463d3d686c10a9b2c844", size = 987965, upload-time = "2026-06-16T05:42:53.064Z" }, + { url = "https://files.pythonhosted.org/packages/f1/61/5caa5986123dc0378a0f296be251502543c55f7d98a06647ff050eb57772/falcon-4.3.1-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:3f4cdd80ffd112766e3e53a166b9f46218bebb3619dd2abeaf4e618386a0cfec", size = 973455, upload-time = "2026-06-16T05:42:55.671Z" }, + { url = "https://files.pythonhosted.org/packages/30/f3/41a4c8fe25af0f7f84b437b87d2b654387bc2a1efcae8076c33079651a7d/falcon-4.3.1-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:9c78fdd7fa7c39f9e179c494716efb5c75b476938078e83a7ff6b247d461b64a", size = 960935, upload-time = "2026-06-16T05:42:57.346Z" }, + { url = "https://files.pythonhosted.org/packages/59/da/99632e285b4622aa9687bac3e682270b09f9f857309158b9668582d71297/falcon-4.3.1-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:2bb8cb5c4e5cfb7819169f3bd11683ca9ef57e0169f9fee0189d0a1b71af6b77", size = 965542, upload-time = "2026-06-16T05:42:58.991Z" }, + { url = "https://files.pythonhosted.org/packages/da/ef/5790e74a7b39d2c085554f347be22a1882649a29a7a65e9c81bfaf9e8fc6/falcon-4.3.1-py3-none-any.whl", hash = "sha256:5402602d14bc426afc01c388538f2ad402ac4c8c2477415dfe972a2deee17248", size = 332719, upload-time = "2026-06-16T05:31:23.373Z" }, +] + [[package]] name = "google-api-core" version = "2.31.0" @@ -669,6 +696,41 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl", hash = "sha256:81a9e26dd42fd28a23a2d169d86d7ac03b46e2f8b59ed4698fb4785f946d0176", size = 1231151, upload-time = "2026-03-29T13:29:30.038Z" }, ] +[[package]] +name = "pynacl" +version = "1.6.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "cffi", marker = "platform_python_implementation != 'PyPy'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/d9/9a/4019b524b03a13438637b11538c82781a5eda427394380381af8f04f467a/pynacl-1.6.2.tar.gz", hash = "sha256:018494d6d696ae03c7e656e5e74cdfd8ea1326962cc401bcf018f1ed8436811c", size = 3511692, upload-time = "2026-01-01T17:48:10.851Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/4b/79/0e3c34dc3c4671f67d251c07aa8eb100916f250ee470df230b0ab89551b4/pynacl-1.6.2-cp314-cp314t-macosx_10_10_universal2.whl", hash = "sha256:622d7b07cc5c02c666795792931b50c91f3ce3c2649762efb1ef0d5684c81594", size = 390064, upload-time = "2026-01-01T17:31:57.264Z" }, + { url = "https://files.pythonhosted.org/packages/eb/1c/23a26e931736e13b16483795c8a6b2f641bf6a3d5238c22b070a5112722c/pynacl-1.6.2-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:d071c6a9a4c94d79eb665db4ce5cedc537faf74f2355e4d502591d850d3913c0", size = 809370, upload-time = "2026-01-01T17:31:59.198Z" }, + { url = "https://files.pythonhosted.org/packages/87/74/8d4b718f8a22aea9e8dcc8b95deb76d4aae380e2f5b570cc70b5fd0a852d/pynacl-1.6.2-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:fe9847ca47d287af41e82be1dd5e23023d3c31a951da134121ab02e42ac218c9", size = 1408304, upload-time = "2026-01-01T17:32:01.162Z" }, + { url = "https://files.pythonhosted.org/packages/fd/73/be4fdd3a6a87fe8a4553380c2b47fbd1f7f58292eb820902f5c8ac7de7b0/pynacl-1.6.2-cp314-cp314t-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:04316d1fc625d860b6c162fff704eb8426b1a8bcd3abacea11142cbd99a6b574", size = 844871, upload-time = "2026-01-01T17:32:02.824Z" }, + { url = "https://files.pythonhosted.org/packages/55/ad/6efc57ab75ee4422e96b5f2697d51bbcf6cdcc091e66310df91fbdc144a8/pynacl-1.6.2-cp314-cp314t-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:44081faff368d6c5553ccf55322ef2819abb40e25afaec7e740f159f74813634", size = 1446356, upload-time = "2026-01-01T17:32:04.452Z" }, + { url = "https://files.pythonhosted.org/packages/78/b7/928ee9c4779caa0a915844311ab9fb5f99585621c5d6e4574538a17dca07/pynacl-1.6.2-cp314-cp314t-manylinux_2_34_aarch64.whl", hash = "sha256:a9f9932d8d2811ce1a8ffa79dcbdf3970e7355b5c8eb0c1a881a57e7f7d96e88", size = 826814, upload-time = "2026-01-01T17:32:06.078Z" }, + { url = "https://files.pythonhosted.org/packages/f7/a9/1bdba746a2be20f8809fee75c10e3159d75864ef69c6b0dd168fc60e485d/pynacl-1.6.2-cp314-cp314t-manylinux_2_34_x86_64.whl", hash = "sha256:bc4a36b28dd72fb4845e5d8f9760610588a96d5a51f01d84d8c6ff9849968c14", size = 1411742, upload-time = "2026-01-01T17:32:07.651Z" }, + { url = "https://files.pythonhosted.org/packages/f3/2f/5e7ea8d85f9f3ea5b6b87db1d8388daa3587eed181bdeb0306816fdbbe79/pynacl-1.6.2-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:3bffb6d0f6becacb6526f8f42adfb5efb26337056ee0831fb9a7044d1a964444", size = 801714, upload-time = "2026-01-01T17:32:09.558Z" }, + { url = "https://files.pythonhosted.org/packages/06/ea/43fe2f7eab5f200e40fb10d305bf6f87ea31b3bbc83443eac37cd34a9e1e/pynacl-1.6.2-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:2fef529ef3ee487ad8113d287a593fa26f48ee3620d92ecc6f1d09ea38e0709b", size = 1372257, upload-time = "2026-01-01T17:32:11.026Z" }, + { url = "https://files.pythonhosted.org/packages/4d/54/c9ea116412788629b1347e415f72195c25eb2f3809b2d3e7b25f5c79f13a/pynacl-1.6.2-cp314-cp314t-win32.whl", hash = "sha256:a84bf1c20339d06dc0c85d9aea9637a24f718f375d861b2668b2f9f96fa51145", size = 231319, upload-time = "2026-01-01T17:32:12.46Z" }, + { url = "https://files.pythonhosted.org/packages/ce/04/64e9d76646abac2dccf904fccba352a86e7d172647557f35b9fe2a5ee4a1/pynacl-1.6.2-cp314-cp314t-win_amd64.whl", hash = "sha256:320ef68a41c87547c91a8b58903c9caa641ab01e8512ce291085b5fe2fcb7590", size = 244044, upload-time = "2026-01-01T17:32:13.781Z" }, + { url = "https://files.pythonhosted.org/packages/33/33/7873dc161c6a06f43cda13dec67b6fe152cb2f982581151956fa5e5cdb47/pynacl-1.6.2-cp314-cp314t-win_arm64.whl", hash = "sha256:d29bfe37e20e015a7d8b23cfc8bd6aa7909c92a1b8f41ee416bbb3e79ef182b2", size = 188740, upload-time = "2026-01-01T17:32:15.083Z" }, + { url = "https://files.pythonhosted.org/packages/be/7b/4845bbf88e94586ec47a432da4e9107e3fc3ce37eb412b1398630a37f7dd/pynacl-1.6.2-cp38-abi3-macosx_10_10_universal2.whl", hash = "sha256:c949ea47e4206af7c8f604b8278093b674f7c79ed0d4719cc836902bf4517465", size = 388458, upload-time = "2026-01-01T17:32:16.829Z" }, + { url = "https://files.pythonhosted.org/packages/1e/b4/e927e0653ba63b02a4ca5b4d852a8d1d678afbf69b3dbf9c4d0785ac905c/pynacl-1.6.2-cp38-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:8845c0631c0be43abdd865511c41eab235e0be69c81dc66a50911594198679b0", size = 800020, upload-time = "2026-01-01T17:32:18.34Z" }, + { url = "https://files.pythonhosted.org/packages/7f/81/d60984052df5c97b1d24365bc1e30024379b42c4edcd79d2436b1b9806f2/pynacl-1.6.2-cp38-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:22de65bb9010a725b0dac248f353bb072969c94fa8d6b1f34b87d7953cf7bbe4", size = 1399174, upload-time = "2026-01-01T17:32:20.239Z" }, + { url = "https://files.pythonhosted.org/packages/68/f7/322f2f9915c4ef27d140101dd0ed26b479f7e6f5f183590fd32dfc48c4d3/pynacl-1.6.2-cp38-abi3-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:46065496ab748469cdd999246d17e301b2c24ae2fdf739132e580a0e94c94a87", size = 835085, upload-time = "2026-01-01T17:32:22.24Z" }, + { url = "https://files.pythonhosted.org/packages/3e/d0/f301f83ac8dbe53442c5a43f6a39016f94f754d7a9815a875b65e218a307/pynacl-1.6.2-cp38-abi3-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:8a66d6fb6ae7661c58995f9c6435bda2b1e68b54b598a6a10247bfcdadac996c", size = 1437614, upload-time = "2026-01-01T17:32:23.766Z" }, + { url = "https://files.pythonhosted.org/packages/c4/58/fc6e649762b029315325ace1a8c6be66125e42f67416d3dbd47b69563d61/pynacl-1.6.2-cp38-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:26bfcd00dcf2cf160f122186af731ae30ab120c18e8375684ec2670dccd28130", size = 818251, upload-time = "2026-01-01T17:32:25.69Z" }, + { url = "https://files.pythonhosted.org/packages/c9/a8/b917096b1accc9acd878819a49d3d84875731a41eb665f6ebc826b1af99e/pynacl-1.6.2-cp38-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:c8a231e36ec2cab018c4ad4358c386e36eede0319a0c41fed24f840b1dac59f6", size = 1402859, upload-time = "2026-01-01T17:32:27.215Z" }, + { url = "https://files.pythonhosted.org/packages/85/42/fe60b5f4473e12c72f977548e4028156f4d340b884c635ec6b063fe7e9a5/pynacl-1.6.2-cp38-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:68be3a09455743ff9505491220b64440ced8973fe930f270c8e07ccfa25b1f9e", size = 791926, upload-time = "2026-01-01T17:32:29.314Z" }, + { url = "https://files.pythonhosted.org/packages/fa/f9/e40e318c604259301cc091a2a63f237d9e7b424c4851cafaea4ea7c4834e/pynacl-1.6.2-cp38-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:8b097553b380236d51ed11356c953bf8ce36a29a3e596e934ecabe76c985a577", size = 1363101, upload-time = "2026-01-01T17:32:31.263Z" }, + { url = "https://files.pythonhosted.org/packages/48/47/e761c254f410c023a469284a9bc210933e18588ca87706ae93002c05114c/pynacl-1.6.2-cp38-abi3-win32.whl", hash = "sha256:5811c72b473b2f38f7e2a3dc4f8642e3a3e9b5e7317266e4ced1fba85cae41aa", size = 227421, upload-time = "2026-01-01T17:32:33.076Z" }, + { url = "https://files.pythonhosted.org/packages/41/ad/334600e8cacc7d86587fe5f565480fde569dfb487389c8e1be56ac21d8ac/pynacl-1.6.2-cp38-abi3-win_amd64.whl", hash = "sha256:62985f233210dee6548c223301b6c25440852e13d59a8b81490203c3227c5ba0", size = 239754, upload-time = "2026-01-01T17:32:34.557Z" }, + { url = "https://files.pythonhosted.org/packages/29/7d/5945b5af29534641820d3bd7b00962abbbdfee84ec7e19f0d5b3175f9a31/pynacl-1.6.2-cp38-abi3-win_arm64.whl", hash = "sha256:834a43af110f743a754448463e8fd61259cd4ab5bbedcf70f9dabad1d28a394c", size = 184801, upload-time = "2026-01-01T17:32:36.309Z" }, +] + [[package]] name = "pyparsing" version = "3.3.2" @@ -841,6 +903,9 @@ dev = [ { name = "pytest" }, { name = "ruff" }, ] +http = [ + { name = "vgi-python", extra = ["http"] }, +] [package.metadata] requires-dist = [ @@ -852,8 +917,9 @@ requires-dist = [ { name = "pytest", marker = "extra == 'dev'", specifier = ">=8" }, { name = "ruff", marker = "extra == 'dev'", specifier = ">=0.5" }, { name = "vgi-python", specifier = ">=0.8.3" }, + { name = "vgi-python", extras = ["http"], marker = "extra == 'http'", specifier = ">=0.8.3" }, ] -provides-extras = ["dev"] +provides-extras = ["dev", "http"] [[package]] name = "vgi-python" @@ -872,6 +938,11 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/af/48/5384a305a6924e4031c98ec404e7e4cf696cd936d3ed4ef012172e013037/vgi_python-0.8.3-py3-none-any.whl", hash = "sha256:18d83ca1243e7521a4235a78bf2b54b77ae33eacb5f4f5d1e87f585f3b35c85c", size = 586297, upload-time = "2026-06-23T20:11:29.302Z" }, ] +[package.optional-dependencies] +http = [ + { name = "vgi-rpc", extra = ["http"] }, +] + [[package]] name = "vgi-rpc" version = "0.20.6" @@ -886,3 +957,61 @@ sdist = { url = "https://files.pythonhosted.org/packages/40/76/4a2c35af34928c6ab wheels = [ { url = "https://files.pythonhosted.org/packages/d3/3c/9ccc888e725ad9d7091e8ec6fd7504eec15dc2ccfabedabd7d072123b0e8/vgi_rpc-0.20.6-py3-none-any.whl", hash = "sha256:74f8b7c0685f1c28a3ff754d76f8c0179c782e33aa5915ad0343bb9955d7509d", size = 371735, upload-time = "2026-06-22T18:24:17.458Z" }, ] + +[package.optional-dependencies] +http = [ + { name = "falcon" }, + { name = "httpx" }, + { name = "pynacl" }, + { name = "waitress" }, + { name = "zstandard" }, +] + +[[package]] +name = "waitress" +version = "3.0.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/bf/cb/04ddb054f45faa306a230769e868c28b8065ea196891f09004ebace5b184/waitress-3.0.2.tar.gz", hash = "sha256:682aaaf2af0c44ada4abfb70ded36393f0e307f4ab9456a215ce0020baefc31f", size = 179901, upload-time = "2024-11-16T20:02:35.195Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/8d/57/a27182528c90ef38d82b636a11f606b0cbb0e17588ed205435f8affe3368/waitress-3.0.2-py3-none-any.whl", hash = "sha256:c56d67fd6e87c2ee598b76abdd4e96cfad1f24cacdea5078d382b1f9d7b5ed2e", size = 56232, upload-time = "2024-11-16T20:02:33.858Z" }, +] + +[[package]] +name = "zstandard" +version = "0.25.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/fd/aa/3e0508d5a5dd96529cdc5a97011299056e14c6505b678fd58938792794b1/zstandard-0.25.0.tar.gz", hash = "sha256:7713e1179d162cf5c7906da876ec2ccb9c3a9dcbdffef0cc7f70c3667a205f0b", size = 711513, upload-time = "2025-09-14T22:15:54.002Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/35/0b/8df9c4ad06af91d39e94fa96cc010a24ac4ef1378d3efab9223cc8593d40/zstandard-0.25.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:ec996f12524f88e151c339688c3897194821d7f03081ab35d31d1e12ec975e94", size = 795735, upload-time = "2025-09-14T22:17:26.042Z" }, + { url = "https://files.pythonhosted.org/packages/3f/06/9ae96a3e5dcfd119377ba33d4c42a7d89da1efabd5cb3e366b156c45ff4d/zstandard-0.25.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:a1a4ae2dec3993a32247995bdfe367fc3266da832d82f8438c8570f989753de1", size = 640440, upload-time = "2025-09-14T22:17:27.366Z" }, + { url = "https://files.pythonhosted.org/packages/d9/14/933d27204c2bd404229c69f445862454dcc101cd69ef8c6068f15aaec12c/zstandard-0.25.0-cp313-cp313-manylinux2010_i686.manylinux2014_i686.manylinux_2_12_i686.manylinux_2_17_i686.whl", hash = "sha256:e96594a5537722fdfb79951672a2a63aec5ebfb823e7560586f7484819f2a08f", size = 5343070, upload-time = "2025-09-14T22:17:28.896Z" }, + { url = "https://files.pythonhosted.org/packages/6d/db/ddb11011826ed7db9d0e485d13df79b58586bfdec56e5c84a928a9a78c1c/zstandard-0.25.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:bfc4e20784722098822e3eee42b8e576b379ed72cca4a7cb856ae733e62192ea", size = 5063001, upload-time = "2025-09-14T22:17:31.044Z" }, + { url = "https://files.pythonhosted.org/packages/db/00/87466ea3f99599d02a5238498b87bf84a6348290c19571051839ca943777/zstandard-0.25.0-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:457ed498fc58cdc12fc48f7950e02740d4f7ae9493dd4ab2168a47c93c31298e", size = 5394120, upload-time = "2025-09-14T22:17:32.711Z" }, + { url = "https://files.pythonhosted.org/packages/2b/95/fc5531d9c618a679a20ff6c29e2b3ef1d1f4ad66c5e161ae6ff847d102a9/zstandard-0.25.0-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:fd7a5004eb1980d3cefe26b2685bcb0b17989901a70a1040d1ac86f1d898c551", size = 5451230, upload-time = "2025-09-14T22:17:34.41Z" }, + { url = "https://files.pythonhosted.org/packages/63/4b/e3678b4e776db00f9f7b2fe58e547e8928ef32727d7a1ff01dea010f3f13/zstandard-0.25.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:8e735494da3db08694d26480f1493ad2cf86e99bdd53e8e9771b2752a5c0246a", size = 5547173, upload-time = "2025-09-14T22:17:36.084Z" }, + { url = "https://files.pythonhosted.org/packages/4e/d5/ba05ed95c6b8ec30bd468dfeab20589f2cf709b5c940483e31d991f2ca58/zstandard-0.25.0-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:3a39c94ad7866160a4a46d772e43311a743c316942037671beb264e395bdd611", size = 5046736, upload-time = "2025-09-14T22:17:37.891Z" }, + { url = "https://files.pythonhosted.org/packages/50/d5/870aa06b3a76c73eced65c044b92286a3c4e00554005ff51962deef28e28/zstandard-0.25.0-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:172de1f06947577d3a3005416977cce6168f2261284c02080e7ad0185faeced3", size = 5576368, upload-time = "2025-09-14T22:17:40.206Z" }, + { url = "https://files.pythonhosted.org/packages/5d/35/398dc2ffc89d304d59bc12f0fdd931b4ce455bddf7038a0a67733a25f550/zstandard-0.25.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:3c83b0188c852a47cd13ef3bf9209fb0a77fa5374958b8c53aaa699398c6bd7b", size = 4954022, upload-time = "2025-09-14T22:17:41.879Z" }, + { url = "https://files.pythonhosted.org/packages/9a/5c/36ba1e5507d56d2213202ec2b05e8541734af5f2ce378c5d1ceaf4d88dc4/zstandard-0.25.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:1673b7199bbe763365b81a4f3252b8e80f44c9e323fc42940dc8843bfeaf9851", size = 5267889, upload-time = "2025-09-14T22:17:43.577Z" }, + { url = "https://files.pythonhosted.org/packages/70/e8/2ec6b6fb7358b2ec0113ae202647ca7c0e9d15b61c005ae5225ad0995df5/zstandard-0.25.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:0be7622c37c183406f3dbf0cba104118eb16a4ea7359eeb5752f0794882fc250", size = 5433952, upload-time = "2025-09-14T22:17:45.271Z" }, + { url = "https://files.pythonhosted.org/packages/7b/01/b5f4d4dbc59ef193e870495c6f1275f5b2928e01ff5a81fecb22a06e22fb/zstandard-0.25.0-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:5f5e4c2a23ca271c218ac025bd7d635597048b366d6f31f420aaeb715239fc98", size = 5814054, upload-time = "2025-09-14T22:17:47.08Z" }, + { url = "https://files.pythonhosted.org/packages/b2/e5/fbd822d5c6f427cf158316d012c5a12f233473c2f9c5fe5ab1ae5d21f3d8/zstandard-0.25.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:4f187a0bb61b35119d1926aee039524d1f93aaf38a9916b8c4b78ac8514a0aaf", size = 5360113, upload-time = "2025-09-14T22:17:48.893Z" }, + { url = "https://files.pythonhosted.org/packages/8e/e0/69a553d2047f9a2c7347caa225bb3a63b6d7704ad74610cb7823baa08ed7/zstandard-0.25.0-cp313-cp313-win32.whl", hash = "sha256:7030defa83eef3e51ff26f0b7bfb229f0204b66fe18e04359ce3474ac33cbc09", size = 436936, upload-time = "2025-09-14T22:17:52.658Z" }, + { url = "https://files.pythonhosted.org/packages/d9/82/b9c06c870f3bd8767c201f1edbdf9e8dc34be5b0fbc5682c4f80fe948475/zstandard-0.25.0-cp313-cp313-win_amd64.whl", hash = "sha256:1f830a0dac88719af0ae43b8b2d6aef487d437036468ef3c2ea59c51f9d55fd5", size = 506232, upload-time = "2025-09-14T22:17:50.402Z" }, + { url = "https://files.pythonhosted.org/packages/d4/57/60c3c01243bb81d381c9916e2a6d9e149ab8627c0c7d7abb2d73384b3c0c/zstandard-0.25.0-cp313-cp313-win_arm64.whl", hash = "sha256:85304a43f4d513f5464ceb938aa02c1e78c2943b29f44a750b48b25ac999a049", size = 462671, upload-time = "2025-09-14T22:17:51.533Z" }, + { url = "https://files.pythonhosted.org/packages/3d/5c/f8923b595b55fe49e30612987ad8bf053aef555c14f05bb659dd5dbe3e8a/zstandard-0.25.0-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:e29f0cf06974c899b2c188ef7f783607dbef36da4c242eb6c82dcd8b512855e3", size = 795887, upload-time = "2025-09-14T22:17:54.198Z" }, + { url = "https://files.pythonhosted.org/packages/8d/09/d0a2a14fc3439c5f874042dca72a79c70a532090b7ba0003be73fee37ae2/zstandard-0.25.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:05df5136bc5a011f33cd25bc9f506e7426c0c9b3f9954f056831ce68f3b6689f", size = 640658, upload-time = "2025-09-14T22:17:55.423Z" }, + { url = "https://files.pythonhosted.org/packages/5d/7c/8b6b71b1ddd517f68ffb55e10834388d4f793c49c6b83effaaa05785b0b4/zstandard-0.25.0-cp314-cp314-manylinux2010_i686.manylinux_2_12_i686.manylinux_2_28_i686.whl", hash = "sha256:f604efd28f239cc21b3adb53eb061e2a205dc164be408e553b41ba2ffe0ca15c", size = 5379849, upload-time = "2025-09-14T22:17:57.372Z" }, + { url = "https://files.pythonhosted.org/packages/a4/86/a48e56320d0a17189ab7a42645387334fba2200e904ee47fc5a26c1fd8ca/zstandard-0.25.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:223415140608d0f0da010499eaa8ccdb9af210a543fac54bce15babbcfc78439", size = 5058095, upload-time = "2025-09-14T22:17:59.498Z" }, + { url = "https://files.pythonhosted.org/packages/f8/ad/eb659984ee2c0a779f9d06dbfe45e2dc39d99ff40a319895df2d3d9a48e5/zstandard-0.25.0-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:2e54296a283f3ab5a26fc9b8b5d4978ea0532f37b231644f367aa588930aa043", size = 5551751, upload-time = "2025-09-14T22:18:01.618Z" }, + { url = "https://files.pythonhosted.org/packages/61/b3/b637faea43677eb7bd42ab204dfb7053bd5c4582bfe6b1baefa80ac0c47b/zstandard-0.25.0-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:ca54090275939dc8ec5dea2d2afb400e0f83444b2fc24e07df7fdef677110859", size = 6364818, upload-time = "2025-09-14T22:18:03.769Z" }, + { url = "https://files.pythonhosted.org/packages/31/dc/cc50210e11e465c975462439a492516a73300ab8caa8f5e0902544fd748b/zstandard-0.25.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:e09bb6252b6476d8d56100e8147b803befa9a12cea144bbe629dd508800d1ad0", size = 5560402, upload-time = "2025-09-14T22:18:05.954Z" }, + { url = "https://files.pythonhosted.org/packages/c9/ae/56523ae9c142f0c08efd5e868a6da613ae76614eca1305259c3bf6a0ed43/zstandard-0.25.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:a9ec8c642d1ec73287ae3e726792dd86c96f5681eb8df274a757bf62b750eae7", size = 4955108, upload-time = "2025-09-14T22:18:07.68Z" }, + { url = "https://files.pythonhosted.org/packages/98/cf/c899f2d6df0840d5e384cf4c4121458c72802e8bda19691f3b16619f51e9/zstandard-0.25.0-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:a4089a10e598eae6393756b036e0f419e8c1d60f44a831520f9af41c14216cf2", size = 5269248, upload-time = "2025-09-14T22:18:09.753Z" }, + { url = "https://files.pythonhosted.org/packages/1b/c0/59e912a531d91e1c192d3085fc0f6fb2852753c301a812d856d857ea03c6/zstandard-0.25.0-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:f67e8f1a324a900e75b5e28ffb152bcac9fbed1cc7b43f99cd90f395c4375344", size = 5430330, upload-time = "2025-09-14T22:18:11.966Z" }, + { url = "https://files.pythonhosted.org/packages/a0/1d/7e31db1240de2df22a58e2ea9a93fc6e38cc29353e660c0272b6735d6669/zstandard-0.25.0-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:9654dbc012d8b06fc3d19cc825af3f7bf8ae242226df5f83936cb39f5fdc846c", size = 5811123, upload-time = "2025-09-14T22:18:13.907Z" }, + { url = "https://files.pythonhosted.org/packages/f6/49/fac46df5ad353d50535e118d6983069df68ca5908d4d65b8c466150a4ff1/zstandard-0.25.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:4203ce3b31aec23012d3a4cf4a2ed64d12fea5269c49aed5e4c3611b938e4088", size = 5359591, upload-time = "2025-09-14T22:18:16.465Z" }, + { url = "https://files.pythonhosted.org/packages/c2/38/f249a2050ad1eea0bb364046153942e34abba95dd5520af199aed86fbb49/zstandard-0.25.0-cp314-cp314-win32.whl", hash = "sha256:da469dc041701583e34de852d8634703550348d5822e66a0c827d39b05365b12", size = 444513, upload-time = "2025-09-14T22:18:20.61Z" }, + { url = "https://files.pythonhosted.org/packages/3a/43/241f9615bcf8ba8903b3f0432da069e857fc4fd1783bd26183db53c4804b/zstandard-0.25.0-cp314-cp314-win_amd64.whl", hash = "sha256:c19bcdd826e95671065f8692b5a4aa95c52dc7a02a4c5a0cac46deb879a017a2", size = 516118, upload-time = "2025-09-14T22:18:17.849Z" }, + { url = "https://files.pythonhosted.org/packages/f0/ef/da163ce2450ed4febf6467d77ccb4cd52c4c30ab45624bad26ca0a27260c/zstandard-0.25.0-cp314-cp314-win_arm64.whl", hash = "sha256:d7541afd73985c630bafcd6338d2518ae96060075f9463d7dc14cfb33514383d", size = 476940, upload-time = "2025-09-14T22:18:19.088Z" }, +]