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

Source Code for Package data

  1  ############################################################################### 
  2  #                                                                             # 
  3  # Copyright (C) 2003-2011 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  from version 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.relax_gui = Gui() 77 78 # Already initialised, so return the instance. 79 return self.instance
80 81
82 - def __repr__(self):
83 """The string representation of the object. 84 85 Rather than using the standard Python conventions (either the string representation of the 86 value or the "<...desc...>" notation), a rich-formatted description of the object is given. 87 """ 88 89 # Intro text. 90 text = "The relax data storage object.\n" 91 92 # The data pipes. 93 text = text + "\n" 94 text = text + "Data pipes:\n" 95 pipes = list(self.instance.keys()) 96 if pipes: 97 for pipe in pipes: 98 text = text + " %s\n" % repr(pipe) 99 else: 100 text = text + " None\n" 101 102 # Data store objects. 103 text = text + "\n" 104 text = text + "Data store objects:\n" 105 names = sorted(self.__class__.__dict__.keys()) 106 for name in names: 107 # The object. 108 obj = getattr(self, name) 109 110 # The text. 111 if obj == None or isinstance(obj, str): 112 text = text + " %s %s: %s\n" % (name, type(obj), obj) 113 else: 114 text = text + " %s %s: %s\n" % (name, type(obj), split(obj.__doc__, '\n')[0]) 115 116 # dict methods. 117 text = text + "\n" 118 text = text + "Inherited dictionary methods:\n" 119 for name in dir(dict): 120 # Skip special methods. 121 if search("^_", name): 122 continue 123 124 # Skip overwritten methods. 125 if name in list(self.__class__.__dict__.keys()): 126 continue 127 128 # The object. 129 obj = getattr(self, name) 130 131 # The text. 132 text = text + " %s %s: %s\n" % (name, type(obj), split(obj.__doc__, '\n')[0]) 133 134 # All other objects. 135 text = text + "\n" 136 text = text + "All other objects:\n" 137 for name in dir(self): 138 # Skip special methods. 139 if search("^_", name): 140 continue 141 142 # Skip overwritten methods. 143 if name in list(self.__class__.__dict__.keys()): 144 continue 145 146 # Skip dictionary methods. 147 if name in dir(dict): 148 continue 149 150 # The object. 151 obj = getattr(self, name) 152 153 # The text. 154 text = text + " %s %s: %s\n" % (name, type(obj), obj) 155 156 # Return the text. 157 return text
158 159
160 - def __reset__(self):
161 """Delete all the data from the relax data storage object. 162 163 This method is to make the current single instance of the Data object identical to a newly 164 created instance of Data, hence resetting the relax program state. 165 """ 166 167 # Loop over the keys of self.__dict__ and delete the corresponding object. 168 for key in list(self.__dict__.keys()): 169 # Delete the object. 170 del self.__dict__[key] 171 172 # Remove all items from the dictionary. 173 self.instance.clear() 174 175 # Reset the current data pipe. 176 __builtin__.cdp = None 177 178 # Re-add the GUI object. 179 self.instance.relax_gui = Gui() 180 181 # Signal the change. 182 status.observers.reset.notify() 183 status.observers.pipe_alteration.notify()
184 185
186 - def add(self, pipe_name, pipe_type, switch=True):
187 """Method for adding a new data pipe container to the dictionary. 188 189 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. 190 191 @param pipe_name: The name of the new data pipe. 192 @type pipe_name: str 193 @param pipe_type: The data pipe type. 194 @type pipe_type: str 195 @keyword switch: A flag which if True will cause the new data pipe to be set to the current data pipe. 196 @type switch: bool 197 """ 198 199 # Test if the pipe already exists. 200 if pipe_name in list(self.instance.keys()): 201 raise RelaxPipeError(pipe_name) 202 203 # Create a new container. 204 self[pipe_name] = PipeContainer() 205 206 # Add the data pipe type string to the container. 207 self[pipe_name].pipe_type = pipe_type 208 209 # Change the current data pipe. 210 if switch: 211 # Set the current data pipe. 212 self.instance.current_pipe = pipe_name 213 __builtin__.cdp = self[pipe_name] 214 215 # Signal the switch. 216 status.observers.pipe_alteration.notify()
217 218
219 - def is_empty(self):
220 """Method for testing if the relax data store is empty. 221 222 @return: True if the data store is empty, False otherwise. 223 @rtype: bool 224 """ 225 226 # No pipes should exist. 227 if not self.keys() == []: 228 stderr.write("The relax data store contains the data pipes %s.\n" % self.keys()) 229 return False 230 231 # Objects which should be in here. 232 blacklist = [ 233 'relax_gui' 234 ] 235 236 # An object has been added to the data store. 237 for name in dir(self): 238 # Skip the data store methods. 239 if name in list(self.__class__.__dict__.keys()): 240 continue 241 242 # Skip the dict methods. 243 if name in list(dict.__dict__.keys()): 244 continue 245 246 # Skip special objects. 247 if search("^__", name): 248 continue 249 250 # Blacklisted objects to skip. 251 if name in blacklist: 252 continue 253 254 # An object has been added. 255 stderr.write("The relax data store contains the object %s.\n" % name) 256 return False 257 258 # The data store is empty. 259 return True
260 261
262 - def from_xml(self, file, dir=None, pipe_to=None, verbosity=1):
263 """Parse a XML document representation of a data pipe, and load it into the relax data store. 264 265 @param file: The open file object. 266 @type file: file 267 @keyword dir: The name of the directory containing the results file (needed 268 for loading external files). 269 @type dir: str 270 @keyword pipe_to: The data pipe to load the XML data pipe into (the file must only 271 contain one data pipe). 272 @type pipe_to: str 273 @keyword verbosity: A flag specifying the amount of information to print. The 274 higher the value, the greater the verbosity. 275 @type verbosity: int 276 @raises RelaxError: If pipe_to is given and the file contains multiple pipe 277 elements; or if the data pipes in the XML file already exist in 278 the relax data store; or if the data pipe type is invalid; or 279 if the target data pipe is not empty. 280 @raises RelaxNoPipeError: If pipe_to is given but the data pipe does not exist. 281 @raises RelaxError: If the data pipes in the XML file already exist in the relax 282 data store, or if the data pipe type is invalid. 283 @raises RelaxPipeError: If the data pipes of the XML file are already present in the 284 relax data store. 285 """ 286 287 # Create the XML document from the file. 288 doc = xml.dom.minidom.parse(file) 289 290 # Get the relax node. 291 relax_node = doc.childNodes[0] 292 293 # Get the relax version of the XML file. 294 file_version = str(relax_node.getAttribute('version')) 295 296 # Get the GUI nodes. 297 gui_nodes = relax_node.getElementsByTagName('relax_gui') 298 if gui_nodes: 299 self.relax_gui.from_xml(gui_nodes[0]) 300 301 # Recreate all the data store data structures. 302 xml_to_object(relax_node, self, blacklist=['pipe', 'relax_gui']) 303 304 # Get the pipe nodes. 305 pipe_nodes = relax_node.getElementsByTagName('pipe') 306 307 # Target loading to a specific pipe (for pipe results reading). 308 if pipe_to: 309 # Check if there are multiple pipes in the XML file. 310 if len(pipe_nodes) > 1: 311 raise RelaxError("The pipe_to target pipe argument '%s' cannot be given as the file contains multiple pipe elements." % pipe_to) 312 313 # The pipe type. 314 pipe_type = pipe_nodes[0].getAttribute('type') 315 316 # Check that the pipe already exists. 317 if not pipe_to in self: 318 raise RelaxNoPipeError(pipe_to) 319 320 # Check if the pipe type matches. 321 if pipe_type != self[pipe_to].pipe_type: 322 raise RelaxError("The XML file pipe type '%s' does not match the pipe type '%s'" % (pipe_type, self[pipe_to].pipe_type)) 323 324 # Check if the pipe is empty. 325 if not self[pipe_to].is_empty(): 326 raise RelaxError("The data pipe '%s' is not empty." % pipe_to) 327 328 # Load the data. 329 self[pipe_to].from_xml(pipe_nodes[0], dir=dir) 330 331 # Load the state. 332 else: 333 # Checks. 334 for pipe_node in pipe_nodes: 335 # The pipe name and type. 336 pipe_name = str(pipe_node.getAttribute('name')) 337 pipe_type = pipe_node.getAttribute('type') 338 339 # Existence check. 340 if pipe_name in self: 341 raise RelaxPipeError(pipe_name) 342 343 # Valid type check. 344 if not pipe_type in generic_fns.pipes.VALID_TYPES: 345 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)) 346 347 # Load the data pipes. 348 for pipe_node in pipe_nodes: 349 # The pipe name and type. 350 pipe_name = str(pipe_node.getAttribute('name')) 351 pipe_type = pipe_node.getAttribute('type') 352 353 # Add the data pipe. 354 switch = False 355 if self.current_pipe == None: 356 switch = True 357 self.add(pipe_name, pipe_type, switch=switch) 358 359 # Fill the pipe. 360 self[pipe_name].from_xml(pipe_node, file_version=file_version, dir=dir) 361 362 # Set the current pipe. 363 if self.current_pipe in self.keys(): 364 __builtin__.cdp = self[self.current_pipe]
365 366
367 - def to_xml(self, file, pipes=None):
368 """Create a XML document representation of the current data pipe. 369 370 This method creates the top level XML document including all the information needed 371 about relax, calls the PipeContainer.xml_write() method to fill in the document contents, 372 and writes the XML into the file object. 373 374 @param file: The open file object. 375 @type file: file 376 @param pipes: The name of the pipe, or list of pipes to place in the XML file. 377 @type pipes: str or list of str 378 """ 379 380 # The pipes to include in the XML file. 381 all = False 382 if not pipes: 383 all = True 384 pipes = self.keys() 385 elif isinstance(pipes, str): 386 pipes = [pipes] 387 388 # Sort the pipes. 389 pipes.sort() 390 391 # Create the XML document object. 392 xmldoc = xml.dom.minidom.Document() 393 394 # Create the top level element, including the relax URL. 395 top_element = xmldoc.createElementNS('http://www.nmr-relax.com', 'relax') 396 397 # Append the element. 398 xmldoc.appendChild(top_element) 399 400 # Set the relax version number, and add a creation time. 401 top_element.setAttribute('version', version) 402 top_element.setAttribute('time', asctime()) 403 404 # Add all objects in the data store base object to the XML element. 405 if all: 406 blacklist = list(self.__class__.__dict__.keys() + dict.__dict__.keys()) 407 for name in dir(self): 408 # Skip blacklisted objects. 409 if name in blacklist: 410 continue 411 412 # Skip special objects. 413 if search('^_', name): 414 continue 415 416 # Execute any to_xml() methods, and add that object to the blacklist. 417 obj = getattr(self, name) 418 if hasattr(obj, 'to_xml'): 419 obj.to_xml(xmldoc, top_element) 420 blacklist = blacklist + [name] 421 422 # Remove the current data pipe from the blacklist! 423 blacklist.remove('current_pipe') 424 425 # Add all simple python objects within the store. 426 fill_object_contents(xmldoc, top_element, object=self, blacklist=blacklist) 427 428 # Loop over the pipes. 429 for pipe in pipes: 430 # Create the pipe XML element and add it to the top level XML element. 431 pipe_element = xmldoc.createElement('pipe') 432 top_element.appendChild(pipe_element) 433 434 # Set the data pipe attributes. 435 pipe_element.setAttribute('desc', 'The contents of a relax data pipe') 436 pipe_element.setAttribute('name', pipe) 437 pipe_element.setAttribute('type', self[pipe].pipe_type) 438 439 # Fill the data pipe XML element. 440 self[pipe].to_xml(xmldoc, pipe_element) 441 442 # Write out the XML file. 443 file.write(xmldoc.toprettyxml(indent=' '))
444