mapkgsutils 0.1.2__tar.gz → 0.2.1__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.
- {mapkgsutils-0.1.2 → mapkgsutils-0.2.1}/PKG-INFO +1 -1
- {mapkgsutils-0.1.2 → mapkgsutils-0.2.1}/pyproject.toml +2 -2
- {mapkgsutils-0.1.2 → mapkgsutils-0.2.1}/src/mapkgsutils/consolidate.py +4 -29
- {mapkgsutils-0.1.2 → mapkgsutils-0.2.1}/src/mapkgsutils/diff.py +2 -2
- {mapkgsutils-0.1.2 → mapkgsutils-0.2.1}/src/mapkgsutils/download.py +2 -2
- {mapkgsutils-0.1.2 → mapkgsutils-0.2.1}/src/mapkgsutils/exports.py +2 -2
- mapkgsutils-0.2.1/src/mapkgsutils/logging.py +68 -0
- {mapkgsutils-0.1.2 → mapkgsutils-0.2.1}/src/mapkgsutils/parsers/base.py +146 -472
- mapkgsutils-0.2.1/src/mapkgsutils/parsers/config.py +293 -0
- mapkgsutils-0.2.1/src/mapkgsutils/resolve.py +606 -0
- {mapkgsutils-0.1.2 → mapkgsutils-0.2.1}/src/mapkgsutils/version.py +2 -2
- mapkgsutils-0.1.2/src/mapkgsutils/logging.py +0 -65
- {mapkgsutils-0.1.2 → mapkgsutils-0.2.1}/LICENSE +0 -0
- {mapkgsutils-0.1.2 → mapkgsutils-0.2.1}/README.md +0 -0
- {mapkgsutils-0.1.2 → mapkgsutils-0.2.1}/src/mapkgsutils/__init__.py +0 -0
- {mapkgsutils-0.1.2 → mapkgsutils-0.2.1}/src/mapkgsutils/config/__init__.py +0 -0
- {mapkgsutils-0.1.2 → mapkgsutils-0.2.1}/src/mapkgsutils/config/schema.py +0 -0
- {mapkgsutils-0.1.2 → mapkgsutils-0.2.1}/src/mapkgsutils/context.py +0 -0
- {mapkgsutils-0.1.2 → mapkgsutils-0.2.1}/src/mapkgsutils/parsers/__init__.py +0 -0
- {mapkgsutils-0.1.2 → mapkgsutils-0.2.1}/src/mapkgsutils/py.typed +0 -0
|
@@ -4,7 +4,7 @@ build-backend = "uv_build"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "mapkgsutils"
|
|
7
|
-
version = "0.1
|
|
7
|
+
version = "0.2.1"
|
|
8
8
|
description = "Utils shared by several mapping set generation tools for biomedical databases"
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
authors = [
|
|
@@ -236,7 +236,7 @@ known-first-party = [
|
|
|
236
236
|
docstring-code-format = true
|
|
237
237
|
|
|
238
238
|
[tool.bumpversion]
|
|
239
|
-
current_version = "0.1
|
|
239
|
+
current_version = "0.2.1"
|
|
240
240
|
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-]+)*))?"
|
|
241
241
|
serialize = [
|
|
242
242
|
"{major}.{minor}.{patch}-{release}+{build}",
|
|
@@ -142,29 +142,15 @@ def load_mapping_dates(cache_path: Path) -> dict[str, str]:
|
|
|
142
142
|
cache_path: Path to the cache TSV (see :func:`write_cache`).
|
|
143
143
|
|
|
144
144
|
Returns:
|
|
145
|
-
Dict mapping each ``record_id`` to
|
|
146
|
-
|
|
147
|
-
produced one, else the first-seen release date. Records with no date
|
|
148
|
-
at all are omitted, leaving their ``mapping_date`` unset rather than
|
|
149
|
-
passing through a non-date value.
|
|
145
|
+
Dict mapping each ``record_id`` to the mapping's ``mapping_date``,
|
|
146
|
+
else the first-seen release date.
|
|
150
147
|
"""
|
|
151
148
|
records = read_cache(cache_path)
|
|
152
149
|
return {rid: date for rid, fields in records.items() if (date := _best_date(fields))}
|
|
153
150
|
|
|
154
151
|
|
|
155
152
|
def _mapping_fields_json(m: Any) -> str:
|
|
156
|
-
"""JSON-encode a mapping's own fields (excluding record_id).
|
|
157
|
-
|
|
158
|
-
Snapshots a mapping's current shape (subject_id, object_id,
|
|
159
|
-
predicate_id, mapping_date, ...) so :func:`build_consolidated_mapping_set`
|
|
160
|
-
can rebuild it into a real SSSOM mapping set later. The parser's own
|
|
161
|
-
per-row ``mapping_date`` is kept (it's release-independent), distinct
|
|
162
|
-
from the first-seen release version. ``default=str`` handles
|
|
163
|
-
enum-valued fields like ``mapping_cardinality``, which round-trip
|
|
164
|
-
cleanly back through ``Mapping(**fields)``. Returns ``"{}"`` for
|
|
165
|
-
non-dataclass stand-ins (e.g. test doubles); callers skip those rows
|
|
166
|
-
rather than materializing them.
|
|
167
|
-
"""
|
|
153
|
+
"""JSON-encode a mapping's own fields (excluding record_id)."""
|
|
168
154
|
from dataclasses import fields as dataclass_fields
|
|
169
155
|
from dataclasses import is_dataclass
|
|
170
156
|
|
|
@@ -193,16 +179,6 @@ def consolidate(
|
|
|
193
179
|
|
|
194
180
|
Keeps every mapping and every available piece of provenance.
|
|
195
181
|
|
|
196
|
-
- **``list_versions`` provided** (versioned archive, e.g. ChEBI/HGNC/
|
|
197
|
-
UniProt/Ensembl): walk every release oldest-first, calling
|
|
198
|
-
``run_one_version(v)`` per release and recording the first/last release
|
|
199
|
-
each mapping was seen in. Resumes from :func:`read_meta` unless
|
|
200
|
-
*force*. This collects the full historical set.
|
|
201
|
-
- **``list_versions`` is ``None``** (no versioned archive, e.g. NCBI/
|
|
202
|
-
VGNC): a single current parse via ``run_one_version(None)`` caching the
|
|
203
|
-
*full* mapping set — every mapping kept, stamped with its own per-row
|
|
204
|
-
date when present and left undated otherwise.
|
|
205
|
-
|
|
206
182
|
Args:
|
|
207
183
|
cache_path: Path to the cache TSV to read/write.
|
|
208
184
|
meta_path: Path to the ``last_version`` sidecar to read/write.
|
|
@@ -257,8 +233,7 @@ def _consolidate_single_parse(
|
|
|
257
233
|
pair_key = str(getattr(m, "record_id", None) or "")[-16:]
|
|
258
234
|
if not pair_key:
|
|
259
235
|
continue
|
|
260
|
-
# The mapping's own per-row date
|
|
261
|
-
# mirrors it so undated rows simply stay undated rather than dropping out.
|
|
236
|
+
# The mapping's own per-row date is taken from fields_json
|
|
262
237
|
date_str = str(m.mapping_date) if getattr(m, "mapping_date", None) else ""
|
|
263
238
|
records[pair_key] = {
|
|
264
239
|
"first_seen_version": version_label,
|
|
@@ -170,7 +170,7 @@ def _read_sssom_to_dataframe(path: Path) -> pl.DataFrame:
|
|
|
170
170
|
"""
|
|
171
171
|
# Count header lines
|
|
172
172
|
header_lines = 0
|
|
173
|
-
with path.open() as f:
|
|
173
|
+
with path.open(encoding="utf-8") as f:
|
|
174
174
|
for line in f:
|
|
175
175
|
if line.startswith("#"):
|
|
176
176
|
header_lines += 1
|
|
@@ -200,7 +200,7 @@ def _extract_sssom_version(path: Path) -> str | None:
|
|
|
200
200
|
Returns:
|
|
201
201
|
Version string or None if not found.
|
|
202
202
|
"""
|
|
203
|
-
with path.open() as f:
|
|
203
|
+
with path.open(encoding="utf-8") as f:
|
|
204
204
|
for line in f:
|
|
205
205
|
if not line.startswith("#"):
|
|
206
206
|
break
|
|
@@ -68,6 +68,7 @@ def _is_cloudflare_blocked(response: httpx.Response) -> bool:
|
|
|
68
68
|
# header being present, check the body.
|
|
69
69
|
content_type = response.headers.get("content-type", "")
|
|
70
70
|
if "text/html" in content_type:
|
|
71
|
+
response.read() # body is unread on a streamed response; .text needs it
|
|
71
72
|
text = response.text
|
|
72
73
|
if "cloudflare" in text.lower() or "cf-ray" in text.lower():
|
|
73
74
|
return True
|
|
@@ -558,8 +559,7 @@ def download_datasource_with_release(
|
|
|
558
559
|
keys: Optional list of file-key names to download.
|
|
559
560
|
tar_extractors: ``{datasource_name: extractor}`` registry for
|
|
560
561
|
datasources that publish a ``.tar.gz`` archive needing
|
|
561
|
-
member-level extraction
|
|
562
|
-
UniProt). Datasources without one are downloaded as-is.
|
|
562
|
+
member-level extraction.
|
|
563
563
|
**kwargs: Datasource-specific knobs forwarded to the resolved hook.
|
|
564
564
|
|
|
565
565
|
Returns:
|
|
@@ -5,9 +5,9 @@ from __future__ import annotations
|
|
|
5
5
|
from pathlib import Path
|
|
6
6
|
from typing import TYPE_CHECKING, Any, TypeVar
|
|
7
7
|
|
|
8
|
-
from sssom import MappingSetDataFrame
|
|
9
|
-
|
|
10
8
|
if TYPE_CHECKING:
|
|
9
|
+
from sssom import MappingSetDataFrame
|
|
10
|
+
|
|
11
11
|
from mapkgsutils.parsers.base import BaseMappingSet
|
|
12
12
|
|
|
13
13
|
_M = TypeVar("_M", bound="BaseMappingSet")
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
"""Logging configuration.
|
|
2
|
+
|
|
3
|
+
Provides a configured package logger. Only CRITICAL messages show by default;
|
|
4
|
+
call :func:`set_log_level` to raise verbosity.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from __future__ import annotations
|
|
8
|
+
|
|
9
|
+
import logging
|
|
10
|
+
import sys
|
|
11
|
+
|
|
12
|
+
__all__ = [
|
|
13
|
+
"LOG_LEVELS",
|
|
14
|
+
"get_logger",
|
|
15
|
+
"logger",
|
|
16
|
+
"set_log_level",
|
|
17
|
+
]
|
|
18
|
+
|
|
19
|
+
# Map of log level names to logging constants
|
|
20
|
+
LOG_LEVELS: dict[str, int] = {
|
|
21
|
+
"critical": logging.CRITICAL,
|
|
22
|
+
"error": logging.ERROR,
|
|
23
|
+
"warning": logging.WARNING,
|
|
24
|
+
"warn": logging.WARNING,
|
|
25
|
+
"info": logging.INFO,
|
|
26
|
+
"debug": logging.DEBUG,
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
def get_logger(name: str) -> logging.Logger:
|
|
31
|
+
"""Return a stderr-handled logger for *name*, defaulting to CRITICAL."""
|
|
32
|
+
log = logging.getLogger(name)
|
|
33
|
+
log.setLevel(logging.CRITICAL)
|
|
34
|
+
if not log.handlers:
|
|
35
|
+
handler = logging.StreamHandler(sys.stderr)
|
|
36
|
+
handler.setFormatter(
|
|
37
|
+
logging.Formatter(
|
|
38
|
+
"%(asctime)s - %(name)s - %(levelname)s - %(message)s",
|
|
39
|
+
datefmt="%Y-%m-%d %H:%M:%S",
|
|
40
|
+
)
|
|
41
|
+
)
|
|
42
|
+
log.addHandler(handler)
|
|
43
|
+
return log
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
logger = get_logger("mapkgsutils")
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
def set_log_level(level: str | int, target: logging.Logger | None = None) -> None:
|
|
50
|
+
"""Set the log level on *target* (the mapkgsutils logger by default).
|
|
51
|
+
|
|
52
|
+
Args:
|
|
53
|
+
level: Level name (``"debug"``/``"info"``/``"warning"``/``"error"``/
|
|
54
|
+
``"critical"``) or an integer such as ``logging.INFO``.
|
|
55
|
+
target: Logger to configure.
|
|
56
|
+
|
|
57
|
+
Example:
|
|
58
|
+
>>> from mapkgsutils.logging import set_log_level
|
|
59
|
+
>>> set_log_level("warning")
|
|
60
|
+
"""
|
|
61
|
+
log = target if target is not None else logger
|
|
62
|
+
if isinstance(level, str):
|
|
63
|
+
level_int = LOG_LEVELS.get(level.lower())
|
|
64
|
+
if level_int is None:
|
|
65
|
+
raise ValueError(f"Unknown log level: {level}. Available: {list(LOG_LEVELS.keys())}")
|
|
66
|
+
log.setLevel(level_int)
|
|
67
|
+
else:
|
|
68
|
+
log.setLevel(level)
|