pymetadata 0.5.3__tar.gz → 0.5.5__tar.gz
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.
Potentially problematic release.
This version of pymetadata might be problematic. Click here for more details.
- {pymetadata-0.5.3 → pymetadata-0.5.5}/.bumpversion.toml +1 -1
- {pymetadata-0.5.3 → pymetadata-0.5.5}/.gitignore +1 -0
- pymetadata-0.5.5/.python-version +1 -0
- {pymetadata-0.5.3 → pymetadata-0.5.5}/PKG-INFO +7 -8
- {pymetadata-0.5.3 → pymetadata-0.5.5}/docs/composite_annotations.md +1 -1
- {pymetadata-0.5.3 → pymetadata-0.5.5}/pyproject.toml +6 -7
- pymetadata-0.5.5/release-notes/0.5.4.md +11 -0
- pymetadata-0.5.5/release-notes/0.5.5.md +13 -0
- {pymetadata-0.5.3 → pymetadata-0.5.5}/src/pymetadata/__init__.py +1 -1
- {pymetadata-0.5.3 → pymetadata-0.5.5}/src/pymetadata/chebi.py +21 -29
- {pymetadata-0.5.3 → pymetadata-0.5.5}/src/pymetadata/core/annotation.py +114 -53
- pymetadata-0.5.5/src/pymetadata/identifiers/registry.py +173 -0
- {pymetadata-0.5.3 → pymetadata-0.5.5}/src/pymetadata/metadata/eco.py +882 -301
- {pymetadata-0.5.3 → pymetadata-0.5.5}/tests/core/test_annotation.py +43 -23
- pymetadata-0.5.3/.github/CONTRIBUTING.rst +0 -141
- pymetadata-0.5.3/.github/ISSUE_TEMPLATE/01-bug-report.md +0 -49
- pymetadata-0.5.3/.github/ISSUE_TEMPLATE/02-question.md +0 -15
- pymetadata-0.5.3/.github/ISSUE_TEMPLATE/03-feature-request.md +0 -36
- pymetadata-0.5.3/.github/ISSUE_TEMPLATE/config.yml +0 -2
- pymetadata-0.5.3/.github/PULL_REQUEST_TEMPLATE.md +0 -4
- pymetadata-0.5.3/.github/SUPPORT.rst +0 -6
- pymetadata-0.5.3/.python-version +0 -1
- pymetadata-0.5.3/src/pymetadata/identifiers/registry.py +0 -375
- pymetadata-0.5.3/src/pymetadata/resources/chebi_webservice_wsdl.xml +0 -509
- pymetadata-0.5.3/uv.lock +0 -1179
- {pymetadata-0.5.3 → pymetadata-0.5.5}/.github/workflows/main.yml +0 -0
- {pymetadata-0.5.3 → pymetadata-0.5.5}/.github/workflows/mypy.yml +0 -0
- {pymetadata-0.5.3 → pymetadata-0.5.5}/.github/workflows/ruff.yml +0 -0
- {pymetadata-0.5.3 → pymetadata-0.5.5}/.pre-commit-config.yaml +0 -0
- {pymetadata-0.5.3 → pymetadata-0.5.5}/.ruff.toml +0 -0
- {pymetadata-0.5.3 → pymetadata-0.5.5}/.zenodo.json +0 -0
- {pymetadata-0.5.3 → pymetadata-0.5.5}/LICENSE +0 -0
- {pymetadata-0.5.3 → pymetadata-0.5.5}/README.md +0 -0
- {pymetadata-0.5.3 → pymetadata-0.5.5}/RELEASE.md +0 -0
- {pymetadata-0.5.3 → pymetadata-0.5.5}/docs/images/favicon/about.txt +0 -0
- {pymetadata-0.5.3 → pymetadata-0.5.5}/docs/images/favicon/android-chrome-192x192.png +0 -0
- {pymetadata-0.5.3 → pymetadata-0.5.5}/docs/images/favicon/android-chrome-512x512.png +0 -0
- {pymetadata-0.5.3 → pymetadata-0.5.5}/docs/images/favicon/apple-touch-icon.png +0 -0
- {pymetadata-0.5.3 → pymetadata-0.5.5}/docs/images/favicon/favicon-16x16.png +0 -0
- {pymetadata-0.5.3 → pymetadata-0.5.5}/docs/images/favicon/favicon-32x32.png +0 -0
- {pymetadata-0.5.3 → pymetadata-0.5.5}/docs/images/favicon/favicon.ico +0 -0
- {pymetadata-0.5.3 → pymetadata-0.5.5}/docs/images/favicon/favicon_io.zip +0 -0
- {pymetadata-0.5.3 → pymetadata-0.5.5}/docs/images/favicon/pymetadata-100x100-300dpi.png +0 -0
- {pymetadata-0.5.3 → pymetadata-0.5.5}/docs/images/favicon/site.webmanifest +0 -0
- {pymetadata-0.5.3 → pymetadata-0.5.5}/release-notes/0.0.10.md +0 -0
- {pymetadata-0.5.3 → pymetadata-0.5.5}/release-notes/0.0.11.md +0 -0
- {pymetadata-0.5.3 → pymetadata-0.5.5}/release-notes/0.0.12.md +0 -0
- {pymetadata-0.5.3 → pymetadata-0.5.5}/release-notes/0.0.13.md +0 -0
- {pymetadata-0.5.3 → pymetadata-0.5.5}/release-notes/0.0.14.md +0 -0
- {pymetadata-0.5.3 → pymetadata-0.5.5}/release-notes/0.0.15.md +0 -0
- {pymetadata-0.5.3 → pymetadata-0.5.5}/release-notes/0.0.16.md +0 -0
- {pymetadata-0.5.3 → pymetadata-0.5.5}/release-notes/0.0.17.md +0 -0
- {pymetadata-0.5.3 → pymetadata-0.5.5}/release-notes/0.0.18.md +0 -0
- {pymetadata-0.5.3 → pymetadata-0.5.5}/release-notes/0.0.19.md +0 -0
- {pymetadata-0.5.3 → pymetadata-0.5.5}/release-notes/0.0.2.md +0 -0
- {pymetadata-0.5.3 → pymetadata-0.5.5}/release-notes/0.0.20.md +0 -0
- {pymetadata-0.5.3 → pymetadata-0.5.5}/release-notes/0.0.21.md +0 -0
- {pymetadata-0.5.3 → pymetadata-0.5.5}/release-notes/0.0.22.md +0 -0
- {pymetadata-0.5.3 → pymetadata-0.5.5}/release-notes/0.0.3.md +0 -0
- {pymetadata-0.5.3 → pymetadata-0.5.5}/release-notes/0.0.4.md +0 -0
- {pymetadata-0.5.3 → pymetadata-0.5.5}/release-notes/0.0.5.md +0 -0
- {pymetadata-0.5.3 → pymetadata-0.5.5}/release-notes/0.0.6.md +0 -0
- {pymetadata-0.5.3 → pymetadata-0.5.5}/release-notes/0.0.7.md +0 -0
- {pymetadata-0.5.3 → pymetadata-0.5.5}/release-notes/0.0.8.md +0 -0
- {pymetadata-0.5.3 → pymetadata-0.5.5}/release-notes/0.0.9.md +0 -0
- {pymetadata-0.5.3 → pymetadata-0.5.5}/release-notes/0.1.0.md +0 -0
- {pymetadata-0.5.3 → pymetadata-0.5.5}/release-notes/0.2.1.md +0 -0
- {pymetadata-0.5.3 → pymetadata-0.5.5}/release-notes/0.2.10.md +0 -0
- {pymetadata-0.5.3 → pymetadata-0.5.5}/release-notes/0.2.2.md +0 -0
- {pymetadata-0.5.3 → pymetadata-0.5.5}/release-notes/0.2.3.md +0 -0
- {pymetadata-0.5.3 → pymetadata-0.5.5}/release-notes/0.2.4.md +0 -0
- {pymetadata-0.5.3 → pymetadata-0.5.5}/release-notes/0.2.5.md +0 -0
- {pymetadata-0.5.3 → pymetadata-0.5.5}/release-notes/0.2.6.md +0 -0
- {pymetadata-0.5.3 → pymetadata-0.5.5}/release-notes/0.2.7.md +0 -0
- {pymetadata-0.5.3 → pymetadata-0.5.5}/release-notes/0.2.8.md +0 -0
- {pymetadata-0.5.3 → pymetadata-0.5.5}/release-notes/0.2.9.md +0 -0
- {pymetadata-0.5.3 → pymetadata-0.5.5}/release-notes/0.3.0.md +0 -0
- {pymetadata-0.5.3 → pymetadata-0.5.5}/release-notes/0.3.1.md +0 -0
- {pymetadata-0.5.3 → pymetadata-0.5.5}/release-notes/0.3.10.md +0 -0
- {pymetadata-0.5.3 → pymetadata-0.5.5}/release-notes/0.3.11.md +0 -0
- {pymetadata-0.5.3 → pymetadata-0.5.5}/release-notes/0.3.2.md +0 -0
- {pymetadata-0.5.3 → pymetadata-0.5.5}/release-notes/0.3.3.md +0 -0
- {pymetadata-0.5.3 → pymetadata-0.5.5}/release-notes/0.3.4.md +0 -0
- {pymetadata-0.5.3 → pymetadata-0.5.5}/release-notes/0.3.5.md +0 -0
- {pymetadata-0.5.3 → pymetadata-0.5.5}/release-notes/0.3.6.md +0 -0
- {pymetadata-0.5.3 → pymetadata-0.5.5}/release-notes/0.3.7.md +0 -0
- {pymetadata-0.5.3 → pymetadata-0.5.5}/release-notes/0.3.8.md +0 -0
- {pymetadata-0.5.3 → pymetadata-0.5.5}/release-notes/0.3.9.md +0 -0
- {pymetadata-0.5.3 → pymetadata-0.5.5}/release-notes/0.4.0.md +0 -0
- {pymetadata-0.5.3 → pymetadata-0.5.5}/release-notes/0.4.1.md +0 -0
- {pymetadata-0.5.3 → pymetadata-0.5.5}/release-notes/0.4.2.md +0 -0
- {pymetadata-0.5.3 → pymetadata-0.5.5}/release-notes/0.4.3.md +0 -0
- {pymetadata-0.5.3 → pymetadata-0.5.5}/release-notes/0.4.4.md +0 -0
- {pymetadata-0.5.3 → pymetadata-0.5.5}/release-notes/0.5.0.md +0 -0
- {pymetadata-0.5.3 → pymetadata-0.5.5}/release-notes/0.5.1.md +0 -0
- {pymetadata-0.5.3 → pymetadata-0.5.5}/release-notes/0.5.2.md +0 -0
- {pymetadata-0.5.3 → pymetadata-0.5.5}/release-notes/0.5.3.md +0 -0
- {pymetadata-0.5.3 → pymetadata-0.5.5}/src/pymetadata/cache.py +0 -0
- {pymetadata-0.5.3 → pymetadata-0.5.5}/src/pymetadata/console.py +0 -0
- {pymetadata-0.5.3 → pymetadata-0.5.5}/src/pymetadata/core/__init__.py +0 -0
- {pymetadata-0.5.3 → pymetadata-0.5.5}/src/pymetadata/core/creator.py +0 -0
- {pymetadata-0.5.3 → pymetadata-0.5.5}/src/pymetadata/core/synonym.py +0 -0
- {pymetadata-0.5.3 → pymetadata-0.5.5}/src/pymetadata/core/xref.py +0 -0
- {pymetadata-0.5.3 → pymetadata-0.5.5}/src/pymetadata/examples/__init__.py +0 -0
- {pymetadata-0.5.3 → pymetadata-0.5.5}/src/pymetadata/examples/cache_path_example.py +0 -0
- {pymetadata-0.5.3 → pymetadata-0.5.5}/src/pymetadata/examples/omex_example.py +0 -0
- {pymetadata-0.5.3 → pymetadata-0.5.5}/src/pymetadata/examples/results/test_from_files.omex +0 -0
- {pymetadata-0.5.3 → pymetadata-0.5.5}/src/pymetadata/examples/results/test_from_omex.omex +0 -0
- {pymetadata-0.5.3 → pymetadata-0.5.5}/src/pymetadata/examples/results/testomex/README.md +0 -0
- {pymetadata-0.5.3 → pymetadata-0.5.5}/src/pymetadata/examples/results/testomex/manifest.xml +0 -0
- {pymetadata-0.5.3 → pymetadata-0.5.5}/src/pymetadata/examples/results/testomex/models/omex_comp.xml +0 -0
- {pymetadata-0.5.3 → pymetadata-0.5.5}/src/pymetadata/examples/results/testomex/models/omex_comp_flat.xml +0 -0
- {pymetadata-0.5.3 → pymetadata-0.5.5}/src/pymetadata/examples/results/testomex/models/omex_minimal.xml +0 -0
- {pymetadata-0.5.3 → pymetadata-0.5.5}/src/pymetadata/examples/test.omex +0 -0
- {pymetadata-0.5.3 → pymetadata-0.5.5}/src/pymetadata/identifiers/__init__.py +0 -0
- {pymetadata-0.5.3 → pymetadata-0.5.5}/src/pymetadata/identifiers/miriam.py +0 -0
- {pymetadata-0.5.3 → pymetadata-0.5.5}/src/pymetadata/log.py +0 -0
- {pymetadata-0.5.3 → pymetadata-0.5.5}/src/pymetadata/metadata/__init__.py +0 -0
- {pymetadata-0.5.3 → pymetadata-0.5.5}/src/pymetadata/metadata/kisao.py +0 -0
- {pymetadata-0.5.3 → pymetadata-0.5.5}/src/pymetadata/metadata/sbo.py +0 -0
- {pymetadata-0.5.3 → pymetadata-0.5.5}/src/pymetadata/omex.py +0 -0
- {pymetadata-0.5.3 → pymetadata-0.5.5}/src/pymetadata/omex_v2.py +0 -0
- {pymetadata-0.5.3 → pymetadata-0.5.5}/src/pymetadata/ontologies/__init__.py +0 -0
- {pymetadata-0.5.3 → pymetadata-0.5.5}/src/pymetadata/ontologies/ols.py +0 -0
- {pymetadata-0.5.3 → pymetadata-0.5.5}/src/pymetadata/ontologies/ontology.py +0 -0
- {pymetadata-0.5.3 → pymetadata-0.5.5}/src/pymetadata/py.typed +0 -0
- {pymetadata-0.5.3 → pymetadata-0.5.5}/src/pymetadata/resources/ontologies/README.md +0 -0
- {pymetadata-0.5.3 → pymetadata-0.5.5}/src/pymetadata/resources/templates/ontology_enum.pytemplate +0 -0
- {pymetadata-0.5.3 → pymetadata-0.5.5}/src/pymetadata/unichem.py +0 -0
- {pymetadata-0.5.3 → pymetadata-0.5.5}/tests/core/test_creator.py +0 -0
- {pymetadata-0.5.3 → pymetadata-0.5.5}/tests/data/omex/BIOMD0000000001.omex +0 -0
- {pymetadata-0.5.3 → pymetadata-0.5.5}/tests/data/omex/CombineArchiveShowCase.omex +0 -0
- {pymetadata-0.5.3 → pymetadata-0.5.5}/tests/data/omex/CombineArchiveShowCase_manifest.xml +0 -0
- {pymetadata-0.5.3 → pymetadata-0.5.5}/tests/data/omex/CompModels.omex +0 -0
- {pymetadata-0.5.3 → pymetadata-0.5.5}/tests/data/omex/CompModels_manifest.xml +0 -0
- {pymetadata-0.5.3 → pymetadata-0.5.5}/tests/data/omex/iCGB21FR.omex +0 -0
- {pymetadata-0.5.3 → pymetadata-0.5.5}/tests/test_chebi.py +0 -0
- {pymetadata-0.5.3 → pymetadata-0.5.5}/tests/test_ols.py +0 -0
- {pymetadata-0.5.3 → pymetadata-0.5.5}/tests/test_omex.py +0 -0
- {pymetadata-0.5.3 → pymetadata-0.5.5}/tests/test_ontology.py +0 -0
- {pymetadata-0.5.3 → pymetadata-0.5.5}/tests/test_registry.py +0 -0
- {pymetadata-0.5.3 → pymetadata-0.5.5}/tests/test_sbo_kisao.py +0 -0
- {pymetadata-0.5.3 → pymetadata-0.5.5}/tests/test_unichem.py +0 -0
- {pymetadata-0.5.3 → pymetadata-0.5.5}/tox.ini +0 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
3.13
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: pymetadata
|
|
3
|
-
Version: 0.5.
|
|
3
|
+
Version: 0.5.5
|
|
4
4
|
Summary: pymetadata are python utilities for working with metadata.
|
|
5
5
|
Author-email: Matthias König <konigmatt@googlemail.com>
|
|
6
6
|
Maintainer-email: Matthias König <konigmatt@googlemail.com>
|
|
@@ -27,16 +27,15 @@ Requires-Dist: pydantic>=2.10.4
|
|
|
27
27
|
Requires-Dist: requests>=2.32.3
|
|
28
28
|
Requires-Dist: rich>=13.9.4
|
|
29
29
|
Requires-Dist: xmltodict>=0.14.2
|
|
30
|
-
Requires-Dist: zeep>=4.3.1
|
|
31
30
|
Provides-Extra: dev
|
|
32
|
-
Requires-Dist: bump-my-version>=
|
|
33
|
-
Requires-Dist: mypy>=1.
|
|
31
|
+
Requires-Dist: bump-my-version>=1.2.4; extra == 'dev'
|
|
32
|
+
Requires-Dist: mypy>=1.18.2; extra == 'dev'
|
|
34
33
|
Requires-Dist: pre-commit>=4.0.1; extra == 'dev'
|
|
35
|
-
Requires-Dist: ruff>=0.
|
|
34
|
+
Requires-Dist: ruff>=0.14.0; extra == 'dev'
|
|
36
35
|
Provides-Extra: test
|
|
37
|
-
Requires-Dist: pytest-cov>=
|
|
38
|
-
Requires-Dist: pytest>=8.
|
|
39
|
-
Requires-Dist: tox>=4.
|
|
36
|
+
Requires-Dist: pytest-cov>=7.0.0; extra == 'test'
|
|
37
|
+
Requires-Dist: pytest>=8.4.2; extra == 'test'
|
|
38
|
+
Requires-Dist: tox>=4.31.0; extra == 'test'
|
|
40
39
|
Description-Content-Type: text/markdown
|
|
41
40
|
|
|
42
41
|

