Skip to content

Commit

Permalink
Allow mmCIF inputs
Browse files Browse the repository at this point in the history
  • Loading branch information
benmwebb committed Aug 26, 2024
1 parent 6116338 commit 0a83ee7
Show file tree
Hide file tree
Showing 5 changed files with 168 additions and 26 deletions.
13 changes: 9 additions & 4 deletions frontend/multifoxs/submit_page.py
Original file line number Diff line number Diff line change
Expand Up @@ -59,17 +59,22 @@ def handle_new_job():
def handle_pdb(pdb_code, pdb_file, job):
"""Handle input PDB code or file. Return file name."""
if pdb_file:
fname = 'input.pdb'
if pdb_file.filename.endswith('.cif'):
fname = 'input.cif'
else:
fname = 'input.pdb'
full_fname = job.get_path(fname)
pdb_file.save(full_fname)
saliweb.frontend.check_pdb(full_fname)
saliweb.frontend.check_pdb_or_mmcif(
full_fname, show_filename=os.path.basename(pdb_file.filename))
return fname
elif pdb_code:
fname = saliweb.frontend.get_pdb_chains(pdb_code, job.directory)
fname = saliweb.frontend.get_pdb_chains(
pdb_code, job.directory, formats=["PDB", "MMCIF", "IHM"])
return os.path.basename(fname)
else:
raise InputValidationError("Error in protein input: please specify "
"PDB code or upload file")
"PDB code or upload PDB/mmCIF file")


def handle_uploaded_file(fh, job, output_file, description,
Expand Down
2 changes: 1 addition & 1 deletion frontend/multifoxs/templates/download.html
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ <h3><font color='#B22222'>Download</font></h3>

<ol>

<li><p>Conformational sampling. Prepare your input PDB file and flexible residues file as explained in <a href="help.cgi?type=help#protein"> Help </a>:</p>
<li><p>Conformational sampling. Prepare your input PDB or mmCIF file and flexible residues file as explained in <a href="help.cgi?type=help#protein"> Help </a>:</p>

<div class="imp-code notranslate htmlHigh">
<br /> rrt_sample protein_PDB flexible_residues_file -i 1000000 -n 10000 <br />
Expand Down
4 changes: 2 additions & 2 deletions frontend/multifoxs/templates/help.html
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@ <h3><font color='#B22222'>Input Fields</font></h3>

<ul>
<li><a name="protein"></a><b>Input protein:</b> it is possible to
specify the PDB code of the input protein <b>or</b> upload a file in PDB
format. Each code is a four character PDB ID, followed by a colon and
specify the PDB code of the input protein <b>or</b> upload a file in PDB or
mmCIF format. Each code is a four character PDB ID, followed by a colon and
a comma-separated list of chain IDs, e.g. 2pka:A,B. If no chain IDs are given,
all the chains of the PDB file are used.

Expand Down
2 changes: 1 addition & 1 deletion frontend/multifoxs/templates/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@

<table cellpadding="5" cellspacing="0">
<tr>
<td>Type PDB code for protein or upload file in PDB format <a href="{{ url_for("help", _anchor="sampleinput") }}">sample input files</a></td>
<td>Type PDB code for protein or upload file in PDB or mmCIF format <a href="{{ url_for("help", _anchor="sampleinput") }}">sample input files</a></td>
</tr>
</table>
<table border="0" cellpadding="5" cellspacing="0" width="99%">
Expand Down
173 changes: 155 additions & 18 deletions test/frontend/test_submit.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,71 @@
import saliweb.test
import tempfile
import os
import gzip
import re

# Import the multifoxs frontend with mocks
multifoxs = saliweb.test.import_mocked_frontend("multifoxs", __file__,
'../../frontend')


def make_test_pdb(pdbf, compressed=False):
def write(fh):
fh.write(
"REMARK\n"
"ATOM 2 CA ALA C 1 26.711 14.576 5.091\n")

if compressed:
with gzip.open(pdbf, 'wt') as fh:
write(fh)
else:
with open(pdbf, 'w') as fh:
write(fh)


def make_test_mmcif(fname, compressed=False):
def write(fh):
fh.write("""
loop_
_atom_site.group_PDB
_atom_site.type_symbol
_atom_site.label_atom_id
_atom_site.label_alt_id
_atom_site.label_comp_id
_atom_site.label_asym_id
_atom_site.auth_asym_id
_atom_site.label_seq_id
_atom_site.auth_seq_id
_atom_site.pdbx_PDB_ins_code
_atom_site.Cartn_x
_atom_site.Cartn_y
_atom_site.Cartn_z
_atom_site.occupancy
_atom_site.B_iso_or_equiv
_atom_site.label_entity_id
_atom_site.id
_atom_site.pdbx_PDB_model_num
ATOM N N . ALA A C 1 1 ? 27.932 14.488 4.257 1.000 23.91 1 1 1
ATOM N N . ALA B D 1 1 ? 27.932 14.488 4.257 1.000 23.91 1 2 1
""")

if compressed:
with gzip.open(fname, 'wt') as fh:
write(fh)
else:
with open(fname, 'w') as fh:
write(fh)


def make_test_profile(saxsf):
with open(saxsf, 'w') as fh:
fh.write("# sample profile\n"
"garbage\n"
"more garbage, ignored\n"
"0.1 -0.5\n"
"0.00000 9656627.00000000 2027.89172363\n")


class Tests(saliweb.test.TestCase):
"""Check submit page"""

Expand All @@ -27,8 +85,9 @@ def test_submit_page_pdb_no_atoms(self):
'/job', data={'pdbfile': open(pdbfile, 'rb'),
'modelsnumber': "5", "units": "unknown"})
self.assertEqual(rv.status_code, 400)
self.assertIn(b'PDB file contains no ATOM or HETATM records',
rv.data)
self.assertIn(
b'PDB file test.pdb contains no ATOM or HETATM records',
rv.data)

