metahq-core 0.1.2__py3-none-any.whl → 1.0.0rc1__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.
- metahq_core/__init__.py +1 -1
- metahq_core/curations/annotation_converter.py +5 -5
- metahq_core/curations/annotations.py +361 -151
- metahq_core/curations/index.py +104 -43
- metahq_core/curations/labels.py +259 -128
- metahq_core/curations/propagator.py +62 -85
- metahq_core/export/__init__.py +0 -0
- metahq_core/export/annotations.py +125 -59
- metahq_core/export/labels.py +128 -70
- metahq_core/logger.py +11 -18
- metahq_core/query.py +346 -241
- metahq_core/{ontology/loader.py → relations_loader.py} +2 -1
- metahq_core/search.py +37 -14
- metahq_core/util/io.py +109 -46
- metahq_core/util/supported.py +16 -5
- {metahq_core-0.1.2.dist-info → metahq_core-1.0.0rc1.dist-info}/METADATA +13 -6
- metahq_core-1.0.0rc1.dist-info/RECORD +30 -0
- {metahq_core-0.1.2.dist-info → metahq_core-1.0.0rc1.dist-info}/WHEEL +1 -1
- metahq_core-1.0.0rc1.dist-info/licenses/LICENSE +28 -0
- metahq_core/ontology/base.py +0 -376
- metahq_core/ontology/graph.py +0 -252
- metahq_core-0.1.2.dist-info/RECORD +0 -30
- /metahq_core/{ontology → curations}/__init__.py +0 -0
|
@@ -20,6 +20,7 @@ from pathlib import Path
|
|
|
20
20
|
import polars as pl
|
|
21
21
|
|
|
22
22
|
from metahq_core.logger import setup_logger
|
|
23
|
+
from metahq_core.util.supported import get_default_log_dir
|
|
23
24
|
|
|
24
25
|
# these are used a lot so defining them as constants to
|
|
25
26
|
# make them easy to change later.
|
|
@@ -35,7 +36,7 @@ class RelationsLoader:
|
|
|
35
36
|
|
|
36
37
|
"""
|
|
37
38
|
|
|
38
|
-
def __init__(self, file, logger=None, loglevel=20, logdir=
|
|
39
|
+
def __init__(self, file, logger=None, loglevel=20, logdir=get_default_log_dir()):
|
|
39
40
|
self.relations: pl.LazyFrame = self.setup(file)
|
|
40
41
|
|
|
41
42
|
if logger is None:
|
metahq_core/search.py
CHANGED
|
@@ -25,6 +25,8 @@ but the current implementation is IMHO a reasonable starting point.
|
|
|
25
25
|
|
|
26
26
|
Author: Faisal Alquaddoomi
|
|
27
27
|
Date: 2025-09-25
|
|
28
|
+
|
|
29
|
+
Last updated: 2025-11-28 by Parker Hicks
|
|
28
30
|
"""
|
|
29
31
|
|
|
30
32
|
from __future__ import annotations
|
|
@@ -60,13 +62,21 @@ DEFAULT_SCOPE = "RELATED"
|
|
|
60
62
|
|
|
61
63
|
|
|
62
64
|
class SynonymEntry(TypedDict):
|
|
65
|
+
"""Storage of synonyms and their scope.
|
|
66
|
+
|
|
67
|
+
Attributes:
|
|
68
|
+
text (str):
|
|
69
|
+
Any piece of text.
|
|
70
|
+
scope (NotRequired[Literal["EXACT", "NARROW", "BROAD", "RELATED"]]):
|
|
71
|
+
The importance of `text`.
|
|
72
|
+
"""
|
|
73
|
+
|
|
63
74
|
text: str
|
|
64
75
|
scope: NotRequired[Literal["EXACT", "NARROW", "BROAD", "RELATED"]]
|
|
65
76
|
|
|
66
77
|
|
|
67
78
|
def doc_text_for(name: str, syns: list[SynonymEntry]) -> str:
|
|
68
|
-
"""
|
|
69
|
-
Build the doc_text column for BM25 indexing from the name and synonyms.
|
|
79
|
+
"""Build the doc_text column for BM25 indexing from the name and synonyms.
|
|
70
80
|
|
|
71
81
|
See the NAME_WEIGHT and SCOPE_WEIGHTS constants for how parts of the record
|
|
72
82
|
are weighted in the resulting document.
|
|
@@ -74,9 +84,14 @@ def doc_text_for(name: str, syns: list[SynonymEntry]) -> str:
|
|
|
74
84
|
Per the OBO 1.4 spec, synonyms can have scopes in {EXACT, BROAD, NARROW,
|
|
75
85
|
RELATED}. If no scope is given, it is treated as RELATED.
|
|
76
86
|
|
|
77
|
-
:
|
|
78
|
-
|
|
79
|
-
|
|
87
|
+
Arguments:
|
|
88
|
+
name (str):
|
|
89
|
+
The primary name of the term.
|
|
90
|
+
syns (list[SynonymEntry]):
|
|
91
|
+
List of {"text": str, "scope": str|None} synonym entries.
|
|
92
|
+
|
|
93
|
+
Returns:
|
|
94
|
+
A string suitable for BM25 indexing.
|
|
80
95
|
"""
|
|
81
96
|
parts = []
|
|
82
97
|
|
|
@@ -101,20 +116,28 @@ def search(
|
|
|
101
116
|
logger: logging.Logger | None = None,
|
|
102
117
|
verbose: bool = False,
|
|
103
118
|
) -> pl.DataFrame:
|
|
104
|
-
"""
|
|
105
|
-
Given a query string, return the top k hits from the ontology search index.
|
|
119
|
+
"""Given a query string, return the top k hits from the ontology search index.
|
|
106
120
|
|
|
107
121
|
The search index is built from the ontology terms' names and synonyms, where
|
|
108
122
|
names are weighted more heavily than synonyms. The search uses the BM25+ algorithm
|
|
109
123
|
to rank the results.
|
|
110
124
|
|
|
111
|
-
:
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
125
|
+
Arguments:
|
|
126
|
+
query (str):
|
|
127
|
+
The query string.
|
|
128
|
+
db (Path | None):
|
|
129
|
+
Path to the DuckDB database file, or None to use the default location.
|
|
130
|
+
k (int):
|
|
131
|
+
The number of top hits to return.
|
|
132
|
+
type (str | None):
|
|
133
|
+
If given, restrict results to this type (e.g. "celltype", "disease", or "tissue").
|
|
134
|
+
ontology (str | None):
|
|
135
|
+
If given, restrict results to this ontology (e.g. "CL", "UBERON", or "MONDO").
|
|
136
|
+
verbose (bool):
|
|
137
|
+
If True, print debug information.
|
|
138
|
+
|
|
139
|
+
Returns:
|
|
140
|
+
A `polars.DataFrame` object with columns: term_id, ontology, name, type, synonyms, score.
|
|
118
141
|
"""
|
|
119
142
|
|
|
120
143
|
if logger is None:
|
metahq_core/util/io.py
CHANGED
|
@@ -1,17 +1,36 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Input/output functions.
|
|
3
|
+
|
|
4
|
+
Author: Parker Hicks
|
|
5
|
+
Date: 2025-04
|
|
6
|
+
|
|
7
|
+
Last updated: 2025-11-28 by Parker Hicks
|
|
8
|
+
"""
|
|
9
|
+
|
|
1
10
|
import json
|
|
2
11
|
import re
|
|
3
|
-
import subprocess
|
|
4
12
|
import sys
|
|
5
13
|
from pathlib import Path
|
|
6
|
-
from typing import Any
|
|
14
|
+
from typing import Any
|
|
7
15
|
|
|
8
16
|
import yaml
|
|
9
17
|
from bson import BSON
|
|
10
18
|
|
|
11
|
-
from metahq_core.util.alltypes import
|
|
19
|
+
from metahq_core.util.alltypes import StringArray
|
|
12
20
|
|
|
13
21
|
|
|
14
|
-
def checkdir(path:
|
|
22
|
+
def checkdir(path: str | Path, is_file: bool = False) -> Path:
|
|
23
|
+
"""Check if directory exists. If not, creates it.
|
|
24
|
+
|
|
25
|
+
Arguments:
|
|
26
|
+
path (str | Path):
|
|
27
|
+
A path to a directory or file.
|
|
28
|
+
is_file (bool):
|
|
29
|
+
If `True` will check the parent of the file path.
|
|
30
|
+
|
|
31
|
+
Returns:
|
|
32
|
+
A `pathlib.Path` object of `path`.
|
|
33
|
+
"""
|
|
15
34
|
if isinstance(path, str):
|
|
16
35
|
path = Path(path)
|
|
17
36
|
if is_file:
|
|
@@ -23,24 +42,48 @@ def checkdir(path: FilePath, is_file: bool = False):
|
|
|
23
42
|
return path
|
|
24
43
|
|
|
25
44
|
|
|
26
|
-
def load_bson(file:
|
|
27
|
-
"""Load dictionary from compressed bson.
|
|
45
|
+
def load_bson(file: str | Path, **kwargs) -> dict[str, Any]:
|
|
46
|
+
"""Load dictionary from compressed bson.
|
|
47
|
+
|
|
48
|
+
Arguments:
|
|
49
|
+
file (str | Path):
|
|
50
|
+
Path to file.bson to load.
|
|
51
|
+
"""
|
|
28
52
|
with open(file, "rb") as bf:
|
|
29
53
|
return BSON(bf.read()).decode(**kwargs)
|
|
30
54
|
|
|
31
55
|
|
|
32
|
-
def load_json(file:
|
|
56
|
+
def load_json(file: str | Path, encoding: str = "utf-8") -> dict[str, Any]:
|
|
57
|
+
"""Load dictionary from JSON.
|
|
58
|
+
|
|
59
|
+
Arguments:
|
|
60
|
+
file (str | Path):
|
|
61
|
+
Path to file.json to load.
|
|
62
|
+
"""
|
|
33
63
|
with open(file, "r", encoding=encoding) as jf:
|
|
34
64
|
return json.load(jf)
|
|
35
65
|
|
|
36
66
|
|
|
37
67
|
def load_txt(
|
|
38
|
-
file:
|
|
68
|
+
file: str | Path,
|
|
39
69
|
cols: int = 1,
|
|
40
70
|
delimiter: str = ",",
|
|
41
71
|
encoding: str = "utf-8",
|
|
42
72
|
) -> list[str]:
|
|
43
|
-
"""Loads a txt file.
|
|
73
|
+
"""Loads a txt file.
|
|
74
|
+
|
|
75
|
+
Arguments:
|
|
76
|
+
file (str | Path):
|
|
77
|
+
Path to file.txt to load.
|
|
78
|
+
cols (int):
|
|
79
|
+
The number of columns in `file`.
|
|
80
|
+
delimiter (str | None):
|
|
81
|
+
Character to separate entries if the `cols>1`.
|
|
82
|
+
encoding (str):
|
|
83
|
+
Text encoding format.
|
|
84
|
+
Returns:
|
|
85
|
+
An list of strings.
|
|
86
|
+
"""
|
|
44
87
|
out = []
|
|
45
88
|
with open(file, "r", encoding=encoding) as f:
|
|
46
89
|
for line in f.readlines():
|
|
@@ -54,21 +97,19 @@ def load_txt(
|
|
|
54
97
|
return out
|
|
55
98
|
|
|
56
99
|
|
|
57
|
-
def load_txt_sections(file:
|
|
58
|
-
"""
|
|
59
|
-
Generator to load a .txt file in sections.
|
|
100
|
+
def load_txt_sections(file: str | Path, delimiter: str, encoding="utf-8") -> list[str]:
|
|
101
|
+
"""Load a .txt file in sections.
|
|
60
102
|
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
103
|
+
Arguments:
|
|
104
|
+
file (str | Path):
|
|
105
|
+
Path to .txt file to load in sections.
|
|
106
|
+
delimiter (str):
|
|
107
|
+
Pattern to split entries in the .txt file.
|
|
108
|
+
encoding (str):
|
|
109
|
+
Text encoding format.
|
|
65
110
|
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
Returns
|
|
70
|
-
------
|
|
71
|
-
Sections of the .txt file separated by the specified delimiter.
|
|
111
|
+
Returns:
|
|
112
|
+
Sections of the .txt file separated by the specified delimiter.
|
|
72
113
|
|
|
73
114
|
"""
|
|
74
115
|
with open(file, "r", encoding=encoding) as f:
|
|
@@ -77,8 +118,15 @@ def load_txt_sections(file: FilePath, delimiter: str, encoding="utf-8") -> list[
|
|
|
77
118
|
return re.split(delimiter, text.strip())
|
|
78
119
|
|
|
79
120
|
|
|
80
|
-
def load_yaml(file:
|
|
81
|
-
"""Load a yaml dictionary.
|
|
121
|
+
def load_yaml(file: str | Path, encoding: str = "utf-8") -> dict[str, Any]:
|
|
122
|
+
"""Load a yaml dictionary.
|
|
123
|
+
|
|
124
|
+
Arguments:
|
|
125
|
+
file (str | Path):
|
|
126
|
+
Path to .yaml file to load.
|
|
127
|
+
encoding (str):
|
|
128
|
+
Text encoding format.
|
|
129
|
+
"""
|
|
82
130
|
with open(file, "r", encoding=encoding) as stream:
|
|
83
131
|
try:
|
|
84
132
|
return yaml.safe_load(stream)
|
|
@@ -86,42 +134,57 @@ def load_yaml(file: FilePath, encoding: str = "utf-8") -> dict[str, Any]:
|
|
|
86
134
|
sys.exit(str(e))
|
|
87
135
|
|
|
88
136
|
|
|
89
|
-
def save_bson(data: dict, file:
|
|
90
|
-
"""Save dictionary to compressed bson.
|
|
137
|
+
def save_bson(data: dict, file: str | Path, **kwargs):
|
|
138
|
+
"""Save dictionary to compressed bson.
|
|
139
|
+
|
|
140
|
+
Arguments:
|
|
141
|
+
data (dict):
|
|
142
|
+
Dictionary to compress and save.
|
|
143
|
+
file (str | Path):
|
|
144
|
+
Path to file.txt to save `data`.
|
|
145
|
+
"""
|
|
91
146
|
with open(file, "wb") as bf:
|
|
92
147
|
bf.write(BSON.encode(data, **kwargs))
|
|
93
148
|
|
|
94
149
|
|
|
95
|
-
def save_json(data: dict, file:
|
|
150
|
+
def save_json(data: dict, file: str | Path, encoding: str = "utf-8"):
|
|
151
|
+
"""Saves a dictionary to file in JSON format.
|
|
152
|
+
|
|
153
|
+
Arguments:
|
|
154
|
+
data (dict):
|
|
155
|
+
Dictionary to save.
|
|
156
|
+
file (str | Path):
|
|
157
|
+
Path to file.txt to save `data`.
|
|
158
|
+
encoding (str):
|
|
159
|
+
Text encoding format.
|
|
160
|
+
"""
|
|
96
161
|
with open(file, "w", encoding=encoding) as jf:
|
|
97
162
|
json.dump(data, jf, indent=4)
|
|
98
163
|
|
|
99
164
|
|
|
100
165
|
def save_txt(
|
|
101
166
|
data: StringArray | list[str],
|
|
102
|
-
file:
|
|
103
|
-
delimiter:
|
|
104
|
-
encoding="utf-8",
|
|
167
|
+
file: str | Path,
|
|
168
|
+
delimiter: str | None = None,
|
|
169
|
+
encoding: str = "utf-8",
|
|
105
170
|
):
|
|
171
|
+
"""Save an array or list to a `.txt` file.
|
|
172
|
+
|
|
173
|
+
Arguments:
|
|
174
|
+
data (StringArray | list[str]):
|
|
175
|
+
An array or list of string entries.
|
|
176
|
+
file (str | Path):
|
|
177
|
+
Path to file.txt to save `data`.
|
|
178
|
+
delimiter (str | None):
|
|
179
|
+
Allows for multidimensional arrays to be saves as
|
|
180
|
+
single dimension arrays by concatenating each
|
|
181
|
+
element in each row by the passed delimiter.
|
|
182
|
+
encoding (str):
|
|
183
|
+
Text encoding format.
|
|
184
|
+
"""
|
|
106
185
|
if delimiter:
|
|
107
186
|
data = [delimiter.join(entry) for entry in data]
|
|
108
187
|
|
|
109
188
|
with open(file, "w", encoding=encoding) as f:
|
|
110
189
|
for entry in data:
|
|
111
190
|
f.write(f"{entry}\n")
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
def run_subprocess(command: str) -> subprocess.CompletedProcess[str] | int:
|
|
115
|
-
try:
|
|
116
|
-
result = subprocess.run(
|
|
117
|
-
["bash", "-c", command],
|
|
118
|
-
stdout=subprocess.PIPE,
|
|
119
|
-
stderr=subprocess.PIPE,
|
|
120
|
-
check=True,
|
|
121
|
-
text=True,
|
|
122
|
-
)
|
|
123
|
-
return result
|
|
124
|
-
|
|
125
|
-
except subprocess.CalledProcessError as e:
|
|
126
|
-
sys.stderr.write(f"{e}\n")
|
|
127
|
-
return 1
|
metahq_core/util/supported.py
CHANGED
|
@@ -7,7 +7,7 @@ Functions beginning with an underscore are intended to be called through the
|
|
|
7
7
|
Author: Parker Hicks
|
|
8
8
|
Date: 2025-04-15
|
|
9
9
|
|
|
10
|
-
Last updated:
|
|
10
|
+
Last updated: 2026-02-02 by Parker Hicks
|
|
11
11
|
"""
|
|
12
12
|
|
|
13
13
|
from pathlib import Path
|
|
@@ -122,7 +122,7 @@ def _age_groups() -> list[str]:
|
|
|
122
122
|
"adolescent",
|
|
123
123
|
"adult",
|
|
124
124
|
"older_adult",
|
|
125
|
-
"
|
|
125
|
+
"elderly_adult",
|
|
126
126
|
]
|
|
127
127
|
|
|
128
128
|
|
|
@@ -141,8 +141,6 @@ def species_map() -> dict[str, str]:
|
|
|
141
141
|
return {
|
|
142
142
|
"human": "homo sapiens",
|
|
143
143
|
"mouse": "mus musculus",
|
|
144
|
-
"worm": "caenorhabditis elegans",
|
|
145
|
-
"fly": "drosophila melanogaster",
|
|
146
144
|
"zebrafish": "danio rerio",
|
|
147
145
|
"rat": "rattus norvegicus",
|
|
148
146
|
}
|
|
@@ -161,7 +159,13 @@ def get_annotations(level: Literal["sample", "series"]) -> Path:
|
|
|
161
159
|
|
|
162
160
|
def get_config():
|
|
163
161
|
"""Loads the MetaHQ config file."""
|
|
164
|
-
|
|
162
|
+
config = load_yaml(get_config_file())
|
|
163
|
+
if config is None:
|
|
164
|
+
raise RuntimeError(
|
|
165
|
+
"The MetaHQ configuration is contaminated. Run `metahq setup`."
|
|
166
|
+
)
|
|
167
|
+
|
|
168
|
+
return config
|
|
165
169
|
|
|
166
170
|
|
|
167
171
|
def get_config_file():
|
|
@@ -326,6 +330,13 @@ def ecodes(query: list[str] | str) -> list[str]:
|
|
|
326
330
|
return query
|
|
327
331
|
|
|
328
332
|
|
|
333
|
+
def levels(query: str) -> str:
|
|
334
|
+
"""Check if queried level is supported."""
|
|
335
|
+
if query in supported("levels"):
|
|
336
|
+
return query
|
|
337
|
+
raise ValueError(f"Expected query in {supported("levels")}, got {query}.")
|
|
338
|
+
|
|
339
|
+
|
|
329
340
|
def metadata_fields(level: str) -> list[str]:
|
|
330
341
|
"""Returns supported metadata fields for a specified level."""
|
|
331
342
|
if level == "sample":
|
|
@@ -1,17 +1,16 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: metahq-core
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 1.0.0rc1
|
|
4
4
|
Summary: Core API for the meta-hq CLI.
|
|
5
5
|
Author-email: Parker Hicks <parker.hicks@cuanschutz.edu>, Faisal Alquaddoomi <faisal.alquaddoomi@cuanschutz.edu>
|
|
6
|
-
|
|
6
|
+
License-File: LICENSE
|
|
7
|
+
Keywords: Data Curation,Database,Public Biomedical Data
|
|
7
8
|
Classifier: Development Status :: 3 - Alpha
|
|
8
9
|
Classifier: Intended Audience :: Science/Research
|
|
9
10
|
Classifier: Operating System :: OS Independent
|
|
10
|
-
Classifier: Programming Language :: Python :: 3
|
|
11
|
-
Classifier: Programming Language :: Python :: 3.11
|
|
12
11
|
Classifier: Programming Language :: Python :: 3.12
|
|
13
12
|
Classifier: Programming Language :: Python :: 3.13
|
|
14
|
-
Requires-Python: >=3.
|
|
13
|
+
Requires-Python: >=3.12
|
|
15
14
|
Requires-Dist: duckdb>=1.4.0
|
|
16
15
|
Requires-Dist: networkx>=3.0
|
|
17
16
|
Requires-Dist: numpy>=2.3.0
|
|
@@ -21,13 +20,20 @@ Requires-Dist: pydantic>=2.0.0
|
|
|
21
20
|
Requires-Dist: pymongo>=4.13.0
|
|
22
21
|
Requires-Dist: pyyaml>=5.1
|
|
23
22
|
Requires-Dist: rank-bm25>=0.2.2
|
|
23
|
+
Requires-Dist: rich>=13.0.0
|
|
24
24
|
Provides-Extra: dev
|
|
25
25
|
Requires-Dist: black; extra == 'dev'
|
|
26
26
|
Requires-Dist: flake8; extra == 'dev'
|
|
27
27
|
Requires-Dist: isort; extra == 'dev'
|
|
28
|
+
Requires-Dist: mkdocs-click; extra == 'dev'
|
|
29
|
+
Requires-Dist: mkdocs-material; extra == 'dev'
|
|
30
|
+
Requires-Dist: mkdocs>=1.6.1; extra == 'dev'
|
|
31
|
+
Requires-Dist: mkdocstrings[python]; extra == 'dev'
|
|
28
32
|
Requires-Dist: mypy; extra == 'dev'
|
|
33
|
+
Requires-Dist: pymdown-extensions; extra == 'dev'
|
|
29
34
|
Requires-Dist: pytest-cov; extra == 'dev'
|
|
30
35
|
Requires-Dist: pytest>=8.0; extra == 'dev'
|
|
36
|
+
Requires-Dist: vulture; extra == 'dev'
|
|
31
37
|
Provides-Extra: test
|
|
32
38
|
Requires-Dist: pytest-benchmark; extra == 'test'
|
|
33
39
|
Requires-Dist: pytest-cov; extra == 'test'
|
|
@@ -37,9 +43,10 @@ Description-Content-Type: text/markdown
|
|
|
37
43
|
# metahq-core
|
|
38
44
|
|
|
39
45
|

|
|
40
|
-

|
|
41
47
|

|
|
42
48
|

|
|
49
|
+
[](https://opensource.org/licenses/BSD-3-Clause)
|
|
43
50
|
|
|
44
51
|
Backend package for `metahq-cli` also available on PyPI. Currently this package
|
|
45
52
|
is solely intended to be used through the MetaHQ CLI.
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
metahq_core/README.md,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
2
|
+
metahq_core/__init__.py,sha256=co7RISTHQOXWWL_YBSfz24445wRZprPGwQxVxn-FWKk,27
|
|
3
|
+
metahq_core/logger.py,sha256=Nq5VjjzrDniL2mZaydniKgElgIWdQOp-k-8DvXCpubU,1165
|
|
4
|
+
metahq_core/query.py,sha256=RlPCUaExFrowfBuwJ8K9SAotTo_ko1FeJr01sskGbq4,22373
|
|
5
|
+
metahq_core/relations_loader.py,sha256=WQMJs4bN9Uy2E8qqrGlDtJMW65A1wt0s4azLLOE0Mew,4758
|
|
6
|
+
metahq_core/search.py,sha256=g0LHprB2Z-8-kmLaOgZ4VUN4RRZNUY_d8RP7Cqzl0c0,10038
|
|
7
|
+
metahq_core/curations/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
8
|
+
metahq_core/curations/_multiprocess_propagator.py,sha256=KUiTgcOSLJv0VskzEk2kOpSFHZsUCyupdpOCVdN8vwM,3510
|
|
9
|
+
metahq_core/curations/annotation_converter.py,sha256=lnDjnGOMXspUgUS7YA13G2BZw-mTApkcQU_6H5C1Nt8,8873
|
|
10
|
+
metahq_core/curations/annotations.py,sha256=WXZMTYuNnDXf8K84yCzOxCJiPm59WKyUoIcCvC9VBPY,26559
|
|
11
|
+
metahq_core/curations/base.py,sha256=3Q3gd9G7K4J9rewg7Cn9rAfml1N2Xgor-V2C3OHWeuI,1829
|
|
12
|
+
metahq_core/curations/index.py,sha256=Chy5Y5z8A2ob-cl0JenR1hWunRRikOpc1BdvrORSbtE,5020
|
|
13
|
+
metahq_core/curations/labels.py,sha256=BVnxd9qeRvS7Ji5OR6fTCcneLYJI4PwgVNwZ5jFIVgs,17205
|
|
14
|
+
metahq_core/curations/propagator.py,sha256=o4MDmZ4ziJ3yZv0yDdAHLcvNtLLA9DKK-TdzGMEquT8,9639
|
|
15
|
+
metahq_core/export/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
16
|
+
metahq_core/export/annotations.py,sha256=kut8HaNBp0Sq1T5SQ7X8KywXfGDXSRU2dLO9Dl6He_Y,14728
|
|
17
|
+
metahq_core/export/base.py,sha256=j7cKc-ru0ggAXEmGFYiaxBn_OROahQ9HPiR1tK-VX94,1394
|
|
18
|
+
metahq_core/export/labels.py,sha256=K9BFz8e-kJtDQOr9RwlF2ebsjWuxWbLUsoojourKeFw,14816
|
|
19
|
+
metahq_core/util/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
20
|
+
metahq_core/util/alltypes.py,sha256=zYrBKvtkAhR7lmqDlGp7BOh2bUNI-toQfd7o7isDCxw,721
|
|
21
|
+
metahq_core/util/checkers.py,sha256=_7Aw2bO1PNg-9TPYOwKwvTqFtmb5vMyYU-omfUID_DE,508
|
|
22
|
+
metahq_core/util/exceptions.py,sha256=FlYUN8g4lNB3OSwQ20dfnSDmgX8NKZV5Yx7xERurrWc,115
|
|
23
|
+
metahq_core/util/helpers.py,sha256=sak1A7gp2qvnbhCBYHNQ5IUxIZeljgyRSu5U7C8a7bU,949
|
|
24
|
+
metahq_core/util/io.py,sha256=oouWuSZhECiXdZN7K9cXU0q4O8RqsEMsiVOpTrsX2gg,4730
|
|
25
|
+
metahq_core/util/progress.py,sha256=NF158KVFO9pO3vrsl7OrPAhYtd-cXaXRavL0iOV5XeM,2128
|
|
26
|
+
metahq_core/util/supported.py,sha256=UJ8S7esdOTFW5oq9kIHQ1N5GPanXIgntVvxMrgiCjjM,11287
|
|
27
|
+
metahq_core-1.0.0rc1.dist-info/METADATA,sha256=QTTHZqHXg4Uu7QLEUmow5_Cp_rkcruJQ4N5TbwxUIn8,2183
|
|
28
|
+
metahq_core-1.0.0rc1.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
|
|
29
|
+
metahq_core-1.0.0rc1.dist-info/licenses/LICENSE,sha256=1KNh4-XEVT4pk2tvDi-deIXms0suss2eiYLBKBiQDGo,1499
|
|
30
|
+
metahq_core-1.0.0rc1.dist-info/RECORD,,
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
BSD 3-Clause License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025, Krishnan Lab
|
|
4
|
+
|
|
5
|
+
Redistribution and use in source and binary forms, with or without
|
|
6
|
+
modification, are permitted provided that the following conditions are met:
|
|
7
|
+
|
|
8
|
+
1. Redistributions of source code must retain the above copyright notice, this
|
|
9
|
+
list of conditions and the following disclaimer.
|
|
10
|
+
|
|
11
|
+
2. Redistributions in binary form must reproduce the above copyright notice,
|
|
12
|
+
this list of conditions and the following disclaimer in the documentation
|
|
13
|
+
and/or other materials provided with the distribution.
|
|
14
|
+
|
|
15
|
+
3. Neither the name of the copyright holder nor the names of its
|
|
16
|
+
contributors may be used to endorse or promote products derived from
|
|
17
|
+
this software without specific prior written permission.
|
|
18
|
+
|
|
19
|
+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
|
20
|
+
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
21
|
+
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
22
|
+
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
|
23
|
+
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
24
|
+
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
|
25
|
+
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
|
26
|
+
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
|
27
|
+
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
28
|
+
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|