statgen 0.2.4__tar.gz → 0.2.6__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.
- {statgen-0.2.4 → statgen-0.2.6}/PKG-INFO +1 -1
- {statgen-0.2.4 → statgen-0.2.6}/pyproject.toml +1 -1
- statgen-0.2.6/statgen/__init__.py +5 -0
- {statgen-0.2.4 → statgen-0.2.6}/statgen/_ld_npz.py +19 -1
- statgen-0.2.6/statgen/_ld_reference.py +26 -0
- {statgen-0.2.4 → statgen-0.2.6}/statgen/_ld_schema.py +13 -3
- {statgen-0.2.4 → statgen-0.2.6}/statgen/_ld_writer.py +30 -1
- statgen-0.2.6/statgen/_verbosity.py +20 -0
- {statgen-0.2.4 → statgen-0.2.6}/statgen/ld.py +25 -13
- {statgen-0.2.4 → statgen-0.2.6}/statgen/reference.py +18 -15
- {statgen-0.2.4 → statgen-0.2.6}/statgen.egg-info/PKG-INFO +1 -1
- {statgen-0.2.4 → statgen-0.2.6}/statgen.egg-info/SOURCES.txt +1 -0
- statgen-0.2.4/statgen/__init__.py +0 -1
- statgen-0.2.4/statgen/_ld_reference.py +0 -57
- {statgen-0.2.4 → statgen-0.2.6}/README.md +0 -0
- {statgen-0.2.4 → statgen-0.2.6}/setup.cfg +0 -0
- {statgen-0.2.4 → statgen-0.2.6}/statgen/_bfile_utils.py +0 -0
- {statgen-0.2.4 → statgen-0.2.6}/statgen/_utils.py +0 -0
- {statgen-0.2.4 → statgen-0.2.6}/statgen/_variant_match.py +0 -0
- {statgen-0.2.4 → statgen-0.2.6}/statgen/annotations.py +0 -0
- {statgen-0.2.4 → statgen-0.2.6}/statgen/genotype.py +0 -0
- {statgen-0.2.4 → statgen-0.2.6}/statgen/sumstats.py +0 -0
- {statgen-0.2.4 → statgen-0.2.6}/statgen.egg-info/dependency_links.txt +0 -0
- {statgen-0.2.4 → statgen-0.2.6}/statgen.egg-info/requires.txt +0 -0
- {statgen-0.2.4 → statgen-0.2.6}/statgen.egg-info/top_level.txt +0 -0
|
@@ -23,7 +23,14 @@ def validate_npz_distribution(path, check_payload_structure=False) -> dict:
|
|
|
23
23
|
raise ValueError("validate_npz_distribution: path must identify a panel root directory")
|
|
24
24
|
|
|
25
25
|
manifest = read_manifest(path / "ld_manifest.json", expected_runtime=PY_RUNTIME_FORMAT)
|
|
26
|
-
|
|
26
|
+
reference_cache_path = path / manifest["reference_cache"]
|
|
27
|
+
require_file(reference_cache_path)
|
|
28
|
+
if md5_file(reference_cache_path) != manifest["reference_cache_md5"]:
|
|
29
|
+
raise ValueError(f"{reference_cache_path}: reference_cache_md5 does not match manifest")
|
|
30
|
+
from .reference import load_reference_cache
|
|
31
|
+
|
|
32
|
+
reference = load_reference_cache(reference_cache_path)
|
|
33
|
+
ref_by_label = {s.label: s for s in reference.shards}
|
|
27
34
|
seen_reference_bim = set()
|
|
28
35
|
for entry in manifest["shards"]:
|
|
29
36
|
shard_path = path / entry["file"]
|
|
@@ -36,6 +43,10 @@ def validate_npz_distribution(path, check_payload_structure=False) -> dict:
|
|
|
36
43
|
check_payload_structure=check_payload_structure,
|
|
37
44
|
)
|
|
38
45
|
validate_manifest_entry_agreement(entry, meta, shard_path)
|
|
46
|
+
ref_shard = ref_by_label.get(entry["chr"])
|
|
47
|
+
if ref_shard is None:
|
|
48
|
+
raise ValueError(f"{reference_cache_path}: reference cache missing shard {entry['chr']}")
|
|
49
|
+
_validate_reference_cache_entry(ref_shard, entry, reference_cache_path)
|
|
39
50
|
reference_key = (
|
|
40
51
|
entry["reference_bim"],
|
|
41
52
|
entry["chr"],
|
|
@@ -64,6 +75,13 @@ def _validate_bundled_reference(*, root: Path, entry: dict) -> None:
|
|
|
64
75
|
validate_bundled_reference_bim(root / entry["reference_bim"], entry, target="manifest")
|
|
65
76
|
|
|
66
77
|
|
|
78
|
+
def _validate_reference_cache_entry(ref_shard, entry: dict, path: Path) -> None:
|
|
79
|
+
if ref_shard.num_snp != int(entry["num_snp"]):
|
|
80
|
+
raise ValueError(f"{path}: reference cache num_snp does not match manifest")
|
|
81
|
+
if ref_shard.checksum != entry["reference_checksum"]:
|
|
82
|
+
raise ValueError(f"{path}: reference cache reference_checksum does not match manifest")
|
|
83
|
+
|
|
84
|
+
|
|
67
85
|
def read_npz_shard(path: Path, check_payload_structure: bool):
|
|
68
86
|
require_file(path)
|
|
69
87
|
with np.load(path, allow_pickle=False) as data:
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
from pathlib import Path
|
|
2
|
+
|
|
3
|
+
from ._ld_schema import require_file
|
|
4
|
+
from .reference import load_reference
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
def validate_bundled_reference_bim(path, entry: dict, *, target: str):
|
|
8
|
+
path = Path(path)
|
|
9
|
+
require_file(path)
|
|
10
|
+
panel = load_reference(path)
|
|
11
|
+
ref_shards = panel.shards
|
|
12
|
+
if len(ref_shards) != 1:
|
|
13
|
+
raise ValueError(f"{path}: bundled reference_bim must contain exactly one shard")
|
|
14
|
+
ref = ref_shards[0]
|
|
15
|
+
validate_reference_shard_for_ld_entry(ref, entry, path, target=target)
|
|
16
|
+
return ref
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def validate_reference_shard_for_ld_entry(ref_shard, entry: dict, path, *, target: str) -> None:
|
|
20
|
+
path = Path(path)
|
|
21
|
+
if ref_shard.label != entry["chr"]:
|
|
22
|
+
raise ValueError(f"{path}: bundled reference_bim chr does not match {target}")
|
|
23
|
+
if ref_shard.num_snp != int(entry["num_snp"]):
|
|
24
|
+
raise ValueError(f"{path}: bundled reference_bim num_snp does not match {target}")
|
|
25
|
+
if ref_shard.checksum != entry["reference_checksum"]:
|
|
26
|
+
raise ValueError(f"{path}: bundled reference_bim reference_checksum does not match {target}")
|
|
@@ -28,6 +28,13 @@ def read_manifest(path: Path, expected_runtime: str | None) -> dict:
|
|
|
28
28
|
raise ValueError(f"{path}: unsupported LD runtime_format {runtime!r}")
|
|
29
29
|
if expected_runtime is not None and runtime != expected_runtime:
|
|
30
30
|
raise ValueError(f"{path}: expected runtime_format {expected_runtime!r}, got {runtime!r}")
|
|
31
|
+
validate_plain_relative_filename(
|
|
32
|
+
manifest.get("reference_cache"),
|
|
33
|
+
f"{path}: reference_cache",
|
|
34
|
+
)
|
|
35
|
+
reference_cache_md5 = manifest.get("reference_cache_md5")
|
|
36
|
+
if not isinstance(reference_cache_md5, str) or len(reference_cache_md5) != 32:
|
|
37
|
+
raise ValueError(f"{path}: reference_cache_md5 must be a lowercase MD5 hex string")
|
|
31
38
|
shards = manifest.get("shards")
|
|
32
39
|
if not isinstance(shards, list) or not shards:
|
|
33
40
|
raise ValueError(f"{path}: shards must be a non-empty list")
|
|
@@ -71,7 +78,7 @@ def validate_manifest_entry(entry: dict, where: str) -> None:
|
|
|
71
78
|
raise ValueError(f"{where}: reference_checksum must be a non-empty string")
|
|
72
79
|
if not isinstance(entry["file_md5"], str) or len(entry["file_md5"]) != 32:
|
|
73
80
|
raise ValueError(f"{where}: file_md5 must be a lowercase MD5 hex string")
|
|
74
|
-
|
|
81
|
+
validate_plain_relative_filename(entry["reference_bim"], f"{where}: reference_bim")
|
|
75
82
|
|
|
76
83
|
|
|
77
84
|
def validate_shard_metadata(meta: dict, path: Path, expected_format: str) -> None:
|
|
@@ -118,7 +125,7 @@ def validate_shard_metadata(meta: dict, path: Path, expected_format: str) -> Non
|
|
|
118
125
|
raise ValueError(f"{path}: metadata value must be 'r'")
|
|
119
126
|
if not isinstance(meta["reference_checksum"], str) or meta["reference_checksum"] == "":
|
|
120
127
|
raise ValueError(f"{path}: metadata reference_checksum must be a non-empty string")
|
|
121
|
-
|
|
128
|
+
validate_plain_relative_filename(meta["reference_bim"], f"{path}: metadata reference_bim")
|
|
122
129
|
if expected_format == NPZ_FORMAT:
|
|
123
130
|
if meta.get("sparse_layout") != "csc":
|
|
124
131
|
raise ValueError(f"{path}: metadata sparse_layout must be 'csc'")
|
|
@@ -154,7 +161,7 @@ def default_reference_bim_filename(chr_label: str) -> str:
|
|
|
154
161
|
return f"reference_chr{chr_label}.bim"
|
|
155
162
|
|
|
156
163
|
|
|
157
|
-
def
|
|
164
|
+
def validate_plain_relative_filename(value, where: str) -> str:
|
|
158
165
|
if not isinstance(value, str) or value == "":
|
|
159
166
|
raise ValueError(f"{where} must be a non-empty filename")
|
|
160
167
|
path = Path(value)
|
|
@@ -163,6 +170,9 @@ def validate_reference_bim_filename(value, where: str) -> str:
|
|
|
163
170
|
return value
|
|
164
171
|
|
|
165
172
|
|
|
173
|
+
validate_reference_bim_filename = validate_plain_relative_filename
|
|
174
|
+
|
|
175
|
+
|
|
166
176
|
def runtime_from_suffix(path: Path) -> str:
|
|
167
177
|
if path.suffix == ".npz":
|
|
168
178
|
return PY_RUNTIME_FORMAT
|
|
@@ -22,9 +22,12 @@ from ._ld_schema import (
|
|
|
22
22
|
validate_shard_metadata,
|
|
23
23
|
)
|
|
24
24
|
from ._ld_reference import validate_bundled_reference_bim
|
|
25
|
+
from .reference import ReferencePanel, load_reference, save_reference_cache
|
|
25
26
|
from ._utils import CHR_RANK
|
|
26
27
|
|
|
27
28
|
|
|
29
|
+
REFERENCE_CACHE_FILENAME = "reference_cache.npz"
|
|
30
|
+
|
|
28
31
|
LD_BUILD_METADATA_DEFAULTS = {
|
|
29
32
|
"build_tool": "statgen",
|
|
30
33
|
"build_command": "synthetic/internal LD artifact writer",
|
|
@@ -101,10 +104,13 @@ def write_ld_npz_manifest(root, records, *, validate=True) -> dict:
|
|
|
101
104
|
records = list(records)
|
|
102
105
|
if not records:
|
|
103
106
|
raise ValueError("LD manifest must contain at least one shard")
|
|
107
|
+
reference_cache = _write_reference_cache(root, records, REFERENCE_CACHE_FILENAME)
|
|
104
108
|
manifest = {
|
|
105
109
|
"object_type": "ld_panel_manifest",
|
|
106
110
|
"schema_version": MANIFEST_SCHEMA,
|
|
107
111
|
"runtime_format": PY_RUNTIME_FORMAT,
|
|
112
|
+
"reference_cache": reference_cache.name,
|
|
113
|
+
"reference_cache_md5": md5_file(reference_cache),
|
|
108
114
|
"shards": records,
|
|
109
115
|
}
|
|
110
116
|
_write_json(root / "ld_manifest.json", manifest)
|
|
@@ -117,7 +123,11 @@ def create_ld_npz_manifest(root, *, validate=True) -> dict:
|
|
|
117
123
|
root = Path(root)
|
|
118
124
|
if not root.is_dir():
|
|
119
125
|
raise FileNotFoundError(f"LD distribution root not found: {root}")
|
|
120
|
-
records = [
|
|
126
|
+
records = [
|
|
127
|
+
_ld_npz_manifest_record(path, root)
|
|
128
|
+
for path in root.glob("*.npz")
|
|
129
|
+
if path.name != REFERENCE_CACHE_FILENAME
|
|
130
|
+
]
|
|
121
131
|
records.sort(key=_ld_manifest_sort_key)
|
|
122
132
|
return write_ld_npz_manifest(root, records, validate=validate)
|
|
123
133
|
|
|
@@ -447,6 +457,25 @@ def _require_reference_bim(root: Path, meta: dict) -> str:
|
|
|
447
457
|
return reference_bim
|
|
448
458
|
|
|
449
459
|
|
|
460
|
+
def _write_reference_cache(root: Path, records: list[dict], file_name: str) -> Path:
|
|
461
|
+
ref_shards = []
|
|
462
|
+
seen = set()
|
|
463
|
+
for record in records:
|
|
464
|
+
label = record["chr"]
|
|
465
|
+
if label in seen:
|
|
466
|
+
continue
|
|
467
|
+
seen.add(label)
|
|
468
|
+
panel = load_reference(root / record["reference_bim"])
|
|
469
|
+
if len(panel.shards) != 1:
|
|
470
|
+
raise ValueError(f"{root / record['reference_bim']}: bundled reference_bim must contain exactly one shard")
|
|
471
|
+
ref = panel.shards[0]
|
|
472
|
+
validate_bundled_reference_bim(root / record["reference_bim"], record, target="manifest")
|
|
473
|
+
ref_shards.append(ref)
|
|
474
|
+
cache_path = root / file_name
|
|
475
|
+
save_reference_cache(ReferencePanel(ref_shards), cache_path)
|
|
476
|
+
return cache_path
|
|
477
|
+
|
|
478
|
+
|
|
450
479
|
def _write_deterministic_npz(path: Path, arrays: dict[str, np.ndarray]) -> None:
|
|
451
480
|
with zipfile.ZipFile(path, "w", compression=zipfile.ZIP_DEFLATED) as zf:
|
|
452
481
|
for name, array in arrays.items():
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import sys
|
|
2
|
+
|
|
3
|
+
_LEVELS = ("quiet", "info")
|
|
4
|
+
_VERBOSITY = "info"
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
def set_verbosity(level: str) -> None:
|
|
8
|
+
global _VERBOSITY
|
|
9
|
+
if level not in _LEVELS:
|
|
10
|
+
raise ValueError("verbosity must be one of: quiet, info")
|
|
11
|
+
_VERBOSITY = level
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
def get_verbosity() -> str:
|
|
15
|
+
return _VERBOSITY
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
def info(message: str) -> None:
|
|
19
|
+
if _VERBOSITY == "info":
|
|
20
|
+
print(message, file=sys.stderr)
|
|
@@ -13,6 +13,7 @@ from ._ld_schema import (
|
|
|
13
13
|
validate_manifest_entry_agreement,
|
|
14
14
|
)
|
|
15
15
|
from ._utils import validate_requested_shards
|
|
16
|
+
from ._verbosity import info as _log_info
|
|
16
17
|
|
|
17
18
|
|
|
18
19
|
class LDShard:
|
|
@@ -245,20 +246,13 @@ class LDPanel:
|
|
|
245
246
|
return sparse.vstack(parts, format=M.getformat()).astype(out_dtype)
|
|
246
247
|
|
|
247
248
|
|
|
248
|
-
def load_ld(path,
|
|
249
|
+
def load_ld(path, shards=None, default_chrX_sex=None) -> LDPanel:
|
|
249
250
|
default_chrX_sex = validate_chrx_sex(
|
|
250
251
|
"female" if default_chrX_sex is None else default_chrX_sex,
|
|
251
252
|
"default_chrX_sex",
|
|
252
253
|
)
|
|
253
|
-
path =
|
|
254
|
-
|
|
255
|
-
raise ValueError("load_ld: path must identify a panel root directory")
|
|
256
|
-
|
|
257
|
-
manifest = read_manifest(path / "ld_manifest.json", expected_runtime=PY_RUNTIME_FORMAT)
|
|
258
|
-
if reference is None:
|
|
259
|
-
reference = _load_bundled_reference(path, manifest, shards)
|
|
260
|
-
elif shards is not None:
|
|
261
|
-
reference = reference.select_shards(shards)
|
|
254
|
+
path, manifest = _read_panel_manifest(path, "load_ld")
|
|
255
|
+
reference = _load_manifest_reference_cache(path, manifest, shards)
|
|
262
256
|
|
|
263
257
|
ref_shards = list(reference.shards)
|
|
264
258
|
if not ref_shards:
|
|
@@ -268,6 +262,11 @@ def load_ld(path, reference=None, shards=None, default_chrX_sex=None) -> LDPanel
|
|
|
268
262
|
return LDPanel(groups, default_chrX_sex=default_chrX_sex, reference=reference)
|
|
269
263
|
|
|
270
264
|
|
|
265
|
+
def load_ld_reference(path, shards=None):
|
|
266
|
+
path, manifest = _read_panel_manifest(path, "load_ld_reference")
|
|
267
|
+
return _load_manifest_reference_cache(path, manifest, shards)
|
|
268
|
+
|
|
269
|
+
|
|
271
270
|
def validate_ld_distribution(path, check_payload_structure=False) -> dict:
|
|
272
271
|
if not Path(path).is_dir():
|
|
273
272
|
raise ValueError("validate_ld_distribution: path must identify a panel root directory")
|
|
@@ -349,10 +348,19 @@ def _write_ld_npz_distribution(*args, **kwargs):
|
|
|
349
348
|
return write_ld_npz_distribution(*args, **kwargs)
|
|
350
349
|
|
|
351
350
|
|
|
352
|
-
def
|
|
353
|
-
|
|
351
|
+
def _read_panel_manifest(path, where: str) -> tuple[Path, dict]:
|
|
352
|
+
path = Path(path)
|
|
353
|
+
if not path.is_dir():
|
|
354
|
+
raise ValueError(f"{where}: path must identify a panel root directory")
|
|
355
|
+
return path, read_manifest(path / "ld_manifest.json", expected_runtime=PY_RUNTIME_FORMAT)
|
|
356
|
+
|
|
357
|
+
|
|
358
|
+
def _load_manifest_reference_cache(root: Path, manifest: dict, shards):
|
|
359
|
+
from .reference import load_reference_cache
|
|
354
360
|
|
|
355
|
-
|
|
361
|
+
reference_cache_path = root / manifest["reference_cache"]
|
|
362
|
+
require_file(reference_cache_path)
|
|
363
|
+
return load_reference_cache(reference_cache_path, shards=shards)
|
|
356
364
|
|
|
357
365
|
|
|
358
366
|
def _load_panel_root(root: Path, manifest: dict, ref_shards: list) -> list[list[LDShard]]:
|
|
@@ -378,6 +386,10 @@ def _load_panel_root(root: Path, manifest: dict, ref_shards: list) -> list[list[
|
|
|
378
386
|
seen_sex = set()
|
|
379
387
|
for entry in selected:
|
|
380
388
|
shard_path = root / entry["file"]
|
|
389
|
+
label = str(entry.get("chr"))
|
|
390
|
+
sex = entry.get("sex")
|
|
391
|
+
suffix = "" if sex is None else f" ({sex})"
|
|
392
|
+
_log_info(f"statgen.load_ld: loading shard {label}{suffix} from {shard_path}")
|
|
381
393
|
shard, meta = _load_npz_shard(shard_path)
|
|
382
394
|
validate_manifest_entry_agreement(entry, meta, shard_path)
|
|
383
395
|
_validate_reference_compatibility(shard, ref_shard, shard_path)
|
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import hashlib
|
|
2
|
+
import io
|
|
2
3
|
import json
|
|
3
4
|
import logging
|
|
4
5
|
from pathlib import Path
|
|
6
|
+
import zipfile
|
|
5
7
|
|
|
6
8
|
import numpy as np
|
|
7
9
|
import pandas as pd
|
|
@@ -339,8 +341,8 @@ class ReferencePanel:
|
|
|
339
341
|
ok = False
|
|
340
342
|
return ok
|
|
341
343
|
|
|
342
|
-
def save_cache(self, path,
|
|
343
|
-
save_reference_cache(self, path,
|
|
344
|
+
def save_cache(self, path, format=None) -> None:
|
|
345
|
+
save_reference_cache(self, path, format=format)
|
|
344
346
|
|
|
345
347
|
|
|
346
348
|
def load_reference(path, shards=None) -> ReferencePanel:
|
|
@@ -401,18 +403,12 @@ def load_reference(path, shards=None) -> ReferencePanel:
|
|
|
401
403
|
return ReferencePanel(out_shards)
|
|
402
404
|
|
|
403
405
|
|
|
404
|
-
def save_reference_cache(panel: ReferencePanel, path,
|
|
405
|
-
mode = str(mode).lower()
|
|
406
|
-
if mode not in {"full", "thin"}:
|
|
407
|
-
raise ValueError("save_reference_cache mode must be 'full' or 'thin'")
|
|
408
|
-
|
|
406
|
+
def save_reference_cache(panel: ReferencePanel, path, format=None) -> None:
|
|
409
407
|
# Metadata (schema, labels, checksums) as a compact JSON blob stored in the npz.
|
|
410
408
|
# SNP-axis numeric vectors (bp) and string arrays are stored as native
|
|
411
409
|
# binary numpy arrays — not JSON — per the performance contract.
|
|
412
|
-
# Python keeps reference caches full even when mode='thin' is requested.
|
|
413
410
|
meta = {
|
|
414
411
|
"schema": _CACHE_SCHEMA,
|
|
415
|
-
"mode": "full",
|
|
416
412
|
"shard_labels": [s.label for s in panel.shards],
|
|
417
413
|
"shard_checksums": [s.checksum for s in panel.shards],
|
|
418
414
|
}
|
|
@@ -428,7 +424,7 @@ def save_reference_cache(panel: ReferencePanel, path, mode: str = "full", format
|
|
|
428
424
|
arrays[p + "a2"] = np.asarray(s.a2, dtype=str)
|
|
429
425
|
arrays[p + "a1_hash64"] = s.a1_hash64
|
|
430
426
|
arrays[p + "a2_hash64"] = s.a2_hash64
|
|
431
|
-
|
|
427
|
+
_write_deterministic_npz(Path(path), arrays)
|
|
432
428
|
|
|
433
429
|
|
|
434
430
|
def load_reference_cache(path, shards=None) -> ReferencePanel:
|
|
@@ -437,11 +433,6 @@ def load_reference_cache(path, shards=None) -> ReferencePanel:
|
|
|
437
433
|
schema = meta.get("schema")
|
|
438
434
|
if schema != _CACHE_SCHEMA:
|
|
439
435
|
raise ValueError(f"Unsupported reference cache schema: {schema!r}")
|
|
440
|
-
mode = meta.get("mode")
|
|
441
|
-
if mode is None:
|
|
442
|
-
raise ValueError("reference cache missing mode; delete and rebuild old cache")
|
|
443
|
-
if mode != "full":
|
|
444
|
-
raise ValueError(f"Unsupported Python reference cache mode: {mode!r}")
|
|
445
436
|
|
|
446
437
|
labels = list(meta.get("shard_labels", []))
|
|
447
438
|
checksums = list(meta.get("shard_checksums", []))
|
|
@@ -470,3 +461,15 @@ def load_reference_cache(path, shards=None) -> ReferencePanel:
|
|
|
470
461
|
)
|
|
471
462
|
)
|
|
472
463
|
return ReferencePanel(shard_objs)
|
|
464
|
+
|
|
465
|
+
|
|
466
|
+
def _write_deterministic_npz(path: Path, arrays: dict[str, np.ndarray]) -> None:
|
|
467
|
+
path.parent.mkdir(parents=True, exist_ok=True)
|
|
468
|
+
with zipfile.ZipFile(path, "w", compression=zipfile.ZIP_DEFLATED) as zf:
|
|
469
|
+
for name, array in arrays.items():
|
|
470
|
+
buf = io.BytesIO()
|
|
471
|
+
np.save(buf, array, allow_pickle=False)
|
|
472
|
+
info = zipfile.ZipInfo(f"{name}.npy", date_time=(1980, 1, 1, 0, 0, 0))
|
|
473
|
+
info.compress_type = zipfile.ZIP_DEFLATED
|
|
474
|
+
info.external_attr = 0o644 << 16
|
|
475
|
+
zf.writestr(info, buf.getvalue())
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
__version__ = "0.2.4"
|
|
@@ -1,57 +0,0 @@
|
|
|
1
|
-
from pathlib import Path
|
|
2
|
-
|
|
3
|
-
from ._ld_schema import require_file
|
|
4
|
-
from ._utils import validate_requested_shards
|
|
5
|
-
from .reference import ReferencePanel, load_reference
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
def validate_bundled_reference_bim(path, entry: dict, *, target: str):
|
|
9
|
-
path = Path(path)
|
|
10
|
-
require_file(path)
|
|
11
|
-
panel = load_reference(path)
|
|
12
|
-
ref_shards = panel.shards
|
|
13
|
-
if len(ref_shards) != 1:
|
|
14
|
-
raise ValueError(f"{path}: bundled reference_bim must contain exactly one shard")
|
|
15
|
-
ref = ref_shards[0]
|
|
16
|
-
validate_reference_shard_for_ld_entry(ref, entry, path, target=target)
|
|
17
|
-
return ref
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
def validate_reference_shard_for_ld_entry(ref_shard, entry: dict, path, *, target: str) -> None:
|
|
21
|
-
path = Path(path)
|
|
22
|
-
if ref_shard.label != entry["chr"]:
|
|
23
|
-
raise ValueError(f"{path}: bundled reference_bim chr does not match {target}")
|
|
24
|
-
if ref_shard.num_snp != int(entry["num_snp"]):
|
|
25
|
-
raise ValueError(f"{path}: bundled reference_bim num_snp does not match {target}")
|
|
26
|
-
if ref_shard.checksum != entry["reference_checksum"]:
|
|
27
|
-
raise ValueError(f"{path}: bundled reference_bim reference_checksum does not match {target}")
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
def load_bundled_reference_panel(root, manifest: dict, shards, *, where: str) -> ReferencePanel:
|
|
31
|
-
root = Path(root)
|
|
32
|
-
available = _manifest_chr_labels(manifest)
|
|
33
|
-
selected = validate_requested_shards(shards, available, where)
|
|
34
|
-
entries_by_chr = {}
|
|
35
|
-
for entry in manifest["shards"]:
|
|
36
|
-
entries_by_chr.setdefault(entry["chr"], []).append(entry)
|
|
37
|
-
|
|
38
|
-
ref_shards = []
|
|
39
|
-
for label in selected:
|
|
40
|
-
entries = entries_by_chr[label]
|
|
41
|
-
reference_path = root / entries[0]["reference_bim"]
|
|
42
|
-
ref_shard = validate_bundled_reference_bim(reference_path, entries[0], target="manifest")
|
|
43
|
-
for entry in entries[1:]:
|
|
44
|
-
validate_reference_shard_for_ld_entry(ref_shard, entry, reference_path, target="manifest")
|
|
45
|
-
ref_shards.append(ref_shard)
|
|
46
|
-
return ReferencePanel(ref_shards)
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
def _manifest_chr_labels(manifest: dict) -> list[str]:
|
|
50
|
-
labels = []
|
|
51
|
-
seen = set()
|
|
52
|
-
for entry in manifest["shards"]:
|
|
53
|
-
label = entry["chr"]
|
|
54
|
-
if label not in seen:
|
|
55
|
-
labels.append(label)
|
|
56
|
-
seen.add(label)
|
|
57
|
-
return labels
|
|
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
|