Repository navigation
fix(gfql): crash family — polars filter helpers (#1882, #1913-f4) + nodes-only pandas Cypher (#1879) - #1942
Merged
Conversation
- filter_by_dict: dispatch polars frames to the native filter_by_dict_polars (public filter_nodes_by_dict/filter_edges_by_dict/filter_by_dict crashed with AttributeError: 'assign'; polars-in comes back polars) (#1882) - prune_self_edges: polars-native filter (boolean __getitem__ selects COLUMNS in polars); pandas null-endpoint semantics preserved (#1913 finding-4) - chain: a nodes-only graph serves node-only chains via an internally synthesized empty edge frame (dropped from the result), and declines edge-op chains with a typed GFQLSchemaError instead of a bare TypeError at ast.py:265; policy on/off now agree (#1879 pandas half) - pins: graphistry/tests/compute/gfql/test_crash_family_1882_1879.py (19 red at master e6625ed, 30 green here) Co-Authored-By: Claude Fable 5 <[email protected]> Claude-Session: https://claude.ai/code/session_01AjbKuKheqDu78oapRT5AYm
…mments Co-Authored-By: Claude Fable 5 <[email protected]> Claude-Session: https://claude.ai/code/session_01AjbKuKheqDu78oapRT5AYm
lmeyerov
added a commit
that referenced
this pull request
Aug 19, 2026
lmeyerov
added a commit
that referenced
this pull request
Aug 19, 2026
Lane-F regenerated the baseline from a pre-#1942 tree (chain.py 7 findings); #1942 landed an 8th on master with its cap. The clean merge kept the stale tighter caps, failing the merge ref — the two-green-PRs baseline-union hazard in comment form. chain.py entries restored to master's values; every other entry keeps this branch's downward-only movement. Co-Authored-By: Claude Opus 5 <[email protected]> Claude-Session: https://claude.ai/code/session_01AjbKuKheqDu78oapRT5AYm
pull Bot
pushed a commit
to admariner/pygraphistry
that referenced
this pull request
Aug 19, 2026
…ph shapes (graphistry#1889) `gfql_validate` returned `{ok: True, diagnostics: []}` on a graph whose frames were never attached (`graphistry.bind(...)` names columns only), then execution died with a bare `ValueError: Missing edges` (pandas/cuDF `materialize_nodes`) or an empty-message `AssertionError` (polars `ensure_nodes_polars`). A preflight that approves what the runtime always rejects is drift by construction. Both sides now consult one predicate, `validate_graph_shape`: * neither nodes nor edges bound -> GFQLSchemaError E305 `graph-not-bound` (new code), with a bind remedy -- raised by the validator AND by execution on every engine (pandas/cuDF via `validate_chain_schema`, polars via the pre-dispatch guard). * edges unbound + an edge pattern -> E304, the same typed decline execution already gave (graphistry#1942); the validator no longer stays silent about it. * nodes-only + node-only pattern stays admitted on both sides and keeps answering. `schema=False` callers (remote preflight, which holds no local frames) skip the shape check, so `chain_remote` is unaffected. Pins: `test_validate_execute_agreement_1889.py` -- the 4 filed combos x {pandas, polars} agreement matrix (10/18 red at master 0c3f3a1), typed-code pins on both surfaces, value-level served-record oracles, and the not-flagged shapes (bound graph, edges-only, schema=False). Each of the 5 fix sites was mutation-checked. `test_gfql_validate_only`'s structural-only expectation moved to `schema=False`, which is what it was really pinning. Co-Authored-By: Claude Fable 5 <[email protected]> Claude-Session: https://claude.ai/code/session_01AjbKuKheqDu78oapRT5AYm
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Pre-release crash-family fixes, all verified live at master
e6625ed28with hand-computed oracles.#1882 — public
filter_by_dicthelpers crash on polars frames (FIXED — Fixes #1882)filter_nodes_by_dict/filter_edges_by_dict/ barefilter_by_dicton polars frames raisedAttributeError: 'DataFrame' object has no attribute 'assign'(filter_by_dict.pybuilt the mask with pandas idioms afterresolve_enginerouted POLARS). Fix:filter_by_dictnow dispatches POLARS-resolved frames to the existing nativefilter_by_dict_polars(same column resolution via the sharedresolve_filter_column, same typed E301/E302 errors, same 3VL membership semantics). Polars-in comes back polars — no silent engine swap; explicitengine='pandas'coercion is unchanged. Exotic predicates with no native polars lowering keep the engine's existing parity-or-error NIE contract (as GFQL polars chains already do).The two secondary findings in the #1882 body (
seeded_typed_hoplazy-frame decline,get_degreesnodes-only divergence) are NOT addressed here — #1882 can close on its headline defect per its title, or stay open if those are tracked under it.#1913 finding-4 — same family on
prune_self_edges(PARTIAL: finding 4 only)prune_self_edgeson polars edges hit polars' column-selecting boolean__getitem__: rawValueError, and it would silently select COLUMNS whenever the row count equals the column count. Now polars-native (.filterexpression, eager and lazy), preserving pandas'NaN != x -> keepnull-endpoint row semantics; polars-in stays polars. Thefilter_nodes_by_dict/filter_edges_by_dicthalf of finding 4 falls out of the #1882 fix and is pinned. #1913 stays open: findings 1–3 (stale-index rebind resurrection, recovery-recipe failures, completeness-lock blind spots) are untouched here.#1879 — Cypher/chain on nodes-only graphs (PARTIAL: pandas half + advice)
On a graph whose edges were NEVER bound, all pandas Cypher/chain died with a bare
TypeError: 'NoneType' object is not subscriptable(ast.py:265slicingg._edges[:0]), with or without a policy attached — the policy toggle was inert because both paths crashed. Now:MATCH (n) …needs no edges): the chain executor synthesizes an internal empty edge frame for node-only op lists and drops it from the result (nodes-only in, nodes-only out; policy on/off agree, and the pins assert the hooks actually fire).GFQLSchemaErrorE304 "Cannot traverse edges: graph has no edges bound" instead of the bare TypeError, on both the Cypher andchain()surfaces.NotImplementedErrordecline, and its "use engine='pandas'" guidance now points at an engine that serves — pinned live (the pin runs the recommended engine and checks the answer).#1879 stays open for the polars half: polars still declines node-only patterns on nodes-only graphs (typed, with working advice) rather than serving them; serving there means teaching
_chain_traversal_polars/ its node-only fast case to run without bound edge endpoints. ASTCall-bearing chains on nodes-only graphs also keep their pre-existing behavior (out of scope).Pins & anti-vacuity
graphistry/tests/compute/gfql/test_crash_family_1882_1879.py(registered inbin/test-polars.shPOLARS_TEST_FILES): 30 tests, 19 red at mastere6625ed28/ 11 both-sides pins green there; all 30 green at this head. Mutation checks: each fix piece reverted independently is caught (filter dispatch → 6 pins; prune polars branch → 1; chain synthesize → 10; typed decline → 2; result strip → 1).Gates
graphistry/tests/computefailure SET identical to master's baseline apart from the new pins (details in checks);gfql/index/test_index.py(GFQL: legitimate .edges() rebind resurrects a STALE adjacency index (silent wrong answers, both engines) + documented recovery fails #1913 rebind/index contracts) failure set identical to master (its 38 cudf-param fails are environmental —libnvrtc.so.12missing on this box, identical at master; pandas/polars all pass)🤖 Generated with Claude Code
https://claude.ai/code/session_01AjbKuKheqDu78oapRT5AYm