Skip to content

Commit bb440f9

Browse files
lmeyerovclaude
andcommitted
test(gfql): seven test files that ran in NO CI lane at all now run (CA4 / #1795)
`bin/test-polars.sh` is the single source of truth for the polars lane's file list. A file absent from it was only ever collected by `test-gfql-core` — which installs the `test` extra and therefore has NO polars — so a module-level `pytest.importorskip("polars")` skipped the whole file there too. Both lanes green, file executed zero times. Added (the three named in the audit): test_engine_polars_call_modality.py 12 test_viz_pipeline_conformance.py 7 test_engine_polars_gpu.py 5 (self-skips without a GPU; see below) and four more found by the same query rather than by name: test_engine_polars_narrow_combine.py 120 test_engine_polars_semi_key_dedup.py 36 (#1784's ONLY test file, for a polars-ONLY change) index/test_indexed_bindings.py 87 (on the polars lane) test_reentry_caller_graph_immutability.py 18 (#1793's suite; no module-level importorskip, so nothing flagged that its polars params ran nowhere) `test_engine_polars_gpu.py` is listed deliberately even though it self-skips without a GPU: absent from the list it is not even IMPORTED, so a broken import or a renamed helper in it goes unnoticed until someone runs it by hand. WHAT IT SURFACED — one CI-red test, one pre-existing fabricated-failure trap, and NO product failures: 1. `test_indexed_bindings.py::test_explicit_polars_gpu_declines_indexed_helper_and_falls_back` had NO GPU guard. Building the polars frames does not need the RAPIDS stack, so the graph constructed fine and the run died later inside `.gfql()` with `ImportError: GFQL engine='polars-gpu' requires the RAPIDS cudf_polars stack`. Listing the file would have turned the lane RED. `_native_frames` now `importorskip`s `cudf_polars` for that engine. 2. `index/test_index.py` — ALREADY in the lane — built its engine list by appending `"polars-gpu"` when **`cudf`** imported. polars-gpu is the `cudf_polars` collect target and raises without it, so any box with cuDF and no `cudf_polars` (a real configuration) got 20 FABRICATED failures, indistinguishable from product breakage. CI never saw it because its polars lane installs neither. The gate now tests `cudf_polars`. 3. No product failures. Green in both configurations that matter: * cuDF absent (the CI polars lane's own configuration): the FULL lane is 2658 passed / 58 skipped / 0 failed in 160s, plus the appended cypher lowering pass at 49 passed. The lane's timeout is 10 min and it runs twice (plain + coverage); the seven files add ~15s per run. * dgx GB10, `graphistry/test-rapids-official:26.02-gfql-polars`, `docker run --gpus all`, cuDF 26.02.01 / polars 1.35.2 — every cuDF and polars-gpu parameter LIVE: 394 passed, 0 failed, 0 skipped. The 37 failures these files show on a developer box with `cudf` importable but `libnvrtc.so.12` missing are that environment, not the product: they reproduce nowhere with a working CUDA runtime. Re-running on real hardware before reporting them is the whole reason this PR claims "no product failures" rather than filing seven issues. Per-file coverage baselines are FLOORS (`min_coverage_percent`), so adding tests can only move the audit in the passing direction. RUNTIME DELTA: zero. No production line changed — the diff is the lane's file list, two test-file guards and the CHANGELOG — so no pyg-bench lane run is required (CB5), and that claim is checkable from the diff. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_015YsqAZQLbqjSDrYSFz2GoB
1 parent 233b64c commit bb440f9

4 files changed

Lines changed: 38 additions & 1 deletion

File tree

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm
2424
- **Seeded typed-hop property projection keeps its fast path through DISTINCT / ORDER BY / SKIP / LIMIT**: those trailing row ops are plain frame operations, so the fast path now delegates them to the canonical chain instead of declining the whole query.
2525

2626
### Changed
27+
- **Seven GFQL test files that ran in NO CI lane at all now run in the polars lane (#1795)**: `bin/test-polars.sh` is the single source of truth for that lane's file list, and a file absent from it was only ever collected by `test-gfql-core` — which installs the `test` extra and therefore has **no polars**, so a module-level `pytest.importorskip("polars")` skipped the whole file there too. The result is the worst kind of green: both lanes pass and the file has executed zero times. Added: `test_engine_polars_call_modality.py` (12 tests), `test_viz_pipeline_conformance.py` (7), `test_engine_polars_gpu.py` (5) — the three named in the audit — plus four more found by the same query rather than by name: `test_engine_polars_narrow_combine.py` (120), `test_engine_polars_semi_key_dedup.py` (36, the #1784 regression suite, which was the ONLY test file for a polars-only change), `index/test_indexed_bindings.py` (87 on the polars lane) and `test_reentry_caller_graph_immutability.py` (18, the #1793 suite — no module-level importorskip, so nothing flagged that its polars parameters ran nowhere). `test_engine_polars_gpu.py` still self-skips without a GPU and is listed deliberately anyway: absent from the list it is not even imported, so a broken import or a renamed helper in it goes unnoticed until someone runs it by hand. **What it surfaced: one CI-red test and no product failures.** `index/test_indexed_bindings.py::test_explicit_polars_gpu_declines_indexed_helper_and_falls_back` had no GPU guard — building the polars frames does not need the RAPIDS stack, so the graph constructed fine and the run died later inside `.gfql()` with `ImportError: GFQL engine='polars-gpu' requires the RAPIDS cudf_polars stack`. Listing the file would therefore have turned the polars lane red; `_native_frames` now `importorskip`s `cudf_polars` for the `polars-gpu` engine so it skips as the environment fact it is. That an unguarded GPU test could sit in the tree unnoticed is the defect this change fixes, in miniature. Running the assembled lane also caught a **pre-existing** trap in a file that was already listed: `index/test_index.py`'s engine list added `polars-gpu` when **`cudf`** imported, but `polars-gpu` is the `cudf_polars` GPU collect target and raises without it — so any box with cuDF and no `cudf_polars` (a real configuration) got **20 fabricated failures** indistinguishable from product breakage. CI never saw it because its polars lane installs neither. The gate now tests `cudf_polars`. 304 passed with cuDF absent (the CI polars lane's configuration) and 394 passed on the dgx GB10 box against `graphistry/test-rapids-official:26.02-gfql-polars` with cuDF 26.02.01 and `cudf_polars` present, i.e. with every cuDF and polars-gpu parameter live. The 37 failures seen on a developer box with `cudf` importable but `libnvrtc.so.12` missing are that environment, not the product — they reproduce nowhere with a working CUDA runtime, which is exactly why they had to be re-run on real hardware before being reported as findings.
2728
- **`is_lazy` is a type predicate, so the polars engine's eager/lazy split is checked instead of asserted**: `dtypes.is_lazy` decides WHICH member of the two-member `PolarsFrame` union a frame is, but it was declared `-> bool`, so that answer was discarded at the call boundary — an eager-only attribute (`.height`, `.columns`, `.schema`) reached after a lazy guard was unprovable, and the native polars chain closed the gap with `cast("pl.DataFrame", frame)`. A cast is not a type: it re-asserts, unchecked, the exact fact the predicate had just established, once per call site, and a wrong one surfaces as a production `AttributeError` rather than a CI error. `is_lazy` is now declared `-> TypeIs["pl.LazyFrame"]` (PEP 742), which narrows the *negative* branch as well as the positive — the eager side is the one that needed it, so `TypeGuard` would not have done — and the cast is gone. Four previously untyped chain-combine helpers (`_semi`, `_combine_edges`, `_apply_node_names`, and the `_known_empty` guard) now carry real signatures: `_semi`'s two frames share the `PolarsT` TypeVar because polars joins do not mix eagerness, and the two combine helpers take the `_LazyShim` collect-once duck-type they are actually called with. Typing `_apply_node_names` also retired a `getattr(next_step, "edges_empty", None)` — the shim declares that tri-state in `__slots__`, so a typo is now a checker error instead of a silent `None` that would have re-armed the very cardinality gate the guard disarms. Internal only: no runtime behaviour, no public API, and the `TypeIs` import is `TYPE_CHECKING`-only, so no new runtime dependency floor.
2829
- **GFQL execution context is declared rather than attached at runtime**: the private `_gfql_*` per-execution fields (index policy and registry, row-pipeline base graph, carried seed nodes, edge aliases, shortest-path backend, and the indexed-bindings handoff) are now declared on `Plottable` with defaults on `PlotterBase`, instead of being set with `setattr` and read back with `getattr(..., default)`. No public API or behaviour change; internal call sites are typed, and hand-rolled `Plottable` stand-ins must now construct the full context.
2930

bin/test-polars.sh

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,28 @@ POLARS_TEST_FILES=(
3535
# engine-agnostic frame/series primitives (graphistry/Engine.py) — the polars branches of
3636
# these dispatch helpers are only measured when this lane covers graphistry (see cov widen below)
3737
graphistry/tests/test_engine_frame_helpers.py
38+
39+
# --- files that ran in NO CI LANE AT ALL until this list grew (#1795) ---------------------
40+
# Each carries a module-level `pytest.importorskip("polars")` AND was absent here. The
41+
# `test-gfql-core` lane DOES collect graphistry/tests/compute/gfql wholesale, but it
42+
# installs `requirements/test-py*.lock` (the `test` extra), which has no polars — so the
43+
# importorskip fired and the whole file was skipped there, while this lane never saw it.
44+
# A file can therefore be green in both lanes and have executed zero times; adding it here
45+
# is the only thing that makes its assertions real.
46+
graphistry/tests/compute/gfql/test_engine_polars_call_modality.py
47+
graphistry/tests/compute/gfql/test_viz_pipeline_conformance.py
48+
# Collected but SKIPPED without a GPU (its own module-level `skipif(not _gpu_available())`).
49+
# Listed deliberately anyway: absent from this list it is not even imported, so a broken
50+
# import or a renamed helper in it goes unnoticed until someone runs it by hand — and on a
51+
# GPU-capable lane it now actually runs.
52+
graphistry/tests/compute/gfql/test_engine_polars_gpu.py
53+
# Same defect, found by the same query rather than named in the original report:
54+
graphistry/tests/compute/gfql/test_engine_polars_narrow_combine.py
55+
graphistry/tests/compute/gfql/test_engine_polars_semi_key_dedup.py
56+
graphistry/tests/compute/gfql/index/test_indexed_bindings.py
57+
# No module-level importorskip, so nothing flagged it — but every polars parameter in it
58+
# runs only here (the #1793 regression suite).
59+
graphistry/tests/compute/gfql/test_reentry_caller_graph_immutability.py
3860
)
3961

4062
COV_ARGS=()

graphistry/tests/compute/gfql/index/test_index.py

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,13 @@ def _engines():
2929
import polars # noqa
3030
out.append("polars")
3131
try:
32-
import cudf # noqa
32+
# `cudf_polars`, NOT `cudf`: engine='polars-gpu' is the cudf_polars GPU collect
33+
# target and raises `ImportError: GFQL engine='polars-gpu' requires the RAPIDS
34+
# cudf_polars stack` without it. Gating on `cudf` fabricated 20 failures on every
35+
# box that has cuDF but not cudf_polars — a real configuration, and the failures
36+
# are indistinguishable from product breakage. CI never saw it because its polars
37+
# lane installs neither, so the parameter simply did not exist there.
38+
import cudf_polars # noqa
3339
out.append("polars-gpu")
3440
except Exception:
3541
pass

graphistry/tests/compute/gfql/index/test_indexed_bindings.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,14 @@ def _native_frames(
7272
) -> Tuple[Any, Any]:
7373
if engine in ("polars", "polars-gpu"):
7474
pl = pytest.importorskip("polars")
75+
if engine == "polars-gpu":
76+
# Frame construction alone does NOT need the GPU stack, so building the graph
77+
# succeeds without it and the failure lands later, inside `.gfql()`, as
78+
# `ImportError: GFQL engine='polars-gpu' requires the RAPIDS cudf_polars stack`.
79+
# That is an environment fact, not a test outcome — skip here so it reads as one.
80+
# This file ran in no CI lane at all until `bin/test-polars.sh` listed it, which is
81+
# why an unguarded polars-gpu test could sit here unnoticed.
82+
pytest.importorskip("cudf_polars")
7583
return pl.from_pandas(nodes), pl.from_pandas(edges)
7684
if engine == "cudf":
7785
cudf = pytest.importorskip("cudf")

0 commit comments

Comments
 (0)