pyjess 0.5.2__pp310-pypy310_pp73-win_amd64.whl → 0.7.0__pp310-pypy310_pp73-win_amd64.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of pyjess might be problematic. Click here for more details.
- pyjess/__main__.py +4 -0
- pyjess/_jess.pyi +53 -9
- pyjess/_jess.pypy310-pp73-win_amd64.pyd +0 -0
- pyjess/_jess.pyx +855 -105
- pyjess/cli.py +281 -0
- pyjess/tests/__init__.py +2 -0
- pyjess/tests/data/1AMY.cif +6259 -0
- pyjess/tests/data/1sur.qry +26 -0
- pyjess/tests/data/4.1.2.tpl +23 -0
- pyjess/tests/data/5ayx.EF.pdb +63 -0
- pyjess/tests/test_doctest.py +78 -0
- pyjess/tests/test_hit.py +26 -2
- pyjess/tests/test_jess.py +124 -3
- pyjess/tests/test_molecule.py +146 -0
- pyjess/tests/test_template.py +10 -1
- {pyjess-0.5.2.dist-info → pyjess-0.7.0.dist-info}/METADATA +76 -15
- pyjess-0.7.0.dist-info/RECORD +34 -0
- pyjess-0.7.0.dist-info/entry_points.txt +3 -0
- pyjess-0.5.2.dist-info/RECORD +0 -26
- {pyjess-0.5.2.dist-info → pyjess-0.7.0.dist-info}/WHEEL +0 -0
- {pyjess-0.5.2.dist-info → pyjess-0.7.0.dist-info}/licenses/COPYING +0 -0
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
REMARK TEMPLATE
|
|
2
|
+
REMARK CLUSTER 1_1_1
|
|
3
|
+
REMARK REPRESENTING 1 CATALYTIC SITES
|
|
4
|
+
REMARK ID 1sur_AA204-AA208-A204-A208
|
|
5
|
+
REMARK MCSA_ID 279
|
|
6
|
+
REMARK PDB_ID 1sur
|
|
7
|
+
REMARK UNIPROT_ID P17854
|
|
8
|
+
REMARK EC 1.8.4.8
|
|
9
|
+
REMARK ENZYME PAPS REDUCTASE
|
|
10
|
+
REMARK EXPERIMENTAL_METHOD X-ray diffraction
|
|
11
|
+
REMARK RESOLUTION 2.0
|
|
12
|
+
REMARK ORGANISM_NAME Escherichia coli
|
|
13
|
+
REMARK ORGANISM_ID 562
|
|
14
|
+
ATOM 0 NE1ZTRPAA 204 38.872 1.684 110.358 W 0.00
|
|
15
|
+
ATOM 0 CZ2ZTRPAA 204 41.345 1.476 110.794 W 0.00
|
|
16
|
+
ATOM 0 CH2ZTRPAA 204 42.567 1.626 110.193 W 0.00
|
|
17
|
+
ATOM 3 CE1ZTYRAA 208 40.509 -1.903 99.734 Y 0.00
|
|
18
|
+
ATOM 3 CZ ZTYRAA 208 41.503 -1.926 98.771 Y 0.00
|
|
19
|
+
ATOM 1 OH ZTYRAA 208 41.320 -2.643 97.607 Y 0.00
|
|
20
|
+
ATOM 0 NE1ZTRP A 204 43.868 1.684 54.342 W 0.00
|
|
21
|
+
ATOM 0 CZ2ZTRP A 204 41.395 1.476 53.906 W 0.00
|
|
22
|
+
ATOM 0 CH2ZTRP A 204 40.173 1.626 54.507 W 0.00
|
|
23
|
+
ATOM 3 CE1ZTYR A 208 42.231 -1.903 64.966 Y 0.00
|
|
24
|
+
ATOM 3 CZ ZTYR A 208 41.237 -1.926 65.929 Y 0.00
|
|
25
|
+
ATOM 1 OH ZTYR A 208 41.420 -2.643 67.093 Y 0.00
|
|
26
|
+
END
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
REMARK TEMPLATE
|
|
2
|
+
REMARK CLUSTER 4_1_2
|
|
3
|
+
REMARK REPRESENTING 10 CATALYTIC SITES
|
|
4
|
+
REMARK ID 2om2_A48-A43-A200-A204-A178
|
|
5
|
+
REMARK MCSA_ID 533
|
|
6
|
+
REMARK PDB_ID 2om2
|
|
7
|
+
REMARK UNIPROT_ID P63096
|
|
8
|
+
REMARK EC None
|
|
9
|
+
REMARK ENZYME Guanine nucleotide-binding protein G(i), alpha-1 subunit, Regulator of G-protein signalling 14 GoLoco motif peptide
|
|
10
|
+
REMARK EXPERIMENTAL_METHOD X-ray diffraction
|
|
11
|
+
REMARK RESOLUTION 2.2
|
|
12
|
+
REMARK ORGANISM_NAME Homo sapiens
|
|
13
|
+
REMARK ORGANISM_ID 9606
|
|
14
|
+
ATOM 3 CA ZTHR A 48 33.911 -23.654 9.552 T 0.53
|
|
15
|
+
ATOM 3 CB ZTHR A 48 34.739 -23.239 8.310 T 0.53
|
|
16
|
+
ATOM 1 OG1ZTHR A 48 36.129 -23.451 8.587 T 0.53
|
|
17
|
+
ATOM 3 CD ZGLU A 43 42.537 -29.462 7.690 E 2.08
|
|
18
|
+
ATOM 3 OE1ZGLU A 43 42.721 -29.948 8.832 E 2.08
|
|
19
|
+
ATOM 3 OE2ZGLU A 43 42.492 -28.227 7.487 E 2.08
|
|
20
|
+
ATOM 0 CZ ZARG A 178 43.760 -26.926 10.370 R 2.35
|
|
21
|
+
ATOM 3 NH1ZARG A 178 42.887 -26.457 9.483 R 2.35
|
|
22
|
+
ATOM 3 NH2ZARG A 178 44.119 -28.202 10.324 R 2.35
|
|
23
|
+
END
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
HEADER TRANSFERASE 14-SEP-15 XXXX
|
|
2
|
+
TITLE CRYSTAL STRUCTURE OF HUMAN QUINOLINATE PHOSPHORIBOSYLTRANSFERASE
|
|
3
|
+
KEYWDS QUINOLINATE PHOSPHORIBOSYLTRANSFERASE, NAD BIOSYNTHESIS, NADC,
|
|
4
|
+
KEYWDS 2 TRANSFERASE
|
|
5
|
+
EXPDTA X-RAY DIFFRACTION
|
|
6
|
+
ATOM 8512 CA GLU E 25 11.770 12.101 -30.191 1.00 63.41 C
|
|
7
|
+
ATOM 8513 C GLU E 25 10.568 12.472 -31.076 1.00 64.47 C
|
|
8
|
+
ATOM 8514 O GLU E 25 10.268 13.659 -31.267 1.00 66.51 O
|
|
9
|
+
ATOM 8515 CB GLU E 25 12.924 11.548 -31.040 1.00 54.61 C
|
|
10
|
+
ATOM 8516 CG GLU E 25 13.586 12.566 -31.990 1.00 63.15 C
|
|
11
|
+
ATOM 8517 CD GLU E 25 14.447 11.902 -33.089 1.00 67.48 C
|
|
12
|
+
ATOM 8518 OE1 GLU E 25 14.041 10.820 -33.594 1.00 62.27 O
|
|
13
|
+
ATOM 8519 OE2 GLU E 25 15.524 12.460 -33.441 1.00 60.34 O
|
|
14
|
+
ATOM 9342 N THR E 141 25.198 6.504 -40.031 1.00 49.91 N
|
|
15
|
+
ATOM 9343 CA THR E 141 24.509 7.667 -39.509 1.00 44.30 C
|
|
16
|
+
ATOM 9344 C THR E 141 24.749 7.734 -38.010 1.00 45.10 C
|
|
17
|
+
ATOM 9345 O THR E 141 24.587 6.721 -37.320 1.00 49.53 O
|
|
18
|
+
ATOM 9346 CB THR E 141 23.029 7.628 -39.780 1.00 40.72 C
|
|
19
|
+
ATOM 9347 OG1 THR E 141 22.810 7.411 -41.175 1.00 41.17 O
|
|
20
|
+
ATOM 9348 CG2 THR E 141 22.434 8.970 -39.391 1.00 45.90 C
|
|
21
|
+
ATOM 9371 N ARG E 145 23.925 3.473 -35.427 1.00 47.01 N
|
|
22
|
+
ATOM 9372 CA ARG E 145 24.909 2.456 -35.770 1.00 50.52 C
|
|
23
|
+
ATOM 9373 C ARG E 145 24.310 1.065 -35.674 1.00 48.71 C
|
|
24
|
+
ATOM 9374 O ARG E 145 24.441 0.255 -36.598 1.00 51.91 O
|
|
25
|
+
ATOM 9375 CB ARG E 145 26.130 2.594 -34.858 1.00 58.30 C
|
|
26
|
+
ATOM 9376 CG ARG E 145 27.168 1.485 -34.964 1.00 56.80 C
|
|
27
|
+
ATOM 9377 CD ARG E 145 28.472 1.971 -34.388 1.00 64.04 C
|
|
28
|
+
ATOM 9378 NE ARG E 145 29.055 3.032 -35.219 1.00 79.49 N
|
|
29
|
+
ATOM 9379 CZ ARG E 145 30.083 3.803 -34.855 1.00 77.12 C
|
|
30
|
+
ATOM 9380 NH1 ARG E 145 30.556 4.728 -35.687 1.00 73.39 N
|
|
31
|
+
ATOM 9381 NH2 ARG E 145 30.640 3.659 -33.657 1.00 73.96 N
|
|
32
|
+
TER 10377 GLU E 289
|
|
33
|
+
ATOM 10557 N GLU F 25 28.218 6.773 -28.434 1.00 49.27 N
|
|
34
|
+
ATOM 10558 CA GLU F 25 28.033 5.648 -29.351 1.00 50.31 C
|
|
35
|
+
ATOM 10559 C GLU F 25 29.332 5.286 -30.079 1.00 60.13 C
|
|
36
|
+
ATOM 10560 O GLU F 25 29.595 4.101 -30.330 1.00 65.02 O
|
|
37
|
+
ATOM 10561 CB GLU F 25 26.927 5.992 -30.358 1.00 47.14 C
|
|
38
|
+
ATOM 10562 CG GLU F 25 26.451 4.872 -31.285 1.00 50.18 C
|
|
39
|
+
ATOM 10563 CD GLU F 25 25.906 5.376 -32.657 1.00 59.80 C
|
|
40
|
+
ATOM 10564 OE1 GLU F 25 26.512 6.292 -33.298 1.00 59.65 O
|
|
41
|
+
ATOM 10565 OE2 GLU F 25 24.859 4.843 -33.098 1.00 56.23 O
|
|
42
|
+
ATOM 11388 N THR F 141 15.709 9.909 -40.611 1.00 43.47 N
|
|
43
|
+
ATOM 11389 CA THR F 141 16.342 8.887 -39.789 1.00 44.34 C
|
|
44
|
+
ATOM 11390 C THR F 141 16.089 9.169 -38.311 1.00 43.54 C
|
|
45
|
+
ATOM 11391 O THR F 141 16.316 10.292 -37.851 1.00 43.12 O
|
|
46
|
+
ATOM 11392 CB THR F 141 17.841 8.832 -40.073 1.00 43.56 C
|
|
47
|
+
ATOM 11393 OG1 THR F 141 18.060 8.851 -41.489 1.00 42.17 O
|
|
48
|
+
ATOM 11394 CG2 THR F 141 18.442 7.560 -39.505 1.00 42.11 C
|
|
49
|
+
ATOM 11417 N ARG F 145 16.934 13.489 -36.682 1.00 42.82 N
|
|
50
|
+
ATOM 11418 CA ARG F 145 15.914 14.290 -37.338 1.00 43.06 C
|
|
51
|
+
ATOM 11419 C ARG F 145 16.352 15.741 -37.468 1.00 47.81 C
|
|
52
|
+
ATOM 11420 O ARG F 145 16.166 16.358 -38.527 1.00 49.55 O
|
|
53
|
+
ATOM 11421 CB ARG F 145 14.611 14.145 -36.548 1.00 52.52 C
|
|
54
|
+
ATOM 11422 CG ARG F 145 13.463 15.093 -36.850 1.00 52.54 C
|
|
55
|
+
ATOM 11423 CD ARG F 145 12.613 15.162 -35.593 1.00 56.72 C
|
|
56
|
+
ATOM 11424 NE ARG F 145 11.200 15.447 -35.811 1.00 61.47 N
|
|
57
|
+
ATOM 11425 CZ ARG F 145 10.285 15.372 -34.842 1.00 73.92 C
|
|
58
|
+
ATOM 11426 NH1 ARG F 145 9.005 15.653 -35.090 1.00 71.75 N
|
|
59
|
+
ATOM 11427 NH2 ARG F 145 10.657 15.007 -33.615 1.00 69.36 N
|
|
60
|
+
TER 12486 GLU F 289
|
|
61
|
+
ENDMDL
|
|
62
|
+
MASTER 0 0 0 76 71 0 0 612499 6 0 144
|
|
63
|
+
END
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
# coding: utf-8
|
|
2
|
+
"""Test doctest contained tests in every file of the module.
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
import configparser
|
|
6
|
+
import doctest
|
|
7
|
+
import importlib
|
|
8
|
+
import json
|
|
9
|
+
import gzip
|
|
10
|
+
import os
|
|
11
|
+
import pkgutil
|
|
12
|
+
import re
|
|
13
|
+
import shutil
|
|
14
|
+
import sys
|
|
15
|
+
import types
|
|
16
|
+
import warnings
|
|
17
|
+
from unittest import mock
|
|
18
|
+
|
|
19
|
+
import pyjess
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
def _load_tests_from_module(tests, module, globs, setUp=None, tearDown=None):
|
|
23
|
+
"""Load tests from module, iterating through submodules."""
|
|
24
|
+
for attr in (getattr(module, x) for x in dir(module) if not x.startswith("_")):
|
|
25
|
+
if isinstance(attr, types.ModuleType):
|
|
26
|
+
suite = doctest.DocTestSuite(
|
|
27
|
+
attr,
|
|
28
|
+
globs,
|
|
29
|
+
setUp=setUp,
|
|
30
|
+
tearDown=tearDown,
|
|
31
|
+
optionflags=+doctest.ELLIPSIS,
|
|
32
|
+
)
|
|
33
|
+
tests.addTests(suite)
|
|
34
|
+
return tests
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
def load_tests(loader, tests, ignore):
|
|
38
|
+
"""`load_test` function used by unittest to find the doctests."""
|
|
39
|
+
_current_cwd = os.getcwd()
|
|
40
|
+
|
|
41
|
+
def setUp(self):
|
|
42
|
+
warnings.simplefilter("ignore")
|
|
43
|
+
os.chdir(os.path.realpath(os.path.join(__file__, os.path.pardir, "data")))
|
|
44
|
+
|
|
45
|
+
def tearDown(self):
|
|
46
|
+
os.chdir(_current_cwd)
|
|
47
|
+
warnings.simplefilter(warnings.defaultaction)
|
|
48
|
+
|
|
49
|
+
# doctests are not compatible with `green`, so we may want to bail out
|
|
50
|
+
# early if `green` is running the tests
|
|
51
|
+
if sys.argv[0].endswith("green"):
|
|
52
|
+
return tests
|
|
53
|
+
|
|
54
|
+
# recursively traverse all library submodules and load tests from them
|
|
55
|
+
packages = [None, pyjess]
|
|
56
|
+
for pkg in iter(packages.pop, None):
|
|
57
|
+
for (_, subpkgname, subispkg) in pkgutil.walk_packages(pkg.__path__):
|
|
58
|
+
# do not import __main__ module to avoid side effects!
|
|
59
|
+
if subpkgname == "__main__" or subpkgname.startswith("tests") or subpkgname.startswith("cli"):
|
|
60
|
+
continue
|
|
61
|
+
# import the submodule and add it to the tests
|
|
62
|
+
module = importlib.import_module(".".join([pkg.__name__, subpkgname]))
|
|
63
|
+
globs = dict(pyjess=pyjess, **module.__dict__)
|
|
64
|
+
tests.addTests(
|
|
65
|
+
doctest.DocTestSuite(
|
|
66
|
+
module,
|
|
67
|
+
globs=globs,
|
|
68
|
+
setUp=setUp,
|
|
69
|
+
tearDown=tearDown,
|
|
70
|
+
optionflags=+doctest.ELLIPSIS,
|
|
71
|
+
)
|
|
72
|
+
)
|
|
73
|
+
# if the submodule is a package, we need to process its submodules
|
|
74
|
+
# as well, so we add it to the package queue
|
|
75
|
+
if subispkg and subpkgname != "tests":
|
|
76
|
+
packages.append(module)
|
|
77
|
+
|
|
78
|
+
return tests
|
pyjess/tests/test_hit.py
CHANGED
|
@@ -2,6 +2,7 @@ import math
|
|
|
2
2
|
import unittest
|
|
3
3
|
import sys
|
|
4
4
|
import pickle
|
|
5
|
+
import textwrap
|
|
5
6
|
|
|
6
7
|
from .._jess import Template, Molecule, Jess
|
|
7
8
|
from .utils import files
|
|
@@ -9,12 +10,14 @@ from . import data
|
|
|
9
10
|
|
|
10
11
|
|
|
11
12
|
class TestHit(unittest.TestCase):
|
|
13
|
+
|
|
14
|
+
maxDiff = None
|
|
12
15
|
|
|
13
16
|
@unittest.skipUnless(files, "importlib.resources not available")
|
|
14
17
|
@classmethod
|
|
15
18
|
def setUpClass(cls):
|
|
16
19
|
with files(data).joinpath("template_01.qry").open() as f:
|
|
17
|
-
template = Template.load(f)
|
|
20
|
+
template = Template.load(f, id="T1")
|
|
18
21
|
jess = Jess([template])
|
|
19
22
|
with files(data).joinpath("pdb1lnb.pdb").open() as f:
|
|
20
23
|
molecule = Molecule.load(f)
|
|
@@ -30,4 +33,25 @@ class TestHit(unittest.TestCase):
|
|
|
30
33
|
self.assertEqual(self.hit.template, hit.template)
|
|
31
34
|
self.assertListEqual(self.hit.atoms(transform=True), hit.atoms(transform=True))
|
|
32
35
|
self.assertListEqual(self.hit.atoms(transform=False), hit.atoms(transform=False))
|
|
33
|
-
self.assertEqual(self.hit.molecule(transform=False), hit.molecule(transform=False))
|
|
36
|
+
self.assertEqual(self.hit.molecule(transform=False), hit.molecule(transform=False))
|
|
37
|
+
|
|
38
|
+
def test_dumps(self):
|
|
39
|
+
expected = textwrap.dedent(
|
|
40
|
+
"""
|
|
41
|
+
REMARK 1LNB 0.555 T1 Det= 1.0 log(E)~ -2.04
|
|
42
|
+
ATOM 1112 ND1 HIS E 142 4.157 -2.574 4.091 1.00 10.22
|
|
43
|
+
ATOM 1115 NE2 HIS E 142 3.805 -2.316 1.890 1.00 16.00
|
|
44
|
+
ATOM 1123 OE1 GLU E 143 0.480 -4.544 -0.363 1.00 14.72
|
|
45
|
+
ATOM 1124 OE2 GLU E 143 1.870 -6.097 0.337 1.00 22.48
|
|
46
|
+
ATOM 1145 CG HIS E 146 0.031 0.017 0.019 1.00 12.45
|
|
47
|
+
ATOM 1146 ND1 HIS E 146 0.823 1.160 0.000 1.00 15.79
|
|
48
|
+
ATOM 1147 CD2 HIS E 146 0.878 -1.064 0.006 1.00 20.85
|
|
49
|
+
ATOM 1148 CE1 HIS E 146 2.115 0.777 -0.013 1.00 13.50
|
|
50
|
+
ATOM 1149 NE2 HIS E 146 2.181 -0.553 -0.032 1.00 12.44
|
|
51
|
+
ATOM 1298 OE1 GLU E 166 6.432 -0.605 1.056 1.00 16.03
|
|
52
|
+
ATOM 1299 OE2 GLU E 166 4.839 0.070 -0.343 1.00 19.31
|
|
53
|
+
ENDMDL
|
|
54
|
+
"""
|
|
55
|
+
).strip()
|
|
56
|
+
actual = self.hit.dumps().strip()
|
|
57
|
+
self.assertMultiLineEqual(actual, expected)
|
pyjess/tests/test_jess.py
CHANGED
|
@@ -92,7 +92,6 @@ class TestJess(unittest.TestCase):
|
|
|
92
92
|
self.assertEqual(len(jess[:1]), 1)
|
|
93
93
|
self.assertEqual(len(jess[1:]), 0)
|
|
94
94
|
|
|
95
|
-
|
|
96
95
|
@unittest.skipUnless(files, "importlib.resources not available")
|
|
97
96
|
def test_multiple_query_split(self):
|
|
98
97
|
with files(data).joinpath("template_01.qry").open() as f:
|
|
@@ -132,6 +131,29 @@ class TestJess(unittest.TestCase):
|
|
|
132
131
|
hits = list(jess.query(molecule, 1, 2, 2))
|
|
133
132
|
self.assertIsInstance(hits[0].template, MyTemplate)
|
|
134
133
|
|
|
134
|
+
@unittest.skipUnless(files, "importlib.resources not available")
|
|
135
|
+
def test_query_max_candidates(self):
|
|
136
|
+
with files(data).joinpath("template_01.qry").open() as f:
|
|
137
|
+
template = Template.load(f)
|
|
138
|
+
jess = Jess([template])
|
|
139
|
+
with files(data).joinpath("pdb1lnb.pdb").open() as f:
|
|
140
|
+
molecule = Molecule.load(f)
|
|
141
|
+
|
|
142
|
+
hits = list(jess.query(molecule, 2, 5, 5))
|
|
143
|
+
self.assertEqual(len(hits), 3)
|
|
144
|
+
|
|
145
|
+
hits = list(jess.query(molecule, 2, 5, 5, max_candidates=3))
|
|
146
|
+
self.assertEqual(len(hits), 3)
|
|
147
|
+
|
|
148
|
+
hits = list(jess.query(molecule, 2, 5, 5, max_candidates=2))
|
|
149
|
+
self.assertEqual(len(hits), 2)
|
|
150
|
+
|
|
151
|
+
hits = list(jess.query(molecule, 2, 5, 5, max_candidates=1))
|
|
152
|
+
self.assertEqual(len(hits), 1)
|
|
153
|
+
|
|
154
|
+
with self.assertRaises(ValueError):
|
|
155
|
+
hits = list(jess.query(molecule, 2, 5, 5, max_candidates=-1))
|
|
156
|
+
|
|
135
157
|
@unittest.skipUnless(files, "importlib.resources not available")
|
|
136
158
|
def test_query(self):
|
|
137
159
|
with files(data).joinpath("template_01.qry").open() as f:
|
|
@@ -204,7 +226,7 @@ class TestJess(unittest.TestCase):
|
|
|
204
226
|
self.assertAlmostEqual(hit.log_evalue, -2.04, places=1)
|
|
205
227
|
|
|
206
228
|
@unittest.skipUnless(files, "importlib.resources not available")
|
|
207
|
-
def
|
|
229
|
+
def test_mcsa_query_no_reorder(self):
|
|
208
230
|
with files(data).joinpath("1.3.3.tpl").open() as f:
|
|
209
231
|
template = Template.load(f)
|
|
210
232
|
jess = Jess([template])
|
|
@@ -213,7 +235,7 @@ class TestJess(unittest.TestCase):
|
|
|
213
235
|
with files(data).joinpath("1AMY+1.3.3.txt").open() as f:
|
|
214
236
|
results = list(filter(None, f.read().split("REMARK")))
|
|
215
237
|
|
|
216
|
-
hits = list(jess.query(molecule, 2, 4, 4))
|
|
238
|
+
hits = list(jess.query(molecule, 2, 4, 4, reorder=False))
|
|
217
239
|
self.assertEqual(len(hits), len(results))
|
|
218
240
|
for hit, block in zip(hits, results):
|
|
219
241
|
self.assertIs(hit.template, template)
|
|
@@ -251,3 +273,102 @@ class TestJess(unittest.TestCase):
|
|
|
251
273
|
self.assertAlmostEqual(atom.occupancy, float(atom_line[55:61]), places=3)
|
|
252
274
|
self.assertAlmostEqual(atom.temperature_factor, float(atom_line[61:67]), places=3)
|
|
253
275
|
|
|
276
|
+
@unittest.skipUnless(files, "importlib.resources not available")
|
|
277
|
+
def test_mcsa_query_reorder(self):
|
|
278
|
+
with files(data).joinpath("1.3.3.tpl").open() as f:
|
|
279
|
+
template = Template.load(f)
|
|
280
|
+
jess = Jess([template])
|
|
281
|
+
with files(data).joinpath("1AMY.pdb").open() as f:
|
|
282
|
+
molecule = Molecule.load(f)
|
|
283
|
+
with files(data).joinpath("1AMY+1.3.3.txt").open() as f:
|
|
284
|
+
results = list(filter(None, f.read().split("REMARK")))
|
|
285
|
+
|
|
286
|
+
hits = list(jess.query(molecule, 2, 4, 4, reorder=True))
|
|
287
|
+
self.assertEqual(len(hits), len(results))
|
|
288
|
+
|
|
289
|
+
# `reorder=True` means that we may get results in a different order
|
|
290
|
+
# to Jess, so we need to match the hits in the file by residue number
|
|
291
|
+
# to make sure we compare them consistently.
|
|
292
|
+
|
|
293
|
+
results_by_serials = {}
|
|
294
|
+
for block in results:
|
|
295
|
+
lines = block.strip().splitlines()
|
|
296
|
+
serials = tuple([ int(line.split()[1]) for line in lines[1:-1] ])
|
|
297
|
+
results_by_serials[serials] = block
|
|
298
|
+
|
|
299
|
+
for hit in hits:
|
|
300
|
+
self.assertIs(hit.template, template)
|
|
301
|
+
block = results_by_serials[tuple(atom.serial for atom in hit.atoms(False))]
|
|
302
|
+
|
|
303
|
+
lines = block.strip().splitlines()
|
|
304
|
+
query_id, rmsd, template_id, _, determinant, _, logE = lines[0].split()
|
|
305
|
+
self.assertEqual(query_id, "1AMY")
|
|
306
|
+
self.assertAlmostEqual(float(rmsd), hit.rmsd, places=3)
|
|
307
|
+
self.assertAlmostEqual(float(determinant), hit.determinant, places=1)
|
|
308
|
+
self.assertAlmostEqual(float(logE), hit.log_evalue, places=1)
|
|
309
|
+
|
|
310
|
+
atom_lines = lines[1:-1]
|
|
311
|
+
atoms = hit.atoms()
|
|
312
|
+
self.assertEqual(len(atoms), len(atom_lines))
|
|
313
|
+
for atom, atom_line in zip(atoms, atom_lines):
|
|
314
|
+
self.assertEqual(atom.serial, int(atom_line[7:12]))
|
|
315
|
+
self.assertEqual(atom.name, atom_line[13:17].strip())
|
|
316
|
+
self.assertEqual(atom.residue_name, atom_line[17:21].strip())
|
|
317
|
+
self.assertEqual(atom.chain_id, atom_line[21:23].strip())
|
|
318
|
+
self.assertEqual(atom.residue_number, int(atom_line[23:27]))
|
|
319
|
+
self.assertAlmostEqual(atom.x, float(atom_line[31:39]), places=3)
|
|
320
|
+
self.assertAlmostEqual(atom.y, float(atom_line[39:47]), places=3)
|
|
321
|
+
self.assertAlmostEqual(atom.z, float(atom_line[47:55]), places=3)
|
|
322
|
+
self.assertAlmostEqual(atom.occupancy, float(atom_line[55:61]), places=3)
|
|
323
|
+
self.assertAlmostEqual(atom.temperature_factor, float(atom_line[61:67]), places=3)
|
|
324
|
+
|
|
325
|
+
atoms = hit.atoms(transform=False)
|
|
326
|
+
self.assertEqual(len(atoms), len(atom_lines))
|
|
327
|
+
for atom, atom_line in zip(atoms, atom_lines):
|
|
328
|
+
self.assertEqual(atom.serial, int(atom_line[7:12]))
|
|
329
|
+
self.assertEqual(atom.name, atom_line[13:17].strip())
|
|
330
|
+
self.assertEqual(atom.residue_name, atom_line[17:21].strip())
|
|
331
|
+
self.assertEqual(atom.chain_id, atom_line[21:23].strip())
|
|
332
|
+
self.assertEqual(atom.residue_number, int(atom_line[23:27]))
|
|
333
|
+
self.assertAlmostEqual(atom.occupancy, float(atom_line[55:61]), places=3)
|
|
334
|
+
self.assertAlmostEqual(atom.temperature_factor, float(atom_line[61:67]), places=3)
|
|
335
|
+
|
|
336
|
+
@unittest.skipUnless(files, "importlib.resources not available")
|
|
337
|
+
def test_ignore_chain_none(self):
|
|
338
|
+
with files(data).joinpath("4.1.2.tpl").open() as f:
|
|
339
|
+
template = Template.load(f)
|
|
340
|
+
jess = Jess([template])
|
|
341
|
+
with files(data).joinpath("5ayx.EF.pdb").open() as f:
|
|
342
|
+
molecule = Molecule.load(f)
|
|
343
|
+
|
|
344
|
+
hits = list(jess.query(molecule, 3, 3, 3, ignore_chain=None))
|
|
345
|
+
self.assertEqual(len(hits), 0)
|
|
346
|
+
|
|
347
|
+
@unittest.skipUnless(files, "importlib.resources not available")
|
|
348
|
+
def test_ignore_chain_residues(self):
|
|
349
|
+
with files(data).joinpath("4.1.2.tpl").open() as f:
|
|
350
|
+
template = Template.load(f)
|
|
351
|
+
jess = Jess([template])
|
|
352
|
+
with files(data).joinpath("5ayx.EF.pdb").open() as f:
|
|
353
|
+
molecule = Molecule.load(f)
|
|
354
|
+
|
|
355
|
+
hits = list(jess.query(molecule, 3, 3, 3, ignore_chain="residues"))
|
|
356
|
+
self.assertEqual(len(hits), 2)
|
|
357
|
+
for hit in hits:
|
|
358
|
+
atoms = hit.atoms(transform=False)
|
|
359
|
+
for i in range(1, len(atoms)):
|
|
360
|
+
if atoms[i-1].residue_number == atoms[i].residue_number:
|
|
361
|
+
self.assertEqual(atoms[i-1].chain_id, atoms[i].chain_id)
|
|
362
|
+
|
|
363
|
+
@unittest.skipUnless(files, "importlib.resources not available")
|
|
364
|
+
def test_ignore_chain_atoms(self):
|
|
365
|
+
with files(data).joinpath("4.1.2.tpl").open() as f:
|
|
366
|
+
template = Template.load(f)
|
|
367
|
+
jess = Jess([template])
|
|
368
|
+
with files(data).joinpath("5ayx.EF.pdb").open() as f:
|
|
369
|
+
molecule = Molecule.load(f)
|
|
370
|
+
|
|
371
|
+
hits = list(jess.query(molecule, 3, 3, 3, ignore_chain="atoms"))
|
|
372
|
+
self.assertEqual(len(hits), 7)
|
|
373
|
+
|
|
374
|
+
|
pyjess/tests/test_molecule.py
CHANGED
|
@@ -1,12 +1,31 @@
|
|
|
1
|
+
import itertools
|
|
1
2
|
import os
|
|
2
3
|
import pickle
|
|
3
4
|
import unittest
|
|
4
5
|
import tempfile
|
|
5
6
|
import textwrap
|
|
6
7
|
import sys
|
|
8
|
+
import warnings
|
|
7
9
|
|
|
10
|
+
from .utils import files
|
|
11
|
+
from . import data
|
|
8
12
|
from .._jess import Atom, Molecule
|
|
9
13
|
|
|
14
|
+
try:
|
|
15
|
+
import gemmi
|
|
16
|
+
except ImportError:
|
|
17
|
+
gemmi = None
|
|
18
|
+
|
|
19
|
+
try:
|
|
20
|
+
import Bio.PDB
|
|
21
|
+
except ImportError:
|
|
22
|
+
Bio = None
|
|
23
|
+
|
|
24
|
+
try:
|
|
25
|
+
from biotite.structure.io.pdb import PDBFile
|
|
26
|
+
except ImportError:
|
|
27
|
+
PDBFile = None
|
|
28
|
+
|
|
10
29
|
MOLECULE = textwrap.dedent(
|
|
11
30
|
"""
|
|
12
31
|
HEADER DNA RECOMBINATION 05-DEC-97 1A0P
|
|
@@ -22,6 +41,38 @@ MOLECULE = textwrap.dedent(
|
|
|
22
41
|
|
|
23
42
|
class TestMolecule(unittest.TestCase):
|
|
24
43
|
|
|
44
|
+
def assertHeteroAtomEqual(self, a1, a2):
|
|
45
|
+
# self.assertEqual(a1.serial, a2.serial)
|
|
46
|
+
self.assertEqual(a1.name, a2.name)
|
|
47
|
+
self.assertEqual(a1.altloc, a2.altloc)
|
|
48
|
+
self.assertEqual(a1.residue_name, a2.residue_name)
|
|
49
|
+
# self.assertEqual(a1.chain_id, a2.chain_id)
|
|
50
|
+
# self.assertEqual(a1.residue_number, a2.residue_number)
|
|
51
|
+
self.assertEqual(a1.insertion_code, a2.insertion_code)
|
|
52
|
+
self.assertEqual(a1.element, a2.element)
|
|
53
|
+
self.assertAlmostEqual(a1.x, a2.x, places=5)
|
|
54
|
+
self.assertAlmostEqual(a1.y, a2.y, places=5)
|
|
55
|
+
self.assertAlmostEqual(a1.z, a2.z, places=5)
|
|
56
|
+
self.assertAlmostEqual(a1.occupancy, a2.occupancy, places=5)
|
|
57
|
+
self.assertAlmostEqual(a1.temperature_factor, a2.temperature_factor, places=5)
|
|
58
|
+
self.assertAlmostEqual(a1.charge, a2.charge, places=5)
|
|
59
|
+
|
|
60
|
+
def assertAtomEqual(self, a1, a2):
|
|
61
|
+
self.assertEqual(a1.serial, a2.serial)
|
|
62
|
+
self.assertEqual(a1.name, a2.name)
|
|
63
|
+
self.assertEqual(a1.altloc, a2.altloc)
|
|
64
|
+
self.assertEqual(a1.residue_name, a2.residue_name)
|
|
65
|
+
self.assertEqual(a1.chain_id, a2.chain_id)
|
|
66
|
+
self.assertEqual(a1.residue_number, a2.residue_number)
|
|
67
|
+
self.assertEqual(a1.insertion_code, a2.insertion_code)
|
|
68
|
+
self.assertEqual(a1.element, a2.element)
|
|
69
|
+
self.assertAlmostEqual(a1.x, a2.x, places=5)
|
|
70
|
+
self.assertAlmostEqual(a1.y, a2.y, places=5)
|
|
71
|
+
self.assertAlmostEqual(a1.z, a2.z, places=5)
|
|
72
|
+
self.assertAlmostEqual(a1.occupancy, a2.occupancy, places=5)
|
|
73
|
+
self.assertAlmostEqual(a1.temperature_factor, a2.temperature_factor, places=5)
|
|
74
|
+
self.assertAlmostEqual(a1.charge, a2.charge, places=5)
|
|
75
|
+
|
|
25
76
|
def _create_atom(self, **kwargs):
|
|
26
77
|
default = dict(serial=1, name='N', altloc=' ', residue_name='GLN', chain_id='A', residue_number=3, x=8.171, y=-51.403, z=42.886, segment='', insertion_code=' ', occupancy=1.0, temperature_factor=55.63, charge=0, element='N')
|
|
27
78
|
default.update(kwargs)
|
|
@@ -139,3 +190,98 @@ class TestMolecule(unittest.TestCase):
|
|
|
139
190
|
self.assertEqual(list(mol1), list(mol2))
|
|
140
191
|
self.assertEqual(mol1.id, mol2.id)
|
|
141
192
|
self.assertEqual(mol1, mol2)
|
|
193
|
+
|
|
194
|
+
@unittest.skipUnless(files, "importlib.resources not available")
|
|
195
|
+
@unittest.skipUnless(gemmi, "gemmi not available")
|
|
196
|
+
def test_load_consistency_no_skip_hetatm(self):
|
|
197
|
+
with files(data).joinpath("1AMY.pdb").open() as f:
|
|
198
|
+
pdb_molecule = Molecule.load(f, format="pdb")
|
|
199
|
+
with files(data).joinpath("1AMY.cif").open() as f:
|
|
200
|
+
with warnings.catch_warnings():
|
|
201
|
+
warnings.simplefilter('ignore')
|
|
202
|
+
cif_molecule = Molecule.load(f, format="cif")
|
|
203
|
+
self.assertEqual(len(cif_molecule), 3339)
|
|
204
|
+
self.assertEqual(len(pdb_molecule), 3339)
|
|
205
|
+
for pdb_atom, cif_atom in itertools.islice(zip(pdb_molecule, cif_molecule), 3184):
|
|
206
|
+
self.assertAtomEqual(pdb_atom, cif_atom)
|
|
207
|
+
for pdb_atom, cif_atom in itertools.islice(zip(pdb_molecule, cif_molecule), 3184, 3339):
|
|
208
|
+
self.assertHeteroAtomEqual(pdb_atom, cif_atom)
|
|
209
|
+
|
|
210
|
+
@unittest.skipUnless(files, "importlib.resources not available")
|
|
211
|
+
@unittest.skipUnless(gemmi, "gemmi not available")
|
|
212
|
+
def test_load_consistency_no_skip_hetatm_use_author(self):
|
|
213
|
+
with files(data).joinpath("1AMY.pdb").open() as f:
|
|
214
|
+
pdb_molecule = Molecule.load(f, format="pdb")
|
|
215
|
+
with files(data).joinpath("1AMY.cif").open() as f:
|
|
216
|
+
cif_molecule = Molecule.load(f, format="cif", use_author=True)
|
|
217
|
+
self.assertEqual(len(cif_molecule), 3339)
|
|
218
|
+
self.assertEqual(len(pdb_molecule), 3339)
|
|
219
|
+
for pdb_atom, cif_atom in itertools.islice(zip(pdb_molecule, cif_molecule), 3184):
|
|
220
|
+
self.assertAtomEqual(pdb_atom, cif_atom)
|
|
221
|
+
for pdb_atom, cif_atom in itertools.islice(zip(pdb_molecule, cif_molecule), 3184, 3339):
|
|
222
|
+
self.assertHeteroAtomEqual(pdb_atom, cif_atom)
|
|
223
|
+
|
|
224
|
+
@unittest.skipUnless(files, "importlib.resources not available")
|
|
225
|
+
@unittest.skipUnless(gemmi, "gemmi not available")
|
|
226
|
+
def test_load_consistency_skip_hetatm(self):
|
|
227
|
+
with files(data).joinpath("1AMY.pdb").open() as f:
|
|
228
|
+
pdb_molecule = Molecule.load(f, format="pdb", skip_hetatm=True)
|
|
229
|
+
with files(data).joinpath("1AMY.cif").open() as f:
|
|
230
|
+
cif_molecule = Molecule.load(f, format="cif", skip_hetatm=True)
|
|
231
|
+
self.assertEqual(len(cif_molecule), 3184)
|
|
232
|
+
self.assertEqual(len(pdb_molecule), 3184)
|
|
233
|
+
for pdb_atom, cif_atom in itertools.islice(zip(pdb_molecule, cif_molecule), 3184):
|
|
234
|
+
self.assertAtomEqual(pdb_atom, cif_atom)
|
|
235
|
+
|
|
236
|
+
@unittest.skipUnless(files, "importlib.resources not available")
|
|
237
|
+
@unittest.skipUnless(gemmi, "gemmi not available")
|
|
238
|
+
def test_load_consistency_skip_hetatm_use_author(self):
|
|
239
|
+
with files(data).joinpath("1AMY.pdb").open() as f:
|
|
240
|
+
pdb_molecule = Molecule.load(f, format="pdb", skip_hetatm=True)
|
|
241
|
+
with files(data).joinpath("1AMY.cif").open() as f:
|
|
242
|
+
cif_molecule = Molecule.load(f, format="cif", skip_hetatm=True, use_author=True)
|
|
243
|
+
self.assertEqual(len(cif_molecule), 3184)
|
|
244
|
+
self.assertEqual(len(pdb_molecule), 3184)
|
|
245
|
+
for pdb_atom, cif_atom in itertools.islice(zip(pdb_molecule, cif_molecule), 3184):
|
|
246
|
+
self.assertAtomEqual(pdb_atom, cif_atom)
|
|
247
|
+
|
|
248
|
+
@unittest.skipUnless(files, "importlib.resources not available")
|
|
249
|
+
@unittest.skipUnless(Bio, "biopython not available")
|
|
250
|
+
def test_from_biopython(self):
|
|
251
|
+
parser = Bio.PDB.PDBParser()
|
|
252
|
+
with files(data).joinpath("1AMY.pdb").open() as f:
|
|
253
|
+
structure = parser.get_structure('1amy', f)
|
|
254
|
+
bio_mol = Molecule.from_biopython(structure)
|
|
255
|
+
with files(data).joinpath("1AMY.pdb").open() as f:
|
|
256
|
+
pdb_mol = Molecule.load(f, format="pdb")
|
|
257
|
+
self.assertEqual(len(pdb_mol), 3339)
|
|
258
|
+
self.assertEqual(len(bio_mol), 3339)
|
|
259
|
+
for pdb_atom, bio_atom in zip(pdb_mol, bio_mol):
|
|
260
|
+
self.assertAtomEqual(pdb_atom, bio_atom)
|
|
261
|
+
|
|
262
|
+
@unittest.skipUnless(files, "importlib.resources not available")
|
|
263
|
+
@unittest.skipUnless(gemmi, "gemmi not available")
|
|
264
|
+
def test_from_gemmi(self):
|
|
265
|
+
with files(data).joinpath("1AMY.pdb").open() as f:
|
|
266
|
+
structure = gemmi.read_pdb_string(f.read())
|
|
267
|
+
gemmi_mol = Molecule.from_gemmi(structure[0])
|
|
268
|
+
with files(data).joinpath("1AMY.pdb").open() as f:
|
|
269
|
+
pdb_mol = Molecule.load(f, format="pdb")
|
|
270
|
+
self.assertEqual(len(pdb_mol), 3339)
|
|
271
|
+
self.assertEqual(len(gemmi_mol), 3339)
|
|
272
|
+
for pdb_atom, gemmi_atom in zip(pdb_mol, gemmi_mol):
|
|
273
|
+
self.assertAtomEqual(pdb_atom, gemmi_atom)
|
|
274
|
+
|
|
275
|
+
@unittest.skipUnless(files, "importlib.resources not available")
|
|
276
|
+
@unittest.skipUnless(PDBFile, "biotite not available")
|
|
277
|
+
def test_from_biotite(self):
|
|
278
|
+
with files(data).joinpath("1AMY.pdb").open() as f:
|
|
279
|
+
pdb_file = PDBFile.read(f)
|
|
280
|
+
structure = pdb_file.get_structure(altloc="all", extra_fields=["atom_id", "b_factor", "occupancy", "charge"])
|
|
281
|
+
biotite_mol = Molecule.from_biotite(structure[0])
|
|
282
|
+
with files(data).joinpath("1AMY.pdb").open() as f:
|
|
283
|
+
pdb_mol = Molecule.load(f, format="pdb")
|
|
284
|
+
self.assertEqual(len(pdb_mol), 3339)
|
|
285
|
+
self.assertEqual(len(biotite_mol), 3339)
|
|
286
|
+
for pdb_atom, biotite_atom in zip(pdb_mol, biotite_mol):
|
|
287
|
+
self.assertAtomEqual(pdb_atom, biotite_atom)
|
pyjess/tests/test_template.py
CHANGED
|
@@ -6,6 +6,8 @@ import textwrap
|
|
|
6
6
|
import sys
|
|
7
7
|
|
|
8
8
|
from .._jess import Template
|
|
9
|
+
from .utils import files
|
|
10
|
+
from . import data
|
|
9
11
|
|
|
10
12
|
TEMPLATE = textwrap.dedent(
|
|
11
13
|
"""
|
|
@@ -109,9 +111,16 @@ class TestTemplate(unittest.TestCase):
|
|
|
109
111
|
tpl2 = tpl1.copy()
|
|
110
112
|
self.assertEqual(len(tpl1), len(tpl2))
|
|
111
113
|
self.assertEqual(tpl1, tpl2)
|
|
114
|
+
self.assertEqual(list(tpl1), list(tpl2))
|
|
112
115
|
|
|
113
116
|
def test_pickle_roundtrip(self):
|
|
114
117
|
tpl1 = Template.loads(TEMPLATE, id="tpl1")
|
|
115
118
|
tpl2 = pickle.loads(pickle.dumps(tpl1))
|
|
116
119
|
self.assertEqual(len(tpl1), len(tpl2))
|
|
117
|
-
self.assertEqual(tpl1, tpl2)
|
|
120
|
+
self.assertEqual(tpl1, tpl2)
|
|
121
|
+
|
|
122
|
+
@unittest.skipUnless(files, "importlib.resources not available")
|
|
123
|
+
def test_dimension_multiple_chains(self):
|
|
124
|
+
with files(data).joinpath("1sur.qry").open() as f:
|
|
125
|
+
template1 = Template.load(f)
|
|
126
|
+
self.assertEqual(template1.dimension, 4)
|