def test_submit_page_bad_profile(self):
"""Test submit page with invalid profile"""
Expand All @@ -38,9 +97,7 @@ def test_submit_page_bad_profile(self):
multifoxs.app.config['DIRECTORIES_INCOMING'] = incoming
c = multifoxs.app.test_client()
pdbfile = os.path.join(tmpdir, 'test.pdb')
with open(pdbfile, 'w') as fh:
fh.write(
"ATOM 2 CA ALA 1 26.711 14.576 5.091\n")
make_test_pdb(pdbfile)
saxsf = os.path.join(tmpdir, 'test.profile')
with open(saxsf, 'w') as fh:
fh.write("garbage\n")
Expand All @@ -52,26 +109,18 @@ def test_submit_page_bad_profile(self):
self.assertEqual(rv.status_code, 400)
self.assertIn(b'Invalid profile uploaded', rv.data)

def test_submit_page(self):
"""Test submit page"""
def test_submit_page_pdb(self):
"""Test submit page, PDB format"""
with tempfile.TemporaryDirectory() as tmpdir:
incoming = os.path.join(tmpdir, 'incoming')
os.mkdir(incoming)
multifoxs.app.config['DIRECTORIES_INCOMING'] = incoming
c = multifoxs.app.test_client()

pdbf = os.path.join(tmpdir, 'test.pdb')
with open(pdbf, 'w') as fh:
fh.write(
"REMARK\n"
"ATOM 2 CA ALA 1 26.711 14.576 5.091\n")
make_test_pdb(pdbf)
saxsf = os.path.join(tmpdir, 'test.profile')
with open(saxsf, 'w') as fh:
fh.write("# sample profile\n"
"garbage\n"
"more garbage, ignored\n"
"0.1 -0.5\n"
"0.00000 9656627.00000000 2027.89172363\n")
make_test_profile(saxsf)
emptyf = os.path.join(tmpdir, 'emptyf')
with open(emptyf, 'w') as fh:
pass
Expand All @@ -98,7 +147,8 @@ def test_submit_page(self):
'hingefile': open(linkf, 'rb'), 'jobname': 'foobar'}
rv = c.post('/job', data=data)
self.assertEqual(rv.status_code, 400)
self.assertIn(b'please specify PDB code or upload file', rv.data)
self.assertIn(b'please specify PDB code or upload PDB/mmCIF file',
rv.data)

# Missing SAXS file
data = {'modelsnumber': '100', 'units': 'unknown',
Expand Down Expand Up @@ -148,6 +198,93 @@ def test_submit_page(self):
re.MULTILINE | re.DOTALL)
self.assertRegex(rv.data, r)

