PGx: ClinPGx variant-based genes (PGX-008) and --guideline dpwg (PGX-025)

- fetch_sources.sh downloads ClinPGx clinicalVariants (CC BY-SA 4.0); pgx db build adds genotype-only
  variant-based genes (levels 1A-2B, level 3 for the parity list), rsIDs resolved from the manifest's probes:
  70 genes in the DB.
- pgx phenotype --guideline dpwg: CPIC mappings for CPIC genes (as ClinPGx curates DPWG), no phenotype for
  DPWG-only genes (flags dpwg_via_cpic_mapping / dpwg_mapping_not_available). K-029 updated.
This commit is contained in:
kemal committed 2026-09-29 17:01:36 +01:00
1 parent dfba22496a
commit e1cfb3dfd0
8 files changed
+161 -10

No files matched your search

+29
View File
@@ -258,3 +258,32 @@ def pharmvar_core_alleles(gene: str, vcfs: dict[str, str]) -> dict[str, list[tup
recs.append((f[0], int(f[1]), f[3].upper(), alt.upper(), rsid))
out[f"*{m.group(1)}"] = recs
return out
CLINPGX_LEVELS = ("1A", "1B", "2A", "2B")
# PGX-008 parity list of variant-based genes: level-3 annotations are kept for these too
PARITY_VARIANT_GENES = {"DPYD", "RYR1", "OPRM1", "CFTR", "DRD2", "COMT", "OPRD1", "CACNA1C", "HTR2A", "OPRK1",
"MT-RNR1", "TNF", "BDNF", "IL6", "HTR2C", "GRIN2B", "MTHFR", "ITGB3", "FKBP5", "ADH1B",
"ANKK1", "HMGCR", "ATM", "KIF6", "F2", "CACNA1S", "LPA", "F13A1", "GRIK1", "GRIK4", "YEATS4",
"ABCG2", "F5", "ALDH2", "ANK3", "VKORC1"} # fmt: skip
def clinpgx_variant_genes(tsv: str, exclude: set[str], levels: tuple[str, ...] = CLINPGX_LEVELS) -> dict[str, set[str]]:
"""ClinPGx ``clinicalVariants.tsv`` → gene → rsIDs with a clinical annotation at the given evidence levels, for
single-gene rows of genes that no allele-definition source covers (level 3 as well for the PGX-008 parity genes)
[DB: ClinPGx clinical annotations, CC BY-SA 4.0].
Positions and alleles are resolved later from the manifest's probes (genotype-only variant-based genes)."""
out: dict[str, set[str]] = {}
lines = tsv.splitlines()
head = lines[0].split("\t")
iv, ig, il = head.index("variant"), head.index("gene"), head.index("level of evidence")
for ln in lines[1:]:
f = ln.split("\t")
if len(f) <= max(iv, ig, il):
continue
gene, var, lev = f[ig].strip(), f[iv].strip(), f[il].strip()
ok_level = lev in levels or (lev == "3" and gene in PARITY_VARIANT_GENES)
if "," in gene or not gene or gene in exclude or not ok_level or not re.fullmatch(r"rs\d+", var):
continue
out.setdefault(gene, set()).add(var)
return out