pysec2pri 0.2.2__tar.gz → 0.2.3__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.3}/PKG-INFO +3 -3
- {pysec2pri-0.2.2 → pysec2pri-0.2.3}/README.md +1 -1
- {pysec2pri-0.2.2 → pysec2pri-0.2.3}/pyproject.toml +3 -3
- {pysec2pri-0.2.2 → pysec2pri-0.2.3}/src/pysec2pri/api.py +5 -13
- {pysec2pri-0.2.2 → pysec2pri-0.2.3}/src/pysec2pri/cli.py +8 -20
- {pysec2pri-0.2.2 → pysec2pri-0.2.3}/src/pysec2pri/config/ensembl.yaml +1 -2
- {pysec2pri-0.2.2 → pysec2pri-0.2.3}/src/pysec2pri/config/hgnc.yaml +1 -2
- {pysec2pri-0.2.2 → pysec2pri-0.2.3}/src/pysec2pri/config/ncbi.yaml +1 -2
- {pysec2pri-0.2.2 → pysec2pri-0.2.3}/src/pysec2pri/consolidate.py +54 -116
- {pysec2pri-0.2.2 → pysec2pri-0.2.3}/src/pysec2pri/downloads/ensembl.py +12 -4
- {pysec2pri-0.2.2 → pysec2pri-0.2.3}/src/pysec2pri/parsers/chebi.py +3 -4
- {pysec2pri-0.2.2 → pysec2pri-0.2.3}/src/pysec2pri/parsers/vgnc.py +2 -3
- {pysec2pri-0.2.2 → pysec2pri-0.2.3}/src/pysec2pri/version.py +1 -1
- {pysec2pri-0.2.2 → pysec2pri-0.2.3}/LICENSE +0 -0
- {pysec2pri-0.2.2 → pysec2pri-0.2.3}/src/pysec2pri/__init__.py +0 -0
- {pysec2pri-0.2.2 → pysec2pri-0.2.3}/src/pysec2pri/__main__.py +0 -0
- {pysec2pri-0.2.2 → pysec2pri-0.2.3}/src/pysec2pri/config/__init__.py +0 -0
- {pysec2pri-0.2.2 → pysec2pri-0.2.3}/src/pysec2pri/config/chebi.yaml +0 -0
- {pysec2pri-0.2.2 → pysec2pri-0.2.3}/src/pysec2pri/config/hmdb_metabolites.yaml +0 -0
- {pysec2pri-0.2.2 → pysec2pri-0.2.3}/src/pysec2pri/config/hmdb_proteins.yaml +0 -0
- {pysec2pri-0.2.2 → pysec2pri-0.2.3}/src/pysec2pri/config/uniprot.yaml +0 -0
- {pysec2pri-0.2.2 → pysec2pri-0.2.3}/src/pysec2pri/config/vgnc.yaml +0 -0
- {pysec2pri-0.2.2 → pysec2pri-0.2.3}/src/pysec2pri/config/wikidata.yaml +0 -0
- {pysec2pri-0.2.2 → pysec2pri-0.2.3}/src/pysec2pri/constants.py +0 -0
- {pysec2pri-0.2.2 → pysec2pri-0.2.3}/src/pysec2pri/download.py +0 -0
- {pysec2pri-0.2.2 → pysec2pri-0.2.3}/src/pysec2pri/downloads/__init__.py +0 -0
- {pysec2pri-0.2.2 → pysec2pri-0.2.3}/src/pysec2pri/downloads/chebi.py +0 -0
- {pysec2pri-0.2.2 → pysec2pri-0.2.3}/src/pysec2pri/downloads/hgnc.py +0 -0
- {pysec2pri-0.2.2 → pysec2pri-0.2.3}/src/pysec2pri/downloads/hmdb.py +0 -0
- {pysec2pri-0.2.2 → pysec2pri-0.2.3}/src/pysec2pri/downloads/ncbi.py +0 -0
- {pysec2pri-0.2.2 → pysec2pri-0.2.3}/src/pysec2pri/downloads/uniprot.py +0 -0
- {pysec2pri-0.2.2 → pysec2pri-0.2.3}/src/pysec2pri/exports.py +0 -0
- {pysec2pri-0.2.2 → pysec2pri-0.2.3}/src/pysec2pri/logging.py +0 -0
- {pysec2pri-0.2.2 → pysec2pri-0.2.3}/src/pysec2pri/parsers/__init__.py +0 -0
- {pysec2pri-0.2.2 → pysec2pri-0.2.3}/src/pysec2pri/parsers/base.py +0 -0
- {pysec2pri-0.2.2 → pysec2pri-0.2.3}/src/pysec2pri/parsers/ensembl.py +0 -0
- {pysec2pri-0.2.2 → pysec2pri-0.2.3}/src/pysec2pri/parsers/hgnc.py +0 -0
- {pysec2pri-0.2.2 → pysec2pri-0.2.3}/src/pysec2pri/parsers/hmdb.py +0 -0
- {pysec2pri-0.2.2 → pysec2pri-0.2.3}/src/pysec2pri/parsers/ncbi.py +0 -0
- {pysec2pri-0.2.2 → pysec2pri-0.2.3}/src/pysec2pri/parsers/uniprot.py +0 -0
- {pysec2pri-0.2.2 → pysec2pri-0.2.3}/src/pysec2pri/parsers/wikidata.py +0 -0
- {pysec2pri-0.2.2 → pysec2pri-0.2.3}/src/pysec2pri/py.typed +0 -0
- {pysec2pri-0.2.2 → pysec2pri-0.2.3}/src/pysec2pri/queries/__init__.py +0 -0
- {pysec2pri-0.2.2 → pysec2pri-0.2.3}/src/pysec2pri/queries/chemical_redirects.rq +0 -0
- {pysec2pri-0.2.2 → pysec2pri-0.2.3}/src/pysec2pri/queries/chemical_redirects_test.rq +0 -0
- {pysec2pri-0.2.2 → pysec2pri-0.2.3}/src/pysec2pri/queries/gene_redirects.rq +0 -0
- {pysec2pri-0.2.2 → pysec2pri-0.2.3}/src/pysec2pri/queries/gene_redirects_test.rq +0 -0
- {pysec2pri-0.2.2 → pysec2pri-0.2.3}/src/pysec2pri/queries/protein_redirects.rq +0 -0
- {pysec2pri-0.2.2 → pysec2pri-0.2.3}/src/pysec2pri/queries/protein_redirects_test.rq +0 -0
- {pysec2pri-0.2.2 → pysec2pri-0.2.3}/src/pysec2pri/update_ids.py +0 -0
- {pysec2pri-0.2.2 → pysec2pri-0.2.3}/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.3
|
|
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.1
|
|
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
|
|
@@ -234,7 +234,7 @@ mappings.
|
|
|
234
234
|
### Aliases / synonyms
|
|
235
235
|
|
|
236
236
|
Alias mappings use `oboInOwl:hasExactSynonym`. The alias is the `subject_label`
|
|
237
|
-
and the
|
|
237
|
+
and the primary name is the `object_label`/`object_id`.
|
|
238
238
|
|
|
239
239
|
```mermaid
|
|
240
240
|
flowchart LR
|
|
@@ -181,7 +181,7 @@ mappings.
|
|
|
181
181
|
### Aliases / synonyms
|
|
182
182
|
|
|
183
183
|
Alias mappings use `oboInOwl:hasExactSynonym`. The alias is the `subject_label`
|
|
184
|
-
and the
|
|
184
|
+
and the primary name is the `object_label`/`object_id`.
|
|
185
185
|
|
|
186
186
|
```mermaid
|
|
187
187
|
flowchart LR
|
|
@@ -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.3"
|
|
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.1",
|
|
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.3"
|
|
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}",
|
|
@@ -244,8 +244,7 @@ def generate_hgnc_primary_ids(
|
|
|
244
244
|
Only the HGNC complete set file is downloaded/read. The returned mapping
|
|
245
245
|
set has an empty ``mappings`` list; its ``_primary_ids`` store is
|
|
246
246
|
populated with every current HGNC ID so that ``to_pri_ids()`` produces
|
|
247
|
-
the
|
|
248
|
-
happen to have an associated secondary.
|
|
247
|
+
the complete list.
|
|
249
248
|
|
|
250
249
|
Args:
|
|
251
250
|
input_path: Local HGNC complete set TSV. Auto-downloaded if ``None``.
|
|
@@ -1112,9 +1111,7 @@ def generate_ensembl_label_history(
|
|
|
1112
1111
|
previous-symbol -> current-symbol transitions are derived by diffing
|
|
1113
1112
|
each release's primary-label snapshot per stable ID. Delegates to
|
|
1114
1113
|
: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.
|
|
1114
|
+
historical release (or a bounded range) and resumes on re-run.
|
|
1118
1115
|
|
|
1119
1116
|
Args:
|
|
1120
1117
|
species: Canonical NCBI taxon ID (default ``9606`` for human).
|
|
@@ -2015,15 +2012,10 @@ def crosswalk(
|
|
|
2015
2012
|
) -> dict[str, str] | pd.DataFrame:
|
|
2016
2013
|
r"""Map a gene identifier from one vocabulary to another, via HGNC.
|
|
2017
2014
|
|
|
2018
|
-
|
|
2019
|
-
resolves through :func:`generate_hgnc_labels` +
|
|
2015
|
+
Wrapper: ``frm="symbol"`` resolves through :func:`generate_hgnc_labels` +
|
|
2020
2016
|
: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.
|
|
2017
|
+
still resolves to its current identity (the temporal aspect) and an ambiguous
|
|
2018
|
+
label is left blank and reported rather than guessed.
|
|
2027
2019
|
|
|
2028
2020
|
Args:
|
|
2029
2021
|
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
|
|
File without changes
|