Source code for mir.alleles

"""Scalar V/D/J/C allele-notation helpers used by the germline distance lookup.

For frame-level allele operations use ``vdjtools.io.schema.strip_allele`` (a polars
expression). These string helpers drive the per-clonotype resolution cascade
(exact allele → ``*01`` → bare gene → fallback) when gathering baked germline
distances.
"""

from __future__ import annotations

import re

_GENE_BASE_RE = re.compile(r"^\s*([^*\s]+)")


[docs] def strip_allele(gene_name: str | None) -> str: """Return the gene base without allele suffix (``TRBV6-5*02`` → ``TRBV6-5``).""" s = str(gene_name or "").strip() if not s: return "" m = _GENE_BASE_RE.match(s) return m.group(1) if m else ""
[docs] def allele_with_default(gene_name: str | None, default_allele: str = "01") -> str: """Append ``*01`` when no allele is given; preserve an explicit allele. ``TRBV6-5`` → ``TRBV6-5*01``; ``TRBV6-5*02`` → ``TRBV6-5*02``. """ s = str(gene_name or "").strip() if not s: return "" if "*" in s: base, allele = s.split("*", 1) base = strip_allele(base) allele = allele.strip() if not base: return "" return f"{base}*{allele or default_allele}" base = strip_allele(s) return f"{base}*{default_allele}" if base else ""
[docs] def allele_to_major(gene_name: str | None) -> str: """Normalize to major-allele form ``*01`` (``TRBV6-5*02`` → ``TRBV6-5*01``).""" base = strip_allele(gene_name) return f"{base}*01" if base else ""
if __name__ == "__main__": assert strip_allele("TRBV6-5*02") == "TRBV6-5" assert allele_with_default("TRBV6-5") == "TRBV6-5*01" assert allele_with_default("TRBV6-5*02") == "TRBV6-5*02" assert allele_to_major("TRBV6-5*02") == "TRBV6-5*01" assert strip_allele("") == "" and allele_with_default(None) == "" print("mir.alleles self-check OK")