Sovereign, offline pyrimethamine-resistance caller for P. falciparum dhfr. Validated on real 3D7 and 20 East African field isolates.
# pfdhfr-caller
Call the classic pyrimethamine-resistance mutations in *Plasmodium falciparum*
dihydrofolate reductase (dhfr) from an in-frame coding sequence.
Given a FASTA of a dhfr coding sequence (CDS), the tool reads codons 51, 59, 108
and 164, translates each, compares it to the wild-type (3D7) residue, and prints
the per-codon call plus a single combined resistance category.
It is deliberately small. For an explicit statement of what it does and does not
cover, see `docs/SCOPE.md`.
## What it checks
| Codon | Wild-type (3D7) | Canonical resistance mutation |
|------:|:---------------:|:------------------------------|
| 51 | N (Asn) | N51I |
| 59 | C (Cys) | C59R |
| 108 | S (Ser) | S108N |
| 164 | I (Ile) | I164L |
S108N is treated as the pivotal mutation; N51I, C59R and I164L stack on top of it
to raise the level. Any residue that differs from the wild-type counts as a
mutation and is labelled with the amino acid actually observed — not only the
canonical resistance allele.
## Combined categories it can emit
- `sensitive (wild-type at all four codons)`
- `pyrimethamine resistance` — S108 mutated, fewer than three codons mutated
- `high-level pyrimethamine resistance` — S108 mutated and at least three of the four codons mutated
- `atypical genotype (resistance codons mutated but S108 wild-type)`
- `indeterminate (one or more codons could not be read)`
The category is a coarse, rule-based summary of the four-codon genotype, not a
clinical recommendation. See `docs/SCOPE.md`.
## Run it
From the repository root:
```
python3 src/call_pfdhfr.py
```
Run the tests (plain asserts, no framework required):
```
python3 tests/test_caller.py
```
## Example: real 3D7 reference
```
$ python3 src/call_pfdhfr.py data/3d7_dhfrts_real.fasta
>lcl|XM_001351443.1_cds_XP_001351479.1_1 (1827 bp)
codon 51: AAT -> N N51
codon …