pyobo 0.12.14__py3-none-any.whl → 0.12.16__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/api/xrefs.py +5 -1
- pyobo/cli/cli.py +2 -0
- pyobo/cli/lookup.py +44 -23
- pyobo/cli/obo_lexical_review.py +207 -0
- pyobo/getters.py +5 -4
- pyobo/sources/ror.py +8 -203
- pyobo/struct/functional/ontology.py +2 -2
- pyobo/struct/obograph/export.py +2 -2
- pyobo/struct/struct.py +6 -6
- pyobo/utils/path.py +0 -1
- pyobo/version.py +1 -1
- {pyobo-0.12.14.dist-info → pyobo-0.12.16.dist-info}/METADATA +10 -7
- {pyobo-0.12.14.dist-info → pyobo-0.12.16.dist-info}/RECORD +16 -15
- {pyobo-0.12.14.dist-info → pyobo-0.12.16.dist-info}/WHEEL +2 -2
- {pyobo-0.12.14.dist-info → pyobo-0.12.16.dist-info}/entry_points.txt +0 -0
- {pyobo-0.12.14.dist-info → pyobo-0.12.16.dist-info}/licenses/LICENSE +0 -0
pyobo/api/xrefs.py
CHANGED
|
@@ -124,7 +124,11 @@ def get_semantic_mappings(
|
|
|
124
124
|
)
|
|
125
125
|
if converter is None:
|
|
126
126
|
converter = get_converter()
|
|
127
|
-
return [
|
|
127
|
+
return [
|
|
128
|
+
# TODO upstream this into sssom-pydantic?
|
|
129
|
+
row_to_semantic_mapping({k: v for k, v in row.items() if pd.notna(v)}, converter=converter)
|
|
130
|
+
for _, row in df.iterrows()
|
|
131
|
+
]
|
|
128
132
|
|
|
129
133
|
|
|
130
134
|
def get_mappings_df(
|
pyobo/cli/cli.py
CHANGED
|
@@ -10,6 +10,7 @@ import click
|
|
|
10
10
|
|
|
11
11
|
from .database import main as database_main
|
|
12
12
|
from .lookup import lookup
|
|
13
|
+
from .obo_lexical_review import obo_lexical_review
|
|
13
14
|
from ..constants import GLOBAL_SKIP, RAW_DIRECTORY
|
|
14
15
|
from ..plugins import has_nomenclature_plugin
|
|
15
16
|
|
|
@@ -101,6 +102,7 @@ def _no_download() -> set[str]:
|
|
|
101
102
|
|
|
102
103
|
main.add_command(lookup)
|
|
103
104
|
main.add_command(database_main)
|
|
105
|
+
main.add_command(obo_lexical_review)
|
|
104
106
|
|
|
105
107
|
if __name__ == "__main__":
|
|
106
108
|
main()
|
pyobo/cli/lookup.py
CHANGED
|
@@ -1,8 +1,12 @@
|
|
|
1
1
|
"""CLI for PyOBO lookups."""
|
|
2
2
|
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import inspect
|
|
3
6
|
import json
|
|
4
7
|
import sys
|
|
5
|
-
from collections.abc import Mapping
|
|
8
|
+
from collections.abc import Iterable, Mapping
|
|
9
|
+
from typing import TYPE_CHECKING
|
|
6
10
|
|
|
7
11
|
import click
|
|
8
12
|
from more_click import verbose_option
|
|
@@ -17,7 +21,10 @@ from .utils import (
|
|
|
17
21
|
strict_option,
|
|
18
22
|
version_option,
|
|
19
23
|
)
|
|
20
|
-
from ..constants import LookupKwargs
|
|
24
|
+
from ..constants import GetOntologyKwargs, LookupKwargs
|
|
25
|
+
|
|
26
|
+
if TYPE_CHECKING:
|
|
27
|
+
from curies import Reference
|
|
21
28
|
|
|
22
29
|
__all__ = [
|
|
23
30
|
"lookup",
|
|
@@ -31,9 +38,12 @@ def lookup():
|
|
|
31
38
|
|
|
32
39
|
def lookup_annotate(f: Clickable) -> Clickable:
|
|
33
40
|
"""Add appropriate decorators to lookup CLI functions."""
|
|
41
|
+
signature = inspect.signature(f)
|
|
42
|
+
param = signature.parameters["kwargs"]
|
|
43
|
+
if param.kind is not inspect.Parameter.VAR_KEYWORD:
|
|
44
|
+
raise ValueError("programmer error")
|
|
34
45
|
for decorator in [
|
|
35
46
|
lookup.command(),
|
|
36
|
-
prefix_argument,
|
|
37
47
|
verbose_option,
|
|
38
48
|
force_option,
|
|
39
49
|
force_process_option,
|
|
@@ -41,6 +51,15 @@ def lookup_annotate(f: Clickable) -> Clickable:
|
|
|
41
51
|
version_option,
|
|
42
52
|
]:
|
|
43
53
|
f = decorator(f)
|
|
54
|
+
|
|
55
|
+
if param.annotation is None:
|
|
56
|
+
pass
|
|
57
|
+
if param.annotation in {"Unpack[LookupKwargs]", Unpack[LookupKwargs]}:
|
|
58
|
+
f = prefix_argument(f)
|
|
59
|
+
elif param.annotation in {"Unpack[GetOntologyKwargs]", Unpack[GetOntologyKwargs]}:
|
|
60
|
+
pass
|
|
61
|
+
else:
|
|
62
|
+
raise ValueError(f"unknown parameter type for {f}: {param.annotation}")
|
|
44
63
|
return f
|
|
45
64
|
|
|
46
65
|
|
|
@@ -249,33 +268,35 @@ def hierarchy(
|
|
|
249
268
|
|
|
250
269
|
|
|
251
270
|
@lookup_annotate
|
|
252
|
-
@click.argument("
|
|
253
|
-
def ancestors(
|
|
254
|
-
identifier: str,
|
|
255
|
-
**kwargs: Unpack[LookupKwargs],
|
|
256
|
-
) -> None:
|
|
271
|
+
@click.argument("curie")
|
|
272
|
+
def ancestors(curie: str, **kwargs: Unpack[GetOntologyKwargs]) -> None:
|
|
257
273
|
"""Look up ancestors."""
|
|
258
|
-
from ..api import get_ancestors
|
|
274
|
+
from ..api import get_ancestors
|
|
259
275
|
|
|
260
|
-
|
|
261
|
-
ancestors
|
|
262
|
-
for ancestor in sorted(ancestors or []):
|
|
263
|
-
click.echo(f"{ancestor.curie}\t{get_name(ancestor, version=kwargs['version'])}")
|
|
276
|
+
ancestors = get_ancestors(curie, **kwargs)
|
|
277
|
+
_list_curies(ancestors, **kwargs)
|
|
264
278
|
|
|
265
279
|
|
|
266
280
|
@lookup_annotate
|
|
267
|
-
@click.argument("
|
|
268
|
-
def descendants(
|
|
269
|
-
identifier: str,
|
|
270
|
-
**kwargs: Unpack[LookupKwargs],
|
|
271
|
-
) -> None:
|
|
281
|
+
@click.argument("curie")
|
|
282
|
+
def descendants(curie: str, **kwargs: Unpack[GetOntologyKwargs]) -> None:
|
|
272
283
|
"""Look up descendants."""
|
|
273
|
-
from ..api import get_descendants
|
|
284
|
+
from ..api import get_descendants
|
|
285
|
+
|
|
286
|
+
descendants = get_descendants(curie, **kwargs)
|
|
287
|
+
_list_curies(descendants, **kwargs)
|
|
288
|
+
|
|
289
|
+
|
|
290
|
+
def _list_curies(
|
|
291
|
+
references: Iterable[Reference] | None, **kwargs: Unpack[GetOntologyKwargs]
|
|
292
|
+
) -> None:
|
|
293
|
+
if not references:
|
|
294
|
+
return
|
|
295
|
+
|
|
296
|
+
from ..api import get_name
|
|
274
297
|
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
for descendant in sorted(descendants or []):
|
|
278
|
-
click.echo(f"{descendant.curie}\t{get_name(descendant, version=kwargs['version'])}")
|
|
298
|
+
for reference in sorted(references or []):
|
|
299
|
+
click.echo(f"{reference.curie}\t{get_name(reference, version=kwargs['version'])}")
|
|
279
300
|
|
|
280
301
|
|
|
281
302
|
@lookup_annotate
|
|
@@ -0,0 +1,207 @@
|
|
|
1
|
+
# /// script
|
|
2
|
+
# requires-python = ">=3.11"
|
|
3
|
+
# dependencies = [
|
|
4
|
+
# "click>=8.3.1",
|
|
5
|
+
# "obographs>=0.0.8",
|
|
6
|
+
# "pyperclip>=1.11.0",
|
|
7
|
+
# "robot-obo-tool>=0.0.1",
|
|
8
|
+
# "ssslm[gilda-slim]>=0.1.3",
|
|
9
|
+
# "tabulate>=0.9.0",
|
|
10
|
+
# "tqdm>=4.67.3",
|
|
11
|
+
# ]
|
|
12
|
+
# ///
|
|
13
|
+
|
|
14
|
+
"""Implement lexical review for an ontology."""
|
|
15
|
+
|
|
16
|
+
from __future__ import annotations
|
|
17
|
+
|
|
18
|
+
from typing import TYPE_CHECKING
|
|
19
|
+
|
|
20
|
+
import click
|
|
21
|
+
|
|
22
|
+
if TYPE_CHECKING:
|
|
23
|
+
import obographs
|
|
24
|
+
import ssslm
|
|
25
|
+
|
|
26
|
+
INDEX_URL = "https://github.com/biopragmatics/biolexica/raw/main/lexica/obo/obo.ssslm.tsv.gz"
|
|
27
|
+
UPPER = {"ncit"}
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
@click.command()
|
|
31
|
+
@click.argument("prefix")
|
|
32
|
+
@click.option(
|
|
33
|
+
"--location",
|
|
34
|
+
help="Local path or URL to an OBO Graph JSON file or OWL file. If not given, will try and look up through the OBO PURL system",
|
|
35
|
+
)
|
|
36
|
+
@click.option(
|
|
37
|
+
"--uri-prefix",
|
|
38
|
+
help="Local path to an OBO Graph JSON file. If not given, will try and look up through the OBO PURL system",
|
|
39
|
+
)
|
|
40
|
+
@click.option("--index-url", default=INDEX_URL, show_default=True)
|
|
41
|
+
@click.option("--show-passed", is_flag=True)
|
|
42
|
+
@click.option("--skip-upper", is_flag=True, help=f"if true, skip upper level ontologies {UPPER}")
|
|
43
|
+
@click.option("--index-force", is_flag=True, help="if true, force re-downloading the lexical index")
|
|
44
|
+
def obo_lexical_review(
|
|
45
|
+
prefix: str,
|
|
46
|
+
location: str | None,
|
|
47
|
+
uri_prefix: str | None,
|
|
48
|
+
index_url: str,
|
|
49
|
+
show_passed: bool,
|
|
50
|
+
skip_upper: bool,
|
|
51
|
+
index_force: bool,
|
|
52
|
+
) -> None:
|
|
53
|
+
"""Make a lexical review of an ontology."""
|
|
54
|
+
import sys
|
|
55
|
+
import time
|
|
56
|
+
|
|
57
|
+
import pyperclip
|
|
58
|
+
import pystow
|
|
59
|
+
import ssslm
|
|
60
|
+
from tabulate import tabulate
|
|
61
|
+
|
|
62
|
+
module = pystow.module("pyobo", "obo-lexical-review")
|
|
63
|
+
|
|
64
|
+
args = " ".join(sys.argv[1:])
|
|
65
|
+
output = f"Analysis of {prefix} run on {time.asctime()} with the following command:\n\n```console\n$ uvx pyobo obo-lexical-review {args}\n```\n\n"
|
|
66
|
+
|
|
67
|
+
graph_document, uri_prefix = _get_graph_document(
|
|
68
|
+
prefix=prefix,
|
|
69
|
+
uri_prefix=uri_prefix,
|
|
70
|
+
ontology_path=location,
|
|
71
|
+
)
|
|
72
|
+
|
|
73
|
+
click.echo(f"Loading lexical index from {index_url} using SSSLM")
|
|
74
|
+
path = module.ensure(url=index_url, force=index_force)
|
|
75
|
+
grounder = ssslm.make_grounder(path)
|
|
76
|
+
click.echo("Done loading lexical index")
|
|
77
|
+
|
|
78
|
+
passed, failed = _get_calls(
|
|
79
|
+
graph_document=graph_document,
|
|
80
|
+
matcher=grounder,
|
|
81
|
+
uri_prefix=uri_prefix,
|
|
82
|
+
skip_upper=skip_upper,
|
|
83
|
+
)
|
|
84
|
+
|
|
85
|
+
total = len(passed) + len(failed)
|
|
86
|
+
|
|
87
|
+
if passed and show_passed:
|
|
88
|
+
passed_table = tabulate(passed, headers=["LUID", "Name"], tablefmt="github")
|
|
89
|
+
passed_msg = f"## Passed Nodes ({len(passed):,}/{total:,}; {len(passed) / total:.1%})\n\n{passed_table}\n\n"
|
|
90
|
+
output += passed_msg
|
|
91
|
+
|
|
92
|
+
if failed:
|
|
93
|
+
rows = []
|
|
94
|
+
for luid, name, matches in failed:
|
|
95
|
+
rows.append((luid, name, *_parts(matches[0])))
|
|
96
|
+
for match in matches[1:]:
|
|
97
|
+
rows.append(("", "", *_parts(match)))
|
|
98
|
+
failed_table = tabulate(
|
|
99
|
+
rows, headers=[prefix, "name", "obo-curie", "obo-name", "obo-score"], tablefmt="github"
|
|
100
|
+
)
|
|
101
|
+
failed_message = f"## Failed Nodes ({len(failed):,}/{total:,}; {len(failed) / total:.1%})\n\n{failed_table}\n\n"
|
|
102
|
+
output += failed_message
|
|
103
|
+
|
|
104
|
+
click.echo(output)
|
|
105
|
+
click.echo("Finished! automatically copied to the clipboard, e.g., for pasting into GitHub)")
|
|
106
|
+
pyperclip.copy(output)
|
|
107
|
+
|
|
108
|
+
|
|
109
|
+
def _parts(match: ssslm.Match) -> tuple[str, str, float]:
|
|
110
|
+
return (
|
|
111
|
+
f"[`{match.curie}`](https://semantic.farm/{match.curie})",
|
|
112
|
+
match.name or "",
|
|
113
|
+
round(match.score, 3),
|
|
114
|
+
)
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
def _get_graph_document(
|
|
118
|
+
prefix: str, uri_prefix: str | None = None, ontology_path: str | None = None
|
|
119
|
+
) -> tuple[obographs.GraphDocument, str]:
|
|
120
|
+
from pathlib import Path
|
|
121
|
+
|
|
122
|
+
import obographs
|
|
123
|
+
import robot_obo_tool
|
|
124
|
+
|
|
125
|
+
if uri_prefix is None:
|
|
126
|
+
uri_prefix = f"http://purl.obolibrary.org/obo/{prefix}_"
|
|
127
|
+
click.echo(f"Inferred URI prefix from given OBO CURIE prefix: {uri_prefix}")
|
|
128
|
+
if ontology_path is None:
|
|
129
|
+
ontology_path = f"https://purl.obolibrary.org/obo/{prefix.lower()}.json"
|
|
130
|
+
click.echo(f"No ontology path given, guessing it's available at {ontology_path}")
|
|
131
|
+
if ontology_path.endswith(".json"):
|
|
132
|
+
click.echo(f"reading OBO Graph JSON from {ontology_path}")
|
|
133
|
+
graph_documents = obographs.read(ontology_path, squeeze=False, timeout=60)
|
|
134
|
+
else:
|
|
135
|
+
import tempfile
|
|
136
|
+
|
|
137
|
+
with tempfile.TemporaryDirectory() as tmpdir:
|
|
138
|
+
tmppath = Path(tmpdir).joinpath("temp.json")
|
|
139
|
+
click.echo(
|
|
140
|
+
"given ontology path does not end with JSON. implicitly converting to OBO Graph JSON using ROBOT"
|
|
141
|
+
)
|
|
142
|
+
robot_obo_tool.convert(
|
|
143
|
+
input_path=ontology_path,
|
|
144
|
+
output_path=tmppath,
|
|
145
|
+
check=False,
|
|
146
|
+
merge=False,
|
|
147
|
+
reason=False,
|
|
148
|
+
)
|
|
149
|
+
click.echo("reading converted OBO Graph JSON")
|
|
150
|
+
graph_documents = obographs.read(tmppath, squeeze=False)
|
|
151
|
+
|
|
152
|
+
return graph_documents, uri_prefix
|
|
153
|
+
|
|
154
|
+
|
|
155
|
+
def _get_calls(
|
|
156
|
+
*,
|
|
157
|
+
graph_document: obographs.GraphDocument,
|
|
158
|
+
matcher: ssslm.Matcher,
|
|
159
|
+
uri_prefix: str,
|
|
160
|
+
skip_upper: bool = False,
|
|
161
|
+
) -> tuple[list[tuple[str, str]], list[tuple[str, str, list[ssslm.Match]]]]:
|
|
162
|
+
"""Get matches."""
|
|
163
|
+
from tqdm import tqdm
|
|
164
|
+
|
|
165
|
+
passed = []
|
|
166
|
+
failed = []
|
|
167
|
+
total = 0
|
|
168
|
+
skipped = 0
|
|
169
|
+
for graph in tqdm(graph_document.graphs, unit="graph"):
|
|
170
|
+
for node in tqdm(sorted(graph.nodes, key=lambda n: n.id), unit="node", leave=False):
|
|
171
|
+
if node.id is None:
|
|
172
|
+
continue
|
|
173
|
+
|
|
174
|
+
total += 1
|
|
175
|
+
if not node.id.startswith(uri_prefix):
|
|
176
|
+
skipped += 1
|
|
177
|
+
continue
|
|
178
|
+
|
|
179
|
+
if not node.lbl:
|
|
180
|
+
continue
|
|
181
|
+
|
|
182
|
+
local_unique_identifier = node.id[len(uri_prefix) :]
|
|
183
|
+
|
|
184
|
+
matches: list[ssslm.Match] = []
|
|
185
|
+
matches.extend(matcher.get_matches(node.lbl))
|
|
186
|
+
if node.meta is not None and node.meta.synonyms is not None:
|
|
187
|
+
matches.extend(
|
|
188
|
+
match
|
|
189
|
+
for synonym in node.meta.synonyms
|
|
190
|
+
for match in matcher.get_matches(synonym.val)
|
|
191
|
+
)
|
|
192
|
+
|
|
193
|
+
# there are a lot of NCIT matches, which aren't that informative
|
|
194
|
+
# since OBO doesn't mind duplicating these terms
|
|
195
|
+
if skip_upper:
|
|
196
|
+
matches = [m for m in matches if m.prefix not in UPPER]
|
|
197
|
+
|
|
198
|
+
if not matches:
|
|
199
|
+
passed.append((local_unique_identifier, node.lbl))
|
|
200
|
+
else:
|
|
201
|
+
failed.append((local_unique_identifier, node.lbl, matches))
|
|
202
|
+
|
|
203
|
+
return passed, failed
|
|
204
|
+
|
|
205
|
+
|
|
206
|
+
if __name__ == "__main__":
|
|
207
|
+
obo_lexical_review()
|
pyobo/getters.py
CHANGED
|
@@ -17,7 +17,6 @@ from pathlib import Path
|
|
|
17
17
|
from textwrap import indent
|
|
18
18
|
from typing import Any, TypeVar
|
|
19
19
|
|
|
20
|
-
import bioontologies.robot
|
|
21
20
|
import bioregistry
|
|
22
21
|
import click
|
|
23
22
|
import pystow.utils
|
|
@@ -80,10 +79,10 @@ REQUIRES_NO_ROBOT_CHECK = {
|
|
|
80
79
|
|
|
81
80
|
|
|
82
81
|
def _convert_to_obo(path: Path) -> Path:
|
|
83
|
-
import
|
|
82
|
+
import robot_obo_tool
|
|
84
83
|
|
|
85
84
|
_converted_obo_path = path.with_suffix(".obo")
|
|
86
|
-
|
|
85
|
+
robot_obo_tool.convert(path, _converted_obo_path, check=False)
|
|
87
86
|
return _converted_obo_path
|
|
88
87
|
|
|
89
88
|
|
|
@@ -338,6 +337,8 @@ def iter_helper_helper(
|
|
|
338
337
|
|
|
339
338
|
:yields: A prefix and the result of the callable ``f``
|
|
340
339
|
"""
|
|
340
|
+
from robot_obo_tool import ROBOTError
|
|
341
|
+
|
|
341
342
|
strict = kwargs.get("strict", True)
|
|
342
343
|
prefixes = list(
|
|
343
344
|
_prefixes(
|
|
@@ -382,7 +383,7 @@ def iter_helper_helper(
|
|
|
382
383
|
if "DrugBank" not in str(e):
|
|
383
384
|
raise
|
|
384
385
|
logger.warning("[drugbank] invalid credentials")
|
|
385
|
-
except (subprocess.CalledProcessError,
|
|
386
|
+
except (subprocess.CalledProcessError, ROBOTError):
|
|
386
387
|
logger.warning("[%s] ROBOT was unable to convert OWL to OBO", prefix)
|
|
387
388
|
except ValueError as e:
|
|
388
389
|
if _is_xml(e):
|
pyobo/sources/ror.py
CHANGED
|
@@ -2,18 +2,14 @@
|
|
|
2
2
|
|
|
3
3
|
from __future__ import annotations
|
|
4
4
|
|
|
5
|
-
import datetime
|
|
6
|
-
import json
|
|
7
5
|
import logging
|
|
8
|
-
import zipfile
|
|
9
6
|
from collections.abc import Iterable
|
|
10
|
-
from
|
|
11
|
-
from pathlib import Path
|
|
12
|
-
from typing import Any, Literal, NamedTuple, TypeAlias
|
|
7
|
+
from typing import Any
|
|
13
8
|
|
|
14
9
|
import bioregistry
|
|
15
|
-
import
|
|
16
|
-
from pydantic import
|
|
10
|
+
import ror_downloader
|
|
11
|
+
from pydantic import ValidationError
|
|
12
|
+
from ror_downloader import OrganizationType
|
|
17
13
|
from tqdm.auto import tqdm
|
|
18
14
|
|
|
19
15
|
from pyobo.struct import Obo, Reference, Term
|
|
@@ -29,16 +25,12 @@ from pyobo.struct.typedef import (
|
|
|
29
25
|
)
|
|
30
26
|
|
|
31
27
|
__all__ = [
|
|
32
|
-
"
|
|
33
|
-
"RORStatus",
|
|
34
|
-
"get_ror_records",
|
|
35
|
-
"get_ror_status",
|
|
28
|
+
"RORGetter",
|
|
36
29
|
"get_ror_to_country_geonames",
|
|
37
30
|
]
|
|
38
31
|
|
|
39
32
|
logger = logging.getLogger(__name__)
|
|
40
33
|
PREFIX = "ror"
|
|
41
|
-
ROR_ZENODO_RECORD_ID = "17953395"
|
|
42
34
|
|
|
43
35
|
# Constants
|
|
44
36
|
ORG_CLASS = Reference(prefix="OBI", identifier="0000245", name="organization")
|
|
@@ -70,7 +62,7 @@ class RORGetter(Obo):
|
|
|
70
62
|
root_terms = [CITY_CLASS, ORG_CLASS]
|
|
71
63
|
|
|
72
64
|
def __post_init__(self):
|
|
73
|
-
self.data_version
|
|
65
|
+
self.data_version = ror_downloader.get_version_info(download=False).version
|
|
74
66
|
super().__post_init__()
|
|
75
67
|
|
|
76
68
|
def iter_terms(self, force: bool = False) -> Iterable[Term]:
|
|
@@ -83,18 +75,6 @@ class RORGetter(Obo):
|
|
|
83
75
|
yield from iterate_ror_terms(force=force)
|
|
84
76
|
|
|
85
77
|
|
|
86
|
-
OrganizationType: TypeAlias = Literal[
|
|
87
|
-
"education",
|
|
88
|
-
"facility",
|
|
89
|
-
"funder",
|
|
90
|
-
"company",
|
|
91
|
-
"government",
|
|
92
|
-
"healthcare",
|
|
93
|
-
"archive",
|
|
94
|
-
"nonprofit",
|
|
95
|
-
"other",
|
|
96
|
-
]
|
|
97
|
-
|
|
98
78
|
ROR_ORGANIZATION_TYPE_TO_OBI: dict[OrganizationType, Term] = {
|
|
99
79
|
"education": Term.default(PREFIX, "education", "educational organization"),
|
|
100
80
|
"facility": Term.default(PREFIX, "facility", "facility"),
|
|
@@ -115,127 +95,9 @@ for _k, v in ROR_ORGANIZATION_TYPE_TO_OBI.items():
|
|
|
115
95
|
_MISSED_ORG_TYPES: set[str] = set()
|
|
116
96
|
|
|
117
97
|
|
|
118
|
-
class LocationDetails(BaseModel):
|
|
119
|
-
"""The location details slot in the ROR schema."""
|
|
120
|
-
|
|
121
|
-
continent_code: str
|
|
122
|
-
continent_name: str
|
|
123
|
-
country_code: str
|
|
124
|
-
country_name: str
|
|
125
|
-
country_subdivision_code: str | None = None
|
|
126
|
-
country_subdivision_name: str | None = None
|
|
127
|
-
lat: float
|
|
128
|
-
lng: float
|
|
129
|
-
name: str
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
class Location(BaseModel):
|
|
133
|
-
"""The lcoation slot in the ROR schema."""
|
|
134
|
-
|
|
135
|
-
geonames_id: int
|
|
136
|
-
geonames_details: LocationDetails
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
class ExternalID(BaseModel):
|
|
140
|
-
"""The external ID slot in the ROR schema."""
|
|
141
|
-
|
|
142
|
-
type: str
|
|
143
|
-
all: list[str]
|
|
144
|
-
preferred: str | None = None
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
class Link(BaseModel):
|
|
148
|
-
"""The link slot in the ROR schema."""
|
|
149
|
-
|
|
150
|
-
type: str
|
|
151
|
-
value: str
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
class Name(BaseModel):
|
|
155
|
-
"""The name slot in the ROR schema."""
|
|
156
|
-
|
|
157
|
-
value: str
|
|
158
|
-
types: list[str]
|
|
159
|
-
lang: str | None = None
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
class Relationship(BaseModel):
|
|
163
|
-
"""The relationship slot in the ROR schema."""
|
|
164
|
-
|
|
165
|
-
type: str
|
|
166
|
-
label: str
|
|
167
|
-
id: str
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
class DateAnnotated(BaseModel):
|
|
171
|
-
"""The annotated date slot in the ROR schema."""
|
|
172
|
-
|
|
173
|
-
date: datetime.date
|
|
174
|
-
schema_version: str
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
class Admin(BaseModel):
|
|
178
|
-
"""The admin slot in the ROR schema."""
|
|
179
|
-
|
|
180
|
-
created: DateAnnotated
|
|
181
|
-
last_modified: DateAnnotated
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
Status: TypeAlias = Literal["active", "inactive", "withdrawn"]
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
class Record(BaseModel):
|
|
188
|
-
"""A ROR record."""
|
|
189
|
-
|
|
190
|
-
locations: list[Location]
|
|
191
|
-
established: int | None = None
|
|
192
|
-
external_ids: list[ExternalID]
|
|
193
|
-
id: str
|
|
194
|
-
domains: list[str]
|
|
195
|
-
links: list[Link]
|
|
196
|
-
names: list[Name]
|
|
197
|
-
relationships: list[Relationship]
|
|
198
|
-
status: Status
|
|
199
|
-
types: list[OrganizationType]
|
|
200
|
-
admin: Admin
|
|
201
|
-
|
|
202
|
-
def get_preferred_label(self) -> str | None:
|
|
203
|
-
"""Get the preferred label."""
|
|
204
|
-
primary_name: str | None = None
|
|
205
|
-
for name in self.names:
|
|
206
|
-
if "ror_display" in name.types:
|
|
207
|
-
primary_name = name.value
|
|
208
|
-
if primary_name is None:
|
|
209
|
-
return None
|
|
210
|
-
primary_name = NAME_REMAPPING.get(primary_name, primary_name)
|
|
211
|
-
return primary_name
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
_description_prefix = {
|
|
215
|
-
"education": "an educational organization",
|
|
216
|
-
"facility": "a facility",
|
|
217
|
-
"funder": "a funder",
|
|
218
|
-
"company": "a company",
|
|
219
|
-
"government": "a governmental organization",
|
|
220
|
-
"healthcare": "a healthcare organization",
|
|
221
|
-
"archive": "an archive",
|
|
222
|
-
"nonprofit": "a nonprofit organization",
|
|
223
|
-
"other": "an organization",
|
|
224
|
-
}
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
def _get_description(record: Record) -> str | None:
|
|
228
|
-
description = (
|
|
229
|
-
f"{_description_prefix[record.types[0]]} in {record.locations[0].geonames_details.name}"
|
|
230
|
-
)
|
|
231
|
-
if record.established:
|
|
232
|
-
description += f" established in {record.established}"
|
|
233
|
-
return description
|
|
234
|
-
|
|
235
|
-
|
|
236
98
|
def iterate_ror_terms(*, force: bool = False) -> Iterable[Term]:
|
|
237
99
|
"""Iterate over terms in ROR."""
|
|
238
|
-
status, records =
|
|
100
|
+
status, records = ror_downloader.get_organizations(force=force)
|
|
239
101
|
unhandled_xref_prefixes: set[str] = set()
|
|
240
102
|
|
|
241
103
|
seen_geonames_references = set()
|
|
@@ -249,7 +111,7 @@ def iterate_ror_terms(*, force: bool = False) -> Iterable[Term]:
|
|
|
249
111
|
term = Term(
|
|
250
112
|
reference=Reference(prefix=PREFIX, identifier=identifier, name=primary_name),
|
|
251
113
|
type="Instance",
|
|
252
|
-
definition=
|
|
114
|
+
definition=record.get_description(),
|
|
253
115
|
)
|
|
254
116
|
for organization_type in record.types:
|
|
255
117
|
if organization_type in ROR_ORGANIZATION_TYPE_TO_OBI:
|
|
@@ -339,63 +201,6 @@ def iterate_ror_terms(*, force: bool = False) -> Iterable[Term]:
|
|
|
339
201
|
yield geonames_term
|
|
340
202
|
|
|
341
203
|
|
|
342
|
-
class RORStatus(NamedTuple):
|
|
343
|
-
"""A version information tuple."""
|
|
344
|
-
|
|
345
|
-
version: str
|
|
346
|
-
url: str
|
|
347
|
-
path: Path
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
def get_ror_status(*, force: bool = False, authenticate_zenodo: bool = True) -> RORStatus:
|
|
351
|
-
"""Ensure the latest ROR record, metadata, and filepath.
|
|
352
|
-
|
|
353
|
-
:param force: Should the record be downloaded again? This almost
|
|
354
|
-
never needs to be true, since the data doesn't change for
|
|
355
|
-
a given version
|
|
356
|
-
:param authenticate_zenodo: Should Zenodo be authenticated?
|
|
357
|
-
This isn't required, but can help avoid rate limits
|
|
358
|
-
:return: A version information tuple
|
|
359
|
-
|
|
360
|
-
.. note::
|
|
361
|
-
|
|
362
|
-
this goes into the ``~/.data/zenodo/6347574`` folder,
|
|
363
|
-
because 6347574 is the super-record ID, which groups all
|
|
364
|
-
versions together. this is different from the value
|
|
365
|
-
for :data:`ROR_ZENODO_RECORD_ID`
|
|
366
|
-
"""
|
|
367
|
-
client = zenodo_client.Zenodo()
|
|
368
|
-
latest_record_id = client.get_latest_record(
|
|
369
|
-
ROR_ZENODO_RECORD_ID, authenticate=authenticate_zenodo
|
|
370
|
-
)
|
|
371
|
-
response = client.get_record(latest_record_id, authenticate=authenticate_zenodo)
|
|
372
|
-
response_json = response.json()
|
|
373
|
-
version = response_json["metadata"]["version"].lstrip("v")
|
|
374
|
-
file_record = response_json["files"][0]
|
|
375
|
-
name = file_record["key"]
|
|
376
|
-
url = file_record["links"]["self"]
|
|
377
|
-
path = client.download(latest_record_id, name=name, force=force)
|
|
378
|
-
return RORStatus(version=version, url=url, path=path)
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
@lru_cache
|
|
382
|
-
def get_ror_records(
|
|
383
|
-
*, force: bool = False, authenticate_zenodo: bool = True
|
|
384
|
-
) -> tuple[RORStatus, list[Record]]:
|
|
385
|
-
"""Get the latest ROR metadata and records."""
|
|
386
|
-
status = get_ror_status(force=force, authenticate_zenodo=authenticate_zenodo)
|
|
387
|
-
with zipfile.ZipFile(status.path) as zf:
|
|
388
|
-
for zip_info in zf.filelist:
|
|
389
|
-
if zip_info.filename.endswith(".json"):
|
|
390
|
-
with zf.open(zip_info) as file:
|
|
391
|
-
records = [
|
|
392
|
-
Record.model_validate(record)
|
|
393
|
-
for record in tqdm(json.load(file), unit_scale=True)
|
|
394
|
-
]
|
|
395
|
-
return status, records
|
|
396
|
-
raise FileNotFoundError
|
|
397
|
-
|
|
398
|
-
|
|
399
204
|
def get_ror_to_country_geonames(**kwargs: Any) -> dict[str, str]:
|
|
400
205
|
"""Get a mapping of ROR ids to GeoNames IDs for countries."""
|
|
401
206
|
from pyobo.sources.geonames.geonames import get_city_to_country
|
|
@@ -250,7 +250,7 @@ class Import(Box):
|
|
|
250
250
|
|
|
251
251
|
def get_rdf_graph_oracle(boxes: list[Box], *, prefix_map: dict[str, str]) -> Graph:
|
|
252
252
|
"""Serialize to turtle via OFN and conversion with ROBOT."""
|
|
253
|
-
import
|
|
253
|
+
import robot_obo_tool
|
|
254
254
|
|
|
255
255
|
ontology = Ontology(
|
|
256
256
|
iri=EXAMPLE_ONTOLOGY_IRI,
|
|
@@ -265,7 +265,7 @@ def get_rdf_graph_oracle(boxes: list[Box], *, prefix_map: dict[str, str]) -> Gra
|
|
|
265
265
|
ofn_path.write_text(text)
|
|
266
266
|
ttl_path = stub.with_suffix(".ttl")
|
|
267
267
|
try:
|
|
268
|
-
|
|
268
|
+
robot_obo_tool.convert(ofn_path, ttl_path)
|
|
269
269
|
except subprocess.CalledProcessError:
|
|
270
270
|
raise RuntimeError(f"failed to convert axioms from:\n\n{text}") from None
|
|
271
271
|
graph.parse(ttl_path)
|
pyobo/struct/obograph/export.py
CHANGED
|
@@ -33,7 +33,7 @@ def to_parsed_obograph_oracle(
|
|
|
33
33
|
obo: Obo, *, converter: Converter | None = None
|
|
34
34
|
) -> og.StandardizedGraphDocument:
|
|
35
35
|
"""Serialize to OBO, convert to OBO Graph JSON with ROBOT, load, then parse."""
|
|
36
|
-
import
|
|
36
|
+
import robot_obo_tool
|
|
37
37
|
|
|
38
38
|
if converter is None:
|
|
39
39
|
converter = get_converter()
|
|
@@ -43,7 +43,7 @@ def to_parsed_obograph_oracle(
|
|
|
43
43
|
obo_path = stub.with_suffix(".obo")
|
|
44
44
|
obograph_path = stub.with_suffix(".json")
|
|
45
45
|
obo.write_obo(obo_path)
|
|
46
|
-
|
|
46
|
+
robot_obo_tool.convert(input_path=obo_path, output_path=obograph_path)
|
|
47
47
|
raw = og.read(obograph_path, squeeze=False)
|
|
48
48
|
rv = raw.standardize(converter)
|
|
49
49
|
for graph in rv.graphs:
|
pyobo/struct/struct.py
CHANGED
|
@@ -1067,12 +1067,12 @@ class Obo:
|
|
|
1067
1067
|
|
|
1068
1068
|
def write_owl(self, path: str | Path) -> None:
|
|
1069
1069
|
"""Write OWL, by first outputting OFN then converting with ROBOT."""
|
|
1070
|
-
|
|
1070
|
+
import robot_obo_tool
|
|
1071
1071
|
|
|
1072
1072
|
with tempfile.TemporaryDirectory() as directory:
|
|
1073
1073
|
ofn_path = Path(directory).joinpath("tmp.ofn")
|
|
1074
1074
|
self.write_ofn(ofn_path)
|
|
1075
|
-
|
|
1075
|
+
robot_obo_tool.convert(ofn_path, path)
|
|
1076
1076
|
|
|
1077
1077
|
def write_rdf(self, path: str | Path) -> None:
|
|
1078
1078
|
"""Write as Turtle RDF."""
|
|
@@ -1312,19 +1312,19 @@ class Obo:
|
|
|
1312
1312
|
tqdm.write(f"[{self._prefix_version}] writing OBO Graph to {self._obograph_path}")
|
|
1313
1313
|
self.write_obograph(self._obograph_path)
|
|
1314
1314
|
else:
|
|
1315
|
-
import
|
|
1315
|
+
import robot_obo_tool
|
|
1316
1316
|
|
|
1317
1317
|
tqdm.write(
|
|
1318
1318
|
f"[{self.ontology}] converting OFN to OBO Graph at {self._obograph_path}"
|
|
1319
1319
|
)
|
|
1320
|
-
|
|
1320
|
+
robot_obo_tool.convert(
|
|
1321
1321
|
self._ofn_path, self._obograph_path, debug=True, merge=False, reason=False
|
|
1322
1322
|
)
|
|
1323
1323
|
if write_owl and (not self._owl_path.is_file() or force):
|
|
1324
1324
|
tqdm.write(f"[{self._prefix_version}] writing OWL to {self._owl_path}")
|
|
1325
|
-
import
|
|
1325
|
+
import robot_obo_tool
|
|
1326
1326
|
|
|
1327
|
-
|
|
1327
|
+
robot_obo_tool.convert(
|
|
1328
1328
|
self._ofn_path, self._owl_path, debug=True, merge=False, reason=False
|
|
1329
1329
|
)
|
|
1330
1330
|
if write_ttl and (not self._ttl_path.is_file() or force):
|
pyobo/utils/path.py
CHANGED
pyobo/version.py
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: pyobo
|
|
3
|
-
Version: 0.12.
|
|
3
|
+
Version: 0.12.16
|
|
4
4
|
Summary: A python package for handling and generating OBO
|
|
5
5
|
Keywords: snekpack,cookiecutter,ontologies,biomedical ontologies,life sciences,natural sciences,bioinformatics,cheminformatics,Open Biomedical Ontologies,OBO
|
|
6
6
|
Author: Charles Tapley Hoyt
|
|
@@ -36,11 +36,10 @@ Requires-Dist: humanize
|
|
|
36
36
|
Requires-Dist: tabulate
|
|
37
37
|
Requires-Dist: cachier
|
|
38
38
|
Requires-Dist: pystow>=0.7.5
|
|
39
|
-
Requires-Dist: bioversions>=0.8.
|
|
39
|
+
Requires-Dist: bioversions>=0.8.243
|
|
40
40
|
Requires-Dist: bioregistry>=0.12.30
|
|
41
|
-
Requires-Dist: bioontologies>=0.7.2
|
|
42
41
|
Requires-Dist: ssslm>=0.0.13
|
|
43
|
-
Requires-Dist: zenodo-client>=0.4.
|
|
42
|
+
Requires-Dist: zenodo-client>=0.4.1
|
|
44
43
|
Requires-Dist: class-resolver>=0.6.0
|
|
45
44
|
Requires-Dist: pydantic>=2.0
|
|
46
45
|
Requires-Dist: curies>=0.10.17
|
|
@@ -52,10 +51,14 @@ Requires-Dist: chembl-downloader
|
|
|
52
51
|
Requires-Dist: umls-downloader>=0.1.3
|
|
53
52
|
Requires-Dist: clinicaltrials-downloader>=0.0.2
|
|
54
53
|
Requires-Dist: nih-reporter-downloader>=0.0.1
|
|
54
|
+
Requires-Dist: ror-downloader>=0.0.4
|
|
55
55
|
Requires-Dist: typing-extensions
|
|
56
56
|
Requires-Dist: rdflib
|
|
57
57
|
Requires-Dist: obographs>=0.0.8
|
|
58
|
-
Requires-Dist: sssom-pydantic>=0.
|
|
58
|
+
Requires-Dist: sssom-pydantic>=0.2.0
|
|
59
|
+
Requires-Dist: pytz
|
|
60
|
+
Requires-Dist: robot-obo-tool
|
|
61
|
+
Requires-Dist: pyperclip
|
|
59
62
|
Requires-Dist: psycopg2-binary ; extra == 'drugcentral'
|
|
60
63
|
Requires-Dist: ssslm[gilda] ; extra == 'gilda'
|
|
61
64
|
Requires-Dist: ssslm[gilda-slim] ; extra == 'gilda-slim'
|
|
@@ -72,10 +75,10 @@ Maintainer: Charles Tapley Hoyt
|
|
|
72
75
|
Maintainer-email: Charles Tapley Hoyt <cthoyt@gmail.com>
|
|
73
76
|
Requires-Python: >=3.10
|
|
74
77
|
Project-URL: Bug Tracker, https://github.com/biopragmatics/pyobo/issues
|
|
75
|
-
Project-URL: Documentation, https://pyobo.readthedocs.io
|
|
76
|
-
Project-URL: Funding, https://github.com/sponsors/cthoyt
|
|
77
78
|
Project-URL: Homepage, https://github.com/biopragmatics/pyobo
|
|
78
79
|
Project-URL: Repository, https://github.com/biopragmatics/pyobo.git
|
|
80
|
+
Project-URL: Documentation, https://pyobo.readthedocs.io
|
|
81
|
+
Project-URL: Funding, https://github.com/sponsors/cthoyt
|
|
79
82
|
Provides-Extra: drugcentral
|
|
80
83
|
Provides-Extra: gilda
|
|
81
84
|
Provides-Extra: gilda-slim
|
|
@@ -14,15 +14,16 @@ pyobo/api/relations.py,sha256=Kebguj5khScU2c0Pm8dJrewu8je9DnKlNenRtmYWGKI,5875
|
|
|
14
14
|
pyobo/api/species.py,sha256=YxzJeClfuKI-pjYLpu5797jdDeyTkXpjQDgdmc9MKwo,2376
|
|
15
15
|
pyobo/api/typedefs.py,sha256=HTui0kl_VELxgji0vfBr-NBG3zrrpCU8tmuQOSWK6fw,1262
|
|
16
16
|
pyobo/api/utils.py,sha256=SCMsy4QyYVhn-QK0h90Ef1XUMbyHKR1fvteRESzs-bk,5192
|
|
17
|
-
pyobo/api/xrefs.py,sha256=
|
|
17
|
+
pyobo/api/xrefs.py,sha256=xrs-c56GThSzIE5Rj0dmrbztxNTr22Y7NykQHeIBPk4,6070
|
|
18
18
|
pyobo/cli/__init__.py,sha256=pTiLuzjjpi0P69yVjQ2kE6nBUmZuYFnqdJNDZLDkgvk,71
|
|
19
|
-
pyobo/cli/cli.py,sha256=
|
|
19
|
+
pyobo/cli/cli.py,sha256=nEU70l12ChHKSYWwWNzwgo-0ldOEa0FCkvH7745u5qA,2992
|
|
20
20
|
pyobo/cli/database.py,sha256=iq4-eJ_8Kgim0MMnSqf1wu2hvHDZk9BWNMVuwykz2Ko,13407
|
|
21
21
|
pyobo/cli/database_utils.py,sha256=jQ7qSg-oZk-Q-RC121NkUbqXeNg0K8fV96igXaK3ra4,5540
|
|
22
|
-
pyobo/cli/lookup.py,sha256
|
|
22
|
+
pyobo/cli/lookup.py,sha256=1VexVdPXM2_tTL2eFyDnepcH-_fsdEDxaQId-LblAXI,10089
|
|
23
|
+
pyobo/cli/obo_lexical_review.py,sha256=x6AJdNPH4WLC419KNV9_dHInVfas97MWMzQhSJRqrho,6709
|
|
23
24
|
pyobo/cli/utils.py,sha256=SfW9JC8olzp4AcAsDodMPdgHfteeXq0Ngd8yQ2kzOMA,1812
|
|
24
25
|
pyobo/constants.py,sha256=_Y4IACPsRu5jHntoc8nEHKLGDl1Bl7YrdS0gG4qxmqw,7582
|
|
25
|
-
pyobo/getters.py,sha256=
|
|
26
|
+
pyobo/getters.py,sha256=nZjynOIXzkeytqgu1UE-WleoStQtdQ3fJeWt8_r_Qxc,18326
|
|
26
27
|
pyobo/gilda_utils.py,sha256=uThAArALSNzJi-hrR9lUvtQci5VIw4Cqq2L6mtkp0Ko,1990
|
|
27
28
|
pyobo/identifier_utils/__init__.py,sha256=iSHAZhOwqWZmYpOfpXNLuKouSYj7ZSViaX7BF5uT8so,793
|
|
28
29
|
pyobo/identifier_utils/api.py,sha256=fik5crIOOhsHIuH-ia_oOQeKZeX5bBMj5S6occWaMeY,9365
|
|
@@ -146,7 +147,7 @@ pyobo/sources/pubchem.py,sha256=lTsc0dgrSJ5kxlcaUcUXJydi-xsMf2fI2EcWsbW8xTU,5153
|
|
|
146
147
|
pyobo/sources/reactome.py,sha256=yzeCCy19Hxr7KFUrg1tePjN40eZLN9G4dm4q0A7izbI,5842
|
|
147
148
|
pyobo/sources/rgd.py,sha256=I6HC7_GZqFPXlRIuuroOgZM7wG85jcE3Po-sry8a1XU,5194
|
|
148
149
|
pyobo/sources/rhea.py,sha256=dbhyVJ1yoAQoxoWp47OKegLAmMh6qoe-7_DafJDeWrk,8164
|
|
149
|
-
pyobo/sources/ror.py,sha256=
|
|
150
|
+
pyobo/sources/ror.py,sha256=osvjhinGU2XJulbne2i2zaZuD_ZuDK4mwkxL3wERNQc,8226
|
|
150
151
|
pyobo/sources/selventa/__init__.py,sha256=cIIDlWL9znL2r0aZIJ2r1FN3NM9io74w-He2egzJwX8,254
|
|
151
152
|
pyobo/sources/selventa/schem.py,sha256=vqN_a_NLeshj-2dRuZelfOLJQ5dyU3ZghfSRIq9EFVA,1162
|
|
152
153
|
pyobo/sources/selventa/scomp.py,sha256=nshskLQeXuzf5t79STJsVKJg3R80CX3DuJBUrEhwSbc,1531
|
|
@@ -181,17 +182,17 @@ pyobo/struct/functional/__init__.py,sha256=1Tbtt_6GoarRlgffPepitJ3QtLsrMPMbhDGoQ
|
|
|
181
182
|
pyobo/struct/functional/dsl.py,sha256=odDX33lzSkKcRjcrsteraFSc00wIOPBHJtxXe9c9RHE,101591
|
|
182
183
|
pyobo/struct/functional/macros.py,sha256=yYHGmAEMpin47U7U3S7aCC3o02khWyoON4Xgpv-gHN4,13811
|
|
183
184
|
pyobo/struct/functional/obo_to_functional.py,sha256=65OmttFto-tm6-7T0RQlgIKo34swVqTpz2B9ykPLNuw,13727
|
|
184
|
-
pyobo/struct/functional/ontology.py,sha256
|
|
185
|
+
pyobo/struct/functional/ontology.py,sha256=1CjtKUtpjCv8MivMfENA2t0LmWx9ZDPlt1nc-0SLrZI,9332
|
|
185
186
|
pyobo/struct/functional/utils.py,sha256=c-XG2SJ7ChYtz7KU3K0F-T6ocMjYevei0WxlkfkkmtE,3487
|
|
186
187
|
pyobo/struct/obo/__init__.py,sha256=xJAFJ4yueWBQv3BrtTuHHJ7AzOqCgOuHgKY4RQocsW0,157
|
|
187
188
|
pyobo/struct/obo/reader.py,sha256=HJ4u1c2ScA-2qxKhyKIZZo8RI2QOUSXwushK9FZGdrQ,50664
|
|
188
189
|
pyobo/struct/obo/reader_utils.py,sha256=UyQVTQhXbhZ9fCizZg26o5TmeHis9-qZMKvQFwIBRgo,4423
|
|
189
190
|
pyobo/struct/obograph/__init__.py,sha256=B4rNP9OCTnMXm8YpQ0rar1swn4GIw9b4gQD-IVuqHyw,452
|
|
190
|
-
pyobo/struct/obograph/export.py,sha256=
|
|
191
|
+
pyobo/struct/obograph/export.py,sha256=Z2IAYK9fRvD5QtR24oxuTFN8oPFS-eKqlvv4i9-CmXk,9935
|
|
191
192
|
pyobo/struct/obograph/reader.py,sha256=264yVeD8a3jGx9EaGUZVxFbSQ_pwQ_6ckVw9S8wiJfM,8525
|
|
192
193
|
pyobo/struct/obograph/utils.py,sha256=je0kSkC24MU9pWRHq1_K-J5jWhjWESY6NI3TpZqvZ_Q,1516
|
|
193
194
|
pyobo/struct/reference.py,sha256=qgwTa-0VIoDklQ7LjlYH-mf2WG0_uO7KlHt0PSBail4,11744
|
|
194
|
-
pyobo/struct/struct.py,sha256=
|
|
195
|
+
pyobo/struct/struct.py,sha256=cxVTrRRlV8KnLaVQBK-3dLVDfpuryBKLuA59lMN2XBk,96648
|
|
195
196
|
pyobo/struct/struct_utils.py,sha256=VFC82fgphTs7sBSNGn53sv2WMl7Ho9srALFq92bRFQQ,41021
|
|
196
197
|
pyobo/struct/typedef.py,sha256=jvETRmNc4g09X7waSjcvEkw7g0kNteLaDOt3mjKbmDc,14871
|
|
197
198
|
pyobo/struct/utils.py,sha256=zkpOE42JQIfkN0rc5qNENK03VIKmkf_57tHojMJK71Y,906
|
|
@@ -202,10 +203,10 @@ pyobo/utils/io.py,sha256=QTvGjNDkaIf78Tca23B5RW_aVweKiSsxmgwSKXcMSNo,3921
|
|
|
202
203
|
pyobo/utils/iter.py,sha256=rYRbbaFJHxMaE0yU-rQZoCagYIrtev09uY0mxFkf5zY,1524
|
|
203
204
|
pyobo/utils/misc.py,sha256=DVLxPynunSubp2xSVKFF_E57BPS3p5wU4Z4A38PI17M,8717
|
|
204
205
|
pyobo/utils/ndex_utils.py,sha256=EokCWS00Wrk_4y8ldeQuUyaaC6yNzBg3DagUl-J2czY,2326
|
|
205
|
-
pyobo/utils/path.py,sha256=
|
|
206
|
-
pyobo/version.py,sha256
|
|
207
|
-
pyobo-0.12.
|
|
208
|
-
pyobo-0.12.
|
|
209
|
-
pyobo-0.12.
|
|
210
|
-
pyobo-0.12.
|
|
211
|
-
pyobo-0.12.
|
|
206
|
+
pyobo/utils/path.py,sha256=oHfYbsfI4UaQ8_rAHqoOTCcCceXhY82_0kLUuxs5BY0,4094
|
|
207
|
+
pyobo/version.py,sha256=nW8tGi5FCn_intTOMB6X02kfn9x4iYN7s9z5HXWvmko,927
|
|
208
|
+
pyobo-0.12.16.dist-info/licenses/LICENSE,sha256=QcgJZKGxlW5BwBNnCBL8VZLVtRvXs81Ch9lJRQSIpJg,1076
|
|
209
|
+
pyobo-0.12.16.dist-info/WHEEL,sha256=fAguSjoiATBe7TNBkJwOjyL1Tt4wwiaQGtNtjRPNMQA,80
|
|
210
|
+
pyobo-0.12.16.dist-info/entry_points.txt,sha256=ANgzvuwF_9_1ipCoxJtbBM6A4i2Mkt39gMPzQO6hvGs,42
|
|
211
|
+
pyobo-0.12.16.dist-info/METADATA,sha256=y5tMlvDbm9jqjJTseIveUFKs-Sb2uBhXIVs75RFKDvg,22859
|
|
212
|
+
pyobo-0.12.16.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|