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