Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm

- **dgx GB10 benchmark safety harness**: `benchmarks/dgx/{safe_run.sh, preflight.py, sitecustomize.py, local_run.sh}` — an RMM device-allocation cap + host-memory watchdog + preflight refusal + hard timeout for running GPU / large-graph benchmarks on the unified-memory GB10 box without OOM-wedging it. Developer/benchmark tooling only; no runtime or library behavior change.
- **Docs CI: polars in the doc-test image (pinned)**: the Sphinx doc-example runner now installs `polars` (pinned to cooldown-safe versions) so `engine='polars'` documentation examples execute — and are SKIPPED, not failed, where polars is unavailable (e.g. the minimal-deps job, Python 3.14). Doc-build / CI only; no runtime or library change.
- **openCypher TCK conformance: `EXISTS { }` existential-subquery scenarios (`expr-existentialsubquery1-1`, `1-3`) now pass**, unblocking the `tck-gfql` CI job. No pygraphistry code change — pygraphistry already renders these correctly (a whole-entity `RETURN n` over a simple-pattern `EXISTS { }` yields the expected entity-text rows). The `success_wrong_rows` was purely a property-map display-whitespace convention (`(:A {prop: 1})` vs the TCK oracle's `(:A {prop:1})`; both valid Cypher). Reconciled harness-side in [tck-gfql#193](https://github.com/graphistry/tck-gfql/pull/193): entity-text whitespace normalization + promoting the two scenarios to supported (and deflaking the pre-existing scipy-`svds` `firstparty-networkx-hits-1` fixture). Conformance/CI only; no runtime or library behavior change.

## [0.57.0 - 2026-06-28]

Expand Down
6 changes: 6 additions & 0 deletions graphistry/compute/gfql/cypher/result_postprocess.py
Original file line number Diff line number Diff line change
Expand Up @@ -186,6 +186,12 @@ def render_entity_text(
the Cypher display string (``(:Label {..})`` / ``[:TYPE {..}]``). Used by the
conformance/TCK driver and by callers who want the human-readable form. The
structured data path itself never pays this cost.

Property maps render with a space after the key colon (``(:A {prop: 1})``) —
our long-standing display convention. The openCypher TCK oracle omits it
(``(:A {prop:1})``); the whitespace is insignificant Cypher, so the TCK
harness normalizes it rather than us changing this convention across ~350
tests (see tck-gfql#193 / CHANGELOG).
"""
rows_df = cast(DataFrameT, result._nodes)
if rows_df is None:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -752,6 +752,39 @@ def test_exists_prune_isolated_flavors_all_engines():
_assert_invariant(g, q, f"prune-isolated {q}")


def test_exists_whole_entity_return_renders_entity_text():
"""Regression for openCypher TCK expr-existentialsubquery1-1 (tck-gfql#193):
a WHOLE-ENTITY ``RETURN n`` over a simple-pattern ``EXISTS { }`` renders the
correct entity text (label + property), not leaked internal marker columns.
Graph mirrors the TCK fixture — node ``a`` is the only one with an out-edge —
so the EXISTS filter keeps exactly ``a`` and it renders ``(:A {prop: 1})``.

``id`` is a STRING on purpose: a numeric id would render as an extra
property (``{id: 0, prop: 1}``). ``n.id`` is the #1650 flattened
whole-entity projection column, not user-aliased output."""
import pandas as pd
from graphistry.compute.gfql.cypher.result_postprocess import render_entity_text
nodes = pd.DataFrame({
"id": ["a", "b", "c", "d"],
"label__A": [True, False, False, False],
"label__B": [False, True, False, False],
"label__C": [False, False, True, False],
"label__D": [False, False, False, True],
"prop": [1, 1, 2, 3],
})
edges = pd.DataFrame({"s": ["a", "a", "a"], "d": ["b", "c", "d"], "eid": [0, 1, 2]})
g = graphistry.nodes(nodes, "id").edges(edges, "s", "d").bind(edge="eid")
q = "MATCH (n) WHERE EXISTS { (n)-->() } RETURN n"
res = g.gfql(q, engine="pandas")
pdf = _to_pd(res._nodes)
assert len(pdf) == 1, "EXISTS keeps exactly the one node with an out-edge"
assert pdf["n.id"].tolist() == ["a"]
assert render_entity_text(res, "n", table="nodes").tolist() == ["(:A {prop: 1})"]
# Cross-engine (this file's invariant): non-pandas engines match pandas
# parity or decline honestly (NIE) — whole-entity RETURN declines on polars.
_assert_invariant(g, q, "exists-whole-entity-return")


def test_tolower_non_string_declines_never_fabricates():
"""toLower/toUpper on a non-string column must never return values (neo4j: type error).
Regression (#1675 wave-1, dgx-repro'd): the scalar fallback broadcast the lowercased
Expand Down
Loading