1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24 """Package containing the relax data storage object."""
25
26
27
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
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
58 """The relax data storage object."""
59
60
61 current_pipe = None
62 __builtin__.cdp = None
63
64
65 instance = None
66
81
82
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
91 text = "The relax data storage object.\n"
92
93
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
104 text = text + "\n"
105 text = text + "Data store objects:\n"
106 names = sorted(self.__class__.__dict__.keys())
107 for name in names:
108
109 obj = getattr(self, name)
110
111
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
118 text = text + "\n"
119 text = text + "Inherited dictionary methods:\n"
120 for name in dir(dict):
121
122 if search("^_", name):
123 continue
124
125
126 if name in list(self.__class__.__dict__.keys()):
127 continue
128
129
130 obj = getattr(self, name)
131
132
133 text = text + " %s %s: %s\n" % (name, type(obj), split(obj.__doc__, '\n')[0])
134
135
136 text = text + "\n"
137 text = text + "All other objects:\n"
138 for name in dir(self):
139
140 if search("^_", name):
141 continue
142
143
144 if name in list(self.__class__.__dict__.keys()):
145 continue
146
147
148 if name in dir(dict):
149 continue
150
151
152 obj = getattr(self, name)
153
154
155 text = text + " %s %s: %s\n" % (name, type(obj), obj)
156
157
158 return text
159
160
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
169 for key in list(self.__dict__.keys()):
170
171 del self.__dict__[key]
172
173
174 self.instance.clear()
175
176
177 __builtin__.cdp = None
178
179
180 self.instance.pipe_bundles = {}
181
182
183 self.instance.relax_gui = Gui()
184
185
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
206 if pipe_name in list(self.instance.keys()):
207 raise RelaxPipeError(pipe_name)
208
209
210 self[pipe_name] = PipeContainer()
211
212
213 self[pipe_name].pipe_type = pipe_type
214
215
216 if bundle:
217
218 if bundle not in self.pipe_bundles.keys():
219 self.pipe_bundles[bundle] = []
220
221
222 self.pipe_bundles[bundle].append(pipe_name)
223
224
225 if switch:
226
227 self.instance.current_pipe = pipe_name
228 __builtin__.cdp = self[pipe_name]
229
230
231 status.observers.pipe_alteration.notify()
232
233
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
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
250 blacklist = [
251 'pipe_bundles',
252 'relax_gui'
253 ]
254
255
256 for name in dir(self):
257
258 if name in list(self.__class__.__dict__.keys()):
259 continue
260
261
262 if name in list(dict.__dict__.keys()):
263 continue
264
265
266 if search("^__", name):
267 continue
268
269
270 if name in blacklist:
271 continue
272
273
274 if verbosity:
275 stderr.write("The relax data store contains the object %s.\n" % name)
276 return False
277
278
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
308 doc = xml.dom.minidom.parse(file)
309
310
311 relax_node = doc.childNodes[0]
312
313
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
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
326 xml_to_object(relax_node, self, file_version=file_version, blacklist=['pipe', 'relax_gui'])
327
328
329 pipe_nodes = relax_node.getElementsByTagName('pipe')
330
331
332 if pipe_to:
333
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
338 pipe_type = pipe_nodes[0].getAttribute('type')
339
340
341 if not pipe_to in self:
342 raise RelaxNoPipeError(pipe_to)
343
344
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
349 if not self[pipe_to].is_empty():
350 raise RelaxError("The data pipe '%s' is not empty." % pipe_to)
351
352
353 self[pipe_to].from_xml(pipe_nodes[0], dir=dir, file_version=file_version)
354
355
356 else:
357
358 for pipe_node in pipe_nodes:
359
360 pipe_name = str(pipe_node.getAttribute('name'))
361 pipe_type = pipe_node.getAttribute('type')
362
363
364 if pipe_name in self:
365 raise RelaxPipeError(pipe_name)
366
367
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
372 for pipe_node in pipe_nodes:
373
374 pipe_name = str(pipe_node.getAttribute('name'))
375 pipe_type = pipe_node.getAttribute('type')
376
377
378 switch = False
379 if self.current_pipe == None:
380 switch = True
381 self.add(pipe_name, pipe_type, switch=switch)
382
383
384 self[pipe_name].from_xml(pipe_node, file_version=file_version, dir=dir)
385
386
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
405 all = False
406 if not pipes:
407 all = True
408 pipes = self.keys()
409 elif isinstance(pipes, str):
410 pipes = [pipes]
411
412
413 pipes.sort()
414
415
416 xmldoc = xml.dom.minidom.Document()
417
418
419 top_element = xmldoc.createElementNS('http://www.nmr-relax.com', 'relax')
420 top_element.setAttribute("xmlns", "http://www.nmr-relax.com")
421
422
423 xmldoc.appendChild(top_element)
424
425
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
437 if all:
438 blacklist = list(self.__class__.__dict__.keys() + dict.__dict__.keys())
439 for name in dir(self):
440
441 if name in blacklist:
442 continue
443
444
445 if search('^_', name):
446 continue
447
448
449 obj = getattr(self, name)
450 if hasattr(obj, 'to_xml'):
451 obj.to_xml(xmldoc, top_element)
452 blacklist = blacklist + [name]
453
454
455 blacklist.remove('current_pipe')
456
457
458 fill_object_contents(xmldoc, top_element, object=self, blacklist=blacklist)
459
460
461 for pipe in pipes:
462
463 pipe_element = xmldoc.createElement('pipe')
464 top_element.appendChild(pipe_element)
465
466
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
472 self[pipe].to_xml(xmldoc, pipe_element)
473
474
475 file.write(xmldoc.toprettyxml(indent=' '))
476