Skip to content

Support un-normalizable exotic alleles (#220) - #221

Merged
iskandr merged 2 commits into
masterfrom
support-unnormalizable-alleles
Jul 9, 2026
Merged

Support un-normalizable exotic alleles (#220)#221
iskandr merged 2 commits into
masterfrom
support-unnormalizable-alleles

Conversation

@iskandr

@iskandr iskandr commented Jul 9, 2026

Copy link
Copy Markdown
Contributor

Closes #220.

Problem

netMHCpan -listMHC reports alleles that mhcgnomes can't parse, so they couldn't be requested even though netMHCpan supports them:

  • exotic non-human alleles — H-2-Qa1, BoLA-amani.1, …
  • HLA low/null-expression variants — HLA-A30:14L

Requesting one raised AlleleParseError during predictor construction. This is the tail left after #219 (which made ~2,456 non-human alleles usable by round-tripping netMHCpan's own spelling — those all normalize, just to a spelling netMHCpan rejects). The names here don't normalize at all, so they have no canonical identity to key on.

Fix

Carry the predictor's own -listMHC spelling as identity for these cases.

  • normalize_allele_name_or_raw() (new, in allele_normalization.py): normalize via mhcgnomes when possible; otherwise fall back to a canonical raw form — strip surrounding whitespace and the * gene/allele separator. netMHCpan echoes a requested HLA-A30:14L back as HLA-A*30:14L, so stripping * collapses both spellings to one identity.
  • BasePredictor.__init__ gains keep_unparseable_alleles (default False). Command-line predictors pass True because they validate against the tool's raw supported list; IEDB / in-process predictors keep raising as before.
  • Output parser (parsing.py) uses the raw fallback instead of raising on an un-normalizable echoed allele, so the requested and echoed forms match in _check_results.

Coverage of the 21 affected names

14 now round-trip end-to-end against netMHCpan 4.2 — 11 BoLA, H-2-Qa1, H-2-Qa2, and HLA-A30:14L (both HLA-A30:14L and HLA-A*30:14L).

7 remain unusableMamu-B12/B17/B20/B22, BoLA-T2C, H2-Qa1, H2-Qa2. netMHCpan lists these but rejects them on -a itself ("cannot be found in allelenames list"), so they fail at predict time with Missing predictions. This is a netMHCpan inconsistency (noted in the issue's caveat) that mhctools can't work around.

Tests

  • tests/test_unparseable_alleles.py — binary-free unit tests for the raw fallback (parse-vs-fallback, whitespace/* stripping, request/echo identity) and the keep_unparseable gate (default raises; kept verbatim when enabled; star-variants dedupe). Added to the public CI subset so it runs on all Python versions.
  • test_netmhc_pan_exotic_unnormalizable_alleles — netMHCpan integration test asserting the round-trip identity for H-2-Qa1, BoLA-amani.1, and both spellings of HLA-A30:14L.

Full suite: 509 passed, 38 skipped, 2 xfailed (with the real netMHCpan 4.2 binary). Bumps version to 3.19.0.

https://claude.ai/code/session_01LZahFhBSCiehXTESCYQ7wG

netMHCpan's -listMHC includes alleles mhcgnomes can't parse: exotic
non-human alleles (H-2-Qa1, BoLA-amani.1) and HLA low/null-expression
variants (HLA-A30:14L). Requesting one raised AlleleParseError during
predictor construction even though netMHCpan supports it. This is the
tail left over after #219 (which handled ~2,456 alleles that normalize
but to a spelling netMHCpan rejects); these names don't normalize at all.

Carry the predictor's own -listMHC spelling as identity for these:

  * add normalize_allele_name_or_raw(): normalize when possible, else fall
    back to a canonical raw form (strip whitespace and the '*' gene/allele
    separator). netMHCpan echoes a requested "HLA-A30:14L" back as
    "HLA-A*30:14L", so stripping '*' makes both spellings one identity.
  * BasePredictor.__init__ gains keep_unparseable_alleles (default False);
    command-line predictors pass True since they validate against the raw
    supported list. IEDB / in-process predictors still raise as before.
  * output parser (parsing.py) uses the raw fallback instead of raising on
    an un-normalizable echoed allele, so requested and echoed forms match
    in _check_results.

14 of the 21 affected names now round-trip end-to-end against netMHCpan
4.2 (11 BoLA, H-2-Qa1/Qa2, HLA-A30:14L in both spellings). The other 7
(Mamu-B12/B17/B20/B22, BoLA-T2C, H2-Qa1, H2-Qa2) are listed by netMHCpan
but rejected on -a by the binary itself, so they fail at predict time
with "Missing predictions" — a documented netMHCpan inconsistency
mhctools can't work around.

Tests: binary-free unit tests for the fallback and keep_unparseable gate
(tests/test_unparseable_alleles.py, added to the public CI subset) plus a
netMHCpan integration test asserting the round-trip identity.

Bump version to 3.19.0.

Claude-Session: https://claude.ai/code/session_01LZahFhBSCiehXTESCYQ7wG
Simplify and harden the changes from the previous commit (no behavior
change):

  * _check_hla_alleles: replace the try/except in the dedup loop with a
    branch on keep_unparseable. This drops a redundant second parse of
    unparseable names (normalize_allele_name_or_raw re-parsed after the
    try already failed) and removes the now-unused AlleleParseError import.
    keep_unparseable=True -> normalize_allele_name_or_raw (parse or raw
    fallback); otherwise normalize_allele_name, which still raises as before.

  * normalize_allele_name_or_raw: document that un-normalizable exotic
    alleles are effectively case-sensitive (parseable names are uppercased
    before normalization, but the raw fallback preserves case to match the
    predictor's -listMHC / output spelling), so they must be requested with
    the tool's own casing.

  * Add a binary-free regression test that runs an exotic allele (H-2-Qa1)
    through the netMHC output parser, which previously raised on names
    mhcgnomes can't parse.

Full suite: 510 passed, 38 skipped, 2 xfailed (netMHCpan 4.2).

Claude-Session: https://claude.ai/code/session_01LZahFhBSCiehXTESCYQ7wG
@iskandr
iskandr merged commit cdd7a19 into master Jul 9, 2026
7 of 8 checks passed
@iskandr
iskandr deleted the support-unnormalizable-alleles branch July 9, 2026 16:28
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Some non-human alleles netMHCpan lists (e.g. H-2-Qa1, BoLA-amani.1) can't be requested

1 participant