#!/usr/bin/env python3 """Load HPO's gene-to-phenotype annotations into the gene_phenotypes table. This is the reference data the ranking matches a case's phenotype against. Source file: https://purl.obolibrary.org/obo/hp/hpoa/genes_to_phenotype.txt (HPO release, ~20 MB). Cite the Human Phenotype Ontology when showing results; see docs/data.md. """ import argparse import csv import io import os import sys import urllib.request from sqlalchemy import create_engine, text from sqlalchemy.engine import make_url URL = "https://purl.obolibrary.org/obo/hp/hpoa/genes_to_phenotype.txt" def rows(handle: io.TextIOBase) -> list[tuple[str, str, str]]: """Unique (gene, term) pairs; the file repeats them once per associated disease.""" seen: set[tuple[str, str]] = set() out: list[tuple[str, str, str]] = [] for row in csv.DictReader(handle, delimiter="\t"): gene, hpo_id, name = row["gene_symbol"], row["hpo_id"], row["hpo_name"] if not gene or not hpo_id or (gene, hpo_id) in seen: continue seen.add((gene, hpo_id)) out.append((gene[:60], hpo_id[:20], name[:200])) return out def main() -> None: p = argparse.ArgumentParser() p.add_argument("--url", default=URL) p.add_argument("--file", help="use a local copy instead of downloading") a = p.parse_args() url = os.environ.get("DATABASE_URL") if not url: sys.exit("DATABASE_URL is not set") if a.file: with open(a.file) as fh: annotations = rows(fh) else: print(f"downloading {a.url}", file=sys.stderr) with urllib.request.urlopen(a.url) as response: # noqa: S310 - fixed HPO release URL annotations = rows(io.TextIOWrapper(response, encoding="utf-8")) print(f"{len(annotations)} gene/term pairs", file=sys.stderr) engine = create_engine(make_url(url).set(drivername="postgresql+psycopg")) with engine.begin() as conn: conn.execute(text("TRUNCATE gene_phenotypes RESTART IDENTITY")) cursor = conn.connection.cursor() with cursor.copy("COPY gene_phenotypes (gene_symbol, hpo_id, hpo_name) FROM STDIN") as copy: for row in annotations: copy.write_row(row) print(f"loaded {len(annotations)} annotations", file=sys.stderr) if __name__ == "__main__": main()