diff --git a/docs/communities/AMD_Acidophile_Heterotroph_Network.html b/docs/communities/AMD_Acidophile_Heterotroph_Network.html index bd18ff1c..dd12db44 100644 --- a/docs/communities/AMD_Acidophile_Heterotroph_Network.html +++ b/docs/communities/AMD_Acidophile_Heterotroph_Network.html @@ -841,8 +841,8 @@

Organic Carbon Scavenging and Remineralization

  • nitrogen compound metabolic process - (GO:0008152) + (GO:0071941)
  • diff --git a/docs/communities/Anammox_Bioreactor_DNRA_Destabilization_Community.html b/docs/communities/Anammox_Bioreactor_DNRA_Destabilization_Community.html index 4e4c5059..e921e3fa 100644 --- a/docs/communities/Anammox_Bioreactor_DNRA_Destabilization_Community.html +++ b/docs/communities/Anammox_Bioreactor_DNRA_Destabilization_Community.html @@ -604,8 +604,8 @@

    DNRA Competes with Anammox for Nitrogen Removal

  • nitrogen compound metabolic process - (GO:0008152) + (GO:0071941)
  • diff --git a/docs/communities/Coastal_Forested_Wetland_Seawater_Ion_Microcosm_Community.html b/docs/communities/Coastal_Forested_Wetland_Seawater_Ion_Microcosm_Community.html index 9d53dc19..e798cac7 100644 --- a/docs/communities/Coastal_Forested_Wetland_Seawater_Ion_Microcosm_Community.html +++ b/docs/communities/Coastal_Forested_Wetland_Seawater_Ion_Microcosm_Community.html @@ -667,8 +667,8 @@

    Non-Sulfate Seawater Ions Drive Community And Emission Responses

  • organic substance catabolic process - (GO:0008152) + (GO:0009056)
  • @@ -813,8 +813,8 @@

    Artificial Seawater Alters Carbon Nitrogen And Phosphorus Gene Response

  • organic substance catabolic process - (GO:0008152) + (GO:0009056)
  • diff --git a/docs/communities/Model_Lignocellulose_Formaldehyde_Crossfeeding_Community.html b/docs/communities/Model_Lignocellulose_Formaldehyde_Crossfeeding_Community.html index dc2cbbf5..d18f2356 100644 --- a/docs/communities/Model_Lignocellulose_Formaldehyde_Crossfeeding_Community.html +++ b/docs/communities/Model_Lignocellulose_Formaldehyde_Crossfeeding_Community.html @@ -751,17 +751,6 @@

    Methylotrophic Formaldehyde Mitigation

    -

    Biological Processes:

    - - @@ -1307,10 +1296,6 @@

    Evidence

    var processes = []; - - processes.push("metabolic process"); - - var evidenceCount = 1; nodes.push({ diff --git a/docs/communities/ORNL_PMI_Populus_PD10_SynCom.html b/docs/communities/ORNL_PMI_Populus_PD10_SynCom.html index 5f8a6732..961471fc 100644 --- a/docs/communities/ORNL_PMI_Populus_PD10_SynCom.html +++ b/docs/communities/ORNL_PMI_Populus_PD10_SynCom.html @@ -918,12 +918,6 @@

    Medium-Dependent Cross-Feeding

    class="term-link" target="_blank" rel="noopener noreferrer">GO:0044419) -
  • - metabolic process - (GO:0008152) -
  • - @@ -1028,12 +1022,6 @@

    Metabolite Exchange with Pantoea

    class="term-link" target="_blank" rel="noopener noreferrer">GO:0044419) -
  • - metabolic process - (GO:0008152) -
  • - @@ -1086,12 +1074,6 @@

    Cross-Feeding with Rhizobium

    class="term-link" target="_blank" rel="noopener noreferrer">GO:0044419) -
  • - metabolic process - (GO:0008152) -
  • - @@ -1144,12 +1126,6 @@

    Cross-Feeding with Bacillus

    class="term-link" target="_blank" rel="noopener noreferrer">GO:0044419) -
  • - metabolic process - (GO:0008152) -
  • - @@ -1202,12 +1178,6 @@

    Cross-Feeding with Caulobacter

    class="term-link" target="_blank" rel="noopener noreferrer">GO:0044419) -
  • - metabolic process - (GO:0008152) -
  • - @@ -1260,12 +1230,6 @@

    Cross-Feeding with Duganella

    class="term-link" target="_blank" rel="noopener noreferrer">GO:0044419) -
  • - metabolic process - (GO:0008152) -
  • - @@ -1318,12 +1282,6 @@

    Cross-Feeding with Streptomyces

    class="term-link" target="_blank" rel="noopener noreferrer">GO:0044419) -
  • - metabolic process - (GO:0008152) -
  • - @@ -1376,12 +1334,6 @@

    Cross-Feeding with Paraburkholderia

    class="term-link" target="_blank" rel="noopener noreferrer">GO:0044419) -
  • - metabolic process - (GO:0008152) -
  • - @@ -1780,8 +1732,6 @@

    Evidence

    processes.push("interspecies interaction between organisms"); - processes.push("metabolic process"); - var evidenceCount = 1; @@ -1858,8 +1808,6 @@

    Evidence

    processes.push("interspecies interaction between organisms"); - processes.push("metabolic process"); - var evidenceCount = 1; @@ -1898,8 +1846,6 @@

    Evidence

    processes.push("interspecies interaction between organisms"); - processes.push("metabolic process"); - var evidenceCount = 1; @@ -1938,8 +1884,6 @@

    Evidence

    processes.push("interspecies interaction between organisms"); - processes.push("metabolic process"); - var evidenceCount = 1; @@ -1978,8 +1922,6 @@

    Evidence

    processes.push("interspecies interaction between organisms"); - processes.push("metabolic process"); - var evidenceCount = 1; @@ -2018,8 +1960,6 @@

    Evidence

    processes.push("interspecies interaction between organisms"); - processes.push("metabolic process"); - var evidenceCount = 1; @@ -2058,8 +1998,6 @@

    Evidence

    processes.push("interspecies interaction between organisms"); - processes.push("metabolic process"); - var evidenceCount = 1; @@ -2098,8 +2036,6 @@

    Evidence

    processes.push("interspecies interaction between organisms"); - processes.push("metabolic process"); - var evidenceCount = 1; diff --git a/docs/communities/Prairie_Pothole_Wetland_Sulfur_Carbon_Virus_Community.html b/docs/communities/Prairie_Pothole_Wetland_Sulfur_Carbon_Virus_Community.html index 1aa1c2d3..8d8541f4 100644 --- a/docs/communities/Prairie_Pothole_Wetland_Sulfur_Carbon_Virus_Community.html +++ b/docs/communities/Prairie_Pothole_Wetland_Sulfur_Carbon_Virus_Community.html @@ -730,8 +730,8 @@

    Diverse Sulfate-Reduction Guild

  • organic substance catabolic process - (GO:0008152) + (GO:0009056)
  • diff --git a/docs/communities/Stordalen_Mire_Methylotrophic_Methanogenesis_Community.html b/docs/communities/Stordalen_Mire_Methylotrophic_Methanogenesis_Community.html index f18d9ce0..9f05682d 100644 --- a/docs/communities/Stordalen_Mire_Methylotrophic_Methanogenesis_Community.html +++ b/docs/communities/Stordalen_Mire_Methylotrophic_Methanogenesis_Community.html @@ -766,8 +766,8 @@

    Bacterial Anaerobic Methylotrophy

  • organic substance catabolic process - (GO:0008152) + (GO:0009056)
  • diff --git a/docs/communities/Wetland_Oxygen_Sulfate_GHG_Microcosm_Community.html b/docs/communities/Wetland_Oxygen_Sulfate_GHG_Microcosm_Community.html index 07788109..2bb3c606 100644 --- a/docs/communities/Wetland_Oxygen_Sulfate_GHG_Microcosm_Community.html +++ b/docs/communities/Wetland_Oxygen_Sulfate_GHG_Microcosm_Community.html @@ -853,8 +853,8 @@

    Lactate-Sulfate Carbon And Sulfur Subnetwork

  • organic substance catabolic process - (GO:0008152) + (GO:0009056)
  • diff --git a/kb/communities/AMD_Acidophile_Heterotroph_Network.yaml b/kb/communities/AMD_Acidophile_Heterotroph_Network.yaml index 86bd0430..a1f5f07c 100644 --- a/kb/communities/AMD_Acidophile_Heterotroph_Network.yaml +++ b/kb/communities/AMD_Acidophile_Heterotroph_Network.yaml @@ -344,8 +344,8 @@ ecological_interactions: label: aerobic respiration - preferred_term: nitrogen compound metabolic process term: - id: GO:0008152 - label: metabolic process + id: GO:0071941 + label: nitrogen cycle metabolic process evidence: - reference: doi:10.3389/fmicb.2015.00475 supports: SUPPORT diff --git a/kb/communities/Anammox_Bioreactor_DNRA_Destabilization_Community.yaml b/kb/communities/Anammox_Bioreactor_DNRA_Destabilization_Community.yaml index 1382e38b..3fa5e46d 100644 --- a/kb/communities/Anammox_Bioreactor_DNRA_Destabilization_Community.yaml +++ b/kb/communities/Anammox_Bioreactor_DNRA_Destabilization_Community.yaml @@ -164,8 +164,8 @@ ecological_interactions: biological_processes: - preferred_term: nitrogen compound metabolic process term: - id: GO:0008152 - label: metabolic process + id: GO:0071941 + label: nitrogen cycle metabolic process evidence: - reference: PMID:31980038 supports: SUPPORT diff --git a/kb/communities/Coastal_Forested_Wetland_Seawater_Ion_Microcosm_Community.yaml b/kb/communities/Coastal_Forested_Wetland_Seawater_Ion_Microcosm_Community.yaml index 07c19b8a..62505ac2 100644 --- a/kb/communities/Coastal_Forested_Wetland_Seawater_Ion_Microcosm_Community.yaml +++ b/kb/communities/Coastal_Forested_Wetland_Seawater_Ion_Microcosm_Community.yaml @@ -129,8 +129,8 @@ ecological_interactions: label: methanogenesis - preferred_term: organic substance catabolic process term: - id: GO:0008152 - label: metabolic process + id: GO:0009056 + label: catabolic process evidence: - reference: PMID:38628812 supports: SUPPORT @@ -198,8 +198,8 @@ ecological_interactions: biological_processes: - preferred_term: organic substance catabolic process term: - id: GO:0008152 - label: metabolic process + id: GO:0009056 + label: catabolic process evidence: - reference: PMID:38628812 supports: SUPPORT diff --git a/kb/communities/Model_Lignocellulose_Formaldehyde_Crossfeeding_Community.yaml b/kb/communities/Model_Lignocellulose_Formaldehyde_Crossfeeding_Community.yaml index ae57eb40..d2606535 100644 --- a/kb/communities/Model_Lignocellulose_Formaldehyde_Crossfeeding_Community.yaml +++ b/kb/communities/Model_Lignocellulose_Formaldehyde_Crossfeeding_Community.yaml @@ -236,10 +236,6 @@ ecological_interactions: id: CHEBI:16842 label: formaldehyde biological_processes: - - preferred_term: metabolic process - term: - id: GO:0008152 - label: metabolic process evidence: - reference: doi:10.3390/microorganisms9020321 supports: SUPPORT diff --git a/kb/communities/ORNL_PMI_Populus_PD10_SynCom.yaml b/kb/communities/ORNL_PMI_Populus_PD10_SynCom.yaml index ee26916c..f4f0a3e0 100644 --- a/kb/communities/ORNL_PMI_Populus_PD10_SynCom.yaml +++ b/kb/communities/ORNL_PMI_Populus_PD10_SynCom.yaml @@ -327,10 +327,6 @@ ecological_interactions: term: id: GO:0044419 label: biological process involved in interspecies interaction between organisms - - preferred_term: metabolic process - term: - id: GO:0008152 - label: metabolic process evidence: - reference: PMID:33995895 supports: SUPPORT @@ -381,10 +377,6 @@ ecological_interactions: term: id: GO:0044419 label: biological process involved in interspecies interaction between organisms - - preferred_term: metabolic process - term: - id: GO:0008152 - label: metabolic process evidence: - reference: PMID:33995895 supports: SUPPORT @@ -410,10 +402,6 @@ ecological_interactions: term: id: GO:0044419 label: biological process involved in interspecies interaction between organisms - - preferred_term: metabolic process - term: - id: GO:0008152 - label: metabolic process evidence: - reference: PMID:33995895 supports: SUPPORT @@ -439,10 +427,6 @@ ecological_interactions: term: id: GO:0044419 label: biological process involved in interspecies interaction between organisms - - preferred_term: metabolic process - term: - id: GO:0008152 - label: metabolic process evidence: - reference: PMID:33995895 supports: SUPPORT @@ -468,10 +452,6 @@ ecological_interactions: term: id: GO:0044419 label: biological process involved in interspecies interaction between organisms - - preferred_term: metabolic process - term: - id: GO:0008152 - label: metabolic process evidence: - reference: PMID:33995895 supports: SUPPORT @@ -497,10 +477,6 @@ ecological_interactions: term: id: GO:0044419 label: biological process involved in interspecies interaction between organisms - - preferred_term: metabolic process - term: - id: GO:0008152 - label: metabolic process evidence: - reference: PMID:33995895 supports: SUPPORT @@ -526,10 +502,6 @@ ecological_interactions: term: id: GO:0044419 label: biological process involved in interspecies interaction between organisms - - preferred_term: metabolic process - term: - id: GO:0008152 - label: metabolic process evidence: - reference: PMID:33995895 supports: SUPPORT @@ -555,10 +527,6 @@ ecological_interactions: term: id: GO:0044419 label: biological process involved in interspecies interaction between organisms - - preferred_term: metabolic process - term: - id: GO:0008152 - label: metabolic process evidence: - reference: PMID:33995895 supports: SUPPORT diff --git a/kb/communities/Prairie_Pothole_Wetland_Sulfur_Carbon_Virus_Community.yaml b/kb/communities/Prairie_Pothole_Wetland_Sulfur_Carbon_Virus_Community.yaml index 27f6c697..d912c7a9 100644 --- a/kb/communities/Prairie_Pothole_Wetland_Sulfur_Carbon_Virus_Community.yaml +++ b/kb/communities/Prairie_Pothole_Wetland_Sulfur_Carbon_Virus_Community.yaml @@ -165,8 +165,8 @@ ecological_interactions: label: dissimilatory sulfate reduction - preferred_term: organic substance catabolic process term: - id: GO:0008152 - label: metabolic process + id: GO:0009056 + label: catabolic process evidence: - reference: PMID:30086797 supports: SUPPORT diff --git a/kb/communities/Stordalen_Mire_Methylotrophic_Methanogenesis_Community.yaml b/kb/communities/Stordalen_Mire_Methylotrophic_Methanogenesis_Community.yaml index 277d5b72..35bc7029 100644 --- a/kb/communities/Stordalen_Mire_Methylotrophic_Methanogenesis_Community.yaml +++ b/kb/communities/Stordalen_Mire_Methylotrophic_Methanogenesis_Community.yaml @@ -189,8 +189,8 @@ ecological_interactions: biological_processes: - preferred_term: organic substance catabolic process term: - id: GO:0008152 - label: metabolic process + id: GO:0009056 + label: catabolic process evidence: - reference: PMID:38063415 supports: SUPPORT diff --git a/kb/communities/Wetland_Oxygen_Sulfate_GHG_Microcosm_Community.yaml b/kb/communities/Wetland_Oxygen_Sulfate_GHG_Microcosm_Community.yaml index 67237861..ca01e829 100644 --- a/kb/communities/Wetland_Oxygen_Sulfate_GHG_Microcosm_Community.yaml +++ b/kb/communities/Wetland_Oxygen_Sulfate_GHG_Microcosm_Community.yaml @@ -233,8 +233,8 @@ ecological_interactions: label: dissimilatory sulfate reduction - preferred_term: organic substance catabolic process term: - id: GO:0008152 - label: metabolic process + id: GO:0009056 + label: catabolic process evidence: - reference: PMID:38961111 supports: SUPPORT diff --git a/tests/test_no_vacuous_go_annotations.py b/tests/test_no_vacuous_go_annotations.py new file mode 100644 index 00000000..938572eb --- /dev/null +++ b/tests/test_no_vacuous_go_annotations.py @@ -0,0 +1,158 @@ +"""Some GO terms are true of every record here, so they annotate nothing (#182). + +The #180 id↔label cleanup remapped obsolete GO ids to their nearest *valid* +term. For a handful that meant climbing to a near-root process, and the result +was sixteen annotations reading + + - preferred_term: metabolic process + term: + id: GO:0008152 + label: metabolic process + +on records in a knowledge base about **microbial communities**, every one of +which does metabolism. Nine were exactly that and were dropped. Seven carried a +real concept in `preferred_term` that had been flattened onto the generic +parent, and were re-grounded rather than deleted: + + organic substance catabolic process -> GO:0009056 catabolic process + nitrogen compound metabolic process -> GO:0071941 nitrogen cycle metabolic process + +Both targets are current; the precise terms a curator would want +(`GO:0006807`, `GO:1901575`) are **obsolete in GO**, which is why they were +flattened in the first place. `GO:0071941` was already used twice elsewhere in +the KB, so this follows an existing convention rather than inventing one. + +`term` is `required: true` on `BiologicalProcessDescriptor`, so "drop the +annotation" necessarily means dropping the whole descriptor — there is no way to +keep an ungrounded `preferred_term`. That is why upgrading beats deleting +wherever a current term exists. +""" + +from __future__ import annotations + +import pathlib + +import pytest +import yaml + +REPO = pathlib.Path(__file__).parent.parent +COMMUNITIES = REPO / "kb/communities" + +# GO terms so close to the root of the biological-process branch that asserting +# them of a microbial community conveys nothing. Each needs a reason, so that +# adding one is a decision rather than a reflex. +_VACUOUS = { + "GO:0008152": "'metabolic process' — true of every organism in the KB", + "GO:0008150": "'biological_process' — the branch root", +} + + +def _walk(node, filename): + """Descriptors under `node`. Module-level so it does not close over the loop + variable — a nested closure here reads `path` from the enclosing scope at + *call* time, which for a generator is after the loop has moved on (ruff + B023). Harmless in this shape, wrong the moment the generator is not drained + immediately.""" + if isinstance(node, dict): + term = node.get("term") + if node.get("preferred_term") and isinstance(term, dict) and term.get("id"): + yield filename, node["preferred_term"], term["id"], term.get("label") + for value in node.values(): + yield from _walk(value, filename) + elif isinstance(node, list): + for value in node: + yield from _walk(value, filename) + + +def _descriptors(corpus: pathlib.Path | None = None): + """Every (file, preferred_term, id, label) biological-process descriptor.""" + for path in sorted((corpus or COMMUNITIES).glob("*.yaml")): + document = yaml.safe_load(path.read_text(encoding="utf-8")) or {} + yield from _walk(document, path.name) + + +def test_no_record_is_annotated_with_a_vacuous_process(): + """The gate.""" + offenders = [ + f"{name}: {preferred!r} -> {identifier} ({_VACUOUS[identifier]})" + for name, preferred, identifier, _label in _descriptors() + if identifier in _VACUOUS + ] + assert offenders == [], ( + "these annotations are true of every community in the KB and so " + "distinguish nothing (#182). Ground the concept in `preferred_term` to " + "a specific current GO term, or drop the descriptor:\n" + + "\n".join(f" {line}" for line in offenders) + ) + + +def test_the_upgraded_terms_are_present_and_correctly_labelled(): + """The seven that were re-grounded rather than deleted. + + Asserts the label travelled with the id: a remap that changed one and not + the other is the exact defect #180 existed to clear, and re-introducing it + here would be ironic. + """ + by_id = {} + for _name, _preferred, identifier, label in _descriptors(): + by_id.setdefault(identifier, set()).add(label) + + assert by_id.get("GO:0009056") == { + "catabolic process" + }, f"GO:0009056 carries unexpected labels: {by_id.get('GO:0009056')}" + assert by_id.get("GO:0071941") == { + "nitrogen cycle metabolic process" + }, f"GO:0071941 carries unexpected labels: {by_id.get('GO:0071941')}" + + +@pytest.mark.parametrize("identifier", sorted(_VACUOUS)) +def test_every_blocked_term_has_a_reason(identifier): + """A blocklist without reasons becomes a place things get added silently.""" + assert _VACUOUS[identifier].strip() + + +def test_the_walk_reaches_the_corpus(): + """An empty walk passes the gate as surely as a clean corpus does.""" + seen = list(_descriptors()) + assert len(seen) > 500, f"only {len(seen)} descriptors walked; the walk is broken" + + +def test_the_gate_can_fire(tmp_path): + """Mutation check, driving the real walk over a record built to offend.""" + corpus = tmp_path / "communities" + corpus.mkdir() + (corpus / "r.yaml").write_text( + "id: CommunityMech:000999\n" + "ecological_interactions:\n" + "- biological_processes:\n" + " - preferred_term: metabolic process\n" + " term:\n" + " id: GO:0008152\n" + " label: metabolic process\n", + encoding="utf-8", + ) + offenders = [d for d in _descriptors(corpus) if d[2] in _VACUOUS] + assert offenders, "the gate found nothing in a record built to contain the defect" + assert offenders[0][1] == "metabolic process" + + +def test_a_specific_process_is_not_flagged(tmp_path): + """Guard against the gate being over-broad. + + A correctly grounded specific term also has `preferred_term == label`; that + is what good curation looks like, not a defect. The gate must key on the + identifier, never on the two strings matching. + """ + corpus = tmp_path / "communities" + corpus.mkdir() + (corpus / "r.yaml").write_text( + "id: CommunityMech:000998\n" + "ecological_interactions:\n" + "- biological_processes:\n" + " - preferred_term: nitrogen cycle metabolic process\n" + " term:\n" + " id: GO:0071941\n" + " label: nitrogen cycle metabolic process\n", + encoding="utf-8", + ) + assert [d for d in _descriptors(corpus) if d[2] in _VACUOUS] == []