|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
Composite annotations are semantic annotations that are comprised of multiple annotation
|
|
4
4
|
terms linked using standard qualifiers (also known as “relations” or “predicates”)
|
|
5
|
-
to indicate the meaning of
|
|
5
|
+
to indicate the meaning of annotation.
|
|
6
6
|
Composite annotations are used when a single knowledge resource term is not available to
|
|
7
7
|
sufficiently define a model or data element. For model-component annotations,
|
|
8
8
|
composite annotations have two primary components:
|
|
@@ -40,7 +40,6 @@ dependencies = [
|
|
|
40
40
|
"lxml>=5.3",
|
|
41
41
|
"rich>=13.9.4",
|
|
42
42
|
"requests>=2.32.3",
|
|
43
|
-
"zeep>=4.3.1",
|
|
44
43
|
"pronto>=2.5.8",
|
|
45
44
|
"fastobo>=0.12.3",
|
|
46
45
|
"jinja2>=3.1.5",
|
|
@@ -50,15 +49,15 @@ dependencies = [
|
|
|
50
49
|
|
|
51
50
|
[project.optional-dependencies]
|
|
52
51
|
dev = [
|
|
53
|
-
"bump-my-version>=
|
|
54
|
-
"ruff>=0.
|
|
52
|
+
"bump-my-version>=1.2.4",
|
|
53
|
+
"ruff>=0.14.0",
|
|
55
54
|
"pre-commit>=4.0.1",
|
|
56
|
-
"mypy>=1.
|
|
55
|
+
"mypy>=1.18.2",
|
|
57
56
|
]
|
|
58
57
|
test = [
|
|
59
|
-
"tox>=4.
|
|
60
|
-
"pytest>=8.
|
|
61
|
-
"pytest-cov>=
|
|
58
|
+
"tox>=4.31.0",
|
|
59
|
+
"pytest>=8.4.2",
|
|
60
|
+
"pytest-cov>=7.0.0",
|
|
62
61
|
]
|
|
63
62
|
|
|
64
63
|
[project_urls]
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
# Release notes for pymetadata 0.5.4
|
|
2
|
+

|
|
3
|
+
|
|
4
|
+
We are pleased to release the next version of pymetadata including the
|
|
5
|
+
following changes:
|
|
6
|
+
|
|
7
|
+
## Features & fixes
|
|
8
|
+
- bugfix for annotations with "/"
|
|
9
|
+
- fixing webservices for Chebi 2.0 (#61)
|
|
10
|
+
|
|
11
|
+
Your pymetadata team
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
# Release notes for pymetadata 0.5.5
|
|
2
|
+

|
|
3
|
+
|
|
4
|
+
We are pleased to release the next version of pymetadata including the
|
|
5
|
+
following changes:
|
|
6
|
+
|
|
7
|
+
## Features & fixes
|
|
8
|
+
- remove custom namespaces (#62)
|
|
9
|
+
- better support of compact identifiers.org identifiers (#63)
|
|
10
|
+
- support of bioregistry.io as provider (#40)
|
|
11
|
+
- updated ECO ontology
|
|
12
|
+
|
|
13
|
+
Your pymetadata team
|
|
@@ -1,28 +1,19 @@
|
|
|
1
1
|
"""Module for working with chebi."""
|
|
2
2
|
|
|
3
3
|
from pathlib import Path
|
|
4
|
-
from pprint import pprint
|
|
5
4
|
from typing import Any, Dict, Optional
|
|
6
|
-
|
|
7
|
-
from zeep import Client
|
|
8
|
-
|
|
5
|
+
import requests
|
|
9
6
|
|
|
10
7
|
import pymetadata
|
|
11
8
|
from pymetadata import log
|
|
12
9
|
from pymetadata.cache import DataclassJSONEncoder, read_json_cache, write_json_cache
|
|
10
|
+
from pymetadata.console import console
|
|
13
11
|
|
|
14
12
|
logger = log.get_logger(__name__)
|
|
15
13
|
|
|
16
|
-
# FIXME: copy the file to the cache dir
|
|
17
|
-
client = Client(str(pymetadata.RESOURCES_DIR / "chebi_webservice_wsdl.xml"))
|
|
18
|
-
|
|
19
14
|
|
|
20
15
|
class ChebiQuery:
|
|
21
|
-
"""Class to query information from ChEBI.
|
|
22
|
-
|
|
23
|
-
An overview over available methods:
|
|
24
|
-
python -mzeep https://www.ebi.ac.uk/webservices/chebi/2.0/webservice?wsdl
|
|
25
|
-
"""
|
|
16
|
+
"""Class to query information from ChEBI."""
|
|
26
17
|
|
|
27
18
|
@staticmethod
|
|
28
19
|
def query(
|
|
@@ -52,27 +43,28 @@ class ChebiQuery:
|
|
|
52
43
|
|
|
53
44
|
# fetch and cache data
|
|
54
45
|
if not data:
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
46
|
+
response = requests.get(
|
|
47
|
+
url=f"https://www.ebi.ac.uk/chebi/backend/api/public/compounds/?chebi_ids={chebi}"
|
|
48
|
+
)
|
|
49
|
+
if response.status_code == 200:
|
|
50
|
+
result = response.json()
|
|
51
|
+
else:
|
|
59
52
|
logger.error(f"CHEBI information could not be retrieved for: {chebi}")
|
|
60
53
|
return dict()
|
|
61
54
|
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
if formulae:
|
|
66
|
-
formula = formulae[0]["data"]
|
|
67
|
-
|
|
55
|
+
result = result[chebi]["data"]
|
|
56
|
+
chemical_data = result["chemical_data"]
|
|
57
|
+
default_structure = result["default_structure"]
|
|
68
58
|
data = {
|
|
69
59
|
"chebi": chebi,
|
|
70
|
-
"name": result["
|
|
60
|
+
"name": result["ascii_name"],
|
|
71
61
|
"definition": result["definition"],
|
|
72
|
-
"formula": formula,
|
|
73
|
-
"charge":
|
|
74
|
-
"mass":
|
|
75
|
-
"inchikey":
|
|
62
|
+
"formula": chemical_data["formula"] if chemical_data else None,
|
|
63
|
+
"charge": chemical_data["charge"] if chemical_data else None,
|
|
64
|
+
"mass": chemical_data["mass"] if chemical_data else None,
|
|
65
|
+
"inchikey": default_structure["standard_inchi_key"]
|
|
66
|
+
if default_structure
|
|
67
|
+
else None,
|
|
76
68
|
}
|
|
77
69
|
|
|
78
70
|
logger.info(f"Write chebi: {chebi_path}")
|
|
@@ -86,7 +78,7 @@ class ChebiQuery:
|
|
|
86
78
|
if __name__ == "__main__":
|
|
87
79
|
chebis = ["CHEBI:2668", "CHEBI:138366", "CHEBI:9637", "CHEBI:155897"]
|
|
88
80
|
for chebi in chebis:
|
|
89
|
-
|
|
81
|
+
console.rule(chebi, align="left", style="bold white")
|
|
90
82
|
d = ChebiQuery.query(chebi=chebi, cache=False)
|
|
91
|
-
|
|
83
|
+
console.print(d)
|
|
92
84
|
d = ChebiQuery.query(chebi=chebi, cache=True)
|
|
@@ -5,12 +5,14 @@ Core data structure to store annotations.
|
|
|
5
5
|
|
|
6
6
|
import re
|
|
7
7
|
import urllib
|
|
8
|
+
from enum import Enum
|
|
8
9
|
from pprint import pprint
|
|
9
10
|
from typing import Any, Dict, Final, List, Optional, Tuple, Union
|
|
10
11
|
|
|
11
12
|
import requests
|
|
12
13
|
|
|
13
14
|
from pymetadata import log
|
|
15
|
+
from pymetadata.console import console
|
|
14
16
|
from pymetadata.core.xref import CrossReference, is_url
|
|
15
17
|
from pymetadata.identifiers.miriam import BQB, BQM
|
|
16
18
|
from pymetadata.identifiers.registry import REGISTRY
|
|
@@ -19,19 +21,31 @@ from pymetadata.ontologies.ols import ONTOLOGIES, OLSQuery
|
|
|
19
21
|
|
|
20
22
|
OLS_QUERY = OLSQuery(ontologies=ONTOLOGIES)
|
|
21
23
|
|
|
22
|
-
IDENTIFIERS_ORG_PREFIX: Final = "
|
|
24
|
+
IDENTIFIERS_ORG_PREFIX: Final = "https://identifiers.org"
|
|
23
25
|
IDENTIFIERS_ORG_PATTERN1: Final = re.compile(r"^https?://identifiers.org/(.+?)/(.+)")
|
|
24
26
|
IDENTIFIERS_ORG_PATTERN2: Final = re.compile(r"^https?://identifiers.org/(.+)")
|
|
27
|
+
|
|
28
|
+
BIOREGISTRY_PREFIX: Final = "https://bioregistry.io"
|
|
29
|
+
BIOREGISTRY_PATTERN: Final = re.compile(r"^https?://bioregistry.io/(.+)")
|
|
30
|
+
|
|
25
31
|
MIRIAM_URN_PATTERN: Final = re.compile(r"^urn:miriam:(.+)")
|
|
26
32
|
|
|
27
33
|
logger = log.get_logger(__name__)
|
|
28
34
|
|
|
29
35
|
|
|
36
|
+
class ProviderType(str, Enum):
|
|
37
|
+
"""Provider type."""
|
|
38
|
+
|
|
39
|
+
IDENTIFIERS_ORG = "identifiers.org"
|
|
40
|
+
BIOREGISTRY_IO = "bioregistry.io"
|
|
41
|
+
NONE = "none"
|
|
42
|
+
|
|
43
|
+
|
|
30
44
|
class RDFAnnotation:
|
|
31
45
|
"""RDFAnnotation class.
|
|
32
46
|
|
|
33
47
|
Basic storage of annotation information. This consists of the relation
|
|
34
|
-
and the
|
|
48
|
+
and the resource.
|
|
35
49
|
The annotations can be attached to other objects thereby forming
|
|
36
50
|
triples which can be converted to RDF.
|
|
37
51
|
|
|
@@ -40,6 +54,7 @@ class RDFAnnotation:
|
|
|
40
54
|
- `collection/term`, i.e., the combination of collection and term
|
|
41
55
|
- `http(s)://arbitrary.url`, an arbitrary URL
|
|
42
56
|
- urn:miriam:uniprot:P03023
|
|
57
|
+
- https://bioregistry.io/chebi:15996 urls via the bioregistry provider
|
|
43
58
|
"""
|
|
44
59
|
|
|
45
60
|
replaced_collections: Dict[str, str] = {
|
|
@@ -53,6 +68,7 @@ class RDFAnnotation:
|
|
|
53
68
|
self.collection: Optional[str] = None
|
|
54
69
|
self.term: Optional[str] = None
|
|
55
70
|
self.resource: str = resource
|
|
71
|
+
self.provider: ProviderType = ProviderType.IDENTIFIERS_ORG
|
|
56
72
|
|
|
57
73
|
if not qualifier:
|
|
58
74
|
raise ValueError(
|
|
@@ -75,15 +91,19 @@ class RDFAnnotation:
|
|
|
75
91
|
if match1:
|
|
76
92
|
# handle identifiers.org pattern
|
|
77
93
|
self.collection, self.term = match1.group(1), match1.group(2)
|
|
94
|
+
self.provider = ProviderType.IDENTIFIERS_ORG
|
|
78
95
|
|
|
79
96
|
if not self.collection:
|
|
80
|
-
# tests new
|
|
97
|
+
# tests new compact patterns
|
|
81
98
|
match2 = IDENTIFIERS_ORG_PATTERN2.match(resource)
|
|
82
99
|
if match2:
|
|
83
100
|
tokens = match2.group(1).split(":")
|
|
84
101
|
if len(tokens) == 2:
|
|
85
102
|
self.collection = tokens[0].lower()
|
|
103
|
+
|
|
104
|
+
# check if the namespace is embedded
|
|
86
105
|
self.term = match2.group(1)
|
|
106
|
+
self.provider = ProviderType.IDENTIFIERS_ORG
|
|
87
107
|
else:
|
|
88
108
|
logger.warning(
|
|
89
109
|
f"Identifiers.org URL does not conform to new"
|
|
@@ -94,16 +114,25 @@ class RDFAnnotation:
|
|
|
94
114
|
# other urls are directly stored as resources without collection
|
|
95
115
|
self.collection = None
|
|
96
116
|
self.term = resource
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
117
|
+
if BIOREGISTRY_PATTERN.match(resource):
|
|
118
|
+
self.provider = ProviderType.BIOREGISTRY_IO
|
|
119
|
+
console.print(self.provider)
|
|
120
|
+
else:
|
|
121
|
+
self.provider = ProviderType.NONE
|
|
122
|
+
logger.warning(
|
|
123
|
+
f"{resource} does not conform to "
|
|
124
|
+
f"http(s)://identifiers.org/collection/id or http(s)://identifiers.org/id or "
|
|
125
|
+
f"https://bioregistry.io/id .",
|
|
126
|
+
)
|
|
127
|
+
|
|
128
|
+
# handle urns
|
|
101
129
|
elif resource.startswith("urn:miriam:"):
|
|
102
130
|
match3 = MIRIAM_URN_PATTERN.match(resource)
|
|
103
131
|
if match3:
|
|
104
132
|
tokens = match3.group(1).split(":")
|
|
105
133
|
self.collection = tokens[0]
|
|
106
134
|
self.term = ":".join(tokens[1:]).replace("%3A", ":")
|
|
135
|
+
self.provider = ProviderType.IDENTIFIERS_ORG
|
|
107
136
|
|
|
108
137
|
logger.warning(
|
|
109
138
|
f"Deprecated urn pattern `{resource}` updated: "
|
|
@@ -113,13 +142,16 @@ class RDFAnnotation:
|
|
|
113
142
|
else:
|
|
114
143
|
# handle short notation
|
|
115
144
|
tokens = resource.split("/")
|
|
116
|
-
if len(tokens)
|
|
145
|
+
if len(tokens) > 1:
|
|
117
146
|
self.collection = tokens[0]
|
|
118
147
|
self.term = "/".join(tokens[1:])
|
|
148
|
+
self.provider = ProviderType.IDENTIFIERS_ORG
|
|
119
149
|
elif len(tokens) == 1 and ":" in tokens[0]:
|
|
120
150
|
self.collection = tokens[0].split(":")[0].lower()
|
|
121
151
|
self.term = tokens[0]
|
|
152
|
+
self.provider = ProviderType.IDENTIFIERS_ORG
|
|
122
153
|
|
|
154
|
+
# validation
|
|
123
155
|
if len(tokens) < 2 and not self.collection:
|
|
124
156
|
logger.error(
|
|
125
157
|
f"Resource `{resource}` could not be split in collection and term. "
|
|
@@ -129,6 +161,13 @@ class RDFAnnotation:
|
|
|
129
161
|
)
|
|
130
162
|
self.collection = None
|
|
131
163
|
self.term = resource
|
|
164
|
+
self.provider = ProviderType.NONE
|
|
165
|
+
|
|
166
|
+
# shorten compact terms
|
|
167
|
+
if self.term and self.collection:
|
|
168
|
+
self.term = self.shorten_compact_term(
|
|
169
|
+
term=self.term, collection=self.collection
|
|
170
|
+
)
|
|
132
171
|
|
|
133
172
|
# clean legacy collections
|
|
134
173
|
if self.collection in self.replaced_collections:
|
|
@@ -136,6 +175,21 @@ class RDFAnnotation:
|
|
|
136
175
|
|
|
137
176
|
self.validate()
|
|
138
177
|
|
|
178
|
+
@staticmethod
|
|
179
|
+
def shorten_compact_term(term: str, collection: str) -> str:
|
|
180
|
+
"""Shorten the compact terms and return term.
|
|
181
|
+
|
|
182
|
+
If the namespace is not embeddd in the term return the shortened term.
|
|
183
|
+
"""
|
|
184
|
+
namespace = REGISTRY.ns_dict.get(collection, None)
|
|
185
|
+
if namespace and not namespace.namespaceEmbeddedInLui:
|
|
186
|
+
# shorter term
|
|
187
|
+
if term.lower().startswith(collection):
|
|
188
|
+
tokens = term.split(":")
|
|
189
|
+
term = ":".join(tokens[1:])
|
|
190
|
+
|
|
191
|
+
return term
|
|
192
|
+
|
|
139
193
|
@staticmethod
|
|
140
194
|
def from_tuple(t: Tuple[Union[BQB, BQM], str]) -> "RDFAnnotation":
|
|
141
195
|
"""Construct from tuple."""
|
|
@@ -161,12 +215,12 @@ class RDFAnnotation:
|
|
|
161
215
|
|
|
162
216
|
def __repr__(self) -> str:
|
|
163
217
|
"""Get representation string."""
|
|
164
|
-
return f"RDFAnnotation({self.qualifier}|{self.collection}|{self.term})"
|
|
218
|
+
return f"RDFAnnotation({self.qualifier}|{self.collection}|{self.term}|{self.provider.value})"
|
|
165
219
|
|
|
166
220
|
def to_dict(self) -> Dict:
|
|
167
221
|
"""Convert to dict."""
|
|
168
222
|
return {
|
|
169
|
-
"qualifier": self.qualifier.value,
|
|
223
|
+
"qualifier": self.qualifier.value,
|
|
170
224
|
"collection": self.collection,
|
|
171
225
|
"term": self.term,
|
|
172
226
|
}
|
|
@@ -343,52 +397,59 @@ class RDFAnnotationData(RDFAnnotation):
|
|
|
343
397
|
|
|
344
398
|
if __name__ == "__main__":
|
|
345
399
|
for annotation in [
|
|
346
|
-
# FIXME: support this
|
|
347
400
|
RDFAnnotation(
|
|
348
401
|
qualifier=BQB.IS_VERSION_OF,
|
|
349
|
-
resource="
|
|
350
|
-
),
|
|
351
|
-
RDFAnnotation(
|
|
352
|
-
qualifier=BQB.IS_VERSION_OF,
|
|
353
|
-
resource="taxonomy/562",
|
|
354
|
-
),
|
|
355
|
-
RDFAnnotation(
|
|
356
|
-
qualifier=BQB.IS_VERSION_OF,
|
|
357
|
-
resource="http://identifiers.org/taxonomy/9606",
|
|
358
|
-
),
|
|
359
|
-
RDFAnnotation(
|
|
360
|
-
qualifier=BQB.IS_VERSION_OF,
|
|
361
|
-
resource="http://identifiers.org/biomodels.sbo/SBO:0000247",
|
|
362
|
-
),
|
|
363
|
-
RDFAnnotation(
|
|
364
|
-
qualifier=BQB.IS_VERSION_OF, resource="urn:miriam:obo.go:GO%3A0005623"
|
|
365
|
-
),
|
|
366
|
-
RDFAnnotation(
|
|
367
|
-
qualifier=BQB.IS_VERSION_OF, resource="urn:miriam:chebi:CHEBI%3A33699"
|
|
368
|
-
),
|
|
369
|
-
RDFAnnotation(qualifier=BQB.IS_VERSION_OF, resource="chebi/CHEBI:456215"),
|
|
370
|
-
RDFAnnotation(
|
|
371
|
-
qualifier=BQB.IS, resource="https://en.wikipedia.org/wiki/Cytosol"
|
|
372
|
-
),
|
|
373
|
-
RDFAnnotation(
|
|
374
|
-
qualifier=BQB.IS_VERSION_OF, resource="urn:miriam:uniprot:P03023"
|
|
375
|
-
),
|
|
376
|
-
RDFAnnotation(
|
|
377
|
-
qualifier=BQB.IS_VERSION_OF,
|
|
378
|
-
resource="http://identifiers.org/go/GO:0005829",
|
|
379
|
-
),
|
|
380
|
-
RDFAnnotation(
|
|
381
|
-
qualifier=BQB.IS_VERSION_OF, resource="http://identifiers.org/go/GO:0005829"
|
|
382
|
-
),
|
|
383
|
-
RDFAnnotation(
|
|
384
|
-
qualifier=BQB.IS_VERSION_OF, resource="http://identifiers.org/GO:0005829"
|
|
385
|
-
),
|
|
386
|
-
RDFAnnotation(
|
|
387
|
-
qualifier=BQB.IS_VERSION_OF, resource="http://identifiers.org/GO:0005829"
|
|
402
|
+
resource="https://bioregistry.io/chebi:15996",
|
|
388
403
|
),
|
|
389
|
-
RDFAnnotation(
|
|
390
|
-
|
|
391
|
-
|
|
404
|
+
# RDFAnnotation(
|
|
405
|
+
# qualifier=BQB.IS_VERSION_OF,
|
|
406
|
+
# resource="NCIT:C75913",
|
|
407
|
+
# ),
|
|
408
|
+
# RDFAnnotation(
|
|
409
|
+
# qualifier=BQB.IS_VERSION_OF,
|
|
410
|
+
# resource="ncit:C75913",
|
|
411
|
+
# ),
|
|
412
|
+
# RDFAnnotation(
|
|
413
|
+
# qualifier=BQB.IS_VERSION_OF,
|
|
414
|
+
# resource="taxonomy/562",
|
|
415
|
+
# ),
|
|
416
|
+
# RDFAnnotation(
|
|
417
|
+
# qualifier=BQB.IS_VERSION_OF,
|
|
418
|
+
# resource="http://identifiers.org/taxonomy/9606",
|
|
419
|
+
# ),
|
|
420
|
+
# RDFAnnotation(
|
|
421
|
+
# qualifier=BQB.IS_VERSION_OF,
|
|
422
|
+
# resource="http://identifiers.org/biomodels.sbo/SBO:0000247",
|
|
423
|
+
# ),
|
|
424
|
+
# RDFAnnotation(
|
|
425
|
+
# qualifier=BQB.IS_VERSION_OF, resource="urn:miriam:obo.go:GO%3A0005623"
|
|
426
|
+
# ),
|
|
427
|
+
# RDFAnnotation(
|
|
428
|
+
# qualifier=BQB.IS_VERSION_OF, resource="urn:miriam:chebi:CHEBI%3A33699"
|
|
429
|
+
# ),
|
|
430
|
+
# RDFAnnotation(qualifier=BQB.IS_VERSION_OF, resource="chebi/CHEBI:456215"),
|
|
431
|
+
# RDFAnnotation(
|
|
432
|
+
# qualifier=BQB.IS, resource="https://en.wikipedia.org/wiki/Cytosol"
|
|
433
|
+
# ),
|
|
434
|
+
# RDFAnnotation(
|
|
435
|
+
# qualifier=BQB.IS_VERSION_OF, resource="urn:miriam:uniprot:P03023"
|
|
436
|
+
# ),
|
|
437
|
+
# RDFAnnotation(
|
|
438
|
+
# qualifier=BQB.IS_VERSION_OF,
|
|
439
|
+
# resource="http://identifiers.org/go/GO:0005829",
|
|
440
|
+
# ),
|
|
441
|
+
# RDFAnnotation(
|
|
442
|
+
# qualifier=BQB.IS_VERSION_OF, resource="http://identifiers.org/go/GO:0005829"
|
|
443
|
+
# ),
|
|
444
|
+
# RDFAnnotation(
|
|
445
|
+
# qualifier=BQB.IS_VERSION_OF, resource="http://identifiers.org/GO:0005829"
|
|
446
|
+
# ),
|
|
447
|
+
# RDFAnnotation(
|
|
448
|
+
# qualifier=BQB.IS_VERSION_OF, resource="http://identifiers.org/GO:0005829"
|
|
449
|
+
# ),
|
|
450
|
+
# RDFAnnotation(qualifier=BQB.IS_VERSION_OF, resource="bto/BTO:0000089"),
|
|
451
|
+
# RDFAnnotation(qualifier=BQB.IS_VERSION_OF, resource="BTO:0000089"),
|
|
452
|
+
# RDFAnnotation(qualifier=BQB.IS_VERSION_OF, resource="chebi/CHEBI:000012"),
|
|
392
453
|
]:
|
|
393
454
|
print("-" * 80)
|
|
394
455
|
data = RDFAnnotationData(annotation)
|
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Helper tools to work with identifiers registry.
|
|
3
|
+
|
|
4
|
+
https://identifiers.org/
|
|
5
|
+
https://docs.identifiers.org/articles/api.html
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from __future__ import annotations
|
|
9
|
+
|
|
10
|
+
import inspect
|
|
11
|
+
import os
|
|
12
|
+
import time
|
|
13
|
+
from dataclasses import dataclass, field
|
|
14
|
+
from pathlib import Path
|
|
15
|
+
from typing import Any, Dict, List, Optional
|
|
16
|
+
|
|
17
|
+
import requests
|
|
18
|
+
|
|
19
|
+
import pymetadata
|
|
20
|
+
from pymetadata import log
|
|
21
|
+
from pymetadata.cache import DataclassJSONEncoder, read_json_cache, write_json_cache
|
|
22
|
+
from pymetadata.console import console
|
|
23
|
+
|
|
24
|
+
logger = log.get_logger(__name__)
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
@dataclass
|
|
28
|
+
class Resource:
|
|
29
|
+
"""Resource."""
|
|
30
|
+
|
|
31
|
+
id: Optional[int]
|
|
32
|
+
providerCode: str
|
|
33
|
+
name: str
|
|
34
|
+
urlPattern: str
|
|
35
|
+
mirId: Optional[str] = field(repr=False)
|
|
36
|
+
description: str = field(repr=False)
|
|
37
|
+
official: bool = field(repr=False)
|
|
38
|
+
|
|
39
|
+
sampleId: Optional[str] = field(repr=False)
|
|
40
|
+
resourceHomeUrl: Optional[str] = field(repr=False)
|
|
41
|
+
institution: dict = field(repr=False)
|
|
42
|
+
location: dict = field(repr=False)
|
|
43
|
+
deprecated: bool = field(repr=False)
|
|
44
|
+
deprecationDate: str = field(repr=False)
|
|
45
|
+
protectedUrls: bool = field(repr=False, default=False)
|
|
46
|
+
renderProtectedLanding: bool = field(repr=False, default=False)
|
|
47
|
+
authHelpUrl: Optional[str] = field(repr=False, default=None)
|
|
48
|
+
authHelpDescription: Optional[str] = field(repr=False, default=None)
|
|
49
|
+
|
|
50
|
+
@classmethod
|
|
51
|
+
def from_dict(cls, d: Dict[str, Any]) -> Resource:
|
|
52
|
+
"""Handle additional keyword arguments."""
|
|
53
|
+
return cls(
|
|
54
|
+
**{k: v for k, v in d.items() if k in inspect.signature(cls).parameters}
|
|
55
|
+
)
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
@dataclass
|
|
59
|
+
class Namespace:
|
|
60
|
+
"""Namespace."""
|
|
61
|
+
|
|
62
|
+
id: Optional[str]
|
|
63
|
+
prefix: Optional[str]
|
|
64
|
+
name: str
|
|
65
|
+
pattern: str
|
|
66
|
+
namespaceEmbeddedInLui: bool
|
|
67
|
+
description: str = field(repr=False)
|
|
68
|
+
mirId: Optional[str] = field(repr=False, default=None)
|
|
69
|
+
resources: Optional[List] = field(repr=False, default=None)
|
|
70
|
+
created: Optional[str] = field(repr=False, default=None)
|
|
71
|
+
modified: Optional[str] = field(repr=False, default=None)
|
|
72
|
+
sampleId: Optional[str] = field(repr=False, default=None)
|
|
73
|
+
deprecated: bool = field(repr=False, default=False)
|
|
74
|
+
deprecationDate: Optional[str] = field(repr=False, default=None)
|
|
75
|
+
|
|
76
|
+
@classmethod
|
|
77
|
+
def from_dict(cls, d: Dict[str, Any]) -> Namespace:
|
|
78
|
+
"""Handle additional keyword arguments."""
|
|
79
|
+
return cls(
|
|
80
|
+
**{k: v for k, v in d.items() if k in inspect.signature(cls).parameters}
|
|
81
|
+
)
|
|
82
|
+
|
|
83
|
+
def __post_init__(self) -> None:
|
|
84
|
+
"""Set resources."""
|
|
85
|
+
if self.resources is not None:
|
|
86
|
+
self.resources = [Resource.from_dict(d) for d in self.resources]
|
|
87
|
+
else:
|
|
88
|
+
self.resources = list()
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
class Registry:
|
|
92
|
+
"""Managing the available annotation information.
|
|
93
|
+
|
|
94
|
+
Registry of meta information.
|
|
95
|
+
"""
|
|
96
|
+
|
|
97
|
+
URL = "https://registry.api.identifiers.org/resolutionApi/getResolverDataset"
|
|
98
|
+
|
|
99
|
+
def __init__(
|
|
100
|
+
self,
|
|
101
|
+
cache_duration: int = 24,
|
|
102
|
+
cache: bool = True,
|
|
103
|
+
):
|
|
104
|
+
"""Initialize registry.
|
|
105
|
+
|
|
106
|
+
:param cache_path: Path of cached identifiers.org path
|
|
107
|
+
:param cache_duration: Duration of caching in hours.
|
|
108
|
+
:param cache: boolean flag to stop caching
|
|
109
|
+
"""
|
|
110
|
+
self.registry_path = pymetadata.CACHE_PATH / "identifiers_registry.json"
|
|
111
|
+
|
|
112
|
+
# check if update needed
|
|
113
|
+
if cache:
|
|
114
|
+
if os.path.exists(self.registry_path):
|
|
115
|
+
registry_age = (
|
|
116
|
+
time.time() - os.path.getmtime(self.registry_path)
|
|
117
|
+
) / 3600 # [hr]
|
|
118
|
+
update = registry_age > cache_duration
|
|
119
|
+
else:
|
|
120
|
+
update = True
|
|
121
|
+
else:
|
|
122
|
+
update = True
|
|
123
|
+
|
|
124
|
+
self.ns_dict: Dict[str, Namespace] = (
|
|
125
|
+
self.update() if update else Registry.load_registry(self.registry_path)
|
|
126
|
+
)
|
|
127
|
+
|
|
128
|
+
def update(self) -> Dict[str, Namespace]:
|
|
129
|
+
"""Update registry."""
|
|
130
|
+
Registry.update_registry(registry_path=self.registry_path)
|
|
131
|
+
return Registry.load_registry(registry_path=self.registry_path)
|
|
132
|
+
|
|
133
|
+
@staticmethod
|
|
134
|
+
def update_registry(
|
|
135
|
+
registry_path: Optional[Path] = None,
|
|
136
|
+
) -> Dict[str, Namespace]:
|
|
137
|
+
"""Update registry from identifiers.org webservice."""
|
|
138
|
+
logger.info(f"Update registry from '{Registry.URL}'")
|
|
139
|
+
response = requests.get(Registry.URL)
|
|
140
|
+
namespaces = response.json()["payload"]["namespaces"]
|
|
141
|
+
|
|
142
|
+
ns_dict = {}
|
|
143
|
+
for _, data in enumerate(namespaces):
|
|
144
|
+
ns = Namespace.from_dict(data)
|
|
145
|
+
ns_dict[ns.prefix] = ns
|
|
146
|
+
|
|
147
|
+
if registry_path is not None:
|
|
148
|
+
write_json_cache(
|
|
149
|
+
data=ns_dict,
|
|
150
|
+
cache_path=registry_path,
|
|
151
|
+
json_encoder=DataclassJSONEncoder,
|
|
152
|
+
)
|
|
153
|
+
|
|
154
|
+
return ns_dict # type: ignore
|
|
155
|
+
|
|
156
|
+
@staticmethod
|
|
157
|
+
def load_registry(registry_path: Path) -> Dict[str, Namespace]:
|
|
158
|
+
"""Load namespaces with resources from path."""
|
|
159
|
+
if not registry_path.exists():
|
|
160
|
+
Registry.update_registry(registry_path=registry_path)
|
|
161
|
+
|
|
162
|
+
d = read_json_cache(cache_path=registry_path)
|
|
163
|
+
if not d:
|
|
164
|
+
raise ValueError("Registry could not be loaded from cache.")
|
|
165
|
+
|
|
166
|
+
return {k: Namespace(**v) for k, v in d.items()}
|
|
167
|
+
|
|
168
|
+
|
|
169
|
+
REGISTRY = Registry()
|
|
170
|
+
|
|
171
|
+
if __name__ == "__main__":
|
|
172
|
+
registry = Registry(cache=False)
|
|
173
|
+
console.print(registry.ns_dict)
|