@@ -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
299325class 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)
0 commit comments