def test_submit_page_mmcif(self):
"""Test submit page, mmCIF format"""
with tempfile.TemporaryDirectory() as tmpdir:
incoming = os.path.join(tmpdir, 'incoming')
os.mkdir(incoming)
multifoxs.app.config['DIRECTORIES_INCOMING'] = incoming
c = multifoxs.app.test_client()

pdbf = os.path.join(tmpdir, 'test.cif')
make_test_mmcif(pdbf)
saxsf = os.path.join(tmpdir, 'test.profile')
make_test_profile(saxsf)
linkf = os.path.join(tmpdir, 'test.linkers')
with open(linkf, 'w') as fh:
fh.write("189 A\n")

data = {'modelsnumber': '100', 'units': 'unknown',
'pdbfile': open(pdbf, 'rb'), 'saxsfile': open(saxsf, 'rb'),
'hingefile': open(linkf, 'rb'), 'jobname': 'foobar'}
rv = c.post('/job', data=data)
self.assertEqual(rv.status_code, 200)
r = re.compile(b'Your job <b>foobar</b> has been submitted.*'
b'Results will be found at',
re.MULTILINE | re.DOTALL)
self.assertRegex(rv.data, r)

def test_submit_pdb_code_pdb(self):
"""Test submit with a PDB code (PDB format)"""
with tempfile.TemporaryDirectory() as tmpdir:
incoming = os.path.join(tmpdir, 'incoming')
os.mkdir(incoming)
pdb_root = os.path.join(tmpdir, 'pdb')
os.mkdir(pdb_root)
multifoxs.app.config['DIRECTORIES_INCOMING'] = incoming
multifoxs.app.config['PDB_ROOT'] = pdb_root
c = multifoxs.app.test_client()

os.mkdir(os.path.join(pdb_root, 'xy'))
pdbf = os.path.join(pdb_root, 'xy', 'pdb1xyz.ent.gz')
make_test_pdb(pdbf, compressed=True)
saxsf = os.path.join(tmpdir, 'test.profile')
make_test_profile(saxsf)
linkf = os.path.join(tmpdir, 'test.linkers')
with open(linkf, 'w') as fh:
fh.write("189 A\n")

data = {'modelsnumber': '100', 'units': 'unknown',
'pdbcode': '1xyz:C', 'saxsfile': open(saxsf, 'rb'),
'hingefile': open(linkf, 'rb'), 'jobname': 'foobar'}
rv = c.post('/job', data=data)
self.assertEqual(rv.status_code, 200)
r = re.compile(b'Your job <b>foobar</b> has been submitted.*'
b'Results will be found at',
re.MULTILINE | re.DOTALL)
self.assertRegex(rv.data, r)

def test_submit_pdb_code_mmcif(self):
"""Test submit with a PDB code (mmCIF format)"""
with tempfile.TemporaryDirectory() as tmpdir:
incoming = os.path.join(tmpdir, 'incoming')
os.mkdir(incoming)
pdb_root = os.path.join(tmpdir, 'pdb')
os.mkdir(pdb_root)
multifoxs.app.config['DIRECTORIES_INCOMING'] = incoming
multifoxs.app.config['PDB_ROOT'] = pdb_root
multifoxs.app.config['MMCIF_ROOT'] = pdb_root
c = multifoxs.app.test_client()

os.mkdir(os.path.join(pdb_root, 'xy'))
pdbf = os.path.join(pdb_root, 'xy', '1xyz.cif.gz')
make_test_mmcif(pdbf, compressed=True)
saxsf = os.path.join(tmpdir, 'test.profile')
make_test_profile(saxsf)
linkf = os.path.join(tmpdir, 'test.linkers')
with open(linkf, 'w') as fh:
fh.write("189 A\n")

data = {'modelsnumber': '100', 'units': 'unknown',
'pdbcode': '1xyz:C', 'saxsfile': open(saxsf, 'rb'),
'hingefile': open(linkf, 'rb'), 'jobname': 'foobar'}
rv = c.post('/job', data=data)
self.assertEqual(rv.status_code, 200)
r = re.compile(b'Your job <b>foobar</b> has been submitted.*'
b'Results will be found at',
re.MULTILINE | re.DOTALL)
self.assertRegex(rv.data, r)


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

0 comments on commit 0a83ee7

Please sign in to comment.