pyobo 0.11.2__py3-none-any.whl → 0.12.1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- pyobo/.DS_Store +0 -0
- pyobo/__init__.py +95 -20
- pyobo/__main__.py +0 -0
- pyobo/api/__init__.py +81 -10
- pyobo/api/alts.py +52 -42
- pyobo/api/combine.py +39 -0
- pyobo/api/edges.py +68 -0
- pyobo/api/hierarchy.py +231 -203
- pyobo/api/metadata.py +14 -19
- pyobo/api/names.py +207 -127
- pyobo/api/properties.py +117 -117
- pyobo/api/relations.py +68 -94
- pyobo/api/species.py +24 -21
- pyobo/api/typedefs.py +11 -11
- pyobo/api/utils.py +66 -13
- pyobo/api/xrefs.py +107 -114
- pyobo/cli/__init__.py +0 -0
- pyobo/cli/cli.py +35 -50
- pyobo/cli/database.py +210 -160
- pyobo/cli/database_utils.py +155 -0
- pyobo/cli/lookup.py +163 -195
- pyobo/cli/utils.py +19 -6
- pyobo/constants.py +102 -3
- pyobo/getters.py +209 -191
- pyobo/gilda_utils.py +52 -250
- pyobo/identifier_utils/__init__.py +33 -0
- pyobo/identifier_utils/api.py +305 -0
- pyobo/identifier_utils/preprocessing.json +873 -0
- pyobo/identifier_utils/preprocessing.py +27 -0
- pyobo/identifier_utils/relations/__init__.py +8 -0
- pyobo/identifier_utils/relations/api.py +162 -0
- pyobo/identifier_utils/relations/data.json +5824 -0
- pyobo/identifier_utils/relations/data_owl.json +57 -0
- pyobo/identifier_utils/relations/data_rdf.json +1 -0
- pyobo/identifier_utils/relations/data_rdfs.json +7 -0
- pyobo/mocks.py +9 -6
- pyobo/ner/__init__.py +9 -0
- pyobo/ner/api.py +72 -0
- pyobo/ner/normalizer.py +33 -0
- pyobo/obographs.py +48 -40
- pyobo/plugins.py +5 -4
- pyobo/py.typed +0 -0
- pyobo/reader.py +1354 -395
- pyobo/reader_utils.py +155 -0
- pyobo/resource_utils.py +42 -22
- pyobo/resources/__init__.py +0 -0
- pyobo/resources/goc.py +75 -0
- pyobo/resources/goc.tsv +188 -0
- pyobo/resources/ncbitaxon.py +4 -5
- pyobo/resources/ncbitaxon.tsv.gz +0 -0
- pyobo/resources/ro.py +3 -2
- pyobo/resources/ro.tsv +0 -0
- pyobo/resources/so.py +0 -0
- pyobo/resources/so.tsv +0 -0
- pyobo/sources/README.md +12 -8
- pyobo/sources/__init__.py +52 -29
- pyobo/sources/agrovoc.py +0 -0
- pyobo/sources/antibodyregistry.py +11 -12
- pyobo/sources/bigg/__init__.py +13 -0
- pyobo/sources/bigg/bigg_compartment.py +81 -0
- pyobo/sources/bigg/bigg_metabolite.py +229 -0
- pyobo/sources/bigg/bigg_model.py +46 -0
- pyobo/sources/bigg/bigg_reaction.py +77 -0
- pyobo/sources/biogrid.py +1 -2
- pyobo/sources/ccle.py +7 -12
- pyobo/sources/cgnc.py +9 -6
- pyobo/sources/chebi.py +1 -1
- pyobo/sources/chembl/__init__.py +9 -0
- pyobo/sources/{chembl.py → chembl/chembl_compound.py} +13 -25
- pyobo/sources/chembl/chembl_target.py +160 -0
- pyobo/sources/civic_gene.py +55 -15
- pyobo/sources/clinicaltrials.py +160 -0
- pyobo/sources/complexportal.py +24 -24
- pyobo/sources/conso.py +14 -22
- pyobo/sources/cpt.py +0 -0
- pyobo/sources/credit.py +1 -9
- pyobo/sources/cvx.py +27 -5
- pyobo/sources/depmap.py +9 -12
- pyobo/sources/dictybase_gene.py +2 -7
- pyobo/sources/drugbank/__init__.py +9 -0
- pyobo/sources/{drugbank.py → drugbank/drugbank.py} +11 -16
- pyobo/sources/{drugbank_salt.py → drugbank/drugbank_salt.py} +3 -8
- pyobo/sources/drugcentral.py +17 -13
- pyobo/sources/expasy.py +31 -34
- pyobo/sources/famplex.py +13 -18
- pyobo/sources/flybase.py +8 -13
- pyobo/sources/gard.py +62 -0
- pyobo/sources/geonames/__init__.py +9 -0
- pyobo/sources/geonames/features.py +28 -0
- pyobo/sources/{geonames.py → geonames/geonames.py} +87 -26
- pyobo/sources/geonames/utils.py +115 -0
- pyobo/sources/gmt_utils.py +6 -7
- pyobo/sources/go.py +20 -13
- pyobo/sources/gtdb.py +154 -0
- pyobo/sources/gwascentral/__init__.py +9 -0
- pyobo/sources/{gwascentral_phenotype.py → gwascentral/gwascentral_phenotype.py} +5 -7
- pyobo/sources/{gwascentral_study.py → gwascentral/gwascentral_study.py} +1 -7
- pyobo/sources/hgnc/__init__.py +9 -0
- pyobo/sources/{hgnc.py → hgnc/hgnc.py} +56 -70
- pyobo/sources/{hgncgenefamily.py → hgnc/hgncgenefamily.py} +8 -18
- pyobo/sources/icd/__init__.py +9 -0
- pyobo/sources/{icd10.py → icd/icd10.py} +35 -37
- pyobo/sources/icd/icd11.py +148 -0
- pyobo/sources/{icd_utils.py → icd/icd_utils.py} +66 -20
- pyobo/sources/interpro.py +4 -9
- pyobo/sources/itis.py +0 -5
- pyobo/sources/kegg/__init__.py +0 -0
- pyobo/sources/kegg/api.py +16 -38
- pyobo/sources/kegg/genes.py +9 -20
- pyobo/sources/kegg/genome.py +1 -7
- pyobo/sources/kegg/pathway.py +9 -21
- pyobo/sources/mesh.py +58 -24
- pyobo/sources/mgi.py +3 -10
- pyobo/sources/mirbase/__init__.py +11 -0
- pyobo/sources/{mirbase.py → mirbase/mirbase.py} +8 -11
- pyobo/sources/{mirbase_constants.py → mirbase/mirbase_constants.py} +0 -0
- pyobo/sources/{mirbase_family.py → mirbase/mirbase_family.py} +4 -8
- pyobo/sources/{mirbase_mature.py → mirbase/mirbase_mature.py} +3 -7
- pyobo/sources/msigdb.py +74 -39
- pyobo/sources/ncbi/__init__.py +9 -0
- pyobo/sources/ncbi/ncbi_gc.py +162 -0
- pyobo/sources/{ncbigene.py → ncbi/ncbigene.py} +18 -19
- pyobo/sources/nih_reporter.py +60 -0
- pyobo/sources/nlm/__init__.py +9 -0
- pyobo/sources/nlm/nlm_catalog.py +48 -0
- pyobo/sources/nlm/nlm_publisher.py +36 -0
- pyobo/sources/nlm/utils.py +116 -0
- pyobo/sources/npass.py +6 -8
- pyobo/sources/omim_ps.py +11 -4
- pyobo/sources/pathbank.py +4 -8
- pyobo/sources/pfam/__init__.py +9 -0
- pyobo/sources/{pfam.py → pfam/pfam.py} +3 -8
- pyobo/sources/{pfam_clan.py → pfam/pfam_clan.py} +2 -7
- pyobo/sources/pharmgkb/__init__.py +15 -0
- pyobo/sources/pharmgkb/pharmgkb_chemical.py +89 -0
- pyobo/sources/pharmgkb/pharmgkb_disease.py +77 -0
- pyobo/sources/pharmgkb/pharmgkb_gene.py +108 -0
- pyobo/sources/pharmgkb/pharmgkb_pathway.py +63 -0
- pyobo/sources/pharmgkb/pharmgkb_variant.py +84 -0
- pyobo/sources/pharmgkb/utils.py +86 -0
- pyobo/sources/pid.py +1 -6
- pyobo/sources/pombase.py +6 -10
- pyobo/sources/pubchem.py +4 -9
- pyobo/sources/reactome.py +5 -11
- pyobo/sources/rgd.py +11 -16
- pyobo/sources/rhea.py +37 -36
- pyobo/sources/ror.py +69 -42
- pyobo/sources/selventa/__init__.py +0 -0
- pyobo/sources/selventa/schem.py +4 -7
- pyobo/sources/selventa/scomp.py +1 -6
- pyobo/sources/selventa/sdis.py +4 -7
- pyobo/sources/selventa/sfam.py +1 -6
- pyobo/sources/sgd.py +6 -11
- pyobo/sources/signor/__init__.py +7 -0
- pyobo/sources/signor/download.py +41 -0
- pyobo/sources/signor/signor_complexes.py +105 -0
- pyobo/sources/slm.py +12 -15
- pyobo/sources/umls/__init__.py +7 -1
- pyobo/sources/umls/__main__.py +0 -0
- pyobo/sources/umls/get_synonym_types.py +20 -4
- pyobo/sources/umls/sty.py +57 -0
- pyobo/sources/umls/synonym_types.tsv +1 -1
- pyobo/sources/umls/umls.py +18 -22
- pyobo/sources/unimod.py +46 -0
- pyobo/sources/uniprot/__init__.py +1 -1
- pyobo/sources/uniprot/uniprot.py +40 -32
- pyobo/sources/uniprot/uniprot_ptm.py +4 -34
- pyobo/sources/utils.py +3 -2
- pyobo/sources/wikipathways.py +7 -10
- pyobo/sources/zfin.py +5 -10
- pyobo/ssg/__init__.py +12 -16
- pyobo/ssg/base.html +0 -0
- pyobo/ssg/index.html +26 -13
- pyobo/ssg/term.html +12 -2
- pyobo/ssg/typedef.html +0 -0
- pyobo/struct/__init__.py +54 -8
- pyobo/struct/functional/__init__.py +1 -0
- pyobo/struct/functional/dsl.py +2572 -0
- pyobo/struct/functional/macros.py +423 -0
- pyobo/struct/functional/obo_to_functional.py +385 -0
- pyobo/struct/functional/ontology.py +272 -0
- pyobo/struct/functional/utils.py +112 -0
- pyobo/struct/reference.py +331 -136
- pyobo/struct/struct.py +1484 -657
- pyobo/struct/struct_utils.py +1078 -0
- pyobo/struct/typedef.py +162 -210
- pyobo/struct/utils.py +12 -5
- pyobo/struct/vocabulary.py +138 -0
- pyobo/utils/__init__.py +0 -0
- pyobo/utils/cache.py +16 -15
- pyobo/utils/io.py +51 -41
- pyobo/utils/iter.py +5 -5
- pyobo/utils/misc.py +41 -53
- pyobo/utils/ndex_utils.py +0 -0
- pyobo/utils/path.py +73 -70
- pyobo/version.py +3 -3
- pyobo-0.12.1.dist-info/METADATA +671 -0
- pyobo-0.12.1.dist-info/RECORD +201 -0
- pyobo-0.12.1.dist-info/WHEEL +4 -0
- {pyobo-0.11.2.dist-info → pyobo-0.12.1.dist-info}/entry_points.txt +1 -0
- pyobo-0.12.1.dist-info/licenses/LICENSE +21 -0
- pyobo/aws.py +0 -162
- pyobo/cli/aws.py +0 -47
- pyobo/identifier_utils.py +0 -142
- pyobo/normalizer.py +0 -232
- pyobo/registries/__init__.py +0 -16
- pyobo/registries/metaregistry.json +0 -507
- pyobo/registries/metaregistry.py +0 -135
- pyobo/sources/icd11.py +0 -105
- pyobo/xrefdb/__init__.py +0 -1
- pyobo/xrefdb/canonicalizer.py +0 -214
- pyobo/xrefdb/priority.py +0 -59
- pyobo/xrefdb/sources/__init__.py +0 -60
- pyobo/xrefdb/sources/biomappings.py +0 -36
- pyobo/xrefdb/sources/cbms2019.py +0 -91
- pyobo/xrefdb/sources/chembl.py +0 -83
- pyobo/xrefdb/sources/compath.py +0 -82
- pyobo/xrefdb/sources/famplex.py +0 -64
- pyobo/xrefdb/sources/gilda.py +0 -50
- pyobo/xrefdb/sources/intact.py +0 -113
- pyobo/xrefdb/sources/ncit.py +0 -133
- pyobo/xrefdb/sources/pubchem.py +0 -27
- pyobo/xrefdb/sources/wikidata.py +0 -116
- pyobo/xrefdb/xrefs_pipeline.py +0 -180
- pyobo-0.11.2.dist-info/METADATA +0 -711
- pyobo-0.11.2.dist-info/RECORD +0 -157
- pyobo-0.11.2.dist-info/WHEEL +0 -5
- pyobo-0.11.2.dist-info/top_level.txt +0 -1
|
@@ -0,0 +1,385 @@
|
|
|
1
|
+
"""Converters from OBO to functional OWL."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from collections.abc import Iterable
|
|
6
|
+
from typing import TYPE_CHECKING, cast
|
|
7
|
+
|
|
8
|
+
import rdflib
|
|
9
|
+
from curies import vocabulary as v
|
|
10
|
+
from rdflib import XSD
|
|
11
|
+
|
|
12
|
+
from pyobo.struct import Stanza
|
|
13
|
+
from pyobo.struct import vocabulary as pv
|
|
14
|
+
from pyobo.struct.functional import dsl as f
|
|
15
|
+
from pyobo.struct.functional import macros as m
|
|
16
|
+
from pyobo.struct.functional.ontology import Document, Ontology
|
|
17
|
+
from pyobo.struct.reference import OBOLiteral, Reference, _parse_datetime
|
|
18
|
+
|
|
19
|
+
if TYPE_CHECKING:
|
|
20
|
+
from pyobo.struct.struct import Obo, Referenced, Term
|
|
21
|
+
from pyobo.struct.struct_utils import Annotation as OBOAnnotation
|
|
22
|
+
from pyobo.struct.typedef import TypeDef
|
|
23
|
+
|
|
24
|
+
__all__ = [
|
|
25
|
+
"get_ofn_from_obo",
|
|
26
|
+
"get_ontology_annotations",
|
|
27
|
+
"get_ontology_axioms",
|
|
28
|
+
"get_term_axioms",
|
|
29
|
+
"get_typedef_axioms",
|
|
30
|
+
]
|
|
31
|
+
|
|
32
|
+
_BASE = "https://w3id.org/biopragmatics/resources"
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
def get_ofn_from_obo(
|
|
36
|
+
obo_ontology: Obo, *, iri: str | None = None, version_iri: str | None = None
|
|
37
|
+
) -> Document:
|
|
38
|
+
"""Convert an ontology."""
|
|
39
|
+
prefix = obo_ontology.ontology
|
|
40
|
+
base = f"{_BASE}/{prefix}"
|
|
41
|
+
if iri is None:
|
|
42
|
+
iri = f"{base}/{prefix}.ofn"
|
|
43
|
+
if version_iri is None and obo_ontology.data_version:
|
|
44
|
+
version_iri = f"{base}/{obo_ontology.data_version}/{prefix}.ofn"
|
|
45
|
+
ofn_ontology = Ontology(
|
|
46
|
+
iri=iri,
|
|
47
|
+
version_iri=version_iri,
|
|
48
|
+
annotations=list(get_ontology_annotations(obo_ontology)),
|
|
49
|
+
axioms=list(get_ontology_axioms(obo_ontology)),
|
|
50
|
+
)
|
|
51
|
+
document = Document(
|
|
52
|
+
ofn_ontology,
|
|
53
|
+
obo_ontology._get_clean_idspaces(),
|
|
54
|
+
)
|
|
55
|
+
return document
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
def get_ontology_axioms(obo_ontology: Obo) -> Iterable[f.Box]:
|
|
59
|
+
"""Get axioms from the ontology."""
|
|
60
|
+
if obo_ontology.root_terms:
|
|
61
|
+
yield f.Declaration(pv.has_ontology_root_term, type="AnnotationProperty")
|
|
62
|
+
yield m.LabelMacro(pv.has_ontology_root_term, cast(str, pv.has_ontology_root_term.name))
|
|
63
|
+
|
|
64
|
+
if obo_ontology.subsetdefs:
|
|
65
|
+
yield f.Declaration("oboInOwl:SubsetProperty", type="AnnotationProperty")
|
|
66
|
+
for subset_typedef, subset_label in obo_ontology.subsetdefs:
|
|
67
|
+
yield f.Declaration(subset_typedef, type="AnnotationProperty")
|
|
68
|
+
yield m.LabelMacro(subset_typedef, subset_label)
|
|
69
|
+
yield f.SubAnnotationPropertyOf(subset_typedef, "oboInOwl:SubsetProperty")
|
|
70
|
+
|
|
71
|
+
if obo_ontology.synonym_typedefs:
|
|
72
|
+
used_has_scope = False
|
|
73
|
+
for synonym_typedef in obo_ontology.synonym_typedefs:
|
|
74
|
+
yield f.Declaration(synonym_typedef, type="AnnotationProperty")
|
|
75
|
+
yield m.LabelMacro(synonym_typedef, synonym_typedef.name)
|
|
76
|
+
yield f.SubAnnotationPropertyOf(synonym_typedef, "oboInOwl:SynonymTypeProperty")
|
|
77
|
+
if synonym_typedef.specificity:
|
|
78
|
+
used_has_scope = True
|
|
79
|
+
yield f.AnnotationAssertion(
|
|
80
|
+
"oboInOwl:hasScope",
|
|
81
|
+
synonym_typedef,
|
|
82
|
+
v.synonym_scopes[synonym_typedef.specificity],
|
|
83
|
+
)
|
|
84
|
+
if used_has_scope:
|
|
85
|
+
yield f.Declaration("oboInOwl:hasScope", type="AnnotationProperty")
|
|
86
|
+
|
|
87
|
+
for typedef in obo_ontology.typedefs or []:
|
|
88
|
+
yield from get_typedef_axioms(typedef)
|
|
89
|
+
|
|
90
|
+
for term in obo_ontology:
|
|
91
|
+
yield from get_term_axioms(term)
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
def get_ontology_annotations(obo_ontology: Obo) -> Iterable[f.Annotation]:
|
|
95
|
+
"""Get annotations from the ontology."""
|
|
96
|
+
for predicate, value in obo_ontology._iterate_property_pairs():
|
|
97
|
+
yield f.Annotation(predicate, value)
|
|
98
|
+
if obo_ontology.data_version:
|
|
99
|
+
yield f.Annotation(pv.version_info, OBOLiteral.string(obo_ontology.data_version))
|
|
100
|
+
if obo_ontology.auto_generated_by is not None:
|
|
101
|
+
yield f.Annotation(
|
|
102
|
+
pv.obo_autogenerated_by, OBOLiteral.string(obo_ontology.auto_generated_by)
|
|
103
|
+
)
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
def _oboliteral_to_literal(obo_literal: OBOLiteral) -> rdflib.Literal:
|
|
107
|
+
if obo_literal.datatype.pair == ("xsd", "string") and obo_literal.language:
|
|
108
|
+
return rdflib.Literal(obo_literal.value, lang=obo_literal.language)
|
|
109
|
+
if obo_literal.datatype.prefix != "xsd":
|
|
110
|
+
raise NotImplementedError(
|
|
111
|
+
f"Automatic literal conversion is not implemented for prefix: {obo_literal.datatype.prefix}"
|
|
112
|
+
)
|
|
113
|
+
if obo_literal.datatype.identifier == "dateTime":
|
|
114
|
+
return rdflib.Literal(_parse_datetime(obo_literal.value), datatype=XSD.dateTime)
|
|
115
|
+
return rdflib.Literal(obo_literal.value, datatype=XSD._NS.term(obo_literal.datatype.identifier))
|
|
116
|
+
|
|
117
|
+
|
|
118
|
+
def get_term_axioms(term: Term) -> Iterable[f.Box]:
|
|
119
|
+
"""Iterate over functional OWL axioms for a term."""
|
|
120
|
+
s = f.IdentifierBox(term)
|
|
121
|
+
# 1 and 13
|
|
122
|
+
if term.type == "Term":
|
|
123
|
+
yield f.Declaration(s, type="Class")
|
|
124
|
+
for parent in term.parents:
|
|
125
|
+
yield f.SubClassOf(s, parent)
|
|
126
|
+
else:
|
|
127
|
+
yield f.Declaration(s, type="NamedIndividual")
|
|
128
|
+
for parent in term.parents:
|
|
129
|
+
yield f.ClassAssertion(parent, s)
|
|
130
|
+
# 2
|
|
131
|
+
if term.is_anonymous is not None:
|
|
132
|
+
yield m.IsAnonymousMacro(s, term.is_anonymous)
|
|
133
|
+
# 3
|
|
134
|
+
if term.name:
|
|
135
|
+
yield m.LabelMacro(s, term.name)
|
|
136
|
+
# 4
|
|
137
|
+
if term.namespace:
|
|
138
|
+
yield m.OBONamespaceMacro(s, term.namespace)
|
|
139
|
+
# 5
|
|
140
|
+
for alt in term.alt_ids:
|
|
141
|
+
yield m.ReplacedByMacro(alt, s)
|
|
142
|
+
# 6
|
|
143
|
+
yield from _yield_definition(term, s)
|
|
144
|
+
# 7 comment is covered by properties
|
|
145
|
+
# 8
|
|
146
|
+
for subset in term.subsets:
|
|
147
|
+
yield m.OBOIsSubsetMacro(s, subset)
|
|
148
|
+
# 9
|
|
149
|
+
yield from _yield_synonyms(term, s)
|
|
150
|
+
# 10
|
|
151
|
+
yield from _yield_xrefs(term, s)
|
|
152
|
+
# 11
|
|
153
|
+
if term.builtin is not None:
|
|
154
|
+
yield m.IsOBOBuiltinMacro(s, term.builtin)
|
|
155
|
+
# 12
|
|
156
|
+
yield from _yield_properties(term, s)
|
|
157
|
+
# 13 parents - see top
|
|
158
|
+
# 14
|
|
159
|
+
if term.intersection_of:
|
|
160
|
+
yield m.ClassIntersectionMacro(s, term.intersection_of)
|
|
161
|
+
# 15
|
|
162
|
+
if term.union_of:
|
|
163
|
+
yield m.ClassUnionMacro(s, term.union_of)
|
|
164
|
+
# 16
|
|
165
|
+
if term.equivalent_to:
|
|
166
|
+
yield f.EquivalentClasses([s, *term.equivalent_to])
|
|
167
|
+
# 17
|
|
168
|
+
if term.disjoint_from:
|
|
169
|
+
yield f.DisjointClasses([s, *term.disjoint_from])
|
|
170
|
+
# 18
|
|
171
|
+
for typedef, value in term.iterate_relations():
|
|
172
|
+
rel_annotations = _get_annotations(term, typedef, value)
|
|
173
|
+
if term.type == "Term":
|
|
174
|
+
yield m.RelationshipMacro(s=s, p=typedef, o=value, annotations=rel_annotations)
|
|
175
|
+
else:
|
|
176
|
+
yield f.ObjectPropertyAssertion(typedef, s, value, annotations=rel_annotations)
|
|
177
|
+
|
|
178
|
+
# 19 TODO created_by
|
|
179
|
+
# 20 TODO creation_date
|
|
180
|
+
# 21
|
|
181
|
+
if term.is_obsolete is not None:
|
|
182
|
+
yield m.IsObsoleteMacro(s, term.is_obsolete)
|
|
183
|
+
# 22 replaced_by is covered by properties
|
|
184
|
+
# 23 consider is covered by properties
|
|
185
|
+
|
|
186
|
+
|
|
187
|
+
def _get_annotations(
|
|
188
|
+
term: Stanza, p: Reference | Referenced, o: Reference | Referenced | OBOLiteral | str
|
|
189
|
+
) -> list[f.Annotation]:
|
|
190
|
+
return _process_anns(term._get_annotations(p, o))
|
|
191
|
+
|
|
192
|
+
|
|
193
|
+
def _process_anns(annotations: list[OBOAnnotation]) -> list[f.Annotation]:
|
|
194
|
+
"""Convert OBO anotations to OFN annotations."""
|
|
195
|
+
return [_convert_annotation(a) for a in annotations]
|
|
196
|
+
|
|
197
|
+
|
|
198
|
+
def _convert_annotation(annotation: OBOAnnotation) -> f.Annotation:
|
|
199
|
+
"""Convert OBO anotations to OFN annotations."""
|
|
200
|
+
match annotation.value:
|
|
201
|
+
case OBOLiteral():
|
|
202
|
+
return f.Annotation(
|
|
203
|
+
annotation.predicate,
|
|
204
|
+
_oboliteral_to_literal(annotation.value),
|
|
205
|
+
)
|
|
206
|
+
case Reference():
|
|
207
|
+
return f.Annotation(
|
|
208
|
+
annotation.predicate,
|
|
209
|
+
annotation.value,
|
|
210
|
+
)
|
|
211
|
+
raise TypeError
|
|
212
|
+
|
|
213
|
+
|
|
214
|
+
def get_typedef_axioms(typedef: TypeDef) -> Iterable[f.Box]:
|
|
215
|
+
"""Iterate over functional OWL axioms for a typedef."""
|
|
216
|
+
r = f.IdentifierBox(typedef)
|
|
217
|
+
# 40
|
|
218
|
+
if typedef.is_metadata_tag:
|
|
219
|
+
yield f.Declaration(r, type="AnnotationProperty")
|
|
220
|
+
else:
|
|
221
|
+
yield f.Declaration(r, type="ObjectProperty")
|
|
222
|
+
# 2
|
|
223
|
+
if typedef.is_anonymous is not None:
|
|
224
|
+
yield m.IsAnonymousMacro(r, typedef.is_anonymous)
|
|
225
|
+
# 3
|
|
226
|
+
if typedef.name:
|
|
227
|
+
yield m.LabelMacro(r, typedef.name)
|
|
228
|
+
# 4
|
|
229
|
+
if typedef.namespace:
|
|
230
|
+
yield m.OBONamespaceMacro(r, typedef.namespace)
|
|
231
|
+
# 5 the way this one works is that all of the alts get a term-replaced-by,
|
|
232
|
+
# as well as getting their own deprecation axioms
|
|
233
|
+
for alt_id in typedef.alt_ids:
|
|
234
|
+
yield m.ReplacedByMacro(alt_id, r)
|
|
235
|
+
# 6
|
|
236
|
+
yield from _yield_definition(typedef, r)
|
|
237
|
+
# 7
|
|
238
|
+
if typedef.comment:
|
|
239
|
+
yield m.CommentMacro(r, typedef.comment)
|
|
240
|
+
# 8
|
|
241
|
+
for subset in typedef.subsets:
|
|
242
|
+
yield m.OBOIsSubsetMacro(r, subset)
|
|
243
|
+
# 9
|
|
244
|
+
yield from _yield_synonyms(typedef, r)
|
|
245
|
+
# 10
|
|
246
|
+
yield from _yield_xrefs(typedef, r)
|
|
247
|
+
# 11
|
|
248
|
+
yield from _yield_properties(typedef, r)
|
|
249
|
+
# 12
|
|
250
|
+
if typedef.domain:
|
|
251
|
+
if typedef.is_metadata_tag:
|
|
252
|
+
yield f.AnnotationPropertyDomain(r, typedef.domain)
|
|
253
|
+
else:
|
|
254
|
+
yield f.ObjectPropertyDomain(r, typedef.domain)
|
|
255
|
+
# 13
|
|
256
|
+
if typedef.range:
|
|
257
|
+
if typedef.is_metadata_tag:
|
|
258
|
+
yield f.AnnotationPropertyRange(r, typedef.range)
|
|
259
|
+
else:
|
|
260
|
+
yield f.ObjectPropertyRange(r, typedef.range)
|
|
261
|
+
# 14
|
|
262
|
+
if typedef.builtin is not None:
|
|
263
|
+
yield m.IsOBOBuiltinMacro(r, typedef.builtin)
|
|
264
|
+
# 15
|
|
265
|
+
for chain in typedef.holds_over_chain:
|
|
266
|
+
yield m.HoldsOverChain(r, chain)
|
|
267
|
+
# 16
|
|
268
|
+
if typedef.is_anti_symmetric:
|
|
269
|
+
yield f.AsymmetricObjectProperty(r)
|
|
270
|
+
# 17
|
|
271
|
+
if typedef.is_cyclic is not None:
|
|
272
|
+
yield m.IsCyclic(r, typedef.is_cyclic)
|
|
273
|
+
# 18
|
|
274
|
+
if typedef.is_reflexive:
|
|
275
|
+
yield f.ReflexiveObjectProperty(r)
|
|
276
|
+
# 19
|
|
277
|
+
if typedef.is_symmetric:
|
|
278
|
+
yield f.SymmetricObjectProperty(r)
|
|
279
|
+
# 20
|
|
280
|
+
if typedef.is_transitive:
|
|
281
|
+
yield f.TransitiveObjectProperty(r)
|
|
282
|
+
# 21
|
|
283
|
+
if typedef.is_functional:
|
|
284
|
+
yield f.FunctionalObjectProperty(r)
|
|
285
|
+
# 22
|
|
286
|
+
if typedef.is_inverse_functional:
|
|
287
|
+
yield f.InverseFunctionalObjectProperty(r)
|
|
288
|
+
# 23
|
|
289
|
+
for parent in typedef.parents:
|
|
290
|
+
if typedef.is_metadata_tag:
|
|
291
|
+
yield f.SubAnnotationPropertyOf(r, parent)
|
|
292
|
+
else:
|
|
293
|
+
yield f.SubObjectPropertyOf(r, parent)
|
|
294
|
+
# 24 TODO intersection_of, ROBOT does not create any output
|
|
295
|
+
# 25 TODO union_of, ROBOT does not create any output
|
|
296
|
+
# 26
|
|
297
|
+
if typedef.equivalent_to:
|
|
298
|
+
yield f.EquivalentObjectProperties([r, *typedef.equivalent_to])
|
|
299
|
+
# 27
|
|
300
|
+
for x in typedef.disjoint_from:
|
|
301
|
+
yield f.DisjointObjectProperties([x, r])
|
|
302
|
+
# 28
|
|
303
|
+
if typedef.inverse:
|
|
304
|
+
yield f.InverseObjectProperties(r, typedef.inverse)
|
|
305
|
+
# 29
|
|
306
|
+
for to in typedef.transitive_over:
|
|
307
|
+
yield m.TransitiveOver(r, to)
|
|
308
|
+
# 30
|
|
309
|
+
for chain in typedef.equivalent_to_chain:
|
|
310
|
+
yield f.SubObjectPropertyOf(f.ObjectPropertyChain(chain), r)
|
|
311
|
+
# 31 TODO disjoint_over, ROBOT does not create any output
|
|
312
|
+
# 32 TODO relationship, ROBOT does not create any output
|
|
313
|
+
# 33
|
|
314
|
+
if typedef.is_obsolete is not None:
|
|
315
|
+
yield m.IsObsoleteMacro(r, typedef.is_obsolete)
|
|
316
|
+
# 34 TODO created_by
|
|
317
|
+
# 35 TODO creation_date
|
|
318
|
+
# 36
|
|
319
|
+
for rep in typedef.get_replaced_by():
|
|
320
|
+
yield m.ReplacedByMacro(rep, r)
|
|
321
|
+
# 37
|
|
322
|
+
for ref in typedef.get_see_also():
|
|
323
|
+
yield m.OBOConsiderMacro(r, ref)
|
|
324
|
+
# 38 TODO expand_assertion_to
|
|
325
|
+
# 39 TODO expand_expression_to
|
|
326
|
+
# 41
|
|
327
|
+
if typedef.is_class_level is not None:
|
|
328
|
+
yield m.OBOIsClassLevelMacro(r, typedef.is_class_level)
|
|
329
|
+
|
|
330
|
+
|
|
331
|
+
def _yield_definition(term: Stanza, s) -> Iterable[m.DescriptionMacro]:
|
|
332
|
+
if term.definition:
|
|
333
|
+
yield m.DescriptionMacro(
|
|
334
|
+
s,
|
|
335
|
+
term.definition,
|
|
336
|
+
annotations=_get_annotations(term, pv.has_description, term.definition),
|
|
337
|
+
)
|
|
338
|
+
|
|
339
|
+
|
|
340
|
+
def _yield_synonyms(stanza: Stanza, r) -> Iterable[m.SynonymMacro]:
|
|
341
|
+
for synonym in stanza.synonyms:
|
|
342
|
+
yield m.SynonymMacro(
|
|
343
|
+
r,
|
|
344
|
+
synonym.name,
|
|
345
|
+
scope=synonym.specificity,
|
|
346
|
+
synonym_type=synonym.type,
|
|
347
|
+
provenance=synonym.provenance,
|
|
348
|
+
annotations=_process_anns(synonym.annotations),
|
|
349
|
+
language=synonym.language,
|
|
350
|
+
)
|
|
351
|
+
|
|
352
|
+
|
|
353
|
+
def _yield_xrefs(term: Stanza, s) -> Iterable[m.XrefMacro]:
|
|
354
|
+
for xref in term.xrefs:
|
|
355
|
+
yield m.XrefMacro(s, xref, annotations=_get_annotations(term, pv.has_dbxref, xref))
|
|
356
|
+
|
|
357
|
+
|
|
358
|
+
_SKIP = {
|
|
359
|
+
# we skip alt terms since OFN
|
|
360
|
+
# prefers to flip the triple and use term-replaced-by instead
|
|
361
|
+
pv.alternative_term,
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
|
|
365
|
+
def _yield_properties(term: Stanza, s) -> Iterable[f.AnnotationAssertion]:
|
|
366
|
+
for typedef, values in term.properties.items():
|
|
367
|
+
for value in values:
|
|
368
|
+
annotations = _get_annotations(term, typedef, value)
|
|
369
|
+
match value:
|
|
370
|
+
case OBOLiteral():
|
|
371
|
+
yield f.AnnotationAssertion(
|
|
372
|
+
typedef,
|
|
373
|
+
s,
|
|
374
|
+
_oboliteral_to_literal(value),
|
|
375
|
+
annotations=annotations,
|
|
376
|
+
)
|
|
377
|
+
case Reference():
|
|
378
|
+
if typedef in _SKIP:
|
|
379
|
+
continue
|
|
380
|
+
yield f.AnnotationAssertion(
|
|
381
|
+
typedef,
|
|
382
|
+
s,
|
|
383
|
+
value,
|
|
384
|
+
annotations=annotations,
|
|
385
|
+
)
|
|
@@ -0,0 +1,272 @@
|
|
|
1
|
+
"""High-level ontology object model."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import subprocess
|
|
6
|
+
import tempfile
|
|
7
|
+
from collections.abc import Sequence
|
|
8
|
+
from pathlib import Path
|
|
9
|
+
|
|
10
|
+
from curies import Converter
|
|
11
|
+
from rdflib import OWL, RDF, Graph, term
|
|
12
|
+
|
|
13
|
+
from pyobo.struct.functional.dsl import Annotation, Annotations, Axiom, Box
|
|
14
|
+
from pyobo.struct.functional.utils import (
|
|
15
|
+
EXAMPLE_ONTOLOGY_IRI,
|
|
16
|
+
FunctionalOWLSerializable,
|
|
17
|
+
list_to_funowl,
|
|
18
|
+
)
|
|
19
|
+
from pyobo.utils.io import safe_open
|
|
20
|
+
|
|
21
|
+
__all__ = [
|
|
22
|
+
"Document",
|
|
23
|
+
"Import",
|
|
24
|
+
"Ontology",
|
|
25
|
+
"Prefix",
|
|
26
|
+
"write_ontology",
|
|
27
|
+
]
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
def write_ontology(
|
|
31
|
+
*,
|
|
32
|
+
prefixes: dict[str, str] | list[Prefix],
|
|
33
|
+
iri: str | None = None,
|
|
34
|
+
version_iri: str | None = None,
|
|
35
|
+
directly_imports_documents: list[Import | str] | None = None,
|
|
36
|
+
annotations: Annotations | None = None,
|
|
37
|
+
axioms: list[Axiom] | None = None,
|
|
38
|
+
file=None,
|
|
39
|
+
) -> None:
|
|
40
|
+
"""Print an ontology serialized as functional OWL."""
|
|
41
|
+
ontology = Ontology(
|
|
42
|
+
iri=iri,
|
|
43
|
+
version_iri=version_iri,
|
|
44
|
+
directly_imports_documents=directly_imports_documents,
|
|
45
|
+
annotations=annotations,
|
|
46
|
+
axioms=axioms,
|
|
47
|
+
)
|
|
48
|
+
document = Document(ontology, prefixes)
|
|
49
|
+
print(document.to_funowl(), file=file)
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
class Document:
|
|
53
|
+
"""Represents a functional OWL document."""
|
|
54
|
+
|
|
55
|
+
prefixes: list[Prefix]
|
|
56
|
+
ontologies: list[Ontology]
|
|
57
|
+
|
|
58
|
+
def __init__(
|
|
59
|
+
self,
|
|
60
|
+
ontologies: Ontology | list[Ontology],
|
|
61
|
+
prefixes: dict[str, str] | list[Prefix],
|
|
62
|
+
) -> None:
|
|
63
|
+
"""Initialize a functional OWL document.
|
|
64
|
+
|
|
65
|
+
:param ontologies: An ontology or list of ontologies.
|
|
66
|
+
|
|
67
|
+
.. warning::
|
|
68
|
+
|
|
69
|
+
RDF export can only be used for a single ontology.
|
|
70
|
+
|
|
71
|
+
:param prefixes: A list of prefixes to define in the document
|
|
72
|
+
|
|
73
|
+
.. seealso::
|
|
74
|
+
|
|
75
|
+
`3.7 "Functional-Style Syntax"
|
|
76
|
+
<https://www.w3.org/TR/owl2-syntax/#Functional-Style_Syntax>`_
|
|
77
|
+
"""
|
|
78
|
+
self.ontologies = ontologies if isinstance(ontologies, list) else [ontologies]
|
|
79
|
+
if isinstance(prefixes, dict):
|
|
80
|
+
self.prefixes = [
|
|
81
|
+
Prefix(prefix, uri_prefix)
|
|
82
|
+
for prefix, uri_prefix in sorted(prefixes.items(), key=lambda kv: kv[0].casefold())
|
|
83
|
+
]
|
|
84
|
+
else:
|
|
85
|
+
self.prefixes = prefixes
|
|
86
|
+
|
|
87
|
+
@property
|
|
88
|
+
def prefix_map(self) -> dict[str, str]:
|
|
89
|
+
"""Get a simple dictionary representation of prefixes."""
|
|
90
|
+
return {prefix.prefix: prefix.uri_prefix for prefix in self.prefixes}
|
|
91
|
+
|
|
92
|
+
def write_rdf(self, path: str | Path) -> None:
|
|
93
|
+
"""Write RDF to a file."""
|
|
94
|
+
path = Path(path).expanduser().resolve()
|
|
95
|
+
graph = self.to_rdf()
|
|
96
|
+
graph.serialize(path, format="ttl")
|
|
97
|
+
|
|
98
|
+
def to_rdf(self) -> Graph:
|
|
99
|
+
"""Get an RDFlib graph representing the ontology."""
|
|
100
|
+
if len(self.ontologies) != 1:
|
|
101
|
+
raise ValueError("Can only export one ontology to RDF")
|
|
102
|
+
graph = Graph()
|
|
103
|
+
for prefix_box in self.prefixes:
|
|
104
|
+
graph.namespace_manager.bind(prefix_box.prefix, prefix_box.uri_prefix)
|
|
105
|
+
converter = Converter.from_rdflib(graph)
|
|
106
|
+
for ontology in self.ontologies:
|
|
107
|
+
ontology.to_rdflib_node(graph, converter)
|
|
108
|
+
return graph
|
|
109
|
+
|
|
110
|
+
def write_funowl(self, path: str | Path) -> None:
|
|
111
|
+
"""Write functional OWL to a file.."""
|
|
112
|
+
path = Path(path).expanduser().resolve()
|
|
113
|
+
with safe_open(path, read=False) as file:
|
|
114
|
+
file.write(self.to_funowl())
|
|
115
|
+
|
|
116
|
+
def to_funowl(self) -> str:
|
|
117
|
+
"""Get the document as a functional OWL string."""
|
|
118
|
+
prefixes = list_to_funowl(self.prefixes, sep="\n")
|
|
119
|
+
ontologies = list_to_funowl(self.ontologies, sep="\n\n")
|
|
120
|
+
return prefixes + "\n\n" + ontologies
|
|
121
|
+
|
|
122
|
+
|
|
123
|
+
class Ontology(Box):
|
|
124
|
+
"""Represents an OWL 2 ontology defined in `3 "Ontologies" <https://www.w3.org/TR/owl2-syntax/#Ontologies>`_."""
|
|
125
|
+
|
|
126
|
+
directly_imports_documents: Sequence[Import]
|
|
127
|
+
annotations: Sequence[Annotation]
|
|
128
|
+
axioms: Sequence[Box]
|
|
129
|
+
|
|
130
|
+
def __init__(
|
|
131
|
+
self,
|
|
132
|
+
iri: str | None = None,
|
|
133
|
+
version_iri: str | None = None,
|
|
134
|
+
directly_imports_documents: list[Import | str] | None = None,
|
|
135
|
+
annotations: Annotations | None = None,
|
|
136
|
+
axioms: Sequence[Box] | None = None,
|
|
137
|
+
) -> None:
|
|
138
|
+
"""Instantiate an ontology.
|
|
139
|
+
|
|
140
|
+
:param iri: The ontology IRI.
|
|
141
|
+
|
|
142
|
+
.. seealso::
|
|
143
|
+
|
|
144
|
+
`3.1 "Ontology IRI and Version IRI"
|
|
145
|
+
<https://www.w3.org/TR/owl2-syntax/#Ontology_IRI_and_Version_IRI>`_
|
|
146
|
+
|
|
147
|
+
:param version_iri: An optional version IRI
|
|
148
|
+
:param directly_imports_documents: Optional ontology imports
|
|
149
|
+
|
|
150
|
+
.. seealso::
|
|
151
|
+
|
|
152
|
+
`3.4 "Imports" <https://www.w3.org/TR/owl2-syntax/#Imports>`_
|
|
153
|
+
|
|
154
|
+
:param annotations: .. seealso::
|
|
155
|
+
|
|
156
|
+
`3.5 "Ontology Annotations"
|
|
157
|
+
<https://www.w3.org/TR/owl2-syntax/#Ontology_Annotations>`_
|
|
158
|
+
:param axioms: statements about what is true in the domain
|
|
159
|
+
|
|
160
|
+
.. seealso::
|
|
161
|
+
|
|
162
|
+
`9 "Axioms" <https://www.w3.org/TR/owl2-syntax/#Axioms>`_
|
|
163
|
+
"""
|
|
164
|
+
self.iri = iri
|
|
165
|
+
self.version_iri = version_iri
|
|
166
|
+
self.directly_imports_documents = [
|
|
167
|
+
Import(i) if isinstance(i, str) else i for i in directly_imports_documents or []
|
|
168
|
+
]
|
|
169
|
+
self.annotations = annotations or []
|
|
170
|
+
self.axioms = axioms or []
|
|
171
|
+
# this is the amount of leading whitespace on each
|
|
172
|
+
# when outputting to functional OWL
|
|
173
|
+
self._leading = ""
|
|
174
|
+
|
|
175
|
+
def to_rdflib_node(self, graph: Graph, converter: Converter) -> term.URIRef | term.BNode:
|
|
176
|
+
"""Add the ontology to the triple store."""
|
|
177
|
+
ontology_node = term.URIRef(self.iri) if self.iri is not None else term.BNode()
|
|
178
|
+
graph.add((ontology_node, RDF.type, OWL.Ontology))
|
|
179
|
+
if self.version_iri:
|
|
180
|
+
graph.add((ontology_node, OWL.versionIRI, term.URIRef(self.version_iri)))
|
|
181
|
+
for imp in self.directly_imports_documents:
|
|
182
|
+
graph.add((ontology_node, OWL.imports, term.URIRef(imp.iri)))
|
|
183
|
+
for annotation in self.annotations:
|
|
184
|
+
annotation._add_to_triple(graph, ontology_node, converter=converter)
|
|
185
|
+
for axiom in self.axioms:
|
|
186
|
+
axiom.to_rdflib_node(graph, converter)
|
|
187
|
+
return ontology_node
|
|
188
|
+
|
|
189
|
+
def to_funowl(self) -> str:
|
|
190
|
+
"""Make functional OWL."""
|
|
191
|
+
tag = self.__class__.__name__
|
|
192
|
+
return f"{tag}({self.to_funowl_args()}\n)"
|
|
193
|
+
|
|
194
|
+
def to_funowl_args(self) -> str:
|
|
195
|
+
"""Get the inside of the functional OWL tag representing the ontology."""
|
|
196
|
+
rv = ""
|
|
197
|
+
if self.iri:
|
|
198
|
+
rv += f"<{self.iri}>"
|
|
199
|
+
if self.version_iri:
|
|
200
|
+
rv += f" <{self.version_iri}>"
|
|
201
|
+
rv += f"\n{self._leading}"
|
|
202
|
+
|
|
203
|
+
parts: list[Sequence[FunctionalOWLSerializable]] = []
|
|
204
|
+
if self.directly_imports_documents:
|
|
205
|
+
parts.append(self.directly_imports_documents)
|
|
206
|
+
if self.annotations:
|
|
207
|
+
parts.append(self.annotations)
|
|
208
|
+
if self.axioms:
|
|
209
|
+
parts.append(self.axioms)
|
|
210
|
+
|
|
211
|
+
rv += f"\n\n{self._leading}".join(
|
|
212
|
+
list_to_funowl(part, sep=f"\n{self._leading}") for part in parts
|
|
213
|
+
)
|
|
214
|
+
return rv
|
|
215
|
+
|
|
216
|
+
|
|
217
|
+
class Prefix(Box):
|
|
218
|
+
"""A model for imports, as defined by `3.7 "Functional-Style Syntax" <https://www.w3.org/TR/owl2-syntax/#Functional-Style_Syntax>`_."""
|
|
219
|
+
|
|
220
|
+
def __init__(self, prefix: str, uri_prefix: str) -> None:
|
|
221
|
+
"""Initialize the definition with a CURIE prefix and URI prefix."""
|
|
222
|
+
self.prefix = prefix
|
|
223
|
+
self.uri_prefix = uri_prefix
|
|
224
|
+
|
|
225
|
+
def to_rdflib_node(self, graph: Graph, converter: Converter) -> term.BNode:
|
|
226
|
+
"""Add the prefix to an RDF graph."""
|
|
227
|
+
graph.namespace_manager.bind(self.prefix, self.uri_prefix)
|
|
228
|
+
return term.BNode() # dummy
|
|
229
|
+
|
|
230
|
+
def to_funowl_args(self) -> str:
|
|
231
|
+
"""Get the inside of the functional OWL tag representing the prefix."""
|
|
232
|
+
return f"{self.prefix}:=<{self.uri_prefix}>"
|
|
233
|
+
|
|
234
|
+
|
|
235
|
+
class Import(Box):
|
|
236
|
+
"""A model for imports, as defined by `3.4 "Imports" <https://www.w3.org/TR/owl2-syntax/#Imports>`_."""
|
|
237
|
+
|
|
238
|
+
def __init__(self, iri: str) -> None:
|
|
239
|
+
"""Initialize the import."""
|
|
240
|
+
self.iri = iri
|
|
241
|
+
|
|
242
|
+
def to_rdflib_node(self, graph: Graph, converter: Converter) -> term.BNode:
|
|
243
|
+
"""Add the import to an RDF graph."""
|
|
244
|
+
raise NotImplementedError
|
|
245
|
+
|
|
246
|
+
def to_funowl_args(self) -> str:
|
|
247
|
+
"""Get the inside of the functional OWL tag representing the import."""
|
|
248
|
+
return f"<{self.iri}>"
|
|
249
|
+
|
|
250
|
+
|
|
251
|
+
def get_rdf_graph_oracle(boxes: list[Box], *, prefix_map: dict[str, str]) -> Graph:
|
|
252
|
+
"""Serialize to turtle via OFN and conversion with ROBOT."""
|
|
253
|
+
from bioontologies.robot import convert
|
|
254
|
+
|
|
255
|
+
ontology = Ontology(
|
|
256
|
+
iri=EXAMPLE_ONTOLOGY_IRI,
|
|
257
|
+
axioms=boxes,
|
|
258
|
+
)
|
|
259
|
+
document = Document(ontology, prefix_map)
|
|
260
|
+
graph = Graph()
|
|
261
|
+
with tempfile.TemporaryDirectory() as directory:
|
|
262
|
+
stub = Path(directory).joinpath("test")
|
|
263
|
+
ofn_path = stub.with_suffix(".ofn")
|
|
264
|
+
text = document.to_funowl()
|
|
265
|
+
ofn_path.write_text(text)
|
|
266
|
+
ttl_path = stub.with_suffix(".ttl")
|
|
267
|
+
try:
|
|
268
|
+
convert(ofn_path, ttl_path)
|
|
269
|
+
except subprocess.CalledProcessError:
|
|
270
|
+
raise RuntimeError(f"failed to convert axioms from:\n\n{text}") from None
|
|
271
|
+
graph.parse(ttl_path)
|
|
272
|
+
return graph
|