Skip to content

Commit

Permalink
Allow branched entities with same "sequence"
Browse files Browse the repository at this point in the history
It is quite possible that a system may contain
multiple branched entities with the same "sequence"
but different connectivity, so relax our "entities
cannot have the same sequence" check for branched
entities. To be strictly correct, we should check
for branched entities that have both the same
sequence *and* the same connectivity, but that is not
handled here. Closes #126.
  • Loading branch information
benmwebb committed Dec 6, 2023
1 parent 205024b commit 833f37a
Show file tree
Hide file tree
Showing 3 changed files with 42 additions and 5 deletions.
15 changes: 12 additions & 3 deletions ihm/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -1330,12 +1330,21 @@ def residue(self, seq_id):
"""Get a :class:`Residue` at the given sequence position"""
return Residue(entity=self, seq_id=seq_id)

# Entities are considered identical if they have the same sequence
# Entities are considered identical if they have the same sequence,
# unless they are branched
def __eq__(self, other):
return isinstance(other, Entity) and self.sequence == other.sequence
if not isinstance(other, Entity):
return False
if self.is_branched() or other.is_branched():
return self is other
else:
return self.sequence == other.sequence

def __hash__(self):
return hash(self.sequence)
if self.is_branched():
return hash(id(self))
else:
return hash(self.sequence)

def __call__(self, seq_id_begin, seq_id_end):
return EntityRange(self, seq_id_begin, seq_id_end)
Expand Down
26 changes: 25 additions & 1 deletion test/test_dumper.py
Original file line number Diff line number Diff line change
Expand Up @@ -414,13 +414,37 @@ def test_entity_dumper(self):
""")

def test_entity_duplicates(self):
"""Test EntityDumper with duplicate entities"""
"""Test EntityDumper with duplicate non-branched entities"""
system = ihm.System()
system.entities.append(ihm.Entity('AHC'))
system.entities.append(ihm.Entity('AHC'))
dumper = ihm.dumper._EntityDumper()
self.assertRaises(ValueError, dumper.finalize, system)

def test_entity_duplicate_branched(self):
"""Test EntityDumper with duplicate branched entities"""
system = ihm.System()
sacc = ihm.SaccharideChemComp('NAG')
system.entities.append(ihm.Entity([sacc]))
system.entities.append(ihm.Entity([sacc]))
dumper = ihm.dumper._EntityDumper()
dumper.finalize(system) # Assign IDs
out = _get_dumper_output(dumper, system)
# Duplicate "sequences" are OK for branched entities
self.assertEqual(out, """#
loop_
_entity.id
_entity.type
_entity.src_method
_entity.pdbx_description
_entity.formula_weight
_entity.pdbx_number_of_molecules
_entity.details
1 branched man . . 0 .
2 branched man . . 0 .
#
""")

def test_entity_src_nat_dumper(self):
"""Test EntitySrcNatDumper"""
system = ihm.System()
Expand Down
6 changes: 5 additions & 1 deletion test/test_main.py
Original file line number Diff line number Diff line change
Expand Up @@ -214,7 +214,7 @@ def test_chem_descriptor(self):
def test_entity(self):
"""Test Entity class"""
e1 = ihm.Entity('AHCD', description='foo')
# Should compare identical if sequences are the same
# Should compare identical if sequences are the same, if not branched
e2 = ihm.Entity('AHCD', description='bar')
e3 = ihm.Entity('AHCDE', description='foo')
heme = ihm.Entity([ihm.NonPolymerChemComp('HEM')])
Expand All @@ -223,6 +223,10 @@ def test_entity(self):
self.assertNotEqual(e1, e3)
self.assertEqual(e1.seq_id_range, (1, 4))
self.assertEqual(e3.seq_id_range, (1, 5))
sugar2 = ihm.Entity([ihm.SaccharideChemComp('NAG')])
# Branched entities never compare equal unless they are the same object
self.assertEqual(sugar, sugar)
self.assertNotEqual(sugar, sugar2)
# seq_id does not exist for nonpolymers
self.assertEqual(heme.seq_id_range, (None, None))
# We do have an internal seq_id_range for branched entities
Expand Down

0 comments on commit 833f37a

Please sign in to comment.