| |
| """Build BindingDB source records and an exact-Kd gold file from pinned zips. |
| |
| Reads the publisher-verified BindingDB curated-articles export (main TSV), |
| the Reactant_set_id -> ENTRYID_ASSAYID mapping, and the Assays export from |
| their ZIP archives, verifies every archive's SHA-256 against the pinned |
| config, and writes: |
| |
| - ``source_records.jsonl``: one versioned JSON envelope per valid |
| single-chain record/measurement (all measurement types and relations), |
| - ``gold_exact_kd.jsonl``: only exact '=' Kd records with one chain, a |
| sequence, a canonicalizable SMILES, a positive nM value, and an assay join, |
| - ``bindingdb_audit.json``: deterministic audit of counts, coverage, and |
| every rejection reason. |
| |
| Nothing is aggregated across rows or assays, and Ki/IC50/EC50 values are |
| never relabeled as Kd. |
| """ |
|
|
| from __future__ import annotations |
|
|
| import argparse |
| import json |
| from pathlib import Path |
|
|
| from mitointeract_recovery import bindingdb_adapter |
|
|
| DEFAULT_CONFIG = Path(__file__).resolve().parents[1] / "config-bindingdb.json" |
|
|
|
|
| def load_config(path: Path) -> dict: |
| config = json.loads(path.read_text()) |
| files = config.get("files") |
| if not isinstance(files, dict): |
| raise ValueError(f"{path}: config must contain a 'files' object") |
| for key in bindingdb_adapter.INPUT_KEYS: |
| entry = files.get(key) |
| if not isinstance(entry, dict): |
| raise ValueError(f"{path}: config files entry {key!r} missing") |
| for field in ("url", "member", "sha256"): |
| if not entry.get(field): |
| raise ValueError(f"{path}: config files[{key!r}] missing {field!r}") |
| return config |
|
|
|
|
| def main() -> None: |
| parser = argparse.ArgumentParser(description=__doc__) |
| parser.add_argument( |
| "--main-zip", type=Path, required=True, help="main articles TSV zip" |
| ) |
| parser.add_argument( |
| "--mapping-zip", |
| type=Path, |
| required=True, |
| help="rsid -> ENTRYID_ASSAYID map zip", |
| ) |
| parser.add_argument( |
| "--assays-zip", type=Path, required=True, help="assay names/descriptions zip" |
| ) |
| parser.add_argument( |
| "--config", |
| type=Path, |
| default=DEFAULT_CONFIG, |
| help="pinned release config (URLs, members, SHA-256 checksums)", |
| ) |
| parser.add_argument("--output-dir", type=Path, required=True) |
| parser.add_argument( |
| "--max-source-rows", |
| type=int, |
| default=None, |
| help="process at most this many main-TSV data rows (for smoke runs)", |
| ) |
| args = parser.parse_args() |
|
|
| if args.max_source_rows is not None and args.max_source_rows < 1: |
| parser.error("--max-source-rows must be a positive integer") |
|
|
| config = load_config(args.config) |
| bindingdb_adapter.run_pipeline( |
| main_zip=args.main_zip, |
| mapping_zip=args.mapping_zip, |
| assays_zip=args.assays_zip, |
| config=config, |
| output_dir=args.output_dir, |
| max_source_rows=args.max_source_rows, |
| ) |
|
|
|
|
| if __name__ == "__main__": |
| main() |
|
|