pyjess 0.3.3__cp311-cp311-win_amd64.whl → 0.4.1__cp311-cp311-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/_jess.cp311-win_amd64.pyd +0 -0
- pyjess/_jess.pyi +29 -3
- pyjess/_jess.pyx +258 -50
- pyjess/tests/test_atom.py +58 -1
- pyjess/tests/test_jess.py +54 -0
- pyjess/tests/test_molecule.py +56 -1
- pyjess/tests/test_template.py +39 -9
- pyjess/tests/test_template_atom.py +45 -3
- {pyjess-0.3.3.dist-info → pyjess-0.4.1.dist-info}/METADATA +2 -2
- {pyjess-0.3.3.dist-info → pyjess-0.4.1.dist-info}/RECORD +12 -12
- {pyjess-0.3.3.dist-info → pyjess-0.4.1.dist-info}/WHEEL +0 -0
- {pyjess-0.3.3.dist-info → pyjess-0.4.1.dist-info}/licenses/COPYING +0 -0
pyjess/_jess.cp311-win_amd64.pyd
CHANGED
|
Binary file
|
pyjess/_jess.pyi
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import os
|
|
2
2
|
import typing
|
|
3
|
-
from typing import Any, Generic, Union, Optional, Sequence, Iterator, Iterable, List, TextIO, Sized, TypeVar
|
|
3
|
+
from typing import Any, Generic, Union, Optional, Sequence, Iterator, Iterable, List, TextIO, Sized, TypeVar, Tuple
|
|
4
4
|
|
|
5
5
|
try:
|
|
6
6
|
from typing import Literal
|
|
@@ -13,6 +13,8 @@ MATCH_MODE = Literal[
|
|
|
13
13
|
|
|
14
14
|
_SELF = TypeVar("_SELF")
|
|
15
15
|
|
|
16
|
+
__version__: str
|
|
17
|
+
|
|
16
18
|
class Molecule(Sequence[Atom]):
|
|
17
19
|
@classmethod
|
|
18
20
|
def load(cls, file: Union[TextIO, str, os.PathLike[str]], id: Optional[str] = None, ignore_endmdl: bool = False) -> Molecule: ...
|
|
@@ -26,9 +28,14 @@ class Molecule(Sequence[Atom]):
|
|
|
26
28
|
def __getitem__(self: _SELF, index: slice) -> _SELF: ...
|
|
27
29
|
@typing.overload
|
|
28
30
|
def __getitem__(self: _SELF, index: Union[int, slice]) -> Union[Atom, _SELF]: ...
|
|
31
|
+
def __copy__(self) -> Molecule: ...
|
|
32
|
+
def __eq__(self, other: object) -> bool: ...
|
|
33
|
+
def __hash__(self) -> int: ...
|
|
34
|
+
def __reduce__(self) -> Tuple[Any, ...]: ...
|
|
29
35
|
@property
|
|
30
36
|
def id(self) -> Optional[str]: ...
|
|
31
37
|
def conserved(self: _SELF, cutoff: float = 0.0) -> _SELF: ...
|
|
38
|
+
def copy(self) -> Molecule: ...
|
|
32
39
|
|
|
33
40
|
class Atom:
|
|
34
41
|
@classmethod
|
|
@@ -54,7 +61,11 @@ class Atom:
|
|
|
54
61
|
element: str = "",
|
|
55
62
|
charge: int = 0,
|
|
56
63
|
): ...
|
|
64
|
+
def __eq__(self, other: object) -> bool: ...
|
|
65
|
+
def __hash__(self) -> int: ...
|
|
66
|
+
def __reduce__(self) -> Tuple[Any, ...]: ...
|
|
57
67
|
def __repr__(self) -> str: ...
|
|
68
|
+
def __copy__(self) -> Atom: ...
|
|
58
69
|
@property
|
|
59
70
|
def serial(self) -> int: ...
|
|
60
71
|
@property
|
|
@@ -85,6 +96,7 @@ class Atom:
|
|
|
85
96
|
def y(self) -> float: ...
|
|
86
97
|
@property
|
|
87
98
|
def z(self) -> float: ...
|
|
99
|
+
def copy(self) -> Atom: ...
|
|
88
100
|
|
|
89
101
|
class TemplateAtom:
|
|
90
102
|
@classmethod
|
|
@@ -105,6 +117,10 @@ class TemplateAtom:
|
|
|
105
117
|
match_mode: MATCH_MODE = 0,
|
|
106
118
|
): ...
|
|
107
119
|
def __repr__(self) -> str: ...
|
|
120
|
+
def __eq__(self, other: object) -> bool: ...
|
|
121
|
+
def __hash__(self) -> int: ...
|
|
122
|
+
def __reduce__(self) -> Tuple[Any, ...]: ...
|
|
123
|
+
def __copy__(self: _SELF) -> _SELF: ...
|
|
108
124
|
@property
|
|
109
125
|
def match_mode(self) -> MATCH_MODE: ...
|
|
110
126
|
@property
|
|
@@ -118,11 +134,12 @@ class TemplateAtom:
|
|
|
118
134
|
@property
|
|
119
135
|
def z(self) -> float: ...
|
|
120
136
|
@property
|
|
121
|
-
def atom_names(self) ->
|
|
137
|
+
def atom_names(self) -> Tuple[str, ...]: ...
|
|
122
138
|
@property
|
|
123
|
-
def residue_names(self) ->
|
|
139
|
+
def residue_names(self) -> Tuple[str, ...]: ...
|
|
124
140
|
@property
|
|
125
141
|
def distance_weight(self) -> float: ...
|
|
142
|
+
def copy(self: _SELF) -> _SELF: ...
|
|
126
143
|
|
|
127
144
|
class Template(Sequence[TemplateAtom]):
|
|
128
145
|
@classmethod
|
|
@@ -137,10 +154,15 @@ class Template(Sequence[TemplateAtom]):
|
|
|
137
154
|
def __getitem__(self: _SELF, index: slice) -> _SELF: ...
|
|
138
155
|
@typing.overload
|
|
139
156
|
def __getitem__(self: _SELF, index: Union[int, slice]) -> Union[TemplateAtom, _SELF]: ...
|
|
157
|
+
def __eq__(self, other: object) -> bool: ...
|
|
158
|
+
def __hash__(self) -> int: ...
|
|
159
|
+
def __reduce__(self) -> Tuple[Any, ...]: ...
|
|
160
|
+
def __copy__(self) -> Template: ...
|
|
140
161
|
@property
|
|
141
162
|
def id(self) -> str: ...
|
|
142
163
|
@property
|
|
143
164
|
def dimension(self) -> int: ...
|
|
165
|
+
def copy(self) -> Template: ...
|
|
144
166
|
|
|
145
167
|
_T = TypeVar("_T", bound=Template)
|
|
146
168
|
|
|
@@ -184,6 +206,10 @@ class Jess(Generic[_T], Sequence[_T]):
|
|
|
184
206
|
def __getitem__(self, index: slice) -> Jess[_T]: ...
|
|
185
207
|
@typing.overload
|
|
186
208
|
def __getitem__(self, index: Union[int, slice]) -> Union[_T, Jess[_T]]: ...
|
|
209
|
+
def __eq__(self, other: object) -> bool: ...
|
|
210
|
+
def __hash__(self) -> int: ...
|
|
211
|
+
def __copy__(self: _SELF) -> _SELF: ...
|
|
212
|
+
def __reduce__(self) -> Tuple[Any, ...]: ...
|
|
187
213
|
def query(
|
|
188
214
|
self,
|
|
189
215
|
molecule: Molecule,
|
pyjess/_jess.pyx
CHANGED
|
@@ -43,7 +43,9 @@ from jess.tess_atom cimport TessAtom as _TessAtom
|
|
|
43
43
|
# --- Python imports ---------------------------------------------------------
|
|
44
44
|
|
|
45
45
|
import contextlib
|
|
46
|
+
import functools
|
|
46
47
|
import io
|
|
48
|
+
import itertools
|
|
47
49
|
import os
|
|
48
50
|
import warnings
|
|
49
51
|
|
|
@@ -53,10 +55,11 @@ __version__ = PROJECT_VERSION
|
|
|
53
55
|
|
|
54
56
|
cdef inline void copy_token(char* dst, const char* src, size_t n) noexcept nogil:
|
|
55
57
|
cdef size_t i
|
|
56
|
-
strncpy(dst, src, n)
|
|
57
58
|
for i in range(n):
|
|
58
|
-
if
|
|
59
|
+
if src[i] == ord(' ') or src[i] == 0:
|
|
59
60
|
dst[i] = ord('_')
|
|
61
|
+
else:
|
|
62
|
+
dst[i] = src[i]
|
|
60
63
|
dst[n] = 0
|
|
61
64
|
|
|
62
65
|
@contextlib.contextmanager
|
|
@@ -68,9 +71,12 @@ def nullcontext(return_value=None):
|
|
|
68
71
|
cdef class Molecule:
|
|
69
72
|
"""A molecule structure, as a sequence of `Atom` objects.
|
|
70
73
|
|
|
71
|
-
..
|
|
74
|
+
.. versionadded:: 0.2.2
|
|
72
75
|
Support identifiers of arbitrary length.
|
|
73
76
|
|
|
77
|
+
.. versionadded:: 0.4.0
|
|
78
|
+
Equality, hashing and pickle protocol support.
|
|
79
|
+
|
|
74
80
|
"""
|
|
75
81
|
cdef _Molecule* _mol
|
|
76
82
|
cdef str _id
|
|
@@ -204,6 +210,26 @@ cdef class Molecule:
|
|
|
204
210
|
atom._atom = <_Atom*> jess.molecule.Molecule_atom(self._mol, index_)
|
|
205
211
|
return atom
|
|
206
212
|
|
|
213
|
+
def __copy__(self):
|
|
214
|
+
return self.copy()
|
|
215
|
+
|
|
216
|
+
def __eq__(self, object other):
|
|
217
|
+
cdef Molecule other_
|
|
218
|
+
if not isinstance(other, Molecule):
|
|
219
|
+
return NotImplemented
|
|
220
|
+
other_ = other
|
|
221
|
+
if self._id != other_._id:
|
|
222
|
+
return False
|
|
223
|
+
if self._mol.count != other_._mol.count:
|
|
224
|
+
return False
|
|
225
|
+
return all(x == y for x,y in zip(self, other_))
|
|
226
|
+
|
|
227
|
+
def __hash__(self):
|
|
228
|
+
return hash((self._id, *(hash(x) for x in self)))
|
|
229
|
+
|
|
230
|
+
def __reduce__(self):
|
|
231
|
+
return type(self), (list(self), self.id)
|
|
232
|
+
|
|
207
233
|
def __sizeof__(self):
|
|
208
234
|
assert self._mol is not NULL
|
|
209
235
|
return (
|
|
@@ -229,9 +255,44 @@ cdef class Molecule:
|
|
|
229
255
|
]
|
|
230
256
|
)
|
|
231
257
|
|
|
258
|
+
cpdef Molecule copy(self):
|
|
259
|
+
"""Create a copy of this molecule and its atoms.
|
|
260
|
+
|
|
261
|
+
Returns:
|
|
262
|
+
`~pyjess.Molecule`: A newly allocated molecule with the same
|
|
263
|
+
identifier and atoms.
|
|
264
|
+
|
|
265
|
+
.. versionadded:: 0.4.0
|
|
266
|
+
|
|
267
|
+
"""
|
|
268
|
+
cdef Molecule copy = Molecule.__new__(Molecule)
|
|
269
|
+
cdef size_t size = sizeof(_Molecule) + self._mol.count * sizeof(_Atom*)
|
|
270
|
+
|
|
271
|
+
with nogil:
|
|
272
|
+
# allocate molecule storage
|
|
273
|
+
copy._mol = <_Molecule*> malloc(size)
|
|
274
|
+
if copy._mol is NULL:
|
|
275
|
+
raise MemoryError("Failed to allocate molecule")
|
|
276
|
+
# copy molecule attributes
|
|
277
|
+
copy._mol.count = self._mol.count
|
|
278
|
+
memset(copy._mol.id, b' ', 5)
|
|
279
|
+
# copy molecule atoms
|
|
280
|
+
for i in range(self._mol.count):
|
|
281
|
+
copy._mol.atom[i] = <_Atom*> malloc(sizeof(_Atom))
|
|
282
|
+
if copy._mol.atom[i] is NULL:
|
|
283
|
+
raise MemoryError("Failed to allocate atom")
|
|
284
|
+
memcpy(copy._mol.atom[i], self._mol.atom[i], sizeof(_Atom))
|
|
285
|
+
|
|
286
|
+
copy._id = self._id
|
|
287
|
+
return copy
|
|
288
|
+
|
|
232
289
|
|
|
233
290
|
cdef class Atom:
|
|
234
291
|
"""A single atom in a molecule.
|
|
292
|
+
|
|
293
|
+
.. versionadded:: 0.4.0
|
|
294
|
+
Equality, hashing and pickle protocol support.
|
|
295
|
+
|
|
235
296
|
"""
|
|
236
297
|
cdef object owner
|
|
237
298
|
cdef bint owned
|
|
@@ -297,11 +358,11 @@ cdef class Atom:
|
|
|
297
358
|
str chain_id,
|
|
298
359
|
int residue_number,
|
|
299
360
|
str insertion_code,
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
361
|
+
double x,
|
|
362
|
+
double y,
|
|
363
|
+
double z,
|
|
364
|
+
double occupancy = 0.0,
|
|
365
|
+
double temperature_factor = 0.0,
|
|
305
366
|
str segment = '',
|
|
306
367
|
str element = '',
|
|
307
368
|
int charge = 0,
|
|
@@ -336,7 +397,7 @@ cdef class Atom:
|
|
|
336
397
|
self._atom.serial = serial
|
|
337
398
|
self._atom.altLoc = ord(altloc)
|
|
338
399
|
self._atom.chainID1 = ord(chain_id[0]) if len(chain_id) > 0 else 0
|
|
339
|
-
self._atom.chainID2 = ord(chain_id[1]) if len(chain_id) > 1 else ord('
|
|
400
|
+
self._atom.chainID2 = ord(chain_id[1]) if len(chain_id) > 1 else ord(' ')
|
|
340
401
|
self._atom.resSeq = residue_number
|
|
341
402
|
self._atom.iCode = ord(insertion_code)
|
|
342
403
|
self._atom.x[0] = x
|
|
@@ -354,29 +415,38 @@ cdef class Atom:
|
|
|
354
415
|
_name.insert(0, ord('_'))
|
|
355
416
|
copy_token(self._atom.name, _name.ljust(4, b'\0'), 4)
|
|
356
417
|
|
|
418
|
+
def __copy__(self):
|
|
419
|
+
return self.copy()
|
|
420
|
+
|
|
421
|
+
cdef dict _state(self):
|
|
422
|
+
return {
|
|
423
|
+
"serial": self.serial,
|
|
424
|
+
"name": self.name,
|
|
425
|
+
"altloc": self.altloc,
|
|
426
|
+
"residue_name": self.residue_name,
|
|
427
|
+
"chain_id": self.chain_id,
|
|
428
|
+
"residue_number": self.residue_number,
|
|
429
|
+
"insertion_code": self.insertion_code,
|
|
430
|
+
"x": self.x,
|
|
431
|
+
"y": self.y,
|
|
432
|
+
"z": self.z,
|
|
433
|
+
"temperature_factor": self.temperature_factor,
|
|
434
|
+
"occupancy": self.occupancy,
|
|
435
|
+
"segment": self.segment,
|
|
436
|
+
"element": self.element,
|
|
437
|
+
"charge": self.charge,
|
|
438
|
+
}
|
|
439
|
+
|
|
440
|
+
def __reduce__(self):
|
|
441
|
+
cdef dict state = self._state()
|
|
442
|
+
return functools.partial(type(self), **state), ()
|
|
443
|
+
|
|
357
444
|
def __repr__(self):
|
|
358
445
|
cdef str ty = type(self).__name__
|
|
359
|
-
cdef list args = [
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
f"residue_name={self.residue_name!r}",
|
|
364
|
-
f"chain_id={self.chain_id!r}",
|
|
365
|
-
f"residue_number={self.residue_number!r}",
|
|
366
|
-
f"x={self.x!r}",
|
|
367
|
-
f"y={self.y!r}",
|
|
368
|
-
f"z={self.z!r}",
|
|
369
|
-
f"segment={self.segment!r}",
|
|
370
|
-
f"insertion_code={self.insertion_code!r}",
|
|
371
|
-
]
|
|
372
|
-
if self.occupancy:
|
|
373
|
-
args.append(f"occupancy={self.occupancy!r}")
|
|
374
|
-
if self.temperature_factor:
|
|
375
|
-
args.append(f"temperature_factor={self.temperature_factor!r}")
|
|
376
|
-
if self.element:
|
|
377
|
-
args.append(f"element={self.element!r}")
|
|
378
|
-
if self.charge:
|
|
379
|
-
args.append(f"charge={self.charge!r}")
|
|
446
|
+
cdef list args = []
|
|
447
|
+
for k,v in self._state().items():
|
|
448
|
+
if v is not None:
|
|
449
|
+
args.append(f"{k}={v!r}")
|
|
380
450
|
return f"{ty}({', '.join(args)})"
|
|
381
451
|
|
|
382
452
|
def __sizeof__(self):
|
|
@@ -385,6 +455,17 @@ cdef class Atom:
|
|
|
385
455
|
size += sizeof(_Atom)
|
|
386
456
|
return size
|
|
387
457
|
|
|
458
|
+
def __eq__(self, object other):
|
|
459
|
+
cdef Atom other_
|
|
460
|
+
if not isinstance(other, Atom):
|
|
461
|
+
return NotImplemented
|
|
462
|
+
other_ = other
|
|
463
|
+
# FIXME: it should be possible to do a memcmp here.
|
|
464
|
+
return self._state() == other_._state()
|
|
465
|
+
|
|
466
|
+
def __hash__(self):
|
|
467
|
+
return hash(tuple(self._state().values()))
|
|
468
|
+
|
|
388
469
|
@property
|
|
389
470
|
def serial(self):
|
|
390
471
|
"""`int`: The atom serial number.
|
|
@@ -484,9 +565,29 @@ cdef class Atom:
|
|
|
484
565
|
assert self._atom is not NULL
|
|
485
566
|
return self._atom.x[2]
|
|
486
567
|
|
|
568
|
+
cpdef Atom copy(self):
|
|
569
|
+
"""Create a copy of this atom.
|
|
570
|
+
|
|
571
|
+
Returns:
|
|
572
|
+
`~pyjess.Atom`: A newly allocated atom with identical attributes.
|
|
573
|
+
|
|
574
|
+
.. versionadded:: 0.4.0
|
|
575
|
+
|
|
576
|
+
"""
|
|
577
|
+
cdef Atom copy = Atom.__new__(Atom)
|
|
578
|
+
copy._atom = <_Atom*> malloc(sizeof(_Atom))
|
|
579
|
+
if copy._atom is NULL:
|
|
580
|
+
raise MemoryError("Failed to allocate atom")
|
|
581
|
+
memcpy(copy._atom, self._atom, sizeof(_Atom))
|
|
582
|
+
return copy
|
|
583
|
+
|
|
487
584
|
|
|
488
585
|
cdef class TemplateAtom:
|
|
489
586
|
"""A single template atom.
|
|
587
|
+
|
|
588
|
+
.. versionadded:: 0.4.0
|
|
589
|
+
Equality, hashing and pickle protocol support.
|
|
590
|
+
|
|
490
591
|
"""
|
|
491
592
|
cdef object owner
|
|
492
593
|
cdef bint owned
|
|
@@ -630,23 +731,42 @@ cdef class TemplateAtom:
|
|
|
630
731
|
raise ValueError(f"Invalid residue name: {name!r}")
|
|
631
732
|
copy_token(self._atom.resName[m], _name.ljust(3, b'\0'), 3)
|
|
632
733
|
|
|
734
|
+
cdef dict _state(self):
|
|
735
|
+
return {
|
|
736
|
+
"chain_id": self.chain_id,
|
|
737
|
+
"residue_number": self.residue_number,
|
|
738
|
+
"x": self.x,
|
|
739
|
+
"y": self.y,
|
|
740
|
+
"z": self.z,
|
|
741
|
+
"residue_names": self.residue_names,
|
|
742
|
+
"atom_names": self.atom_names,
|
|
743
|
+
"distance_weight": self.distance_weight,
|
|
744
|
+
"match_mode": self.match_mode,
|
|
745
|
+
}
|
|
746
|
+
|
|
633
747
|
def __repr__(self):
|
|
634
748
|
cdef str ty = type(self).__name__
|
|
635
|
-
cdef list args = [
|
|
636
|
-
|
|
637
|
-
f"
|
|
638
|
-
f"x={self.x!r}",
|
|
639
|
-
f"y={self.y!r}",
|
|
640
|
-
f"z={self.z!r}",
|
|
641
|
-
f"residue_names={self.residue_names!r}",
|
|
642
|
-
f"atom_names={self.atom_names!r}",
|
|
643
|
-
]
|
|
644
|
-
if self.distance_weight:
|
|
645
|
-
args.append(f"distance_weight={self.distance_weight!r}")
|
|
646
|
-
if self.match_mode:
|
|
647
|
-
args.append(f"match_mode={self.match_mode!r}")
|
|
749
|
+
cdef list args = []
|
|
750
|
+
for k, v in self._state().items():
|
|
751
|
+
args.append(f"{k}={v!r}")
|
|
648
752
|
return f"{ty}({', '.join(args)})"
|
|
649
753
|
|
|
754
|
+
def __copy__(self):
|
|
755
|
+
return self.copy()
|
|
756
|
+
|
|
757
|
+
def __eq__(self, object other):
|
|
758
|
+
cdef TemplateAtom other_
|
|
759
|
+
if not isinstance(other, TemplateAtom):
|
|
760
|
+
return NotImplemented
|
|
761
|
+
other_ = other
|
|
762
|
+
return self._state() == other_._state()
|
|
763
|
+
|
|
764
|
+
def __hash__(self):
|
|
765
|
+
return hash(tuple(self._state().values()))
|
|
766
|
+
|
|
767
|
+
def __reduce__(self):
|
|
768
|
+
return functools.partial(type(self), **self._state()), ()
|
|
769
|
+
|
|
650
770
|
def __sizeof__(self):
|
|
651
771
|
assert self._atom is not NULL
|
|
652
772
|
|
|
@@ -708,7 +828,11 @@ cdef class TemplateAtom:
|
|
|
708
828
|
|
|
709
829
|
@property
|
|
710
830
|
def atom_names(self):
|
|
711
|
-
"""`
|
|
831
|
+
"""`tuple` of `str`: The different atom names for this atom.
|
|
832
|
+
|
|
833
|
+
.. versionchanged:: 0.4.1
|
|
834
|
+
Property now returns a `tuple` rather than a `list`.
|
|
835
|
+
|
|
712
836
|
"""
|
|
713
837
|
assert self._atom is not NULL
|
|
714
838
|
|
|
@@ -717,11 +841,15 @@ cdef class TemplateAtom:
|
|
|
717
841
|
|
|
718
842
|
for i in range(self._atom.nameCount):
|
|
719
843
|
l.append(self._atom.name[i].replace(b'_', b'').decode())
|
|
720
|
-
return l
|
|
844
|
+
return tuple(l)
|
|
721
845
|
|
|
722
846
|
@property
|
|
723
847
|
def residue_names(self):
|
|
724
|
-
"""`
|
|
848
|
+
"""`tuple` of `str`: The different residue names for this atom.
|
|
849
|
+
|
|
850
|
+
.. versionchanged:: 0.4.1
|
|
851
|
+
Property now returns a `tuple` rather than a `list`.
|
|
852
|
+
|
|
725
853
|
"""
|
|
726
854
|
assert self._atom is not NULL
|
|
727
855
|
|
|
@@ -730,7 +858,7 @@ cdef class TemplateAtom:
|
|
|
730
858
|
|
|
731
859
|
for i in range(self._atom.resNameCount):
|
|
732
860
|
l.append(self._atom.resName[i].replace(b'_', b'').decode())
|
|
733
|
-
return l
|
|
861
|
+
return tuple(l)
|
|
734
862
|
|
|
735
863
|
@property
|
|
736
864
|
def distance_weight(self):
|
|
@@ -739,9 +867,25 @@ cdef class TemplateAtom:
|
|
|
739
867
|
assert self._atom is not NULL
|
|
740
868
|
return self._atom.distWeight
|
|
741
869
|
|
|
870
|
+
cpdef TemplateAtom copy(self):
|
|
871
|
+
"""Create a copy of this template atom.
|
|
872
|
+
|
|
873
|
+
Returns:
|
|
874
|
+
`~pyjess.TemplateAtom`: A new template atom object with
|
|
875
|
+
identical attributes.
|
|
876
|
+
|
|
877
|
+
.. versionadded:: 0.4.0
|
|
878
|
+
|
|
879
|
+
"""
|
|
880
|
+
return type(self)(**self._state())
|
|
881
|
+
|
|
742
882
|
|
|
743
883
|
cdef class Template:
|
|
744
884
|
"""A template, as a sequence of `TemplateAtom` objects.
|
|
885
|
+
|
|
886
|
+
.. versionadded:: 0.4.0
|
|
887
|
+
Equality, hashing and pickle protocol support.
|
|
888
|
+
|
|
745
889
|
"""
|
|
746
890
|
cdef object owner
|
|
747
891
|
cdef bint owned
|
|
@@ -858,6 +1002,9 @@ cdef class Template:
|
|
|
858
1002
|
residues = { self._tess.atom[i].resSeq for i in range(count) }
|
|
859
1003
|
self._tess.dim = len(residues)
|
|
860
1004
|
|
|
1005
|
+
def __copy__(self):
|
|
1006
|
+
return self.copy()
|
|
1007
|
+
|
|
861
1008
|
def __len__(self):
|
|
862
1009
|
assert self._tpl is not NULL
|
|
863
1010
|
return self._tess.count
|
|
@@ -884,6 +1031,28 @@ cdef class Template:
|
|
|
884
1031
|
atom._atom = self._tess.atom[index_]
|
|
885
1032
|
return atom
|
|
886
1033
|
|
|
1034
|
+
def __eq__(self, object other):
|
|
1035
|
+
cdef Template other_
|
|
1036
|
+
if not isinstance(other, Template):
|
|
1037
|
+
return NotImplemented
|
|
1038
|
+
other_ = other
|
|
1039
|
+
if self.id != other_.id:
|
|
1040
|
+
return False
|
|
1041
|
+
if self.dimension != other_.dimension:
|
|
1042
|
+
return False
|
|
1043
|
+
if len(self) != len(other_):
|
|
1044
|
+
return False
|
|
1045
|
+
return all(x == y for x,y in zip(self, other_))
|
|
1046
|
+
|
|
1047
|
+
def __hash__(self):
|
|
1048
|
+
return hash((
|
|
1049
|
+
self.id,
|
|
1050
|
+
*(hash(x) for x in self)
|
|
1051
|
+
))
|
|
1052
|
+
|
|
1053
|
+
def __reduce__(self):
|
|
1054
|
+
return type(self), (list(self), self.id)
|
|
1055
|
+
|
|
887
1056
|
def __sizeof__(self):
|
|
888
1057
|
assert self._tess is not NULL
|
|
889
1058
|
|
|
@@ -927,6 +1096,12 @@ cdef class Template:
|
|
|
927
1096
|
assert self._tess is not NULL
|
|
928
1097
|
return self._tess.dim
|
|
929
1098
|
|
|
1099
|
+
cpdef Template copy(self):
|
|
1100
|
+
return Template(
|
|
1101
|
+
self,
|
|
1102
|
+
self.id
|
|
1103
|
+
)
|
|
1104
|
+
|
|
930
1105
|
|
|
931
1106
|
cdef class Query:
|
|
932
1107
|
"""A query over templates with a given molecule.
|
|
@@ -1177,10 +1352,14 @@ cdef class Hit:
|
|
|
1177
1352
|
|
|
1178
1353
|
cdef class Jess:
|
|
1179
1354
|
"""A handle to run Jess over a list of templates.
|
|
1355
|
+
|
|
1356
|
+
.. versionadded:: 0.4.0
|
|
1357
|
+
Equality, hashing and pickle protocol support.
|
|
1358
|
+
|
|
1180
1359
|
"""
|
|
1181
1360
|
cdef _Jess* _jess
|
|
1182
1361
|
cdef dict _indices
|
|
1183
|
-
cdef
|
|
1362
|
+
cdef tuple _templates
|
|
1184
1363
|
cdef size_t length
|
|
1185
1364
|
|
|
1186
1365
|
def __cinit__(self):
|
|
@@ -1208,10 +1387,10 @@ cdef class Jess:
|
|
|
1208
1387
|
"""
|
|
1209
1388
|
cdef Template template
|
|
1210
1389
|
cdef _Template* tpl
|
|
1390
|
+
cdef list _templates = []
|
|
1211
1391
|
|
|
1212
1392
|
self._jess = jess.jess.Jess_create()
|
|
1213
1393
|
self._indices = {}
|
|
1214
|
-
self._templates = []
|
|
1215
1394
|
|
|
1216
1395
|
for template in templates:
|
|
1217
1396
|
# NOTE: the Jess storage owns the data, so we make a copy of the
|
|
@@ -1219,9 +1398,27 @@ cdef class Jess:
|
|
|
1219
1398
|
tpl = template._tpl.copy(template._tpl)
|
|
1220
1399
|
jess.jess.Jess_addTemplate(self._jess, tpl)
|
|
1221
1400
|
self._indices[<size_t> tpl] = self.length
|
|
1222
|
-
|
|
1401
|
+
_templates.append(template)
|
|
1223
1402
|
self.length += 1
|
|
1224
1403
|
|
|
1404
|
+
self._templates = tuple(_templates)
|
|
1405
|
+
|
|
1406
|
+
def __copy__(self):
|
|
1407
|
+
return self.copy()
|
|
1408
|
+
|
|
1409
|
+
def __reduce__(self):
|
|
1410
|
+
return type(self), (self._templates,)
|
|
1411
|
+
|
|
1412
|
+
def __eq__(self, object other):
|
|
1413
|
+
cdef Jess other_
|
|
1414
|
+
if not isinstance(other, Jess):
|
|
1415
|
+
return NotImplemented
|
|
1416
|
+
other_ = other
|
|
1417
|
+
return self._templates == other_._templates
|
|
1418
|
+
|
|
1419
|
+
def __hash__(self):
|
|
1420
|
+
return hash((Jess, self._templates))
|
|
1421
|
+
|
|
1225
1422
|
def __len__(self):
|
|
1226
1423
|
return self.length
|
|
1227
1424
|
|
|
@@ -1239,6 +1436,17 @@ cdef class Jess:
|
|
|
1239
1436
|
raise IndexError(index)
|
|
1240
1437
|
return self._templates[index_]
|
|
1241
1438
|
|
|
1439
|
+
cpdef Jess copy(self):
|
|
1440
|
+
"""Create a copy of the `Jess` object.
|
|
1441
|
+
|
|
1442
|
+
Returns:
|
|
1443
|
+
`~pyjess.Jess`: A `Jess` object containing the same templates.
|
|
1444
|
+
|
|
1445
|
+
.. versionadded:: 0.4.0
|
|
1446
|
+
|
|
1447
|
+
"""
|
|
1448
|
+
return type(self)(self._templates)
|
|
1449
|
+
|
|
1242
1450
|
def query(
|
|
1243
1451
|
self,
|
|
1244
1452
|
Molecule molecule,
|
pyjess/tests/test_atom.py
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
|
+
import ctypes
|
|
1
2
|
import unittest
|
|
3
|
+
import pickle
|
|
2
4
|
|
|
3
5
|
from .._jess import Atom
|
|
4
6
|
|
|
@@ -25,6 +27,25 @@ class TestAtom(unittest.TestCase):
|
|
|
25
27
|
self.assertEqual(atom.segment, '')
|
|
26
28
|
self.assertEqual(atom.element, 'C')
|
|
27
29
|
self.assertEqual(atom.charge, 0)
|
|
30
|
+
|
|
31
|
+
def test_init_consistency(self):
|
|
32
|
+
loaded = Atom.loads("ATOM 39 CA PRO A 469 -14.948 2.091 10.228 1.00 27.71 C")
|
|
33
|
+
created = Atom(
|
|
34
|
+
serial=loaded.serial,
|
|
35
|
+
name=loaded.name,
|
|
36
|
+
residue_name=loaded.residue_name,
|
|
37
|
+
chain_id=loaded.chain_id,
|
|
38
|
+
altloc=loaded.altloc,
|
|
39
|
+
insertion_code=loaded.insertion_code,
|
|
40
|
+
residue_number=loaded.residue_number,
|
|
41
|
+
x=loaded.x,
|
|
42
|
+
y=loaded.y,
|
|
43
|
+
z=loaded.z,
|
|
44
|
+
occupancy=loaded.occupancy,
|
|
45
|
+
temperature_factor=loaded.temperature_factor,
|
|
46
|
+
element=loaded.element,
|
|
47
|
+
)
|
|
48
|
+
self.assertEqual(loaded, created)
|
|
28
49
|
|
|
29
50
|
def test_init_invalid_chain_id(self):
|
|
30
51
|
self.assertRaises(ValueError, self._create_atom, chain_id="too long")
|
|
@@ -35,6 +56,22 @@ class TestAtom(unittest.TestCase):
|
|
|
35
56
|
def test_init_invalid_residue_name(self):
|
|
36
57
|
self.assertRaises(ValueError, self._create_atom, residue_name="too long")
|
|
37
58
|
|
|
59
|
+
def test_hash(self):
|
|
60
|
+
a1 = self._create_atom()
|
|
61
|
+
a2 = self._create_atom()
|
|
62
|
+
self.assertEqual(hash(a1), hash(a2))
|
|
63
|
+
self.assertIsNot(a1, a2)
|
|
64
|
+
a3 = self._create_atom(x=1.0)
|
|
65
|
+
self.assertNotEqual(hash(a1), hash(a3))
|
|
66
|
+
|
|
67
|
+
def test_eq(self):
|
|
68
|
+
a1 = self._create_atom()
|
|
69
|
+
a2 = self._create_atom()
|
|
70
|
+
self.assertEqual(a1, a2)
|
|
71
|
+
self.assertIsNot(a1, a2)
|
|
72
|
+
a3 = self._create_atom(x=1.0)
|
|
73
|
+
self.assertNotEqual(a1, a3)
|
|
74
|
+
|
|
38
75
|
def test_repr_roundtrip(self):
|
|
39
76
|
atom = self._create_atom()
|
|
40
77
|
copy = eval(repr(atom))
|
|
@@ -51,4 +88,24 @@ class TestAtom(unittest.TestCase):
|
|
|
51
88
|
self.assertEqual(atom.charge, copy.charge)
|
|
52
89
|
self.assertEqual(atom.x, copy.x)
|
|
53
90
|
self.assertEqual(atom.y, copy.y)
|
|
54
|
-
self.assertEqual(atom.z, copy.z)
|
|
91
|
+
self.assertEqual(atom.z, copy.z)
|
|
92
|
+
self.assertEqual(atom, copy)
|
|
93
|
+
|
|
94
|
+
def test_pickle_roundtrip(self):
|
|
95
|
+
atom = self._create_atom()
|
|
96
|
+
copy = pickle.loads(pickle.dumps(atom))
|
|
97
|
+
self.assertEqual(atom.serial, copy.serial)
|
|
98
|
+
self.assertEqual(atom.altloc, copy.altloc)
|
|
99
|
+
self.assertEqual(atom.name, copy.name)
|
|
100
|
+
self.assertEqual(atom.residue_name, copy.residue_name)
|
|
101
|
+
self.assertEqual(atom.residue_number, copy.residue_number)
|
|
102
|
+
self.assertEqual(atom.element, copy.element)
|
|
103
|
+
self.assertEqual(atom.insertion_code, copy.insertion_code)
|
|
104
|
+
self.assertEqual(atom.chain_id, copy.chain_id)
|
|
105
|
+
self.assertEqual(atom.occupancy, copy.occupancy)
|
|
106
|
+
self.assertEqual(atom.temperature_factor, copy.temperature_factor)
|
|
107
|
+
self.assertEqual(atom.charge, copy.charge)
|
|
108
|
+
self.assertEqual(atom.x, copy.x)
|
|
109
|
+
self.assertEqual(atom.y, copy.y)
|
|
110
|
+
self.assertEqual(atom.z, copy.z)
|
|
111
|
+
self.assertEqual(atom, copy)
|
pyjess/tests/test_jess.py
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import math
|
|
2
2
|
import unittest
|
|
3
3
|
import sys
|
|
4
|
+
import pickle
|
|
4
5
|
|
|
5
6
|
from .._jess import Template, Molecule, Jess
|
|
6
7
|
from .utils import files
|
|
@@ -20,6 +21,59 @@ class TestJess(unittest.TestCase):
|
|
|
20
21
|
hits = jess.query(mol, 2, 2, 4)
|
|
21
22
|
self.assertRaises(StopIteration, next, hits)
|
|
22
23
|
|
|
24
|
+
def test_hash_empty(self):
|
|
25
|
+
j1 = Jess()
|
|
26
|
+
j2 = Jess()
|
|
27
|
+
self.assertEqual(j1, j2)
|
|
28
|
+
self.assertEqual(hash(j1), hash(j2))
|
|
29
|
+
self.assertIsNot(j1, j2)
|
|
30
|
+
|
|
31
|
+
@unittest.skipUnless(files, "importlib.resources not available")
|
|
32
|
+
def test_copy(self):
|
|
33
|
+
with files(data).joinpath("template_01.qry").open() as f:
|
|
34
|
+
template1 = Template.load(f)
|
|
35
|
+
with files(data).joinpath("template_02.qry").open() as f:
|
|
36
|
+
template2 = Template.load(f)
|
|
37
|
+
jess = Jess([template1, template2])
|
|
38
|
+
copy = jess.copy()
|
|
39
|
+
self.assertEqual(jess, copy)
|
|
40
|
+
|
|
41
|
+
@unittest.skipUnless(files, "importlib.resources not available")
|
|
42
|
+
def test_hash(self):
|
|
43
|
+
with files(data).joinpath("template_01.qry").open() as f:
|
|
44
|
+
template1 = Template.load(f)
|
|
45
|
+
with files(data).joinpath("template_02.qry").open() as f:
|
|
46
|
+
template2 = Template.load(f)
|
|
47
|
+
j1 = Jess([template1, template2])
|
|
48
|
+
j2 = Jess([template1, template2])
|
|
49
|
+
self.assertEqual(hash(j1), hash(j2))
|
|
50
|
+
self.assertIsNot(j1, j2)
|
|
51
|
+
j3 = Jess([template1])
|
|
52
|
+
self.assertNotEqual(hash(j1), hash(j3))
|
|
53
|
+
|
|
54
|
+
@unittest.skipUnless(files, "importlib.resources not available")
|
|
55
|
+
def test_eq(self):
|
|
56
|
+
with files(data).joinpath("template_01.qry").open() as f:
|
|
57
|
+
template1 = Template.load(f)
|
|
58
|
+
with files(data).joinpath("template_02.qry").open() as f:
|
|
59
|
+
template2 = Template.load(f)
|
|
60
|
+
j1 = Jess([template1, template2])
|
|
61
|
+
j2 = Jess([template1, template2])
|
|
62
|
+
self.assertEqual(j1, j2)
|
|
63
|
+
self.assertIsNot(j1, j2)
|
|
64
|
+
j3 = Jess([template1])
|
|
65
|
+
self.assertNotEqual(j1, j3)
|
|
66
|
+
|
|
67
|
+
@unittest.skipUnless(files, "importlib.resources not available")
|
|
68
|
+
def test_pickle_roundtrip(self):
|
|
69
|
+
with files(data).joinpath("template_01.qry").open() as f:
|
|
70
|
+
template1 = Template.load(f)
|
|
71
|
+
with files(data).joinpath("template_02.qry").open() as f:
|
|
72
|
+
template2 = Template.load(f)
|
|
73
|
+
jess = Jess([template1, template2])
|
|
74
|
+
copy = pickle.loads(pickle.dumps(jess))
|
|
75
|
+
self.assertEqual(jess, copy)
|
|
76
|
+
|
|
23
77
|
@unittest.skipUnless(sys.implementation.name == "cpython", "only available on CPython")
|
|
24
78
|
@unittest.skipUnless(files, "importlib.resources not available")
|
|
25
79
|
def test_sizeof(self):
|
pyjess/tests/test_molecule.py
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import os
|
|
2
|
+
import pickle
|
|
2
3
|
import unittest
|
|
3
4
|
import tempfile
|
|
4
5
|
import textwrap
|
|
@@ -83,4 +84,58 @@ class TestMolecule(unittest.TestCase):
|
|
|
83
84
|
self.assertEqual(mol2.id, mol.id)
|
|
84
85
|
self.assertEqual(len(mol2), 2)
|
|
85
86
|
self.assertEqual(mol2[0].name, "CA")
|
|
86
|
-
self.assertEqual(mol2[1].name, "C")
|
|
87
|
+
self.assertEqual(mol2[1].name, "C")
|
|
88
|
+
|
|
89
|
+
def test_hash(self):
|
|
90
|
+
atoms = [
|
|
91
|
+
self._create_atom(serial=1, name='N'),
|
|
92
|
+
self._create_atom(serial=2, name='CA'),
|
|
93
|
+
self._create_atom(serial=3, name='C'),
|
|
94
|
+
self._create_atom(serial=4, name='O'),
|
|
95
|
+
]
|
|
96
|
+
mol1 = Molecule(atoms)
|
|
97
|
+
mol2 = Molecule(atoms)
|
|
98
|
+
self.assertEqual(hash(mol1), hash(mol2))
|
|
99
|
+
self.assertIsNot(mol1, mol2)
|
|
100
|
+
mol3 = Molecule(atoms[:-1])
|
|
101
|
+
self.assertNotEqual(hash(mol1), hash(mol3))
|
|
102
|
+
|
|
103
|
+
def test_eq(self):
|
|
104
|
+
atoms = [
|
|
105
|
+
self._create_atom(serial=1, name='N'),
|
|
106
|
+
self._create_atom(serial=2, name='CA'),
|
|
107
|
+
self._create_atom(serial=3, name='C'),
|
|
108
|
+
self._create_atom(serial=4, name='O'),
|
|
109
|
+
]
|
|
110
|
+
mol1 = Molecule(atoms)
|
|
111
|
+
mol2 = Molecule(atoms)
|
|
112
|
+
self.assertEqual(mol1, mol2)
|
|
113
|
+
self.assertIsNot(mol1, mol2)
|
|
114
|
+
mol3 = Molecule(atoms[:-1])
|
|
115
|
+
self.assertNotEqual(mol1, mol3)
|
|
116
|
+
|
|
117
|
+
def test_copy(self):
|
|
118
|
+
atoms = [
|
|
119
|
+
self._create_atom(serial=1, name='N'),
|
|
120
|
+
self._create_atom(serial=2, name='CA'),
|
|
121
|
+
self._create_atom(serial=3, name='C'),
|
|
122
|
+
self._create_atom(serial=4, name='O'),
|
|
123
|
+
]
|
|
124
|
+
mol1 = Molecule(atoms)
|
|
125
|
+
mol2 = mol1.copy()
|
|
126
|
+
self.assertEqual(list(mol1), list(mol2))
|
|
127
|
+
self.assertEqual(mol1.id, mol2.id)
|
|
128
|
+
self.assertEqual(mol1, mol2)
|
|
129
|
+
|
|
130
|
+
def test_pickle_roundtrip(self):
|
|
131
|
+
atoms = [
|
|
132
|
+
self._create_atom(serial=1, name='N'),
|
|
133
|
+
self._create_atom(serial=2, name='CA'),
|
|
134
|
+
self._create_atom(serial=3, name='C'),
|
|
135
|
+
self._create_atom(serial=4, name='O'),
|
|
136
|
+
]
|
|
137
|
+
mol1 = Molecule(atoms)
|
|
138
|
+
mol2 = pickle.loads(pickle.dumps(mol1))
|
|
139
|
+
self.assertEqual(list(mol1), list(mol2))
|
|
140
|
+
self.assertEqual(mol1.id, mol2.id)
|
|
141
|
+
self.assertEqual(mol1, mol2)
|
pyjess/tests/test_template.py
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import os
|
|
2
|
+
import pickle
|
|
2
3
|
import unittest
|
|
3
4
|
import tempfile
|
|
4
5
|
import textwrap
|
|
@@ -29,9 +30,9 @@ class TestTemplate(unittest.TestCase):
|
|
|
29
30
|
template = Template.loads(TEMPLATE)
|
|
30
31
|
self.assertEqual(len(template), 11)
|
|
31
32
|
self.assertEqual(template.dimension, 5)
|
|
32
|
-
self.assertEqual(template[0].residue_names,
|
|
33
|
-
self.assertEqual(template[0].atom_names,
|
|
34
|
-
self.assertEqual(template[1].atom_names,
|
|
33
|
+
self.assertEqual(template[0].residue_names, ("LYS",))
|
|
34
|
+
self.assertEqual(template[0].atom_names, ("NZ",))
|
|
35
|
+
self.assertEqual(template[1].atom_names, ("CG",))
|
|
35
36
|
self.assertEqual(template[2].residue_number, 1132)
|
|
36
37
|
self.assertEqual(template[-1].residue_number, 1150)
|
|
37
38
|
|
|
@@ -41,9 +42,9 @@ class TestTemplate(unittest.TestCase):
|
|
|
41
42
|
f.write(TEMPLATE)
|
|
42
43
|
f.flush()
|
|
43
44
|
template = Template.load(f.name)
|
|
44
|
-
self.assertEqual(template[0].residue_names,
|
|
45
|
-
self.assertEqual(template[0].atom_names,
|
|
46
|
-
self.assertEqual(template[1].atom_names,
|
|
45
|
+
self.assertEqual(template[0].residue_names, ("LYS",))
|
|
46
|
+
self.assertEqual(template[0].atom_names, ("NZ",))
|
|
47
|
+
self.assertEqual(template[1].atom_names, ("CG",))
|
|
47
48
|
self.assertEqual(template[2].residue_number, 1132)
|
|
48
49
|
self.assertEqual(template[-1].residue_number, 1150)
|
|
49
50
|
|
|
@@ -54,9 +55,9 @@ class TestTemplate(unittest.TestCase):
|
|
|
54
55
|
f.flush()
|
|
55
56
|
f.seek(0)
|
|
56
57
|
template = Template.load(f)
|
|
57
|
-
self.assertEqual(template[0].residue_names,
|
|
58
|
-
self.assertEqual(template[0].atom_names,
|
|
59
|
-
self.assertEqual(template[1].atom_names,
|
|
58
|
+
self.assertEqual(template[0].residue_names, ("LYS",))
|
|
59
|
+
self.assertEqual(template[0].atom_names, ("NZ",))
|
|
60
|
+
self.assertEqual(template[1].atom_names, ("CG",))
|
|
60
61
|
self.assertEqual(template[2].residue_number, 1132)
|
|
61
62
|
self.assertEqual(template[-1].residue_number, 1150)
|
|
62
63
|
|
|
@@ -85,3 +86,32 @@ class TestTemplate(unittest.TestCase):
|
|
|
85
86
|
tpl1 = Template.loads(TEMPLATE, id="tpl1")
|
|
86
87
|
tpl2 = tpl1[1:4]
|
|
87
88
|
self.assertEqual(len(tpl2), 3)
|
|
89
|
+
|
|
90
|
+
def test_hash(self):
|
|
91
|
+
tpl1 = Template.loads(TEMPLATE, id="tpl1")
|
|
92
|
+
tpl2 = Template.loads(TEMPLATE, id="tpl1")
|
|
93
|
+
self.assertEqual(tpl1, tpl2)
|
|
94
|
+
self.assertEqual(hash(tpl1), hash(tpl2))
|
|
95
|
+
self.assertIsNot(tpl1, tpl2)
|
|
96
|
+
tpl3 = Template.loads(TEMPLATE, id="tpl3")
|
|
97
|
+
self.assertNotEqual(hash(tpl1), hash(tpl3))
|
|
98
|
+
|
|
99
|
+
def test_eq(self):
|
|
100
|
+
tpl1 = Template.loads(TEMPLATE, id="tpl1")
|
|
101
|
+
tpl2 = Template.loads(TEMPLATE, id="tpl1")
|
|
102
|
+
self.assertEqual(tpl1, tpl2)
|
|
103
|
+
self.assertIsNot(tpl1, tpl2)
|
|
104
|
+
tpl3 = Template.loads(TEMPLATE, id="tpl3")
|
|
105
|
+
self.assertNotEqual(tpl1, tpl3)
|
|
106
|
+
|
|
107
|
+
def test_copy(self):
|
|
108
|
+
tpl1 = Template.loads(TEMPLATE, id="tpl1")
|
|
109
|
+
tpl2 = tpl1.copy()
|
|
110
|
+
self.assertEqual(len(tpl1), len(tpl2))
|
|
111
|
+
self.assertEqual(tpl1, tpl2)
|
|
112
|
+
|
|
113
|
+
def test_pickle_roundtrip(self):
|
|
114
|
+
tpl1 = Template.loads(TEMPLATE, id="tpl1")
|
|
115
|
+
tpl2 = pickle.loads(pickle.dumps(tpl1))
|
|
116
|
+
self.assertEqual(len(tpl1), len(tpl2))
|
|
117
|
+
self.assertEqual(tpl1, tpl2)
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import unittest
|
|
2
2
|
import sys
|
|
3
|
+
import pickle
|
|
3
4
|
|
|
4
5
|
from .._jess import TemplateAtom
|
|
5
6
|
|
|
@@ -9,8 +10,8 @@ class TestTemplateAtom(unittest.TestCase):
|
|
|
9
10
|
def test_load(self):
|
|
10
11
|
atom = TemplateAtom.loads("ATOM 1 NE ARG A1136 3.953 0.597 -1.721 K")
|
|
11
12
|
self.assertEqual(atom.match_mode, 1)
|
|
12
|
-
self.assertEqual(atom.atom_names,
|
|
13
|
-
self.assertEqual(atom.residue_names,
|
|
13
|
+
self.assertEqual(atom.atom_names, ("NE",))
|
|
14
|
+
self.assertEqual(atom.residue_names, ("ARG", "LYS",))
|
|
14
15
|
self.assertEqual(atom.chain_id, "A")
|
|
15
16
|
self.assertEqual(atom.residue_number, 1136)
|
|
16
17
|
self.assertEqual(atom.x, 3.953)
|
|
@@ -31,6 +32,22 @@ class TestTemplateAtom(unittest.TestCase):
|
|
|
31
32
|
default.update(kwargs)
|
|
32
33
|
return TemplateAtom(**default)
|
|
33
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
|
+
|
|
34
51
|
@unittest.skipUnless(sys.implementation.name == "cpython", "only available on CPython")
|
|
35
52
|
def test_sizeof(self):
|
|
36
53
|
atom = self._create_atom()
|
|
@@ -43,8 +60,33 @@ class TestTemplateAtom(unittest.TestCase):
|
|
|
43
60
|
def test_init_invalid_residue_name(self):
|
|
44
61
|
self.assertRaises(ValueError, self._create_atom, residue_names=["something"])
|
|
45
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
|
+
|
|
46
80
|
def test_repr_roundtrip(self):
|
|
47
81
|
atom = self._create_atom()
|
|
48
82
|
copy = eval(repr(atom))
|
|
49
83
|
for attribute in ("atom_names", "residue_names", "chain_id", "x", "y", "z", "match_mode"):
|
|
50
|
-
self.assertEqual(getattr(copy, attribute), getattr(atom, attribute))
|
|
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)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: pyjess
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.4.1
|
|
4
4
|
Summary: Cython bindings and Python interface to JESS, a 3D template matching software.
|
|
5
5
|
Keywords: bioinformatics,structure,template,matching
|
|
6
6
|
Author-Email: Martin Larralde <martin.larralde@embl.de>
|
|
@@ -25,7 +25,7 @@ License: MIT License
|
|
|
25
25
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
26
26
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
27
27
|
SOFTWARE.
|
|
28
|
-
Classifier: Development Status ::
|
|
28
|
+
Classifier: Development Status :: 4 - Beta
|
|
29
29
|
Classifier: Intended Audience :: Developers
|
|
30
30
|
Classifier: Intended Audience :: Science/Research
|
|
31
31
|
Classifier: License :: OSI Approved :: MIT License
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
pyjess/.gitignore,sha256=u14v4OOy8U50Kp9SUKU8DupCG-mQIuel47gdbNDmAwg,21
|
|
2
2
|
pyjess/__init__.py,sha256=Xe9GBQUBm9ik-ty5tcE3UQ9Ip1p-C_IGvTPuGULolng,766
|
|
3
|
-
pyjess/_jess.cp311-win_amd64.pyd,sha256=
|
|
4
|
-
pyjess/_jess.pyi,sha256=
|
|
5
|
-
pyjess/_jess.pyx,sha256=
|
|
3
|
+
pyjess/_jess.cp311-win_amd64.pyd,sha256=As_iMvp8hVMJ3P4haBpqHKIDko7eibCIMXXH7zoYhwA,286208
|
|
4
|
+
pyjess/_jess.pyi,sha256=sdkkFpbgmc56Rg7dxjXIHxdcGbhAxs0ON5dsqVd-Y98,7122
|
|
5
|
+
pyjess/_jess.pyx,sha256=RHJp808Kj6d7T6W_7Ykx5Dh-jT8HYZLKDwer5kmLo1s,48799
|
|
6
6
|
pyjess/CMakeLists.txt,sha256=H9eXbrFcGF2OLP8muQctb4cOb27Qp2uZj5KRjoDAROg,36
|
|
7
7
|
pyjess/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
8
8
|
pyjess/tests/__init__.py,sha256=h83kBzYKH_i1InkM8mOA23zE3PBaB9lrNDCuhC8LOl4,544
|
|
@@ -13,13 +13,13 @@ pyjess/tests/data/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU
|
|
|
13
13
|
pyjess/tests/data/pdb1lnb.pdb,sha256=F8A6OdRly5c-pxsDw1LjTFINI75r1HaKaYB_eXv1QuM,273388
|
|
14
14
|
pyjess/tests/data/template_01.qry,sha256=izCIhUUTEk-IvQowhSVLiJaCAhpPbyvrfyoR4Q6-Pm0,616
|
|
15
15
|
pyjess/tests/data/template_02.qry,sha256=5IYRTqsvO_roB2INLwfFDEaWJW9VRcXdbK4oe8VKMxE,618
|
|
16
|
-
pyjess/tests/test_atom.py,sha256=
|
|
17
|
-
pyjess/tests/test_jess.py,sha256=
|
|
18
|
-
pyjess/tests/test_molecule.py,sha256=
|
|
19
|
-
pyjess/tests/test_template.py,sha256=
|
|
20
|
-
pyjess/tests/test_template_atom.py,sha256=
|
|
16
|
+
pyjess/tests/test_atom.py,sha256=clLN9IVuivadztGtagDhdPBDGoMkUgs41lEWuTCCmFA,4741
|
|
17
|
+
pyjess/tests/test_jess.py,sha256=kBmsFAl7tmCAFamk3JqGAwttI6SJiAl3aLJUO-9FmOA,9976
|
|
18
|
+
pyjess/tests/test_molecule.py,sha256=9k6uiTeOWc5NiO7epyxY9lm_GgksPb7-o-ZcNFNxutw,5452
|
|
19
|
+
pyjess/tests/test_template.py,sha256=AIN-ba5-YTnGdT9SGPU4q45AZ03QnPE769WyItSpoPs,4657
|
|
20
|
+
pyjess/tests/test_template_atom.py,sha256=oK8cfKe4_k3Pm1PqoTTxTzAoeUVLiCFsg6QmiTQ-RCQ,3496
|
|
21
21
|
pyjess/tests/utils.py,sha256=Z7rUPC-D8dZlRfHAnLaXHUg6M10D3zFvNiwDvvHA3xc,202
|
|
22
|
-
pyjess-0.
|
|
23
|
-
pyjess-0.
|
|
24
|
-
pyjess-0.
|
|
25
|
-
pyjess-0.
|
|
22
|
+
pyjess-0.4.1.dist-info/METADATA,sha256=iHTTiJz29i7uRreAEeB_ow4-DArxSGb5Nz2Y9N4RblQ,10785
|
|
23
|
+
pyjess-0.4.1.dist-info/WHEEL,sha256=kXCl1J14PkmxQKXf5U_5vxmme_OmC3Ydcral7u0yA3M,106
|
|
24
|
+
pyjess-0.4.1.dist-info/licenses/COPYING,sha256=WpSMpnu8fCvYt4QNIp0SCsWgeXIRr1KEXBfqiPwrPZ4,1119
|
|
25
|
+
pyjess-0.4.1.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|