stcrpy 1.0.5__tar.gz → 1.0.6__tar.gz
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.
- {stcrpy-1.0.5 → stcrpy-1.0.6}/PKG-INFO +3 -2
- {stcrpy-1.0.5 → stcrpy-1.0.6}/README.md +1 -1
- {stcrpy-1.0.5 → stcrpy-1.0.6}/pyproject.toml +3 -2
- {stcrpy-1.0.5 → stcrpy-1.0.6}/stcrpy/tcr_interactions/TCRInteractionProfiler.py +8 -1
- {stcrpy-1.0.5 → stcrpy-1.0.6}/stcrpy/tcr_processing/TCRParser.py +5 -3
- {stcrpy-1.0.5 → stcrpy-1.0.6}/stcrpy/tcr_processing/utils/symmetry_mates.py +32 -26
- {stcrpy-1.0.5 → stcrpy-1.0.6}/stcrpy.egg-info/PKG-INFO +3 -2
- {stcrpy-1.0.5 → stcrpy-1.0.6}/stcrpy.egg-info/SOURCES.txt +0 -1
- {stcrpy-1.0.5 → stcrpy-1.0.6}/stcrpy.egg-info/requires.txt +1 -0
- {stcrpy-1.0.5 → stcrpy-1.0.6}/test/test_tcr_datasets.py +10 -10
- stcrpy-1.0.6/test/test_tcr_formats.py +79 -0
- stcrpy-1.0.6/test/test_tcr_geometry.py +260 -0
- {stcrpy-1.0.5 → stcrpy-1.0.6}/test/test_tcr_interactions.py +17 -48
- {stcrpy-1.0.5 → stcrpy-1.0.6}/test/test_tcr_metrics.py +4 -12
- {stcrpy-1.0.5 → stcrpy-1.0.6}/test/test_tcr_processing.py +59 -121
- {stcrpy-1.0.5 → stcrpy-1.0.6}/test/test_tcr_sequence_operations.py +1 -1
- stcrpy-1.0.5/test/test_symmetry_mates.py +0 -11
- stcrpy-1.0.5/test/test_tcr_formats.py +0 -79
- stcrpy-1.0.5/test/test_tcr_geometry.py +0 -259
- {stcrpy-1.0.5 → stcrpy-1.0.6}/LICENCE +0 -0
- {stcrpy-1.0.5 → stcrpy-1.0.6}/examples/__init__.py +0 -0
- {stcrpy-1.0.5 → stcrpy-1.0.6}/examples/egnn.py +0 -0
- {stcrpy-1.0.5 → stcrpy-1.0.6}/setup.cfg +0 -0
- {stcrpy-1.0.5 → stcrpy-1.0.6}/stcrpy/__init__.py +0 -0
- {stcrpy-1.0.5 → stcrpy-1.0.6}/stcrpy/tcr_datasets/__init__.py +0 -0
- {stcrpy-1.0.5 → stcrpy-1.0.6}/stcrpy/tcr_datasets/tcr_graph_dataset.py +0 -0
- {stcrpy-1.0.5 → stcrpy-1.0.6}/stcrpy/tcr_datasets/tcr_selector.py +0 -0
- {stcrpy-1.0.5 → stcrpy-1.0.6}/stcrpy/tcr_datasets/tcr_structure_dataset.py +0 -0
- {stcrpy-1.0.5 → stcrpy-1.0.6}/stcrpy/tcr_datasets/utils.py +0 -0
- {stcrpy-1.0.5 → stcrpy-1.0.6}/stcrpy/tcr_formats/__init__.py +0 -0
- {stcrpy-1.0.5 → stcrpy-1.0.6}/stcrpy/tcr_formats/tcr_formats.py +0 -0
- {stcrpy-1.0.5 → stcrpy-1.0.6}/stcrpy/tcr_formats/tcr_haddock.py +0 -0
- {stcrpy-1.0.5 → stcrpy-1.0.6}/stcrpy/tcr_geometry/TCRAngle.py +0 -0
- {stcrpy-1.0.5 → stcrpy-1.0.6}/stcrpy/tcr_geometry/TCRCoM.py +0 -0
- {stcrpy-1.0.5 → stcrpy-1.0.6}/stcrpy/tcr_geometry/TCRCoM_LICENCE +0 -0
- {stcrpy-1.0.5 → stcrpy-1.0.6}/stcrpy/tcr_geometry/TCRDock.py +0 -0
- {stcrpy-1.0.5 → stcrpy-1.0.6}/stcrpy/tcr_geometry/TCRGeom.py +0 -0
- {stcrpy-1.0.5 → stcrpy-1.0.6}/stcrpy/tcr_geometry/TCRGeomFiltering.py +0 -0
- {stcrpy-1.0.5 → stcrpy-1.0.6}/stcrpy/tcr_geometry/__init__.py +0 -0
- {stcrpy-1.0.5 → stcrpy-1.0.6}/stcrpy/tcr_geometry/reference_data/Acoreset.txt +0 -0
- {stcrpy-1.0.5 → stcrpy-1.0.6}/stcrpy/tcr_geometry/reference_data/Bcoreset.txt +0 -0
- {stcrpy-1.0.5 → stcrpy-1.0.6}/stcrpy/tcr_geometry/reference_data/__init__.py +0 -0
- {stcrpy-1.0.5 → stcrpy-1.0.6}/stcrpy/tcr_geometry/reference_data/consensus_A.pdb +0 -0
- {stcrpy-1.0.5 → stcrpy-1.0.6}/stcrpy/tcr_geometry/reference_data/consensus_B.pdb +0 -0
- {stcrpy-1.0.5 → stcrpy-1.0.6}/stcrpy/tcr_geometry/reference_data/consensus_D.pdb +0 -0
- {stcrpy-1.0.5 → stcrpy-1.0.6}/stcrpy/tcr_geometry/reference_data/consensus_G.pdb +0 -0
- {stcrpy-1.0.5 → stcrpy-1.0.6}/stcrpy/tcr_geometry/reference_data/dock_reference_1_imgt_numbered.pdb +0 -0
- {stcrpy-1.0.5 → stcrpy-1.0.6}/stcrpy/tcr_geometry/reference_data/dock_reference_2_imgt_numbered.pdb +0 -0
- {stcrpy-1.0.5 → stcrpy-1.0.6}/stcrpy/tcr_geometry/reference_data/pcA.txt +0 -0
- {stcrpy-1.0.5 → stcrpy-1.0.6}/stcrpy/tcr_geometry/reference_data/pcB.txt +0 -0
- {stcrpy-1.0.5 → stcrpy-1.0.6}/stcrpy/tcr_geometry/reference_data/reference_A.pdb +0 -0
- {stcrpy-1.0.5 → stcrpy-1.0.6}/stcrpy/tcr_geometry/reference_data/reference_B.pdb +0 -0
- {stcrpy-1.0.5 → stcrpy-1.0.6}/stcrpy/tcr_geometry/reference_data/reference_D.pdb +0 -0
- {stcrpy-1.0.5 → stcrpy-1.0.6}/stcrpy/tcr_geometry/reference_data/reference_G.pdb +0 -0
- {stcrpy-1.0.5 → stcrpy-1.0.6}/stcrpy/tcr_geometry/reference_data/reference_data.py +0 -0
- {stcrpy-1.0.5 → stcrpy-1.0.6}/stcrpy/tcr_interactions/PLIPParser.py +0 -0
- {stcrpy-1.0.5 → stcrpy-1.0.6}/stcrpy/tcr_interactions/TCRpMHC_PLIP_Model_Parser.py +0 -0
- {stcrpy-1.0.5 → stcrpy-1.0.6}/stcrpy/tcr_interactions/__init__.py +0 -0
- {stcrpy-1.0.5 → stcrpy-1.0.6}/stcrpy/tcr_interactions/utils.py +0 -0
- {stcrpy-1.0.5 → stcrpy-1.0.6}/stcrpy/tcr_methods/__init__.py +0 -0
- {stcrpy-1.0.5 → stcrpy-1.0.6}/stcrpy/tcr_methods/tcr_batch_operations.py +0 -0
- {stcrpy-1.0.5 → stcrpy-1.0.6}/stcrpy/tcr_methods/tcr_methods.py +0 -0
- {stcrpy-1.0.5 → stcrpy-1.0.6}/stcrpy/tcr_methods/tcr_reformatting.py +0 -0
- {stcrpy-1.0.5 → stcrpy-1.0.6}/stcrpy/tcr_metrics/__init__.py +0 -0
- {stcrpy-1.0.5 → stcrpy-1.0.6}/stcrpy/tcr_metrics/constants.py +0 -0
- {stcrpy-1.0.5 → stcrpy-1.0.6}/stcrpy/tcr_metrics/tcr_dockq.py +0 -0
- {stcrpy-1.0.5 → stcrpy-1.0.6}/stcrpy/tcr_metrics/tcr_interface_rmsd.py +0 -0
- {stcrpy-1.0.5 → stcrpy-1.0.6}/stcrpy/tcr_metrics/tcr_rmsd.py +0 -0
- {stcrpy-1.0.5 → stcrpy-1.0.6}/stcrpy/tcr_ml/__init__.py +0 -0
- {stcrpy-1.0.5 → stcrpy-1.0.6}/stcrpy/tcr_ml/geometry_predictor.py +0 -0
- {stcrpy-1.0.5 → stcrpy-1.0.6}/stcrpy/tcr_processing/AGchain.py +0 -0
- {stcrpy-1.0.5 → stcrpy-1.0.6}/stcrpy/tcr_processing/Chemical_components.py +0 -0
- {stcrpy-1.0.5 → stcrpy-1.0.6}/stcrpy/tcr_processing/Entity.py +0 -0
- {stcrpy-1.0.5 → stcrpy-1.0.6}/stcrpy/tcr_processing/Fragment.py +0 -0
- {stcrpy-1.0.5 → stcrpy-1.0.6}/stcrpy/tcr_processing/Holder.py +0 -0
- {stcrpy-1.0.5 → stcrpy-1.0.6}/stcrpy/tcr_processing/MHC.py +0 -0
- {stcrpy-1.0.5 → stcrpy-1.0.6}/stcrpy/tcr_processing/MHCchain.py +0 -0
- {stcrpy-1.0.5 → stcrpy-1.0.6}/stcrpy/tcr_processing/Model.py +0 -0
- {stcrpy-1.0.5 → stcrpy-1.0.6}/stcrpy/tcr_processing/Select.py +0 -0
- {stcrpy-1.0.5 → stcrpy-1.0.6}/stcrpy/tcr_processing/TCR.py +0 -0
- {stcrpy-1.0.5 → stcrpy-1.0.6}/stcrpy/tcr_processing/TCRIO.py +0 -0
- {stcrpy-1.0.5 → stcrpy-1.0.6}/stcrpy/tcr_processing/TCRStructure.py +0 -0
- {stcrpy-1.0.5 → stcrpy-1.0.6}/stcrpy/tcr_processing/TCRchain.py +0 -0
- {stcrpy-1.0.5 → stcrpy-1.0.6}/stcrpy/tcr_processing/__init__.py +0 -0
- {stcrpy-1.0.5 → stcrpy-1.0.6}/stcrpy/tcr_processing/annotate.py +0 -0
- {stcrpy-1.0.5 → stcrpy-1.0.6}/stcrpy/tcr_processing/utils/__init__.py +0 -0
- {stcrpy-1.0.5 → stcrpy-1.0.6}/stcrpy/tcr_processing/utils/common.py +0 -0
- {stcrpy-1.0.5 → stcrpy-1.0.6}/stcrpy/tcr_processing/utils/constants.py +0 -0
- {stcrpy-1.0.5 → stcrpy-1.0.6}/stcrpy/tcr_processing/utils/region_definitions.py +0 -0
- {stcrpy-1.0.5 → stcrpy-1.0.6}/stcrpy/utils/__init__.py +0 -0
- {stcrpy-1.0.5 → stcrpy-1.0.6}/stcrpy/utils/error_stream.py +0 -0
- {stcrpy-1.0.5 → stcrpy-1.0.6}/stcrpy.egg-info/dependency_links.txt +0 -0
- {stcrpy-1.0.5 → stcrpy-1.0.6}/stcrpy.egg-info/top_level.txt +0 -0
- {stcrpy-1.0.5 → stcrpy-1.0.6}/test/test_annotations.py +0 -0
- {stcrpy-1.0.5 → stcrpy-1.0.6}/test/test_tcr_geometry_filters.py +0 -0
- {stcrpy-1.0.5 → stcrpy-1.0.6}/test/test_tcr_methods.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: stcrpy
|
|
3
|
-
Version: 1.0.
|
|
3
|
+
Version: 1.0.6
|
|
4
4
|
Summary: Set of methods to parse, annotate, and calculate features of TCR structures
|
|
5
5
|
Maintainer-email: Nele Quast <quast@stats.ox.ac.uk>
|
|
6
6
|
Requires-Python: >=3.10
|
|
@@ -12,6 +12,7 @@ Requires-Dist: numpy==1.26.4
|
|
|
12
12
|
Requires-Dist: lxml
|
|
13
13
|
Requires-Dist: openbabel-wheel==3.1.1.21
|
|
14
14
|
Requires-Dist: rdkit
|
|
15
|
+
Requires-Dist: pyhmmer==0.11.4
|
|
15
16
|
Requires-Dist: anarci-mhc
|
|
16
17
|
Requires-Dist: pandas
|
|
17
18
|
Requires-Dist: matplotlib
|
|
@@ -42,7 +43,7 @@ Please feel free to reach out with any comments or feedback.
|
|
|
42
43
|
|
|
43
44
|
Under review, please cite:
|
|
44
45
|
|
|
45
|
-
**Quast, N. , Deane, C., & Raybould, M. (2025). STCRpy: a software suite for TCR:pMHC structure parsing, interaction profiling, and machine learning dataset preparation.
|
|
46
|
+
**Quast, N. , Deane, C., & Raybould, M. (2025). STCRpy: a software suite for TCR:pMHC structure parsing, interaction profiling, and machine learning dataset preparation. Bioinformatics. [https://doi.org/10.1093/bioinformatics/btaf566](https://doi.org/10.1093/bioinformatics/btaf566)**
|
|
46
47
|
|
|
47
48
|
<img src="./stcrpy_main_fig.png" alt="drawing" width="1500"/>
|
|
48
49
|
|
|
@@ -15,7 +15,7 @@ Please feel free to reach out with any comments or feedback.
|
|
|
15
15
|
|
|
16
16
|
Under review, please cite:
|
|
17
17
|
|
|
18
|
-
**Quast, N. , Deane, C., & Raybould, M. (2025). STCRpy: a software suite for TCR:pMHC structure parsing, interaction profiling, and machine learning dataset preparation.
|
|
18
|
+
**Quast, N. , Deane, C., & Raybould, M. (2025). STCRpy: a software suite for TCR:pMHC structure parsing, interaction profiling, and machine learning dataset preparation. Bioinformatics. [https://doi.org/10.1093/bioinformatics/btaf566](https://doi.org/10.1093/bioinformatics/btaf566)**
|
|
19
19
|
|
|
20
20
|
<img src="./stcrpy_main_fig.png" alt="drawing" width="1500"/>
|
|
21
21
|
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "stcrpy"
|
|
7
|
-
version = "1.0.
|
|
7
|
+
version = "1.0.6"
|
|
8
8
|
description = "Set of methods to parse, annotate, and calculate features of TCR structures"
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
license-files = [
|
|
@@ -17,10 +17,11 @@ maintainers = [
|
|
|
17
17
|
requires-python = ">=3.10"
|
|
18
18
|
dependencies = [
|
|
19
19
|
"biopython",
|
|
20
|
-
"numpy==1.26.4",
|
|
20
|
+
"numpy==1.26.4", # required by DockQ
|
|
21
21
|
"lxml",
|
|
22
22
|
"openbabel-wheel==3.1.1.21",
|
|
23
23
|
"rdkit",
|
|
24
|
+
"pyhmmer==0.11.4", # fix pyhmmer version to prevent string encoding bu. TODO:fix this within anarci-mhc directly and redeploy
|
|
24
25
|
"anarci-mhc",
|
|
25
26
|
"pandas",
|
|
26
27
|
"matplotlib",
|
|
@@ -8,6 +8,7 @@ from ..tcr_processing.TCRParser import TCRParser
|
|
|
8
8
|
try:
|
|
9
9
|
import plip
|
|
10
10
|
from plip.basic.remote import VisualizerData
|
|
11
|
+
from plip.visualization.visualize import visualize_in_pymol
|
|
11
12
|
|
|
12
13
|
except ModuleNotFoundError as e:
|
|
13
14
|
if "pymol" in str(e):
|
|
@@ -413,7 +414,8 @@ class TCRInteractionProfiler:
|
|
|
413
414
|
heatmap_b[pair[0][1], ligand_number_mapping[int(pair[1][1])]] = (
|
|
414
415
|
heatmap_b[pair[0][1], ligand_number_mapping[int(pair[1][1])]] + 1
|
|
415
416
|
)
|
|
416
|
-
|
|
417
|
+
|
|
418
|
+
im_beta = ax_beta.imshow(heatmap_b.T, cmap="PuRd")
|
|
417
419
|
for i in plot_index:
|
|
418
420
|
ax_beta.axhline(y=i - 0.5, color="blue", linewidth=1)
|
|
419
421
|
ax_beta.axhline(y=i + 0.5, color="blue", linewidth=1)
|
|
@@ -427,6 +429,11 @@ class TCRInteractionProfiler:
|
|
|
427
429
|
ax_beta.set_xticks([], [], rotation=90)
|
|
428
430
|
ax_beta.set_yticks([], [])
|
|
429
431
|
|
|
432
|
+
cbar = fig.colorbar(
|
|
433
|
+
im_beta, ax=[ax_alpha, ax_beta], orientation="vertical", shrink=0.8
|
|
434
|
+
)
|
|
435
|
+
cbar.set_label("Interaction count", rotation=270, labelpad=15)
|
|
436
|
+
|
|
430
437
|
if save_as is not None:
|
|
431
438
|
fig.savefig(save_as, bbox_inches="tight", dpi=200)
|
|
432
439
|
|
|
@@ -1130,9 +1130,11 @@ class TCRParser(PDBParser, MMCIFParser):
|
|
|
1130
1130
|
and len(mhc_complexes) > 0
|
|
1131
1131
|
): # check if all TCRs have been paired if MHC is present.
|
|
1132
1132
|
# try searching for symmetry mates
|
|
1133
|
-
|
|
1134
|
-
|
|
1135
|
-
|
|
1133
|
+
try:
|
|
1134
|
+
symmetry_mates = self._generate_symmetry_mates()
|
|
1135
|
+
mhc_complexes.extend([m for t in symmetry_mates for m in t.get_MHCs()])
|
|
1136
|
+
except Exception as e:
|
|
1137
|
+
warnings.warn(f"Symmetry mate generation failed with: {str(e)}")
|
|
1136
1138
|
(
|
|
1137
1139
|
model,
|
|
1138
1140
|
tcell_receptors,
|
|
@@ -35,33 +35,39 @@ def get_symmetry_mates(filename):
|
|
|
35
35
|
tcp = TCRParser()
|
|
36
36
|
pdp = PDBParser(QUIET=True)
|
|
37
37
|
pdbio = PDBIO()
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
)
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
chain
|
|
57
|
-
symmetry_mate
|
|
58
|
-
|
|
59
|
-
|
|
38
|
+
try:
|
|
39
|
+
with tempfile.TemporaryDirectory() as tmpdir:
|
|
40
|
+
for i, obj in enumerate(cmd.get_object_list()):
|
|
41
|
+
fn = os.path.join(tmpdir, f"{obj_name}_symmetry_mate_{i}.pdb")
|
|
42
|
+
cmd.save(fn, obj)
|
|
43
|
+
symmetry_mate = pdp.get_structure("tmp", fn)
|
|
44
|
+
if i == 0:
|
|
45
|
+
chain_ids = generate_chain_id_list(
|
|
46
|
+
len(
|
|
47
|
+
list(symmetry_mate.get_chains())
|
|
48
|
+
* len(cmd.get_object_list())
|
|
49
|
+
)
|
|
50
|
+
)
|
|
51
|
+
for c in symmetry_mate.get_chains():
|
|
52
|
+
chain_ids.remove(
|
|
53
|
+
c.id
|
|
54
|
+
) # remove all chain ids of the original structure
|
|
55
|
+
if i > 0: # Skip the original structure
|
|
56
|
+
# rename chain ids, this cannot be done directly to TCR structure without breaking the TCR and MHC chain assignments.
|
|
57
|
+
for chain in reversed(list(symmetry_mate.get_chains())):
|
|
58
|
+
symmetry_mate[0].detach_child(chain.id)
|
|
59
|
+
new_id = chain_ids.pop(0)
|
|
60
|
+
chain.id = new_id
|
|
61
|
+
symmetry_mate[0].add(chain)
|
|
62
|
+
pdbio.set_structure(symmetry_mate)
|
|
63
|
+
pdbio.save(fn)
|
|
60
64
|
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
+
symmetry_mate = tcp.get_tcr_structure(
|
|
66
|
+
f"{obj_name}_symmetry_{i}", fn, include_symmetry_mates=False
|
|
67
|
+
)
|
|
68
|
+
tcr_symmetry_mates.append(symmetry_mate)
|
|
69
|
+
except Exception as e:
|
|
70
|
+
warnings.warn(f"Symmetry mate generation failed with: {str(e)}")
|
|
65
71
|
|
|
66
72
|
# clean up the pymol cmd space
|
|
67
73
|
for obj in cmd.get_object_list():
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: stcrpy
|
|
3
|
-
Version: 1.0.
|
|
3
|
+
Version: 1.0.6
|
|
4
4
|
Summary: Set of methods to parse, annotate, and calculate features of TCR structures
|
|
5
5
|
Maintainer-email: Nele Quast <quast@stats.ox.ac.uk>
|
|
6
6
|
Requires-Python: >=3.10
|
|
@@ -12,6 +12,7 @@ Requires-Dist: numpy==1.26.4
|
|
|
12
12
|
Requires-Dist: lxml
|
|
13
13
|
Requires-Dist: openbabel-wheel==3.1.1.21
|
|
14
14
|
Requires-Dist: rdkit
|
|
15
|
+
Requires-Dist: pyhmmer==0.11.4
|
|
15
16
|
Requires-Dist: anarci-mhc
|
|
16
17
|
Requires-Dist: pandas
|
|
17
18
|
Requires-Dist: matplotlib
|
|
@@ -42,7 +43,7 @@ Please feel free to reach out with any comments or feedback.
|
|
|
42
43
|
|
|
43
44
|
Under review, please cite:
|
|
44
45
|
|
|
45
|
-
**Quast, N. , Deane, C., & Raybould, M. (2025). STCRpy: a software suite for TCR:pMHC structure parsing, interaction profiling, and machine learning dataset preparation.
|
|
46
|
+
**Quast, N. , Deane, C., & Raybould, M. (2025). STCRpy: a software suite for TCR:pMHC structure parsing, interaction profiling, and machine learning dataset preparation. Bioinformatics. [https://doi.org/10.1093/bioinformatics/btaf566](https://doi.org/10.1093/bioinformatics/btaf566)**
|
|
46
47
|
|
|
47
48
|
<img src="./stcrpy_main_fig.png" alt="drawing" width="1500"/>
|
|
48
49
|
|
|
@@ -22,13 +22,13 @@ class TestTCRDatasets(unittest.TestCase):
|
|
|
22
22
|
tcr = stcrpy.fetch_TCRs("8gvb")[0]
|
|
23
23
|
graph_constructor.build_graph(tcr)
|
|
24
24
|
|
|
25
|
-
def test_TCRGraphDataset(self):
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
25
|
+
# def test_TCRGraphDataset(self):
|
|
26
|
+
# dataset = TCRGraphDataset(
|
|
27
|
+
# root="./test_files/TCRGraphDataset_test_files",
|
|
28
|
+
# data_paths="./test_files/TCRGraphDataset_test_files/raw_files",
|
|
29
|
+
# force_reload=True,
|
|
30
|
+
# )
|
|
31
|
+
# print(dataset)
|
|
32
|
+
# for i in range(len(dataset)):
|
|
33
|
+
# datapoint = dataset[i]
|
|
34
|
+
# print(datapoint)
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import unittest
|
|
2
|
+
import glob
|
|
3
|
+
import os
|
|
4
|
+
|
|
5
|
+
import stcrpy.tcr_processing
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class TestTCRFormats(unittest.TestCase):
|
|
9
|
+
def test_tcr_to_haddock(self):
|
|
10
|
+
import stcrpy
|
|
11
|
+
|
|
12
|
+
tcrs = stcrpy.load_TCRs(
|
|
13
|
+
glob.glob("./test_files/TCRParser_test_files/*.pdb")
|
|
14
|
+
) + stcrpy.load_TCRs(glob.glob("./test_files/TCRParser_test_files/*.cif"))
|
|
15
|
+
|
|
16
|
+
from stcrpy.tcr_formats import tcr_haddock
|
|
17
|
+
|
|
18
|
+
haddock_formatter = tcr_haddock.HADDOCKFormatter("./test_files/out/haddock/")
|
|
19
|
+
for tcr in tcrs:
|
|
20
|
+
if tcr is not None:
|
|
21
|
+
haddock_formatter.tcr_to_haddock(tcr)
|
|
22
|
+
|
|
23
|
+
def test_pMHC_to_haddock(self):
|
|
24
|
+
import stcrpy
|
|
25
|
+
|
|
26
|
+
tcrs = stcrpy.load_TCRs(
|
|
27
|
+
glob.glob("./test_files/TCRParser_test_files/*.pdb")
|
|
28
|
+
) + stcrpy.load_TCRs(glob.glob("./test_files/TCRParser_test_files/*.cif"))
|
|
29
|
+
|
|
30
|
+
from stcrpy.tcr_formats import tcr_haddock
|
|
31
|
+
|
|
32
|
+
haddock_formatter = tcr_haddock.HADDOCKFormatter(
|
|
33
|
+
save_dir="./test_files/out/haddock/"
|
|
34
|
+
)
|
|
35
|
+
for tcr in tcrs:
|
|
36
|
+
if (
|
|
37
|
+
tcr is not None
|
|
38
|
+
and len(tcr.get_MHC()) > 0
|
|
39
|
+
and len(tcr.antigen) > 0
|
|
40
|
+
and isinstance(tcr.antigen[0], stcrpy.tcr_processing.AGchain.AGchain)
|
|
41
|
+
):
|
|
42
|
+
haddock_formatter.pMHC_to_haddock(tcr.get_MHC()[0], tcr.antigen)
|
|
43
|
+
|
|
44
|
+
# def test_from_haddock_to_TCR_pMHC(self):
|
|
45
|
+
# import stcrpy
|
|
46
|
+
# from stcrpy.tcr_formats import tcr_haddock
|
|
47
|
+
|
|
48
|
+
# haddock_results_parser = tcr_haddock.HADDOCKResultsParser(
|
|
49
|
+
# haddock_results_dir="./test_files/TCRHaddock_test_files/387937-tcr_6eqa_mel5_bulged",
|
|
50
|
+
# tcr_renumbering_file="./test_files/TCRHaddock_test_files/6eqa_TCR_haddock_renumbering.txt",
|
|
51
|
+
# pmhc_renumbering_file="./test_files/TCRHaddock_test_files/6eqa_pMHC_haddock_renumbering.txt",
|
|
52
|
+
# )
|
|
53
|
+
|
|
54
|
+
# for renumbered_file_path in glob.glob(
|
|
55
|
+
# "./test_files/TCRHaddock_test_files/haddock_output/renumbered_complex*.pdb"
|
|
56
|
+
# ):
|
|
57
|
+
# os.remove(renumbered_file_path)
|
|
58
|
+
|
|
59
|
+
# haddock_results_parser.renumber_all_haddock_predictions()
|
|
60
|
+
# for file_path in glob.glob(
|
|
61
|
+
# "./test_files/TCRHaddock_test_files/haddock_output/complex*.pdb"
|
|
62
|
+
# ):
|
|
63
|
+
# renumbered_file_path = (
|
|
64
|
+
# file_path.split("complex")[0]
|
|
65
|
+
# + "renumbered_complex"
|
|
66
|
+
# + file_path.split("complex")[1]
|
|
67
|
+
# )
|
|
68
|
+
# assert os.path.exists(renumbered_file_path)
|
|
69
|
+
|
|
70
|
+
# def test_get_haddock_scores(self):
|
|
71
|
+
# import stcrpy
|
|
72
|
+
# from stcrpy.tcr_formats import tcr_haddock
|
|
73
|
+
|
|
74
|
+
# haddock_results_parser = tcr_haddock.HADDOCKResultsParser(
|
|
75
|
+
# haddock_results_dir="./test_files/TCRHaddock_test_files/387937-tcr_6eqa_mel5_bulged",
|
|
76
|
+
# )
|
|
77
|
+
|
|
78
|
+
# scores = haddock_results_parser.get_haddock_scores()
|
|
79
|
+
# assert len(scores) == 200
|
|
@@ -0,0 +1,260 @@
|
|
|
1
|
+
import unittest
|
|
2
|
+
import glob
|
|
3
|
+
import numpy as np
|
|
4
|
+
|
|
5
|
+
import stcrpy
|
|
6
|
+
from stcrpy.tcr_processing import TCRParser
|
|
7
|
+
from stcrpy.tcr_geometry import TCRDock, TCRCoM, TCRGeom
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class TestTCRGeometry(unittest.TestCase):
|
|
11
|
+
def test_TCRDock_init(self):
|
|
12
|
+
tcr = stcrpy.fetch_TCRs("5hyj")
|
|
13
|
+
[TCRDock.TCRDock(x) for x in tcr]
|
|
14
|
+
|
|
15
|
+
def test_calculate_docking_angle_5hyj(self):
|
|
16
|
+
tcr = stcrpy.fetch_TCRs("5hyj")
|
|
17
|
+
|
|
18
|
+
tcr_docks = [TCRDock.TCRDock(x) for x in tcr]
|
|
19
|
+
assert all(
|
|
20
|
+
[
|
|
21
|
+
x.calculate_docking_angle() < 50.0
|
|
22
|
+
and x.calculate_docking_angle() > 40.0
|
|
23
|
+
for x in tcr_docks
|
|
24
|
+
]
|
|
25
|
+
)
|
|
26
|
+
|
|
27
|
+
# def test_calculate_docking_angle_7l1d(self):
|
|
28
|
+
# parser = TCRParser.TCRParser()
|
|
29
|
+
# pdb_file = "./test_files/7l1d.pdb"
|
|
30
|
+
# tcr = parser.get_tcr_structure("test", pdb_file)
|
|
31
|
+
# tcr = stcrpy.fetch_TCRs("7l1d")
|
|
32
|
+
|
|
33
|
+
# tcr_docks = [TCRDock.TCRDock(x) for x in tcr.get_TCRs()]
|
|
34
|
+
# assert all(
|
|
35
|
+
# [
|
|
36
|
+
# x.calculate_docking_angle() < 50.0
|
|
37
|
+
# and x.calculate_docking_angle() > 40.0
|
|
38
|
+
# for x in tcr_docks
|
|
39
|
+
# ]
|
|
40
|
+
# )
|
|
41
|
+
|
|
42
|
+
# def test_calculate_docking_angle_7rrg(self):
|
|
43
|
+
# # parser = TCRParser.TCRParser()
|
|
44
|
+
# # pdb_file = "./test_files/7rrg.pdb"
|
|
45
|
+
# # tcr = parser.get_tcr_structure("test", pdb_file)
|
|
46
|
+
# tcr = stcrpy.fetch_TCRs("7rrg")
|
|
47
|
+
|
|
48
|
+
# tcr_docks = [TCRDock.TCRDock(x) for x in tcr]
|
|
49
|
+
# angles = [x.calculate_docking_angle() for x in tcr_docks]
|
|
50
|
+
# print(angles)
|
|
51
|
+
# assert all(
|
|
52
|
+
# [
|
|
53
|
+
# x.calculate_docking_angle() < 80.0
|
|
54
|
+
# and x.calculate_docking_angle() > 70.0
|
|
55
|
+
# for x in tcr_docks
|
|
56
|
+
# ]
|
|
57
|
+
# )
|
|
58
|
+
|
|
59
|
+
def test_calculate_docking_angle_of_docks(self):
|
|
60
|
+
parser = TCRParser.TCRParser()
|
|
61
|
+
dock_pdb_files = glob.glob(
|
|
62
|
+
"./test_files/TCRHaddock_test_files/predictions/renumbered_complex*.pdb"
|
|
63
|
+
)
|
|
64
|
+
dock_pdb_files.sort()
|
|
65
|
+
for pdb_file in dock_pdb_files:
|
|
66
|
+
tcr = parser.get_tcr_structure("test", pdb_file)
|
|
67
|
+
[TCRDock.TCRDock(x) for x in tcr.get_TCRs()]
|
|
68
|
+
|
|
69
|
+
# def test_docking_angle_reverse_docks(self):
|
|
70
|
+
# parser = TCRParser.TCRParser()
|
|
71
|
+
# reverse_dock_108 = "./test_files/aligned_complex_108.pdb"
|
|
72
|
+
# dock_63 = "./test_files/aligned_complex_63.pdb"
|
|
73
|
+
# dock_pdb_files = [dock_63, reverse_dock_108]
|
|
74
|
+
# docking_angles = []
|
|
75
|
+
# for pdb_file in dock_pdb_files:
|
|
76
|
+
# tcr = parser.get_tcr_structure("test", pdb_file)
|
|
77
|
+
|
|
78
|
+
# tcr_docks = [TCRDock.TCRDock(x) for x in tcr.get_TCRs()]
|
|
79
|
+
# docking_angles.append(tcr_docks[0].calculate_docking_angle())
|
|
80
|
+
|
|
81
|
+
# print(docking_angles)
|
|
82
|
+
|
|
83
|
+
# def test_MH1_TCRCoM(self):
|
|
84
|
+
# parser = TCRParser.TCRParser()
|
|
85
|
+
# pdb_file = "./test_files/4nhu.pdb"
|
|
86
|
+
# tcr_structure = parser.get_tcr_structure("test", pdb_file)
|
|
87
|
+
# tcr_com = TCRCoM.MHCI_TCRCoM()
|
|
88
|
+
# # TEST DEPRECATED
|
|
89
|
+
# # for tcr in tcr_structure.get_TCRs():
|
|
90
|
+
# # r, theta, phi = tcr_com.calculate_geometry(
|
|
91
|
+
# # tcr,
|
|
92
|
+
# # save_aligned_as=f"./test_files/out/aligned_test_{tcr.id}.pdb",
|
|
93
|
+
# # )
|
|
94
|
+
# # print(r, theta, phi)
|
|
95
|
+
# # pdb_file = "./stcrpy/stcrpy/tcr_geometry/reference_data/dock_reference_1_imgt_numbered.pdb"
|
|
96
|
+
# # tcr_structure = parser.get_tcr_structure("test", pdb_file)
|
|
97
|
+
# # tcr_com = TCRCoM.MHCI_TCRCoM()
|
|
98
|
+
# # for tcr in tcr_structure.get_TCRs():
|
|
99
|
+
# # r, theta, phi = tcr_com.calculate_geometry(
|
|
100
|
+
# # tcr,
|
|
101
|
+
# # save_aligned_as=f"./test_files/out/aligned_test_dock_ref_mhcI_{tcr.id}.pdb",
|
|
102
|
+
# # )
|
|
103
|
+
# # print(r, theta, phi)
|
|
104
|
+
|
|
105
|
+
# def test_MH2_TCRCoM(self):
|
|
106
|
+
# parser = TCRParser.TCRParser()
|
|
107
|
+
# pdb_file = "./test_files/6r0e.cif"
|
|
108
|
+
# tcr_structure = parser.get_tcr_structure("test", pdb_file)
|
|
109
|
+
# tcr_com = TCRCoM.MHCII_TCRCoM()
|
|
110
|
+
# # TEST DEPRECATED
|
|
111
|
+
# # for tcr in tcr_structure.get_TCRs():
|
|
112
|
+
# # r, theta, phi = tcr_com.calculate_geometry(
|
|
113
|
+
# # tcr,
|
|
114
|
+
# # save_aligned_as=f"./test_files/out/aligned_test_{tcr.id}.pdb",
|
|
115
|
+
# # )
|
|
116
|
+
|
|
117
|
+
# # pdb_file = (
|
|
118
|
+
# # "./stcrpy/stcrpy/tcr_geometry/include/dock_reference_2_imgt_numbered.pdb"
|
|
119
|
+
# # )
|
|
120
|
+
# # tcr_structure = parser.get_tcr_structure("test", pdb_file)
|
|
121
|
+
# # tcr_com = TCRCoM.MHCII_TCRCoM()
|
|
122
|
+
# # for tcr in tcr_structure.get_TCRs():
|
|
123
|
+
# # r, theta, phi = tcr_com.calculate_geometry(
|
|
124
|
+
# # tcr,
|
|
125
|
+
# # save_aligned_as=f"./test_files/out/aligned_test_dock_ref_mhcII_{tcr.id}.pdb",
|
|
126
|
+
# # )
|
|
127
|
+
# # print(r, theta, phi)
|
|
128
|
+
|
|
129
|
+
def testTCRGeom(self):
|
|
130
|
+
parser = TCRParser.TCRParser()
|
|
131
|
+
pdb_files = glob.glob("./test_files/TCRCoM_test_files/*.cif")
|
|
132
|
+
# 'TCRpy/test/test_files/TCRCoM_test_files/7sg0.cif')
|
|
133
|
+
for file in pdb_files:
|
|
134
|
+
file_id = file.split("/")[-1].split(".")[0]
|
|
135
|
+
print(file_id)
|
|
136
|
+
tcr = parser.get_tcr_structure(file_id, file)
|
|
137
|
+
for x in tcr.get_TCRs():
|
|
138
|
+
try:
|
|
139
|
+
x.geometry = TCRGeom.TCRGeom(
|
|
140
|
+
x,
|
|
141
|
+
save_aligned_as=f"./test_files/out/{file_id}_aligned.pdb",
|
|
142
|
+
)
|
|
143
|
+
print(x.geometry)
|
|
144
|
+
except Exception as e:
|
|
145
|
+
print(e)
|
|
146
|
+
|
|
147
|
+
# def test_TCR_geom_methods(self):
|
|
148
|
+
# parser = TCRParser.TCRParser()
|
|
149
|
+
# test_file = "./test_files/8gvb.cif"
|
|
150
|
+
# tcr = list(parser.get_tcr_structure("8gvb", test_file).get_TCRs())[0]
|
|
151
|
+
# geometry = tcr.calculate_docking_geometry()
|
|
152
|
+
# assert "scanning_angle" in geometry
|
|
153
|
+
|
|
154
|
+
# def test_calculate_docking_angle_cys_method(self):
|
|
155
|
+
# import stcrpy
|
|
156
|
+
|
|
157
|
+
# pdb_files = [
|
|
158
|
+
# "./test_files/5hyj.pdb",
|
|
159
|
+
# "./test_files/7l1d.pdb",
|
|
160
|
+
# "./test_files/7rrg.pdb",
|
|
161
|
+
# ]
|
|
162
|
+
# tcrs = stcrpy.load_TCRs(pdb_files)
|
|
163
|
+
|
|
164
|
+
# true_scanning_angles = [
|
|
165
|
+
# 42.9581,
|
|
166
|
+
# 47.4101,
|
|
167
|
+
# 47.4101,
|
|
168
|
+
# 73.7909,
|
|
169
|
+
# ] # [5hyj, 7l1d, 7rrg] - repeat value is for TCR repeats in PDB file parsed as independent TCR structures
|
|
170
|
+
# true_pitch_angles = [12.3062, 3.46555, 3.46555, 12.0141]
|
|
171
|
+
|
|
172
|
+
# cys_crossing_angles = []
|
|
173
|
+
# com_crossing_angles = []
|
|
174
|
+
# for i, tcr in enumerate(tcrs):
|
|
175
|
+
# cys_crossing_angles.append(tcr.get_scanning_angle(mode="cys"))
|
|
176
|
+
# com_crossing_angles.append(tcr.get_scanning_angle(mode="com"))
|
|
177
|
+
|
|
178
|
+
# self.assertTrue(
|
|
179
|
+
# np.sum(
|
|
180
|
+
# np.abs(
|
|
181
|
+
# np.asarray(cys_crossing_angles) - np.asarray(true_scanning_angles)
|
|
182
|
+
# )
|
|
183
|
+
# )
|
|
184
|
+
# / len(cys_crossing_angles)
|
|
185
|
+
# < 1.5
|
|
186
|
+
# )
|
|
187
|
+
|
|
188
|
+
# # pitch = tcr.get_pitch_angle()
|
|
189
|
+
# # self.assertAlmostEqual(pitch, true_pitch_angles[i])
|
|
190
|
+
|
|
191
|
+
# def test_calculate_docking_angle_com_method(self):
|
|
192
|
+
# import stcrpy
|
|
193
|
+
|
|
194
|
+
# pdb_files = [
|
|
195
|
+
# "./test_files/5hyj.pdb",
|
|
196
|
+
# "./test_files/7l1d.pdb",
|
|
197
|
+
# "./test_files/7rrg.pdb",
|
|
198
|
+
# ]
|
|
199
|
+
# tcrs = stcrpy.load_TCRs(pdb_files)
|
|
200
|
+
|
|
201
|
+
# true_scanning_angles = [42.9581, 47.4101, 73.7909] # [5hyj, 7l1d, 7rrg]
|
|
202
|
+
# true_pitch_angles = [12.3062, 3.46555, 12.0141]
|
|
203
|
+
# for i, tcr in enumerate(tcrs):
|
|
204
|
+
# crossing_angle = tcr.get_scanning_angle(mode="com")
|
|
205
|
+
# self.assertAlmostEqual(
|
|
206
|
+
# crossing_angle,
|
|
207
|
+
# true_scanning_angles[i],
|
|
208
|
+
# )
|
|
209
|
+
# pitch = tcr.get_pitch_angle()
|
|
210
|
+
# self.assertAlmostEqual(pitch, true_pitch_angles[i])
|
|
211
|
+
|
|
212
|
+
def test_get_alpha_helices(self):
|
|
213
|
+
import stcrpy
|
|
214
|
+
|
|
215
|
+
tcrs = stcrpy.load_TCRs(glob.glob("test_files/TCRCoM_test_files/*.cif"))
|
|
216
|
+
|
|
217
|
+
for tcr in tcrs:
|
|
218
|
+
if (
|
|
219
|
+
len(tcr.get_MHC()) == 1
|
|
220
|
+
and hasattr(tcr.get_MHC()[0], "MHC_type")
|
|
221
|
+
and tcr.get_MHC()[0].MHC_type in ["MH1", "MH2"]
|
|
222
|
+
):
|
|
223
|
+
tcr_geom = TCRGeom.TCRGeom(tcr)
|
|
224
|
+
# since tcr should be aligned to reference MHC mhc vector should be approximately [0, 1, 0]
|
|
225
|
+
self.assertAlmostEqual(
|
|
226
|
+
np.dot(
|
|
227
|
+
tcr_geom._get_mhc_helix_vectors(tcr.get_MHC()[0]),
|
|
228
|
+
np.asarray([0, 1, 0]),
|
|
229
|
+
),
|
|
230
|
+
1,
|
|
231
|
+
places=1,
|
|
232
|
+
)
|
|
233
|
+
|
|
234
|
+
def test_rudolph_scanning_angle(self):
|
|
235
|
+
import stcrpy
|
|
236
|
+
|
|
237
|
+
tcrs = stcrpy.load_TCRs(
|
|
238
|
+
glob.glob("test_files/TCRGeom_rudolph_test_files/*.cif")
|
|
239
|
+
)
|
|
240
|
+
|
|
241
|
+
rudolph_scanning_angles = {
|
|
242
|
+
"2ckb": 22,
|
|
243
|
+
"1g6r": 23,
|
|
244
|
+
"1mwa": 23,
|
|
245
|
+
"1fo0": 41,
|
|
246
|
+
"1nam": 40,
|
|
247
|
+
"1kj2": 31,
|
|
248
|
+
"1bd2": 48,
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
for tcr in tcrs:
|
|
252
|
+
tcr_geom = TCRGeom.TCRGeom(tcr, mode="rudolph")
|
|
253
|
+
|
|
254
|
+
assert (
|
|
255
|
+
abs(
|
|
256
|
+
np.degrees(tcr_geom.scanning_angle)
|
|
257
|
+
- rudolph_scanning_angles[tcr.parent.parent.id]
|
|
258
|
+
)
|
|
259
|
+
< 3.0
|
|
260
|
+
)
|