pysec2pri 0.2.2__tar.gz → 0.2.4__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.
- {pysec2pri-0.2.2 → pysec2pri-0.2.4}/PKG-INFO +19 -10
- {pysec2pri-0.2.2 → pysec2pri-0.2.4}/README.md +17 -8
- {pysec2pri-0.2.2 → pysec2pri-0.2.4}/pyproject.toml +3 -3
- {pysec2pri-0.2.2 → pysec2pri-0.2.4}/src/pysec2pri/__init__.py +22 -0
- {pysec2pri-0.2.2 → pysec2pri-0.2.4}/src/pysec2pri/api.py +130 -85
- {pysec2pri-0.2.2 → pysec2pri-0.2.4}/src/pysec2pri/cli.py +8 -20
- {pysec2pri-0.2.2 → pysec2pri-0.2.4}/src/pysec2pri/config/ensembl.yaml +1 -2
- {pysec2pri-0.2.2 → pysec2pri-0.2.4}/src/pysec2pri/config/hgnc.yaml +1 -2
- {pysec2pri-0.2.2 → pysec2pri-0.2.4}/src/pysec2pri/config/ncbi.yaml +1 -2
- {pysec2pri-0.2.2 → pysec2pri-0.2.4}/src/pysec2pri/consolidate.py +54 -116
- {pysec2pri-0.2.2 → pysec2pri-0.2.4}/src/pysec2pri/downloads/ensembl.py +12 -4
- {pysec2pri-0.2.2 → pysec2pri-0.2.4}/src/pysec2pri/parsers/chebi.py +3 -4
- {pysec2pri-0.2.2 → pysec2pri-0.2.4}/src/pysec2pri/parsers/vgnc.py +2 -3
- {pysec2pri-0.2.2 → pysec2pri-0.2.4}/src/pysec2pri/version.py +1 -1
- {pysec2pri-0.2.2 → pysec2pri-0.2.4}/LICENSE +0 -0
- {pysec2pri-0.2.2 → pysec2pri-0.2.4}/src/pysec2pri/__main__.py +0 -0
- {pysec2pri-0.2.2 → pysec2pri-0.2.4}/src/pysec2pri/config/__init__.py +0 -0
- {pysec2pri-0.2.2 → pysec2pri-0.2.4}/src/pysec2pri/config/chebi.yaml +0 -0
- {pysec2pri-0.2.2 → pysec2pri-0.2.4}/src/pysec2pri/config/hmdb_metabolites.yaml +0 -0
- {pysec2pri-0.2.2 → pysec2pri-0.2.4}/src/pysec2pri/config/hmdb_proteins.yaml +0 -0
- {pysec2pri-0.2.2 → pysec2pri-0.2.4}/src/pysec2pri/config/uniprot.yaml +0 -0
- {pysec2pri-0.2.2 → pysec2pri-0.2.4}/src/pysec2pri/config/vgnc.yaml +0 -0
- {pysec2pri-0.2.2 → pysec2pri-0.2.4}/src/pysec2pri/config/wikidata.yaml +0 -0
- {pysec2pri-0.2.2 → pysec2pri-0.2.4}/src/pysec2pri/constants.py +0 -0
- {pysec2pri-0.2.2 → pysec2pri-0.2.4}/src/pysec2pri/download.py +0 -0
- {pysec2pri-0.2.2 → pysec2pri-0.2.4}/src/pysec2pri/downloads/__init__.py +0 -0
- {pysec2pri-0.2.2 → pysec2pri-0.2.4}/src/pysec2pri/downloads/chebi.py +0 -0
- {pysec2pri-0.2.2 → pysec2pri-0.2.4}/src/pysec2pri/downloads/hgnc.py +0 -0
- {pysec2pri-0.2.2 → pysec2pri-0.2.4}/src/pysec2pri/downloads/hmdb.py +0 -0
- {pysec2pri-0.2.2 → pysec2pri-0.2.4}/src/pysec2pri/downloads/ncbi.py +0 -0
- {pysec2pri-0.2.2 → pysec2pri-0.2.4}/src/pysec2pri/downloads/uniprot.py +0 -0
- {pysec2pri-0.2.2 → pysec2pri-0.2.4}/src/pysec2pri/exports.py +0 -0
- {pysec2pri-0.2.2 → pysec2pri-0.2.4}/src/pysec2pri/logging.py +0 -0
- {pysec2pri-0.2.2 → pysec2pri-0.2.4}/src/pysec2pri/parsers/__init__.py +0 -0
- {pysec2pri-0.2.2 → pysec2pri-0.2.4}/src/pysec2pri/parsers/base.py +0 -0
- {pysec2pri-0.2.2 → pysec2pri-0.2.4}/src/pysec2pri/parsers/ensembl.py +0 -0
- {pysec2pri-0.2.2 → pysec2pri-0.2.4}/src/pysec2pri/parsers/hgnc.py +0 -0
- {pysec2pri-0.2.2 → pysec2pri-0.2.4}/src/pysec2pri/parsers/hmdb.py +0 -0
- {pysec2pri-0.2.2 → pysec2pri-0.2.4}/src/pysec2pri/parsers/ncbi.py +0 -0
- {pysec2pri-0.2.2 → pysec2pri-0.2.4}/src/pysec2pri/parsers/uniprot.py +0 -0
- {pysec2pri-0.2.2 → pysec2pri-0.2.4}/src/pysec2pri/parsers/wikidata.py +0 -0
- {pysec2pri-0.2.2 → pysec2pri-0.2.4}/src/pysec2pri/py.typed +0 -0
- {pysec2pri-0.2.2 → pysec2pri-0.2.4}/src/pysec2pri/queries/__init__.py +0 -0
- {pysec2pri-0.2.2 → pysec2pri-0.2.4}/src/pysec2pri/queries/chemical_redirects.rq +0 -0
- {pysec2pri-0.2.2 → pysec2pri-0.2.4}/src/pysec2pri/queries/chemical_redirects_test.rq +0 -0
- {pysec2pri-0.2.2 → pysec2pri-0.2.4}/src/pysec2pri/queries/gene_redirects.rq +0 -0
- {pysec2pri-0.2.2 → pysec2pri-0.2.4}/src/pysec2pri/queries/gene_redirects_test.rq +0 -0
- {pysec2pri-0.2.2 → pysec2pri-0.2.4}/src/pysec2pri/queries/protein_redirects.rq +0 -0
- {pysec2pri-0.2.2 → pysec2pri-0.2.4}/src/pysec2pri/queries/protein_redirects_test.rq +0 -0
- {pysec2pri-0.2.2 → pysec2pri-0.2.4}/src/pysec2pri/update_ids.py +0 -0
- {pysec2pri-0.2.2 → pysec2pri-0.2.4}/src/pysec2pri/xref.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: pysec2pri
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.4
|
|
4
4
|
Summary: Secondary to primary identifier mapping
|
|
5
5
|
Keywords: snekpack,cookiecutter
|
|
6
6
|
Author: Javier Millán Acosta
|
|
@@ -40,7 +40,7 @@ Requires-Dist: numpy
|
|
|
40
40
|
Requires-Dist: rdkit
|
|
41
41
|
Requires-Dist: polars-runtime-32
|
|
42
42
|
Requires-Dist: sssom-schema==1.1.0a5
|
|
43
|
-
Requires-Dist: mapkgsutils
|
|
43
|
+
Requires-Dist: mapkgsutils==0.1.2
|
|
44
44
|
Maintainer: Javier Millán Acosta
|
|
45
45
|
Maintainer-email: Javier Millán Acosta <javier.millan.acosta@gmail.com>
|
|
46
46
|
Requires-Python: >=3.10
|
|
@@ -182,6 +182,15 @@ pysec2pri hgnc ids # outputs hgnc_{version}_sssom.tsv
|
|
|
182
182
|
pysec2pri update-ids gene_ex.tsv hgnc --at gene --mapping hgnc_{version}_sssom.tsv
|
|
183
183
|
```
|
|
184
184
|
|
|
185
|
+
In Python, `load_<datasource>` reads a written SSSOM file back into the same
|
|
186
|
+
`IdMappingSet`/`LabelMappingSet`:
|
|
187
|
+
|
|
188
|
+
```python
|
|
189
|
+
from pysec2pri import load_hgnc, update_ids
|
|
190
|
+
hgnc_ms = load_hgnc("hgnc_115_sssom.tsv")
|
|
191
|
+
df_with_new_column = update_ids(mapping_set=hgnc_ms, ids=df, at="gene")
|
|
192
|
+
```
|
|
193
|
+
|
|
185
194
|
Ambiguous mappings (where a deprecated ID or label serves as a recommended for
|
|
186
195
|
another entity) are not resolved, but flagged for users to solve them manually.
|
|
187
196
|
If the input file has a column of known aliases or synonyms for each row, pass
|
|
@@ -234,7 +243,7 @@ mappings.
|
|
|
234
243
|
### Aliases / synonyms
|
|
235
244
|
|
|
236
245
|
Alias mappings use `oboInOwl:hasExactSynonym`. The alias is the `subject_label`
|
|
237
|
-
and the
|
|
246
|
+
and the primary name is the `object_label`/`object_id`.
|
|
238
247
|
|
|
239
248
|
```mermaid
|
|
240
249
|
flowchart LR
|
|
@@ -324,15 +333,15 @@ crosswalk("ENSG00000141510", frm="ensembl", to="symbol") # via HGNC's own cross
|
|
|
324
333
|
### Consolidating mapping dates across releases
|
|
325
334
|
|
|
326
335
|
A single release snapshot only presents each mapping's _last-seen_ date.
|
|
327
|
-
`consolidate` builds a first-seen-date index
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
336
|
+
`consolidate` builds a first-seen-date index and writes it back out as a real
|
|
337
|
+
SSSOM mapping set whose `mapping_date` is each mapping's true first appearance.
|
|
338
|
+
The path is chosen automatically: datasources with a versioned archive are
|
|
339
|
+
walked release by release, while those without one (NCBI, VGNC) are covered in a
|
|
340
|
+
single fast pass over the current release:
|
|
332
341
|
|
|
333
342
|
```bash
|
|
334
|
-
pysec2pri chebi consolidate
|
|
335
|
-
pysec2pri
|
|
343
|
+
pysec2pri chebi consolidate # walks ~250 ChEBI releases (versioned archive); slow, run as a one-off
|
|
344
|
+
pysec2pri ncbi consolidate # single fast pass (no versioned archive)
|
|
336
345
|
```
|
|
337
346
|
|
|
338
347
|
Supported for `chebi`, `ensembl`, `hgnc`, `ncbi`, `uniprot`, and `vgnc`. Ensembl
|
|
@@ -129,6 +129,15 @@ pysec2pri hgnc ids # outputs hgnc_{version}_sssom.tsv
|
|
|
129
129
|
pysec2pri update-ids gene_ex.tsv hgnc --at gene --mapping hgnc_{version}_sssom.tsv
|
|
130
130
|
```
|
|
131
131
|
|
|
132
|
+
In Python, `load_<datasource>` reads a written SSSOM file back into the same
|
|
133
|
+
`IdMappingSet`/`LabelMappingSet`:
|
|
134
|
+
|
|
135
|
+
```python
|
|
136
|
+
from pysec2pri import load_hgnc, update_ids
|
|
137
|
+
hgnc_ms = load_hgnc("hgnc_115_sssom.tsv")
|
|
138
|
+
df_with_new_column = update_ids(mapping_set=hgnc_ms, ids=df, at="gene")
|
|
139
|
+
```
|
|
140
|
+
|
|
132
141
|
Ambiguous mappings (where a deprecated ID or label serves as a recommended for
|
|
133
142
|
another entity) are not resolved, but flagged for users to solve them manually.
|
|
134
143
|
If the input file has a column of known aliases or synonyms for each row, pass
|
|
@@ -181,7 +190,7 @@ mappings.
|
|
|
181
190
|
### Aliases / synonyms
|
|
182
191
|
|
|
183
192
|
Alias mappings use `oboInOwl:hasExactSynonym`. The alias is the `subject_label`
|
|
184
|
-
and the
|
|
193
|
+
and the primary name is the `object_label`/`object_id`.
|
|
185
194
|
|
|
186
195
|
```mermaid
|
|
187
196
|
flowchart LR
|
|
@@ -271,15 +280,15 @@ crosswalk("ENSG00000141510", frm="ensembl", to="symbol") # via HGNC's own cross
|
|
|
271
280
|
### Consolidating mapping dates across releases
|
|
272
281
|
|
|
273
282
|
A single release snapshot only presents each mapping's _last-seen_ date.
|
|
274
|
-
`consolidate` builds a first-seen-date index
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
283
|
+
`consolidate` builds a first-seen-date index and writes it back out as a real
|
|
284
|
+
SSSOM mapping set whose `mapping_date` is each mapping's true first appearance.
|
|
285
|
+
The path is chosen automatically: datasources with a versioned archive are
|
|
286
|
+
walked release by release, while those without one (NCBI, VGNC) are covered in a
|
|
287
|
+
single fast pass over the current release:
|
|
279
288
|
|
|
280
289
|
```bash
|
|
281
|
-
pysec2pri chebi consolidate
|
|
282
|
-
pysec2pri
|
|
290
|
+
pysec2pri chebi consolidate # walks ~250 ChEBI releases (versioned archive); slow, run as a one-off
|
|
291
|
+
pysec2pri ncbi consolidate # single fast pass (no versioned archive)
|
|
283
292
|
```
|
|
284
293
|
|
|
285
294
|
Supported for `chebi`, `ensembl`, `hgnc`, `ncbi`, `uniprot`, and `vgnc`. Ensembl
|
|
@@ -7,7 +7,7 @@ build-backend = "uv_build"
|
|
|
7
7
|
|
|
8
8
|
[project]
|
|
9
9
|
name = "pysec2pri"
|
|
10
|
-
version = "0.2.
|
|
10
|
+
version = "0.2.4"
|
|
11
11
|
description = "Secondary to primary identifier mapping"
|
|
12
12
|
readme = "README.md"
|
|
13
13
|
authors = [
|
|
@@ -71,7 +71,7 @@ dependencies = [
|
|
|
71
71
|
"rdkit", # Chemistry toolkit for SDF parsing
|
|
72
72
|
"polars-runtime-32", # Polars runtime for 32-bit systems
|
|
73
73
|
"sssom-schema==1.1.0a5", # SSSOM schema for validation
|
|
74
|
-
"mapkgsutils
|
|
74
|
+
"mapkgsutils==0.1.2",
|
|
75
75
|
]
|
|
76
76
|
|
|
77
77
|
# see https://peps.python.org/pep-0735/ and https://docs.astral.sh/uv/concepts/dependencies/#dependency-groups
|
|
@@ -255,7 +255,7 @@ known-first-party = [
|
|
|
255
255
|
docstring-code-format = true
|
|
256
256
|
|
|
257
257
|
[tool.bumpversion]
|
|
258
|
-
current_version = "0.2.
|
|
258
|
+
current_version = "0.2.4"
|
|
259
259
|
parse = "(?P<major>\\d+)\\.(?P<minor>\\d+)\\.(?P<patch>\\d+)(?:-(?P<release>[0-9A-Za-z-]+(?:\\.[0-9A-Za-z-]+)*))?(?:\\+(?P<build>[0-9A-Za-z-]+(?:\\.[0-9A-Za-z-]+)*))?"
|
|
260
260
|
serialize = [
|
|
261
261
|
"{major}.{minor}.{patch}-{release}+{build}",
|
|
@@ -33,6 +33,17 @@ from pysec2pri.api import (
|
|
|
33
33
|
generate_wikidata,
|
|
34
34
|
generate_wikidata_labels,
|
|
35
35
|
list_versions,
|
|
36
|
+
load_chebi,
|
|
37
|
+
load_ensembl,
|
|
38
|
+
load_hgnc,
|
|
39
|
+
load_hmdb,
|
|
40
|
+
load_hmdb_proteins,
|
|
41
|
+
load_label_mapping,
|
|
42
|
+
load_mapping,
|
|
43
|
+
load_ncbi,
|
|
44
|
+
load_uniprot,
|
|
45
|
+
load_vgnc,
|
|
46
|
+
load_wikidata,
|
|
36
47
|
resolve_ids,
|
|
37
48
|
resolve_labels,
|
|
38
49
|
write_json,
|
|
@@ -101,6 +112,17 @@ __all__ = [
|
|
|
101
112
|
"generate_wikidata",
|
|
102
113
|
"generate_wikidata_labels",
|
|
103
114
|
"list_versions",
|
|
115
|
+
"load_chebi",
|
|
116
|
+
"load_ensembl",
|
|
117
|
+
"load_hgnc",
|
|
118
|
+
"load_hmdb",
|
|
119
|
+
"load_hmdb_proteins",
|
|
120
|
+
"load_label_mapping",
|
|
121
|
+
"load_mapping",
|
|
122
|
+
"load_ncbi",
|
|
123
|
+
"load_uniprot",
|
|
124
|
+
"load_vgnc",
|
|
125
|
+
"load_wikidata",
|
|
104
126
|
"load_xref_mapping",
|
|
105
127
|
"resolve_ambiguous_with_hints",
|
|
106
128
|
"resolve_ids",
|
|
@@ -86,8 +86,17 @@ __all__ = [
|
|
|
86
86
|
"generate_wikidata_labels",
|
|
87
87
|
"generate_wikidata_labels",
|
|
88
88
|
"list_versions",
|
|
89
|
+
"load_chebi",
|
|
90
|
+
"load_ensembl",
|
|
91
|
+
"load_hgnc",
|
|
92
|
+
"load_hmdb",
|
|
93
|
+
"load_hmdb_proteins",
|
|
89
94
|
"load_label_mapping",
|
|
90
95
|
"load_mapping",
|
|
96
|
+
"load_ncbi",
|
|
97
|
+
"load_uniprot",
|
|
98
|
+
"load_vgnc",
|
|
99
|
+
"load_wikidata",
|
|
91
100
|
"load_xref_mapping",
|
|
92
101
|
"resolve_ids",
|
|
93
102
|
"resolve_labels",
|
|
@@ -244,8 +253,7 @@ def generate_hgnc_primary_ids(
|
|
|
244
253
|
Only the HGNC complete set file is downloaded/read. The returned mapping
|
|
245
254
|
set has an empty ``mappings`` list; its ``_primary_ids`` store is
|
|
246
255
|
populated with every current HGNC ID so that ``to_pri_ids()`` produces
|
|
247
|
-
the
|
|
248
|
-
happen to have an associated secondary.
|
|
256
|
+
the complete list.
|
|
249
257
|
|
|
250
258
|
Args:
|
|
251
259
|
input_path: Local HGNC complete set TSV. Auto-downloaded if ``None``.
|
|
@@ -1112,9 +1120,7 @@ def generate_ensembl_label_history(
|
|
|
1112
1120
|
previous-symbol -> current-symbol transitions are derived by diffing
|
|
1113
1121
|
each release's primary-label snapshot per stable ID. Delegates to
|
|
1114
1122
|
:func:`pysec2pri.consolidate.build_label_history`, which walks every
|
|
1115
|
-
historical release (or a bounded range) and resumes on re-run.
|
|
1116
|
-
a network-heavy, run-on-demand operation, not part of normal
|
|
1117
|
-
single-release generation.
|
|
1123
|
+
historical release (or a bounded range) and resumes on re-run.
|
|
1118
1124
|
|
|
1119
1125
|
Args:
|
|
1120
1126
|
species: Canonical NCBI taxon ID (default ``9606`` for human).
|
|
@@ -1506,95 +1512,139 @@ def write_diff_output(
|
|
|
1506
1512
|
|
|
1507
1513
|
|
|
1508
1514
|
def load_mapping(path: Path | str) -> IdMappingSet:
|
|
1509
|
-
"""Load an ID mapping set from
|
|
1515
|
+
"""Load an ID mapping set from an SSSOM TSV file.
|
|
1510
1516
|
|
|
1511
|
-
|
|
1512
|
-
|
|
1513
|
-
(comment-prefixed metadata lines are skipped automatically).
|
|
1517
|
+
Produces the same :class:`~pysec2pri.parsers.base.IdMappingSet` a fresh
|
|
1518
|
+
parse would, ready to pass to :func:`resolve_ids`.
|
|
1514
1519
|
|
|
1515
1520
|
Args:
|
|
1516
|
-
path: Path to the TSV file to load.
|
|
1517
|
-
|
|
1518
|
-
Returns:
|
|
1519
|
-
An :class:`~pysec2pri.parsers.base.IdMappingSet` populated from the
|
|
1520
|
-
file, ready to pass to :func:`resolve_ids`.
|
|
1521
|
+
path: Path to the SSSOM TSV file to load.
|
|
1521
1522
|
"""
|
|
1522
|
-
|
|
1523
|
-
from sssom_schema import Mapping
|
|
1523
|
+
from mapkgsutils.exports import read_sssom
|
|
1524
1524
|
|
|
1525
|
-
path =
|
|
1526
|
-
df = pd.read_csv(path, sep="\t", dtype=str, comment="#")
|
|
1527
|
-
ms = IdMappingSet(
|
|
1528
|
-
mapping_set_id=str(path),
|
|
1529
|
-
license="https://creativecommons.org/licenses/by/4.0/",
|
|
1530
|
-
)
|
|
1531
|
-
mappings: list[Mapping] = []
|
|
1532
|
-
for _, row in df.iterrows():
|
|
1533
|
-
m = Mapping(
|
|
1534
|
-
subject_id=row.get("subject_id") or "",
|
|
1535
|
-
object_id=row.get("object_id") or "",
|
|
1536
|
-
predicate_id=row.get("predicate_id") or "",
|
|
1537
|
-
mapping_justification=row.get("mapping_justification")
|
|
1538
|
-
or "semapv:BackgroundKnowledgeBasedMatching",
|
|
1539
|
-
mapping_cardinality=row.get("mapping_cardinality") or None,
|
|
1540
|
-
)
|
|
1541
|
-
mappings.append(m)
|
|
1542
|
-
ms.mappings = mappings
|
|
1543
|
-
return ms
|
|
1525
|
+
return read_sssom(path, mapping_set_class=IdMappingSet, on="id")
|
|
1544
1526
|
|
|
1545
1527
|
|
|
1546
1528
|
def load_label_mapping(path: Path | str) -> LabelMappingSet:
|
|
1547
|
-
"""Load a label
|
|
1529
|
+
"""Load a label mapping set from an SSSOM TSV file.
|
|
1530
|
+
|
|
1531
|
+
Produces the same :class:`~pysec2pri.parsers.base.LabelMappingSet` a fresh
|
|
1532
|
+
parse would, ready to pass to :func:`resolve_labels`.
|
|
1533
|
+
|
|
1534
|
+
Args:
|
|
1535
|
+
path: Path to the SSSOM TSV file to load.
|
|
1536
|
+
"""
|
|
1537
|
+
from mapkgsutils.exports import read_sssom
|
|
1548
1538
|
|
|
1549
|
-
|
|
1539
|
+
return read_sssom(path, mapping_set_class=LabelMappingSet, on="label")
|
|
1550
1540
|
|
|
1551
|
-
- **New** (``label_sec2pri`` tabular output): ``secondary_id``,
|
|
1552
|
-
``secondary_label``, ``primary_id``, ``primary_label``,
|
|
1553
|
-
``predicate_id``, ``mapping_cardinality``.
|
|
1554
|
-
- **Legacy** (SSSOM or old tabular output): ``subject_id``,
|
|
1555
|
-
``subject_label``, ``object_id``, ``object_label``, ``predicate_id``.
|
|
1556
1541
|
|
|
1557
|
-
|
|
1542
|
+
def load_chebi(path: Path | str, *, mapping_type: str | None = None) -> BaseMappingSet:
|
|
1543
|
+
"""Load a ChEBI SSSOM file into the proper mapping set object.
|
|
1558
1544
|
|
|
1559
1545
|
Args:
|
|
1560
|
-
path: Path to the TSV file
|
|
1546
|
+
path: Path to the SSSOM TSV file.
|
|
1547
|
+
mapping_type: ``"id"``/``"label"`` to force the class, else inferred.
|
|
1548
|
+
"""
|
|
1549
|
+
from pysec2pri.parsers import ChEBIParser
|
|
1561
1550
|
|
|
1562
|
-
|
|
1563
|
-
|
|
1564
|
-
|
|
1551
|
+
return ChEBIParser().load(path, mapping_type=mapping_type)
|
|
1552
|
+
|
|
1553
|
+
|
|
1554
|
+
def load_ensembl(path: Path | str, *, mapping_type: str | None = None) -> BaseMappingSet:
|
|
1555
|
+
"""Load an Ensembl SSSOM file into the proper mapping set object.
|
|
1556
|
+
|
|
1557
|
+
Args:
|
|
1558
|
+
path: Path to the SSSOM TSV file.
|
|
1559
|
+
mapping_type: ``"id"``/``"label"`` to force the class, else inferred.
|
|
1565
1560
|
"""
|
|
1566
|
-
|
|
1567
|
-
from sssom_schema import Mapping
|
|
1561
|
+
from pysec2pri.parsers import EnsemblParser
|
|
1568
1562
|
|
|
1569
|
-
path =
|
|
1570
|
-
df = pd.read_csv(path, sep="\t", dtype=str, comment="#")
|
|
1571
|
-
ms = LabelMappingSet(
|
|
1572
|
-
mapping_set_id=str(path),
|
|
1573
|
-
license="https://creativecommons.org/licenses/by/4.0/",
|
|
1574
|
-
)
|
|
1563
|
+
return EnsemblParser().load(path, mapping_type=mapping_type)
|
|
1575
1564
|
|
|
1576
|
-
|
|
1577
|
-
|
|
1578
|
-
|
|
1579
|
-
|
|
1580
|
-
|
|
1581
|
-
|
|
1582
|
-
|
|
1583
|
-
|
|
1584
|
-
|
|
1585
|
-
|
|
1586
|
-
|
|
1587
|
-
|
|
1588
|
-
|
|
1589
|
-
|
|
1590
|
-
|
|
1591
|
-
|
|
1592
|
-
|
|
1593
|
-
|
|
1594
|
-
|
|
1595
|
-
|
|
1596
|
-
|
|
1597
|
-
|
|
1565
|
+
|
|
1566
|
+
def load_hgnc(path: Path | str, *, mapping_type: str | None = None) -> BaseMappingSet:
|
|
1567
|
+
"""Load an HGNC SSSOM file into the proper mapping set object.
|
|
1568
|
+
|
|
1569
|
+
Args:
|
|
1570
|
+
path: Path to the SSSOM TSV file.
|
|
1571
|
+
mapping_type: ``"id"``/``"label"`` to force the class, else inferred.
|
|
1572
|
+
"""
|
|
1573
|
+
from pysec2pri.parsers import HGNCParser
|
|
1574
|
+
|
|
1575
|
+
return HGNCParser().load(path, mapping_type=mapping_type)
|
|
1576
|
+
|
|
1577
|
+
|
|
1578
|
+
def load_ncbi(path: Path | str, *, mapping_type: str | None = None) -> BaseMappingSet:
|
|
1579
|
+
"""Load an NCBI SSSOM file into the proper mapping set object.
|
|
1580
|
+
|
|
1581
|
+
Args:
|
|
1582
|
+
path: Path to the SSSOM TSV file.
|
|
1583
|
+
mapping_type: ``"id"``/``"label"`` to force the class, else inferred.
|
|
1584
|
+
"""
|
|
1585
|
+
from pysec2pri.parsers import NCBIParser
|
|
1586
|
+
|
|
1587
|
+
return NCBIParser().load(path, mapping_type=mapping_type)
|
|
1588
|
+
|
|
1589
|
+
|
|
1590
|
+
def load_uniprot(path: Path | str, *, mapping_type: str | None = None) -> BaseMappingSet:
|
|
1591
|
+
"""Load a UniProt SSSOM file into the proper mapping set object.
|
|
1592
|
+
|
|
1593
|
+
Args:
|
|
1594
|
+
path: Path to the SSSOM TSV file.
|
|
1595
|
+
mapping_type: ``"id"``/``"label"`` to force the class, else inferred.
|
|
1596
|
+
"""
|
|
1597
|
+
from pysec2pri.parsers import UniProtParser
|
|
1598
|
+
|
|
1599
|
+
return UniProtParser().load(path, mapping_type=mapping_type)
|
|
1600
|
+
|
|
1601
|
+
|
|
1602
|
+
def load_vgnc(path: Path | str, *, mapping_type: str | None = None) -> BaseMappingSet:
|
|
1603
|
+
"""Load a VGNC SSSOM file into the proper mapping set object.
|
|
1604
|
+
|
|
1605
|
+
Args:
|
|
1606
|
+
path: Path to the SSSOM TSV file.
|
|
1607
|
+
mapping_type: ``"id"``/``"label"`` to force the class, else inferred.
|
|
1608
|
+
"""
|
|
1609
|
+
from pysec2pri.parsers import VGNCParser
|
|
1610
|
+
|
|
1611
|
+
return VGNCParser().load(path, mapping_type=mapping_type)
|
|
1612
|
+
|
|
1613
|
+
|
|
1614
|
+
def load_hmdb(path: Path | str, *, mapping_type: str | None = None) -> BaseMappingSet:
|
|
1615
|
+
"""Load an HMDB metabolite SSSOM file into the proper mapping set object.
|
|
1616
|
+
|
|
1617
|
+
Args:
|
|
1618
|
+
path: Path to the SSSOM TSV file.
|
|
1619
|
+
mapping_type: ``"id"``/``"label"`` to force the class, else inferred.
|
|
1620
|
+
"""
|
|
1621
|
+
from pysec2pri.parsers import HMDBMetaboliteParser
|
|
1622
|
+
|
|
1623
|
+
return HMDBMetaboliteParser().load(path, mapping_type=mapping_type)
|
|
1624
|
+
|
|
1625
|
+
|
|
1626
|
+
def load_hmdb_proteins(path: Path | str, *, mapping_type: str | None = None) -> BaseMappingSet:
|
|
1627
|
+
"""Load an HMDB protein SSSOM file into the proper mapping set object.
|
|
1628
|
+
|
|
1629
|
+
Args:
|
|
1630
|
+
path: Path to the SSSOM TSV file.
|
|
1631
|
+
mapping_type: ``"id"``/``"label"`` to force the class, else inferred.
|
|
1632
|
+
"""
|
|
1633
|
+
from pysec2pri.parsers import HMDBProteinParser
|
|
1634
|
+
|
|
1635
|
+
return HMDBProteinParser().load(path, mapping_type=mapping_type)
|
|
1636
|
+
|
|
1637
|
+
|
|
1638
|
+
def load_wikidata(path: Path | str, *, mapping_type: str | None = None) -> BaseMappingSet:
|
|
1639
|
+
"""Load a Wikidata SSSOM file into the proper mapping set object.
|
|
1640
|
+
|
|
1641
|
+
Args:
|
|
1642
|
+
path: Path to the SSSOM TSV file.
|
|
1643
|
+
mapping_type: ``"id"``/``"label"`` to force the class, else inferred.
|
|
1644
|
+
"""
|
|
1645
|
+
from pysec2pri.parsers import WikidataParser
|
|
1646
|
+
|
|
1647
|
+
return WikidataParser().load(path, mapping_type=mapping_type)
|
|
1598
1648
|
|
|
1599
1649
|
|
|
1600
1650
|
def resolve_ids(
|
|
@@ -2015,15 +2065,10 @@ def crosswalk(
|
|
|
2015
2065
|
) -> dict[str, str] | pd.DataFrame:
|
|
2016
2066
|
r"""Map a gene identifier from one vocabulary to another, via HGNC.
|
|
2017
2067
|
|
|
2018
|
-
|
|
2019
|
-
resolves through :func:`generate_hgnc_labels` +
|
|
2068
|
+
Wrapper: ``frm="symbol"`` resolves through :func:`generate_hgnc_labels` +
|
|
2020
2069
|
:func:`~pysec2pri.update_ids.update_labels`, so a *previous* HGNC symbol
|
|
2021
|
-
still resolves to its current identity (the temporal aspect) and
|
|
2022
|
-
|
|
2023
|
-
guessed. ``frm`` in ``"ensembl"``, ``"entrez"``, ``"refseq"``, or
|
|
2024
|
-
``"uniprot"`` resolves through HGNC's own cross-reference crosswalk
|
|
2025
|
-
table, downloaded from the ``xref_sources`` declared in
|
|
2026
|
-
``config/hgnc.yaml`` unless *xref_mapping* is supplied explicitly.
|
|
2070
|
+
still resolves to its current identity (the temporal aspect) and an ambiguous
|
|
2071
|
+
label is left blank and reported rather than guessed.
|
|
2027
2072
|
|
|
2028
2073
|
Args:
|
|
2029
2074
|
input_data: A single identifier string, a list of identifier
|
|
@@ -638,7 +638,6 @@ def _make_consolidate_cmd(cfg_id: str, extra_opts: list[Callable[..., Any]]) ->
|
|
|
638
638
|
"""Return a decorated (but not yet click.command-wrapped) ``consolidate`` callable."""
|
|
639
639
|
|
|
640
640
|
def _cmd(
|
|
641
|
-
mode: str,
|
|
642
641
|
mapping_sets: str,
|
|
643
642
|
cache_dir: Path | None,
|
|
644
643
|
force: bool,
|
|
@@ -651,12 +650,11 @@ def _make_consolidate_cmd(cfg_id: str, extra_opts: list[Callable[..., Any]]) ->
|
|
|
651
650
|
extras = ", ".join(f"{k}={v}" for k, v in extra_kwargs.items() if v is not None)
|
|
652
651
|
click.echo(
|
|
653
652
|
f"Consolidating {cfg_id.upper()} mapping dates "
|
|
654
|
-
f"(
|
|
653
|
+
f"({extras + ', ' if extras else ''}{mapping_sets})..."
|
|
655
654
|
)
|
|
656
655
|
try:
|
|
657
656
|
path, _ = consolidate_mapping_dates(
|
|
658
657
|
cfg_id,
|
|
659
|
-
mode=mode,
|
|
660
658
|
cache_dir=cache_dir,
|
|
661
659
|
mapping_sets=mapping_sets,
|
|
662
660
|
show_progress=not no_progress,
|
|
@@ -669,17 +667,6 @@ def _make_consolidate_cmd(cfg_id: str, extra_opts: list[Callable[..., Any]]) ->
|
|
|
669
667
|
click.echo(f"Wrote consolidated mapping set -> {output or _sssom_output_path(path)}")
|
|
670
668
|
|
|
671
669
|
decorators: list[Callable[..., Any]] = [
|
|
672
|
-
click.option(
|
|
673
|
-
"--mode",
|
|
674
|
-
default="release",
|
|
675
|
-
show_default=True,
|
|
676
|
-
type=click.Choice(["release", "date"]),
|
|
677
|
-
help=(
|
|
678
|
-
"'release': walk every historical release for the first-seen version/date. "
|
|
679
|
-
"'date': single pass using the source's own per-row date (falls back to "
|
|
680
|
-
"'release' with a warning if the source has none)."
|
|
681
|
-
),
|
|
682
|
-
),
|
|
683
670
|
*extra_opts,
|
|
684
671
|
click.option(
|
|
685
672
|
"--mapping-sets",
|
|
@@ -727,12 +714,13 @@ def _register_consolidate_commands(parent: click.Group) -> None:
|
|
|
727
714
|
"Build/update the per-mapping first-seen-date index, written as a real "
|
|
728
715
|
"SSSOM mapping set whose mapping_date is each mapping's date of first "
|
|
729
716
|
"appearance.\n\n"
|
|
730
|
-
"
|
|
731
|
-
"
|
|
732
|
-
"
|
|
733
|
-
"manual/one-off operation, not
|
|
734
|
-
"
|
|
735
|
-
"
|
|
717
|
+
"For datasources with a versioned archive (ChEBI, Ensembl, HGNC, "
|
|
718
|
+
"UniProt), walks every historical release once to discover the earliest "
|
|
719
|
+
"release each mapping appeared in. This is slow and network-heavy (~250 "
|
|
720
|
+
"releases for ChEBI); meant to be run as a manual/one-off operation, not "
|
|
721
|
+
"as part of normal mapping generation. For datasources without one "
|
|
722
|
+
"(NCBI, VGNC), a single current-release pass captures the source's own "
|
|
723
|
+
"per-row date directly (fast)."
|
|
736
724
|
),
|
|
737
725
|
)(raw_cmd)
|
|
738
726
|
)
|
|
@@ -504,5 +504,4 @@ xref_sources:
|
|
|
504
504
|
refseq: "RefSeq IDs"
|
|
505
505
|
uniprot: "UniProt ID(supplied by UniProt)"
|
|
506
506
|
note:
|
|
507
|
-
"Source of truth for cross-references varies; this is a suggested default
|
|
508
|
-
not authoritative."
|
|
507
|
+
"Source of truth for cross-references varies; this is a suggested default."
|
|
@@ -142,8 +142,7 @@ xref_sources:
|
|
|
142
142
|
refseq: "RefSeq IDs"
|
|
143
143
|
uniprot: "UniProt ID(supplied by UniProt)"
|
|
144
144
|
note:
|
|
145
|
-
"Source of truth for cross-references varies; this is a suggested default
|
|
146
|
-
not authoritative."
|
|
145
|
+
"Source of truth for cross-references varies; this is a suggested default"
|
|
147
146
|
|
|
148
147
|
mapping_sets:
|
|
149
148
|
ids:
|
|
@@ -165,5 +165,4 @@ xref_sources:
|
|
|
165
165
|
refseq: "RefSeq IDs"
|
|
166
166
|
uniprot: "UniProt ID(supplied by UniProt)"
|
|
167
167
|
note:
|
|
168
|
-
"Source of truth for cross-references varies; this is a suggested default
|
|
169
|
-
not authoritative."
|
|
168
|
+
"Source of truth for cross-references varies; this is a suggested default"
|
|
@@ -40,7 +40,6 @@ import json
|
|
|
40
40
|
import os
|
|
41
41
|
import shutil
|
|
42
42
|
import tempfile
|
|
43
|
-
import warnings
|
|
44
43
|
from collections.abc import Callable, Iterable
|
|
45
44
|
from pathlib import Path
|
|
46
45
|
from typing import Any
|
|
@@ -60,7 +59,7 @@ __all__ = [
|
|
|
60
59
|
]
|
|
61
60
|
|
|
62
61
|
# Datasources this module knows how to download+parse per release.
|
|
63
|
-
# NCBI and VGNC have no versioned archive, so
|
|
62
|
+
# NCBI and VGNC have no versioned archive, so they take the single-parse path.
|
|
64
63
|
SUPPORTED_DATASOURCES = ("chebi", "ensembl", "hgnc", "ncbi", "uniprot", "vgnc")
|
|
65
64
|
|
|
66
65
|
# mapping_sets kinds each datasource's parser actually supports.
|
|
@@ -100,7 +99,8 @@ def _uniprot_versions(**kwargs: Any) -> list[str]:
|
|
|
100
99
|
return UniProtDownloader().list_versions()
|
|
101
100
|
|
|
102
101
|
|
|
103
|
-
# Datasources with a versioned archive that can be walked
|
|
102
|
+
# Datasources with a versioned archive that can be walked release by release.
|
|
103
|
+
# Datasources absent here (NCBI, VGNC) take the single-parse path instead.
|
|
104
104
|
_LIST_VERSIONS_FNS: dict[str, Callable[..., list[str]]] = {
|
|
105
105
|
"chebi": _chebi_versions,
|
|
106
106
|
"ensembl": _ensembl_versions,
|
|
@@ -167,53 +167,6 @@ def _save_optional_output(mapping_set: BaseMappingSet, output: Path | None) -> N
|
|
|
167
167
|
mapping_set.save("sssom", output)
|
|
168
168
|
|
|
169
169
|
|
|
170
|
-
def _consolidate_by_date_full(
|
|
171
|
-
cache_path: Path,
|
|
172
|
-
meta_path: Path,
|
|
173
|
-
*,
|
|
174
|
-
run_one_version: Callable[[], Any],
|
|
175
|
-
) -> bool:
|
|
176
|
-
"""Date mode that caches the *full* mapping set, not just dated rows.
|
|
177
|
-
|
|
178
|
-
:func:`mapkgsutils.consolidate.consolidate_by_date` keeps only rows that
|
|
179
|
-
carry a real per-row ``mapping_date`` and drops the rest, so a single
|
|
180
|
-
parse of e.g. HGNC labels would cache only its ~12k dated previous-symbol
|
|
181
|
-
mappings and lose the ~48k alias mappings. This builds a complete cache
|
|
182
|
-
from one (current) parse: every mapping is kept, stamped with its own
|
|
183
|
-
per-row date when present and left undated otherwise (exactly how the
|
|
184
|
-
release walk treats an unresolvable date).
|
|
185
|
-
|
|
186
|
-
Returns ``True`` (cache written) when the parse yields at least one real
|
|
187
|
-
per-row date, and ``False`` (cache untouched) when it yields none -- so
|
|
188
|
-
date-less sources (ChEBI, UniProt) still fall back to a release walk
|
|
189
|
-
rather than caching a fully undated set.
|
|
190
|
-
"""
|
|
191
|
-
mapping_set = run_one_version()
|
|
192
|
-
mappings = mapping_set.mappings or []
|
|
193
|
-
if not any(getattr(m, "mapping_date", None) for m in mappings):
|
|
194
|
-
return False
|
|
195
|
-
|
|
196
|
-
version_label = str(getattr(mapping_set, "mapping_set_version", None) or "current")
|
|
197
|
-
records: dict[str, dict[str, str]] = {}
|
|
198
|
-
for m in mappings:
|
|
199
|
-
# record_id is release-scoped; its trailing 16 hex chars are the
|
|
200
|
-
# version-independent pair hash (see mapkgsutils.parsers.base.pair_hash).
|
|
201
|
-
pair_key = str(getattr(m, "record_id", None) or "")[-16:]
|
|
202
|
-
if not pair_key:
|
|
203
|
-
continue
|
|
204
|
-
date_str = str(m.mapping_date) if getattr(m, "mapping_date", None) else ""
|
|
205
|
-
records[pair_key] = {
|
|
206
|
-
"first_seen_version": version_label,
|
|
207
|
-
"first_seen_date": date_str,
|
|
208
|
-
"last_seen_version": version_label,
|
|
209
|
-
"last_seen_date": date_str,
|
|
210
|
-
"fields_json": _consolidate._mapping_fields_json(m),
|
|
211
|
-
}
|
|
212
|
-
_write_cache(cache_path, records)
|
|
213
|
-
_write_meta(meta_path, version_label)
|
|
214
|
-
return True
|
|
215
|
-
|
|
216
|
-
|
|
217
170
|
def load_mapping_dates(
|
|
218
171
|
datasource: str,
|
|
219
172
|
cache_dir: Path | None = None,
|
|
@@ -435,7 +388,6 @@ def _write_consolidated_sssom(
|
|
|
435
388
|
def consolidate_mapping_dates(
|
|
436
389
|
datasource: str,
|
|
437
390
|
*,
|
|
438
|
-
mode: str = "release",
|
|
439
391
|
cache_dir: Path | None = None,
|
|
440
392
|
mapping_sets: str = "ids",
|
|
441
393
|
show_progress: bool = True,
|
|
@@ -445,40 +397,35 @@ def consolidate_mapping_dates(
|
|
|
445
397
|
) -> tuple[Path, BaseMappingSet]:
|
|
446
398
|
"""Build/update the first-seen-date index for *datasource*.
|
|
447
399
|
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
Either way, alongside the internal cache file this also writes a
|
|
468
|
-
companion real SSSOM mapping set (see :func:`_sssom_output_path`) where
|
|
469
|
-
every row's ``mapping_date`` is its true first-seen date, rather than
|
|
470
|
-
whichever release happened to be parsed last.
|
|
400
|
+
Collects every mapping using all available provenance. The walk shape is
|
|
401
|
+
chosen automatically by data availability, not by a requested mode:
|
|
402
|
+
|
|
403
|
+
- Datasources **with** a versioned archive (ChEBI, Ensembl, HGNC,
|
|
404
|
+
UniProt): walk every historical release once (oldest first, resuming
|
|
405
|
+
from the last completed version unless *force*). For every mapping
|
|
406
|
+
seen, records the version/date it first appeared and keeps bumping the
|
|
407
|
+
version/date it was last seen. Slow and network-heavy (~250 releases
|
|
408
|
+
for ChEBI); meant to be run manually/as a one-off.
|
|
409
|
+
- Datasources **without** one (NCBI, VGNC): a single current parse
|
|
410
|
+
caching the *full* mapping set — every mapping kept, stamped with its
|
|
411
|
+
own per-row ``mapping_date`` when the parser provides one and left
|
|
412
|
+
undated otherwise. Fast, no historical walk.
|
|
413
|
+
|
|
414
|
+
Alongside the internal cache file this also writes a companion real SSSOM
|
|
415
|
+
mapping set (see :func:`_sssom_output_path`) where each row's
|
|
416
|
+
``mapping_date`` is its per-row date when present, else its first-seen
|
|
417
|
+
release date — distinct from the first-seen release version carried in
|
|
418
|
+
``subject_source_version``/``object_source_version``.
|
|
471
419
|
|
|
472
420
|
Args:
|
|
473
421
|
datasource: One of :data:`SUPPORTED_DATASOURCES`.
|
|
474
|
-
mode: ``"release"`` or ``"date"``.
|
|
475
422
|
cache_dir: Directory to write the cache file. Defaults to
|
|
476
423
|
:func:`default_cache_dir`.
|
|
477
424
|
mapping_sets: ``"ids"`` or ``"labels"``.
|
|
478
425
|
show_progress: Whether to show a progress bar over releases
|
|
479
|
-
(
|
|
426
|
+
(versioned-archive datasources only).
|
|
480
427
|
force: Re-scan every release from scratch, ignoring any existing
|
|
481
|
-
cache/resume state (
|
|
428
|
+
cache/resume state (versioned-archive datasources only).
|
|
482
429
|
output: Optional path to also write the consolidated SSSOM mapping
|
|
483
430
|
set to. The internal cache-adjacent copy (see
|
|
484
431
|
:func:`_sssom_output_path`) is always written; when *output* is
|
|
@@ -493,13 +440,9 @@ def consolidate_mapping_dates(
|
|
|
493
440
|
written alongside it) and the in-memory consolidated mapping set.
|
|
494
441
|
|
|
495
442
|
Raises:
|
|
496
|
-
ValueError: For an
|
|
497
|
-
|
|
498
|
-
``mode="release"`` against a datasource with no versioned
|
|
499
|
-
archive.
|
|
443
|
+
ValueError: For an unsupported *datasource* or an unsupported
|
|
444
|
+
*mapping_sets* for *datasource*.
|
|
500
445
|
"""
|
|
501
|
-
if mode not in ("release", "date"):
|
|
502
|
-
raise ValueError(f"mode must be 'release' or 'date', got {mode!r}")
|
|
503
446
|
if datasource not in SUPPORTED_DATASOURCES:
|
|
504
447
|
raise ValueError(
|
|
505
448
|
f"Unsupported datasource: {datasource!r}. Supported: {SUPPORTED_DATASOURCES}"
|
|
@@ -524,41 +467,36 @@ def consolidate_mapping_dates(
|
|
|
524
467
|
cache_path = _cache_path(cache_dir, datasource, mapping_sets, **kwargs)
|
|
525
468
|
meta_path = _meta_path(cache_dir, datasource, mapping_sets, **kwargs)
|
|
526
469
|
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
cache_path,
|
|
530
|
-
meta_path,
|
|
531
|
-
run_one_version=lambda: _run_one_version(datasource, None, mapping_sets, **kwargs),
|
|
532
|
-
)
|
|
533
|
-
if got_dates:
|
|
534
|
-
_, mapping_set = _write_consolidated_sssom(
|
|
535
|
-
datasource, mapping_sets, cache_path, meta_path
|
|
536
|
-
)
|
|
537
|
-
_save_optional_output(mapping_set, output)
|
|
538
|
-
return cache_path, mapping_set
|
|
539
|
-
msg = (
|
|
540
|
-
f"{datasource!r} has no parseable per-row mapping dates; "
|
|
541
|
-
"falling back to mode='release'."
|
|
542
|
-
)
|
|
543
|
-
logger.warning(msg)
|
|
544
|
-
warnings.warn(msg, UserWarning, stacklevel=2)
|
|
470
|
+
def _run(version: str | None) -> Any:
|
|
471
|
+
return _run_one_version(datasource, version, mapping_sets, **kwargs)
|
|
545
472
|
|
|
546
473
|
list_versions_fn = _LIST_VERSIONS_FNS.get(datasource)
|
|
547
474
|
if list_versions_fn is None:
|
|
548
|
-
|
|
475
|
+
# No versioned archive (NCBI, VGNC): single current parse, full set.
|
|
476
|
+
_consolidate.consolidate(
|
|
477
|
+
cache_path,
|
|
478
|
+
meta_path,
|
|
479
|
+
label=datasource,
|
|
480
|
+
run_one_version=_run,
|
|
481
|
+
show_progress=show_progress,
|
|
482
|
+
force=force,
|
|
483
|
+
)
|
|
484
|
+
else:
|
|
485
|
+
# Versioned archive: walk every historical release for first-seen dates.
|
|
486
|
+
from pysec2pri.download import resolve_release_date
|
|
549
487
|
|
|
550
|
-
|
|
488
|
+
fn = list_versions_fn
|
|
489
|
+
_consolidate.consolidate(
|
|
490
|
+
cache_path,
|
|
491
|
+
meta_path,
|
|
492
|
+
label=datasource,
|
|
493
|
+
run_one_version=_run,
|
|
494
|
+
list_versions=lambda: fn(**kwargs),
|
|
495
|
+
resolve_release_date=lambda v: resolve_release_date(datasource, v, **kwargs),
|
|
496
|
+
show_progress=show_progress,
|
|
497
|
+
force=force,
|
|
498
|
+
)
|
|
551
499
|
|
|
552
|
-
_consolidate.consolidate_by_release(
|
|
553
|
-
cache_path,
|
|
554
|
-
meta_path,
|
|
555
|
-
label=datasource,
|
|
556
|
-
list_versions=lambda: list_versions_fn(**kwargs),
|
|
557
|
-
run_one_version=lambda v: _run_one_version(datasource, v, mapping_sets, **kwargs),
|
|
558
|
-
resolve_release_date=lambda v: resolve_release_date(datasource, v, **kwargs),
|
|
559
|
-
show_progress=show_progress,
|
|
560
|
-
force=force,
|
|
561
|
-
)
|
|
562
500
|
_, mapping_set = _write_consolidated_sssom(datasource, mapping_sets, cache_path, meta_path)
|
|
563
501
|
_save_optional_output(mapping_set, output)
|
|
564
502
|
return cache_path, mapping_set
|
|
@@ -632,8 +570,8 @@ def build_label_history(
|
|
|
632
570
|
previous release's, oldest to newest. Network-heavy and resumable --
|
|
633
571
|
meant to be run on demand, not as part of normal mapping generation
|
|
634
572
|
(mirrors the release-walk pattern in
|
|
635
|
-
:func:`mapkgsutils.consolidate.
|
|
636
|
-
|
|
573
|
+
:func:`mapkgsutils.consolidate.consolidate`, but tracks a carried label
|
|
574
|
+
map instead of first/last-seen dates).
|
|
637
575
|
|
|
638
576
|
Args:
|
|
639
577
|
datasource: Currently only ``"ensembl"`` is supported.
|
|
@@ -709,7 +647,7 @@ def build_label_history(
|
|
|
709
647
|
shutil.rmtree(tmpdir, ignore_errors=True)
|
|
710
648
|
|
|
711
649
|
release_date = resolve_release_date(datasource, v, species=species)
|
|
712
|
-
# Unlike
|
|
650
|
+
# Unlike the consolidate walk's plain-dict cache, these rows become
|
|
713
651
|
# real Mapping objects -- mapping_date must be a valid date or None,
|
|
714
652
|
# never the raw (non-date-shaped) version string.
|
|
715
653
|
date_str = release_date.date().isoformat() if release_date else None
|
|
@@ -375,8 +375,16 @@ def urls_and_date(
|
|
|
375
375
|
urls = _get_ensembl_urls_for_version(version, species=species)
|
|
376
376
|
logger.info("Ensembl version %s (species %s): %s", version, species, urls)
|
|
377
377
|
else:
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
378
|
+
# The release number is global across species, but the URLs (and the
|
|
379
|
+
# resolved release date) are species-specific, so resolve the latest
|
|
380
|
+
# version and build URLs for the requested species rather than reusing
|
|
381
|
+
# check_ensembl_release()'s human-only URLs.
|
|
382
|
+
versions = EnsemblDownloader(show_progress=False).list_versions()
|
|
383
|
+
if not versions:
|
|
384
|
+
raise ValueError("Could not find Ensembl releases on the FTP server")
|
|
385
|
+
version = versions[-1]
|
|
386
|
+
urls = _get_ensembl_urls_for_version(version, species=species)
|
|
387
|
+
check_url = urls.get("stable_id_event")
|
|
388
|
+
release_date = get_file_last_modified(check_url) if check_url else None
|
|
389
|
+
logger.info("Ensembl release %s (species %s): %s", version, species, urls)
|
|
382
390
|
return urls, release_date
|
|
@@ -190,8 +190,7 @@ class ChEBIParser(BaseParser):
|
|
|
190
190
|
Reads ``compounds.tsv`` (TSV releases >= 245) to extract every current
|
|
191
191
|
ChEBI compound ID. The returned mapping set has an empty ``mappings``
|
|
192
192
|
list; its ``_primary_ids`` store is populated with every current ChEBI
|
|
193
|
-
ID (CHEBI: prefixed) so that ``to_pri_ids()`` produces the
|
|
194
|
-
complete list.
|
|
193
|
+
ID (CHEBI: prefixed) so that ``to_pri_ids()`` produces the complete list.
|
|
195
194
|
|
|
196
195
|
Args:
|
|
197
196
|
input_path: Path to a directory containing ``compounds.tsv``, or
|
|
@@ -496,7 +495,7 @@ def _parse_names_tsv(
|
|
|
496
495
|
|
|
497
496
|
Format: id|compound_id|name|type|status_id|adapted|language_code|ascii_name
|
|
498
497
|
|
|
499
|
-
The
|
|
498
|
+
The true primary (canonical) name for each compound is taken from
|
|
500
499
|
the ``name`` column of ``compounds.tsv``: the same value displayed on the
|
|
501
500
|
ChEBI website and stored as the top-level label in the ChEBI ontology.
|
|
502
501
|
Every entry in ``names.tsv`` that differs from that canonical name is
|
|
@@ -526,7 +525,7 @@ def _parse_names_tsv(
|
|
|
526
525
|
"Pass the path to compounds.tsv."
|
|
527
526
|
)
|
|
528
527
|
|
|
529
|
-
# Load canonical names from compounds.tsv (ChEBI
|
|
528
|
+
# Load canonical names from compounds.tsv (ChEBI primary label)
|
|
530
529
|
cpd_cols = ["id", "name", "stars"] if subset == "3star" else ["id", "name"]
|
|
531
530
|
cpd_df = pl.read_csv(
|
|
532
531
|
compounds_path,
|
|
@@ -25,9 +25,8 @@ This parser extracts:
|
|
|
25
25
|
detection and ``to_pri_labels()`` stay scoped to one species' namespace
|
|
26
26
|
instead of flagging cross-species homonyms as ambiguous. Passing
|
|
27
27
|
:data:`ALL_SPECIES` processes every species together instead, in which
|
|
28
|
-
case a shared symbol
|
|
29
|
-
to tell the species apart) and gets flagged accordingly
|
|
30
|
-
``_annotate_ambiguous_mappings`` doing its job, not a bug.
|
|
28
|
+
case a shared symbol is really ambiguous (there's no other context
|
|
29
|
+
to tell the species apart) and gets flagged accordingly.
|
|
31
30
|
|
|
32
31
|
Uses SSSOM-compliant MappingSet classes with cardinality computation.
|
|
33
32
|
"""
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|