Package data
[hide private]
[frames] | no frames]

Source Code for Package data

  1  ############################################################################### 
  2  #                                                                             # 
  3  # Copyright (C) 2003-2012 Edward d'Auvergne                                   # 
  4  #                                                                             # 
  5  # This file is part of the program relax.                                     # 
  6  #                                                                             # 
  7  # relax is free software; you can redistribute it and/or modify               # 
  8  # it under the terms of the GNU General Public License as published by        # 
  9  # the Free Software Foundation; either version 2 of the License, or           # 
 10  # (at your option) any later version.                                         # 
 11  #                                                                             # 
 12  # relax is distributed in the hope that it will be useful,                    # 
 13  # but WITHOUT ANY WARRANTY; without even the implied warranty of              # 
 14  # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the               # 
 15  # GNU General Public License for more details.                                # 
 16  #                                                                             # 
 17  # You should have received a copy of the GNU General Public License           # 
 18  # along with relax; if not, write to the Free Software                        # 
 19  # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA   # 
 20  #                                                                             # 
 21  ############################################################################### 
 22   
 23  # Module docstring. 
 24  """Package containing the relax data storage object.""" 
 25   
 26   
 27  # Python module imports. 
 28  import __builtin__ 
 29  from re import search 
 30  from string import split 
 31  from sys import stderr 
 32  from time import asctime 
 33  import xml.dom.minidom 
 34   
 35  # relax module imports. 
 36  from pipe_container import PipeContainer 
 37  import generic_fns 
 38  from gui import Gui 
 39  from relax_errors import RelaxError, RelaxPipeError, RelaxNoPipeError 
 40  from relax_xml import fill_object_contents, xml_to_object 
 41  from status import Status; status = Status() 
 42  import version 
 43   
 44   
 45  __all__ = [ 'align_tensor', 
 46              'data_classes', 
 47              'diff_tensor', 
 48              'exp_info', 
 49              'gui', 
 50              'mol_res_spin', 
 51              'pipe_container', 
 52              'prototype', 
 53              'relax_xml' 
 54  ] 
 55   
 56   
