--regions crashes when multiple ligand regions share the same first residue
Describe the bug
PLIP 3.0.1 crashes with a KeyError when one --regions invocation contains
multiple ligand regions whose representative first residue is identical. This
is common for overlapping or nested domain annotations.
The bug is present in:
- release
v3.0.1, commit 2f4911d307490479ac023b22d6faa8f59b577ca8
- current
development, commit 7f4a3626e7c35f262a744f2c8ea77575b35837e7
I reproduced it using a local image built from the official v3.0.1
Dockerfile. The container reports PLIP 3.0.1, Python 3.13, and OpenBabel 3.1.1.
To reproduce
Download the current AlphaFold model and run:
git clone --depth 1 --branch v3.0.1 https://github.com/pharmai/plip.git
docker build -t plip-region-repro:v3.0.1 plip
mkdir -p results
curl -fLO https://alphafold.ebi.ac.uk/files/AF-A0A2S0HST4-F1-model_v6.pdb
docker run --rm \
-v "$PWD:/work" \
-w /work/results \
plip-region-repro:v3.0.1 \
-f /work/AF-A0A2S0HST4-F1-model_v6.pdb \
--regions '[({A: 10-96},), ({A: 10-88},)]' \
-x
Observed result: exit code 1.
Traceback (most recent call last):
...
File "/src/plip/structure/preparation.py", line 1262, in __init__
self.hydroph_atoms = self.hydrophobic_atoms(self.all_atoms)
File "/src/plip/structure/preparation.py", line 561, in hydrophobic_atoms
orig_idx = self.Mapper.mapid(atom.idx, mtype=self.mtype, bsid=self.bsid)
File "/src/plip/structure/preparation.py", line 531, in mapid
return self.proteinmap[self.ligandmaps[bsid][idx]]
KeyError: 636
Controls
Each region works individually:
--regions '[({A: 10-96},)]'
--regions '[({A: 10-88},)]'
Two overlapping ligand regions with different first residues also work:
--regions '[({A: 10-96},), ({A: 11-88},)]'
The reverse ordering also happens to work:
--regions '[({A: 10-88},), ({A: 10-96},)]'
This makes the failure order-dependent: the larger region fails when its atom
map is overwritten by the shorter region's map.
Expected behavior
Every ligand/receptor region tuple should retain its own atom-ID mapping, even
when multiple regions have the same first residue. The command should generate
two binding-site reports and exit successfully.
Cause
In LigandFinder.extract_ligand, ligandmaps is populated before the region
index is appended to lig.title:
lig.title = ':'.join((rname, rchain, str(rnum)))
self.mapper.ligandmaps[lig.title] = mapold
if config.REGIONS:
lig_idx = config.REGIONS.index(regions)
lig.title = ':'.join((rname, rchain, str(rnum), str(lig_idx)))
Ligand.__init__ also reconstructs bsid without the region index:
self.bsid = ':'.join([self.hetid, self.chain, str(self.position)])
Consequently, both regions above use the key LYS:A:10. The second extraction
overwrites the first mapping. When PLIP later processes the larger ligand, atom
636 is not present in the shorter region's map, causing the KeyError.
Candidate fix
Store and retrieve region-mode mappings using the already-generated unique
region title:
diff --git a/plip/structure/preparation.py b/plip/structure/preparation.py
@@
lig.title = ':'.join((rname, rchain, str(rnum)))
- self.mapper.ligandmaps[lig.title] = mapold
if config.REGIONS:
lig_idx = config.REGIONS.index(regions)
lig.title = ':'.join((rname, rchain, str(rnum), str(lig_idx)))
+ self.mapper.ligandmaps[lig.title] = mapold
@@
- self.bsid = ':'.join([self.hetid, self.chain, str(self.position)])
+ self.bsid = (ligand.mol.title if ligand.regions is not None
+ else ':'.join([self.hetid, self.chain, str(self.position)]))
With this change, both the minimal reproducer and the original three-pair
command complete successfully:
[({A: 10-96}, {A: 10-88}),
({A: 10-96}, {A: 110-207}),
({A: 10-88}, {A: 110-207})]
This proposed patch has only been exercised against this reproducer and should
be accompanied by a regression test covering two regions with the same first
residue.
Additional context
Nine independent AlphaFold/domain cases reproduced the same KeyError; all
nine contained at least two annotated regions beginning at the same residue.
No equivalent open issue was found in the current issue list.
--regionscrashes when multiple ligand regions share the same first residueDescribe the bug
PLIP 3.0.1 crashes with a
KeyErrorwhen one--regionsinvocation containsmultiple ligand regions whose representative first residue is identical. This
is common for overlapping or nested domain annotations.
The bug is present in:
v3.0.1, commit2f4911d307490479ac023b22d6faa8f59b577ca8development, commit7f4a3626e7c35f262a744f2c8ea77575b35837e7I reproduced it using a local image built from the official
v3.0.1Dockerfile. The container reports PLIP 3.0.1, Python 3.13, and OpenBabel 3.1.1.
To reproduce
Download the current AlphaFold model and run:
Observed result: exit code 1.
Controls
Each region works individually:
Two overlapping ligand regions with different first residues also work:
--regions '[({A: 10-96},), ({A: 11-88},)]'The reverse ordering also happens to work:
--regions '[({A: 10-88},), ({A: 10-96},)]'This makes the failure order-dependent: the larger region fails when its atom
map is overwritten by the shorter region's map.
Expected behavior
Every ligand/receptor region tuple should retain its own atom-ID mapping, even
when multiple regions have the same first residue. The command should generate
two binding-site reports and exit successfully.
Cause
In
LigandFinder.extract_ligand,ligandmapsis populated before the regionindex is appended to
lig.title:Ligand.__init__also reconstructsbsidwithout the region index:Consequently, both regions above use the key
LYS:A:10. The second extractionoverwrites the first mapping. When PLIP later processes the larger ligand, atom
636 is not present in the shorter region's map, causing the
KeyError.Candidate fix
Store and retrieve region-mode mappings using the already-generated unique
region title:
With this change, both the minimal reproducer and the original three-pair
command complete successfully:
This proposed patch has only been exercised against this reproducer and should
be accompanied by a regression test covering two regions with the same first
residue.
Additional context
Nine independent AlphaFold/domain cases reproduced the same
KeyError; allnine contained at least two annotated regions beginning at the same residue.
No equivalent open issue was found in the current issue list.