Skip to content

Commit aa53ad4

Browse files
committed
fix graph_builder expectation of a single query term
1 parent 399888e commit aa53ad4

2 files changed

Lines changed: 60 additions & 0 deletions

File tree

src/test/test_graph_builder.py

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -295,6 +295,32 @@ def test_empty(self, monkeypatch):
295295
_mock_batch_lookup(monkeypatch)
296296
assert graph_from_downstream_class([], "FBbt_x") is None
297297

298+
def test_filters_to_input_term_block(self, monkeypatch):
299+
"""Per-subclass result blocks are filtered to the queried class itself
300+
(query_id == primary_id); rows tagged with a subclass query_id are
301+
excluded so the same partner isn't duplicated / its edge conflated
302+
across (sub)class blocks."""
303+
_mock_batch_lookup(monkeypatch)
304+
rows = [
305+
# input-term block (query_id == primary)
306+
{"id": "FBbt_d1", "query_id": "FBbt_primary",
307+
"upstream_class": "[KC](FBbt_primary)", "downstream_class": "[MBON-01](FBbt_d1)",
308+
"total_n": 100, "connected_n": 50, "percent_connected": 50,
309+
"pairwise_connections": 200, "total_weight": 5000, "avg_weight": 25},
310+
# subclass block — SAME partner, must be excluded from the graph
311+
{"id": "FBbt_d1", "query_id": "FBbt_sub1",
312+
"upstream_class": "[KC subtype](FBbt_sub1)", "downstream_class": "[MBON-01](FBbt_d1)",
313+
"total_n": 10, "connected_n": 5, "percent_connected": 50,
314+
"pairwise_connections": 20, "total_weight": 500, "avg_weight": 25},
315+
]
316+
g = graph_from_downstream_class(rows, "FBbt_primary", "KC")
317+
assert g is not None
318+
assert len(g["nodes"]) == 2 # primary + the one input-term partner
319+
assert len(g["edges"]) == 1
320+
assert g["edges"][0]["source"] == "FBbt_primary"
321+
assert g["edges"][0]["target"] == "FBbt_d1"
322+
assert g["edges"][0]["weight"] == 5000 # input-term block, not the subclass's 500
323+
298324

299325
class TestGraphFromUpstreamClass:
300326
def test_basic(self, monkeypatch):
@@ -316,6 +342,30 @@ def test_empty(self, monkeypatch):
316342
_mock_batch_lookup(monkeypatch)
317343
assert graph_from_upstream_class([], "FBbt_x") is None
318344

345+
def test_filters_to_input_term_block(self, monkeypatch):
346+
"""Only the queried class's own block (query_id == primary_id) feeds the
347+
graph; subclass blocks are excluded so partners aren't duplicated /
348+
edges conflated across (sub)classes."""
349+
_mock_batch_lookup(monkeypatch)
350+
rows = [
351+
{"id": "FBbt_u1", "query_id": "FBbt_primary",
352+
"upstream_class": "[PN1](FBbt_u1)", "downstream_class": "[KC](FBbt_primary)",
353+
"total_n": 60, "connected_n": 30, "percent_connected": 50,
354+
"pairwise_connections": 150, "total_weight": 3000, "avg_weight": 20},
355+
# subclass block — SAME partner, must be excluded
356+
{"id": "FBbt_u1", "query_id": "FBbt_sub1",
357+
"upstream_class": "[PN1](FBbt_u1)", "downstream_class": "[KC subtype](FBbt_sub1)",
358+
"total_n": 12, "connected_n": 6, "percent_connected": 50,
359+
"pairwise_connections": 30, "total_weight": 600, "avg_weight": 20},
360+
]
361+
g = graph_from_upstream_class(rows, "FBbt_primary", "KC")
362+
assert g is not None
363+
assert len(g["nodes"]) == 2 # primary + the one input-term partner
364+
assert len(g["edges"]) == 1
365+
assert g["edges"][0]["source"] == "FBbt_u1"
366+
assert g["edges"][0]["target"] == "FBbt_primary"
367+
assert g["edges"][0]["weight"] == 3000 # input-term block, not the subclass's 600
368+
319369

320370
# ---------------------------------------------------------------------------
321371
# Integration tests (require network access to Neo4j)

src/vfbquery/graph_builder.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -504,6 +504,11 @@ def graph_from_downstream_class(rows, primary_id, primary_label=None):
504504
:param primary_id: short_form of the query neuron class
505505
:param primary_label: fallback label
506506
"""
507+
# Class connectivity now returns one block of rows per queried (sub)class;
508+
# the graph reflects only the queried class itself, so keep the input-term
509+
# block (query_id == primary_id). ``None`` tolerates older cached rows that
510+
# predate the query_id field.
511+
rows = [r for r in rows if r.get("query_id") in (None, primary_id)]
507512
if not rows:
508513
return None
509514

@@ -574,6 +579,11 @@ def graph_from_upstream_class(rows, primary_id, primary_label=None):
574579
:param primary_id: short_form of the query neuron class
575580
:param primary_label: fallback label
576581
"""
582+
# Class connectivity now returns one block of rows per queried (sub)class;
583+
# the graph reflects only the queried class itself, so keep the input-term
584+
# block (query_id == primary_id). ``None`` tolerates older cached rows that
585+
# predate the query_id field.
586+
rows = [r for r in rows if r.get("query_id") in (None, primary_id)]
577587
if not rows:
578588
return None
579589

0 commit comments

Comments
 (0)