pyjess 0.6.0__pp39-pypy39_pp73-win_amd64.whl → 0.7.0__pp39-pypy39_pp73-win_amd64.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- pyjess/__main__.py +4 -0
- pyjess/_jess.pyi +52 -9
- pyjess/_jess.pypy39-pp73-win_amd64.pyd +0 -0
- pyjess/_jess.pyx +830 -101
- pyjess/cli.py +281 -0
- pyjess/tests/__init__.py +2 -0
- pyjess/tests/data/1AMY.cif +6259 -0
- pyjess/tests/data/1sur.qry +26 -0
- pyjess/tests/data/4.1.2.tpl +23 -0
- pyjess/tests/data/5ayx.EF.pdb +63 -0
- pyjess/tests/test_doctest.py +78 -0
- pyjess/tests/test_hit.py +26 -2
- pyjess/tests/test_jess.py +62 -1
- pyjess/tests/test_molecule.py +146 -0
- pyjess/tests/test_template.py +10 -1
- {pyjess-0.6.0.dist-info → pyjess-0.7.0.dist-info}/METADATA +59 -16
- pyjess-0.7.0.dist-info/RECORD +34 -0
- pyjess-0.7.0.dist-info/entry_points.txt +3 -0
- pyjess-0.6.0.dist-info/RECORD +0 -26
- {pyjess-0.6.0.dist-info → pyjess-0.7.0.dist-info}/WHEEL +0 -0
- {pyjess-0.6.0.dist-info → pyjess-0.7.0.dist-info}/licenses/COPYING +0 -0
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
REMARK TEMPLATE
|
|
2
|
+
REMARK CLUSTER 1_1_1
|
|
3
|
+
REMARK REPRESENTING 1 CATALYTIC SITES
|
|
4
|
+
REMARK ID 1sur_AA204-AA208-A204-A208
|
|
5
|
+
REMARK MCSA_ID 279
|
|
6
|
+
REMARK PDB_ID 1sur
|
|
7
|
+
REMARK UNIPROT_ID P17854
|
|
8
|
+
REMARK EC 1.8.4.8
|
|
9
|
+
REMARK ENZYME PAPS REDUCTASE
|
|
10
|
+
REMARK EXPERIMENTAL_METHOD X-ray diffraction
|
|
11
|
+
REMARK RESOLUTION 2.0
|
|
12
|
+
REMARK ORGANISM_NAME Escherichia coli
|
|
13
|
+
REMARK ORGANISM_ID 562
|
|
14
|
+
ATOM 0 NE1ZTRPAA 204 38.872 1.684 110.358 W 0.00
|
|
15
|
+
ATOM 0 CZ2ZTRPAA 204 41.345 1.476 110.794 W 0.00
|
|
16
|
+
ATOM 0 CH2ZTRPAA 204 42.567 1.626 110.193 W 0.00
|
|
17
|
+
ATOM 3 CE1ZTYRAA 208 40.509 -1.903 99.734 Y 0.00
|
|
18
|
+
ATOM 3 CZ ZTYRAA 208 41.503 -1.926 98.771 Y 0.00
|
|
19
|
+
ATOM 1 OH ZTYRAA 208 41.320 -2.643 97.607 Y 0.00
|
|
20
|
+
ATOM 0 NE1ZTRP A 204 43.868 1.684 54.342 W 0.00
|
|
21
|
+
ATOM 0 CZ2ZTRP A 204 41.395 1.476 53.906 W 0.00
|
|
22
|
+
ATOM 0 CH2ZTRP A 204 40.173 1.626 54.507 W 0.00
|
|
23
|
+
ATOM 3 CE1ZTYR A 208 42.231 -1.903 64.966 Y 0.00
|
|
24
|
+
ATOM 3 CZ ZTYR A 208 41.237 -1.926 65.929 Y 0.00
|
|
25
|
+
ATOM 1 OH ZTYR A 208 41.420 -2.643 67.093 Y 0.00
|
|
26
|
+
END
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
REMARK TEMPLATE
|
|
2
|
+
REMARK CLUSTER 4_1_2
|
|
3
|
+
REMARK REPRESENTING 10 CATALYTIC SITES
|
|
4
|
+
REMARK ID 2om2_A48-A43-A200-A204-A178
|
|
5
|
+
REMARK MCSA_ID 533
|
|
6
|
+
REMARK PDB_ID 2om2
|
|
7
|
+
REMARK UNIPROT_ID P63096
|
|
8
|
+
REMARK EC None
|
|
9
|
+
REMARK ENZYME Guanine nucleotide-binding protein G(i), alpha-1 subunit, Regulator of G-protein signalling 14 GoLoco motif peptide
|
|
10
|
+
REMARK EXPERIMENTAL_METHOD X-ray diffraction
|
|
11
|
+
REMARK RESOLUTION 2.2
|
|
12
|
+
REMARK ORGANISM_NAME Homo sapiens
|
|
13
|
+
REMARK ORGANISM_ID 9606
|
|
14
|
+
ATOM 3 CA ZTHR A 48 33.911 -23.654 9.552 T 0.53
|
|
15
|
+
ATOM 3 CB ZTHR A 48 34.739 -23.239 8.310 T 0.53
|
|
16
|
+
ATOM 1 OG1ZTHR A 48 36.129 -23.451 8.587 T 0.53
|
|
17
|
+
ATOM 3 CD ZGLU A 43 42.537 -29.462 7.690 E 2.08
|
|
18
|
+
ATOM 3 OE1ZGLU A 43 42.721 -29.948 8.832 E 2.08
|
|
19
|
+
ATOM 3 OE2ZGLU A 43 42.492 -28.227 7.487 E 2.08
|
|
20
|
+
ATOM 0 CZ ZARG A 178 43.760 -26.926 10.370 R 2.35
|
|
21
|
+
ATOM 3 NH1ZARG A 178 42.887 -26.457 9.483 R 2.35
|
|
22
|
+
ATOM 3 NH2ZARG A 178 44.119 -28.202 10.324 R 2.35
|
|
23
|
+
END
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
HEADER TRANSFERASE 14-SEP-15 XXXX
|
|
2
|
+
TITLE CRYSTAL STRUCTURE OF HUMAN QUINOLINATE PHOSPHORIBOSYLTRANSFERASE
|
|
3
|
+
KEYWDS QUINOLINATE PHOSPHORIBOSYLTRANSFERASE, NAD BIOSYNTHESIS, NADC,
|
|
4
|
+
KEYWDS 2 TRANSFERASE
|
|
5
|
+
EXPDTA X-RAY DIFFRACTION
|
|
6
|
+
ATOM 8512 CA GLU E 25 11.770 12.101 -30.191 1.00 63.41 C
|
|
7
|
+
ATOM 8513 C GLU E 25 10.568 12.472 -31.076 1.00 64.47 C
|
|
8
|
+
ATOM 8514 O GLU E 25 10.268 13.659 -31.267 1.00 66.51 O
|
|
9
|
+
ATOM 8515 CB GLU E 25 12.924 11.548 -31.040 1.00 54.61 C
|
|
10
|
+
ATOM 8516 CG GLU E 25 13.586 12.566 -31.990 1.00 63.15 C
|
|
11
|
+
ATOM 8517 CD GLU E 25 14.447 11.902 -33.089 1.00 67.48 C
|
|
12
|
+
ATOM 8518 OE1 GLU E 25 14.041 10.820 -33.594 1.00 62.27 O
|
|
13
|
+
ATOM 8519 OE2 GLU E 25 15.524 12.460 -33.441 1.00 60.34 O
|
|
14
|
+
ATOM 9342 N THR E 141 25.198 6.504 -40.031 1.00 49.91 N
|
|
15
|
+
ATOM 9343 CA THR E 141 24.509 7.667 -39.509 1.00 44.30 C
|
|
16
|
+
ATOM 9344 C THR E 141 24.749 7.734 -38.010 1.00 45.10 C
|
|
17
|
+
ATOM 9345 O THR E 141 24.587 6.721 -37.320 1.00 49.53 O
|
|
18
|
+
ATOM 9346 CB THR E 141 23.029 7.628 -39.780 1.00 40.72 C
|
|
19
|
+
ATOM 9347 OG1 THR E 141 22.810 7.411 -41.175 1.00 41.17 O
|
|
20
|
+
ATOM 9348 CG2 THR E 141 22.434 8.970 -39.391 1.00 45.90 C
|
|
21
|
+
ATOM 9371 N ARG E 145 23.925 3.473 -35.427 1.00 47.01 N
|
|
22
|
+
ATOM 9372 CA ARG E 145 24.909 2.456 -35.770 1.00 50.52 C
|
|
23
|
+
ATOM 9373 C ARG E 145 24.310 1.065 -35.674 1.00 48.71 C
|
|
24
|
+
ATOM 9374 O ARG E 145 24.441 0.255 -36.598 1.00 51.91 O
|
|
25
|
+
ATOM 9375 CB ARG E 145 26.130 2.594 -34.858 1.00 58.30 C
|
|
26
|
+
ATOM 9376 CG ARG E 145 27.168 1.485 -34.964 1.00 56.80 C
|
|
27
|
+
ATOM 9377 CD ARG E 145 28.472 1.971 -34.388 1.00 64.04 C
|
|
28
|
+
ATOM 9378 NE ARG E 145 29.055 3.032 -35.219 1.00 79.49 N
|
|
29
|
+
ATOM 9379 CZ ARG E 145 30.083 3.803 -34.855 1.00 77.12 C
|
|
30
|
+
ATOM 9380 NH1 ARG E 145 30.556 4.728 -35.687 1.00 73.39 N
|
|
31
|
+
ATOM 9381 NH2 ARG E 145 30.640 3.659 -33.657 1.00 73.96 N
|
|
32
|
+
TER 10377 GLU E 289
|
|
33
|
+
ATOM 10557 N GLU F 25 28.218 6.773 -28.434 1.00 49.27 N
|
|
34
|
+
ATOM 10558 CA GLU F 25 28.033 5.648 -29.351 1.00 50.31 C
|
|
35
|
+
ATOM 10559 C GLU F 25 29.332 5.286 -30.079 1.00 60.13 C
|
|
36
|
+
ATOM 10560 O GLU F 25 29.595 4.101 -30.330 1.00 65.02 O
|
|
37
|
+
ATOM 10561 CB GLU F 25 26.927 5.992 -30.358 1.00 47.14 C
|
|
38
|
+
ATOM 10562 CG GLU F 25 26.451 4.872 -31.285 1.00 50.18 C
|
|
39
|
+
ATOM 10563 CD GLU F 25 25.906 5.376 -32.657 1.00 59.80 C
|
|
40
|
+
ATOM 10564 OE1 GLU F 25 26.512 6.292 -33.298 1.00 59.65 O
|
|
41
|
+
ATOM 10565 OE2 GLU F 25 24.859 4.843 -33.098 1.00 56.23 O
|
|
42
|
+
ATOM 11388 N THR F 141 15.709 9.909 -40.611 1.00 43.47 N
|
|
43
|
+
ATOM 11389 CA THR F 141 16.342 8.887 -39.789 1.00 44.34 C
|
|
44
|
+
ATOM 11390 C THR F 141 16.089 9.169 -38.311 1.00 43.54 C
|
|
45
|
+
ATOM 11391 O THR F 141 16.316 10.292 -37.851 1.00 43.12 O
|
|
46
|
+
ATOM 11392 CB THR F 141 17.841 8.832 -40.073 1.00 43.56 C
|
|
47
|
+
ATOM 11393 OG1 THR F 141 18.060 8.851 -41.489 1.00 42.17 O
|
|
48
|
+
ATOM 11394 CG2 THR F 141 18.442 7.560 -39.505 1.00 42.11 C
|
|
49
|
+
ATOM 11417 N ARG F 145 16.934 13.489 -36.682 1.00 42.82 N
|
|
50
|
+
ATOM 11418 CA ARG F 145 15.914 14.290 -37.338 1.00 43.06 C
|
|
51
|
+
ATOM 11419 C ARG F 145 16.352 15.741 -37.468 1.00 47.81 C
|
|
52
|
+
ATOM 11420 O ARG F 145 16.166 16.358 -38.527 1.00 49.55 O
|
|
53
|
+
ATOM 11421 CB ARG F 145 14.611 14.145 -36.548 1.00 52.52 C
|
|
54
|
+
ATOM 11422 CG ARG F 145 13.463 15.093 -36.850 1.00 52.54 C
|
|
55
|
+
ATOM 11423 CD ARG F 145 12.613 15.162 -35.593 1.00 56.72 C
|
|
56
|
+
ATOM 11424 NE ARG F 145 11.200 15.447 -35.811 1.00 61.47 N
|
|
57
|
+
ATOM 11425 CZ ARG F 145 10.285 15.372 -34.842 1.00 73.92 C
|
|
58
|
+
ATOM 11426 NH1 ARG F 145 9.005 15.653 -35.090 1.00 71.75 N
|
|
59
|
+
ATOM 11427 NH2 ARG F 145 10.657 15.007 -33.615 1.00 69.36 N
|
|
60
|
+
TER 12486 GLU F 289
|
|
61
|
+
ENDMDL
|
|
62
|
+
MASTER 0 0 0 76 71 0 0 612499 6 0 144
|
|
63
|
+
END
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
# coding: utf-8
|
|
2
|
+
"""Test doctest contained tests in every file of the module.
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
import configparser
|
|
6
|
+
import doctest
|
|
7
|
+
import importlib
|
|
8
|
+
import json
|
|
9
|
+
import gzip
|
|
10
|
+
import os
|
|
11
|
+
import pkgutil
|
|
12
|
+
import re
|
|
13
|
+
import shutil
|
|
14
|
+
import sys
|
|
15
|
+
import types
|
|
16
|
+
import warnings
|
|
17
|
+
from unittest import mock
|
|
18
|
+
|
|
19
|
+
import pyjess
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
def _load_tests_from_module(tests, module, globs, setUp=None, tearDown=None):
|
|
23
|
+
"""Load tests from module, iterating through submodules."""
|
|
24
|
+
for attr in (getattr(module, x) for x in dir(module) if not x.startswith("_")):
|
|
25
|
+
if isinstance(attr, types.ModuleType):
|
|
26
|
+
suite = doctest.DocTestSuite(
|
|
27
|
+
attr,
|
|
28
|
+
globs,
|
|
29
|
+
setUp=setUp,
|
|
30
|
+
tearDown=tearDown,
|
|
31
|
+
optionflags=+doctest.ELLIPSIS,
|
|
32
|
+
)
|
|
33
|
+
tests.addTests(suite)
|
|
34
|
+
return tests
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
def load_tests(loader, tests, ignore):
|
|
38
|
+
"""`load_test` function used by unittest to find the doctests."""
|
|
39
|
+
_current_cwd = os.getcwd()
|
|
40
|
+
|
|
41
|
+
def setUp(self):
|
|
42
|
+
warnings.simplefilter("ignore")
|
|
43
|
+
os.chdir(os.path.realpath(os.path.join(__file__, os.path.pardir, "data")))
|
|
44
|
+
|
|
45
|
+
def tearDown(self):
|
|
46
|
+
os.chdir(_current_cwd)
|
|
47
|
+
warnings.simplefilter(warnings.defaultaction)
|
|
48
|
+
|
|
49
|
+
# doctests are not compatible with `green`, so we may want to bail out
|
|
50
|
+
# early if `green` is running the tests
|
|
51
|
+
if sys.argv[0].endswith("green"):
|
|
52
|
+
return tests
|
|
53
|
+
|
|
54
|
+
# recursively traverse all library submodules and load tests from them
|
|
55
|
+
packages = [None, pyjess]
|
|
56
|
+
for pkg in iter(packages.pop, None):
|
|
57
|
+
for (_, subpkgname, subispkg) in pkgutil.walk_packages(pkg.__path__):
|
|
58
|
+
# do not import __main__ module to avoid side effects!
|
|
59
|
+
if subpkgname == "__main__" or subpkgname.startswith("tests") or subpkgname.startswith("cli"):
|
|
60
|
+
continue
|
|
61
|
+
# import the submodule and add it to the tests
|
|
62
|
+
module = importlib.import_module(".".join([pkg.__name__, subpkgname]))
|
|
63
|
+
globs = dict(pyjess=pyjess, **module.__dict__)
|
|
64
|
+
tests.addTests(
|
|
65
|
+
doctest.DocTestSuite(
|
|
66
|
+
module,
|
|
67
|
+
globs=globs,
|
|
68
|
+
setUp=setUp,
|
|
69
|
+
tearDown=tearDown,
|
|
70
|
+
optionflags=+doctest.ELLIPSIS,
|
|
71
|
+
)
|
|
72
|
+
)
|
|
73
|
+
# if the submodule is a package, we need to process its submodules
|
|
74
|
+
# as well, so we add it to the package queue
|
|
75
|
+
if subispkg and subpkgname != "tests":
|
|
76
|
+
packages.append(module)
|
|
77
|
+
|
|
78
|
+
return tests
|
pyjess/tests/test_hit.py
CHANGED
|
@@ -2,6 +2,7 @@ import math
|
|
|
2
2
|
import unittest
|
|
3
3
|
import sys
|
|
4
4
|
import pickle
|
|
5
|
+
import textwrap
|
|
5
6
|
|
|
6
7
|
from .._jess import Template, Molecule, Jess
|
|
7
8
|
from .utils import files
|
|
@@ -9,12 +10,14 @@ from . import data
|
|
|
9
10
|
|
|
10
11
|
|
|
11
12
|
class TestHit(unittest.TestCase):
|
|
13
|
+
|
|
14
|
+
maxDiff = None
|
|
12
15
|
|
|
13
16
|
@unittest.skipUnless(files, "importlib.resources not available")
|
|
14
17
|
@classmethod
|
|
15
18
|
def setUpClass(cls):
|
|
16
19
|
with files(data).joinpath("template_01.qry").open() as f:
|
|
17
|
-
template = Template.load(f)
|
|
20
|
+
template = Template.load(f, id="T1")
|
|
18
21
|
jess = Jess([template])
|
|
19
22
|
with files(data).joinpath("pdb1lnb.pdb").open() as f:
|
|
20
23
|
molecule = Molecule.load(f)
|
|
@@ -30,4 +33,25 @@ class TestHit(unittest.TestCase):
|
|
|
30
33
|
self.assertEqual(self.hit.template, hit.template)
|
|
31
34
|
self.assertListEqual(self.hit.atoms(transform=True), hit.atoms(transform=True))
|
|
32
35
|
self.assertListEqual(self.hit.atoms(transform=False), hit.atoms(transform=False))
|
|
33
|
-
self.assertEqual(self.hit.molecule(transform=False), hit.molecule(transform=False))
|
|
36
|
+
self.assertEqual(self.hit.molecule(transform=False), hit.molecule(transform=False))
|
|
37
|
+
|
|
38
|
+
def test_dumps(self):
|
|
39
|
+
expected = textwrap.dedent(
|
|
40
|
+
"""
|
|
41
|
+
REMARK 1LNB 0.555 T1 Det= 1.0 log(E)~ -2.04
|
|
42
|
+
ATOM 1112 ND1 HIS E 142 4.157 -2.574 4.091 1.00 10.22
|
|
43
|
+
ATOM 1115 NE2 HIS E 142 3.805 -2.316 1.890 1.00 16.00
|
|
44
|
+
ATOM 1123 OE1 GLU E 143 0.480 -4.544 -0.363 1.00 14.72
|
|
45
|
+
ATOM 1124 OE2 GLU E 143 1.870 -6.097 0.337 1.00 22.48
|
|
46
|
+
ATOM 1145 CG HIS E 146 0.031 0.017 0.019 1.00 12.45
|
|
47
|
+
ATOM 1146 ND1 HIS E 146 0.823 1.160 0.000 1.00 15.79
|
|
48
|
+
ATOM 1147 CD2 HIS E 146 0.878 -1.064 0.006 1.00 20.85
|
|
49
|
+
ATOM 1148 CE1 HIS E 146 2.115 0.777 -0.013 1.00 13.50
|
|
50
|
+
ATOM 1149 NE2 HIS E 146 2.181 -0.553 -0.032 1.00 12.44
|
|
51
|
+
ATOM 1298 OE1 GLU E 166 6.432 -0.605 1.056 1.00 16.03
|
|
52
|
+
ATOM 1299 OE2 GLU E 166 4.839 0.070 -0.343 1.00 19.31
|
|
53
|
+
ENDMDL
|
|
54
|
+
"""
|
|
55
|
+
).strip()
|
|
56
|
+
actual = self.hit.dumps().strip()
|
|
57
|
+
self.assertMultiLineEqual(actual, expected)
|
pyjess/tests/test_jess.py
CHANGED
|
@@ -92,7 +92,6 @@ class TestJess(unittest.TestCase):
|
|
|
92
92
|
self.assertEqual(len(jess[:1]), 1)
|
|
93
93
|
self.assertEqual(len(jess[1:]), 0)
|
|
94
94
|
|
|
95
|
-
|
|
96
95
|
@unittest.skipUnless(files, "importlib.resources not available")
|
|
97
96
|
def test_multiple_query_split(self):
|
|
98
97
|
with files(data).joinpath("template_01.qry").open() as f:
|
|
@@ -132,6 +131,29 @@ class TestJess(unittest.TestCase):
|
|
|
132
131
|
hits = list(jess.query(molecule, 1, 2, 2))
|
|
133
132
|
self.assertIsInstance(hits[0].template, MyTemplate)
|
|
134
133
|
|
|
134
|
+
@unittest.skipUnless(files, "importlib.resources not available")
|
|
135
|
+
def test_query_max_candidates(self):
|
|
136
|
+
with files(data).joinpath("template_01.qry").open() as f:
|
|
137
|
+
template = Template.load(f)
|
|
138
|
+
jess = Jess([template])
|
|
139
|
+
with files(data).joinpath("pdb1lnb.pdb").open() as f:
|
|
140
|
+
molecule = Molecule.load(f)
|
|
141
|
+
|
|
142
|
+
hits = list(jess.query(molecule, 2, 5, 5))
|
|
143
|
+
self.assertEqual(len(hits), 3)
|
|
144
|
+
|
|
145
|
+
hits = list(jess.query(molecule, 2, 5, 5, max_candidates=3))
|
|
146
|
+
self.assertEqual(len(hits), 3)
|
|
147
|
+
|
|
148
|
+
hits = list(jess.query(molecule, 2, 5, 5, max_candidates=2))
|
|
149
|
+
self.assertEqual(len(hits), 2)
|
|
150
|
+
|
|
151
|
+
hits = list(jess.query(molecule, 2, 5, 5, max_candidates=1))
|
|
152
|
+
self.assertEqual(len(hits), 1)
|
|
153
|
+
|
|
154
|
+
with self.assertRaises(ValueError):
|
|
155
|
+
hits = list(jess.query(molecule, 2, 5, 5, max_candidates=-1))
|
|
156
|
+
|
|
135
157
|
@unittest.skipUnless(files, "importlib.resources not available")
|
|
136
158
|
def test_query(self):
|
|
137
159
|
with files(data).joinpath("template_01.qry").open() as f:
|
|
@@ -311,3 +333,42 @@ class TestJess(unittest.TestCase):
|
|
|
311
333
|
self.assertAlmostEqual(atom.occupancy, float(atom_line[55:61]), places=3)
|
|
312
334
|
self.assertAlmostEqual(atom.temperature_factor, float(atom_line[61:67]), places=3)
|
|
313
335
|
|
|
336
|
+
@unittest.skipUnless(files, "importlib.resources not available")
|
|
337
|
+
def test_ignore_chain_none(self):
|
|
338
|
+
with files(data).joinpath("4.1.2.tpl").open() as f:
|
|
339
|
+
template = Template.load(f)
|
|
340
|
+
jess = Jess([template])
|
|
341
|
+
with files(data).joinpath("5ayx.EF.pdb").open() as f:
|
|
342
|
+
molecule = Molecule.load(f)
|
|
343
|
+
|
|
344
|
+
hits = list(jess.query(molecule, 3, 3, 3, ignore_chain=None))
|
|
345
|
+
self.assertEqual(len(hits), 0)
|
|
346
|
+
|
|
347
|
+
@unittest.skipUnless(files, "importlib.resources not available")
|
|
348
|
+
def test_ignore_chain_residues(self):
|
|
349
|
+
with files(data).joinpath("4.1.2.tpl").open() as f:
|
|
350
|
+
template = Template.load(f)
|
|
351
|
+
jess = Jess([template])
|
|
352
|
+
with files(data).joinpath("5ayx.EF.pdb").open() as f:
|
|
353
|
+
molecule = Molecule.load(f)
|
|
354
|
+
|
|
355
|
+
hits = list(jess.query(molecule, 3, 3, 3, ignore_chain="residues"))
|
|
356
|
+
self.assertEqual(len(hits), 2)
|
|
357
|
+
for hit in hits:
|
|
358
|
+
atoms = hit.atoms(transform=False)
|
|
359
|
+
for i in range(1, len(atoms)):
|
|
360
|
+
if atoms[i-1].residue_number == atoms[i].residue_number:
|
|
361
|
+
self.assertEqual(atoms[i-1].chain_id, atoms[i].chain_id)
|
|
362
|
+
|
|
363
|
+
@unittest.skipUnless(files, "importlib.resources not available")
|
|
364
|
+
def test_ignore_chain_atoms(self):
|
|
365
|
+
with files(data).joinpath("4.1.2.tpl").open() as f:
|
|
366
|
+
template = Template.load(f)
|
|
367
|
+
jess = Jess([template])
|
|
368
|
+
with files(data).joinpath("5ayx.EF.pdb").open() as f:
|
|
369
|
+
molecule = Molecule.load(f)
|
|
370
|
+
|
|
371
|
+
hits = list(jess.query(molecule, 3, 3, 3, ignore_chain="atoms"))
|
|
372
|
+
self.assertEqual(len(hits), 7)
|
|
373
|
+
|
|
374
|
+
|
pyjess/tests/test_molecule.py
CHANGED
|
@@ -1,12 +1,31 @@
|
|
|
1
|
+
import itertools
|
|
1
2
|
import os
|
|
2
3
|
import pickle
|
|
3
4
|
import unittest
|
|
4
5
|
import tempfile
|
|
5
6
|
import textwrap
|
|
6
7
|
import sys
|
|
8
|
+
import warnings
|
|
7
9
|
|
|
10
|
+
from .utils import files
|
|
11
|
+
from . import data
|
|
8
12
|
from .._jess import Atom, Molecule
|
|
9
13
|
|
|
14
|
+
try:
|
|
15
|
+
import gemmi
|
|
16
|
+
except ImportError:
|
|
17
|
+
gemmi = None
|
|
18
|
+
|
|
19
|
+
try:
|
|
20
|
+
import Bio.PDB
|
|
21
|
+
except ImportError:
|
|
22
|
+
Bio = None
|
|
23
|
+
|
|
24
|
+
try:
|
|
25
|
+
from biotite.structure.io.pdb import PDBFile
|
|
26
|
+
except ImportError:
|
|
27
|
+
PDBFile = None
|
|
28
|
+
|
|
10
29
|
MOLECULE = textwrap.dedent(
|
|
11
30
|
"""
|
|
12
31
|
HEADER DNA RECOMBINATION 05-DEC-97 1A0P
|
|
@@ -22,6 +41,38 @@ MOLECULE = textwrap.dedent(
|
|
|
22
41
|
|
|
23
42
|
class TestMolecule(unittest.TestCase):
|
|
24
43
|
|
|
44
|
+
def assertHeteroAtomEqual(self, a1, a2):
|
|
45
|
+
# self.assertEqual(a1.serial, a2.serial)
|
|
46
|
+
self.assertEqual(a1.name, a2.name)
|
|
47
|
+
self.assertEqual(a1.altloc, a2.altloc)
|
|
48
|
+
self.assertEqual(a1.residue_name, a2.residue_name)
|
|
49
|
+
# self.assertEqual(a1.chain_id, a2.chain_id)
|
|
50
|
+
# self.assertEqual(a1.residue_number, a2.residue_number)
|
|
51
|
+
self.assertEqual(a1.insertion_code, a2.insertion_code)
|
|
52
|
+
self.assertEqual(a1.element, a2.element)
|
|
53
|
+
self.assertAlmostEqual(a1.x, a2.x, places=5)
|
|
54
|
+
self.assertAlmostEqual(a1.y, a2.y, places=5)
|
|
55
|
+
self.assertAlmostEqual(a1.z, a2.z, places=5)
|
|
56
|
+
self.assertAlmostEqual(a1.occupancy, a2.occupancy, places=5)
|
|
57
|
+
self.assertAlmostEqual(a1.temperature_factor, a2.temperature_factor, places=5)
|
|
58
|
+
self.assertAlmostEqual(a1.charge, a2.charge, places=5)
|
|
59
|
+
|
|
60
|
+
def assertAtomEqual(self, a1, a2):
|
|
61
|
+
self.assertEqual(a1.serial, a2.serial)
|
|
62
|
+
self.assertEqual(a1.name, a2.name)
|
|
63
|
+
self.assertEqual(a1.altloc, a2.altloc)
|
|
64
|
+
self.assertEqual(a1.residue_name, a2.residue_name)
|
|
65
|
+
self.assertEqual(a1.chain_id, a2.chain_id)
|
|
66
|
+
self.assertEqual(a1.residue_number, a2.residue_number)
|
|
67
|
+
self.assertEqual(a1.insertion_code, a2.insertion_code)
|
|
68
|
+
self.assertEqual(a1.element, a2.element)
|
|
69
|
+
self.assertAlmostEqual(a1.x, a2.x, places=5)
|
|
70
|
+
self.assertAlmostEqual(a1.y, a2.y, places=5)
|
|
71
|
+
self.assertAlmostEqual(a1.z, a2.z, places=5)
|
|
72
|
+
self.assertAlmostEqual(a1.occupancy, a2.occupancy, places=5)
|
|
73
|
+
self.assertAlmostEqual(a1.temperature_factor, a2.temperature_factor, places=5)
|
|
74
|
+
self.assertAlmostEqual(a1.charge, a2.charge, places=5)
|
|
75
|
+
|
|
25
76
|
def _create_atom(self, **kwargs):
|
|
26
77
|
default = dict(serial=1, name='N', altloc=' ', residue_name='GLN', chain_id='A', residue_number=3, x=8.171, y=-51.403, z=42.886, segment='', insertion_code=' ', occupancy=1.0, temperature_factor=55.63, charge=0, element='N')
|
|
27
78
|
default.update(kwargs)
|
|
@@ -139,3 +190,98 @@ class TestMolecule(unittest.TestCase):
|
|
|
139
190
|
self.assertEqual(list(mol1), list(mol2))
|
|
140
191
|
self.assertEqual(mol1.id, mol2.id)
|
|
141
192
|
self.assertEqual(mol1, mol2)
|
|
193
|
+
|
|
194
|
+
@unittest.skipUnless(files, "importlib.resources not available")
|
|
195
|
+
@unittest.skipUnless(gemmi, "gemmi not available")
|
|
196
|
+
def test_load_consistency_no_skip_hetatm(self):
|
|
197
|
+
with files(data).joinpath("1AMY.pdb").open() as f:
|
|
198
|
+
pdb_molecule = Molecule.load(f, format="pdb")
|
|
199
|
+
with files(data).joinpath("1AMY.cif").open() as f:
|
|
200
|
+
with warnings.catch_warnings():
|
|
201
|
+
warnings.simplefilter('ignore')
|
|
202
|
+
cif_molecule = Molecule.load(f, format="cif")
|
|
203
|
+
self.assertEqual(len(cif_molecule), 3339)
|
|
204
|
+
self.assertEqual(len(pdb_molecule), 3339)
|
|
205
|
+
for pdb_atom, cif_atom in itertools.islice(zip(pdb_molecule, cif_molecule), 3184):
|
|
206
|
+
self.assertAtomEqual(pdb_atom, cif_atom)
|
|
207
|
+
for pdb_atom, cif_atom in itertools.islice(zip(pdb_molecule, cif_molecule), 3184, 3339):
|
|
208
|
+
self.assertHeteroAtomEqual(pdb_atom, cif_atom)
|
|
209
|
+
|
|
210
|
+
@unittest.skipUnless(files, "importlib.resources not available")
|
|
211
|
+
@unittest.skipUnless(gemmi, "gemmi not available")
|
|
212
|
+
def test_load_consistency_no_skip_hetatm_use_author(self):
|
|
213
|
+
with files(data).joinpath("1AMY.pdb").open() as f:
|
|
214
|
+
pdb_molecule = Molecule.load(f, format="pdb")
|
|
215
|
+
with files(data).joinpath("1AMY.cif").open() as f:
|
|
216
|
+
cif_molecule = Molecule.load(f, format="cif", use_author=True)
|
|
217
|
+
self.assertEqual(len(cif_molecule), 3339)
|
|
218
|
+
self.assertEqual(len(pdb_molecule), 3339)
|
|
219
|
+
for pdb_atom, cif_atom in itertools.islice(zip(pdb_molecule, cif_molecule), 3184):
|
|
220
|
+
self.assertAtomEqual(pdb_atom, cif_atom)
|
|
221
|
+
for pdb_atom, cif_atom in itertools.islice(zip(pdb_molecule, cif_molecule), 3184, 3339):
|
|
222
|
+
self.assertHeteroAtomEqual(pdb_atom, cif_atom)
|
|
223
|
+
|
|
224
|
+
@unittest.skipUnless(files, "importlib.resources not available")
|
|
225
|
+
@unittest.skipUnless(gemmi, "gemmi not available")
|
|
226
|
+
def test_load_consistency_skip_hetatm(self):
|
|
227
|
+
with files(data).joinpath("1AMY.pdb").open() as f:
|
|
228
|
+
pdb_molecule = Molecule.load(f, format="pdb", skip_hetatm=True)
|
|
229
|
+
with files(data).joinpath("1AMY.cif").open() as f:
|
|
230
|
+
cif_molecule = Molecule.load(f, format="cif", skip_hetatm=True)
|
|
231
|
+
self.assertEqual(len(cif_molecule), 3184)
|
|
232
|
+
self.assertEqual(len(pdb_molecule), 3184)
|
|
233
|
+
for pdb_atom, cif_atom in itertools.islice(zip(pdb_molecule, cif_molecule), 3184):
|
|
234
|
+
self.assertAtomEqual(pdb_atom, cif_atom)
|
|
235
|
+
|
|
236
|
+
@unittest.skipUnless(files, "importlib.resources not available")
|
|
237
|
+
@unittest.skipUnless(gemmi, "gemmi not available")
|
|
238
|
+
def test_load_consistency_skip_hetatm_use_author(self):
|
|
239
|
+
with files(data).joinpath("1AMY.pdb").open() as f:
|
|
240
|
+
pdb_molecule = Molecule.load(f, format="pdb", skip_hetatm=True)
|
|
241
|
+
with files(data).joinpath("1AMY.cif").open() as f:
|
|
242
|
+
cif_molecule = Molecule.load(f, format="cif", skip_hetatm=True, use_author=True)
|
|
243
|
+
self.assertEqual(len(cif_molecule), 3184)
|
|
244
|
+
self.assertEqual(len(pdb_molecule), 3184)
|
|
245
|
+
for pdb_atom, cif_atom in itertools.islice(zip(pdb_molecule, cif_molecule), 3184):
|
|
246
|
+
self.assertAtomEqual(pdb_atom, cif_atom)
|
|
247
|
+
|
|
248
|
+
@unittest.skipUnless(files, "importlib.resources not available")
|
|
249
|
+
@unittest.skipUnless(Bio, "biopython not available")
|
|
250
|
+
def test_from_biopython(self):
|
|
251
|
+
parser = Bio.PDB.PDBParser()
|
|
252
|
+
with files(data).joinpath("1AMY.pdb").open() as f:
|
|
253
|
+
structure = parser.get_structure('1amy', f)
|
|
254
|
+
bio_mol = Molecule.from_biopython(structure)
|
|
255
|
+
with files(data).joinpath("1AMY.pdb").open() as f:
|
|
256
|
+
pdb_mol = Molecule.load(f, format="pdb")
|
|
257
|
+
self.assertEqual(len(pdb_mol), 3339)
|
|
258
|
+
self.assertEqual(len(bio_mol), 3339)
|
|
259
|
+
for pdb_atom, bio_atom in zip(pdb_mol, bio_mol):
|
|
260
|
+
self.assertAtomEqual(pdb_atom, bio_atom)
|
|
261
|
+
|
|
262
|
+
@unittest.skipUnless(files, "importlib.resources not available")
|
|
263
|
+
@unittest.skipUnless(gemmi, "gemmi not available")
|
|
264
|
+
def test_from_gemmi(self):
|
|
265
|
+
with files(data).joinpath("1AMY.pdb").open() as f:
|
|
266
|
+
structure = gemmi.read_pdb_string(f.read())
|
|
267
|
+
gemmi_mol = Molecule.from_gemmi(structure[0])
|
|
268
|
+
with files(data).joinpath("1AMY.pdb").open() as f:
|
|
269
|
+
pdb_mol = Molecule.load(f, format="pdb")
|
|
270
|
+
self.assertEqual(len(pdb_mol), 3339)
|
|
271
|
+
self.assertEqual(len(gemmi_mol), 3339)
|
|
272
|
+
for pdb_atom, gemmi_atom in zip(pdb_mol, gemmi_mol):
|
|
273
|
+
self.assertAtomEqual(pdb_atom, gemmi_atom)
|
|
274
|
+
|
|
275
|
+
@unittest.skipUnless(files, "importlib.resources not available")
|
|
276
|
+
@unittest.skipUnless(PDBFile, "biotite not available")
|
|
277
|
+
def test_from_biotite(self):
|
|
278
|
+
with files(data).joinpath("1AMY.pdb").open() as f:
|
|
279
|
+
pdb_file = PDBFile.read(f)
|
|
280
|
+
structure = pdb_file.get_structure(altloc="all", extra_fields=["atom_id", "b_factor", "occupancy", "charge"])
|
|
281
|
+
biotite_mol = Molecule.from_biotite(structure[0])
|
|
282
|
+
with files(data).joinpath("1AMY.pdb").open() as f:
|
|
283
|
+
pdb_mol = Molecule.load(f, format="pdb")
|
|
284
|
+
self.assertEqual(len(pdb_mol), 3339)
|
|
285
|
+
self.assertEqual(len(biotite_mol), 3339)
|
|
286
|
+
for pdb_atom, biotite_atom in zip(pdb_mol, biotite_mol):
|
|
287
|
+
self.assertAtomEqual(pdb_atom, biotite_atom)
|
pyjess/tests/test_template.py
CHANGED
|
@@ -6,6 +6,8 @@ import textwrap
|
|
|
6
6
|
import sys
|
|
7
7
|
|
|
8
8
|
from .._jess import Template
|
|
9
|
+
from .utils import files
|
|
10
|
+
from . import data
|
|
9
11
|
|
|
10
12
|
TEMPLATE = textwrap.dedent(
|
|
11
13
|
"""
|
|
@@ -109,9 +111,16 @@ class TestTemplate(unittest.TestCase):
|
|
|
109
111
|
tpl2 = tpl1.copy()
|
|
110
112
|
self.assertEqual(len(tpl1), len(tpl2))
|
|
111
113
|
self.assertEqual(tpl1, tpl2)
|
|
114
|
+
self.assertEqual(list(tpl1), list(tpl2))
|
|
112
115
|
|
|
113
116
|
def test_pickle_roundtrip(self):
|
|
114
117
|
tpl1 = Template.loads(TEMPLATE, id="tpl1")
|
|
115
118
|
tpl2 = pickle.loads(pickle.dumps(tpl1))
|
|
116
119
|
self.assertEqual(len(tpl1), len(tpl2))
|
|
117
|
-
self.assertEqual(tpl1, tpl2)
|
|
120
|
+
self.assertEqual(tpl1, tpl2)
|
|
121
|
+
|
|
122
|
+
@unittest.skipUnless(files, "importlib.resources not available")
|
|
123
|
+
def test_dimension_multiple_chains(self):
|
|
124
|
+
with files(data).joinpath("1sur.qry").open() as f:
|
|
125
|
+
template1 = Template.load(f)
|
|
126
|
+
self.assertEqual(template1.dimension, 4)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.2
|
|
2
2
|
Name: pyjess
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.7.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>
|
|
@@ -56,6 +56,8 @@ Project-URL: PiWheels, https://piwheels.org/project/pyjess/
|
|
|
56
56
|
Requires-Python: >=3.7
|
|
57
57
|
Provides-Extra: test
|
|
58
58
|
Requires-Dist: importlib-resources; python_version < "3.9" and extra == "test"
|
|
59
|
+
Provides-Extra: cif
|
|
60
|
+
Requires-Dist: gemmi~=0.7.0; extra == "cif"
|
|
59
61
|
Description-Content-Type: text/markdown
|
|
60
62
|
|
|
61
63
|
# 🐍🔍 PyJess [](https://github.com/althonos/pyjess/stargazers)
|
|
@@ -115,7 +117,7 @@ package:
|
|
|
115
117
|
$ conda install -c bioconda pyjess
|
|
116
118
|
```
|
|
117
119
|
|
|
118
|
-
Check the [*install* page](https://pyjess.readthedocs.io/en/stable/install.html)
|
|
120
|
+
Check the [*install* page](https://pyjess.readthedocs.io/en/stable/guide/install.html)
|
|
119
121
|
of the documentation for other ways to install PyJess on your machine.
|
|
120
122
|
|
|
121
123
|
|
|
@@ -129,7 +131,9 @@ Jess if you are using it in an academic work, for instance as:
|
|
|
129
131
|
|
|
130
132
|
## 💡 Example
|
|
131
133
|
|
|
132
|
-
|
|
134
|
+
#### Prepare templates
|
|
135
|
+
|
|
136
|
+
Load [`Template`](https://pyjess.readthedocs.io/en/latest/api/template.html#pyjess.Template)
|
|
133
137
|
objects to be used as references from different template files:
|
|
134
138
|
|
|
135
139
|
```python
|
|
@@ -141,15 +145,46 @@ for path in sorted(pathlib.Path("vendor/jess/examples").glob("template_*.qry")):
|
|
|
141
145
|
templates.append(pyjess.Template.load(path, id=path.stem))
|
|
142
146
|
```
|
|
143
147
|
|
|
144
|
-
|
|
145
|
-
|
|
148
|
+
#### Prepare query structures
|
|
149
|
+
|
|
150
|
+
Load a [`Molecule`](https://pyjess.readthedocs.io/en/latest/api/molecule.html#pyjess.Molecule)
|
|
151
|
+
(a PDB structure) from a PDB file, create one with the Python API, or
|
|
152
|
+
convert it from a [`Bio.Model`](https://biopython.org/docs/1.76/api/Bio.PDB.Model.html),
|
|
153
|
+
[`gemmi.Model`](https://gemmi.readthedocs.io/en/latest/mol.html#model),
|
|
154
|
+
or [`biotite.structure.AtomArray`](https://www.biotite-python.org/latest/apidoc/biotite.structure.AtomArray.html)
|
|
155
|
+
object:
|
|
146
156
|
|
|
147
157
|
```python
|
|
148
|
-
|
|
158
|
+
# load from PDB file or mmCIF file
|
|
149
159
|
mol = pyjess.Molecule.load("vendor/jess/examples/test_pdbs/pdb1a0p.ent")
|
|
160
|
+
|
|
161
|
+
# load with BioPython
|
|
162
|
+
parser = Bio.PDB.PDBParser()
|
|
163
|
+
structure = parser.get_structure('pdb1a0p', "vendor/jess/examples/test_pdbs/pdb1a0p.ent")
|
|
164
|
+
mol = Molecule.from_biopython(structure, id="1a0p")
|
|
165
|
+
|
|
166
|
+
# load with Gemmi
|
|
167
|
+
structure = gemmi.read_pdb_string("vendor/jess/examples/test_pdbs/pdb1a0p.ent")
|
|
168
|
+
mol = Molecule.from_gemmi(structure[0], id="1a0p")
|
|
169
|
+
|
|
170
|
+
# load with Biotite
|
|
171
|
+
pdb_file = biotite.structure.io.pdb.PDBFile.read(f)
|
|
172
|
+
structure = pdb_file.get_structure(altloc="all", extra_fields=["atom_id", "b_factor", "occupancy", "charge"])
|
|
173
|
+
mol = Molecule.from_biotite(structure[0])
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
### Match templates
|
|
177
|
+
|
|
178
|
+
Create a [`Jess`](https://pyjess.readthedocs.io/en/latest/api/jess.html#pyjess.Jess)
|
|
179
|
+
instance and use it to query a against the stored templates:
|
|
180
|
+
|
|
181
|
+
```python
|
|
182
|
+
jess = pyjess.Jess(templates)
|
|
150
183
|
query = jess.query(mol, rmsd_threshold=2.0, distance_cutoff=3.0, max_dynamic_distance=3.0)
|
|
151
184
|
```
|
|
152
185
|
|
|
186
|
+
### Process hits
|
|
187
|
+
|
|
153
188
|
The hits are computed iteratively, and the different output statistics are
|
|
154
189
|
computed on-the-fly when requested:
|
|
155
190
|
|
|
@@ -160,13 +195,19 @@ for hit in query:
|
|
|
160
195
|
print(atom.name, atom.x, atom.y, atom.z)
|
|
161
196
|
```
|
|
162
197
|
|
|
198
|
+
Hits can also be rendered in PDB format like in the original Jess output,
|
|
199
|
+
either by writing to a file directly, or to a Python string:
|
|
200
|
+
```python
|
|
201
|
+
for hit in query:
|
|
202
|
+
hit.dump(sys.stdout, format="pdb")
|
|
203
|
+
```
|
|
163
204
|
|
|
164
205
|
## 🧶 Thread-safety
|
|
165
206
|
|
|
166
|
-
Once a [`Jess`](https://pyjess.readthedocs.io/en/latest/api/jess.html#pyjess.Jess)
|
|
207
|
+
Once a [`Jess`](https://pyjess.readthedocs.io/en/latest/api/jess.html#pyjess.Jess)
|
|
167
208
|
instance has been created, the templates cannot be edited anymore,
|
|
168
|
-
making the [`Jess.query`](https://pyjess.readthedocs.io/en/latest/api/jess.html#pyjess.Jess.query) method re-entrant and thread-safe. This allows querying
|
|
169
|
-
several molecules against the same templates in parallel using e.g a
|
|
209
|
+
making the [`Jess.query`](https://pyjess.readthedocs.io/en/latest/api/jess.html#pyjess.Jess.query) method re-entrant and thread-safe. This allows querying
|
|
210
|
+
several molecules against the same templates in parallel using e.g a
|
|
170
211
|
[`ThreadPool`](https://docs.python.org/3/library/multiprocessing.html#multiprocessing.pool.ThreadPool):
|
|
171
212
|
|
|
172
213
|
```python
|
|
@@ -183,9 +224,9 @@ If running Jess in parallel, make sure to use `v0.2.1` or later to use the code
|
|
|
183
224
|
|
|
184
225
|
## ⏱️ Benchmarks
|
|
185
226
|
|
|
186
|
-
The following table reports the runtime of PyJess to match
|
|
187
|
-
structures to the
|
|
188
|
-
[EnzyMM](https://github.com/RayHackett/enzymm), using
|
|
227
|
+
The following table reports the runtime of PyJess to match N=132 protein
|
|
228
|
+
structures to the M=7607 templates of
|
|
229
|
+
[EnzyMM](https://github.com/RayHackett/enzymm), using J=12 threads to parallelize.
|
|
189
230
|
|
|
190
231
|
| Version | Runtime (s) | Match Speed (N * M / s * J) | Speedup |
|
|
191
232
|
| ----------- | ----------- | --------------------------- | ----------- |
|
|
@@ -193,10 +234,11 @@ structures to the $m=7607$ templates of
|
|
|
193
234
|
| ``v0.5.0`` | 586.3 | 142.7 | x1.05 |
|
|
194
235
|
| ``v0.5.1`` | 365.6 | 228.9 | x1.69 |
|
|
195
236
|
| ``v0.5.2`` | 327.2 | 255.7 | x1.88 |
|
|
196
|
-
| ``v0.6.0`` | 54.5 | 1535.4 |
|
|
237
|
+
| ``v0.6.0`` | 54.5 | 1535.4 | x11.34 |
|
|
238
|
+
| ``v0.7.0`` | 52.4 | 1597.5 | **x11.80** |
|
|
197
239
|
|
|
198
|
-
*Benchmarks were run on a quiet [i7-1255U](https://www.intel.com/content/www/us/en/products/sku/226259/intel-core-i71255u-processor-12m-cache-up-to-4-70-ghz/specifications.html)
|
|
199
|
-
cores.*
|
|
240
|
+
*Benchmarks were run on a quiet [i7-1255U](https://www.intel.com/content/www/us/en/products/sku/226259/intel-core-i71255u-processor-12m-cache-up-to-4-70-ghz/specifications.html)
|
|
241
|
+
CPU running @4.70GHz with 10 physical cores / 12 logical cores.*
|
|
200
242
|
|
|
201
243
|
## 💭 Feedback
|
|
202
244
|
|
|
@@ -224,7 +266,8 @@ in the [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) format.
|
|
|
224
266
|
|
|
225
267
|
## ⚖️ License
|
|
226
268
|
|
|
227
|
-
This library is provided under the [MIT License](https://choosealicense.com/licenses/mit/).
|
|
269
|
+
This library is provided under the [MIT License](https://choosealicense.com/licenses/mit/).
|
|
270
|
+
The JESS code is distributed under the [MIT License](https://choosealicense.com/licenses/mit/) as well.
|
|
228
271
|
|
|
229
272
|
*This project is in no way not affiliated, sponsored, or otherwise endorsed
|
|
230
273
|
by the JESS authors. It was developed
|