Skip to content

Commit 7910635

Browse files
committed
Add method to check a BinaryCIF file
1 parent 4e7e730 commit 7910635

File tree

3 files changed

+84
-1
lines changed

3 files changed

+84
-1
lines changed

doc/modules/frontend.rst

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,8 @@ The :mod:`saliweb.frontend` Python module
4141

4242
.. autofunction:: check_mmcif
4343

44+
.. autofunction:: check_bcif
45+
4446
.. autofunction:: check_pdb
4547

4648
.. autofunction:: pdb_code_exists

python/saliweb/frontend/__init__.py

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -516,7 +516,7 @@ class _AtomSiteHandler:
516516
def __init__(self):
517517
self.num_rows = 0
518518

519-
def __call__(self):
519+
def __call__(self, cartn_x, cartn_y, cartn_z):
520520
self.num_rows += 1
521521

522522

@@ -547,6 +547,33 @@ def check_mmcif(filename, show_filename=None):
547547
"%s contains no _atom_site entries!" % cif_file)
548548

549549

550+
def check_bcif(filename, show_filename=None):
551+
"""Check that a BinaryCIF file really looks like an (atomic) BinaryCIF
552+
file. If it does not, raise an :exc:`InputValidationError` exception.
553+
554+
:param str filename: The BinaryCIF file to check.
555+
:param str show_filename: If provided, include this filename in any
556+
error message to identify the BinaryCIF file (useful for services
557+
that allow upload of multiple BinaryCIF files).
558+
"""
559+
if show_filename:
560+
bcif_file = "BinaryCIF file %s" % show_filename
561+
else:
562+
bcif_file = "BinaryCIF file"
563+
ash = _AtomSiteHandler()
564+
with open(filename, 'rb') as fh:
565+
c = ihm.format_bcif.BinaryCifReader(
566+
fh, category_handler={'_atom_site': ash})
567+
try:
568+
c.read_file() # read first block
569+
except Exception as err:
570+
raise InputValidationError(
571+
"Invalid %s uploaded: %s" % (bcif_file, str(err)))
572+
if ash.num_rows == 0:
573+
raise InputValidationError(
574+
"%s contains no _atom_site entries!" % bcif_file)
575+
576+
550577
def check_pdb_or_mmcif(filename, show_filename=None):
551578
"""Check that a PDB or mmCIF file really looks like an (atomic) PDB
552579
or mmCIF file.

test/pyfrontend/test_frontend.py

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@
66
import os
77
import gzip
88
import tempfile
9+
import struct
10+
import ihm.format_bcif
911
import flask
1012

1113

@@ -27,6 +29,32 @@ def __init__(self):
2729
del flask.request
2830

2931

32+
def _add_msgpack(d, fh):
33+
"""Add `d` to filelike object `fh` in msgpack format"""
34+
if isinstance(d, dict):
35+
fh.write(struct.pack('>Bi', 0xdf, len(d)))
36+
for key, val in d.items():
37+
_add_msgpack(key, fh)
38+
_add_msgpack(val, fh)
39+
elif isinstance(d, list):
40+
fh.write(struct.pack('>Bi', 0xdd, len(d)))
41+
for val in d:
42+
_add_msgpack(val, fh)
43+
elif isinstance(d, str):
44+
b = d.encode('utf8')
45+
fh.write(struct.pack('>Bi', 0xdb, len(b)))
46+
fh.write(b)
47+
elif isinstance(d, bytes):
48+
fh.write(struct.pack('>Bi', 0xc6, len(d)))
49+
fh.write(d)
50+
elif isinstance(d, int):
51+
fh.write(struct.pack('>Bi', 0xce, d))
52+
elif d is None:
53+
fh.write(b'\xc0')
54+
else:
55+
raise TypeError("Cannot handle %s" % type(d))
56+
57+
3058
def make_test_pdb(tmpdir):
3159
os.mkdir(os.path.join(tmpdir, 'xy'))
3260
with gzip.open(os.path.join(tmpdir, 'xy', 'pdb1xyz.ent.gz'), 'wt') as fh:
@@ -265,6 +293,32 @@ def test_check_mmcif(self):
265293
self.assertRaises(saliweb.frontend.InputValidationError,
266294
saliweb.frontend.check_pdb_or_mmcif, bad_cif)
267295

296+
def test_check_bcif(self):
297+
"""Test check_bcif"""
298+
c = {'name': 'Cartn_x',
299+
'mask': None,
300+
'data': {'data': struct.pack('<2d', 1.0, 2.0),
301+
'encoding':
302+
[{'kind': 'ByteArray',
303+
'type': ihm.format_bcif._Float64}]}}
304+
d = {'dataBlocks': [{'categories': [{'name': '_atom_site',
305+
'columns': [c]}]}]}
306+
307+
with tempfile.TemporaryDirectory() as tmpdir:
308+
good_bcif = os.path.join(tmpdir, 'good.bcif')
309+
with open(good_bcif, 'wb') as fh:
310+
_add_msgpack(d, fh)
311+
bad_bcif = os.path.join(tmpdir, 'bad.bcif')
312+
with open(bad_bcif, 'w') as fh:
313+
fh.write('garbage')
314+
saliweb.frontend.check_bcif(good_bcif)
315+
saliweb.frontend.check_bcif(good_bcif, show_filename='good.bcif')
316+
self.assertRaises(saliweb.frontend.InputValidationError,
317+
saliweb.frontend.check_bcif, bad_bcif)
318+
self.assertRaises(saliweb.frontend.InputValidationError,
319+
saliweb.frontend.check_bcif, bad_bcif,
320+
show_filename='bad.bcif')
321+
268322
def test_check_modeller_key(self):
269323
"""Test check_modeller_key function"""
270324
class MockApp(object):

0 commit comments

Comments
 (0)