From ebcd75d43fffe44b1ba117ebcc6e6c517ca145c2 Mon Sep 17 00:00:00 2001 From: Chris Mungall Date: Wed, 15 May 2024 10:46:14 -0700 Subject: [PATCH 01/10] Making prefix mapping less strict, fixes #702 Adds test that currently codifies ambiguous behavior. See also #760 for broader issue. This PR also extends the obo test suite to include this, and adds some derived files previously missing. --- .../interfaces/basic_ontology_interface.py | 2 +- tests/input/obo-compliance.obo | 61 ++++++++ .../expansion-conflict-main-idspace.meta.yaml | 4 + .../expansion-conflict-main-idspace.obo | 10 ++ .../gci-is-a/gci-is-a.expected.json | 31 ++++ .../gci-is-a/gci-is-a.expected.owl | 83 +++++++++++ .../gci-is-a/gci-is-a.meta.yaml | 3 + .../obo-compliance/gci-is-a/gci-is-a.obo | 7 + .../gci-relation/gci-relation.expected.json | 31 ++++ .../gci-relation/gci-relation.expected.owl | 104 ++++++++++++++ .../gci-relation/gci-relation.meta.yaml | 3 + .../gci-relation/gci-relation.obo | 7 + .../prefixes-conflict-main-idspace.meta.yaml | 4 + .../prefixes-conflict-main-idspace.obo | 9 ++ .../prefixes-conflict-oio.expected.json | 33 +++++ .../prefixes-conflict-oio.expected.owl | 81 +++++++++++ .../prefixes-conflict-oio.meta.yaml | 4 + .../prefixes-conflict-oio.obo | 9 ++ .../prefixes-conflict-skos.expected.json | 38 +++++ .../prefixes-conflict-skos.expected.owl | 81 +++++++++++ .../prefixes-conflict-skos.meta.yaml | 4 + .../prefixes-conflict-skos.obo | 12 ++ .../prefixes-created_by.obo | 1 - tests/test_converters/test_obo_format.py | 136 ++++++++++++++++-- tests/test_implementations/test_pronto.py | 16 +++ tests/test_implementations/test_simple_obo.py | 16 +++ 26 files changed, 773 insertions(+), 17 deletions(-) create mode 100644 tests/input/obo-compliance/expansion-conflict-main-idspace/expansion-conflict-main-idspace.meta.yaml create mode 100644 tests/input/obo-compliance/expansion-conflict-main-idspace/expansion-conflict-main-idspace.obo create mode 100644 tests/input/obo-compliance/gci-is-a/gci-is-a.expected.json create mode 100644 tests/input/obo-compliance/gci-is-a/gci-is-a.expected.owl create mode 100644 tests/input/obo-compliance/gci-is-a/gci-is-a.meta.yaml create mode 100644 tests/input/obo-compliance/gci-is-a/gci-is-a.obo create mode 100644 tests/input/obo-compliance/gci-relation/gci-relation.expected.json create mode 100644 tests/input/obo-compliance/gci-relation/gci-relation.expected.owl create mode 100644 tests/input/obo-compliance/gci-relation/gci-relation.meta.yaml create mode 100644 tests/input/obo-compliance/gci-relation/gci-relation.obo create mode 100644 tests/input/obo-compliance/prefixes-conflict-main-idspace/prefixes-conflict-main-idspace.meta.yaml create mode 100644 tests/input/obo-compliance/prefixes-conflict-main-idspace/prefixes-conflict-main-idspace.obo create mode 100644 tests/input/obo-compliance/prefixes-conflict-oio/prefixes-conflict-oio.expected.json create mode 100644 tests/input/obo-compliance/prefixes-conflict-oio/prefixes-conflict-oio.expected.owl create mode 100644 tests/input/obo-compliance/prefixes-conflict-oio/prefixes-conflict-oio.meta.yaml create mode 100644 tests/input/obo-compliance/prefixes-conflict-oio/prefixes-conflict-oio.obo create mode 100644 tests/input/obo-compliance/prefixes-conflict-skos/prefixes-conflict-skos.expected.json create mode 100644 tests/input/obo-compliance/prefixes-conflict-skos/prefixes-conflict-skos.expected.owl create mode 100644 tests/input/obo-compliance/prefixes-conflict-skos/prefixes-conflict-skos.meta.yaml create mode 100644 tests/input/obo-compliance/prefixes-conflict-skos/prefixes-conflict-skos.obo diff --git a/src/oaklib/interfaces/basic_ontology_interface.py b/src/oaklib/interfaces/basic_ontology_interface.py index 22038ab30..a5d8d1afa 100644 --- a/src/oaklib/interfaces/basic_ontology_interface.py +++ b/src/oaklib/interfaces/basic_ontology_interface.py @@ -203,7 +203,7 @@ def converter(self) -> curies.Converter: :return: A converter """ if self._converter is None: - self._converter = curies.Converter.from_prefix_map(self.prefix_map()) + self._converter = curies.Converter.from_prefix_map(self.prefix_map(), strict=False) return self._converter def set_metamodel_mappings(self, mappings: Union[str, Path, List[Mapping]]) -> None: diff --git a/tests/input/obo-compliance.obo b/tests/input/obo-compliance.obo index f70afd914..20df87b16 100644 --- a/tests/input/obo-compliance.obo +++ b/tests/input/obo-compliance.obo @@ -565,6 +565,53 @@ idspace: Y http://example.org/Y/ id: X:1 created_by: Y:1 +!! name: prefixes-conflict-oio +!! description: tests conflicting prefixes/contractions for oboInOwl namespace, where oio might be built-in +!! unstable: true +!! seeAlso: https://github.com/INCATools/ontology-access-kit/issues/760 +idspace: oboInOwl http://www.geneontology.org/formats/oboInOwl# + +[Term] +id: X:1 +name: X:1 +def: "." [] + +!! name: prefixes-conflict-skos +!! description: tests conflicting prefixes for the SKOS namespace +!! unstable: true +!! seeAlso: https://github.com/INCATools/ontology-access-kit/issues/760 +idspace: skos http://example.org/not-skos/ + +[Term] +id: X:1 +property_value: skos:exactMatch Y:1 + +[Typedef] +id: skos:exactMatch +is_metadata_tag: true + +!! name: prefixes-conflict-main-idspace +!! description: tests conflicting prefixes for the main ID space +!! invalid: true +!! seeAlso: https://github.com/INCATools/ontology-access-kit/issues/760 +idspace: X http://example.org/X/ +idspace: FAKEX http://example.org/X/ + +[Term] +id: X:1 +name: X:1 + +!! name: expansion-conflict-main-idspace +!! description: tests conflicting expansions for the main ID space +!! invalid: true +!! seeAlso: https://github.com/INCATools/ontology-access-kit/issues/760 +idspace: X http://example.org/X/ +idspace: X http://example.org/FAKEX/ + +[Term] +id: X:1 +name: X:1 + !! # ######### !! # Headers !! # ######### @@ -658,6 +705,20 @@ subset: S {source="PMID:123464"} id: X:1 disjoint_from: X:2 {source="PMID:123465"} +!! name: gci-relation +!! description: General Class Inclusion relation + +[Term] +id: X:1 +relationship: R:1 X:2 {gci_predicate="R:2", gci_filler="X:3"} + +!! name: gci-is-a +!! description: General Class Inclusion is_a + +[Term] +id: X:1 +is_a: X:2 {gci_predicate="R:2", gci_filler="X:3"} + !! name: created_by-annotated !! description: Metadata for creator with annotation diff --git a/tests/input/obo-compliance/expansion-conflict-main-idspace/expansion-conflict-main-idspace.meta.yaml b/tests/input/obo-compliance/expansion-conflict-main-idspace/expansion-conflict-main-idspace.meta.yaml new file mode 100644 index 000000000..8e57bb043 --- /dev/null +++ b/tests/input/obo-compliance/expansion-conflict-main-idspace/expansion-conflict-main-idspace.meta.yaml @@ -0,0 +1,4 @@ +name: expansion-conflict-main-idspace +name: expansion-conflict-main-idspace +description: tests conflicting expansions for the main ID space +invalid: true \ No newline at end of file diff --git a/tests/input/obo-compliance/expansion-conflict-main-idspace/expansion-conflict-main-idspace.obo b/tests/input/obo-compliance/expansion-conflict-main-idspace/expansion-conflict-main-idspace.obo new file mode 100644 index 000000000..1d96a591a --- /dev/null +++ b/tests/input/obo-compliance/expansion-conflict-main-idspace/expansion-conflict-main-idspace.obo @@ -0,0 +1,10 @@ +format-version: 1.4 +ontology: expansion-conflict-main-idspace +idspace: X http://example.org/X/ +idspace: X http://example.org/FAKEX/ + +[Term] +id: X:1 +name: X:1 + + diff --git a/tests/input/obo-compliance/gci-is-a/gci-is-a.expected.json b/tests/input/obo-compliance/gci-is-a/gci-is-a.expected.json new file mode 100644 index 000000000..3acf8d565 --- /dev/null +++ b/tests/input/obo-compliance/gci-is-a/gci-is-a.expected.json @@ -0,0 +1,31 @@ +{ + "graphs" : [ { + "id" : "http://purl.obolibrary.org/obo/gci-is-a.owl", + "meta" : { + "basicPropertyValues" : [ { + "pred" : "http://www.geneontology.org/formats/oboInOwl#hasOBOFormatVersion", + "val" : "1.4" + } ] + }, + "nodes" : [ { + "id" : "http://www.geneontology.org/formats/oboInOwl#hasOBOFormatVersion", + "lbl" : "has_obo_format_version", + "type" : "PROPERTY" + }, { + "id" : "http://www.geneontology.org/formats/oboInOwl#id", + "lbl" : "id", + "type" : "PROPERTY" + } ], + "edges" : [ { + "sub" : "http://purl.obolibrary.org/obo/X_1", + "pred" : "is_a", + "obj" : "http://purl.obolibrary.org/obo/X_2", + "meta" : { + "basicPropertyValues" : [ { + "pred" : "http://www.geneontology.org/formats/oboInOwl#gci_predicate", + "val" : "R:2" + } ] + } + } ] + } ] +} \ No newline at end of file diff --git a/tests/input/obo-compliance/gci-is-a/gci-is-a.expected.owl b/tests/input/obo-compliance/gci-is-a/gci-is-a.expected.owl new file mode 100644 index 000000000..2c52ec4b4 --- /dev/null +++ b/tests/input/obo-compliance/gci-is-a/gci-is-a.expected.owl @@ -0,0 +1,83 @@ + + + + 1.4 + + + + + + + + + + + + + + + + + + + has_obo_format_version + + + + + + + + id + + + + + + + + + + + + + + X:1 + + + + + + R:2 + + + + + + + + + + + + + diff --git a/tests/input/obo-compliance/gci-is-a/gci-is-a.meta.yaml b/tests/input/obo-compliance/gci-is-a/gci-is-a.meta.yaml new file mode 100644 index 000000000..d896fb72f --- /dev/null +++ b/tests/input/obo-compliance/gci-is-a/gci-is-a.meta.yaml @@ -0,0 +1,3 @@ +name: gci-is-a +name: gci-is-a +description: General Class Inclusion is_a \ No newline at end of file diff --git a/tests/input/obo-compliance/gci-is-a/gci-is-a.obo b/tests/input/obo-compliance/gci-is-a/gci-is-a.obo new file mode 100644 index 000000000..37ac76264 --- /dev/null +++ b/tests/input/obo-compliance/gci-is-a/gci-is-a.obo @@ -0,0 +1,7 @@ +format-version: 1.4 +ontology: gci-is-a + +[Term] +id: X:1 +is_a: X:2 {gci_predicate="R:2", gci_filler="X:3"} + diff --git a/tests/input/obo-compliance/gci-relation/gci-relation.expected.json b/tests/input/obo-compliance/gci-relation/gci-relation.expected.json new file mode 100644 index 000000000..091f684f0 --- /dev/null +++ b/tests/input/obo-compliance/gci-relation/gci-relation.expected.json @@ -0,0 +1,31 @@ +{ + "graphs" : [ { + "id" : "http://purl.obolibrary.org/obo/gci-relation.owl", + "meta" : { + "basicPropertyValues" : [ { + "pred" : "http://www.geneontology.org/formats/oboInOwl#hasOBOFormatVersion", + "val" : "1.4" + } ] + }, + "nodes" : [ { + "id" : "http://www.geneontology.org/formats/oboInOwl#hasOBOFormatVersion", + "lbl" : "has_obo_format_version", + "type" : "PROPERTY" + }, { + "id" : "http://www.geneontology.org/formats/oboInOwl#id", + "lbl" : "id", + "type" : "PROPERTY" + } ], + "edges" : [ { + "sub" : "http://purl.obolibrary.org/obo/X_1", + "pred" : "http://purl.obolibrary.org/obo/R_1", + "obj" : "http://purl.obolibrary.org/obo/X_2", + "meta" : { + "basicPropertyValues" : [ { + "pred" : "http://www.geneontology.org/formats/oboInOwl#gci_predicate", + "val" : "R:2" + } ] + } + } ] + } ] +} \ No newline at end of file diff --git a/tests/input/obo-compliance/gci-relation/gci-relation.expected.owl b/tests/input/obo-compliance/gci-relation/gci-relation.expected.owl new file mode 100644 index 000000000..826fe43d4 --- /dev/null +++ b/tests/input/obo-compliance/gci-relation/gci-relation.expected.owl @@ -0,0 +1,104 @@ + + + + 1.4 + + + + + + + + + + + + + + + + + + + has_obo_format_version + + + + + + + + id + + + + + + + + + + + + + + + + + + + + + + + + + X:1 + + + + + + + + + + R:2 + + + + + + + + + + + + + diff --git a/tests/input/obo-compliance/gci-relation/gci-relation.meta.yaml b/tests/input/obo-compliance/gci-relation/gci-relation.meta.yaml new file mode 100644 index 000000000..eceb19845 --- /dev/null +++ b/tests/input/obo-compliance/gci-relation/gci-relation.meta.yaml @@ -0,0 +1,3 @@ +name: gci-relation +name: gci-relation +description: General Class Inclusion relation \ No newline at end of file diff --git a/tests/input/obo-compliance/gci-relation/gci-relation.obo b/tests/input/obo-compliance/gci-relation/gci-relation.obo new file mode 100644 index 000000000..89d296e94 --- /dev/null +++ b/tests/input/obo-compliance/gci-relation/gci-relation.obo @@ -0,0 +1,7 @@ +format-version: 1.4 +ontology: gci-relation + +[Term] +id: X:1 +relationship: R:1 X:2 {gci_predicate="R:2", gci_filler="X:3"} + diff --git a/tests/input/obo-compliance/prefixes-conflict-main-idspace/prefixes-conflict-main-idspace.meta.yaml b/tests/input/obo-compliance/prefixes-conflict-main-idspace/prefixes-conflict-main-idspace.meta.yaml new file mode 100644 index 000000000..bb65f539e --- /dev/null +++ b/tests/input/obo-compliance/prefixes-conflict-main-idspace/prefixes-conflict-main-idspace.meta.yaml @@ -0,0 +1,4 @@ +name: prefixes-conflict-main-idspace +name: prefixes-conflict-main-idspace +description: tests conflicting prefixes for the main ID space +invalid: true \ No newline at end of file diff --git a/tests/input/obo-compliance/prefixes-conflict-main-idspace/prefixes-conflict-main-idspace.obo b/tests/input/obo-compliance/prefixes-conflict-main-idspace/prefixes-conflict-main-idspace.obo new file mode 100644 index 000000000..e6e80a0ba --- /dev/null +++ b/tests/input/obo-compliance/prefixes-conflict-main-idspace/prefixes-conflict-main-idspace.obo @@ -0,0 +1,9 @@ +format-version: 1.4 +ontology: prefixes-conflict-main-idspace +idspace: X http://example.org/X/ +idspace: FAKEX http://example.org/X/ + +[Term] +id: X:1 +name: X:1 + diff --git a/tests/input/obo-compliance/prefixes-conflict-oio/prefixes-conflict-oio.expected.json b/tests/input/obo-compliance/prefixes-conflict-oio/prefixes-conflict-oio.expected.json new file mode 100644 index 000000000..d8b4987c2 --- /dev/null +++ b/tests/input/obo-compliance/prefixes-conflict-oio/prefixes-conflict-oio.expected.json @@ -0,0 +1,33 @@ +{ + "graphs" : [ { + "id" : "http://purl.obolibrary.org/obo/prefixes-conflict-oio.owl", + "meta" : { + "basicPropertyValues" : [ { + "pred" : "http://www.geneontology.org/formats/oboInOwl#hasOBOFormatVersion", + "val" : "1.4" + } ] + }, + "nodes" : [ { + "id" : "http://purl.obolibrary.org/obo/IAO_0000115", + "lbl" : "definition", + "type" : "PROPERTY" + }, { + "id" : "http://purl.obolibrary.org/obo/X_1", + "lbl" : "X:1", + "type" : "CLASS", + "meta" : { + "definition" : { + "val" : "." + } + } + }, { + "id" : "http://www.geneontology.org/formats/oboInOwl#hasOBOFormatVersion", + "lbl" : "has_obo_format_version", + "type" : "PROPERTY" + }, { + "id" : "http://www.geneontology.org/formats/oboInOwl#id", + "lbl" : "id", + "type" : "PROPERTY" + } ] + } ] +} \ No newline at end of file diff --git a/tests/input/obo-compliance/prefixes-conflict-oio/prefixes-conflict-oio.expected.owl b/tests/input/obo-compliance/prefixes-conflict-oio/prefixes-conflict-oio.expected.owl new file mode 100644 index 000000000..4cd6d71c9 --- /dev/null +++ b/tests/input/obo-compliance/prefixes-conflict-oio/prefixes-conflict-oio.expected.owl @@ -0,0 +1,81 @@ + + + + 1.4 + + + + + + + + + + + + + definition + + + + + + + + has_obo_format_version + + + + + + + + id + + + + + + + + + + + + + + + + + + + . + X:1 + X:1 + + + + + + + diff --git a/tests/input/obo-compliance/prefixes-conflict-oio/prefixes-conflict-oio.meta.yaml b/tests/input/obo-compliance/prefixes-conflict-oio/prefixes-conflict-oio.meta.yaml new file mode 100644 index 000000000..07c2775ad --- /dev/null +++ b/tests/input/obo-compliance/prefixes-conflict-oio/prefixes-conflict-oio.meta.yaml @@ -0,0 +1,4 @@ +name: prefixes-conflict-oio +name: prefixes-conflict-oio +description: tests conflicting prefixes/contractions for oboInOwl namespace, where oio might be built-in +unstable: true \ No newline at end of file diff --git a/tests/input/obo-compliance/prefixes-conflict-oio/prefixes-conflict-oio.obo b/tests/input/obo-compliance/prefixes-conflict-oio/prefixes-conflict-oio.obo new file mode 100644 index 000000000..ef80fa07b --- /dev/null +++ b/tests/input/obo-compliance/prefixes-conflict-oio/prefixes-conflict-oio.obo @@ -0,0 +1,9 @@ +format-version: 1.4 +ontology: prefixes-conflict-oio +idspace: oboInOwl http://www.geneontology.org/formats/oboInOwl# + +[Term] +id: X:1 +name: X:1 +def: "." [] + diff --git a/tests/input/obo-compliance/prefixes-conflict-skos/prefixes-conflict-skos.expected.json b/tests/input/obo-compliance/prefixes-conflict-skos/prefixes-conflict-skos.expected.json new file mode 100644 index 000000000..c2e92992c --- /dev/null +++ b/tests/input/obo-compliance/prefixes-conflict-skos/prefixes-conflict-skos.expected.json @@ -0,0 +1,38 @@ +{ + "graphs" : [ { + "id" : "http://purl.obolibrary.org/obo/prefixes-conflict-skos.owl", + "meta" : { + "basicPropertyValues" : [ { + "pred" : "http://www.geneontology.org/formats/oboInOwl#hasOBOFormatVersion", + "val" : "1.4" + } ] + }, + "nodes" : [ { + "id" : "http://example.org/not-skos/exactMatch", + "type" : "PROPERTY", + "meta" : { + "basicPropertyValues" : [ { + "pred" : "http://www.geneontology.org/formats/oboInOwl#is_metadata_tag", + "val" : "true" + } ] + } + }, { + "id" : "http://purl.obolibrary.org/obo/X_1", + "type" : "CLASS", + "meta" : { + "basicPropertyValues" : [ { + "pred" : "http://example.org/not-skos/exactMatch", + "val" : "http://purl.obolibrary.org/obo/Y_1" + } ] + } + }, { + "id" : "http://www.geneontology.org/formats/oboInOwl#hasOBOFormatVersion", + "lbl" : "has_obo_format_version", + "type" : "PROPERTY" + }, { + "id" : "http://www.geneontology.org/formats/oboInOwl#id", + "lbl" : "id", + "type" : "PROPERTY" + } ] + } ] +} \ No newline at end of file diff --git a/tests/input/obo-compliance/prefixes-conflict-skos/prefixes-conflict-skos.expected.owl b/tests/input/obo-compliance/prefixes-conflict-skos/prefixes-conflict-skos.expected.owl new file mode 100644 index 000000000..389b2d20a --- /dev/null +++ b/tests/input/obo-compliance/prefixes-conflict-skos/prefixes-conflict-skos.expected.owl @@ -0,0 +1,81 @@ + + + + 1.4 + + + + + + + + + + + + + skos:exactMatch + true + + + + + + + + has_obo_format_version + + + + + + + + id + + + + + + + + + + + + + + + + + + + + X:1 + + + + + + + diff --git a/tests/input/obo-compliance/prefixes-conflict-skos/prefixes-conflict-skos.meta.yaml b/tests/input/obo-compliance/prefixes-conflict-skos/prefixes-conflict-skos.meta.yaml new file mode 100644 index 000000000..f7fc31b2a --- /dev/null +++ b/tests/input/obo-compliance/prefixes-conflict-skos/prefixes-conflict-skos.meta.yaml @@ -0,0 +1,4 @@ +name: prefixes-conflict-skos +name: prefixes-conflict-skos +description: tests conflicting prefixes for the SKOS namespace +unstable: true \ No newline at end of file diff --git a/tests/input/obo-compliance/prefixes-conflict-skos/prefixes-conflict-skos.obo b/tests/input/obo-compliance/prefixes-conflict-skos/prefixes-conflict-skos.obo new file mode 100644 index 000000000..829a2173f --- /dev/null +++ b/tests/input/obo-compliance/prefixes-conflict-skos/prefixes-conflict-skos.obo @@ -0,0 +1,12 @@ +format-version: 1.4 +ontology: prefixes-conflict-skos +idspace: skos http://example.org/not-skos/ + +[Term] +id: X:1 +property_value: skos:exactMatch Y:1 + +[Typedef] +id: skos:exactMatch +is_metadata_tag: true + diff --git a/tests/input/obo-compliance/prefixes-created_by/prefixes-created_by.obo b/tests/input/obo-compliance/prefixes-created_by/prefixes-created_by.obo index d74ef1fbb..e58492d16 100644 --- a/tests/input/obo-compliance/prefixes-created_by/prefixes-created_by.obo +++ b/tests/input/obo-compliance/prefixes-created_by/prefixes-created_by.obo @@ -6,4 +6,3 @@ idspace: Y http://example.org/Y/ id: X:1 created_by: Y:1 - diff --git a/tests/test_converters/test_obo_format.py b/tests/test_converters/test_obo_format.py index 33a28df33..1b937aac3 100644 --- a/tests/test_converters/test_obo_format.py +++ b/tests/test_converters/test_obo_format.py @@ -8,13 +8,77 @@ Note: some of these tests may migrate from OAK to a more central location. -Currently these tests do two things: +Currently the tests in this suite do two things: -1. Compile a compliance suite by converting from a source .obo file +1. Compile a compliance suite by converting from a source .obo file (COMPILED_OBO_FILE) - writes to tests/input/obo-compliance - these may eventually be moved to a separate repo 2. Test that conversion to and from .obo matches these files - generates files in tests/output/obo-compliance + +Step 1: Generate the compliance suite +-------------------------------------- + +Step 1 is intended to be run relatively infrequently. It generates the source-of-truth "expected" files. +Note there is some bootstrapping here. We trust a certain version of robot/obographs/owlapi to generate the +canonical files. For the first iteration these should be manually inspected to see if they align to the spec. +Once we are happy with these, in general they should not change again. + +The source file COMPILED_OBO_FILE looks like this: + +.. code-block:: obo + + !! name: name + !! description: rdfs:label + + [Term] + id: X:1 + name: x1 + + !! name: invalid-name-duplicate + !! description: max 1 name + !! invalid: true + + [Term] + id: X:1 + name: x1 + name: x2 + + !! name: namespace + !! description: oio:namespace + + [Term] + id: X:1 + namespace: NS1 + + !! name: xref + !! description: rdfs:label + +This is designed for easy editing. New tests can be added by providing !! separators +and name/description metadata. + +If new tests are added, test_generate_canonical_files in unskip mode. This will generate the directories in +tests/input/obo-compliance + +E.g. + +.. code-block:: bash + + alt_id/ + alt_id.obo + alt_id.meta.yaml + +Next, robot will be run from the command line to generate the expected files: + +- alt_id.expected.json +- alt_id.expected.obo +- alt_id.expected.ofn +- alt_id.expected.owl + +Step 2: Checking current behavior against the compliance suite +-------------------------------------------------------------- + + """ import difflib @@ -24,7 +88,7 @@ import subprocess from functools import lru_cache from pathlib import Path -from typing import Optional +from typing import Optional, Union, Tuple import pytest import rdflib @@ -202,15 +266,18 @@ def test_generate_canonical_files(split_compiled_obo, output_format): make_filename(ontology_id, "expected", output_format, parent=OBO_COMPLIANCE_DIR) ) if canonical_path.exists(): - logger.info(f"(skipping) Comparing {output_path} to {canonical_path}") - # compare_output(path, ontology_id, "robot", output_format) + print(f"Comparing {output_path} to {canonical_path}") + compare_output(output_path, canonical_path, output_format, strict=True) else: canonical_path.parent.mkdir(exist_ok=True, parents=True) # copy the output to the input dir # logger.info(f"Copying {output_path} to {canonical_path}") shutil.copy(output_path, canonical_path) + shutil.copy(mk_version_path(output_path), mk_version_path(canonical_path)) else: assert ok is None + print(f"DID NOT CONVERT {path} to {output_path}") + assert False @pytest.mark.parametrize( @@ -226,6 +293,9 @@ def test_oak_loaders_dumpers(split_compiled_obo, output_format, wrapper): """ Tests that conversion via OAK generates files that are compliant. + This tests the conversion from .obo format (these are generated in advance from source, see + docs above) into other formats using OAK. + :param split_compiled_obo: :param output_format: :param wrapper: @@ -255,23 +325,29 @@ def test_oak_loaders_dumpers(split_compiled_obo, output_format, wrapper): # non-canonical forms are not expected to be identical continue canonical = canonical_path(ontology_id, output_format) - _, _, fatal = compare_output( - output_path, canonical, output_format, metadata=metadata[ontology_id] + compare_output( + output_path, canonical, output_format, metadata=metadata[ontology_id], strict=False ) - if output_format == "obo": - assert not fatal def compare_output( - generated_path: str, canonical_path: str, format: str = None, metadata: dict = None -): + generated_path: str, canonical_path: str, format: str = None, metadata: dict = None, strict=False, +) -> Tuple[int, list, bool]: """ Compare the output of OAK loading and dumping vs canonical files. + In all cases difflib is used over ascii representations + + - for obo files, the diff is a simple ascii diff (this sensitive to line ordering) + - for json files, the files are reserialized to canonicalize the order of keys + - for owl files, the files are reserialized using rdflib + + The constant KNOWN_ISSUES holds the list of test names that are known to be problematic. + :param generated_path: :param canonical_path: :param format: - :return: + :return: Tuple of [number of changes, list of diffs, fatal] """ fatal = False if not metadata: @@ -314,10 +390,12 @@ def compare_output( expected = "EXPECTED" else: if name in KNOWN_ISSUES: - expected = "TOD" + expected = "TODO" else: expected = "UNEXPECTED" - fatal = False + fatal = True + if strict: + raise ValueError(f"UNEXPECTED DIFF {format}: {canonical_path} vs {generated_path}") logger.info(f"## {name}:: {expected} DIFF {format}: {canonical_path} vs {generated_path}:") for diff in diffs: logger.info(diff) @@ -394,6 +472,15 @@ def canonical_path(ontology_id: str, output_format: str) -> str: return str(OBO_COMPLIANCE_DIR / ontology_id / f"{ontology_id}.expected.{output_format}") +def mk_version_path(path: Union[str, Path]) -> str: + """ + Make a version path for a given path. + + :param path: + :return: + """ + return f"{path}.versioninfo" + def robot_convert(input_path: str, output_path: str) -> Optional[bool]: """ Convert an ontology using robot. @@ -403,24 +490,43 @@ def robot_convert(input_path: str, output_path: str) -> Optional[bool]: :return: """ if not robot_is_on_path(): + logger.warning(f"ROBOT NOT ON PATH") return None cmd = [ "robot", "convert", "-i", input_path, + # "-t", + # "http://www.geneontology.org/formats/oboInOwl#id", + # "convert", "-o", output_path, ] try: + print(f"Running {cmd}") result = subprocess.run(cmd, check=True, capture_output=True, text=True) if result.stderr: logging.warning(result.stderr) logging.info(result.stdout) - return True except subprocess.CalledProcessError as e: logging.info(f"Robot call failed: {e}") return False + try: + version_meta_file = mk_version_path(output_path) + version_cmd = [ + "robot", + "--version", + ] + with open(version_meta_file, "w") as outfile: + result = subprocess.run(version_cmd, check=True, stdout=outfile, text=True) + if result.stderr: + logging.warning(result.stderr) + logging.info(result.stdout) + return True + except subprocess.CalledProcessError as e: + logging.info(f"Robot --version call failed: {e}") + return False def ogger_convert(input_path: str, output_path: str) -> Optional[bool]: diff --git a/tests/test_implementations/test_pronto.py b/tests/test_implementations/test_pronto.py index 3c5610fce..d9625b807 100644 --- a/tests/test_implementations/test_pronto.py +++ b/tests/test_implementations/test_pronto.py @@ -86,6 +86,22 @@ def test_custom_prefixes(self): if iri is not None: self.assertEqual(oi.uri_to_curie(iri), curie, f"in contract iri: {iri}") + def test_conflicting_oio_prefixes(self): + """ + See https://github.com/INCATools/ontology-access-kit/issues/702 + """ + resource = OntologyResource(slug="metadata-map-prefixes-test.obo", directory=INPUT_DIR, local=True) + adapter = ProntoImplementation(resource) + m = adapter.entity_metadata_map("HP:0000001") + self.assertIsNotNone(m) + uri = "http://www.geneontology.org/formats/oboInOwl#foo" + curie = adapter.uri_to_curie(uri) + # behavior is currently intentionally undefined + assert (curie == "oio:foo" or curie == "oboInOwl:foo") + # must be reversible + assert adapter.curie_to_uri(curie) == uri + + def test_relationship_map(self): oi = self.oi rels = oi.outgoing_relationship_map("GO:0005773") diff --git a/tests/test_implementations/test_simple_obo.py b/tests/test_implementations/test_simple_obo.py index a1eced5f7..eae4d697b 100644 --- a/tests/test_implementations/test_simple_obo.py +++ b/tests/test_implementations/test_simple_obo.py @@ -103,6 +103,22 @@ def test_custom_prefixes(self): if iri is not None: self.assertEqual(oi.uri_to_curie(iri), curie, f"in contract iri: {iri}") + def test_conflicting_oio_prefixes(self): + """ + See https://github.com/INCATools/ontology-access-kit/issues/702 + """ + # TODO: DRY. This is currently duplicative of a pronto test + resource = OntologyResource(slug="metadata-map-prefixes-test.obo", directory=INPUT_DIR, local=True) + adapter = SimpleOboImplementation(resource) + m = adapter.entity_metadata_map("HP:0000001") + self.assertIsNotNone(m) + uri = "http://www.geneontology.org/formats/oboInOwl#foo" + curie = adapter.uri_to_curie(uri) + # behavior is currently intentionally undefined + assert (curie == "oio:foo" or curie == "oboInOwl:foo") + # must be reversible + assert adapter.curie_to_uri(curie) == uri + def test_relationships_extra(self): oi = self.oi rels = oi.outgoing_relationship_map("GO:0005773") From 958b5a3ce4f02e04995b4573f4b6d081fa5c3345 Mon Sep 17 00:00:00 2001 From: Chris Mungall Date: Wed, 15 May 2024 12:39:02 -0700 Subject: [PATCH 02/10] format --- tests/test_converters/test_obo_format.py | 23 +++++++++++++++-------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/tests/test_converters/test_obo_format.py b/tests/test_converters/test_obo_format.py index 1b937aac3..ccf000b96 100644 --- a/tests/test_converters/test_obo_format.py +++ b/tests/test_converters/test_obo_format.py @@ -88,7 +88,7 @@ import subprocess from functools import lru_cache from pathlib import Path -from typing import Optional, Union, Tuple +from typing import Optional, Tuple, Union import pytest import rdflib @@ -277,7 +277,7 @@ def test_generate_canonical_files(split_compiled_obo, output_format): else: assert ok is None print(f"DID NOT CONVERT {path} to {output_path}") - assert False + raise AssertionError(f"Could not convert {path} to {output_path}") @pytest.mark.parametrize( @@ -331,7 +331,11 @@ def test_oak_loaders_dumpers(split_compiled_obo, output_format, wrapper): def compare_output( - generated_path: str, canonical_path: str, format: str = None, metadata: dict = None, strict=False, + generated_path: str, + canonical_path: str, + format: str = None, + metadata: dict = None, + strict=False, ) -> Tuple[int, list, bool]: """ Compare the output of OAK loading and dumping vs canonical files. @@ -395,7 +399,9 @@ def compare_output( expected = "UNEXPECTED" fatal = True if strict: - raise ValueError(f"UNEXPECTED DIFF {format}: {canonical_path} vs {generated_path}") + raise ValueError( + f"UNEXPECTED DIFF {format}: {canonical_path} vs {generated_path}" + ) logger.info(f"## {name}:: {expected} DIFF {format}: {canonical_path} vs {generated_path}:") for diff in diffs: logger.info(diff) @@ -481,6 +487,7 @@ def mk_version_path(path: Union[str, Path]) -> str: """ return f"{path}.versioninfo" + def robot_convert(input_path: str, output_path: str) -> Optional[bool]: """ Convert an ontology using robot. @@ -490,16 +497,16 @@ def robot_convert(input_path: str, output_path: str) -> Optional[bool]: :return: """ if not robot_is_on_path(): - logger.warning(f"ROBOT NOT ON PATH") + logger.warning("ROBOT NOT ON PATH") return None cmd = [ "robot", "convert", "-i", input_path, - # "-t", - # "http://www.geneontology.org/formats/oboInOwl#id", - # "convert", + # "-t", + # "http://www.geneontology.org/formats/oboInOwl#id", + # "convert", "-o", output_path, ] From a20ecfe65e3ed7e6f962f1cfd413f324d2a59ed0 Mon Sep 17 00:00:00 2001 From: Chris Mungall Date: Wed, 15 May 2024 14:15:55 -0700 Subject: [PATCH 03/10] add missing --- tests/input/metadata-map-prefixes-test.obo | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) create mode 100644 tests/input/metadata-map-prefixes-test.obo diff --git a/tests/input/metadata-map-prefixes-test.obo b/tests/input/metadata-map-prefixes-test.obo new file mode 100644 index 000000000..9ccaad358 --- /dev/null +++ b/tests/input/metadata-map-prefixes-test.obo @@ -0,0 +1,17 @@ +format-version: 1.2 +ontology: test.obo +idspace: dc http://purl.org/dc/elements/1.1/ +idspace: oboInOwl http://www.geneontology.org/formats/oboInOwl# +idspace: owl http://www.w3.org/2002/07/owl# +idspace: rdf http://www.w3.org/1999/02/22-rdf-syntax-ns# +idspace: rdfs http://www.w3.org/2000/01/rdf-schema# +idspace: terms http://purl.org/dc/terms/ +idspace: xml http://www.w3.org/XML/1998/namespace +idspace: xsd http://www.w3.org/2001/XMLSchema# +idspace: HP http://purl.obolibrary.org/obo/HP_ + +[Term] +id: HP:0000001 +name: All +def: "." [PMID:1] + From d8c394ae4f0e31610fc58fbb60efafaac266196f Mon Sep 17 00:00:00 2001 From: Chris Mungall Date: Wed, 15 May 2024 16:48:53 -0700 Subject: [PATCH 04/10] add missing --- .../gci-is-a/gci-is-a.expected.obo | 7 +++ .../gci-is-a/gci-is-a.expected.ofn | 41 ++++++++++++++++ .../gci-relation/gci-relation.expected.obo | 7 +++ .../gci-relation/gci-relation.expected.ofn | 43 +++++++++++++++++ .../prefixes-conflict-oio.expected.obo | 9 ++++ .../prefixes-conflict-oio.expected.ofn | 47 +++++++++++++++++++ .../prefixes-conflict-skos.expected.obo | 12 +++++ .../prefixes-conflict-skos.expected.ofn | 47 +++++++++++++++++++ 8 files changed, 213 insertions(+) create mode 100644 tests/input/obo-compliance/gci-is-a/gci-is-a.expected.obo create mode 100644 tests/input/obo-compliance/gci-is-a/gci-is-a.expected.ofn create mode 100644 tests/input/obo-compliance/gci-relation/gci-relation.expected.obo create mode 100644 tests/input/obo-compliance/gci-relation/gci-relation.expected.ofn create mode 100644 tests/input/obo-compliance/prefixes-conflict-oio/prefixes-conflict-oio.expected.obo create mode 100644 tests/input/obo-compliance/prefixes-conflict-oio/prefixes-conflict-oio.expected.ofn create mode 100644 tests/input/obo-compliance/prefixes-conflict-skos/prefixes-conflict-skos.expected.obo create mode 100644 tests/input/obo-compliance/prefixes-conflict-skos/prefixes-conflict-skos.expected.ofn diff --git a/tests/input/obo-compliance/gci-is-a/gci-is-a.expected.obo b/tests/input/obo-compliance/gci-is-a/gci-is-a.expected.obo new file mode 100644 index 000000000..5d881b925 --- /dev/null +++ b/tests/input/obo-compliance/gci-is-a/gci-is-a.expected.obo @@ -0,0 +1,7 @@ +format-version: 1.2 +ontology: gci-is-a + +[Term] +id: X:1 +is_a: X:2 {gci_predicate="R:2"} + diff --git a/tests/input/obo-compliance/gci-is-a/gci-is-a.expected.ofn b/tests/input/obo-compliance/gci-is-a/gci-is-a.expected.ofn new file mode 100644 index 000000000..acede5c45 --- /dev/null +++ b/tests/input/obo-compliance/gci-is-a/gci-is-a.expected.ofn @@ -0,0 +1,41 @@ +Prefix(:=) +Prefix(owl:=) +Prefix(rdf:=) +Prefix(xml:=) +Prefix(xsd:=) +Prefix(rdfs:=) + + +Ontology( +Annotation( "1.4") + +Declaration(Class()) +Declaration(Class()) +Declaration(AnnotationProperty()) +Declaration(AnnotationProperty()) +Declaration(AnnotationProperty()) +############################ +# Annotation Properties +############################ + +# Annotation Property: (has_obo_format_version) + +AnnotationAssertion(rdfs:label "has_obo_format_version") + +# Annotation Property: (id) + +AnnotationAssertion(rdfs:label "id") + + + +############################ +# Classes +############################ + +# Class: () + +AnnotationAssertion( "X:1") +SubClassOf(Annotation( "R:2") ) + + +) \ No newline at end of file diff --git a/tests/input/obo-compliance/gci-relation/gci-relation.expected.obo b/tests/input/obo-compliance/gci-relation/gci-relation.expected.obo new file mode 100644 index 000000000..92d234370 --- /dev/null +++ b/tests/input/obo-compliance/gci-relation/gci-relation.expected.obo @@ -0,0 +1,7 @@ +format-version: 1.2 +ontology: gci-relation + +[Term] +id: X:1 +relationship: R:1 X:2 {gci_predicate="R:2"} + diff --git a/tests/input/obo-compliance/gci-relation/gci-relation.expected.ofn b/tests/input/obo-compliance/gci-relation/gci-relation.expected.ofn new file mode 100644 index 000000000..5a7a8d6dc --- /dev/null +++ b/tests/input/obo-compliance/gci-relation/gci-relation.expected.ofn @@ -0,0 +1,43 @@ +Prefix(:=) +Prefix(owl:=) +Prefix(rdf:=) +Prefix(xml:=) +Prefix(xsd:=) +Prefix(rdfs:=) + + +Ontology( +Annotation( "1.4") + +Declaration(Class()) +Declaration(Class()) +Declaration(ObjectProperty()) +Declaration(AnnotationProperty()) +Declaration(AnnotationProperty()) +Declaration(AnnotationProperty()) +############################ +# Annotation Properties +############################ + +# Annotation Property: (has_obo_format_version) + +AnnotationAssertion(rdfs:label "has_obo_format_version") + +# Annotation Property: (id) + +AnnotationAssertion(rdfs:label "id") + + + + +############################ +# Classes +############################ + +# Class: () + +AnnotationAssertion( "X:1") +SubClassOf(Annotation( "R:2") ObjectSomeValuesFrom( )) + + +) \ No newline at end of file diff --git a/tests/input/obo-compliance/prefixes-conflict-oio/prefixes-conflict-oio.expected.obo b/tests/input/obo-compliance/prefixes-conflict-oio/prefixes-conflict-oio.expected.obo new file mode 100644 index 000000000..99e3b962e --- /dev/null +++ b/tests/input/obo-compliance/prefixes-conflict-oio/prefixes-conflict-oio.expected.obo @@ -0,0 +1,9 @@ +format-version: 1.2 +idspace: oboInOwl http://www.geneontology.org/formats/oboInOwl# +ontology: prefixes-conflict-oio + +[Term] +id: X:1 +name: X:1 +def: "." [] + diff --git a/tests/input/obo-compliance/prefixes-conflict-oio/prefixes-conflict-oio.expected.ofn b/tests/input/obo-compliance/prefixes-conflict-oio/prefixes-conflict-oio.expected.ofn new file mode 100644 index 000000000..c9cde933e --- /dev/null +++ b/tests/input/obo-compliance/prefixes-conflict-oio/prefixes-conflict-oio.expected.ofn @@ -0,0 +1,47 @@ +Prefix(:=) +Prefix(owl:=) +Prefix(rdf:=) +Prefix(xml:=) +Prefix(xsd:=) +Prefix(rdfs:=) +Prefix(oboInOwl:=) + + +Ontology( +Annotation(oboInOwl:hasOBOFormatVersion "1.4") + +Declaration(Class()) +Declaration(AnnotationProperty()) +Declaration(AnnotationProperty(oboInOwl:hasOBOFormatVersion)) +Declaration(AnnotationProperty(oboInOwl:id)) +Declaration(AnnotationProperty(rdfs:label)) +############################ +# Annotation Properties +############################ + +# Annotation Property: (definition) + +AnnotationAssertion(rdfs:label "definition") + +# Annotation Property: oboInOwl:hasOBOFormatVersion (has_obo_format_version) + +AnnotationAssertion(rdfs:label oboInOwl:hasOBOFormatVersion "has_obo_format_version") + +# Annotation Property: oboInOwl:id (id) + +AnnotationAssertion(rdfs:label oboInOwl:id "id") + + + +############################ +# Classes +############################ + +# Class: (X:1) + +AnnotationAssertion( ".") +AnnotationAssertion(oboInOwl:id "X:1") +AnnotationAssertion(rdfs:label "X:1") + + +) \ No newline at end of file diff --git a/tests/input/obo-compliance/prefixes-conflict-skos/prefixes-conflict-skos.expected.obo b/tests/input/obo-compliance/prefixes-conflict-skos/prefixes-conflict-skos.expected.obo new file mode 100644 index 000000000..6b4c94b90 --- /dev/null +++ b/tests/input/obo-compliance/prefixes-conflict-skos/prefixes-conflict-skos.expected.obo @@ -0,0 +1,12 @@ +format-version: 1.2 +idspace: skos http://example.org/not-skos/ +ontology: prefixes-conflict-skos + +[Term] +id: X:1 +relationship: skos:exactMatch Y:1 + +[Typedef] +id: skos:exactMatch +is_metadata_tag: true + diff --git a/tests/input/obo-compliance/prefixes-conflict-skos/prefixes-conflict-skos.expected.ofn b/tests/input/obo-compliance/prefixes-conflict-skos/prefixes-conflict-skos.expected.ofn new file mode 100644 index 000000000..94bfacd9f --- /dev/null +++ b/tests/input/obo-compliance/prefixes-conflict-skos/prefixes-conflict-skos.expected.ofn @@ -0,0 +1,47 @@ +Prefix(:=) +Prefix(owl:=) +Prefix(rdf:=) +Prefix(xml:=) +Prefix(xsd:=) +Prefix(rdfs:=) +Prefix(skos:=) + + +Ontology( +Annotation( "1.4") + +Declaration(Class()) +Declaration(AnnotationProperty(skos:exactMatch)) +Declaration(AnnotationProperty()) +Declaration(AnnotationProperty()) +Declaration(AnnotationProperty()) +############################ +# Annotation Properties +############################ + +# Annotation Property: skos:exactMatch (skos:exactMatch) + +AnnotationAssertion( skos:exactMatch "skos:exactMatch") +AnnotationAssertion( skos:exactMatch "true"^^xsd:boolean) + +# Annotation Property: (has_obo_format_version) + +AnnotationAssertion(rdfs:label "has_obo_format_version") + +# Annotation Property: (id) + +AnnotationAssertion(rdfs:label "id") + + + +############################ +# Classes +############################ + +# Class: () + +AnnotationAssertion(skos:exactMatch ) +AnnotationAssertion( "X:1") + + +) \ No newline at end of file From 5a5ec1f0a8897b7749c7b3138b56ba0d12adb20d Mon Sep 17 00:00:00 2001 From: Chris Mungall Date: Fri, 17 May 2024 12:43:40 -0700 Subject: [PATCH 05/10] fix GCI example --- tests/input/obo-compliance.obo | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/input/obo-compliance.obo b/tests/input/obo-compliance.obo index 20df87b16..44e7ee8b3 100644 --- a/tests/input/obo-compliance.obo +++ b/tests/input/obo-compliance.obo @@ -710,14 +710,14 @@ disjoint_from: X:2 {source="PMID:123465"} [Term] id: X:1 -relationship: R:1 X:2 {gci_predicate="R:2", gci_filler="X:3"} +relationship: R:1 X:2 {gci_relation="R:2", gci_filler="X:3"} !! name: gci-is-a !! description: General Class Inclusion is_a [Term] id: X:1 -is_a: X:2 {gci_predicate="R:2", gci_filler="X:3"} +is_a: X:2 {gci_relation="R:2", gci_filler="X:3"} !! name: created_by-annotated !! description: Metadata for creator with annotation From 2b15538016843771e6f85cc779ed52e540a338b7 Mon Sep 17 00:00:00 2001 From: Chris Mungall Date: Wed, 5 Jun 2024 07:58:59 -0700 Subject: [PATCH 06/10] fixed docs --- tests/test_converters/test_obo_graph_to_cx.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_converters/test_obo_graph_to_cx.py b/tests/test_converters/test_obo_graph_to_cx.py index 37a5be3df..089e5f4ff 100644 --- a/tests/test_converters/test_obo_graph_to_cx.py +++ b/tests/test_converters/test_obo_graph_to_cx.py @@ -16,7 +16,7 @@ class OboGraphToCXTest(unittest.TestCase): - """Tests OBO JSON -> RDF/OWL.""" + """Tests OBO JSON -> NDEx CX format.""" def setUp(self): self.converter = OboGraphToCXConverter() From 246ca91ee4556ba2e9be57641f373dae54fbac43 Mon Sep 17 00:00:00 2001 From: Chris Mungall Date: Wed, 5 Jun 2024 09:59:57 -0700 Subject: [PATCH 07/10] regenrate compliance test outputs --- .../expansion-conflict-main-idspace.meta.yaml | 3 ++- tests/input/obo-compliance/gci-is-a/gci-is-a.obo | 2 +- tests/input/obo-compliance/gci-relation/gci-relation.obo | 2 +- .../prefixes-conflict-main-idspace.meta.yaml | 3 ++- .../prefixes-conflict-oio/prefixes-conflict-oio.meta.yaml | 3 ++- .../prefixes-conflict-skos/prefixes-conflict-skos.meta.yaml | 3 ++- 6 files changed, 10 insertions(+), 6 deletions(-) diff --git a/tests/input/obo-compliance/expansion-conflict-main-idspace/expansion-conflict-main-idspace.meta.yaml b/tests/input/obo-compliance/expansion-conflict-main-idspace/expansion-conflict-main-idspace.meta.yaml index 8e57bb043..146b62fb4 100644 --- a/tests/input/obo-compliance/expansion-conflict-main-idspace/expansion-conflict-main-idspace.meta.yaml +++ b/tests/input/obo-compliance/expansion-conflict-main-idspace/expansion-conflict-main-idspace.meta.yaml @@ -1,4 +1,5 @@ name: expansion-conflict-main-idspace name: expansion-conflict-main-idspace description: tests conflicting expansions for the main ID space -invalid: true \ No newline at end of file +invalid: true +seeAlso: https://github.com/INCATools/ontology-access-kit/issues/760 \ No newline at end of file diff --git a/tests/input/obo-compliance/gci-is-a/gci-is-a.obo b/tests/input/obo-compliance/gci-is-a/gci-is-a.obo index 37ac76264..953a73231 100644 --- a/tests/input/obo-compliance/gci-is-a/gci-is-a.obo +++ b/tests/input/obo-compliance/gci-is-a/gci-is-a.obo @@ -3,5 +3,5 @@ ontology: gci-is-a [Term] id: X:1 -is_a: X:2 {gci_predicate="R:2", gci_filler="X:3"} +is_a: X:2 {gci_relation="R:2", gci_filler="X:3"} diff --git a/tests/input/obo-compliance/gci-relation/gci-relation.obo b/tests/input/obo-compliance/gci-relation/gci-relation.obo index 89d296e94..84503b0ed 100644 --- a/tests/input/obo-compliance/gci-relation/gci-relation.obo +++ b/tests/input/obo-compliance/gci-relation/gci-relation.obo @@ -3,5 +3,5 @@ ontology: gci-relation [Term] id: X:1 -relationship: R:1 X:2 {gci_predicate="R:2", gci_filler="X:3"} +relationship: R:1 X:2 {gci_relation="R:2", gci_filler="X:3"} diff --git a/tests/input/obo-compliance/prefixes-conflict-main-idspace/prefixes-conflict-main-idspace.meta.yaml b/tests/input/obo-compliance/prefixes-conflict-main-idspace/prefixes-conflict-main-idspace.meta.yaml index bb65f539e..b0a8e87ad 100644 --- a/tests/input/obo-compliance/prefixes-conflict-main-idspace/prefixes-conflict-main-idspace.meta.yaml +++ b/tests/input/obo-compliance/prefixes-conflict-main-idspace/prefixes-conflict-main-idspace.meta.yaml @@ -1,4 +1,5 @@ name: prefixes-conflict-main-idspace name: prefixes-conflict-main-idspace description: tests conflicting prefixes for the main ID space -invalid: true \ No newline at end of file +invalid: true +seeAlso: https://github.com/INCATools/ontology-access-kit/issues/760 \ No newline at end of file diff --git a/tests/input/obo-compliance/prefixes-conflict-oio/prefixes-conflict-oio.meta.yaml b/tests/input/obo-compliance/prefixes-conflict-oio/prefixes-conflict-oio.meta.yaml index 07c2775ad..af55397b2 100644 --- a/tests/input/obo-compliance/prefixes-conflict-oio/prefixes-conflict-oio.meta.yaml +++ b/tests/input/obo-compliance/prefixes-conflict-oio/prefixes-conflict-oio.meta.yaml @@ -1,4 +1,5 @@ name: prefixes-conflict-oio name: prefixes-conflict-oio description: tests conflicting prefixes/contractions for oboInOwl namespace, where oio might be built-in -unstable: true \ No newline at end of file +unstable: true +seeAlso: https://github.com/INCATools/ontology-access-kit/issues/760 \ No newline at end of file diff --git a/tests/input/obo-compliance/prefixes-conflict-skos/prefixes-conflict-skos.meta.yaml b/tests/input/obo-compliance/prefixes-conflict-skos/prefixes-conflict-skos.meta.yaml index f7fc31b2a..dd532151b 100644 --- a/tests/input/obo-compliance/prefixes-conflict-skos/prefixes-conflict-skos.meta.yaml +++ b/tests/input/obo-compliance/prefixes-conflict-skos/prefixes-conflict-skos.meta.yaml @@ -1,4 +1,5 @@ name: prefixes-conflict-skos name: prefixes-conflict-skos description: tests conflicting prefixes for the SKOS namespace -unstable: true \ No newline at end of file +unstable: true +seeAlso: https://github.com/INCATools/ontology-access-kit/issues/760 \ No newline at end of file From 861dc0ce56db6bceee24cec374bd7e627cf3d859 Mon Sep 17 00:00:00 2001 From: Chris Mungall Date: Wed, 5 Jun 2024 12:44:23 -0700 Subject: [PATCH 08/10] Ensure prefixmap is not mutated --- src/oaklib/interfaces/basic_ontology_interface.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/oaklib/interfaces/basic_ontology_interface.py b/src/oaklib/interfaces/basic_ontology_interface.py index a5d8d1afa..11f486186 100644 --- a/src/oaklib/interfaces/basic_ontology_interface.py +++ b/src/oaklib/interfaces/basic_ontology_interface.py @@ -2,6 +2,7 @@ import logging from abc import ABC from collections import defaultdict +from copy import copy from dataclasses import dataclass, field from functools import lru_cache from pathlib import Path @@ -164,6 +165,8 @@ class BasicOntologyInterface(OntologyInterface, ABC): _edge_index: Optional[EdgeIndex] = None _entailed_edge_index: Optional[EdgeIndex] = None + _prefix_map: Optional[PREFIX_MAP] = None + def prefix_map(self) -> PREFIX_MAP: """ Return a dictionary mapping all prefixes known to the resource to their URI expansion. @@ -183,7 +186,9 @@ def prefix_map(self) -> PREFIX_MAP: :return: prefix map """ - return get_default_prefix_map() + if not self._prefix_map: + self._prefix_map = copy(get_default_prefix_map()) + return self._prefix_map @deprecated("Replaced by prefix_map") def get_prefix_map(self) -> PREFIX_MAP: From 4d1f4c3c1b92aaeb9e74a392ec69826c5ed06679 Mon Sep 17 00:00:00 2001 From: Chris Mungall Date: Wed, 5 Jun 2024 12:44:38 -0700 Subject: [PATCH 09/10] relax test --- tests/test_cli.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/tests/test_cli.py b/tests/test_cli.py index 58c319c8d..67a1efaeb 100644 --- a/tests/test_cli.py +++ b/tests/test_cli.py @@ -1140,7 +1140,13 @@ def test_lexmatch(self): self.assertIn(intracellular_match, contents) msdf = parse_sssom_table(outfile) msd = to_mapping_set_document(msdf) - self.assertEqual("http://purl.obolibrary.org/obo/XX_", msd.prefix_map["XX"]) + self.assertIn( + msd.prefix_map["XX"], + [ + "http://purl.obolibrary.org/obo/XX_", + "http://w3id.org/sssom/unknown_prefix/xx/", + ], + ) cases = [ (nucleus_match, NUCLEUS, SKOS_EXACT_MATCH), (intracellular_match, INTRACELLULAR, SKOS_CLOSE_MATCH), From 53c965c52f32267a642787cc58ce03d9d7438bc5 Mon Sep 17 00:00:00 2001 From: Chris Mungall Date: Wed, 5 Jun 2024 12:44:54 -0700 Subject: [PATCH 10/10] fmt --- tests/test_implementations/test_pronto.py | 7 ++++--- tests/test_implementations/test_simple_obo.py | 6 ++++-- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/tests/test_implementations/test_pronto.py b/tests/test_implementations/test_pronto.py index d9625b807..694762cd2 100644 --- a/tests/test_implementations/test_pronto.py +++ b/tests/test_implementations/test_pronto.py @@ -90,18 +90,19 @@ def test_conflicting_oio_prefixes(self): """ See https://github.com/INCATools/ontology-access-kit/issues/702 """ - resource = OntologyResource(slug="metadata-map-prefixes-test.obo", directory=INPUT_DIR, local=True) + resource = OntologyResource( + slug="metadata-map-prefixes-test.obo", directory=INPUT_DIR, local=True + ) adapter = ProntoImplementation(resource) m = adapter.entity_metadata_map("HP:0000001") self.assertIsNotNone(m) uri = "http://www.geneontology.org/formats/oboInOwl#foo" curie = adapter.uri_to_curie(uri) # behavior is currently intentionally undefined - assert (curie == "oio:foo" or curie == "oboInOwl:foo") + assert curie == "oio:foo" or curie == "oboInOwl:foo" # must be reversible assert adapter.curie_to_uri(curie) == uri - def test_relationship_map(self): oi = self.oi rels = oi.outgoing_relationship_map("GO:0005773") diff --git a/tests/test_implementations/test_simple_obo.py b/tests/test_implementations/test_simple_obo.py index eae4d697b..5b6bb584a 100644 --- a/tests/test_implementations/test_simple_obo.py +++ b/tests/test_implementations/test_simple_obo.py @@ -108,14 +108,16 @@ def test_conflicting_oio_prefixes(self): See https://github.com/INCATools/ontology-access-kit/issues/702 """ # TODO: DRY. This is currently duplicative of a pronto test - resource = OntologyResource(slug="metadata-map-prefixes-test.obo", directory=INPUT_DIR, local=True) + resource = OntologyResource( + slug="metadata-map-prefixes-test.obo", directory=INPUT_DIR, local=True + ) adapter = SimpleOboImplementation(resource) m = adapter.entity_metadata_map("HP:0000001") self.assertIsNotNone(m) uri = "http://www.geneontology.org/formats/oboInOwl#foo" curie = adapter.uri_to_curie(uri) # behavior is currently intentionally undefined - assert (curie == "oio:foo" or curie == "oboInOwl:foo") + assert curie == "oio:foo" or curie == "oboInOwl:foo" # must be reversible assert adapter.curie_to_uri(curie) == uri