pyjess 0.7.0__cp38-abi3-macosx_11_0_arm64.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/.gitignore +2 -0
- pyjess/CMakeLists.txt +1 -0
- pyjess/__init__.py +21 -0
- pyjess/__main__.py +4 -0
- pyjess/_jess.abi3.so +0 -0
- pyjess/_jess.pyi +268 -0
- pyjess/_jess.pyx +2371 -0
- pyjess/cli.py +281 -0
- pyjess/py.typed +0 -0
- pyjess/tests/__init__.py +20 -0
- pyjess/tests/data/1.3.3.tpl +23 -0
- pyjess/tests/data/1AMY+1.3.3.txt +1872 -0
- pyjess/tests/data/1AMY.cif +6259 -0
- pyjess/tests/data/1AMY.pdb +3941 -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/data/__init__.py +0 -0
- pyjess/tests/data/pdb1lnb.pdb +3334 -0
- pyjess/tests/data/template_01.qry +11 -0
- pyjess/tests/data/template_02.qry +11 -0
- pyjess/tests/test_atom.py +111 -0
- pyjess/tests/test_doctest.py +78 -0
- pyjess/tests/test_hit.py +57 -0
- pyjess/tests/test_jess.py +374 -0
- pyjess/tests/test_molecule.py +287 -0
- pyjess/tests/test_template.py +126 -0
- pyjess/tests/test_template_atom.py +92 -0
- pyjess/tests/utils.py +7 -0
- pyjess-0.7.0.dist-info/METADATA +282 -0
- pyjess-0.7.0.dist-info/RECORD +34 -0
- pyjess-0.7.0.dist-info/WHEEL +5 -0
- pyjess-0.7.0.dist-info/entry_points.txt +3 -0
- pyjess-0.7.0.dist-info/licenses/COPYING +21 -0
|
@@ -0,0 +1,287 @@
|
|
|
1
|
+
import itertools
|
|
2
|
+
import os
|
|
3
|
+
import pickle
|
|
4
|
+
import unittest
|
|
5
|
+
import tempfile
|
|
6
|
+
import textwrap
|
|
7
|
+
import sys
|
|
8
|
+
import warnings
|
|
9
|
+
|
|
10
|
+
from .utils import files
|
|
11
|
+
from . import data
|
|
12
|
+
from .._jess import Atom, Molecule
|
|
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
|
+
|
|
29
|
+
MOLECULE = textwrap.dedent(
|
|
30
|
+
"""
|
|
31
|
+
HEADER DNA RECOMBINATION 05-DEC-97 1A0P
|
|
32
|
+
COMPND MOL_ID: 1;
|
|
33
|
+
ATOM 1 N GLN A 3 8.171 -51.403 42.886 1.00 55.63 N
|
|
34
|
+
ATOM 2 CA GLN A 3 9.475 -50.697 42.743 1.00 56.29 C
|
|
35
|
+
ATOM 3 C GLN A 3 10.215 -51.213 41.516 1.00 55.54 C
|
|
36
|
+
ATOM 4 O GLN A 3 10.401 -50.398 40.585 1.00 56.57 O
|
|
37
|
+
ATOM 5 CB GLN A 3 10.267 -50.747 44.040 1.00 72.29 C
|
|
38
|
+
"""
|
|
39
|
+
).strip()
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
class TestMolecule(unittest.TestCase):
|
|
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
|
+
|
|
76
|
+
def _create_atom(self, **kwargs):
|
|
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')
|
|
78
|
+
default.update(kwargs)
|
|
79
|
+
return Atom(**default)
|
|
80
|
+
|
|
81
|
+
def test_loads(self):
|
|
82
|
+
molecule = Molecule.loads(MOLECULE)
|
|
83
|
+
self.assertEqual(len(molecule), 5)
|
|
84
|
+
self.assertEqual(molecule.id, '1A0P')
|
|
85
|
+
|
|
86
|
+
@unittest.skipUnless(sys.implementation.name == "cpython", "only available on CPython")
|
|
87
|
+
def test_sizeof(self):
|
|
88
|
+
molecule = Molecule.loads(MOLECULE)
|
|
89
|
+
self.assertGreater(sys.getsizeof(molecule), 0)
|
|
90
|
+
|
|
91
|
+
@unittest.skipIf(os.name == "nt", "permission errors on Windows")
|
|
92
|
+
def test_load_filename(self):
|
|
93
|
+
with tempfile.NamedTemporaryFile("w", suffix=".pdb") as f:
|
|
94
|
+
f.write(MOLECULE)
|
|
95
|
+
f.flush()
|
|
96
|
+
molecule = Molecule.load(f.name)
|
|
97
|
+
self.assertEqual(len(molecule), 5)
|
|
98
|
+
self.assertEqual(molecule.id, '1A0P')
|
|
99
|
+
|
|
100
|
+
@unittest.skipIf(os.name == "nt", "permission errors on Windows")
|
|
101
|
+
def test_load_file(self):
|
|
102
|
+
with tempfile.NamedTemporaryFile("r+", suffix=".pdb") as f:
|
|
103
|
+
f.write(MOLECULE)
|
|
104
|
+
f.flush()
|
|
105
|
+
f.seek(0)
|
|
106
|
+
molecule = Molecule.load(f)
|
|
107
|
+
self.assertEqual(len(molecule), 5)
|
|
108
|
+
self.assertEqual(molecule.id, '1A0P')
|
|
109
|
+
|
|
110
|
+
@unittest.skipIf(os.name == "nt", "permission errors on Windows")
|
|
111
|
+
def test_load_error(self):
|
|
112
|
+
self.assertRaises(FileNotFoundError, Molecule.load, "/some/nonsensical/file")
|
|
113
|
+
self.assertRaises(IsADirectoryError, Molecule.load, os.path.dirname(__file__))
|
|
114
|
+
|
|
115
|
+
def test_init(self):
|
|
116
|
+
atoms = [
|
|
117
|
+
self._create_atom(serial=1, name='N'),
|
|
118
|
+
self._create_atom(serial=2, name='CA'),
|
|
119
|
+
self._create_atom(serial=3, name='C'),
|
|
120
|
+
self._create_atom(serial=4, name='O'),
|
|
121
|
+
]
|
|
122
|
+
molecule = Molecule(atoms)
|
|
123
|
+
self.assertEqual(molecule[0].name, 'N')
|
|
124
|
+
self.assertEqual(molecule[1].name, 'CA')
|
|
125
|
+
self.assertEqual(molecule[2].name, 'C')
|
|
126
|
+
self.assertEqual(molecule[3].name, 'O')
|
|
127
|
+
|
|
128
|
+
def test_init_long_id(self):
|
|
129
|
+
mol = Molecule.loads(MOLECULE, id="long identifier")
|
|
130
|
+
self.assertEqual(mol.id, "long identifier")
|
|
131
|
+
|
|
132
|
+
def test_getitem_slicing(self):
|
|
133
|
+
mol = Molecule.loads(MOLECULE)
|
|
134
|
+
mol2 = mol[1:3]
|
|
135
|
+
self.assertEqual(mol2.id, mol.id)
|
|
136
|
+
self.assertEqual(len(mol2), 2)
|
|
137
|
+
self.assertEqual(mol2[0].name, "CA")
|
|
138
|
+
self.assertEqual(mol2[1].name, "C")
|
|
139
|
+
|
|
140
|
+
def test_hash(self):
|
|
141
|
+
atoms = [
|
|
142
|
+
self._create_atom(serial=1, name='N'),
|
|
143
|
+
self._create_atom(serial=2, name='CA'),
|
|
144
|
+
self._create_atom(serial=3, name='C'),
|
|
145
|
+
self._create_atom(serial=4, name='O'),
|
|
146
|
+
]
|
|
147
|
+
mol1 = Molecule(atoms)
|
|
148
|
+
mol2 = Molecule(atoms)
|
|
149
|
+
self.assertEqual(hash(mol1), hash(mol2))
|
|
150
|
+
self.assertIsNot(mol1, mol2)
|
|
151
|
+
mol3 = Molecule(atoms[:-1])
|
|
152
|
+
self.assertNotEqual(hash(mol1), hash(mol3))
|
|
153
|
+
|
|
154
|
+
def test_eq(self):
|
|
155
|
+
atoms = [
|
|
156
|
+
self._create_atom(serial=1, name='N'),
|
|
157
|
+
self._create_atom(serial=2, name='CA'),
|
|
158
|
+
self._create_atom(serial=3, name='C'),
|
|
159
|
+
self._create_atom(serial=4, name='O'),
|
|
160
|
+
]
|
|
161
|
+
mol1 = Molecule(atoms)
|
|
162
|
+
mol2 = Molecule(atoms)
|
|
163
|
+
self.assertEqual(mol1, mol2)
|
|
164
|
+
self.assertIsNot(mol1, mol2)
|
|
165
|
+
mol3 = Molecule(atoms[:-1])
|
|
166
|
+
self.assertNotEqual(mol1, mol3)
|
|
167
|
+
|
|
168
|
+
def test_copy(self):
|
|
169
|
+
atoms = [
|
|
170
|
+
self._create_atom(serial=1, name='N'),
|
|
171
|
+
self._create_atom(serial=2, name='CA'),
|
|
172
|
+
self._create_atom(serial=3, name='C'),
|
|
173
|
+
self._create_atom(serial=4, name='O'),
|
|
174
|
+
]
|
|
175
|
+
mol1 = Molecule(atoms)
|
|
176
|
+
mol2 = mol1.copy()
|
|
177
|
+
self.assertEqual(list(mol1), list(mol2))
|
|
178
|
+
self.assertEqual(mol1.id, mol2.id)
|
|
179
|
+
self.assertEqual(mol1, mol2)
|
|
180
|
+
|
|
181
|
+
def test_pickle_roundtrip(self):
|
|
182
|
+
atoms = [
|
|
183
|
+
self._create_atom(serial=1, name='N'),
|
|
184
|
+
self._create_atom(serial=2, name='CA'),
|
|
185
|
+
self._create_atom(serial=3, name='C'),
|
|
186
|
+
self._create_atom(serial=4, name='O'),
|
|
187
|
+
]
|
|
188
|
+
mol1 = Molecule(atoms)
|
|
189
|
+
mol2 = pickle.loads(pickle.dumps(mol1))
|
|
190
|
+
self.assertEqual(list(mol1), list(mol2))
|
|
191
|
+
self.assertEqual(mol1.id, mol2.id)
|
|
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)
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
import os
|
|
2
|
+
import pickle
|
|
3
|
+
import unittest
|
|
4
|
+
import tempfile
|
|
5
|
+
import textwrap
|
|
6
|
+
import sys
|
|
7
|
+
|
|
8
|
+
from .._jess import Template
|
|
9
|
+
from .utils import files
|
|
10
|
+
from . import data
|
|
11
|
+
|
|
12
|
+
TEMPLATE = textwrap.dedent(
|
|
13
|
+
"""
|
|
14
|
+
ATOM 0 NZ LYS A1030 1.431 -9.717 -1.722
|
|
15
|
+
ATOM 0 CG ASP A1132 0.000 0.000 0.000
|
|
16
|
+
ATOM 0 OD1 ASP A1132 0.595 1.085 0.000
|
|
17
|
+
ATOM 0 OD2 ASP A1132 0.609 -1.111 0.000
|
|
18
|
+
ATOM 1 NE ARG A1136 3.953 0.597 -1.721 K
|
|
19
|
+
ATOM 0 CG ASN A1137 0.736 -1.869 -4.261
|
|
20
|
+
ATOM 0 OD1 ASN A1137 1.760 -2.435 -4.344
|
|
21
|
+
ATOM 0 ND2 ASN A1137 0.264 -1.477 -3.134
|
|
22
|
+
ATOM 0 CG ASP A1150 -0.010 -5.408 -2.070
|
|
23
|
+
ATOM 0 OD1 ASP A1150 -0.587 -5.769 -1.153
|
|
24
|
+
ATOM 0 OD2 ASP A1150 1.085 -5.212 -2.011
|
|
25
|
+
"""
|
|
26
|
+
).strip()
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
class TestTemplate(unittest.TestCase):
|
|
30
|
+
|
|
31
|
+
def test_loads(self):
|
|
32
|
+
template = Template.loads(TEMPLATE)
|
|
33
|
+
self.assertEqual(len(template), 11)
|
|
34
|
+
self.assertEqual(template.dimension, 5)
|
|
35
|
+
self.assertEqual(template[0].residue_names, ("LYS",))
|
|
36
|
+
self.assertEqual(template[0].atom_names, ("NZ",))
|
|
37
|
+
self.assertEqual(template[1].atom_names, ("CG",))
|
|
38
|
+
self.assertEqual(template[2].residue_number, 1132)
|
|
39
|
+
self.assertEqual(template[-1].residue_number, 1150)
|
|
40
|
+
|
|
41
|
+
@unittest.skipIf(os.name == "nt", "permission errors on Windows")
|
|
42
|
+
def test_load_filename(self):
|
|
43
|
+
with tempfile.NamedTemporaryFile("w", suffix=".pdb") as f:
|
|
44
|
+
f.write(TEMPLATE)
|
|
45
|
+
f.flush()
|
|
46
|
+
template = Template.load(f.name)
|
|
47
|
+
self.assertEqual(template[0].residue_names, ("LYS",))
|
|
48
|
+
self.assertEqual(template[0].atom_names, ("NZ",))
|
|
49
|
+
self.assertEqual(template[1].atom_names, ("CG",))
|
|
50
|
+
self.assertEqual(template[2].residue_number, 1132)
|
|
51
|
+
self.assertEqual(template[-1].residue_number, 1150)
|
|
52
|
+
|
|
53
|
+
@unittest.skipIf(os.name == "nt", "permission errors on Windows")
|
|
54
|
+
def test_load_file(self):
|
|
55
|
+
with tempfile.NamedTemporaryFile("r+", suffix=".pdb") as f:
|
|
56
|
+
f.write(TEMPLATE)
|
|
57
|
+
f.flush()
|
|
58
|
+
f.seek(0)
|
|
59
|
+
template = Template.load(f)
|
|
60
|
+
self.assertEqual(template[0].residue_names, ("LYS",))
|
|
61
|
+
self.assertEqual(template[0].atom_names, ("NZ",))
|
|
62
|
+
self.assertEqual(template[1].atom_names, ("CG",))
|
|
63
|
+
self.assertEqual(template[2].residue_number, 1132)
|
|
64
|
+
self.assertEqual(template[-1].residue_number, 1150)
|
|
65
|
+
|
|
66
|
+
@unittest.skipIf(os.name == "nt", "permission errors on Windows")
|
|
67
|
+
def test_load_error(self):
|
|
68
|
+
self.assertRaises(FileNotFoundError, Template.load, "/some/nonsensical/file")
|
|
69
|
+
self.assertRaises(IsADirectoryError, Template.load, os.path.dirname(__file__))
|
|
70
|
+
|
|
71
|
+
@unittest.skipUnless(sys.implementation.name == "cpython", "only available on CPython")
|
|
72
|
+
def test_sizeof(self):
|
|
73
|
+
template = Template.loads(TEMPLATE)
|
|
74
|
+
self.assertGreater(sys.getsizeof(template), 0)
|
|
75
|
+
|
|
76
|
+
def test_init_empty(self):
|
|
77
|
+
template = Template()
|
|
78
|
+
self.assertEqual(len(template), 0)
|
|
79
|
+
self.assertFalse(bool(template))
|
|
80
|
+
|
|
81
|
+
def test_loads_id(self):
|
|
82
|
+
template = Template.loads(TEMPLATE)
|
|
83
|
+
self.assertIs(template.id, None)
|
|
84
|
+
template = Template.loads("REMARK PDB_ID 2bw4\n" + TEMPLATE)
|
|
85
|
+
self.assertEqual(template.id, "2bw4")
|
|
86
|
+
|
|
87
|
+
def test_getitem_slicing(self):
|
|
88
|
+
tpl1 = Template.loads(TEMPLATE, id="tpl1")
|
|
89
|
+
tpl2 = tpl1[1:4]
|
|
90
|
+
self.assertEqual(len(tpl2), 3)
|
|
91
|
+
|
|
92
|
+
def test_hash(self):
|
|
93
|
+
tpl1 = Template.loads(TEMPLATE, id="tpl1")
|
|
94
|
+
tpl2 = Template.loads(TEMPLATE, id="tpl1")
|
|
95
|
+
self.assertEqual(tpl1, tpl2)
|
|
96
|
+
self.assertEqual(hash(tpl1), hash(tpl2))
|
|
97
|
+
self.assertIsNot(tpl1, tpl2)
|
|
98
|
+
tpl3 = Template.loads(TEMPLATE, id="tpl3")
|
|
99
|
+
self.assertNotEqual(hash(tpl1), hash(tpl3))
|
|
100
|
+
|
|
101
|
+
def test_eq(self):
|
|
102
|
+
tpl1 = Template.loads(TEMPLATE, id="tpl1")
|
|
103
|
+
tpl2 = Template.loads(TEMPLATE, id="tpl1")
|
|
104
|
+
self.assertEqual(tpl1, tpl2)
|
|
105
|
+
self.assertIsNot(tpl1, tpl2)
|
|
106
|
+
tpl3 = Template.loads(TEMPLATE, id="tpl3")
|
|
107
|
+
self.assertNotEqual(tpl1, tpl3)
|
|
108
|
+
|
|
109
|
+
def test_copy(self):
|
|
110
|
+
tpl1 = Template.loads(TEMPLATE, id="tpl1")
|
|
111
|
+
tpl2 = tpl1.copy()
|
|
112
|
+
self.assertEqual(len(tpl1), len(tpl2))
|
|
113
|
+
self.assertEqual(tpl1, tpl2)
|
|
114
|
+
self.assertEqual(list(tpl1), list(tpl2))
|
|
115
|
+
|
|
116
|
+
def test_pickle_roundtrip(self):
|
|
117
|
+
tpl1 = Template.loads(TEMPLATE, id="tpl1")
|
|
118
|
+
tpl2 = pickle.loads(pickle.dumps(tpl1))
|
|
119
|
+
self.assertEqual(len(tpl1), len(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)
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
import unittest
|
|
2
|
+
import sys
|
|
3
|
+
import pickle
|
|
4
|
+
|
|
5
|
+
from .._jess import TemplateAtom
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class TestTemplateAtom(unittest.TestCase):
|
|
9
|
+
|
|
10
|
+
def test_load(self):
|
|
11
|
+
atom = TemplateAtom.loads("ATOM 1 NE ARG A1136 3.953 0.597 -1.721 K")
|
|
12
|
+
self.assertEqual(atom.match_mode, 1)
|
|
13
|
+
self.assertEqual(atom.atom_names, ("NE",))
|
|
14
|
+
self.assertEqual(atom.residue_names, ("ARG", "LYS",))
|
|
15
|
+
self.assertEqual(atom.chain_id, "A")
|
|
16
|
+
self.assertEqual(atom.residue_number, 1136)
|
|
17
|
+
self.assertEqual(atom.x, 3.953)
|
|
18
|
+
self.assertEqual(atom.y, 0.597)
|
|
19
|
+
self.assertEqual(atom.z, -1.721)
|
|
20
|
+
|
|
21
|
+
def _create_atom(self, **kwargs):
|
|
22
|
+
default = {
|
|
23
|
+
"atom_names": ["NE"],
|
|
24
|
+
"residue_names": ["ARG"],
|
|
25
|
+
"chain_id": "A",
|
|
26
|
+
"residue_number": 1,
|
|
27
|
+
"x": 0.0,
|
|
28
|
+
"y": 0.0,
|
|
29
|
+
"z": 0.0,
|
|
30
|
+
"match_mode": 0,
|
|
31
|
+
}
|
|
32
|
+
default.update(kwargs)
|
|
33
|
+
return TemplateAtom(**default)
|
|
34
|
+
|
|
35
|
+
def test_hash(self):
|
|
36
|
+
a1 = self._create_atom()
|
|
37
|
+
a2 = self._create_atom()
|
|
38
|
+
self.assertEqual(hash(a1), hash(a2))
|
|
39
|
+
self.assertIsNot(a1, a2)
|
|
40
|
+
a3 = self._create_atom(x=1.0)
|
|
41
|
+
self.assertNotEqual(hash(a1), hash(a3))
|
|
42
|
+
|
|
43
|
+
def test_eq(self):
|
|
44
|
+
a1 = self._create_atom()
|
|
45
|
+
a2 = self._create_atom()
|
|
46
|
+
self.assertEqual(a1, a2)
|
|
47
|
+
self.assertIsNot(a1, a2)
|
|
48
|
+
a3 = self._create_atom(x=1.0)
|
|
49
|
+
self.assertNotEqual(a1, a3)
|
|
50
|
+
|
|
51
|
+
@unittest.skipUnless(sys.implementation.name == "cpython", "only available on CPython")
|
|
52
|
+
def test_sizeof(self):
|
|
53
|
+
atom = self._create_atom()
|
|
54
|
+
self.assertGreater(sys.getsizeof(atom), 0)
|
|
55
|
+
|
|
56
|
+
def test_init_invalid_match_code(self):
|
|
57
|
+
self.assertRaises(ValueError, self._create_atom, match_mode=2000)
|
|
58
|
+
self.assertRaises(ValueError, self._create_atom, match_mode=-10)
|
|
59
|
+
|
|
60
|
+
def test_init_invalid_residue_name(self):
|
|
61
|
+
self.assertRaises(ValueError, self._create_atom, residue_names=["something"])
|
|
62
|
+
|
|
63
|
+
def test_init_consistency(self):
|
|
64
|
+
loaded = TemplateAtom.loads("ATOM 1 NE ARG A1136 3.953 0.597 -1.721 K")
|
|
65
|
+
created = TemplateAtom(
|
|
66
|
+
chain_id=loaded.chain_id,
|
|
67
|
+
residue_number=loaded.residue_number,
|
|
68
|
+
x=loaded.x,
|
|
69
|
+
y=loaded.y,
|
|
70
|
+
z=loaded.z,
|
|
71
|
+
residue_names=loaded.residue_names,
|
|
72
|
+
atom_names=loaded.atom_names,
|
|
73
|
+
distance_weight=loaded.distance_weight,
|
|
74
|
+
match_mode=loaded.match_mode
|
|
75
|
+
)
|
|
76
|
+
for attribute in ("atom_names", "residue_names", "chain_id", "x", "y", "z", "match_mode"):
|
|
77
|
+
self.assertEqual(getattr(loaded, attribute), getattr(created, attribute))
|
|
78
|
+
self.assertEqual(loaded, created)
|
|
79
|
+
|
|
80
|
+
def test_repr_roundtrip(self):
|
|
81
|
+
atom = self._create_atom()
|
|
82
|
+
copy = eval(repr(atom))
|
|
83
|
+
for attribute in ("atom_names", "residue_names", "chain_id", "x", "y", "z", "match_mode"):
|
|
84
|
+
self.assertEqual(getattr(copy, attribute), getattr(atom, attribute))
|
|
85
|
+
self.assertEqual(atom, copy)
|
|
86
|
+
|
|
87
|
+
def test_pickle_roundtrip(self):
|
|
88
|
+
atom = self._create_atom()
|
|
89
|
+
copy = pickle.loads(pickle.dumps(atom))
|
|
90
|
+
for attribute in ("atom_names", "residue_names", "chain_id", "x", "y", "z", "match_mode"):
|
|
91
|
+
self.assertEqual(getattr(copy, attribute), getattr(atom, attribute))
|
|
92
|
+
self.assertEqual(atom, copy)
|