Commit a101735
* test(gfql): decide #1793's clear-vs-restore question, and pin it (#1793 review)
Review asked whether `clear_row_exec_context` should RESTORE the value the graph
carried on entry rather than NULLing it — a fair question, because
`attach_row_exec_context` INHERITS on the way in (a `None` argument keeps what
`g` already carries), so an outer scope's value can reach an inner execution and
be dropped by it.
Determination: NULL is correct and restore would reintroduce #1786. Three
reasons, each now carried by a test rather than by argument:
1. `clear` is PURE. It returns `g.bind()` and never writes through to the
object it was handed, so an outer scope that set the field still has it
afterwards. There is no caller state to save. That is exactly what
separates this from #1786, which WAS an in-place write onto the caller's
own graph — restore is the fix for a mutation, and there is no mutation.
2. The only channel restore would change is the RETURN VALUE, and putting the
seed back there IS the second half of #1786 ("the result of a WITH query
carries the seed, and a follow-up query on that result is answered against
it"). Measured: hand-restoring the seed onto a result changes the answer of
the next query on it (7 -> 2 -> 1 rows).
3. No execution frame inherits a context it did not set. Instrumenting
`attach` over `graphistry/tests/compute` recorded 3907 calls and ZERO
inheriting ones. 53 DID enter on a graph already carrying a seed (nested
boundary frames) but each was handed the IDENTICAL `start_nodes` parameter,
so the frame still owns what it sets. The cross-segment WITH seed travels
as the explicit `start_nodes` PARAMETER (`chain_impl(..., start_nodes=)`,
`_compiled_query_reentry_state`), never through the graph field, so the
field's lifetime is exactly one boundary-call run.
`test_exec_context_scoping.py` re-runs that ownership measurement as an
assertion over a corpus of the shapes that reach every attach site, so a future
path that starts relying on inheritance reopens this decision loudly instead of
silently losing an outer value.
MUTATION-CHECKED IN THE DECIDING DIRECTION: implementing save/restore at all
three attach sites (chain, native polars chain, gfql_unified) fails 4 of the new
tests on every runnable engine — while the existing #1793 suite
(`test_reentry_caller_graph_immutability.py`) passes UNCHANGED. Those tests
could not distinguish the two designs; this file can, which is why it exists.
Engine-parametrized over pandas/polars/cuDF/polars-gpu with a fixed engine list
plus a runtime probe (not `available_nonpandas_engines()`, which silently
shrinks): a non-runnable engine reports SKIPPED, it does not vanish from the
report. Also added to `bin/test-polars.sh` — the file has no module-level
`importorskip`, so nothing would otherwise have flagged that its polars params
run in no lane (#1795 class).
RUNTIME DELTA: zero. No production line changed; the only non-test edits are the
`clear_row_exec_context` docstring and a CHANGELOG entry, so no pyg-bench lane
run is required (CB5).
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015YsqAZQLbqjSDrYSFz2GoB
* test(gfql): classify engine availability instead of swallowing every failure
The first version of this file's engine probe wrapped a smoke query in a bare
`except Exception: return False`. Two things went wrong with that, both found by
trying rather than by argument (on the sibling #1788/#1790 parametrization):
* a probe that runs THE SHAPE UNDER TEST disarms its own file — reverting a
production guard made the probe raise and every parameter reported SKIPPED
instead of failing;
* a probe that swallows EVERYTHING is worse — a transient
`MemoryError: ... cudaErrorMemoryAllocation` in a fresh GPU container
silently dropped cuDF from a run that otherwise passed, and a skipped GPU
parameter reads as evidence of passing.
So the check now CLASSIFIES: a missing module skips, a recognisable GPU-stack
error skips WITH ITS TEXT QUOTED in the reason, and any other failure
propagates. The smoke query stays a plain traversal, never the shape under test.
GPU receipts — dgx GB10, `graphistry/test-rapids-official:26.02-gfql-polars`,
`docker run --gpus all`, cuDF 26.02.01 / polars 1.35.2: 43 passed, 0 skipped
(this file plus the #1793 suite), repeated.
The marker list is duplicated from the copy landing in `polars_test_utils.py`
alongside the #1788/#1790 parametrization; collapse to one definition once both
land. Kept duplicated for now so the two PRs stay independently mergeable.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015YsqAZQLbqjSDrYSFz2GoB
---------
Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
1 parent d08720e commit a101735
4 files changed
Lines changed: 374 additions & 0 deletions
File tree
- bin
- graphistry
- compute/gfql
- tests/compute/gfql
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
25 | 25 | | |
26 | 26 | | |
27 | 27 | | |
| 28 | + | |
28 | 29 | | |
29 | 30 | | |
30 | 31 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
30 | 30 | | |
31 | 31 | | |
32 | 32 | | |
| 33 | + | |
| 34 | + | |
| 35 | + | |
33 | 36 | | |
34 | 37 | | |
35 | 38 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
48 | 48 | | |
49 | 49 | | |
50 | 50 | | |
| 51 | + | |
| 52 | + | |
| 53 | + | |
| 54 | + | |
| 55 | + | |
| 56 | + | |
| 57 | + | |
| 58 | + | |
| 59 | + | |
| 60 | + | |
| 61 | + | |
| 62 | + | |
| 63 | + | |
| 64 | + | |
| 65 | + | |
| 66 | + | |
| 67 | + | |
| 68 | + | |
| 69 | + | |
| 70 | + | |
| 71 | + | |
| 72 | + | |
| 73 | + | |
51 | 74 | | |
52 | 75 | | |
53 | 76 | | |
| |||
0 commit comments