mapkgsutils 0.0.2__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
mapkgsutils/exports.py ADDED
@@ -0,0 +1,180 @@
1
+ """Generic mapping-set export functions (SSSOM, RDF, JSON, OWL)."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from pathlib import Path
6
+ from typing import TYPE_CHECKING
7
+
8
+ from sssom import MappingSetDataFrame
9
+
10
+ if TYPE_CHECKING:
11
+ from mapkgsutils.parsers.base import BaseMappingSet
12
+
13
+ __all__ = [
14
+ "write_json",
15
+ "write_owl",
16
+ "write_rdf",
17
+ "write_sssom",
18
+ ]
19
+
20
+
21
+ def write_sssom(
22
+ mapping_set: BaseMappingSet,
23
+ output_path: Path | str,
24
+ ) -> Path:
25
+ """Write a mapping set to an SSSOM TSV file.
26
+
27
+ Args:
28
+ mapping_set: The mapping set to write.
29
+ output_path: Destination ``.sssom.tsv`` file path.
30
+
31
+ Returns:
32
+ Path to the written file.
33
+ """
34
+ import codecs
35
+ import re
36
+ from typing import cast
37
+
38
+ import curies
39
+ from sssom.parsers import to_mapping_set_dataframe # type: ignore[attr-defined]
40
+ from sssom.sssom_document import MappingSetDocument
41
+ from sssom.writers import write_table
42
+
43
+ output_path = Path(output_path)
44
+ output_path.parent.mkdir(parents=True, exist_ok=True)
45
+
46
+ # Build a curies.Converter from the curie_map stored on the mapping set.
47
+ # Using Converter(records=...) preserves prefix casing exactly as declared
48
+ # and handles pydantic-wrapped Prefix objects (which expose .prefix_url).
49
+ raw_curie_map: object = mapping_set.curie_map or {}
50
+ records: list[curies.Record] = []
51
+ if isinstance(raw_curie_map, dict):
52
+ for k, v in raw_curie_map.items():
53
+ if isinstance(v, str):
54
+ uri_prefix: str = v
55
+ elif hasattr(v, "prefix_url"):
56
+ uri_prefix = cast(str, v.prefix_url)
57
+ else:
58
+ continue
59
+ records.append(curies.Record(prefix=k, uri_prefix=uri_prefix))
60
+ converter = curies.Converter(records=records)
61
+ doc = MappingSetDocument(mapping_set=mapping_set, converter=converter)
62
+ msdf = to_mapping_set_dataframe(doc)
63
+
64
+ with output_path.open("w", encoding="utf-8") as f:
65
+ write_table(msdf, f)
66
+
67
+ # Fix escaped unicode in YAML header (sssom issue)
68
+ content = output_path.read_text(encoding="utf-8")
69
+ content = re.sub(
70
+ r"\\x([0-9a-fA-F]{2})",
71
+ lambda m: codecs.decode(bytes([int(m.group(1), 16)]), "latin-1"),
72
+ content,
73
+ )
74
+ output_path.write_text(content, encoding="utf-8")
75
+
76
+ return output_path
77
+
78
+
79
+ def _to_msdf_via_sssom_parser(mapping_set: BaseMappingSet) -> MappingSetDataFrame | None:
80
+ """Write to a temporary SSSOM TSV then parse back with sssom's own parser.
81
+
82
+ Args:
83
+ mapping_set: The mapping set to convert.
84
+
85
+ Returns:
86
+ A fully-validated ``MappingSetDataFrame`` ready for RDF/JSON/OWL serialisation.
87
+ """
88
+ import tempfile
89
+
90
+ from sssom.parsers import parse_sssom_table
91
+
92
+ with tempfile.NamedTemporaryFile(
93
+ suffix=".sssom.tsv", mode="w", encoding="utf-8", delete=False
94
+ ) as tmp:
95
+ tmp_path = Path(tmp.name)
96
+
97
+ try:
98
+ write_sssom(mapping_set, tmp_path)
99
+ return parse_sssom_table(str(tmp_path))
100
+ finally:
101
+ tmp_path.unlink(missing_ok=True)
102
+
103
+
104
+ def write_rdf(
105
+ mapping_set: BaseMappingSet,
106
+ output_path: Path | str,
107
+ serialisation: str = "turtle",
108
+ ) -> Path:
109
+ """Write a mapping set to an RDF file.
110
+
111
+ Args:
112
+ mapping_set: The mapping set to write.
113
+ output_path: Destination file path (e.g. ``mappings.ttl``).
114
+ serialisation: RDFLib serialisation format.
115
+
116
+ Returns:
117
+ Path to the written file.
118
+ """
119
+ from sssom.writers import write_rdf as _sssom_write_rdf
120
+
121
+ output_path = Path(output_path)
122
+ output_path.parent.mkdir(parents=True, exist_ok=True)
123
+ msdf = _to_msdf_via_sssom_parser(mapping_set)
124
+ if msdf is None:
125
+ raise ValueError("Failed to parse mapping set for RDF serialisation.")
126
+ with output_path.open("w", encoding="utf-8") as f:
127
+ _sssom_write_rdf(msdf, f, serialisation=serialisation)
128
+ return output_path
129
+
130
+
131
+ def write_json(
132
+ mapping_set: BaseMappingSet,
133
+ output_path: Path | str,
134
+ ) -> Path:
135
+ """Write a mapping set to an SSSOM JSON file.
136
+
137
+ Args:
138
+ mapping_set: The mapping set to write.
139
+ output_path: Destination file path (e.g. ``mappings.json``).
140
+
141
+ Returns:
142
+ Path to the written file.
143
+ """
144
+ from sssom.writers import write_json as _sssom_write_json
145
+
146
+ output_path = Path(output_path)
147
+ output_path.parent.mkdir(parents=True, exist_ok=True)
148
+ msdf = _to_msdf_via_sssom_parser(mapping_set)
149
+ if msdf is None:
150
+ raise ValueError("Failed to parse mapping set for JSON serialisation.")
151
+ with output_path.open("w", encoding="utf-8") as f:
152
+ _sssom_write_json(msdf, f)
153
+ return output_path
154
+
155
+
156
+ def write_owl(
157
+ mapping_set: BaseMappingSet,
158
+ output_path: Path | str,
159
+ serialisation: str = "turtle",
160
+ ) -> Path:
161
+ """Write a mapping set to an OWL/RDF file (default: Turtle).
162
+
163
+ Args:
164
+ mapping_set: The mapping set to write.
165
+ output_path: Destination file path (e.g. ``mappings_owl.ttl``).
166
+ serialisation: RDFLib serialisation format.
167
+
168
+ Returns:
169
+ Path to the written file.
170
+ """
171
+ from sssom.writers import write_owl as _sssom_write_owl
172
+
173
+ output_path = Path(output_path)
174
+ output_path.parent.mkdir(parents=True, exist_ok=True)
175
+ msdf = _to_msdf_via_sssom_parser(mapping_set)
176
+ if msdf is None:
177
+ raise ValueError("Failed to parse mapping set for OWL serialisation.")
178
+ with output_path.open("w", encoding="utf-8") as f:
179
+ _sssom_write_owl(msdf, f, serialisation=serialisation)
180
+ return output_path
mapkgsutils/logging.py ADDED
@@ -0,0 +1,65 @@
1
+ """Logging configuration for mapkgsutils.
2
+
3
+ This module provides a centralized logger for the package.
4
+ By default, only CRITICAL messages are shown. Use set_log_level()
5
+ to adjust verbosity.
6
+ """
7
+
8
+ from __future__ import annotations
9
+
10
+ import logging
11
+ import sys
12
+
13
+ __all__ = [
14
+ "LOG_LEVELS",
15
+ "logger",
16
+ "set_log_level",
17
+ ]
18
+
19
+ # Package logger
20
+ logger = logging.getLogger("mapkgsutils")
21
+
22
+ # Default to CRITICAL (minimal output)
23
+ logger.setLevel(logging.CRITICAL)
24
+
25
+ # Add a handler if none exists
26
+ if not logger.handlers:
27
+ handler = logging.StreamHandler(sys.stderr)
28
+ handler.setFormatter(
29
+ logging.Formatter(
30
+ "%(asctime)s - %(name)s - %(levelname)s - %(message)s",
31
+ datefmt="%Y-%m-%d %H:%M:%S",
32
+ )
33
+ )
34
+ logger.addHandler(handler)
35
+
36
+ # Map of log level names to logging constants
37
+ LOG_LEVELS: dict[str, int] = {
38
+ "critical": logging.CRITICAL,
39
+ "error": logging.ERROR,
40
+ "warning": logging.WARNING,
41
+ "warn": logging.WARNING,
42
+ "info": logging.INFO,
43
+ "debug": logging.DEBUG,
44
+ }
45
+
46
+
47
+ def set_log_level(level: str | int) -> None:
48
+ """Set the logging level for mapkgsutils.
49
+
50
+ Args:
51
+ level: Log level as string ('debug', 'info', 'warning', 'error', 'critical')
52
+ or as an int (logging.DEBUG, logging.INFO, etc.)
53
+
54
+ Example:
55
+ >>> from mapkgsutils.logging import set_log_level
56
+ >>> set_log_level("warning") # Show warnings and above
57
+ >>> set_log_level("debug") # Show all messages
58
+ """
59
+ if isinstance(level, str):
60
+ level_int = LOG_LEVELS.get(level.lower())
61
+ if level_int is None:
62
+ raise ValueError(f"Unknown log level: {level}. Available: {list(LOG_LEVELS.keys())}")
63
+ logger.setLevel(level_int)
64
+ else:
65
+ logger.setLevel(level)
@@ -0,0 +1 @@
1
+ """Datasource-agnostic parser and downloader framework."""