Package Bio :: Package PDB :: Module Entity
[hide private]
[frames] | no frames]

Source Code for Module Bio.PDB.Entity

  1  # Copyright (C) 2002, Thomas Hamelryck (thamelry@binf.ku.dk) 
  2  # This code is part of the Biopython distribution and governed by its 
  3  # license.  Please see the LICENSE file that should have been included 
  4  # as part of this package. 
  5   
  6  """Base class for Residue, Chain, Model and Structure classes. 
  7   
  8  It is a simple container class, with list and dictionary like properties. 
  9  """ 
 10   
 11  from copy import copy 
 12   
 13  from Bio.PDB.PDBExceptions import PDBConstructionException 
14 15 16 -class Entity(object):
17 """Basic container object for PDB heirachy. 18 19 Structure, Model, Chain and Residue are subclasses of Entity. 20 It deals with storage and lookup. 21 """ 22
23 - def __init__(self, id):
24 self._id = id 25 self.full_id = None 26 self.parent = None 27 self.child_list = [] 28 self.child_dict = {} 29 # Dictionary that keeps additional properties 30 self.xtra = {}
31 32 # Special methods 33
34 - def __len__(self):
35 """Return the number of children.""" 36 return len(self.child_list)
37
38 - def __getitem__(self, id):
39 """Return the child with given id.""" 40 return self.child_dict[id]
41
42 - def __delitem__(self, id):
43 """Remove a child.""" 44 return self.detach_child(id)
45
46 - def __contains__(self, id):
47 """True if there is a child element with the given id.""" 48 return (id in self.child_dict)
49
50 - def __iter__(self):
51 """Iterate over children.""" 52 for child in self.child_list: 53 yield child
54 55 # Private methods 56
57 - def _reset_full_id(self):
58 """Reset the full_id. 59 60 Sets the full_id of this entity and 61 recursively of all its children to None. 62 This means that it will be newly generated 63 at the next call to get_full_id. 64 """ 65 for child in self: 66 try: 67 child._reset_full_id() 68 except AttributeError: 69 pass # Atoms do not cache their full ids. 70 self.full_id = None
71 72 # Public methods 73 74 @property
75 - def id(self):
76 return self._id
77 78 @id.setter
79 - def id(self, value):
80 """Change the id of this entity. 81 82 This will update the child_dict of this entity's parent 83 and invalidate all cached full ids involving this entity. 84 85 @raises: ValueError 86 """ 87 if self.parent: 88 if value in self.parent.child_dict: 89 raise ValueError( 90 "Cannot change id from `{}` to `{}`. " 91 "The id `{}` is already used for a sibling of" 92 " this entity.".format(self._id, value, value)) 93 del self.parent.child_dict[self._id] 94 self.parent.child_dict[value] = self 95 96 self._id = value 97 self._reset_full_id()
98
99 - def get_level(self):
100 """Return level in hierarchy. 101 102 A - atom 103 R - residue 104 C - chain 105 M - model 106 S - structure 107 """ 108 return self.level
109
110 - def set_parent(self, entity):
111 """Set the parent Entity object.""" 112 self.parent = entity
113
114 - def detach_parent(self):
115 """Detach the parent.""" 116 self.parent = None
117
118 - def detach_child(self, id):
119 """Remove a child.""" 120 child = self.child_dict[id] 121 child.detach_parent() 122 del self.child_dict[id] 123 self.child_list.remove(child)
124
125 - def add(self, entity):
126 """Add a child to the Entity.""" 127 entity_id = entity.get_id() 128 if self.has_id(entity_id): 129 raise PDBConstructionException( 130 "%s defined twice" % str(entity_id)) 131 entity.set_parent(self) 132 self.child_list.append(entity) 133 self.child_dict[entity_id] = entity
134
135 - def insert(self, pos, entity):
136 """Add a child to the Entity at a specified position.""" 137 entity_id = entity.get_id() 138 if self.has_id(entity_id): 139 raise PDBConstructionException( 140 "%s defined twice" % str(entity_id)) 141 entity.set_parent(self) 142 self.child_list[pos:pos] = [entity] 143 self.child_dict[entity_id] = entity
144
145 - def get_iterator(self):
146 """Return iterator over children.""" 147 for child in self.child_list: 148 yield child
149
150 - def get_list(self):
151 """Return a copy of the list of children.""" 152 return copy(self.child_list)
153
154 - def has_id(self, id):
155 """True if a child with given id exists.""" 156 return (id in self.child_dict)
157
158 - def get_parent(self):
159 """Return the parent Entity object.""" 160 return self.parent
161
162 - def get_id(self):
163 """Return the id.""" 164 return self.id
165
166 - def get_full_id(self):
167 """Return the full id. 168 169 The full id is a tuple containing all id's starting from 170 the top object (Structure) down to the current object. A full id for 171 a Residue object e.g. is something like: 172 173 ("1abc", 0, "A", (" ", 10, "A")) 174 175 This corresponds to: 176 177 Structure with id "1abc" 178 Model with id 0 179 Chain with id "A" 180 Residue with id (" ", 10, "A") 181 182 The Residue id indicates that the residue is not a hetero-residue 183 (or a water) because it has a blank hetero field, that its sequence 184 identifier is 10 and its insertion code "A". 185 """ 186 if self.full_id is None: 187 entity_id = self.get_id() 188 l = [entity_id] 189 parent = self.get_parent() 190 while parent is not None: 191 entity_id = parent.get_id() 192 l.append(entity_id) 193 parent = parent.get_parent() 194 l.reverse() 195 self.full_id = tuple(l) 196 return self.full_id
197
198 - def transform(self, rot, tran):
199 """Apply rotation and translation to the atomic coordinates. 200 201 Example: 202 >>> rotation=rotmat(pi, Vector(1, 0, 0)) 203 >>> translation=array((0, 0, 1), 'f') 204 >>> entity.transform(rotation, translation) 205 206 @param rot: A right multiplying rotation matrix 207 @type rot: 3x3 Numeric array 208 209 @param tran: the translation vector 210 @type tran: size 3 Numeric array 211 """ 212 for o in self.get_list(): 213 o.transform(rot, tran)
214
215 - def copy(self):
216 shallow = copy(self) 217 218 shallow.child_list = [] 219 shallow.child_dict = {} 220 shallow.xtra = copy(self.xtra) 221 222 shallow.detach_parent() 223 224 for child in self.child_list: 225 shallow.add(child.copy()) 226 return shallow
227
228 229 -class DisorderedEntityWrapper(object):
230 """Wrapper class to group equivalent Entities. 231 232 This class is a simple wrapper class that groups a number of equivalent 233 Entities and forwards all method calls to one of them (the currently selected 234 object). DisorderedResidue and DisorderedAtom are subclasses of this class. 235 236 E.g.: A DisorderedAtom object contains a number of Atom objects, 237 where each Atom object represents a specific position of a disordered 238 atom in the structure. 239 """ 240
241 - def __init__(self, id):
242 self.id = id 243 self.child_dict = {} 244 self.selected_child = None 245 self.parent = None
246 247 # Special methods 248
249 - def __getattr__(self, method):
250 """Forward the method call to the selected child.""" 251 if method == '__setstate__': 252 # Avoid issues with recursion when attempting deepcopy 253 raise AttributeError 254 if not hasattr(self, 'selected_child'): 255 # Avoid problems with pickling 256 # Unpickling goes into infinite loop! 257 raise AttributeError 258 return getattr(self.selected_child, method)
259
260 - def __getitem__(self, id):
261 """Return the child with the given id.""" 262 return self.selected_child[id]
263 264 # XXX Why doesn't this forward to selected_child? 265 # (NB: setitem was here before getitem, iter, len, sub)
266 - def __setitem__(self, id, child):
267 """Add a child, associated with a certain id.""" 268 self.child_dict[id] = child
269
270 - def __contains__(self, id):
271 """True if the child has the given id.""" 272 return (id in self.selected_child)
273
274 - def __iter__(self):
275 """Return the number of children.""" 276 return iter(self.selected_child)
277
278 - def __len__(self):
279 """Return the number of children.""" 280 return len(self.selected_child)
281
282 - def __sub__(self, other):
283 """Subtraction with another object.""" 284 return self.selected_child - other
285 286 # Public methods 287
288 - def get_id(self):
289 """Return the id.""" 290 return self.id
291
292 - def disordered_has_id(self, id):
293 """True if there is an object present associated with this id.""" 294 return (id in self.child_dict)
295
296 - def detach_parent(self):
297 """Detach the parent.""" 298 self.parent = None 299 for child in self.disordered_get_list(): 300 child.detach_parent()
301
302 - def get_parent(self):
303 """Return parent.""" 304 return self.parent
305
306 - def set_parent(self, parent):
307 """Set the parent for the object and its children.""" 308 self.parent = parent 309 for child in self.disordered_get_list(): 310 child.set_parent(parent)
311
312 - def disordered_select(self, id):
313 """Select the object with given id as the currently active object. 314 315 Uncaught method calls are forwarded to the selected child object. 316 """ 317 self.selected_child = self.child_dict[id]
318
319 - def disordered_add(self, child):
320 """Add disordered entry. 321 322 This is implemented by DisorderedAtom and DisorderedResidue. 323 """ 324 raise NotImplementedError
325
326 - def is_disordered(self):
327 """Return 2, indicating that this Entity is a collection of Entities.""" 328 return 2
329
330 - def disordered_get_id_list(self):
331 """Return a list of id's.""" 332 # sort id list alphabetically 333 return sorted(self.child_dict)
334
335 - def disordered_get(self, id=None):
336 """Get the child object associated with id. 337 338 If id is None, the currently selected child is returned. 339 """ 340 if id is None: 341 return self.selected_child 342 return self.child_dict[id]
343
344 - def disordered_get_list(self):
345 """Return list of children.""" 346 return list(self.child_dict.values())
347