Skip to content

Commit

Permalink
Add support for branch descriptors
Browse files Browse the repository at this point in the history
  • Loading branch information
benmwebb committed Sep 23, 2023
1 parent 7533fc5 commit 9c0281b
Show file tree
Hide file tree
Showing 7 changed files with 111 additions and 2 deletions.
3 changes: 3 additions & 0 deletions docs/main.rst
Original file line number Diff line number Diff line change
Expand Up @@ -110,3 +110,6 @@ The :mod:`ihm` Python module

.. autoclass:: Collection
:members:

.. autoclass:: BranchDescriptor
:members:
24 changes: 24 additions & 0 deletions ihm/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -1299,6 +1299,11 @@ def get_chem_comp(s):
self.references = []
self.references.extend(references)

#: String descriptors of branched chemical structure.
#: These generally only make sense for oligosaccharide entities,
#: and should be a list of :class:`BranchDescriptor` objects.
self.branch_descriptors = []

def __str__(self):
return "<ihm.Entity(%s)>" % self.description

Expand Down Expand Up @@ -1584,3 +1589,22 @@ class Collection(object):
"""
def __init__(self, id, name=None, details=None):
self.id, self.name, self.details = id, name, details


class BranchDescriptor(object):
"""String descriptor of branched chemical structure.
These generally only make sense for oligosaccharide entities.
See :attr:`Entity.branch_descriptors`.
:param str text: The value of this descriptor.
:param str type: The type of the descriptor; one of
"Glycam Condensed Core Sequence", "Glycam Condensed Sequence",
"LINUCS", or "WURCS".
:param str program: The name of the program or library used to compute
the descriptor.
:param str program_version: The version of the program or library
used to compute the descriptor.
"""
def __init__(self, text, type, program=None, program_version=None):
self.text, self.type = text, type
self.program, self.program_version = program, program_version
15 changes: 14 additions & 1 deletion ihm/dumper.py
Original file line number Diff line number Diff line change
Expand Up @@ -751,6 +751,19 @@ def dump(self, system, writer):
auth_mon_id=comp.id)


class _BranchDescriptorDumper(Dumper):
def dump(self, system, writer):
ordinal = itertools.count(1)
with writer.loop("_pdbx_entity_branch_descriptor",
["ordinal", "entity_id", "descriptor", "type",
"program", "program_version"]) as lp:
for entity in system.entities:
for d in entity.branch_descriptors:
lp.write(ordinal=next(ordinal), entity_id=entity._id,
descriptor=d.text, type=d.type, program=d.program,
program_version=d.program_version)


class _AsymIDProvider(object):
"""Provide unique asym IDs"""
def __init__(self, seen_ids):
Expand Down Expand Up @@ -3293,7 +3306,7 @@ class IHMVariant(Variant):
_EntityPolyDumper, _EntityNonPolyDumper, _EntityPolySeqDumper,
_EntityPolySegmentDumper, _EntityBranchListDumper, _EntityBranchDumper,
_StructAsymDumper, _PolySeqSchemeDumper,
_NonPolySchemeDumper, _BranchSchemeDumper,
_NonPolySchemeDumper, _BranchSchemeDumper, _BranchDescriptorDumper,
_AssemblyDumper, _ExternalReferenceDumper,
_DatasetDumper, _ModelRepresentationDumper, _StartingModelDumper,
_ProtocolDumper, _PostProcessDumper, _PseudoSiteDumper,
Expand Down
12 changes: 11 additions & 1 deletion ihm/reader.py
Original file line number Diff line number Diff line change
Expand Up @@ -2544,6 +2544,16 @@ def __call__(self, entity_id, comp_id, num):
s.sequence[seq_id - 1] = self.sysr.chem_comps.get_by_id(comp_id)


class _BranchDescriptorHandler(Handler):
category = '_pdbx_entity_branch_descriptor'

def __call__(self, entity_id, descriptor, type, program, program_version):
e = self.sysr.entities.get_by_id(entity_id)
d = ihm.BranchDescriptor(text=descriptor, type=type, program=program,
program_version=program_version)
e.branch_descriptors.append(d)


class _CrossLinkListHandler(Handler):
category = '_ihm_cross_link_list'
ignored_keywords = ['entity_description_1', 'entity_description_2',
Expand Down Expand Up @@ -3363,7 +3373,7 @@ class IHMVariant(Variant):
_SphereHandler, _TorusHandler, _HalfTorusHandler, _AxisHandler,
_PlaneHandler, _GeometricRestraintHandler, _PolySeqSchemeHandler,
_NonPolySchemeHandler, _BranchSchemeHandler, _EntityBranchListHandler,
_CrossLinkListHandler,
_BranchDescriptorHandler, _CrossLinkListHandler,
_CrossLinkRestraintHandler, _CrossLinkPseudoSiteHandler,
_CrossLinkResultHandler, _StartingModelSeqDifHandler,
_OrderedEnsembleHandler]
Expand Down
25 changes: 25 additions & 0 deletions test/test_dumper.py
Original file line number Diff line number Diff line change
Expand Up @@ -4521,6 +4521,31 @@ def test_branch_scheme_dumper(self):
#
""")

