stcrpy 1.0.0__py3-none-any.whl → 1.0.3__py3-none-any.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.
@@ -21,7 +21,10 @@ class TCRDock(object):
21
21
  def __init__(self, tcr, QUIET=False):
22
22
  """
23
23
  Calculate the docking angle between TCR and pMHC.
24
- @param TCR: input a TCR object (abTCR or gdTCR or dbTCR).
24
+
25
+ Args:
26
+ tcr (TCR): TCR input
27
+ QUIET (bool, optional): Verbosity of error stream. Defaults to False.
25
28
  """
26
29
  self.warnings = ErrorStream()
27
30
  self.QUIET = QUIET
@@ -38,9 +38,30 @@ class TCRpMHC_PLIP_Model_Parser:
38
38
  ligand = PDB.Model.Model(id=0)
39
39
 
40
40
  peptide_chain = tcr_pmhc_complex.antigen
41
+ if len(peptide_chain) != 1:
42
+ # try to identify correct antigen
43
+ # if a chain is longer than 25 residues reject it, this may happen if anarci has failed to label an MHC chain
44
+ peptide_chain = [
45
+ c
46
+ for c in peptide_chain
47
+ if (
48
+ len(c) < 25
49
+ and isinstance(c, PDB.Chain.Chain)
50
+ or isinstance(c, PDB.Residue.Residue)
51
+ )
52
+ ]
53
+
41
54
  assert (
42
55
  len(peptide_chain) == 1
43
56
  ), f"More or less than one peptide chain found: {peptide_chain}"
57
+
58
+ if isinstance(
59
+ peptide_chain[0], PDB.Residue.Residue
60
+ ): # wrap single residue antigen in chain
61
+ residue_as_chain = PDB.Chain.Chain(id="Z")
62
+ residue_as_chain.add(peptide_chain[0].copy())
63
+ peptide_chain = [residue_as_chain]
64
+
44
65
  ligand.add(peptide_chain[0].copy())
45
66
 