57 -class Relax_data_store(dict):
58 """The relax data storage object.""" 59 60 # The current data pipe. 61 current_pipe = None 62 __builtin__.cdp = None 63 64 # Class variable for storing the class instance. 65 instance = None 66
67 - def __new__(self, *args, **kargs):
68 """Replacement function for implementing the singleton design pattern.""" 69 70 # First initialisation. 71 if self.instance is None: 72 # Create a new instance. 73 self.instance = dict.__new__(self, *args, **kargs) 74 75 # Add some initial structures. 76 self.instance.pipe_bundles = {} 77 self.instance.relax_gui = Gui() 78 79 # Already initialised, so return the instance. 80 return self.instance
81 82
83 - def __repr__(self):
84 """The string representation of the object. 85 86 Rather than using the standard Python conventions (either the string representation of the 87 value or the "<...desc...>" notation), a rich-formatted description of the object is given. 88 """ 89 90 # Intro text. 91 text = "The relax data storage object.\n" 92 93 # The data pipes. 94 text = text + "\n" 95 text = text + "Data pipes:\n" 96 pipes = list(self.instance.keys()) 97 if pipes: 98 for pipe in pipes: 99 text = text + " %s\n" % repr(pipe) 100 else: 101 text = text + " None\n" 102 103 # Data store objects. 104 text = text + "\n" 105 text = text + "Data store objects:\n" 106 names = sorted(self.__class__.__dict__.keys()) 107 for name in names: 108 # The object. 109 obj = getattr(self, name) 110 111 # The text. 112 if obj == None or isinstance(obj, str): 113 text = text + " %s %s: %s\n" % (name, type(obj), obj) 114 else: 115 text = text + " %s %s: %s\n" % (name, type(obj), split(obj.__doc__, '\n')[0]) 116 117 # dict methods. 118 text = text + "\n" 119 text = text + "Inherited dictionary methods:\n" 120 for name in dir(dict): 121 # Skip special methods. 122 if search("^_", name): 123 continue 124 125 # Skip overwritten methods. 126 if name in list(self.__class__.__dict__.keys()): 127 continue 128 129 # The object. 130 obj = getattr(self, name) 131 132 # The text. 133 text = text + " %s %s: %s\n" % (name, type(obj), split(obj.__doc__, '\n')[0]) 134 135 # All other objects. 136 text = text + "\n" 137 text = text + "All other objects:\n" 138 for name in dir(self): 139 # Skip special methods. 140 if search("^_", name): 141 continue 142 143 # Skip overwritten methods. 144 if name in list(self.__class__.__dict__.keys()): 145 continue 146 147 # Skip dictionary methods. 148 if name in dir(dict): 149 continue 150 151 # The object. 152 obj = getattr(self, name) 153 154 # The text. 155 text = text + " %s %s: %s\n" % (name, type(obj), obj) 156 157 # Return the text. 158 return text
159 160
161 - def __reset__(self):
162 """Delete all the data from the relax data storage object. 163 164 This method is to make the current single instance of the Data object identical to a newly 165 created instance of Data, hence resetting the relax program state. 166 """ 167 168 # Loop over the keys of self.__dict__ and delete the corresponding object. 169 for key in list(self.__dict__.keys()): 170 # Delete the object. 171 del self.__dict__[key] 172 173 # Remove all items from the dictionary. 174 self.instance.clear() 175 176 # Reset the current data pipe. 177 __builtin__.cdp = None 178 179 # Recreate the pipe bundle object. 180 self.instance.pipe_bundles = {} 181 182 # Re-add the GUI object. 183 self.instance.relax_gui = Gui() 184 185 # Signal the change. 186 status.observers.reset.notify() 187 status.observers.pipe_alteration.notify()
188 189
190 - def add(self, pipe_name, pipe_type, bundle=None, switch=True):
191 """Method for adding a new data pipe container to the dictionary. 192 193 This method should be used rather than importing the PipeContainer class and using the statement 'D[pipe] = PipeContainer()', where D is the relax data storage object and pipe is the name of the data pipe. 194 195 @param pipe_name: The name of the new data pipe. 196 @type pipe_name: str 197 @param pipe_type: The data pipe type. 198 @type pipe_type: str 199 @keyword bundle: The optional data pipe bundle to associate the data pipe with. 200 @type bundle: str or None 201 @keyword switch: A flag which if True will cause the new data pipe to be set to the current data pipe. 202 @type switch: bool 203 """ 204 205 # Test if the pipe already exists. 206 if pipe_name in list(self.instance.keys()): 207 raise RelaxPipeError(pipe_name) 208 209 # Create a new container. 210 self[pipe_name] = PipeContainer() 211 212 # Add the data pipe type string to the container. 213 self[pipe_name].pipe_type = pipe_type 214 215 # The pipe bundle. 216 if bundle: 217 # A new bundle. 218 if bundle not in self.pipe_bundles.keys(): 219 self.pipe_bundles[bundle] = [] 220 221 # Add the pipe to the bundle. 222 self.pipe_bundles[bundle].append(pipe_name) 223 224 # Change the current data pipe. 225 if switch: 226 # Set the current data pipe. 227 self.instance.current_pipe = pipe_name 228 __builtin__.cdp = self[pipe_name] 229 230 # Signal the switch. 231 status.observers.pipe_alteration.notify()
232 233
234 - def is_empty(self, verbosity=False):
235 """Method for testing if the relax data store is empty. 236 237 @keyword verbosity: A flag which if True will cause messages to be printed to STDERR. 238 @type verbosity: bool 239 @return: True if the data store is empty, False otherwise. 240 @rtype: bool 241 """ 242 243 # No pipes should exist. 244 if not self.keys() == []: 245 if verbosity: 246 stderr.write("The relax data store contains the data pipes %s.\n" % self.keys()) 247 return False 248 249 # Objects which should be in here. 250 blacklist = [ 251 'pipe_bundles', 252 'relax_gui' 253 ] 254 255 # An object has been added to the data store. 256 for name in dir(self): 257 # Skip the data store methods. 258 if name in list(self.__class__.__dict__.keys()): 259 continue 260 261 # Skip the dict methods. 262 if name in list(dict.__dict__.keys()): 263 continue 264 265 # Skip special objects. 266 if search("^__", name): 267 continue 268 269 # Blacklisted objects to skip. 270 if name in blacklist: 271 continue 272 273 # An object has been added. 274 if verbosity: 275 stderr.write("The relax data store contains the object %s.\n" % name) 276 return False 277 278 # The data store is empty. 279 return True
280 281
282 - def from_xml(self, file, dir=None, pipe_to=None, verbosity=1):
283 """Parse a XML document representation of a data pipe, and load it into the relax data store. 284 285 @param file: The open file object. 286 @type file: file 287 @keyword dir: The name of the directory containing the results file (needed 288 for loading external files). 289 @type dir: str 290 @keyword pipe_to: The data pipe to load the XML data pipe into (the file must only 291 contain one data pipe). 292 @type pipe_to: str 293 @keyword verbosity: A flag specifying the amount of information to print. The 294 higher the value, the greater the verbosity. 295 @type verbosity: int 296 @raises RelaxError: If pipe_to is given and the file contains multiple pipe 297 elements; or if the data pipes in the XML file already exist in 298 the relax data store; or if the data pipe type is invalid; or 299 if the target data pipe is not empty. 300 @raises RelaxNoPipeError: If pipe_to is given but the data pipe does not exist. 301 @raises RelaxError: If the data pipes in the XML file already exist in the relax 302 data store, or if the data pipe type is invalid. 303 @raises RelaxPipeError: If the data pipes of the XML file are already present in the 304 relax data store. 305 """ 306 307 # Create the XML document from the file. 308 doc = xml.dom.minidom.parse(file) 309 310 # Get the relax node. 311 relax_node = doc.childNodes[0] 312 313 # Get the relax version of the XML file. 314 file_version = relax_node.getAttribute('file_version') 315 if file_version == '': 316 file_version = 1 317 else: 318 file_version = int(file_version) 319 320 # Get the GUI nodes. 321 gui_nodes = relax_node.getElementsByTagName('relax_gui') 322 if gui_nodes: 323 self.relax_gui.from_xml(gui_nodes[0], file_version=file_version) 324 325 # Recreate all the data store data structures. 326 xml_to_object(relax_node, self, file_version=file_version, blacklist=['pipe', 'relax_gui']) 327 328 # Get the pipe nodes. 329 pipe_nodes = relax_node.getElementsByTagName('pipe') 330 331 # Target loading to a specific pipe (for pipe results reading). 332 if pipe_to: 333 # Check if there are multiple pipes in the XML file. 334 if len(pipe_nodes) > 1: 335 raise RelaxError("The pipe_to target pipe argument '%s' cannot be given as the file contains multiple pipe elements." % pipe_to) 336 337 # The pipe type. 338 pipe_type = pipe_nodes[0].getAttribute('type') 339 340 # Check that the pipe already exists. 341 if not pipe_to in self: 342 raise RelaxNoPipeError(pipe_to) 343 344 # Check if the pipe type matches. 345 if pipe_type != self[pipe_to].pipe_type: 346 raise RelaxError("The XML file pipe type '%s' does not match the pipe type '%s'" % (pipe_type, self[pipe_to].pipe_type)) 347 348 # Check if the pipe is empty. 349 if not self[pipe_to].is_empty(): 350 raise RelaxError("The data pipe '%s' is not empty." % pipe_to) 351 352 # Load the data. 353 self[pipe_to].from_xml(pipe_nodes[0], dir=dir, file_version=file_version) 354 355 # Load the state. 356 else: 357 # Checks. 358 for pipe_node in pipe_nodes: 359 # The pipe name and type. 360 pipe_name = str(pipe_node.getAttribute('name')) 361 pipe_type = pipe_node.getAttribute('type') 362 363 # Existence check. 364 if pipe_name in self: 365 raise RelaxPipeError(pipe_name) 366 367 # Valid type check. 368 if not pipe_type in generic_fns.pipes.VALID_TYPES: 369 raise RelaxError("The data pipe type '%s' is invalid and must be one of the strings in the list %s." % (pipe_type, generic_fns.pipes.VALID_TYPES)) 370 371 # Load the data pipes. 372 for pipe_node in pipe_nodes: 373 # The pipe name and type. 374 pipe_name = str(pipe_node.getAttribute('name')) 375 pipe_type = pipe_node.getAttribute('type') 376 377 # Add the data pipe. 378 switch = False 379 if self.current_pipe == None: 380 switch = True 381 self.add(pipe_name, pipe_type, switch=switch) 382 383 # Fill the pipe. 384 self[pipe_name].from_xml(pipe_node, file_version=file_version, dir=dir) 385 386 # Set the current pipe. 387 if self.current_pipe in self.keys(): 388 __builtin__.cdp = self[self.current_pipe]
389 390
391 - def to_xml(self, file, pipes=None):
392 """Create a XML document representation of the current data pipe. 393 394 This method creates the top level XML document including all the information needed 395 about relax, calls the PipeContainer.xml_write() method to fill in the document contents, 396 and writes the XML into the file object. 397 398 @param file: The open file object. 399 @type file: file 400 @param pipes: The name of the pipe, or list of pipes to place in the XML file. 401 @type pipes: str or list of str 402 """ 403 404 # The pipes to include in the XML file. 405 all = False 406 if not pipes: 407 all = True 408 pipes = self.keys() 409 elif isinstance(pipes, str): 410 pipes = [pipes] 411 412 # Sort the pipes. 413 pipes.sort() 414 415 # Create the XML document object. 416 xmldoc = xml.dom.minidom.Document() 417 418 # Create the top level element, including the relax URL. 419 top_element = xmldoc.createElementNS('http://www.nmr-relax.com', 'relax') 420 top_element.setAttribute("xmlns", "http://www.nmr-relax.com") 421 422 # Append the element. 423 xmldoc.appendChild(top_element) 424 425 # Set the relax version number, and add a creation time. 426 top_element.setAttribute('version', version.version) 427 top_element.setAttribute('time', asctime()) 428 top_element.setAttribute('file_version', "2") 429 rev = version.revision() 430 if rev: 431 top_element.setAttribute('revision', rev) 432 url = version.url() 433 if url: 434 top_element.setAttribute('url', url) 435 436 # Add all objects in the data store base object to the XML element. 437 if all: 438 blacklist = list(self.__class__.__dict__.keys() + dict.__dict__.keys()) 439 for name in dir(self): 440 # Skip blacklisted objects. 441 if name in blacklist: 442 continue 443 444 # Skip special objects. 445 if search('^_', name): 446 continue 447 448 # Execute any to_xml() methods, and add that object to the blacklist. 449 obj = getattr(self, name) 450 if hasattr(obj, 'to_xml'): 451 obj.to_xml(xmldoc, top_element) 452 blacklist = blacklist + [name] 453 454 # Remove the current data pipe from the blacklist! 455 blacklist.remove('current_pipe') 456 457 # Add all simple python objects within the store. 458 fill_object_contents(xmldoc, top_element, object=self, blacklist=blacklist) 459 460 # Loop over the pipes. 461 for pipe in pipes: 462 # Create the pipe XML element and add it to the top level XML element. 463 pipe_element = xmldoc.createElement('pipe') 464 top_element.appendChild(pipe_element) 465 466 # Set the data pipe attributes. 467 pipe_element.setAttribute('desc', 'The contents of a relax data pipe') 468 pipe_element.setAttribute('name', pipe) 469 pipe_element.setAttribute('type', self[pipe].pipe_type) 470 471 # Fill the data pipe XML element. 472 self[pipe].to_xml(xmldoc, pipe_element) 473 474 # Write out the XML file. 475 file.write(xmldoc.toprettyxml(indent=' '))
476