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 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
58 """The relax data storage object."""
59
60
61 current_pipe = None
62 __builtin__.cdp = None
63
64
65 instance = None
66
80
81
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
90 text = "The relax data storage object.\n"
91
92
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
103 text = text + "\n"
104 text = text + "Data store objects:\n"
105 names = sorted(self.__class__.__dict__.keys())
106 for name in names:
107
108 obj = getattr(self, name)
109
110
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
117 text = text + "\n"
118 text = text + "Inherited dictionary methods:\n"
119 for name in dir(dict):
120
121 if search("^_", name):
122 continue
123
124
125 if name in list(self.__class__.__dict__.keys()):
126 continue
127
128
129 obj = getattr(self, name)
130
131
132 text = text + " %s %s: %s\n" % (name, type(obj), split(obj.__doc__, '\n')[0])
133
134
135 text = text + "\n"
136 text = text + "All other objects:\n"
137 for name in dir(self):
138
139 if search("^_", name):
140 continue
141
142
143 if name in list(self.__class__.__dict__.keys()):
144 continue
145
146
147 if name in dir(dict):
148 continue
149
150
151 obj = getattr(self, name)
152
153
154 text = text + " %s %s: %s\n" % (name, type(obj), obj)
155
156
157 return text
158
159
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
168 for key in list(self.__dict__.keys()):
169
170 del self.__dict__[key]
171
172
173 self.instance.clear()
174
175
176 __builtin__.cdp = None
177
178
179 self.instance.relax_gui = Gui()
180
181
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
200 if pipe_name in list(self.instance.keys()):
201 raise RelaxPipeError(pipe_name)
202
203
204 self[pipe_name] = PipeContainer()
205
206
207 self[pipe_name].pipe_type = pipe_type
208
209
210 if switch:
211
212 self.instance.current_pipe = pipe_name
213 __builtin__.cdp = self[pipe_name]
214
215
216 status.observers.pipe_alteration.notify()
217
218
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
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
232 blacklist = [
233 'relax_gui'
234 ]
235
236
237 for name in dir(self):
238
239 if name in list(self.__class__.__dict__.keys()):
240 continue
241
242
243 if name in list(dict.__dict__.keys()):
244 continue
245
246
247 if search("^__", name):
248 continue
249
250
251 if name in blacklist:
252 continue
253
254
255 stderr.write("The relax data store contains the object %s.\n" % name)
256 return False
257
258
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
288 doc = xml.dom.minidom.parse(file)
289
290
291 relax_node = doc.childNodes[0]
292
293
294 file_version = str(relax_node.getAttribute('version'))
295
296
297 gui_nodes = relax_node.getElementsByTagName('relax_gui')
298 if gui_nodes:
299 self.relax_gui.from_xml(gui_nodes[0])
300
301
302 xml_to_object(relax_node, self, blacklist=['pipe', 'relax_gui'])
303
304
305 pipe_nodes = relax_node.getElementsByTagName('pipe')
306
307
308 if pipe_to:
309
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
314 pipe_type = pipe_nodes[0].getAttribute('type')
315
316
317 if not pipe_to in self:
318 raise RelaxNoPipeError(pipe_to)
319
320
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
325 if not self[pipe_to].is_empty():
326 raise RelaxError("The data pipe '%s' is not empty." % pipe_to)
327
328
329 self[pipe_to].from_xml(pipe_nodes[0], dir=dir)
330
331
332 else:
333
334 for pipe_node in pipe_nodes:
335
336 pipe_name = str(pipe_node.getAttribute('name'))
337 pipe_type = pipe_node.getAttribute('type')
338
339
340 if pipe_name in self:
341 raise RelaxPipeError(pipe_name)
342
343
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
348 for pipe_node in pipe_nodes:
349
350 pipe_name = str(pipe_node.getAttribute('name'))
351 pipe_type = pipe_node.getAttribute('type')
352
353
354 switch = False
355 if self.current_pipe == None:
356 switch = True
357 self.add(pipe_name, pipe_type, switch=switch)
358
359
360 self[pipe_name].from_xml(pipe_node, file_version=file_version, dir=dir)
361
362
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
381 all = False
382 if not pipes:
383 all = True
384 pipes = self.keys()
385 elif isinstance(pipes, str):
386 pipes = [pipes]
387
388
389 pipes.sort()
390
391
392 xmldoc = xml.dom.minidom.Document()
393
394
395 top_element = xmldoc.createElementNS('http://www.nmr-relax.com', 'relax')
396
397
398 xmldoc.appendChild(top_element)
399
400
401 top_element.setAttribute('version', version)
402 top_element.setAttribute('time', asctime())
403
404
405 if all:
406 blacklist = list(self.__class__.__dict__.keys() + dict.__dict__.keys())
407 for name in dir(self):
408
409 if name in blacklist:
410 continue
411
412
413 if search('^_', name):
414 continue
415
416
417 obj = getattr(self, name)
418 if hasattr(obj, 'to_xml'):
419 obj.to_xml(xmldoc, top_element)
420 blacklist = blacklist + [name]
421
422
423 blacklist.remove('current_pipe')
424
425
426 fill_object_contents(xmldoc, top_element, object=self, blacklist=blacklist)
427
428
429 for pipe in pipes:
430
431 pipe_element = xmldoc.createElement('pipe')
432 top_element.appendChild(pipe_element)
433
434
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
440 self[pipe].to_xml(xmldoc, pipe_element)
441
442
443 file.write(xmldoc.toprettyxml(indent=' '))
444