46
67
  tcr_and_mhc_chains = [
@@ -48761,10 +48761,10 @@ def is_common_buffer(residue):
48761
48761
  Is the residue a common buffer?
48762
48762
  If it occurs in the L{common buffers<common_buffers>} list it is considered a common buffer.
48763
48763
 
48764
- @param residue: A AbPDB residue object or residues identifier e.g. PO4
48765
-
48766
- @return: Flag if the residue is a common buffer.
48767
- @rtype: C{bool}
48764
+ Args:
48765
+ residue: A AbPDB residue object or residues identifier e.g. PO4
48766
+ Returns:
48767
+ Flag if the residue is a common buffer.
48768
48768
  """
48769
48769
  if not isinstance(residue, str):
48770
48770
  residue = residue.get_resname()
@@ -81,8 +81,9 @@ class Entity(Bio.PDB.Entity.Entity):
81
81
  def _get_output_string(self, selection, n):
82
82
  """
83
83
  Method to get the atom lines of the entity's children.
84
- @param selection: Selector object from TcrPDB.Select or inherited class.
85
- @param n: An integer value to number the current atom with.
84
+ Args:
85
+ selection: Selector object from TcrPDB.Select or inherited class.
86
+ n: An integer value to number the current atom with.
86
87
  If this is False the original numbering is used from the pdb file.
87
88
  """
88
89
  output_string = ""
@@ -102,23 +103,24 @@ class Entity(Bio.PDB.Entity.Entity):
102
103
 
103
104
  def save(self, output=sys.stdout, renumber=True, selection=False, remarks=True):
104
105
  """
105
- Save the coordinates of the entity
106
+ Save the coordinates of the entity.
107
+ Example:
108
+ entity.save("path/to/file/filename.pdb")
109
+ residue.save( "residue1.pdb" )
106
110
 
107
- @param output: Where to write coordinates to. Should be an an open file, string or sys.stdout.
111
+ Args:
112
+ output: Where to write coordinates to. Should be an an open file, string or sys.stdout.
108
113
  By default the output is written to stdout
109
- @param renumber: Flag whether to renumber the atoms to IMGT scheme
114
+ renumber: Flag whether to renumber the atoms to IMGT scheme
110
115
  Default is to renumber the atoms so that the first is 1 etc.
111
116
  Use renumber = False to retain the original atom numbering from the pdb file
112
117
 
113
- @param selection: Provide a selector object to select which children of the entity should be outputted.
118
+ selection: Provide a selector object to select which children of the entity should be outputted.
114
119
  Selection should be a selector object from TcrPDB.Select.
115
120
  Some basic selector classes are provided in the module. More complex classes can be created by inheriting from these.
116
121
  If selection = False (default) all atoms in the entity are output
117
122
 
118
- @param remarks: Flag to print out remarks generated by TcrPDB. Default TRUE
119
- Example:
120
- entity.save("path/to/file/filename.pdb")
121
- residue.save( "residue1.pdb" )
123
+ remarks: Flag to print out remarks generated by TcrPDB. Default TRUE
122
124
  """
123
125
 
124
126
  def ag_chain_and_type(ags):
@@ -264,12 +266,9 @@ class Entity(Bio.PDB.Entity.Entity):
264
266
  >>> rotation=rotmat(pi, Vector(1,0,0))
265
267
  >>> translation=array((0,0,1), 'f')
266
268
  >>> entity.transform(rotation, translation)
267
-
268
- @param rot: A right multiplying rotation matrix
269
- @type rot: 3x3 Numeric array
270
-
271
- @param tran: the translation vector
272
- @type tran: size 3 Numeric array
269
+ Args:
270
+ rot: A right multiplying rotation matrix (3x3 Numeric array)
271
+ tran: the translation vector (size 3 Numeric array)
273
272
  """
274
273
 
275
274
  for o in self.get_list():
@@ -447,3 +447,70 @@ class scCD1(MHC):
447
447
 
448
448
  def get_B2M(self):
449
449
  return None
450
+
451
+
452
+ class scMH2(MHC):
453
+ """
454
+ Single chain MHC class 2.
455
+ Holds single GA or GB chain.
456
+ Usually this will only occur if ANARCI has not been identified one of the two chains correctly.
457
+ """
458
+
459
+ def __init__(self, c1):
460
+ assert c1.chain_type in [
461
+ "GA",
462
+ "GB",
463
+ ], f"Chain {c1} with can not form a single chain MHC class I."
464
+ Entity.__init__(self, c1.id)
465
+
466
+ self.level = "H"
467
+ self._add_domain(c1)
468
+ self._set_MHC_type()
469
+ self.child_list = sorted(self.child_list, key=lambda x: x.id)
470
+ self.antigen = []
471
+ self.tcr = []
472
+ self.engineered = False
473
+
474
+ def __repr__(self):
475
+ if self.MHC_type == "MH2":
476
+ if hasattr(self, "GA"):
477
+ return "<%s %s GA=%s>" % (
478
+ self.MHC_type,
479
+ self.GA,
480
+ self.GA,
481
+ )
482
+ elif hasattr(self, "GB"):
483
+ return "<%s %s GB=%s>" % (
484
+ self.MHC_type,
485
+ self.GB,
486
+ self.GB,
487
+ )
488
+
489
+ else:
490
+ if hasattr(self, "GA"):
491
+ return "<GA %s GA=%s>" % (self.GA, self.GA)
492
+ elif hasattr(self, "GB"):
493
+ return "<GB %s GB=%s>" % (self.GB, self.GB)
494
+
495
+ def _set_MHC_type(self):
496
+ if hasattr(self, "GA") and hasattr(self, "GB"):
497
+ self.MHC_type = "MH2"
498
+ else:
499
+ self.MHC_type = ""
500
+
501
+ def _add_domain(self, chain):
502
+ if chain.chain_type == "GA":
503
+ self.GA = chain.id
504
+ elif chain.chain_type == "GB":
505
+ self.GB = chain.id
506
+
507
+ # Add the chain as a child of this entity.
508
+ self.add(chain)
509
+
510
+ def get_GA(self):
511
+ if hasattr(self, "GA"):
512
+ return self.child_dict[self.GA]
513
+
514
+ def get_GB(self):
515
+ if hasattr(self, "GB"):
516
+ return self.child_dict[self.GB]
@@ -1,6 +1,6 @@
1
1
  """
2
2
  Created on 3rd April 2024
3
- @author: Nele Quast based on work by Dunbar and Leem
3
+ Nele Quast based on work by Dunbar and Leem
4
4
  The TCR class.
5
5
  """
6
6
 
@@ -20,15 +20,28 @@ except ImportError as e:
20
20
 
21
21
  class TCR(Entity):
22
22
  """
23
- TCR class. This is generic which is inherited later.
24
- Holds paired TCR chains.
23
+ TCR class. Inherits from PDB.Entity.
24
+ This is a base class for TCR strucutres, enabling antigen and MHC association.
25
+ abTCR and gdTCR are the instantiated subclasses of this class.
25
26
  """
26
27
 
27
28
  def _add_antigen(self, antigen=None):
29
+ """
30
+ Append associated antigen to TCR antigen field.
31
+
32
+ Args:
33
+ antigen (Antigen, optional): Antigen to associate with TCR. Defaults to None.
34
+ """
28
35
  if antigen not in self.antigen:
29
36
  self.antigen.append(antigen)
30
37
 
31
38
  def _add_mhc(self, mhc=None):
39
+ """
40
+ Append associated MHC to TCR MHC field. If antigen are associted with MHC but not TCR, add them to TCR antigen.
41
+
42
+ Args:
43
+ mhc (MHC, optional): MHC to associate with TCR. Defaults to None.
44
+ """
32
45
  if mhc not in self.MHC:
33
46
  self.MHC.append(mhc)
34
47
  # If there are any het antigens that are in the MHC but not in close proximity of the TCR
@@ -38,17 +51,21 @@ class TCR(Entity):
38
51
 
39
52
  def get_antigen(self):
40
53
  """
41
- Return a list of bound antigens.
54
+ Return a list of TCR associated antigens.
42
55
  """
43
56
  return self.antigen
44
57
 
45
58
  def get_MHC(self):
46
- """ """
59
+ """
60
+ Return a list of TCR associated MHCs.
61
+ """
47
62
  return self.MHC
48
63
 
49
64
  def is_bound(self):
50
- """
51
- Check whether this TCR is bound to an antigen
65
+ """True or False if the TCR is associated with an antigen.
66
+
67
+ Returns:
68
+ bool: Whether TCR is associated with an antigen.
52
69
  """
53
70
  if self.get_antigen():
54
71
  return True
@@ -56,22 +73,40 @@ class TCR(Entity):
56
73
  return False
57
74
 
58
75
  def get_chains(self):
76
+ """Returns generator of TCR chains.
77
+
78
+ Yields:
79
+ Chain: TCR chain
80
+ """
59
81
  for c in self:
60
82
  yield c
61
83
 
62
84
  def get_residues(self):
85
+ """Returns generator of TCR residues.
86
+
87
+ Yields:
88
+ Residue: TCR residue
89
+ """
63
90
  for c in self.get_chains():
64
91
  for r in c:
65
92
  yield r
66
93
 
67
94
  def get_atoms(self):
95
+ """Returns generator of TCR atoms.
96
+
97
+ Yields:
98
+ Atom: TCR atoms
99
+ """
68
100
  for r in self.get_residues():
69
101
  for a in r:
70
102
  yield a
71
103
 
72
104
  def get_frameworks(self):
73
105
  """
74
- Obtain framework regions from a TCR structure object.
106
+ Obtain framework regions from a TCR structure object as generator.
107
+
108
+ Yields:
109
+ Fragment: TCR framework regions
75
110
  """
76
111
  for f in self.get_fragments():
77
112
  if "fw" in f.id:
@@ -79,15 +114,20 @@ class TCR(Entity):
79
114
 
80
115
  def get_CDRs(self):
81
116
  """
82
- Obtain CDR loops from a TCR structure object
117
+ Obtain complementarity determining regions (CDRs) from a TCR structure object as generator.
118
+
119
+ Yields:
120
+ Fragment: TCR CDR regions
83
121
  """
84
122
  for f in self.get_fragments():
85
123
  if "cdr" in f.id:
86
124
  yield f
87
125
 
88
126
  def get_TCR_type(self):
89
- """
90
- Get the TCR type
127
+ """Get TCR type according to variable region assignments.
128
+
129
+ Returns:
130
+ str: TCR type (abTCR, gdTCR, dbTCR)
91
131
  """
92
132
  if hasattr(self, "tcr_type"):
93
133
  return self.tcr_type
@@ -102,9 +142,22 @@ class TCR(Entity):
102
142
  return self.tcr_type
103
143
 
104
144
  def get_germline_assignments(self):
145
+ """Retrive germline assignments for all TCR chains.
146
+ This is a dictionary with the chain ID as key and the germline assignments as value.
147
+
148
+ Returns:
149
+ dict: dict with TCR chain ID as key and germline assignments as value
150
+ """
105
151
  return {c.id: c.get_germline_assignments() for c in self.get_chains()}
106
152
 
107
153
  def get_MHC_allele_assignments(self):
154
+ """
155
+ Retrieve MHC allele assignments for all TCR associated MHCs.
156
+ This is a list of dictionaries with the MHC ID as key and the allele assignments as value.
157
+
158
+ Returns:
159
+ dict: dict with MHC chain ID as key and allele assignments as value
160
+ """
108
161
  return [
109
162
  (
110
163
  mhc.get_allele_assignments()
@@ -116,6 +169,11 @@ class TCR(Entity):
116
169
  ]
117
170
 
118
171
  def get_germlines_and_alleles(self):
172
+ """Get all germline and allele assignments for TCR and MHC chains as a dictionary with the chain ID as key and the germline assignments as value.
173
+
174
+ Returns:
175
+ dict: Dictionary of TCR germline and MHC allele assignemnts with amino acid sequences.
176
+ """
119
177
  from ..tcr_formats.tcr_formats import get_sequences
120
178
 
121
179
  germlines_and_alleles = {}
@@ -167,22 +225,59 @@ class TCR(Entity):
167
225
  return germlines_and_alleles
168
226
 
169
227
  def save(self, save_as=None, tcr_only: bool = False, format: str = "pdb"):
228
+ """Save TCR object as PDB or MMCIF file.
229
+
230
+ Args:
231
+ save_as (str, optional): File path to save TCR to. Defaults to None.
232
+ tcr_only (bool, optional): Whether to save TCR only or to include MHC and antigen. Defaults to False.
233
+ format (str, optional): Whether to save as PDB or MMCIF. Defaults to "pdb".
234
+ """
170
235
  from . import TCRIO
171
236
 
172
237
  tcrio = TCRIO.TCRIO()
173
238
  tcrio.save(self, save_as=save_as, tcr_only=tcr_only, format=format)
174
239
 
175
240
  def get_scanning_angle(self, mode="rudolph"):
241
+ """
242
+ Returns TCR:pMHC complex scanning (aka crossing, incident) angle of TCR to MHC.
243
+ See paper for details.
244
+
245
+ Args:
246
+ mode (str, optional): Mode for calculating the scanning angle. Options "rudolph", "cys", "com". Defaults to "rudolph".
247
+
248
+ Returns:
249
+ float: Scanning angle of TCR to MHC in degrees
250
+ """
176
251
  if not hasattr(self, "geometry") or self.geometry.mode != mode:
177
252
  self.calculate_docking_geometry(mode=mode)
178
253
  return self.geometry.get_scanning_angle()
179
254
 
180
- def get_pitch_angle(self, mode="rudolph"):
255
+ def get_pitch_angle(self, mode="cys"):
256
+ """
257
+ Returns TCR:pMHC complex pitch angle of TCR to MHC.
258
+ See paper for details.
259
+
260
+ Args:
261
+ mode (str, optional): Mode for calculating the scanning angle. Options "rudolph", "cys", "com". Defaults to "cys".
262
+
263
+ Returns:
264
+ float: Pitch angle of TCR to MHC in degrees
265
+ """
181
266
  if not hasattr(self, "geometry") or self.geometry.mode != mode:
182
267
  self.calculate_docking_geometry(mode=mode)
183
268
  return self.geometry.get_pitch_angle()
184
269
 
185
270
  def calculate_docking_geometry(self, mode="rudolph", as_df=False):
271
+ """Calculate docking geometry of TCR to MHC.
272
+ This is a wrapper function for the TCRGeom class.
273
+
274
+ Args:
275
+ mode (str, optional): Mode for calculating the geometry. Options "rudolph", "cys", "com". Defaults to "rudolph".
276
+ as_df (bool, optional): Whether to return as dictionary or dataframe. Defaults to False.
277
+
278
+ Returns:
279
+ [dict, DataFrame]: TCR to MHC geometry.
280
+ """
186
281
  if len(self.get_MHC()) == 0:
187
282
  warnings.warn(
188
283
  f"No MHC found for TCR {self}. Docking geometry cannot be calcuated"
@@ -203,20 +298,39 @@ class TCR(Entity):
203
298
  return self.geometry.to_dict()
204
299
 
205
300
  def score_docking_geometry(self, **kwargs):
301
+ """
302
+ Score docking geometry of TCR to MHC.
303
+ This is a wrapper function for the TCRGeomFiltering class.
304
+ The score is calculated as the negative log of the TCR:pMHC complex geometry feature probabilities based on the distributions fit by maximum likelihood estimation of TCR to Class I MHC strucutres from STCRDab.
305
+ Please see the paper methods for details.
306
+
307
+ Returns:
308
+ float: TCR:pMHC complex score as negative log of TCR:pMHC complex geometry feature probabilities
309
+ """
206
310
  from ..tcr_geometry.TCRGeomFiltering import DockingGeometryFilter
207
311
 
208
312
  geom_filter = DockingGeometryFilter()
209
313
  if not hasattr(self, "geometry"):
210
314
  self.calculate_docking_geometry(mode="com")
211
315
  return geom_filter.score_docking_geometry(
212
- self.geometry.get_scanning_angle(),
213
- self.geometry.get_pitch_angle(),
316
+ self.geometry.get_scanning_angle(mode="com"),
317
+ self.geometry.get_pitch_angle(mode="com"),
214
318
  self.geometry.tcr_com[-1], # z component of TCR centre of mass
215
319
  )
216
320
 
217
321
  def profile_peptide_interactions(
218
322
  self, renumber: bool = True, save_to: str = None, **kwargs
219
323
  ) -> "pd.DataFrame":
324
+ """
325
+ Profile the interactions of the peptide to the TCR and the MHC.
326
+
327
+ Args:
328
+ renumber (bool, optional): Whether to renumber the interacting residues. Defaults to True.
329
+ save_to (str, optional): Path to save intraction data to as csv. Defaults to None.
330
+
331
+ Returns:
332
+ pd.DataFrame: Dataframe of peptide interactions
333
+ """
220
334
  if len(self.get_antigen()) == 0:
221
335
  warnings.warn(
222
336
  f"No peptide antigen found for TCR {self}. Peptide interactions cannot be profiled"
@@ -238,6 +352,25 @@ class TCR(Entity):
238
352
  return interactions
239
353
 
240
354
  def get_interaction_heatmap(self, plotting_kwargs={}, **interaction_kwargs):
355
+ """
356
+ Get interaction heatmap of TCR to MHC and peptide.
357
+ Generates heatmap image.
358
+ Plotting kwargs are passed to heatmap function.
359
+
360
+ Args:
361
+ plotting_kwargs (dict, optional):
362
+ save_as: path to save heatmap image to
363
+ interaction_type: type of interaction (eg. saltbridge, h_bond) to plot. All interactions are plotted by default.
364
+ antigen_name: name of antigen for plot title
365
+ mutation_index: index of antigen residues to highlight in plot
366
+ Defaults to {
367
+ save_as:None,
368
+ interaction_type:None,
369
+ antigen_name:None,
370
+ mutation_index:None
371
+ }.
372
+ interaction_kwargs: kwargs for TCRInteractionProfiler class. See TCRInteractionProfiler for details.
373
+ """
241
374
  from ..tcr_interactions import TCRInteractionProfiler
242
375
 
243
376
  interaction_profiler = TCRInteractionProfiler.TCRInteractionProfiler(
@@ -266,6 +399,15 @@ class TCR(Entity):
266
399
  def visualise_interactions(
267
400
  save_as=None, antigen_residues_to_highlight=None, **interaction_kwargs
268
401
  ):
402
+ """Visualise peptide interactions in pymol.
403
+
404
+ Args:
405
+ save_as (str, optional): path to save pymol session to. Defaults to None.
406
+ antigen_residues_to_highlight (list[int], optional): antigen residues to highlight red in pymol session. Defaults to None.
407
+ **interaction_kwargs: kwargs for TCRInteractionProfiler class. See TCRInteractionProfiler for details.
408
+ Returns:
409
+ str: path to saved pymol session
410
+ """
269
411
  from ..tcr_interactions import TCRInteractionProfiler
270
412
 
271
413
  interaction_profiler = TCRInteractionProfiler.TCRInteractionProfiler(
@@ -306,7 +448,18 @@ class TCR(Entity):
306
448
 
307
449
 
308
450
  class abTCR(TCR):
451
+ """
452
+ abTCR class. Inherits from TCR.
453
+ This is a subclass of TCR for TCRs with alpha and beta chains.
454
+ """
309
455
  def __init__(self, c1, c2):
456
+ """
457
+ Initialise abTCR object. This is a subclass of TCR for TCRs with alpha and beta chains.
458
+
459
+ Args:
460
+ c1 (TCRchain): alpha or beta type TCR chain
461
+ c2 (TCRchain): alpha or beta type TCR chain
462
+ """
310
463
 
311
464
  if c1.chain_type == "B":
312
465
  Entity.__init__(self, c1.id + c2.id)
@@ -328,9 +481,22 @@ class abTCR(TCR):
328
481
  self.visualise_interactions = self._create_interaction_visualiser()
329
482
 
330
483
  def __repr__(self):
484
+ """
485
+ String representation of the abTCR object.
486
+
487
+ Returns:
488
+ str: String representation of the abTCR objec
489
+ """
331
490
  return "<TCR %s%s beta=%s; alpha=%s>" % (self.VB, self.VA, self.VB, self.VA)
332
491
 
333
492
  def _add_domain(self, chain):
493
+ """
494
+ Add a variable alpha or variable beta domain to the TCR object.
495
+ Links the domain to the chain ID.
496
+
497
+ Args:
498
+ chain (TCRchain): TCR chain whose domain is being added.
499
+ """
334
500
  if chain.chain_type == "B":
335
501
  self.VB = chain.id
336
502
  elif chain.chain_type == "A" or chain.chain_type == "D":
@@ -340,14 +506,32 @@ class abTCR(TCR):
340
506
  self.add(chain)
341
507
 
342
508
  def get_VB(self):
509
+ """
510
+ Retrieve the variable beta chain of the TCR
511
+
512
+ Returns:
513
+ TCRchain: VB chain
514
+ """
343
515
  if hasattr(self, "VB"):
344
516
  return self.child_dict[self.VB]
345
517
 
346
518
  def get_VA(self):
519
+ """
520
+ Retrieve the variable alpha chain of the TCR
521
+
522
+ Returns:
523
+ TCRchain: VA chain
524
+ """
347
525
  if hasattr(self, "VA"):
348
526
  return self.child_dict[self.VA]
349
527
 
350
528
  def get_domain_assignment(self):
529
+ """
530
+ Retrieve the domain assignment of the TCR as a dict with variable domain type as key and chain ID as value.
531
+
532
+ Returns:
533
+ dict: domain assignment from domain to chain ID, e.g. {"VA": "D", "VB": "E"}
534
+ """
351
535
  try:
352
536
  return {"VA": self.VA, "VB": self.VB}
353
537
  except AttributeError:
@@ -358,6 +542,12 @@ class abTCR(TCR):
358
542
  return None
359
543
 
360
544
  def is_engineered(self):
545
+ """
546
+ Flag for engineered TCRs.
547
+
548
+ Returns:
549
+ bool: Flag for engineered TCRs
550
+ """
361
551
  if self.engineered:
362
552
  return True
363
553
  else:
@@ -371,6 +561,12 @@ class abTCR(TCR):
371
561
  return False
372
562
 
373
563
  def get_fragments(self):
564
+ """
565
+ Retrieve the fragments, ie FW and CDR loops of the TCR as a generator.
566
+
567
+ Yields:
568
+ Fragment: fragment of TCR chain.
569
+ """
374
570
  vb, va = self.get_VB(), self.get_VA()
375
571
 
376
572
  # If a variable domain exists
@@ -9,6 +9,7 @@ from itertools import combinations, product
9
9
  import sys
10
10
  import os
11
11
  from collections import defaultdict
12
+ import warnings
12
13
 
13
14
  from Bio.PDB.PDBParser import PDBParser
14
15
  from Bio.PDB.MMCIFParser import MMCIFParser
@@ -22,7 +23,7 @@ from ..utils.error_stream import ErrorStream
22
23
  from .TCRStructure import TCRStructure
23
24
  from .Model import Model
24
25
  from .TCR import TCR, abTCR, gdTCR
25
- from .MHC import MHC, MH1, MH2, CD1, MR1, scMH1, scCD1
26
+ from .MHC import MHC, MH1, MH2, CD1, MR1, scMH1, scCD1, scMH2
26
27
  from .Holder import Holder
27
28
  from .TCRchain import TCRchain
28
29
  from .MHCchain import MHCchain
@@ -461,6 +462,7 @@ class TCRParser(PDBParser, MMCIFParser):
461
462
  newmodel.add(mhc)
462
463
 
463
464
  # allow instantiation of single chain MH1 type MH class if the alpha helices forming chain has been observed
465
+ # allow instantiation of single chain MH2 type MH class if one of the GA or GB chain has been observed
464
466
  ids_to_detach = []
465
467
  for mhc_chain in mhchains:
466
468
  if mhc_chain.chain_type in ["MH1", "GA1", "GA2"]:
@@ -471,6 +473,13 @@ class TCRParser(PDBParser, MMCIFParser):
471
473
  ids_to_detach.append(mhc_chain.id)
472
474
  sc_mhc = scCD1(mhc_chain)
473
475
  newmodel.add(sc_mhc)
476
+ elif mhc_chain.chain_type in ["GA", "GB"]:
477
+ ids_to_detach.append(mhc_chain.id)
478
+ sc_mhc = scMH2(mhc_chain)
479
+ newmodel.add(sc_mhc)
480
+ warnings.warn(
481
+ f"Single chain MH class II instantiated with chain type {mhc_chain.chain_type}. It is possible the other MHC class II chain has not been identified."
482
+ )
474
483
 
475
484
  for mhc_chain_id in ids_to_detach:
476
485
  mhchains.detach_child(mhc_chain_id)
@@ -1005,9 +1014,11 @@ class TCRParser(PDBParser, MMCIFParser):
1005
1014
  ):
1006
1015
  """
1007
1016
  This is a generic method to process which proteins/peptides belong to a TCR or MHC. Needs testing.
1008
- @param complexes: list of TCR/TCRchain objects or MHC/MHCchain objects
1009
- @param receptor_atoms: list of atom subset that will likely contact the antigen (e.g. cdr_atoms)
1010
- @param antigen_atoms: list of atoms in the antigen.
1017
+
1018
+ Args:
1019
+ complexes: list of TCR/TCRchain objects or MHC/MHCchain objects
1020
+ receptor_atoms: list of atom subset that will likely contact the antigen (e.g. cdr_atoms)
1021
+ antigen_atoms: list of atoms in the antigen.
1011
1022
  """
1012
1023
  ns = NeighborSearch(
1013
1024
  [atom for chain in receptor_atoms for atom in receptor_atoms[chain]]
@@ -38,10 +38,12 @@ def call_anarci(
38
38
  ):
39
39
  """
40
40
  Use the ANARCI program to number the sequence.
41
- @param seq: An amino acid sequence that you wish to number.
42
- @type seq: C{str}
43
41
 
44
- @return: numbering, chain type
42
+ Args:
43
+ seq: An amino acid sequence that you wish to number.
44
+
45
+ Returns:
46
+ numbering, chain type, germline information
45
47
  """
46
48
  from anarci import number as anarci_number
47
49
 
@@ -49,7 +51,7 @@ def call_anarci(
49
51
  seq, allow=allow, assign_germline=True
50
52
  )
51
53
 
52
- if numbering and "MR" not in chain_type and chain_type in allow:
54
+ if numbering and chain_type in allow:
53
55
  return [(_, aa) for _, aa in numbering if aa != "-"], chain_type, germline_info
54
56
  elif numbering and chain_type in ["BA", "GD", "AB", "DG"]:
55
57
  return (
@@ -85,15 +87,15 @@ def annotate(chain):
85
87
  )
86
88
  # aligned_numbering = cleanup_scTCR_numbering(aligned_numbering, sequence_list)
87
89
  scTCR = True
88
- elif chtype == "DC1" or chtype == "RM1":
89
- # Use the scTCR numbering trick; since CD1/MR1 numbering only spans up to residue ~87 and
90
- aligned_numbering = align_scTCR_numbering(
91
- numbering, sequence_list, sequence_str
92
- )
93
- aligned_numbering[0].update(aligned_numbering[1])
94
- aligned_numbering = aligned_numbering[0] # combine the numbering
95
- aligned_numbering = cleanup_scTCR_numbering(aligned_numbering, sequence_list)
96
- scTCR = False
90
+ # elif chtype == "DC1" or chtype == "RM1":
91
+ # # Use the scTCR numbering trick; since CD1/MR1 numbering only spans up to residue ~87 and
92
+ # aligned_numbering = align_scTCR_numbering(
93
+ # numbering, sequence_list, sequence_str
94
+ # )
95
+ # aligned_numbering[0].update(aligned_numbering[1])
96
+ # aligned_numbering = aligned_numbering[0] # combine the numbering
97
+ # aligned_numbering = cleanup_scTCR_numbering(aligned_numbering, sequence_list)
98
+ # scTCR = False
97
99
  else:
98
100
  # align the original residue id's to the numbering
99
101
  aligned_numbering = align_numbering(numbering, sequence_list)
@@ -108,16 +110,18 @@ def extract_sequence(
108
110
  ):
109
111
  """
110
112
  Get the amino acid sequence of the chain.
111
- @change: Residues containing HETATOMs are skipped --> Residues containing HETATOMs are checked as an amino acid.
113
+ Residues containing HETATOMs are skipped --> Residues containing HETATOMs are checked as an amino acid.
112
114
 
113
115
  Residues containing HETATOMs are checked to be amino acids and the single letter returned.
114
116
 
115
117
  This works provided the residues in the chain are in the correct order.
116
118
 
117
- @param selection: a selection object to select certain residues
118
- @param return_warnings: Flag to return a list of warnings or not
119
- @param backbone: Flag whether to only show residues with a complete backbone (in the structure) or not.
120
- @return: The sequence in a resid:aa tuple list and the sequence as a string.
119
+ Args:
120
+ selection: a selection object to select certain residues
121
+ return_warnings: Flag to return a list of warnings or not
122
+ backbone: Flag whether to only show residues with a complete backbone (in the structure) or not.
123
+ Returns:
124
+ The sequence in a resid:aa tuple list and the sequence as a string.
121
125
 
122
126
  """
123
127
  sequence_list = []
@@ -257,9 +261,10 @@ def align_numbering(numbering, sequence_list, alignment_dict={}):
257
261
  def align_scTCR_numbering(numbering, sequence_list, sequence_str):
258
262
  """
259
263
  Align the sequence that has been numbered to a scTCR structure.
260
- @param numbering: numbered list of residues; this is usually a two-element list/tuple from TCRDB.anarci.number
261
- @param sequence_list: list of residues (e.g. from a structure) in its original numbering
262
- @param sequence_str: string form of sequence_list
264
+ Args:
265
+ numbering: numbered list of residues; this is usually a two-element list/tuple from TCRDB.anarci.number
266
+ sequence_list: list of residues (e.g. from a structure) in its original numbering
267
+ sequence_str: string form of sequence_list
263
268
  """
264
269
  if numbering:
265
270
  numbered_sequence = ["".join([r[1] for r in n]) for n in numbering]
@@ -321,8 +326,9 @@ def cleanup_scTCR_numbering(numbering_dict, sequence_list):
321
326
  This is to close the gaps in the numbering so that residues that were unnumbered by anarci don't move around
322
327
  during structural parsing (when they're probably just connections between domains).
323
328
 
324
- @param numbering_dict: numbered dictionary from align_scTCR_numbering
325
- @param sequence_list : sequence list from the structure for alignment.
329
+ Args:
330
+ numbering_dict: numbered dictionary from align_scTCR_numbering
331
+ sequence_list : sequence list from the structure for alignment.
326
332
  """
327
333
  positions = [p[0] for p in sequence_list]
328
334
 
@@ -23,8 +23,9 @@ def identity(seq1, seq2, positions=[]):
23
23
  """
24
24
  Find the matched sequence identity between two aligned sequences.
25
25
  Can accept lists/strings, but this assumes that the two sequences are of the same length.
26
- @param seq1: Dictionary with key as the position and value as the single letter amino acid code. or an aligned list or string
27
- @param seq2: Dictionary with key as the position and value as the single letter amino acid code. or an aligned list or string
26
+ Args:
27
+ seq1: Dictionary with key as the position and value as the single letter amino acid code. or an aligned list or string
28
+ seq2: Dictionary with key as the position and value as the single letter amino acid code. or an aligned list or string
28
29
  """
29
30
  n = 0 # number
30
31
  m = 0 # match
@@ -12,9 +12,10 @@ import re
12
12
  def tuplefy(x):
13
13
  """
14
14
  Interpretation for converting numbering (in string) into a tuple.
15
-
16
- @param x: A string for the identifier of a numbered position. e.g "H100A".
17
- @return : A tuple of the chain tupe followed by a tuple of residue id and insertion code. eg. ( H, (100, "A") )
15
+ Args:
16
+ x: A string for the identifier of a numbered position. e.g "H100A".
17
+ Returns:
18
+ A tuple of the chain tupe followed by a tuple of residue id and insertion code. eg. ( H, (100, "A") )
18
19
 
19
20
  """
20
21
  chain, resi, ins = re.split(r"(\d+)", x)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: stcrpy
3
- Version: 1.0.0
3
+ Version: 1.0.3
4
4
  Summary: Set of methods to parse, annotate, and calculate features of TCR structures
5
5
  Maintainer: Nele Quast
6
6
  Maintainer-email: quast@stats.ox.ac.uk
@@ -102,7 +102,7 @@ pip install einops
102
102
  STCRpy [documentation](https://stcrpy.readthedocs.io/en/latest/) is hosted on ReadtheDocs.
103
103
 
104
104
  # Examples
105
- STCRpy generates and operates on TCR structure objects. The majority of the API can be accessed through functions of the format: `tcr.some_stcrpy_function()`. TCR objects are associated with their MHC and antigen if these are presented in the structure.
105
+ STCRpy generates and operates on TCR structure objects. The majority of the API can be accessed through functions of the format: [`tcr.some_stcrpy_function()`](https://stcrpy.readthedocs.io/en/latest/stcrpy.tcr_processing.html#stcrpy.tcr_processing.TCR.TCR). TCR objects are associated with their MHC and antigen if these are presented in the structure.
106
106
 
107
107
  A notebook with examples can be found under [examples/STCRpy_examples.ipynb](./examples/STCRpy_examples.ipynb)
108
108
 
@@ -11,7 +11,7 @@ stcrpy/tcr_formats/tcr_formats.py,sha256=ZLouBdpY1K8xOA7tORkfljE9iUsbn_oay4DRHvP
11
11
  stcrpy/tcr_formats/tcr_haddock.py,sha256=ejGs1DsOMKE-CDK5k9M4J-9y-7bLq_BbNLAkBNhpjjQ,21913
12
12
  stcrpy/tcr_geometry/TCRCoM.py,sha256=Mtq0ieQUTj2R_EN9BUFdUtSbT9AtI5OPi1TEdnMlxME,12883
13
13
  stcrpy/tcr_geometry/TCRCoM_LICENCE,sha256=93k_qqF0rgpyWEmxpcl2sbZS3CK1dkGrIuvJtKsBlCA,7844
14
- stcrpy/tcr_geometry/TCRDock.py,sha256=CEwcDbekOy5KvKw-_0DMMU4CwfK01km_NHg2lZaLquI,9911
14
+ stcrpy/tcr_geometry/TCRDock.py,sha256=Uga1OV5owC-lVfzzKFn5dGEGnaeHJUHMpppdUxnK84k,9975
15
15
  stcrpy/tcr_geometry/TCRGeom.py,sha256=niol8kNMUufFkjxhOkFhBhonNIKpQwhl6V8qbVa7tLg,19041
16
16
  stcrpy/tcr_geometry/TCRGeomFiltering.py,sha256=JN02yyxeXy6XRH3oSKTskcUkxoqvxsvSRGpR-4H25kA,9666
17
17
  stcrpy/tcr_geometry/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -25,7 +25,7 @@ stcrpy/tcr_geometry/reference_data/reference_G.pdb,sha256=Fs8e_UDb6dI1qqhNSttWaH
25
25
  stcrpy/tcr_geometry/reference_data/reference_data.py,sha256=q3L-cQ1UQUfZxeIMKIiiase_6SEEuWlx7UsLndwNLAk,1658
26
26
  stcrpy/tcr_interactions/PLIPParser.py,sha256=zetY_LvH_8E-26xXc02c7_edoHWEwIWB9_XIu1szRcA,5785
27
27
  stcrpy/tcr_interactions/TCRInteractionProfiler.py,sha256=Q4OBQ3DooM592Sk5DnjeAJAAohVOkrbp8MAXNRTLnVg,17835
28
- stcrpy/tcr_interactions/TCRpMHC_PLIP_Model_Parser.py,sha256=wRY0gOoWMb5hDqPn6vKn5oLXCkMvoFgwuKSqYkB-MM8,4688
28
+ stcrpy/tcr_interactions/TCRpMHC_PLIP_Model_Parser.py,sha256=-fm_rtPJhU-h3WuX1U5Cv3vjO0eAlzwbm1HTreQIDCI,5464
29
29
  stcrpy/tcr_interactions/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
30
30
  stcrpy/tcr_interactions/utils.py,sha256=KEGybd1ugZvFdj4Gqn9Xo4lnJbU1ivADmEDjkvuaNiw,5177
31
31
  stcrpy/tcr_methods/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -39,30 +39,30 @@ stcrpy/tcr_metrics/tcr_rmsd.py,sha256=cbK20z1ELjeEecPxZF3vQ4uDlorrAAb5C8D8YtTpwz
39
39
  stcrpy/tcr_ml/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
40
40
  stcrpy/tcr_ml/geometry_predictor.py,sha256=D0w_Rx2PIwPQORyglvlugwI4wGg4xZyXUxRtIOEYyK0,38
41
41
  stcrpy/tcr_processing/AGchain.py,sha256=iVpiNMXOz3tnBIK0CYhq1EUdObMckGO6vkilwWQhjmU,2455
42
- stcrpy/tcr_processing/Chemical_components.py,sha256=8xcUg9HBya2_--hdAtMonECZeyl684wTvCUkrmUdPcE,2020304
43
- stcrpy/tcr_processing/Entity.py,sha256=5WZN5vcEFQfFxZCXcqr9exrA5vOlrH0I82LRNgPe3KY,11198
42
+ stcrpy/tcr_processing/Chemical_components.py,sha256=KuJiV-SnATz1cWoZnZmamNaivOhPhrsIdjKK-VCtKgE,2020298
43
+ stcrpy/tcr_processing/Entity.py,sha256=kY8oLVnmWOMMzj4Gj7ouE-IaxLHrlchX1Y2EAu8Sstw,11180
44
44
  stcrpy/tcr_processing/Fragment.py,sha256=QW_6sPWi2HX7mq5dLLwvA-7Q9oiBHCS0p02WgFLDisA,1908
45
45
  stcrpy/tcr_processing/Holder.py,sha256=y_q2NF0YiCf9CuXWlIm9-EWpD5CJj95o2wUCYDyEHOA,549
46
- stcrpy/tcr_processing/MHC.py,sha256=OfOb9aMKqcP9jM0TRFZo_ZQDB1idqCaJhn9rlBaAKA4,11736
46
+ stcrpy/tcr_processing/MHC.py,sha256=71IiBc2t3_w4_BeA99SJV8RKwWxhEMYpZG3Q5akaV0A,13639
47
47
  stcrpy/tcr_processing/MHCchain.py,sha256=rT0FCkKD2pbZm-VTvcLwCdS5UOy-ibxnNcsgREIxgSs,4357
48
48
  stcrpy/tcr_processing/Model.py,sha256=K8wTrSCECHyqJX9811wU9MxgdGDVyCXraQ4-rOOa08U,1230
49
49
  stcrpy/tcr_processing/Select.py,sha256=VuVSgmqHBPD1DGRumM44HDzcQ-aQOwg_6zQHM3Ulm0U,3543
50
- stcrpy/tcr_processing/TCR.py,sha256=JR_CQovd7syVLd4k9tPYaFiwXpjP5dl51_-4hI2Phno,17206
50
+ stcrpy/tcr_processing/TCR.py,sha256=DHkNZ309TTfn_Ou2XL0dACK5KVR3j4Sj5G-42cuELi4,24651
51
51
  stcrpy/tcr_processing/TCRIO.py,sha256=tSJLVN6MG6gyT26PreVJOz5DqD1e-VsBjBpu3mBBPKg,1501
52
- stcrpy/tcr_processing/TCRParser.py,sha256=D97-MTdbasEdtMR-mT6Up5tY2LK1LRgALVRrTearJJs,51162
52
+ stcrpy/tcr_processing/TCRParser.py,sha256=DzRin1hQ6DfvRhPnt6pKiB6TJAzM5C7ivPwH39-m_hk,51738
53
53
  stcrpy/tcr_processing/TCRStructure.py,sha256=yFiUeo02KXIBBEljy0mebv5ol5uCQRTy-Sfs94Rt6Hc,3810
54
54
  stcrpy/tcr_processing/TCRchain.py,sha256=2CdP_JX5LG7nM8Lsuhcevf7SyRaQUZlizt3ntEYVPjg,4769
55
55
  stcrpy/tcr_processing/__init__.py,sha256=BefeJ0jefteeOzWrkOMvxLCvzd0aJDhXWrdTm7zlP94,94
56
- stcrpy/tcr_processing/annotate.py,sha256=aa3Bu_5UXC8H3C7jibBk0YapynhwPAP-Dx69cmGXRw8,17163
56
+ stcrpy/tcr_processing/annotate.py,sha256=JDXsIooYewRzI8-Hh9sd84QJvPrc4GZ3MfN6A-jJPLU,17172
57
57
  stcrpy/tcr_processing/utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
58
- stcrpy/tcr_processing/utils/common.py,sha256=SmIbvf9-cH_T4ENBRNdAmhZ4buzRHDN-QY0csVB3pCo,1865
59
- stcrpy/tcr_processing/utils/constants.py,sha256=k16xeH8gMBdgdXy6h829kJ2qIHx2-sDnwv66zlf1aIA,8138
58
+ stcrpy/tcr_processing/utils/common.py,sha256=5e-dP6jPlaFZEErusakdQYpyj79E3WvEGF5-sG0LitI,1869
59
+ stcrpy/tcr_processing/utils/constants.py,sha256=AHReE1QkeqTnhjvQI7nrPqLF4XdtzHV9C1w1uHTiVcM,8151
60
60
  stcrpy/tcr_processing/utils/region_definitions.py,sha256=pWE3xJAhnGtLHWxvJOHaU5Y5spcHuZwPzcIDCsH920I,18806
61
61
  stcrpy/utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
62
62
  stcrpy/utils/error_stream.py,sha256=BLHJnf-tWU41MXh6sHSZgkTFOMiWZsCgwM2qIKBnwr4,247
63
- stcrpy-1.0.0.dist-info/licenses/LICENCE,sha256=G1FnVDsfeYoveKTu9Xaqukcm-4xZ4mzakjLpFMnNfJ0,1507
64
- stcrpy-1.0.0.dist-info/licenses/stcrpy/tcr_geometry/TCRCoM_LICENCE,sha256=93k_qqF0rgpyWEmxpcl2sbZS3CK1dkGrIuvJtKsBlCA,7844
65
- stcrpy-1.0.0.dist-info/METADATA,sha256=CEw0KlbcZz8peJ1s8nIrxet6yllG1XU0ZLx3cD0DD-Y,5785
66
- stcrpy-1.0.0.dist-info/WHEEL,sha256=ck4Vq1_RXyvS4Jt6SI0Vz6fyVs4GWg7AINwpsaGEgPE,91
67
- stcrpy-1.0.0.dist-info/top_level.txt,sha256=kAkgyHyGW-_YswJpcuA3pSqzuQVbUggFUmZg2OTx_B8,16
68
- stcrpy-1.0.0.dist-info/RECORD,,
63
+ stcrpy-1.0.3.dist-info/licenses/LICENCE,sha256=G1FnVDsfeYoveKTu9Xaqukcm-4xZ4mzakjLpFMnNfJ0,1507
64
+ stcrpy-1.0.3.dist-info/licenses/stcrpy/tcr_geometry/TCRCoM_LICENCE,sha256=93k_qqF0rgpyWEmxpcl2sbZS3CK1dkGrIuvJtKsBlCA,7844
65
+ stcrpy-1.0.3.dist-info/METADATA,sha256=widJsCi2RfI9soEo0mPM1TUtgJopNRvPinR-n6Z3qYo,5885
66
+ stcrpy-1.0.3.dist-info/WHEEL,sha256=wXxTzcEDnjrTwFYjLPcsW_7_XihufBwmpiBeiXNBGEA,91
67
+ stcrpy-1.0.3.dist-info/top_level.txt,sha256=kAkgyHyGW-_YswJpcuA3pSqzuQVbUggFUmZg2OTx_B8,16
68
+ stcrpy-1.0.3.dist-info/RECORD,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: setuptools (80.0.0)
2
+ Generator: setuptools (80.1.0)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5