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.
Files changed (96) hide show
  1. {stcrpy-1.0.5 → stcrpy-1.0.6}/PKG-INFO +3 -2
  2. {stcrpy-1.0.5 → stcrpy-1.0.6}/README.md +1 -1
  3. {stcrpy-1.0.5 → stcrpy-1.0.6}/pyproject.toml +3 -2
  4. {stcrpy-1.0.5 → stcrpy-1.0.6}/stcrpy/tcr_interactions/TCRInteractionProfiler.py +8 -1
  5. {stcrpy-1.0.5 → stcrpy-1.0.6}/stcrpy/tcr_processing/TCRParser.py +5 -3
  6. {stcrpy-1.0.5 → stcrpy-1.0.6}/stcrpy/tcr_processing/utils/symmetry_mates.py +32 -26
  7. {stcrpy-1.0.5 → stcrpy-1.0.6}/stcrpy.egg-info/PKG-INFO +3 -2
  8. {stcrpy-1.0.5 → stcrpy-1.0.6}/stcrpy.egg-info/SOURCES.txt +0 -1
  9. {stcrpy-1.0.5 → stcrpy-1.0.6}/stcrpy.egg-info/requires.txt +1 -0
  10. {stcrpy-1.0.5 → stcrpy-1.0.6}/test/test_tcr_datasets.py +10 -10
  11. stcrpy-1.0.6/test/test_tcr_formats.py +79 -0
  12. stcrpy-1.0.6/test/test_tcr_geometry.py +260 -0
  13. {stcrpy-1.0.5 → stcrpy-1.0.6}/test/test_tcr_interactions.py +17 -48
  14. {stcrpy-1.0.5 → stcrpy-1.0.6}/test/test_tcr_metrics.py +4 -12
  15. {stcrpy-1.0.5 → stcrpy-1.0.6}/test/test_tcr_processing.py +59 -121
  16. {stcrpy-1.0.5 → stcrpy-1.0.6}/test/test_tcr_sequence_operations.py +1 -1
  17. stcrpy-1.0.5/test/test_symmetry_mates.py +0 -11
  18. stcrpy-1.0.5/test/test_tcr_formats.py +0 -79
  19. stcrpy-1.0.5/test/test_tcr_geometry.py +0 -259
  20. {stcrpy-1.0.5 → stcrpy-1.0.6}/LICENCE +0 -0
  21. {stcrpy-1.0.5 → stcrpy-1.0.6}/examples/__init__.py +0 -0
  22. {stcrpy-1.0.5 → stcrpy-1.0.6}/examples/egnn.py +0 -0
  23. {stcrpy-1.0.5 → stcrpy-1.0.6}/setup.cfg +0 -0
  24. {stcrpy-1.0.5 → stcrpy-1.0.6}/stcrpy/__init__.py +0 -0
  25. {stcrpy-1.0.5 → stcrpy-1.0.6}/stcrpy/tcr_datasets/__init__.py +0 -0
  26. {stcrpy-1.0.5 → stcrpy-1.0.6}/stcrpy/tcr_datasets/tcr_graph_dataset.py +0 -0
  27. {stcrpy-1.0.5 → stcrpy-1.0.6}/stcrpy/tcr_datasets/tcr_selector.py +0 -0
  28. {stcrpy-1.0.5 → stcrpy-1.0.6}/stcrpy/tcr_datasets/tcr_structure_dataset.py +0 -0
  29. {stcrpy-1.0.5 → stcrpy-1.0.6}/stcrpy/tcr_datasets/utils.py +0 -0
  30. {stcrpy-1.0.5 → stcrpy-1.0.6}/stcrpy/tcr_formats/__init__.py +0 -0
  31. {stcrpy-1.0.5 → stcrpy-1.0.6}/stcrpy/tcr_formats/tcr_formats.py +0 -0
  32. {stcrpy-1.0.5 → stcrpy-1.0.6}/stcrpy/tcr_formats/tcr_haddock.py +0 -0
  33. {stcrpy-1.0.5 → stcrpy-1.0.6}/stcrpy/tcr_geometry/TCRAngle.py +0 -0
  34. {stcrpy-1.0.5 → stcrpy-1.0.6}/stcrpy/tcr_geometry/TCRCoM.py +0 -0
  35. {stcrpy-1.0.5 → stcrpy-1.0.6}/stcrpy/tcr_geometry/TCRCoM_LICENCE +0 -0
  36. {stcrpy-1.0.5 → stcrpy-1.0.6}/stcrpy/tcr_geometry/TCRDock.py +0 -0
  37. {stcrpy-1.0.5 → stcrpy-1.0.6}/stcrpy/tcr_geometry/TCRGeom.py +0 -0
  38. {stcrpy-1.0.5 → stcrpy-1.0.6}/stcrpy/tcr_geometry/TCRGeomFiltering.py +0 -0
  39. {stcrpy-1.0.5 → stcrpy-1.0.6}/stcrpy/tcr_geometry/__init__.py +0 -0
  40. {stcrpy-1.0.5 → stcrpy-1.0.6}/stcrpy/tcr_geometry/reference_data/Acoreset.txt +0 -0
  41. {stcrpy-1.0.5 → stcrpy-1.0.6}/stcrpy/tcr_geometry/reference_data/Bcoreset.txt +0 -0
  42. {stcrpy-1.0.5 → stcrpy-1.0.6}/stcrpy/tcr_geometry/reference_data/__init__.py +0 -0
  43. {stcrpy-1.0.5 → stcrpy-1.0.6}/stcrpy/tcr_geometry/reference_data/consensus_A.pdb +0 -0
  44. {stcrpy-1.0.5 → stcrpy-1.0.6}/stcrpy/tcr_geometry/reference_data/consensus_B.pdb +0 -0
  45. {stcrpy-1.0.5 → stcrpy-1.0.6}/stcrpy/tcr_geometry/reference_data/consensus_D.pdb +0 -0
  46. {stcrpy-1.0.5 → stcrpy-1.0.6}/stcrpy/tcr_geometry/reference_data/consensus_G.pdb +0 -0
  47. {stcrpy-1.0.5 → stcrpy-1.0.6}/stcrpy/tcr_geometry/reference_data/dock_reference_1_imgt_numbered.pdb +0 -0
  48. {stcrpy-1.0.5 → stcrpy-1.0.6}/stcrpy/tcr_geometry/reference_data/dock_reference_2_imgt_numbered.pdb +0 -0
  49. {stcrpy-1.0.5 → stcrpy-1.0.6}/stcrpy/tcr_geometry/reference_data/pcA.txt +0 -0
  50. {stcrpy-1.0.5 → stcrpy-1.0.6}/stcrpy/tcr_geometry/reference_data/pcB.txt +0 -0
  51. {stcrpy-1.0.5 → stcrpy-1.0.6}/stcrpy/tcr_geometry/reference_data/reference_A.pdb +0 -0
  52. {stcrpy-1.0.5 → stcrpy-1.0.6}/stcrpy/tcr_geometry/reference_data/reference_B.pdb +0 -0
  53. {stcrpy-1.0.5 → stcrpy-1.0.6}/stcrpy/tcr_geometry/reference_data/reference_D.pdb +0 -0
  54. {stcrpy-1.0.5 → stcrpy-1.0.6}/stcrpy/tcr_geometry/reference_data/reference_G.pdb +0 -0
  55. {stcrpy-1.0.5 → stcrpy-1.0.6}/stcrpy/tcr_geometry/reference_data/reference_data.py +0 -0
  56. {stcrpy-1.0.5 → stcrpy-1.0.6}/stcrpy/tcr_interactions/PLIPParser.py +0 -0
  57. {stcrpy-1.0.5 → stcrpy-1.0.6}/stcrpy/tcr_interactions/TCRpMHC_PLIP_Model_Parser.py +0 -0
  58. {stcrpy-1.0.5 → stcrpy-1.0.6}/stcrpy/tcr_interactions/__init__.py +0 -0
  59. {stcrpy-1.0.5 → stcrpy-1.0.6}/stcrpy/tcr_interactions/utils.py +0 -0
  60. {stcrpy-1.0.5 → stcrpy-1.0.6}/stcrpy/tcr_methods/__init__.py +0 -0
  61. {stcrpy-1.0.5 → stcrpy-1.0.6}/stcrpy/tcr_methods/tcr_batch_operations.py +0 -0
  62. {stcrpy-1.0.5 → stcrpy-1.0.6}/stcrpy/tcr_methods/tcr_methods.py +0 -0
  63. {stcrpy-1.0.5 → stcrpy-1.0.6}/stcrpy/tcr_methods/tcr_reformatting.py +0 -0
  64. {stcrpy-1.0.5 → stcrpy-1.0.6}/stcrpy/tcr_metrics/__init__.py +0 -0
  65. {stcrpy-1.0.5 → stcrpy-1.0.6}/stcrpy/tcr_metrics/constants.py +0 -0
  66. {stcrpy-1.0.5 → stcrpy-1.0.6}/stcrpy/tcr_metrics/tcr_dockq.py +0 -0
  67. {stcrpy-1.0.5 → stcrpy-1.0.6}/stcrpy/tcr_metrics/tcr_interface_rmsd.py +0 -0
  68. {stcrpy-1.0.5 → stcrpy-1.0.6}/stcrpy/tcr_metrics/tcr_rmsd.py +0 -0
  69. {stcrpy-1.0.5 → stcrpy-1.0.6}/stcrpy/tcr_ml/__init__.py +0 -0
  70. {stcrpy-1.0.5 → stcrpy-1.0.6}/stcrpy/tcr_ml/geometry_predictor.py +0 -0
  71. {stcrpy-1.0.5 → stcrpy-1.0.6}/stcrpy/tcr_processing/AGchain.py +0 -0
  72. {stcrpy-1.0.5 → stcrpy-1.0.6}/stcrpy/tcr_processing/Chemical_components.py +0 -0
  73. {stcrpy-1.0.5 → stcrpy-1.0.6}/stcrpy/tcr_processing/Entity.py +0 -0
  74. {stcrpy-1.0.5 → stcrpy-1.0.6}/stcrpy/tcr_processing/Fragment.py +0 -0
  75. {stcrpy-1.0.5 → stcrpy-1.0.6}/stcrpy/tcr_processing/Holder.py +0 -0
  76. {stcrpy-1.0.5 → stcrpy-1.0.6}/stcrpy/tcr_processing/MHC.py +0 -0
  77. {stcrpy-1.0.5 → stcrpy-1.0.6}/stcrpy/tcr_processing/MHCchain.py +0 -0
  78. {stcrpy-1.0.5 → stcrpy-1.0.6}/stcrpy/tcr_processing/Model.py +0 -0
  79. {stcrpy-1.0.5 → stcrpy-1.0.6}/stcrpy/tcr_processing/Select.py +0 -0
  80. {stcrpy-1.0.5 → stcrpy-1.0.6}/stcrpy/tcr_processing/TCR.py +0 -0
  81. {stcrpy-1.0.5 → stcrpy-1.0.6}/stcrpy/tcr_processing/TCRIO.py +0 -0
  82. {stcrpy-1.0.5 → stcrpy-1.0.6}/stcrpy/tcr_processing/TCRStructure.py +0 -0
  83. {stcrpy-1.0.5 → stcrpy-1.0.6}/stcrpy/tcr_processing/TCRchain.py +0 -0
  84. {stcrpy-1.0.5 → stcrpy-1.0.6}/stcrpy/tcr_processing/__init__.py +0 -0
  85. {stcrpy-1.0.5 → stcrpy-1.0.6}/stcrpy/tcr_processing/annotate.py +0 -0
  86. {stcrpy-1.0.5 → stcrpy-1.0.6}/stcrpy/tcr_processing/utils/__init__.py +0 -0
  87. {stcrpy-1.0.5 → stcrpy-1.0.6}/stcrpy/tcr_processing/utils/common.py +0 -0
  88. {stcrpy-1.0.5 → stcrpy-1.0.6}/stcrpy/tcr_processing/utils/constants.py +0 -0
  89. {stcrpy-1.0.5 → stcrpy-1.0.6}/stcrpy/tcr_processing/utils/region_definitions.py +0 -0
  90. {stcrpy-1.0.5 → stcrpy-1.0.6}/stcrpy/utils/__init__.py +0 -0
  91. {stcrpy-1.0.5 → stcrpy-1.0.6}/stcrpy/utils/error_stream.py +0 -0
  92. {stcrpy-1.0.5 → stcrpy-1.0.6}/stcrpy.egg-info/dependency_links.txt +0 -0
  93. {stcrpy-1.0.5 → stcrpy-1.0.6}/stcrpy.egg-info/top_level.txt +0 -0
  94. {stcrpy-1.0.5 → stcrpy-1.0.6}/test/test_annotations.py +0 -0
  95. {stcrpy-1.0.5 → stcrpy-1.0.6}/test/test_tcr_geometry_filters.py +0 -0
  96. {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.5
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. BioRxiv. https://doi.org/10.1101/2025.04.25.650667**
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. BioRxiv. https://doi.org/10.1101/2025.04.25.650667**
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.5"
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
- ax_beta.imshow(heatmap_b.T, cmap="PuRd")
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
- symmetry_mates = self._generate_symmetry_mates()
1134
- mhc_complexes.extend([m for t in symmetry_mates for m in t.get_MHCs()])
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
- with tempfile.TemporaryDirectory() as tmpdir:
39
- for i, obj in enumerate(cmd.get_object_list()):
40
- fn = os.path.join(tmpdir, f"{obj_name}_symmetry_mate_{i}.pdb")
41
- cmd.save(fn, obj)
42
- symmetry_mate = pdp.get_structure("tmp", fn)
43
- if i == 0:
44
- chain_ids = generate_chain_id_list(
45
- len(list(symmetry_mate.get_chains()) * len(cmd.get_object_list()))
46
- )
47
- for c in symmetry_mate.get_chains():
48
- chain_ids.remove(
49
- c.id
50
- ) # remove all chain ids of the original structure
51
- if i > 0: # Skip the original structure
52
- # rename chain ids, this cannot be done directly to TCR structure without breaking the TCR and MHC chain assignments.
53
- for chain in reversed(list(symmetry_mate.get_chains())):
54
- symmetry_mate[0].detach_child(chain.id)
55
- new_id = chain_ids.pop(0)
56
- chain.id = new_id
57
- symmetry_mate[0].add(chain)
58
- pdbio.set_structure(symmetry_mate)
59
- pdbio.save(fn)
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
- symmetry_mate = tcp.get_tcr_structure(
62
- f"{obj_name}_symmetry_{i}", fn, include_symmetry_mates=False
63
- )
64
- tcr_symmetry_mates.append(symmetry_mate)
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.5
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. BioRxiv. https://doi.org/10.1101/2025.04.25.650667**
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
 
@@ -80,7 +80,6 @@ stcrpy/tcr_processing/utils/symmetry_mates.py
80
80
  stcrpy/utils/__init__.py
81
81
  stcrpy/utils/error_stream.py
82
82
  test/test_annotations.py
83
- test/test_symmetry_mates.py
84
83
  test/test_tcr_datasets.py
85
84
  test/test_tcr_formats.py
86
85
  test/test_tcr_geometry.py
@@ -3,6 +3,7 @@ numpy==1.26.4
3
3
  lxml
4
4
  openbabel-wheel==3.1.1.21
5
5
  rdkit
6
+ pyhmmer==0.11.4
6
7
  anarci-mhc
7
8
  pandas
8
9
  matplotlib
@@ -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
- 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)
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
+ )