obographs 0.0.2__py3-none-any.whl → 0.0.4__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.
- obographs/__init__.py +60 -1
- obographs/model.py +80 -32
- obographs/standardized.py +556 -67
- obographs/version.py +1 -1
- {obographs-0.0.2.dist-info → obographs-0.0.4.dist-info}/METADATA +7 -23
- obographs-0.0.4.dist-info/RECORD +10 -0
- {obographs-0.0.2.dist-info → obographs-0.0.4.dist-info}/WHEEL +1 -1
- obographs-0.0.2.dist-info/RECORD +0 -10
- {obographs-0.0.2.dist-info → obographs-0.0.4.dist-info}/entry_points.txt +0 -0
- {obographs-0.0.2.dist-info → obographs-0.0.4.dist-info}/licenses/LICENSE +0 -0
obographs/__init__.py
CHANGED
|
@@ -1,13 +1,72 @@
|
|
|
1
1
|
"""A python data model for OBO Graphs."""
|
|
2
2
|
|
|
3
|
-
from .model import
|
|
3
|
+
from .model import (
|
|
4
|
+
Definition,
|
|
5
|
+
DomainRangeAxiom,
|
|
6
|
+
Edge,
|
|
7
|
+
EquivalentNodeSet,
|
|
8
|
+
ExistentialRestrictionExpression,
|
|
9
|
+
Graph,
|
|
10
|
+
GraphDocument,
|
|
11
|
+
LogicalDefinition,
|
|
12
|
+
Meta,
|
|
13
|
+
Node,
|
|
14
|
+
NodeType,
|
|
15
|
+
Property,
|
|
16
|
+
PropertyChainAxiom,
|
|
17
|
+
PropertyType,
|
|
18
|
+
Synonym,
|
|
19
|
+
Xref,
|
|
20
|
+
read,
|
|
21
|
+
)
|
|
22
|
+
from .standardized import (
|
|
23
|
+
StandardizedBaseModel,
|
|
24
|
+
StandardizedDefinition,
|
|
25
|
+
StandardizedDomainRangeAxiom,
|
|
26
|
+
StandardizedEdge,
|
|
27
|
+
StandardizedEquivalentNodeSet,
|
|
28
|
+
StandardizedExistentialRestriction,
|
|
29
|
+
StandardizedGraph,
|
|
30
|
+
StandardizedGraphDocument,
|
|
31
|
+
StandardizedLogicalDefinition,
|
|
32
|
+
StandardizedMeta,
|
|
33
|
+
StandardizedNode,
|
|
34
|
+
StandardizedProperty,
|
|
35
|
+
StandardizedPropertyChainAxiom,
|
|
36
|
+
StandardizedSynonym,
|
|
37
|
+
StandardizedXref,
|
|
38
|
+
)
|
|
4
39
|
|
|
5
40
|
__all__ = [
|
|
41
|
+
"Definition",
|
|
42
|
+
"DomainRangeAxiom",
|
|
43
|
+
"Edge",
|
|
44
|
+
"EquivalentNodeSet",
|
|
45
|
+
"ExistentialRestrictionExpression",
|
|
6
46
|
"Graph",
|
|
7
47
|
"GraphDocument",
|
|
48
|
+
"LogicalDefinition",
|
|
8
49
|
"Meta",
|
|
9
50
|
"Node",
|
|
51
|
+
"NodeType",
|
|
10
52
|
"Property",
|
|
53
|
+
"PropertyChainAxiom",
|
|
54
|
+
"PropertyType",
|
|
55
|
+
"StandardizedBaseModel",
|
|
56
|
+
"StandardizedDefinition",
|
|
57
|
+
"StandardizedDomainRangeAxiom",
|
|
58
|
+
"StandardizedEdge",
|
|
59
|
+
"StandardizedEquivalentNodeSet",
|
|
60
|
+
"StandardizedExistentialRestriction",
|
|
61
|
+
"StandardizedGraph",
|
|
62
|
+
"StandardizedGraphDocument",
|
|
63
|
+
"StandardizedLogicalDefinition",
|
|
64
|
+
"StandardizedMeta",
|
|
65
|
+
"StandardizedNode",
|
|
66
|
+
"StandardizedProperty",
|
|
67
|
+
"StandardizedPropertyChainAxiom",
|
|
68
|
+
"StandardizedSynonym",
|
|
69
|
+
"StandardizedXref",
|
|
11
70
|
"Synonym",
|
|
12
71
|
"Xref",
|
|
13
72
|
"read",
|
obographs/model.py
CHANGED
|
@@ -9,27 +9,35 @@
|
|
|
9
9
|
|
|
10
10
|
from __future__ import annotations
|
|
11
11
|
|
|
12
|
+
import gzip
|
|
12
13
|
import json
|
|
13
14
|
import logging
|
|
14
15
|
from collections import defaultdict
|
|
15
16
|
from pathlib import Path
|
|
16
|
-
from typing import TYPE_CHECKING,
|
|
17
|
+
from typing import TYPE_CHECKING, Literal, TypeAlias, overload
|
|
17
18
|
|
|
19
|
+
import curies
|
|
20
|
+
from curies.vocabulary import SynonymScopeOIO
|
|
18
21
|
from pydantic import BaseModel, Field
|
|
19
22
|
|
|
20
23
|
if TYPE_CHECKING:
|
|
21
|
-
import curies
|
|
22
|
-
|
|
23
24
|
from .standardized import StandardizedGraph
|
|
24
25
|
|
|
25
26
|
__all__ = [
|
|
26
27
|
"Definition",
|
|
28
|
+
"DomainRangeAxiom",
|
|
27
29
|
"Edge",
|
|
30
|
+
"EquivalentNodeSet",
|
|
31
|
+
"ExistentialRestrictionExpression",
|
|
28
32
|
"Graph",
|
|
29
33
|
"GraphDocument",
|
|
34
|
+
"LogicalDefinition",
|
|
30
35
|
"Meta",
|
|
31
36
|
"Node",
|
|
37
|
+
"NodeType",
|
|
32
38
|
"Property",
|
|
39
|
+
"PropertyChainAxiom",
|
|
40
|
+
"PropertyType",
|
|
33
41
|
"Synonym",
|
|
34
42
|
"Xref",
|
|
35
43
|
"read",
|
|
@@ -40,31 +48,24 @@ logger = logging.getLogger(__name__)
|
|
|
40
48
|
OBO_URI_PREFIX = "http://purl.obolibrary.org/obo/"
|
|
41
49
|
OBO_URI_PREFIX_LEN = len(OBO_URI_PREFIX)
|
|
42
50
|
|
|
43
|
-
SynonymPredicate: TypeAlias = Literal[
|
|
44
|
-
"hasExactSynonym",
|
|
45
|
-
"hasBroadSynonym",
|
|
46
|
-
"hasNarrowSynonym",
|
|
47
|
-
"hasRelatedSynonym",
|
|
48
|
-
]
|
|
49
51
|
NodeType: TypeAlias = Literal["CLASS", "PROPERTY", "INDIVIDUAL"]
|
|
50
52
|
|
|
51
|
-
|
|
53
|
+
#: When node type is ``PROPERTY``, this is extra information
|
|
54
|
+
PropertyType: TypeAlias = Literal["ANNOTATION", "OBJECT", "DATA"]
|
|
52
55
|
|
|
53
|
-
|
|
54
|
-
#: identifiers. See https://owlcollab.github.io/oboformat/doc/GO.format.obo-1_4.html
|
|
55
|
-
OBO_SYNONYM_TO_OIO: dict[str, SynonymPredicate] = {
|
|
56
|
-
"EXACT": "hasExactSynonym",
|
|
57
|
-
"BROAD": "hasBroadSynonym",
|
|
58
|
-
"NARROW": "hasNarrowSynonym",
|
|
59
|
-
"RELATED": "hasRelatedSynonym",
|
|
60
|
-
}
|
|
56
|
+
TimeoutHint = int | float | None
|
|
61
57
|
|
|
62
58
|
|
|
63
59
|
class Property(BaseModel):
|
|
64
60
|
"""Represent a property inside a metadata element."""
|
|
65
61
|
|
|
66
62
|
pred: str
|
|
67
|
-
val: str
|
|
63
|
+
val: str | None = Field(
|
|
64
|
+
None,
|
|
65
|
+
description="Stores the value of the property. This can be a string representing a "
|
|
66
|
+
"literal or IRI. This isn't supposed to be nullable, but it happens a lot - might be a "
|
|
67
|
+
"bug in OWLAPI or ROBOT",
|
|
68
|
+
)
|
|
68
69
|
xrefs: list[str] | None = None
|
|
69
70
|
meta: Meta | None = None
|
|
70
71
|
|
|
@@ -86,8 +87,8 @@ class Synonym(BaseModel):
|
|
|
86
87
|
"""Represents a synonym inside an object meta."""
|
|
87
88
|
|
|
88
89
|
val: str | None = Field(default=None)
|
|
89
|
-
pred:
|
|
90
|
-
synonymType: str | None = Field(examples=["OMO:0003000"]) # noqa:N815
|
|
90
|
+
pred: SynonymScopeOIO = Field(default="hasExactSynonym")
|
|
91
|
+
synonymType: str | None = Field(None, examples=["OMO:0003000"]) # noqa:N815
|
|
91
92
|
xrefs: list[str] = Field(
|
|
92
93
|
default_factory=list,
|
|
93
94
|
description="A list of CURIEs/IRIs for provenance for the synonym",
|
|
@@ -123,7 +124,52 @@ class Node(BaseModel):
|
|
|
123
124
|
id: str = Field(..., description="The IRI for the node")
|
|
124
125
|
lbl: str | None = Field(None, description="The name of the node")
|
|
125
126
|
meta: Meta | None = None
|
|
126
|
-
type: NodeType = Field(
|
|
127
|
+
type: NodeType | None = Field(None, description="Type of node")
|
|
128
|
+
propertyType: PropertyType | None = Field( # noqa:N815
|
|
129
|
+
None, description="Type of property, if the node type is a property"
|
|
130
|
+
)
|
|
131
|
+
|
|
132
|
+
|
|
133
|
+
class DomainRangeAxiom(BaseModel):
|
|
134
|
+
"""Represents a domain/range axiom."""
|
|
135
|
+
|
|
136
|
+
predicateId: str # noqa:N815
|
|
137
|
+
domainClassIds: list[str] | None = None # noqa:N815
|
|
138
|
+
rangeClassIds: list[str] | None = None # noqa:N815
|
|
139
|
+
allValuesFromEdges: list[Edge] | None = None # noqa:N815
|
|
140
|
+
meta: Meta | None = None
|
|
141
|
+
|
|
142
|
+
|
|
143
|
+
class PropertyChainAxiom(BaseModel):
|
|
144
|
+
"""Represents a property chain axiom."""
|
|
145
|
+
|
|
146
|
+
predicateId: str # noqa:N815
|
|
147
|
+
chainPredicateIds: list[str] # noqa:N815
|
|
148
|
+
meta: Meta | None = None
|
|
149
|
+
|
|
150
|
+
|
|
151
|
+
class ExistentialRestrictionExpression(BaseModel):
|
|
152
|
+
"""Represents an existential restriction."""
|
|
153
|
+
|
|
154
|
+
propertyId: str # noqa:N815
|
|
155
|
+
fillerId: str # noqa:N815
|
|
156
|
+
|
|
157
|
+
|
|
158
|
+
class LogicalDefinition(BaseModel):
|
|
159
|
+
"""Represents a logical definition chain axiom."""
|
|
160
|
+
|
|
161
|
+
definedClassId: str # noqa:N815
|
|
162
|
+
genusIds: list[str] | None = None # noqa:N815
|
|
163
|
+
restrictions: list[ExistentialRestrictionExpression] | None = None
|
|
164
|
+
meta: Meta | None = None
|
|
165
|
+
|
|
166
|
+
|
|
167
|
+
class EquivalentNodeSet(BaseModel):
|
|
168
|
+
"""Represents a set of equivalent nodes."""
|
|
169
|
+
|
|
170
|
+
representativeNodeId: str # noqa:N815
|
|
171
|
+
nodeIds: list[str] # noqa:N815
|
|
172
|
+
meta: Meta | None = None
|
|
127
173
|
|
|
128
174
|
|
|
129
175
|
class Graph(BaseModel):
|
|
@@ -133,10 +179,10 @@ class Graph(BaseModel):
|
|
|
133
179
|
meta: Meta | None = None
|
|
134
180
|
nodes: list[Node] = Field(default_factory=list)
|
|
135
181
|
edges: list[Edge] = Field(default_factory=list)
|
|
136
|
-
equivalentNodesSets: list[
|
|
137
|
-
logicalDefinitionAxioms: list[
|
|
138
|
-
domainRangeAxioms: list[
|
|
139
|
-
propertyChainAxioms: list[
|
|
182
|
+
equivalentNodesSets: list[EquivalentNodeSet] = Field(default_factory=list) # noqa:N815
|
|
183
|
+
logicalDefinitionAxioms: list[LogicalDefinition] = Field(default_factory=list) # noqa:N815
|
|
184
|
+
domainRangeAxioms: list[DomainRangeAxiom] = Field(default_factory=list) # noqa:N815
|
|
185
|
+
propertyChainAxioms: list[PropertyChainAxiom] = Field(default_factory=list) # noqa:N815
|
|
140
186
|
|
|
141
187
|
def standardize(self, converter: curies.Converter) -> StandardizedGraph:
|
|
142
188
|
"""Standardize the graph."""
|
|
@@ -205,12 +251,14 @@ def read(
|
|
|
205
251
|
|
|
206
252
|
elif isinstance(source, str | Path):
|
|
207
253
|
path = Path(source).expanduser().resolve()
|
|
208
|
-
if path.is_file():
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
254
|
+
if not path.is_file():
|
|
255
|
+
raise FileNotFoundError
|
|
256
|
+
if path.suffix.endswith(".gz"):
|
|
257
|
+
with gzip.open(path, mode="rt") as file:
|
|
258
|
+
graph_document = GraphDocument.model_validate(json.load(file))
|
|
259
|
+
else:
|
|
260
|
+
with path.open() as file:
|
|
261
|
+
graph_document = GraphDocument.model_validate(json.load(file))
|
|
214
262
|
else:
|
|
215
263
|
raise TypeError(f"Unhandled source: {source}")
|
|
216
264
|
|
obographs/standardized.py
CHANGED
|
@@ -2,68 +2,172 @@
|
|
|
2
2
|
|
|
3
3
|
from __future__ import annotations
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
import logging
|
|
6
|
+
from abc import ABC, abstractmethod
|
|
7
|
+
from typing import Generic, TypeVar, cast
|
|
8
|
+
|
|
9
|
+
import curies.preprocessing
|
|
10
|
+
from curies import Converter, Reference, Triple, vocabulary
|
|
11
|
+
from curies.vocabulary import SynonymScopeOIO
|
|
6
12
|
from pydantic import BaseModel, Field
|
|
7
13
|
from typing_extensions import Self
|
|
8
14
|
|
|
9
|
-
from obographs.model import
|
|
15
|
+
from obographs.model import (
|
|
16
|
+
Definition,
|
|
17
|
+
DomainRangeAxiom,
|
|
18
|
+
Edge,
|
|
19
|
+
EquivalentNodeSet,
|
|
20
|
+
ExistentialRestrictionExpression,
|
|
21
|
+
Graph,
|
|
22
|
+
GraphDocument,
|
|
23
|
+
LogicalDefinition,
|
|
24
|
+
Meta,
|
|
25
|
+
Node,
|
|
26
|
+
NodeType,
|
|
27
|
+
Property,
|
|
28
|
+
PropertyChainAxiom,
|
|
29
|
+
PropertyType,
|
|
30
|
+
Synonym,
|
|
31
|
+
Xref,
|
|
32
|
+
)
|
|
10
33
|
|
|
11
34
|
__all__ = [
|
|
35
|
+
"StandardizedBaseModel",
|
|
12
36
|
"StandardizedDefinition",
|
|
37
|
+
"StandardizedDomainRangeAxiom",
|
|
13
38
|
"StandardizedEdge",
|
|
39
|
+
"StandardizedEquivalentNodeSet",
|
|
40
|
+
"StandardizedExistentialRestriction",
|
|
14
41
|
"StandardizedGraph",
|
|
42
|
+
"StandardizedGraphDocument",
|
|
43
|
+
"StandardizedLogicalDefinition",
|
|
15
44
|
"StandardizedMeta",
|
|
16
45
|
"StandardizedNode",
|
|
46
|
+
"StandardizedProperty",
|
|
47
|
+
"StandardizedPropertyChainAxiom",
|
|
48
|
+
"StandardizedSynonym",
|
|
17
49
|
"StandardizedXref",
|
|
18
50
|
]
|
|
19
51
|
|
|
52
|
+
logger = logging.getLogger(__name__)
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
def _expand_list(references: list[Reference] | None, converter: Converter) -> list[str] | None:
|
|
56
|
+
if references is None or not references:
|
|
57
|
+
return None
|
|
58
|
+
return [converter.expand_reference(r, strict=True) for r in references]
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
X = TypeVar("X")
|
|
20
62
|
|
|
21
|
-
|
|
63
|
+
|
|
64
|
+
class StandardizedBaseModel(BaseModel, ABC, Generic[X]):
|
|
65
|
+
"""A standardized property."""
|
|
66
|
+
|
|
67
|
+
@classmethod
|
|
68
|
+
@abstractmethod
|
|
69
|
+
def from_obograph_raw(
|
|
70
|
+
cls, obj: X, converter: Converter, *, strict: bool = False
|
|
71
|
+
) -> Self | None:
|
|
72
|
+
"""Instantiate by standardizing a raw OBO Graph object."""
|
|
73
|
+
raise NotImplementedError
|
|
74
|
+
|
|
75
|
+
@abstractmethod
|
|
76
|
+
def to_raw(self, converter: Converter) -> X:
|
|
77
|
+
"""Create a raw object."""
|
|
78
|
+
raise NotImplementedError
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
class StandardizedProperty(StandardizedBaseModel[Property]):
|
|
22
82
|
"""A standardized property."""
|
|
23
83
|
|
|
24
84
|
predicate: Reference
|
|
25
|
-
value: Reference
|
|
85
|
+
value: Reference | str = Field(
|
|
86
|
+
..., description="Parsed into a Reference if a CURIE or IRI, or a string if it's a literal"
|
|
87
|
+
)
|
|
26
88
|
xrefs: list[Reference] | None = None
|
|
27
89
|
meta: StandardizedMeta | None = None
|
|
28
90
|
|
|
29
91
|
@classmethod
|
|
30
|
-
def from_obograph_raw(
|
|
92
|
+
def from_obograph_raw(
|
|
93
|
+
cls, prop: Property, converter: Converter, *, strict: bool = False
|
|
94
|
+
) -> Self:
|
|
31
95
|
"""Instantiate by standardizing a raw OBO Graph object."""
|
|
96
|
+
if not prop.val or not prop.pred:
|
|
97
|
+
raise ValueError
|
|
98
|
+
value: Reference | str | None
|
|
99
|
+
|
|
100
|
+
if (
|
|
101
|
+
prop.val.startswith("http://")
|
|
102
|
+
or prop.val.startswith("https")
|
|
103
|
+
or converter.is_curie(prop.val)
|
|
104
|
+
or prop.val in BUILTINS
|
|
105
|
+
):
|
|
106
|
+
value = _curie_or_uri_to_ref(prop.val, converter, strict=False) or prop.val
|
|
107
|
+
else:
|
|
108
|
+
value = prop.val
|
|
32
109
|
return cls(
|
|
33
|
-
predicate=_curie_or_uri_to_ref(prop.pred, converter),
|
|
34
|
-
value=
|
|
110
|
+
predicate=_curie_or_uri_to_ref(prop.pred, converter, strict=strict),
|
|
111
|
+
value=value,
|
|
35
112
|
)
|
|
36
113
|
|
|
114
|
+
def to_raw(self, converter: Converter) -> Property:
|
|
115
|
+
"""Create a raw object."""
|
|
116
|
+
return Property(
|
|
117
|
+
pred=converter.expand_reference(self.predicate),
|
|
118
|
+
val=converter.expand_reference(self.value)
|
|
119
|
+
if isinstance(self.value, Reference)
|
|
120
|
+
else self.value,
|
|
121
|
+
xrefs=_expand_list(self.xrefs, converter),
|
|
122
|
+
meta=self.meta.to_raw(converter) if self.meta is not None else None,
|
|
123
|
+
)
|
|
37
124
|
|
|
38
|
-
|
|
125
|
+
|
|
126
|
+
class StandardizedDefinition(StandardizedBaseModel[Definition]):
|
|
39
127
|
"""A standardized definition."""
|
|
40
128
|
|
|
41
129
|
value: str | None = Field(default=None)
|
|
42
130
|
xrefs: list[Reference] | None = Field(default=None)
|
|
43
131
|
|
|
44
132
|
@classmethod
|
|
45
|
-
def from_obograph_raw(
|
|
46
|
-
|
|
133
|
+
def from_obograph_raw(
|
|
134
|
+
cls, definition: Definition | None, converter: Converter, *, strict: bool = False
|
|
135
|
+
) -> Self | None:
|
|
136
|
+
"""Parse a raw object."""
|
|
47
137
|
if definition is None:
|
|
48
138
|
return None
|
|
49
139
|
return cls(
|
|
50
140
|
value=definition.val,
|
|
51
|
-
xrefs=_parse_list(definition.xrefs, converter),
|
|
141
|
+
xrefs=_parse_list(definition.xrefs, converter, strict=strict),
|
|
142
|
+
)
|
|
143
|
+
|
|
144
|
+
def to_raw(self, converter: Converter) -> Definition:
|
|
145
|
+
"""Create a raw object."""
|
|
146
|
+
return Definition(
|
|
147
|
+
val=self.value,
|
|
148
|
+
xrefs=_expand_list(self.xrefs, converter),
|
|
52
149
|
)
|
|
53
150
|
|
|
54
151
|
|
|
55
|
-
class StandardizedXref(
|
|
152
|
+
class StandardizedXref(StandardizedBaseModel[Xref]):
|
|
56
153
|
"""A standardized database cross-reference."""
|
|
57
154
|
|
|
58
155
|
reference: Reference
|
|
59
156
|
|
|
60
157
|
@classmethod
|
|
61
|
-
def from_obograph_raw(cls, xref: Xref, converter: Converter) -> Self:
|
|
158
|
+
def from_obograph_raw(cls, xref: Xref, converter: Converter, *, strict: bool = False) -> Self:
|
|
62
159
|
"""Instantiate by standardizing a raw OBO Graph object."""
|
|
63
|
-
|
|
160
|
+
reference = _curie_or_uri_to_ref(xref.val, converter, strict=strict)
|
|
161
|
+
if reference is None:
|
|
162
|
+
raise ValueError(f"could not parse xref: {xref.val}")
|
|
163
|
+
return cls(reference=reference)
|
|
64
164
|
|
|
165
|
+
def to_raw(self, converter: Converter) -> Xref:
|
|
166
|
+
"""Create a raw object."""
|
|
167
|
+
return Xref(val=self.reference.curie)
|
|
65
168
|
|
|
66
|
-
|
|
169
|
+
|
|
170
|
+
class StandardizedSynonym(StandardizedBaseModel[Synonym]):
|
|
67
171
|
"""A standardized synonym."""
|
|
68
172
|
|
|
69
173
|
text: str
|
|
@@ -72,17 +176,31 @@ class StandardizedSynonym(BaseModel):
|
|
|
72
176
|
xrefs: list[Reference] | None = None
|
|
73
177
|
|
|
74
178
|
@classmethod
|
|
75
|
-
def from_obograph_raw(
|
|
179
|
+
def from_obograph_raw(
|
|
180
|
+
cls, synonym: Synonym, converter: Converter, *, strict: bool = False
|
|
181
|
+
) -> Self:
|
|
76
182
|
"""Instantiate by standardizing a raw OBO Graph object."""
|
|
77
183
|
return cls(
|
|
78
184
|
text=synonym.val,
|
|
79
185
|
predicate=Reference(prefix="oboInOwl", identifier=synonym.pred),
|
|
80
|
-
type=synonym.synonymType
|
|
81
|
-
|
|
186
|
+
type=synonym.synonymType
|
|
187
|
+
and _curie_or_uri_to_ref(synonym.synonymType, converter, strict=strict),
|
|
188
|
+
xrefs=_parse_list(synonym.xrefs, converter, strict=strict),
|
|
189
|
+
)
|
|
190
|
+
|
|
191
|
+
def to_raw(self, converter: Converter) -> Synonym:
|
|
192
|
+
"""Create a raw object."""
|
|
193
|
+
if self.predicate.prefix.lower() != "oboinowl":
|
|
194
|
+
raise ValueError
|
|
195
|
+
return Synonym(
|
|
196
|
+
val=self.text,
|
|
197
|
+
pred=cast(SynonymScopeOIO, self.predicate.identifier),
|
|
198
|
+
synonymType=converter.expand_reference(self.type) if self.type is not None else None,
|
|
199
|
+
xrefs=_expand_list(self.xrefs, converter) or [],
|
|
82
200
|
)
|
|
83
201
|
|
|
84
202
|
|
|
85
|
-
class StandardizedMeta(
|
|
203
|
+
class StandardizedMeta(StandardizedBaseModel[Meta]):
|
|
86
204
|
"""A standardized meta object."""
|
|
87
205
|
|
|
88
206
|
definition: StandardizedDefinition | None
|
|
@@ -95,56 +213,131 @@ class StandardizedMeta(BaseModel):
|
|
|
95
213
|
properties: list[StandardizedProperty] | None = None
|
|
96
214
|
|
|
97
215
|
@classmethod
|
|
98
|
-
def from_obograph_raw(
|
|
216
|
+
def from_obograph_raw( # noqa:C901
|
|
217
|
+
cls, meta: Meta | None, converter: Converter, flag: str = "", strict: bool = False
|
|
218
|
+
) -> Self | None:
|
|
99
219
|
"""Instantiate by standardizing a raw OBO Graph object."""
|
|
100
220
|
if meta is None:
|
|
101
221
|
return None
|
|
222
|
+
|
|
223
|
+
xrefs = []
|
|
224
|
+
for raw_xref in meta.xrefs or []:
|
|
225
|
+
if raw_xref.val:
|
|
226
|
+
try:
|
|
227
|
+
st_xref = StandardizedXref.from_obograph_raw(raw_xref, converter, strict=strict)
|
|
228
|
+
except ValueError:
|
|
229
|
+
if strict:
|
|
230
|
+
raise
|
|
231
|
+
logger.debug("[%s] failed to standardize xref: %s", flag, raw_xref)
|
|
232
|
+
else:
|
|
233
|
+
xrefs.append(st_xref)
|
|
234
|
+
|
|
235
|
+
synonyms = []
|
|
236
|
+
for raw_synonym in meta.synonyms or []:
|
|
237
|
+
if raw_synonym.val:
|
|
238
|
+
try:
|
|
239
|
+
s = StandardizedSynonym.from_obograph_raw(raw_synonym, converter, strict=strict)
|
|
240
|
+
except ValueError:
|
|
241
|
+
if strict:
|
|
242
|
+
raise
|
|
243
|
+
logger.debug("[%s] failed to standardize synonym: %s", flag, raw_synonym)
|
|
244
|
+
else:
|
|
245
|
+
synonyms.append(s)
|
|
246
|
+
|
|
247
|
+
props = []
|
|
248
|
+
for raw_prop in meta.basicPropertyValues or []:
|
|
249
|
+
if raw_prop.val and raw_prop.pred:
|
|
250
|
+
try:
|
|
251
|
+
prop = StandardizedProperty.from_obograph_raw(
|
|
252
|
+
raw_prop, converter, strict=strict
|
|
253
|
+
)
|
|
254
|
+
except ValueError:
|
|
255
|
+
if strict:
|
|
256
|
+
raise
|
|
257
|
+
logger.debug("[%s] failed to standardize property: %s", flag, raw_prop)
|
|
258
|
+
else:
|
|
259
|
+
props.append(prop)
|
|
260
|
+
|
|
102
261
|
return cls(
|
|
103
|
-
definition=StandardizedDefinition.from_obograph_raw(
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
if meta.xrefs
|
|
109
|
-
else None,
|
|
110
|
-
synonyms=[
|
|
111
|
-
StandardizedSynonym.from_obograph_raw(synonym, converter)
|
|
112
|
-
for synonym in meta.synonyms
|
|
262
|
+
definition=StandardizedDefinition.from_obograph_raw(
|
|
263
|
+
meta.definition, converter, strict=strict
|
|
264
|
+
),
|
|
265
|
+
subsets=[
|
|
266
|
+
_curie_or_uri_to_ref(subset, converter, strict=strict) for subset in meta.subsets
|
|
113
267
|
]
|
|
114
|
-
if meta.
|
|
268
|
+
if meta.subsets
|
|
115
269
|
else None,
|
|
270
|
+
xrefs=xrefs or None,
|
|
271
|
+
synonyms=synonyms or None,
|
|
116
272
|
comments=meta.comments,
|
|
117
273
|
version=meta.version,
|
|
118
274
|
deprecated=meta.deprecated,
|
|
119
|
-
properties=
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
275
|
+
properties=props or None,
|
|
276
|
+
)
|
|
277
|
+
|
|
278
|
+
def to_raw(self, converter: Converter) -> Meta:
|
|
279
|
+
"""Create a raw object."""
|
|
280
|
+
return Meta(
|
|
281
|
+
definition=self.definition.to_raw(converter)
|
|
282
|
+
if self.definition and self.definition.value
|
|
283
|
+
else None,
|
|
284
|
+
subsets=_expand_list(self.subsets, converter),
|
|
285
|
+
xrefs=[xref.to_raw(converter) for xref in self.xrefs] if self.xrefs else None,
|
|
286
|
+
synonyms=[s.to_raw(converter) for s in self.synonyms] if self.synonyms else None,
|
|
287
|
+
comments=self.comments,
|
|
288
|
+
version=self.version, # TODO might need some kind of expansion?
|
|
289
|
+
deprecated=self.deprecated,
|
|
290
|
+
basicPropertyValues=[p.to_raw(converter) for p in self.properties]
|
|
291
|
+
if self.properties
|
|
124
292
|
else None,
|
|
125
293
|
)
|
|
126
294
|
|
|
127
295
|
|
|
128
|
-
class StandardizedNode(
|
|
296
|
+
class StandardizedNode(StandardizedBaseModel[Node]):
|
|
129
297
|
"""A standardized node."""
|
|
130
298
|
|
|
131
299
|
reference: Reference
|
|
132
300
|
label: str | None = Field(None)
|
|
133
301
|
meta: StandardizedMeta | None = None
|
|
134
|
-
type: NodeType = Field(
|
|
302
|
+
type: NodeType | None = Field(None, description="Type of node")
|
|
303
|
+
property_type: PropertyType | None = Field(
|
|
304
|
+
None, description="Type of property, if the node type is a property"
|
|
305
|
+
)
|
|
135
306
|
|
|
136
307
|
@classmethod
|
|
137
|
-
def from_obograph_raw(
|
|
308
|
+
def from_obograph_raw(
|
|
309
|
+
cls, node: Node, converter: Converter, *, strict: bool = False
|
|
310
|
+
) -> Self | None:
|
|
138
311
|
"""Instantiate by standardizing a raw OBO Graph object."""
|
|
312
|
+
reference = _curie_or_uri_to_ref(node.id, converter, strict=strict)
|
|
313
|
+
if reference is None:
|
|
314
|
+
if strict:
|
|
315
|
+
raise ValueError(f"failed to parse node's ID: {node.id}")
|
|
316
|
+
logger.warning("failed to parse node's ID %s", node.id)
|
|
317
|
+
return None
|
|
318
|
+
|
|
139
319
|
return cls(
|
|
140
|
-
reference=
|
|
320
|
+
reference=reference,
|
|
141
321
|
label=node.lbl,
|
|
142
|
-
meta=StandardizedMeta.from_obograph_raw(
|
|
322
|
+
meta=StandardizedMeta.from_obograph_raw(
|
|
323
|
+
node.meta, converter, flag=reference.curie, strict=strict
|
|
324
|
+
),
|
|
143
325
|
type=node.type,
|
|
326
|
+
property_type=node.propertyType,
|
|
327
|
+
)
|
|
328
|
+
|
|
329
|
+
def to_raw(self, converter: Converter) -> Node:
|
|
330
|
+
"""Create a raw object."""
|
|
331
|
+
return Node(
|
|
332
|
+
id=converter.expand_reference(self.reference),
|
|
333
|
+
lbl=self.label,
|
|
334
|
+
meta=self.meta.to_raw(converter) if self.meta is not None else None,
|
|
335
|
+
type=self.type,
|
|
336
|
+
propertyType=self.property_type,
|
|
144
337
|
)
|
|
145
338
|
|
|
146
339
|
|
|
147
|
-
class StandardizedEdge(
|
|
340
|
+
class StandardizedEdge(Triple, StandardizedBaseModel[Edge]):
|
|
148
341
|
"""A standardized edge."""
|
|
149
342
|
|
|
150
343
|
subject: Reference
|
|
@@ -153,17 +346,205 @@ class StandardizedEdge(BaseModel):
|
|
|
153
346
|
meta: StandardizedMeta | None = None
|
|
154
347
|
|
|
155
348
|
@classmethod
|
|
156
|
-
def from_obograph_raw(
|
|
349
|
+
def from_obograph_raw(
|
|
350
|
+
cls, edge: Edge, converter: Converter, *, strict: bool = False
|
|
351
|
+
) -> Self | None:
|
|
157
352
|
"""Instantiate by standardizing a raw OBO Graph object."""
|
|
353
|
+
subject = _curie_or_uri_to_ref(edge.sub, converter, strict=strict)
|
|
354
|
+
if not subject:
|
|
355
|
+
if strict:
|
|
356
|
+
raise ValueError
|
|
357
|
+
logger.warning("failed to parse edge's subject %s", edge.sub)
|
|
358
|
+
return None
|
|
359
|
+
predicate = _curie_or_uri_to_ref(edge.pred, converter, strict=strict)
|
|
360
|
+
if not predicate:
|
|
361
|
+
if strict:
|
|
362
|
+
raise ValueError
|
|
363
|
+
logger.warning("failed to parse edge's predicate %s", edge.pred)
|
|
364
|
+
return None
|
|
365
|
+
obj = _curie_or_uri_to_ref(edge.obj, converter, strict=strict)
|
|
366
|
+
if not obj:
|
|
367
|
+
if strict:
|
|
368
|
+
raise ValueError
|
|
369
|
+
logger.warning("failed to parse edge's object %s", edge.obj)
|
|
370
|
+
return None
|
|
158
371
|
return cls(
|
|
159
|
-
subject=
|
|
160
|
-
predicate=
|
|
161
|
-
object=
|
|
162
|
-
meta=StandardizedMeta.from_obograph_raw(
|
|
372
|
+
subject=subject,
|
|
373
|
+
predicate=predicate,
|
|
374
|
+
object=obj,
|
|
375
|
+
meta=StandardizedMeta.from_obograph_raw(
|
|
376
|
+
edge.meta,
|
|
377
|
+
converter,
|
|
378
|
+
flag=f"{subject.curie} {predicate.curie} {obj.curie}",
|
|
379
|
+
strict=strict,
|
|
380
|
+
),
|
|
381
|
+
)
|
|
382
|
+
|
|
383
|
+
def to_raw(self, converter: Converter) -> Edge:
|
|
384
|
+
"""Create a raw object."""
|
|
385
|
+
if self.predicate in REVERSE_BUILTINS:
|
|
386
|
+
predicate = REVERSE_BUILTINS[self.predicate]
|
|
387
|
+
else:
|
|
388
|
+
predicate = converter.expand_reference(self.predicate, strict=True)
|
|
389
|
+
|
|
390
|
+
return Edge(
|
|
391
|
+
sub=converter.expand_reference(self.subject),
|
|
392
|
+
pred=predicate,
|
|
393
|
+
obj=converter.expand_reference(self.object),
|
|
394
|
+
meta=self.meta.to_raw(converter) if self.meta is not None else None,
|
|
163
395
|
)
|
|
164
396
|
|
|
165
397
|
|
|
166
|
-
class
|
|
398
|
+
class StandardizedDomainRangeAxiom(StandardizedBaseModel[DomainRangeAxiom]):
|
|
399
|
+
"""Represents a domain/range axiom."""
|
|
400
|
+
|
|
401
|
+
predicate: Reference
|
|
402
|
+
domains: list[Reference] = Field(default_factory=list)
|
|
403
|
+
ranges: list[Reference] = Field(default_factory=list)
|
|
404
|
+
all_values_from_edges: list[StandardizedEdge] = Field(default_factory=list)
|
|
405
|
+
meta: StandardizedMeta | None = None
|
|
406
|
+
|
|
407
|
+
@classmethod
|
|
408
|
+
def from_obograph_raw(
|
|
409
|
+
cls, obj: DomainRangeAxiom, converter: Converter, *, strict: bool = False
|
|
410
|
+
) -> Self | None:
|
|
411
|
+
"""Parse a raw object."""
|
|
412
|
+
return cls(
|
|
413
|
+
predicate=_curie_or_uri_to_ref(obj.predicateId, converter, strict=strict),
|
|
414
|
+
domains=_parse_list(obj.domainClassIds, converter, strict=strict) or [],
|
|
415
|
+
ranges=_parse_list(obj.rangeClassIds, converter, strict=strict) or [],
|
|
416
|
+
all_values_from_edges=[
|
|
417
|
+
StandardizedEdge.from_obograph_raw(edge, converter, strict=strict)
|
|
418
|
+
for edge in obj.allValuesFromEdges or []
|
|
419
|
+
],
|
|
420
|
+
meta=StandardizedMeta.from_obograph_raw(obj.meta, converter, strict=strict),
|
|
421
|
+
)
|
|
422
|
+
|
|
423
|
+
def to_raw(self, converter: Converter) -> DomainRangeAxiom:
|
|
424
|
+
"""Create a raw object."""
|
|
425
|
+
return DomainRangeAxiom(
|
|
426
|
+
predicateId=converter.expand_reference(self.predicate),
|
|
427
|
+
domainClassIds=_expand_list(self.domains, converter),
|
|
428
|
+
rangeClassIds=_expand_list(self.ranges, converter),
|
|
429
|
+
allValuesFromEdges=[edge.to_raw(converter) for edge in self.all_values_from_edges]
|
|
430
|
+
if self.all_values_from_edges
|
|
431
|
+
else None,
|
|
432
|
+
meta=self.meta.to_raw(converter) if self.meta is not None else None,
|
|
433
|
+
)
|
|
434
|
+
|
|
435
|
+
|
|
436
|
+
class StandardizedPropertyChainAxiom(StandardizedBaseModel[PropertyChainAxiom]):
|
|
437
|
+
"""Represents a property chain axiom."""
|
|
438
|
+
|
|
439
|
+
predicate: Reference
|
|
440
|
+
chain: list[Reference] = Field(default_factory=list)
|
|
441
|
+
meta: StandardizedMeta | None = None
|
|
442
|
+
|
|
443
|
+
@classmethod
|
|
444
|
+
def from_obograph_raw(
|
|
445
|
+
cls, obj: PropertyChainAxiom, converter: Converter, *, strict: bool = False
|
|
446
|
+
) -> Self | None:
|
|
447
|
+
"""Parse a raw object."""
|
|
448
|
+
return cls(
|
|
449
|
+
predicate=_curie_or_uri_to_ref(obj.predicateId, converter, strict=strict),
|
|
450
|
+
chain=_parse_list(obj.chainPredicateIds, converter, strict=strict),
|
|
451
|
+
meta=StandardizedMeta.from_obograph_raw(obj.meta, converter, strict=strict),
|
|
452
|
+
)
|
|
453
|
+
|
|
454
|
+
def to_raw(self, converter: Converter) -> PropertyChainAxiom:
|
|
455
|
+
"""Create a raw object."""
|
|
456
|
+
return PropertyChainAxiom(
|
|
457
|
+
predicateId=converter.expand_reference(self.predicate),
|
|
458
|
+
chainPredicateIds=_expand_list(self.chain, converter),
|
|
459
|
+
meta=self.meta.to_raw(converter) if self.meta is not None else None,
|
|
460
|
+
)
|
|
461
|
+
|
|
462
|
+
|
|
463
|
+
class StandardizedEquivalentNodeSet(StandardizedBaseModel[EquivalentNodeSet]):
|
|
464
|
+
"""Represents an equivalence set."""
|
|
465
|
+
|
|
466
|
+
node: Reference
|
|
467
|
+
equivalents: list[Reference] = Field(default_factory=list)
|
|
468
|
+
meta: StandardizedMeta | None = None
|
|
469
|
+
|
|
470
|
+
@classmethod
|
|
471
|
+
def from_obograph_raw(
|
|
472
|
+
cls, obj: EquivalentNodeSet, converter: Converter, *, strict: bool = False
|
|
473
|
+
) -> Self | None:
|
|
474
|
+
"""Parse a raw object."""
|
|
475
|
+
return cls(
|
|
476
|
+
node=_curie_or_uri_to_ref(obj.representativeNodeId, converter, strict=strict),
|
|
477
|
+
equivalents=_parse_list(obj.nodeIds, converter, strict=strict),
|
|
478
|
+
meta=StandardizedMeta.from_obograph_raw(obj.meta, converter, strict=strict),
|
|
479
|
+
)
|
|
480
|
+
|
|
481
|
+
def to_raw(self, converter: Converter) -> EquivalentNodeSet:
|
|
482
|
+
"""Create a raw object."""
|
|
483
|
+
return EquivalentNodeSet(
|
|
484
|
+
representativeNodeId=converter.expand_reference(self.node),
|
|
485
|
+
nodeIds=_expand_list(self.equivalents, converter),
|
|
486
|
+
meta=self.meta.to_raw(converter) if self.meta is not None else None,
|
|
487
|
+
)
|
|
488
|
+
|
|
489
|
+
|
|
490
|
+
class StandardizedExistentialRestriction(StandardizedBaseModel[ExistentialRestrictionExpression]):
|
|
491
|
+
"""Represents an existential restriction expression."""
|
|
492
|
+
|
|
493
|
+
predicate: Reference
|
|
494
|
+
target: Reference
|
|
495
|
+
|
|
496
|
+
@classmethod
|
|
497
|
+
def from_obograph_raw(
|
|
498
|
+
cls, obj: ExistentialRestrictionExpression, converter: Converter, *, strict: bool = False
|
|
499
|
+
) -> Self | None:
|
|
500
|
+
"""Parse a raw object."""
|
|
501
|
+
return cls(
|
|
502
|
+
predicate=_curie_or_uri_to_ref(obj.propertyId, converter, strict=strict),
|
|
503
|
+
target=_curie_or_uri_to_ref(obj.fillerId, converter, strict=strict),
|
|
504
|
+
)
|
|
505
|
+
|
|
506
|
+
def to_raw(self, converter: Converter) -> ExistentialRestrictionExpression:
|
|
507
|
+
"""Create a raw object."""
|
|
508
|
+
return ExistentialRestrictionExpression(
|
|
509
|
+
propertyId=converter.expand_reference(self.predicate),
|
|
510
|
+
fillerId=converter.expand_reference(self.target),
|
|
511
|
+
)
|
|
512
|
+
|
|
513
|
+
|
|
514
|
+
class StandardizedLogicalDefinition(StandardizedBaseModel[LogicalDefinition]):
|
|
515
|
+
"""Represents a logical definition axiom."""
|
|
516
|
+
|
|
517
|
+
node: Reference
|
|
518
|
+
geni: list[Reference] = Field(default_factory=list)
|
|
519
|
+
restrictions: list[StandardizedExistentialRestriction] = Field(default_factory=list)
|
|
520
|
+
meta: StandardizedMeta | None = None
|
|
521
|
+
|
|
522
|
+
@classmethod
|
|
523
|
+
def from_obograph_raw(
|
|
524
|
+
cls, obj: LogicalDefinition, converter: Converter, *, strict: bool = False
|
|
525
|
+
) -> Self | None:
|
|
526
|
+
"""Parse a raw object."""
|
|
527
|
+
return cls(
|
|
528
|
+
node=_curie_or_uri_to_ref(obj.definedClassId, converter, strict=strict),
|
|
529
|
+
geni=_parse_list(obj.genusIds, converter, strict=strict),
|
|
530
|
+
restrictions=[
|
|
531
|
+
StandardizedExistentialRestriction.from_obograph_raw(r, converter, strict=strict)
|
|
532
|
+
for r in obj.restrictions or []
|
|
533
|
+
],
|
|
534
|
+
meta=StandardizedMeta.from_obograph_raw(obj.meta, converter, strict=strict),
|
|
535
|
+
)
|
|
536
|
+
|
|
537
|
+
def to_raw(self, converter: Converter) -> LogicalDefinition:
|
|
538
|
+
"""Create a raw object."""
|
|
539
|
+
return LogicalDefinition(
|
|
540
|
+
definedClassId=converter.expand_reference(self.node),
|
|
541
|
+
genusIds=_expand_list(self.geni, converter),
|
|
542
|
+
restrictions=[r.to_raw(converter) for r in self.restrictions],
|
|
543
|
+
meta=self.meta.to_raw(converter) if self.meta is not None else None,
|
|
544
|
+
)
|
|
545
|
+
|
|
546
|
+
|
|
547
|
+
class StandardizedGraph(StandardizedBaseModel[Graph]):
|
|
167
548
|
"""A standardized graph."""
|
|
168
549
|
|
|
169
550
|
id: str | None = None
|
|
@@ -171,40 +552,148 @@ class StandardizedGraph(BaseModel):
|
|
|
171
552
|
nodes: list[StandardizedNode] = Field(default_factory=list)
|
|
172
553
|
edges: list[StandardizedEdge] = Field(default_factory=list)
|
|
173
554
|
|
|
174
|
-
|
|
555
|
+
equivalent_node_sets: list[StandardizedEquivalentNodeSet] = Field(default_factory=list)
|
|
556
|
+
logical_definition_axioms: list[StandardizedLogicalDefinition] = Field(default_factory=list)
|
|
557
|
+
domain_range_axioms: list[StandardizedDomainRangeAxiom] = Field(default_factory=list)
|
|
558
|
+
property_chain_axioms: list[StandardizedPropertyChainAxiom] = Field(default_factory=list)
|
|
175
559
|
|
|
176
560
|
@classmethod
|
|
177
|
-
def from_obograph_raw(cls, graph: Graph, converter: Converter) -> Self:
|
|
561
|
+
def from_obograph_raw(cls, graph: Graph, converter: Converter, *, strict: bool = False) -> Self:
|
|
178
562
|
"""Instantiate by standardizing a raw OBO Graph object."""
|
|
179
563
|
return cls(
|
|
180
564
|
id=graph.id,
|
|
181
|
-
meta=StandardizedMeta.from_obograph_raw(
|
|
182
|
-
|
|
183
|
-
|
|
565
|
+
meta=StandardizedMeta.from_obograph_raw(
|
|
566
|
+
graph.meta, converter, flag=graph.id or "", strict=strict
|
|
567
|
+
),
|
|
568
|
+
nodes=[
|
|
569
|
+
s_node
|
|
570
|
+
for node in graph.nodes
|
|
571
|
+
if (s_node := StandardizedNode.from_obograph_raw(node, converter, strict=strict))
|
|
572
|
+
],
|
|
573
|
+
edges=[
|
|
574
|
+
s_edge
|
|
575
|
+
for edge in graph.edges
|
|
576
|
+
if (s_edge := StandardizedEdge.from_obograph_raw(edge, converter, strict=strict))
|
|
577
|
+
],
|
|
578
|
+
equivalent_node_sets=[
|
|
579
|
+
StandardizedEquivalentNodeSet.from_obograph_raw(e, converter, strict=strict)
|
|
580
|
+
for e in graph.equivalentNodesSets or []
|
|
581
|
+
],
|
|
582
|
+
logical_definition_axioms=[
|
|
583
|
+
StandardizedLogicalDefinition.from_obograph_raw(e, converter, strict=strict)
|
|
584
|
+
for e in graph.logicalDefinitionAxioms or []
|
|
585
|
+
],
|
|
586
|
+
property_chain_axioms=[
|
|
587
|
+
StandardizedPropertyChainAxiom.from_obograph_raw(e, converter, strict=strict)
|
|
588
|
+
for e in graph.propertyChainAxioms or []
|
|
589
|
+
],
|
|
590
|
+
domain_range_axioms=[
|
|
591
|
+
StandardizedDomainRangeAxiom.from_obograph_raw(e, converter, strict=strict)
|
|
592
|
+
for e in graph.domainRangeAxioms or []
|
|
593
|
+
],
|
|
594
|
+
)
|
|
595
|
+
|
|
596
|
+
def to_raw(self, converter: Converter) -> Graph:
|
|
597
|
+
"""Create a raw object."""
|
|
598
|
+
return Graph(
|
|
599
|
+
id=self.id,
|
|
600
|
+
meta=self.meta.to_raw(converter) if self.meta is not None else None,
|
|
601
|
+
nodes=[node.to_raw(converter) for node in self.nodes],
|
|
602
|
+
edges=[edge.to_raw(converter) for edge in self.edges],
|
|
603
|
+
logicalDefinitionAxioms=[
|
|
604
|
+
axiom.to_raw(converter) for axiom in self.logical_definition_axioms
|
|
605
|
+
],
|
|
606
|
+
propertyChainAxioms=[axiom.to_raw(converter) for axiom in self.property_chain_axioms],
|
|
607
|
+
domainRangeAxioms=[axiom.to_raw(converter) for axiom in self.domain_range_axioms],
|
|
608
|
+
equivalentNodesSets=[axiom.to_raw(converter) for axiom in self.equivalent_node_sets],
|
|
609
|
+
)
|
|
610
|
+
|
|
611
|
+
def _get_property(self, predicate: Reference) -> str | Reference | None:
|
|
612
|
+
if self.meta is None:
|
|
613
|
+
return None
|
|
614
|
+
|
|
615
|
+
for p in self.meta.properties or []:
|
|
616
|
+
if p.predicate == predicate:
|
|
617
|
+
return p.value
|
|
618
|
+
|
|
619
|
+
return None
|
|
620
|
+
|
|
621
|
+
@property
|
|
622
|
+
def name(self) -> str | None:
|
|
623
|
+
"""Look up the name of the graph."""
|
|
624
|
+
r = self._get_property(Reference(prefix="dcterms", identifier="title"))
|
|
625
|
+
if isinstance(r, Reference):
|
|
626
|
+
raise TypeError
|
|
627
|
+
return r
|
|
628
|
+
|
|
629
|
+
|
|
630
|
+
class StandardizedGraphDocument(StandardizedBaseModel[GraphDocument]):
|
|
631
|
+
"""A standardized graph document."""
|
|
632
|
+
|
|
633
|
+
graphs: list[StandardizedGraph]
|
|
634
|
+
meta: StandardizedMeta | None = None
|
|
635
|
+
|
|
636
|
+
@classmethod
|
|
637
|
+
def from_obograph_raw(
|
|
638
|
+
cls, graph_document: GraphDocument, converter: Converter, *, strict: bool = False
|
|
639
|
+
) -> Self:
|
|
640
|
+
"""Instantiate by standardizing a raw OBO Graph Document object."""
|
|
641
|
+
return cls(
|
|
642
|
+
graphs=[
|
|
643
|
+
StandardizedGraph.from_obograph_raw(graph, converter, strict=strict)
|
|
644
|
+
for graph in graph_document.graphs
|
|
645
|
+
],
|
|
646
|
+
meta=StandardizedMeta.from_obograph_raw(graph_document.meta, converter, strict=strict),
|
|
647
|
+
)
|
|
648
|
+
|
|
649
|
+
def to_raw(self, converter: Converter) -> GraphDocument:
|
|
650
|
+
"""Create a raw object."""
|
|
651
|
+
return GraphDocument(
|
|
652
|
+
graphs=[graph.to_raw(converter) for graph in self.graphs],
|
|
653
|
+
meta=self.meta.to_raw(converter) if self.meta is not None else None,
|
|
184
654
|
)
|
|
185
655
|
|
|
186
656
|
|
|
187
|
-
def _parse_list(
|
|
188
|
-
|
|
657
|
+
def _parse_list(
|
|
658
|
+
curie_or_uris: list[str] | None, converter: Converter, *, strict: bool
|
|
659
|
+
) -> list[Reference] | None:
|
|
660
|
+
if not curie_or_uris:
|
|
189
661
|
return None
|
|
190
|
-
return [
|
|
662
|
+
return [
|
|
663
|
+
reference
|
|
664
|
+
for curie_or_uri in curie_or_uris
|
|
665
|
+
if (reference := _curie_or_uri_to_ref(curie_or_uri, converter, strict=strict))
|
|
666
|
+
]
|
|
191
667
|
|
|
192
668
|
|
|
193
669
|
#: defined in https://github.com/geneontology/obographs/blob/6676b10a5cce04707d75b9dd46fa08de70322b0b/obographs-owlapi/src/main/java/org/geneontology/obographs/owlapi/FromOwl.java#L36-L39
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
"
|
|
197
|
-
"
|
|
670
|
+
#: this list is complete.
|
|
671
|
+
BUILTINS: dict[str, Reference] = {
|
|
672
|
+
"is_a": vocabulary.is_a,
|
|
673
|
+
"subPropertyOf": vocabulary.subproperty_of,
|
|
674
|
+
"type": vocabulary.rdf_type,
|
|
198
675
|
"inverseOf": Reference(prefix="owl", identifier="inverseOf"),
|
|
199
676
|
}
|
|
200
677
|
|
|
678
|
+
"""maybe add these later?
|
|
679
|
+
# predicates, see https://github.com/geneontology/obographs/blob/6676b10a5cce04707d75b9dd46fa08de70322b0b/obographs-core/src/test/java/org/geneontology/obographs/core/model/axiom/PropertyChainAxiomTest.java#L12-L14
|
|
680
|
+
# "part_of": vocabulary.part_of,
|
|
681
|
+
# "has_part": vocabulary.has_part,
|
|
682
|
+
# "overlaps": Reference(prefix="RO", identifier="0002131"),
|
|
683
|
+
"""
|
|
201
684
|
|
|
202
|
-
|
|
685
|
+
REVERSE_BUILTINS: dict[Reference, str] = {v: k for k, v in BUILTINS.items()}
|
|
686
|
+
|
|
687
|
+
|
|
688
|
+
def _curie_or_uri_to_ref(s: str, converter: Converter, *, strict: bool) -> Reference | None:
|
|
203
689
|
if s in BUILTINS:
|
|
204
690
|
return BUILTINS[s]
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
691
|
+
try:
|
|
692
|
+
reference_tuple = converter.parse(s, strict=False)
|
|
693
|
+
except curies.preprocessing.BlocklistError:
|
|
694
|
+
return None
|
|
695
|
+
if reference_tuple is not None:
|
|
696
|
+
return reference_tuple.to_pydantic()
|
|
697
|
+
if strict:
|
|
698
|
+
raise ValueError(f"could not parse {s}")
|
|
699
|
+
return None
|
obographs/version.py
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: obographs
|
|
3
|
-
Version: 0.0.
|
|
3
|
+
Version: 0.0.4
|
|
4
4
|
Summary: A python data model for OBO Graphs
|
|
5
5
|
Keywords: snekpack,cookiecutter
|
|
6
6
|
Author: Charles Tapley Hoyt
|
|
@@ -23,15 +23,8 @@ Classifier: Programming Language :: Python :: 3.13
|
|
|
23
23
|
Classifier: Programming Language :: Python :: 3 :: Only
|
|
24
24
|
Classifier: Typing :: Typed
|
|
25
25
|
Requires-Dist: pydantic
|
|
26
|
-
Requires-Dist: curies
|
|
26
|
+
Requires-Dist: curies>=0.10.19
|
|
27
27
|
Requires-Dist: typing-extensions
|
|
28
|
-
Requires-Dist: sphinx>=8 ; extra == 'docs'
|
|
29
|
-
Requires-Dist: sphinx-rtd-theme>=3.0 ; extra == 'docs'
|
|
30
|
-
Requires-Dist: sphinx-automodapi ; extra == 'docs'
|
|
31
|
-
Requires-Dist: autodoc-pydantic ; extra == 'docs'
|
|
32
|
-
Requires-Dist: requests ; extra == 'network'
|
|
33
|
-
Requires-Dist: pytest ; extra == 'tests'
|
|
34
|
-
Requires-Dist: coverage[toml] ; extra == 'tests'
|
|
35
28
|
Maintainer: Charles Tapley Hoyt
|
|
36
29
|
Maintainer-email: Charles Tapley Hoyt <cthoyt@gmail.com>
|
|
37
30
|
Requires-Python: >=3.10
|
|
@@ -40,9 +33,6 @@ Project-URL: Documentation, https://obographs.readthedocs.io
|
|
|
40
33
|
Project-URL: Funding, https://github.com/sponsors/cthoyt
|
|
41
34
|
Project-URL: Homepage, https://github.com/cthoyt/obographs
|
|
42
35
|
Project-URL: Repository, https://github.com/cthoyt/obographs.git
|
|
43
|
-
Provides-Extra: docs
|
|
44
|
-
Provides-Extra: network
|
|
45
|
-
Provides-Extra: tests
|
|
46
36
|
Description-Content-Type: text/markdown
|
|
47
37
|
|
|
48
38
|
<!--
|
|
@@ -97,7 +87,7 @@ graph_raw = obographs.read(url)
|
|
|
97
87
|
The OBO Graph JSON schema uses non-Pythonic names, and it's inherently not aware
|
|
98
88
|
of semantics - it uses a combination of URIs and ad-hoc symbols as identifiers.
|
|
99
89
|
`obographs` implements a standardization workflow that creates new data
|
|
100
|
-
structures with parsed/normalized URIs and symbols that has Pythonic
|
|
90
|
+
structures with parsed/normalized URIs and symbols that has Pythonic names. Use
|
|
101
91
|
it like:
|
|
102
92
|
|
|
103
93
|
```python
|
|
@@ -129,18 +119,15 @@ $ python3 -m pip install obographs
|
|
|
129
119
|
The most recent code and data can be installed directly from GitHub with uv:
|
|
130
120
|
|
|
131
121
|
```console
|
|
132
|
-
$ uv
|
|
122
|
+
$ uv pip install git+https://github.com/cthoyt/obographs.git
|
|
133
123
|
```
|
|
134
124
|
|
|
135
125
|
or with pip:
|
|
136
126
|
|
|
137
127
|
```console
|
|
138
|
-
$
|
|
128
|
+
$ python3 -m pip install git+https://github.com/cthoyt/obographs.git
|
|
139
129
|
```
|
|
140
130
|
|
|
141
|
-
Note that this requires setting `UV_PREVIEW` mode enabled until the uv build
|
|
142
|
-
backend becomes a stable feature.
|
|
143
|
-
|
|
144
131
|
## 👐 Contributing
|
|
145
132
|
|
|
146
133
|
Contributions, whether filing an issue, making a pull request, or forking, are
|
|
@@ -203,18 +190,15 @@ To install in development mode, use the following:
|
|
|
203
190
|
```console
|
|
204
191
|
$ git clone git+https://github.com/cthoyt/obographs.git
|
|
205
192
|
$ cd obographs
|
|
206
|
-
$ uv
|
|
193
|
+
$ uv pip install -e .
|
|
207
194
|
```
|
|
208
195
|
|
|
209
196
|
Alternatively, install using pip:
|
|
210
197
|
|
|
211
198
|
```console
|
|
212
|
-
$
|
|
199
|
+
$ python3 -m pip install -e .
|
|
213
200
|
```
|
|
214
201
|
|
|
215
|
-
Note that this requires setting `UV_PREVIEW` mode enabled until the uv build
|
|
216
|
-
backend becomes a stable feature.
|
|
217
|
-
|
|
218
202
|
### Updating Package Boilerplate
|
|
219
203
|
|
|
220
204
|
This project uses `cruft` to keep boilerplate (i.e., configuration, contribution
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
obographs/__init__.py,sha256=55f4bf18441bd7f6c41afa68d094532933b02b21dbdd20679cf8807c1791d494,1601
|
|
2
|
+
obographs/model.py,sha256=1f1bda132b83d8e08d7301eddb9be8d58b7e61c5b30e9baab9c24fd22348db53,8457
|
|
3
|
+
obographs/py.typed,sha256=01ba4719c80b6fe911b091a7c05124b64eeece964e09c058ef8f9805daca546b,1
|
|
4
|
+
obographs/standardized.py,sha256=69d26bbd35b49232b8d4bc2ae462f864f4fffcadf3acb7d541783fc8745dbd5e,25791
|
|
5
|
+
obographs/version.py,sha256=c50bb52fc81eb5b19dedfb8583a0c19b6127aff659301cb2d3d51f4d244fefc3,961
|
|
6
|
+
obographs-0.0.4.dist-info/licenses/LICENSE,sha256=4be0ec343e3bf11fd54321a6b576d5616ebb7d18898f741f63c517209e33bcb2,1076
|
|
7
|
+
obographs-0.0.4.dist-info/WHEEL,sha256=65f6765ba93534713730ff2172cd912ef280aa42867625a73f77c2fef0639dae,78
|
|
8
|
+
obographs-0.0.4.dist-info/entry_points.txt,sha256=9a9819cedd2186e28d5d42ddce5e3de1417b0db2b07392ff35f9adc7c86a8619,50
|
|
9
|
+
obographs-0.0.4.dist-info/METADATA,sha256=ac4daf3fa7f23379788e758debc91663ee15663ee1c9fabbf79bc69ca79c5e5b,12768
|
|
10
|
+
obographs-0.0.4.dist-info/RECORD,,
|
obographs-0.0.2.dist-info/RECORD
DELETED
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
obographs/version.py,sha256=04839f3ad0ad481ebb750f5228278ee8a55b26c17bd61c0a3f2ccc6da50204ae,961
|
|
2
|
-
obographs/__init__.py,sha256=93807a9cc6f4002ac923a84a8c5e1a9b6301c5368cd61a957c9115adfaef1a56,254
|
|
3
|
-
obographs/model.py,sha256=3387390f1a30fe47b22c7c346dfdf2b6a595ccbc7cd8d7d09debf4a13f8f6e6c,6846
|
|
4
|
-
obographs/py.typed,sha256=01ba4719c80b6fe911b091a7c05124b64eeece964e09c058ef8f9805daca546b,1
|
|
5
|
-
obographs/standardized.py,sha256=15a58dcb9af39a01565fdb096389caf2702f94052e933f9368d93caf620022f5,7099
|
|
6
|
-
obographs-0.0.2.dist-info/licenses/LICENSE,sha256=4be0ec343e3bf11fd54321a6b576d5616ebb7d18898f741f63c517209e33bcb2,1076
|
|
7
|
-
obographs-0.0.2.dist-info/WHEEL,sha256=e3765529bb0cc791d07188d72ec6a759d7625ff6d3a5e4b710d25409bae03770,79
|
|
8
|
-
obographs-0.0.2.dist-info/entry_points.txt,sha256=9a9819cedd2186e28d5d42ddce5e3de1417b0db2b07392ff35f9adc7c86a8619,50
|
|
9
|
-
obographs-0.0.2.dist-info/METADATA,sha256=3e577f9dcce8afd6b2b0694935c320b898e5253ba6f0dcf8520b4d1a996ef3a3,13429
|
|
10
|
-
obographs-0.0.2.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|