Skip to content

Commit 7a754fc

Browse files
Merge pull request #125 from reactome/rna-table-100
rnas.csv: list RNA species per network (deltasignal specs/100)
2 parents c15e27d + 135af3c commit 7a754fc

5 files changed

Lines changed: 78 additions & 4 deletions

File tree

‎src/logic_network_generator.py‎

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4010,9 +4010,24 @@ def export_pathogens(pathway_logic_network: pd.DataFrame,
40104010
get_pathogen_entities, "pathogen-derived")
40114011

40124012

4013+
def export_rnas(pathway_logic_network: pd.DataFrame,
4014+
reactome_id_to_uuid: Dict[str, str],
4015+
output_file: str) -> None:
4016+
"""Write rnas.csv: which entities in THIS network are RNA species (deltasignal
4017+
specs/100), by :func:`src.neo4j_connector.get_rna_entities`. A consumer joins
4018+
node copies of one RNA (a root mRNA copy reads the copy transcription makes).
4019+
Same columns and always-written rule as drugs.csv and pathogens.csv."""
4020+
from src.neo4j_connector import get_rna_entities
4021+
# only nodes that ARE an RNA species: a variant of a complex that chose an RNA
4022+
# member (a miR-26A RISC) is a complex, not the RNA (the drug rule's member
4023+
# clause would list it; the first variant build listed 2,393 such rows)
4024+
_export_derived(pathway_logic_network, reactome_id_to_uuid, output_file,
4025+
get_rna_entities, "RNA", by_member=False)
4026+
4027+
40134028
def _export_derived(pathway_logic_network: pd.DataFrame,
40144029
reactome_id_to_uuid: Dict[str, str],
4015-
output_file: str, finder, label: str) -> None:
4030+
output_file: str, finder, label: str, by_member: bool = True) -> None:
40164031
"""The node listing shared by drugs.csv and pathogens.csv. ``finder`` maps
40174032
stable ids to {stId: {"schema_class", "name"}} for the derived ones."""
40184033
from src.neo4j_connector import get_reactome_release
@@ -4042,7 +4057,8 @@ def parts(node_id: str):
40424057
rows = []
40434058
for n in sorted(node_ids):
40444059
parent, members = parts(n)
4045-
hit = parent if parent in derived else next((m for m in members if m in derived), None)
4060+
hit = parent if parent in derived else \
4061+
(next((m for m in members if m in derived), None) if by_member else None)
40464062
if hit is None:
40474063
continue
40484064
rows.append({"stable_id": n, "schema_class": derived[hit]["schema_class"],

‎src/neo4j_connector.py‎

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -942,6 +942,20 @@ def derived(s: str, depth: int = 0) -> bool:
942942
PROTEIN_REFERENCE_CLASSES = frozenset({"ReferenceGeneProduct", "ReferenceIsoform"})
943943

944944

945+
def get_rna_entities(stable_ids) -> Dict[str, Dict[str, str]]:
946+
"""The entities among ``stable_ids`` that are RNA: an entity whose reference
947+
entity is a ReferenceRNASequence (an mRNA, a miRNA), with schema class and
948+
display name (deltasignal specs/100). Complexes and sets are not listed: the
949+
consumer twins node copies of one RNA species, never of a complex holding one."""
950+
ids = sorted({s for s in stable_ids if s})
951+
if not ids:
952+
return {}
953+
rows = get_graph().run(
954+
"UNWIND $ids AS s MATCH (e:PhysicalEntity {stId: s})-[:referenceEntity]->(:ReferenceRNASequence) "
955+
"RETURN s, e.schemaClass AS c, e.displayName AS n", ids=ids).data()
956+
return {r["s"]: {"schema_class": r["c"], "name": r["n"]} for r in rows}
957+
958+
945959
def get_pathogen_entities(stable_ids) -> Dict[str, Dict[str, str]]:
946960
"""The entities among ``stable_ids`` that are PATHOGEN-DERIVED, with their
947961
schema class and display name (deltasignal specs/048).

‎src/pathway_generator.py‎

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
export_drugs,
1616
export_pathogens,
1717
export_pools,
18+
export_rnas,
1819
export_containment,
1920
export_containment_structure,
2021
export_entity_reaction_proxy_mapping,
@@ -234,7 +235,7 @@ def _write_cache_fingerprint(
234235
"logic_network.csv", "stid_to_uuid_mapping.csv", "entity_reaction_proxy_mapping.csv",
235236
"nodes.csv", "node_reaction_context.csv", "node_resolution.csv", "node_exclusions.csv",
236237
"boundary_edges.csv", "cofactors.csv", "containment.csv", "containment_structure.csv",
237-
"drugs.csv", "pathogens.csv",
238+
"drugs.csv", "pathogens.csv", "rnas.csv",
238239
"pools.csv", "pool_transitions.csv", "pool_carriers.csv", "carrier_loops.csv",
239240
)
240241

@@ -615,6 +616,17 @@ def generate_pathway_file(
615616
logger.error(f"Failed to write pathogens.csv: {e}", exc_info=True)
616617
raise
617618

619+
# RNA species (deltasignal specs/100), likewise on their own.
620+
try:
621+
export_rnas(
622+
result.logic_network,
623+
result.uuid_mapping,
624+
str(pathway_output_dir / "rnas.csv"),
625+
)
626+
except Exception as e:
627+
logger.error(f"Failed to write rnas.csv: {e}", exc_info=True)
628+
raise
629+
618630
# Interconversion pools (deltasignal specs/039), in their own block.
619631
try:
620632
export_pools(

‎tests/test_export_failfast.py‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@
2424
EXPORTS = ["export_uuid_to_reactome_mapping", "export_entity_reaction_proxy_mapping",
2525
"export_nodes", "export_node_reaction_context", "export_node_resolution",
2626
"export_cofactors", "export_containment", "export_containment_structure",
27-
"export_drugs", "export_pathogens", "export_pools"]
27+
"export_drugs", "export_pathogens", "export_rnas", "export_pools"]
2828

2929

3030
@pytest.fixture

‎tests/test_provenance_exports.py‎

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -510,3 +510,35 @@ def test_pathogen_polymer_counts_through_its_repeated_unit(monkeypatch):
510510
monkeypatch.setenv("LNG_PATHOGEN_PROTEIN", "1")
511511
assert set(neo4j_connector.get_pathogen_entities(cache)) == {"REV", "POLY", "C"}
512512

513+
514+
515+
# --- rnas.csv (deltasignal specs/100) ------------------------------------------
516+
517+
def test_export_rnas_lists_rna_species(tmp_path, monkeypatch):
518+
monkeypatch.setattr(neo4j_connector, "get_rna_entities",
519+
lambda stids: {"R-HSA-MRNA": {"schema_class": "EntityWithAccessionedSequence",
520+
"name": "PTEN mRNA [cytosol]"}})
521+
monkeypatch.setattr(neo4j_connector, "get_reactome_release", lambda: 97)
522+
out = tmp_path / "rnas.csv"
523+
risc = "R-HSA-RISC::variant::R-HSA-MRNA" # a complex variant that chose the RNA
524+
m.export_rnas(pd.DataFrame([{"source_id": "u-1", "target_id": "u-2"}, {"source_id": "u-3", "target_id": "u-2"}]),
525+
{"R-HSA-MRNA": "u-1", "R-HSA-P": "u-2", risc: "u-3"}, str(out))
526+
df = pd.read_csv(out)
527+
assert list(df.columns) == ["stable_id", "schema_class", "name", "reactome_release"]
528+
assert list(df.stable_id) == ["R-HSA-MRNA"] # the complex variant is not listed
529+
530+
531+
def test_rna_finder_reads_the_reference_entity_class(monkeypatch):
532+
seen = {}
533+
class G:
534+
def run(self, q, **kw):
535+
seen["q"] = q
536+
class R:
537+
def data(self_inner):
538+
return [{"s": "R-HSA-MRNA", "c": "EntityWithAccessionedSequence", "n": "PTEN mRNA"}]
539+
return R()
540+
monkeypatch.setattr(neo4j_connector, "get_graph", lambda: G())
541+
assert neo4j_connector.get_rna_entities({"R-HSA-MRNA", "R-HSA-P", ""}) == {
542+
"R-HSA-MRNA": {"schema_class": "EntityWithAccessionedSequence", "name": "PTEN mRNA"}}
543+
assert "ReferenceRNASequence" in seen["q"]
544+
assert neo4j_connector.get_rna_entities(set()) == {}

0 commit comments

Comments
 (0)