def test_branch_descriptor_dumper(self):
"""Test BranchDescriptorDumper"""
system = ihm.System()
e1 = ihm.Entity([ihm.SaccharideChemComp('NAG')])
bd1 = ihm.BranchDescriptor('foo', type='typ1', program='prog',
program_version='1.0')
bd2 = ihm.BranchDescriptor('bar', type='typ2')
e1.branch_descriptors.extend((bd1, bd2))
system.entities.append(e1)
ihm.dumper._EntityDumper().finalize(system)
dumper = ihm.dumper._BranchDescriptorDumper()
out = _get_dumper_output(dumper, system)
self.assertEqual(out, """#
loop_
_pdbx_entity_branch_descriptor.ordinal
_pdbx_entity_branch_descriptor.entity_id
_pdbx_entity_branch_descriptor.descriptor
_pdbx_entity_branch_descriptor.type
_pdbx_entity_branch_descriptor.program
_pdbx_entity_branch_descriptor.program_version
1 1 foo typ1 prog 1.0
2 1 bar typ2 . .
#
""")


if __name__ == '__main__':
unittest.main()
9 changes: 9 additions & 0 deletions test/test_main.py
Original file line number Diff line number Diff line change
Expand Up @@ -1083,6 +1083,15 @@ def test_unknown(self):
# Should act like False
self.assertFalse(u)

def test_branch_descriptor(self):
"""Test the BranchDescriptor class"""
bd = ihm.BranchDescriptor(text='foo', type='bar', program='baz',
program_version="1.0")
self.assertEqual(bd.text, 'foo')
self.assertEqual(bd.type, 'bar')
self.assertEqual(bd.program, 'baz')
self.assertEqual(bd.program_version, '1.0')


if __name__ == '__main__':
unittest.main()
25 changes: 25 additions & 0 deletions test/test_reader.py
Original file line number Diff line number Diff line change
Expand Up @@ -4400,6 +4400,31 @@ def test_entity_branch_list_handler(self):
c1, c2, c3, c4 = e1.sequence
self.assertEqual([c.id for c in e1.sequence], ['BGC'] * 4)

def test_entity_branch_descriptor_handler(self):
"""Test EntityBranchDescriptorHandler"""
fh = StringIO("""
loop_
_pdbx_entity_branch_descriptor.ordinal
_pdbx_entity_branch_descriptor.entity_id
_pdbx_entity_branch_descriptor.descriptor
_pdbx_entity_branch_descriptor.type
_pdbx_entity_branch_descriptor.program
_pdbx_entity_branch_descriptor.program_version
1 1 foo typ1 prog 1.0
2 1 bar typ2 . .
""")
s, = ihm.reader.read(fh)
e1, = s.entities
bd1, bd2 = e1.branch_descriptors
self.assertEqual(bd1.text, 'foo')
self.assertEqual(bd1.type, 'typ1')
self.assertEqual(bd1.program, 'prog')
self.assertEqual(bd1.program_version, '1.0')
self.assertEqual(bd2.text, 'bar')
self.assertEqual(bd2.type, 'typ2')
self.assertIsNone(bd2.program)
self.assertIsNone(bd2.program_version)


if __name__ == '__main__':
unittest.main()

0 comments on commit 9c0281b

Please sign in to comment.