pyjess 0.3.3__cp39-cp39-win_amd64.whl → 0.4.0__cp39-cp39-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.cp39-win_amd64.pyd +0 -0
- pyjess/_jess.pyi +27 -1
- pyjess/_jess.pyx +241 -43
- pyjess/tests/test_atom.py +49 -1
- pyjess/tests/test_jess.py +21 -0
- pyjess/tests/test_molecule.py +40 -1
- pyjess/tests/test_template.py +13 -0
- pyjess/tests/test_template_atom.py +27 -1
- {pyjess-0.3.3.dist-info → pyjess-0.4.0.dist-info}/METADATA +2 -2
- {pyjess-0.3.3.dist-info → pyjess-0.4.0.dist-info}/RECORD +12 -12
- {pyjess-0.3.3.dist-info → pyjess-0.4.0.dist-info}/WHEEL +0 -0
- {pyjess-0.3.3.dist-info → pyjess-0.4.0.dist-info}/licenses/COPYING +0 -0
pyjess/_jess.cp39-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
|
|
@@ -123,6 +139,7 @@ class TemplateAtom:
|
|
|
123
139
|
def residue_names(self) -> List[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
|
|
|
@@ -739,9 +859,25 @@ cdef class TemplateAtom:
|
|
|
739
859
|
assert self._atom is not NULL
|
|
740
860
|
return self._atom.distWeight
|
|
741
861
|
|
|
862
|
+
cpdef TemplateAtom copy(self):
|
|
863
|
+
"""Create a copy of this template atom.
|
|
864
|
+
|
|
865
|
+
Returns:
|
|
866
|
+
`~pyjess.TemplateAtom`: A new template atom object with
|
|
867
|
+
identical attributes.
|
|
868
|
+
|
|
869
|
+
.. versionadded:: 0.4.0
|
|
870
|
+
|
|
871
|
+
"""
|
|
872
|
+
return type(self)(**self._state())
|
|
873
|
+
|
|
742
874
|
|
|
743
875
|
cdef class Template:
|
|
744
876
|
"""A template, as a sequence of `TemplateAtom` objects.
|
|
877
|
+
|
|
878
|
+
.. versionadded:: 0.4.0
|
|
879
|
+
Equality, hashing and pickle protocol support.
|
|
880
|
+
|
|
745
881
|
"""
|
|
746
882
|
cdef object owner
|
|
747
883
|
cdef bint owned
|
|
@@ -858,6 +994,9 @@ cdef class Template:
|
|
|
858
994
|
residues = { self._tess.atom[i].resSeq for i in range(count) }
|
|
859
995
|
self._tess.dim = len(residues)
|
|
860
996
|
|
|
997
|
+
def __copy__(self):
|
|
998
|
+
return self.copy()
|
|
999
|
+
|
|
861
1000
|
def __len__(self):
|
|
862
1001
|
assert self._tpl is not NULL
|
|
863
1002
|
return self._tess.count
|
|
@@ -884,6 +1023,28 @@ cdef class Template:
|
|
|
884
1023
|
atom._atom = self._tess.atom[index_]
|
|
885
1024
|
return atom
|
|
886
1025
|
|
|
1026
|
+
def __eq__(self, object other):
|
|
1027
|
+
cdef Template other_
|
|
1028
|
+
if not isinstance(other, Template):
|
|
1029
|
+
return NotImplemented
|
|
1030
|
+
other_ = other
|
|
1031
|
+
if self.id != other_.id:
|
|
1032
|
+
return False
|
|
1033
|
+
if self.dimension != other_.dimension:
|
|
1034
|
+
return False
|
|
1035
|
+
if len(self) != len(other_):
|
|
1036
|
+
return False
|
|
1037
|
+
return all(x == y for x,y in zip(self, other_))
|
|
1038
|
+
|
|
1039
|
+
def __hash__(self):
|
|
1040
|
+
return hash(
|
|
1041
|
+
self.id,
|
|
1042
|
+
*(hash(x) for x in self)
|
|
1043
|
+
)
|
|
1044
|
+
|
|
1045
|
+
def __reduce__(self):
|
|
1046
|
+
return type(self), (list(self), self.id)
|
|
1047
|
+
|
|
887
1048
|
def __sizeof__(self):
|
|
888
1049
|
assert self._tess is not NULL
|
|
889
1050
|
|
|
@@ -927,6 +1088,12 @@ cdef class Template:
|
|
|
927
1088
|
assert self._tess is not NULL
|
|
928
1089
|
return self._tess.dim
|
|
929
1090
|
|
|
1091
|
+
cpdef Template copy(self):
|
|
1092
|
+
return Template(
|
|
1093
|
+
self,
|
|
1094
|
+
self.id
|
|
1095
|
+
)
|
|
1096
|
+
|
|
930
1097
|
|
|
931
1098
|
cdef class Query:
|
|
932
1099
|
"""A query over templates with a given molecule.
|
|
@@ -1177,6 +1344,10 @@ cdef class Hit:
|
|
|
1177
1344
|
|
|
1178
1345
|
cdef class Jess:
|
|
1179
1346
|
"""A handle to run Jess over a list of templates.
|
|
1347
|
+
|
|
1348
|
+
.. versionadded:: 0.4.0
|
|
1349
|
+
Equality, hashing and pickle protocol support.
|
|
1350
|
+
|
|
1180
1351
|
"""
|
|
1181
1352
|
cdef _Jess* _jess
|
|
1182
1353
|
cdef dict _indices
|
|
@@ -1222,6 +1393,22 @@ cdef class Jess:
|
|
|
1222
1393
|
self._templates.append(template)
|
|
1223
1394
|
self.length += 1
|
|
1224
1395
|
|
|
1396
|
+
def __copy__(self):
|
|
1397
|
+
return self.copy()
|
|
1398
|
+
|
|
1399
|
+
def __reduce__(self):
|
|
1400
|
+
return type(self), (self._templates,)
|
|
1401
|
+
|
|
1402
|
+
def __eq__(self, object other):
|
|
1403
|
+
cdef Jess other_
|
|
1404
|
+
if not isinstance(other, Jess):
|
|
1405
|
+
return NotImplemented
|
|
1406
|
+
other_ = other
|
|
1407
|
+
return self._templates == other_._templates
|
|
1408
|
+
|
|
1409
|
+
def __hash__(self):
|
|
1410
|
+
return hash(tuple(hash(t) for t in self._templates))
|
|
1411
|
+
|
|
1225
1412
|
def __len__(self):
|
|
1226
1413
|
return self.length
|
|
1227
1414
|
|
|
@@ -1239,6 +1426,17 @@ cdef class Jess:
|
|
|
1239
1426
|
raise IndexError(index)
|
|
1240
1427
|
return self._templates[index_]
|
|
1241
1428
|
|
|
1429
|
+
cpdef Jess copy(self):
|
|
1430
|
+
"""Create a copy of the `Jess` object.
|
|
1431
|
+
|
|
1432
|
+
Returns:
|
|
1433
|
+
`~pyjess.Jess`: A `Jess` object containing the same templates.
|
|
1434
|
+
|
|
1435
|
+
.. versionadded:: 0.4.0
|
|
1436
|
+
|
|
1437
|
+
"""
|
|
1438
|
+
return type(self)(self._templates)
|
|
1439
|
+
|
|
1242
1440
|
def query(
|
|
1243
1441
|
self,
|
|
1244
1442
|
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,13 @@ 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(a1, a2)
|
|
63
|
+
self.assertEqual(hash(a1), hash(a2))
|
|
64
|
+
self.assertIsNot(a1, a2)
|
|
65
|
+
|
|
38
66
|
def test_repr_roundtrip(self):
|
|
39
67
|
atom = self._create_atom()
|
|
40
68
|
copy = eval(repr(atom))
|
|
@@ -51,4 +79,24 @@ class TestAtom(unittest.TestCase):
|
|
|
51
79
|
self.assertEqual(atom.charge, copy.charge)
|
|
52
80
|
self.assertEqual(atom.x, copy.x)
|
|
53
81
|
self.assertEqual(atom.y, copy.y)
|
|
54
|
-
self.assertEqual(atom.z, copy.z)
|
|
82
|
+
self.assertEqual(atom.z, copy.z)
|
|
83
|
+
self.assertEqual(atom, copy)
|
|
84
|
+
|
|
85
|
+
def test_pickle_roundtrip(self):
|
|
86
|
+
atom = self._create_atom()
|
|
87
|
+
copy = pickle.loads(pickle.dumps(atom))
|
|
88
|
+
self.assertEqual(atom.serial, copy.serial)
|
|
89
|
+
self.assertEqual(atom.altloc, copy.altloc)
|
|
90
|
+
self.assertEqual(atom.name, copy.name)
|
|
91
|
+
self.assertEqual(atom.residue_name, copy.residue_name)
|
|
92
|
+
self.assertEqual(atom.residue_number, copy.residue_number)
|
|
93
|
+
self.assertEqual(atom.element, copy.element)
|
|
94
|
+
self.assertEqual(atom.insertion_code, copy.insertion_code)
|
|
95
|
+
self.assertEqual(atom.chain_id, copy.chain_id)
|
|
96
|
+
self.assertEqual(atom.occupancy, copy.occupancy)
|
|
97
|
+
self.assertEqual(atom.temperature_factor, copy.temperature_factor)
|
|
98
|
+
self.assertEqual(atom.charge, copy.charge)
|
|
99
|
+
self.assertEqual(atom.x, copy.x)
|
|
100
|
+
self.assertEqual(atom.y, copy.y)
|
|
101
|
+
self.assertEqual(atom.z, copy.z)
|
|
102
|
+
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,26 @@ class TestJess(unittest.TestCase):
|
|
|
20
21
|
hits = jess.query(mol, 2, 2, 4)
|
|
21
22
|
self.assertRaises(StopIteration, next, hits)
|
|
22
23
|
|
|
24
|
+
@unittest.skipUnless(files, "importlib.resources not available")
|
|
25
|
+
def test_copy(self):
|
|
26
|
+
with files(data).joinpath("template_01.qry").open() as f:
|
|
27
|
+
template1 = Template.load(f)
|
|
28
|
+
with files(data).joinpath("template_02.qry").open() as f:
|
|
29
|
+
template2 = Template.load(f)
|
|
30
|
+
jess = Jess([template1, template2])
|
|
31
|
+
copy = jess.copy()
|
|
32
|
+
self.assertEqual(jess, copy)
|
|
33
|
+
|
|
34
|
+
@unittest.skipUnless(files, "importlib.resources not available")
|
|
35
|
+
def test_pickle_roundtrip(self):
|
|
36
|
+
with files(data).joinpath("template_01.qry").open() as f:
|
|
37
|
+
template1 = Template.load(f)
|
|
38
|
+
with files(data).joinpath("template_02.qry").open() as f:
|
|
39
|
+
template2 = Template.load(f)
|
|
40
|
+
jess = Jess([template1, template2])
|
|
41
|
+
copy = pickle.loads(pickle.dumps(jess))
|
|
42
|
+
self.assertEqual(jess, copy)
|
|
43
|
+
|
|
23
44
|
@unittest.skipUnless(sys.implementation.name == "cpython", "only available on CPython")
|
|
24
45
|
@unittest.skipUnless(files, "importlib.resources not available")
|
|
25
46
|
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,42 @@ 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.assertEqual(mol1, mol2)
|
|
100
|
+
|
|
101
|
+
def test_copy(self):
|
|
102
|
+
atoms = [
|
|
103
|
+
self._create_atom(serial=1, name='N'),
|
|
104
|
+
self._create_atom(serial=2, name='CA'),
|
|
105
|
+
self._create_atom(serial=3, name='C'),
|
|
106
|
+
self._create_atom(serial=4, name='O'),
|
|
107
|
+
]
|
|
108
|
+
mol1 = Molecule(atoms)
|
|
109
|
+
mol2 = mol1.copy()
|
|
110
|
+
self.assertEqual(list(mol1), list(mol2))
|
|
111
|
+
self.assertEqual(mol1.id, mol2.id)
|
|
112
|
+
self.assertEqual(mol1, mol2)
|
|
113
|
+
|
|
114
|
+
def test_pickle_roundtrip(self):
|
|
115
|
+
atoms = [
|
|
116
|
+
self._create_atom(serial=1, name='N'),
|
|
117
|
+
self._create_atom(serial=2, name='CA'),
|
|
118
|
+
self._create_atom(serial=3, name='C'),
|
|
119
|
+
self._create_atom(serial=4, name='O'),
|
|
120
|
+
]
|
|
121
|
+
mol1 = Molecule(atoms)
|
|
122
|
+
mol2 = pickle.loads(pickle.dumps(mol1))
|
|
123
|
+
self.assertEqual(list(mol1), list(mol2))
|
|
124
|
+
self.assertEqual(mol1.id, mol2.id)
|
|
125
|
+
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
|
|
@@ -85,3 +86,15 @@ 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_copy(self):
|
|
91
|
+
tpl1 = Template.loads(TEMPLATE, id="tpl1")
|
|
92
|
+
tpl2 = tpl1.copy()
|
|
93
|
+
self.assertEqual(len(tpl1), len(tpl2))
|
|
94
|
+
self.assertEqual(tpl1, tpl2)
|
|
95
|
+
|
|
96
|
+
def test_pickle_roundtrip(self):
|
|
97
|
+
tpl1 = Template.loads(TEMPLATE, id="tpl1")
|
|
98
|
+
tpl2 = pickle.loads(pickle.dumps(tpl1))
|
|
99
|
+
self.assertEqual(len(tpl1), len(tpl2))
|
|
100
|
+
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
|
|
|
@@ -43,8 +44,33 @@ class TestTemplateAtom(unittest.TestCase):
|
|
|
43
44
|
def test_init_invalid_residue_name(self):
|
|
44
45
|
self.assertRaises(ValueError, self._create_atom, residue_names=["something"])
|
|
45
46
|
|
|
47
|
+
def test_init_consistency(self):
|
|
48
|
+
loaded = TemplateAtom.loads("ATOM 1 NE ARG A1136 3.953 0.597 -1.721 K")
|
|
49
|
+
created = TemplateAtom(
|
|
50
|
+
chain_id=loaded.chain_id,
|
|
51
|
+
residue_number=loaded.residue_number,
|
|
52
|
+
x=loaded.x,
|
|
53
|
+
y=loaded.y,
|
|
54
|
+
z=loaded.z,
|
|
55
|
+
residue_names=loaded.residue_names,
|
|
56
|
+
atom_names=loaded.atom_names,
|
|
57
|
+
distance_weight=loaded.distance_weight,
|
|
58
|
+
match_mode=loaded.match_mode
|
|
59
|
+
)
|
|
60
|
+
for attribute in ("atom_names", "residue_names", "chain_id", "x", "y", "z", "match_mode"):
|
|
61
|
+
self.assertEqual(getattr(loaded, attribute), getattr(created, attribute))
|
|
62
|
+
self.assertEqual(loaded, created)
|
|
63
|
+
|
|
46
64
|
def test_repr_roundtrip(self):
|
|
47
65
|
atom = self._create_atom()
|
|
48
66
|
copy = eval(repr(atom))
|
|
49
67
|
for attribute in ("atom_names", "residue_names", "chain_id", "x", "y", "z", "match_mode"):
|
|
50
|
-
self.assertEqual(getattr(copy, attribute), getattr(atom, attribute))
|
|
68
|
+
self.assertEqual(getattr(copy, attribute), getattr(atom, attribute))
|
|
69
|
+
self.assertEqual(atom, copy)
|
|
70
|
+
|
|
71
|
+
def test_pickle_roundtrip(self):
|
|
72
|
+
atom = self._create_atom()
|
|
73
|
+
copy = pickle.loads(pickle.dumps(atom))
|
|
74
|
+
for attribute in ("atom_names", "residue_names", "chain_id", "x", "y", "z", "match_mode"):
|
|
75
|
+
self.assertEqual(getattr(copy, attribute), getattr(atom, attribute))
|
|
76
|
+
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.0
|
|
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.cp39-win_amd64.pyd,sha256=
|
|
4
|
-
pyjess/_jess.pyi,sha256=
|
|
5
|
-
pyjess/_jess.pyx,sha256=
|
|
3
|
+
pyjess/_jess.cp39-win_amd64.pyd,sha256=BrnhIWErWT6vTBf_Agb0hUvNkZamk32sGmI5A6BbTBo,288768
|
|
4
|
+
pyjess/_jess.pyi,sha256=DD1ZMKSbgCBKPiTVZc8ojmkYJcgjSESqyMIHIqL1exg,7110
|
|
5
|
+
pyjess/_jess.pyx,sha256=pU8KKFLyRHGwieDmG9AZNhCuctGCti3BkrOW-NyW-gM,48525
|
|
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=UJhb9VJR4Hm6g0eIlkypnnUf3jcGC6csbGuTL7VGF30,4449
|
|
17
|
+
pyjess/tests/test_jess.py,sha256=XItj6F0XBe_cmsRmgGnyu81wah6bVdfFXEcmO2EZRg0,8686
|
|
18
|
+
pyjess/tests/test_molecule.py,sha256=lT9ZdW1aWrrQR95iRBET3NJYIKlNT3IiRMadD_RUSgs,4879
|
|
19
|
+
pyjess/tests/test_template.py,sha256=LJGKHc7BzDdl42nHVF0-6m92alBogWXQneeE0tkobQQ,3986
|
|
20
|
+
pyjess/tests/test_template_atom.py,sha256=W6Iruh7f4gNiohkTHN1hcjDBByWiYTlyXcGmD_I-Pdw,2992
|
|
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.0.dist-info/METADATA,sha256=vaDoU5JzpxXjRTl-M43Stw7evHX75QHWTexO_TF7_DE,10785
|
|
23
|
+
pyjess-0.4.0.dist-info/WHEEL,sha256=s-IzttuPuPJp8zDv-jm-zGvTOCxdFCvjX9dIQ9zqnM8,104
|
|
24
|
+
pyjess-0.4.0.dist-info/licenses/COPYING,sha256=WpSMpnu8fCvYt4QNIp0SCsWgeXIRr1KEXBfqiPwrPZ4,1119
|
|
25
|
+
pyjess-0.4.0.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|