source: sasview/invariantview/perspectives/invariant/invariant_state.py @ f310316

ESS_GUIESS_GUI_DocsESS_GUI_batch_fittingESS_GUI_bumps_abstractionESS_GUI_iss1116ESS_GUI_iss879ESS_GUI_iss959ESS_GUI_openclESS_GUI_orderingESS_GUI_sync_sascalccostrafo411magnetic_scattrelease-4.1.1release-4.1.2release-4.2.2release_4.0.1ticket-1009ticket-1094-headlessticket-1242-2d-resolutionticket-1243ticket-1249ticket885unittest-saveload
Last change on this file since f310316 was f310316, checked in by Jae Cho <jhjcho@…>, 14 years ago

conficts between PIL and py2exe found, fixed report display, and removed the saving as pdf file

  • Property mode set to 100644
File size: 29.5 KB
Line 
1import time, os, sys
2import logging
3import copy
4import DataLoader
5from xml.dom.minidom import parse
6from lxml import etree
7"""
8try:
9    import PIL.Image as Image
10    import PIL.PngImagePlugin as PngImagePlugin
11    Image._initialized = 2
12except:
13    try:
14        import Image
15        import PngImagePlugin
16        Image._initialized = 2
17    except:
18        Image = None   
19"""
20
21
22from DataLoader.readers.cansas_reader import Reader as CansasReader
23from DataLoader.readers.cansas_reader import get_content
24from sans.guiframe.utils import format_number
25from sans.guiframe.dataFitting import Theory1D, Data1D
26INVNODE_NAME = 'invariant'
27CANSAS_NS = "cansas1d/1.0"
28# default state
29list = {'file': 'None',
30        'compute_num':0,
31        'state_num':0,
32        'is_time_machine':False,
33        'background_tcl':0.0,
34        'scale_tcl':1.0,
35        'contrast_tcl':1.0,
36        'porod_constant_tcl':'',
37        'npts_low_tcl':10,
38        'npts_high_tcl':10,
39        'power_high_tcl':4.0,
40        'power_low_tcl': 4.0,
41        'enable_high_cbox':False,
42        'enable_low_cbox':False,
43        'guinier': True,
44        'power_law_high': False,
45        'power_law_low': False,
46        'fit_enable_high': False,
47        'fit_enable_low': False,
48        'fix_enable_high':True,
49        'fix_enable_low':True,
50        'volume_tcl':'',
51        'volume_err_tcl':'',
52        'surface_tcl':'',
53        'surface_err_tcl':''}
54# list of states: This list will be filled as panel init and the number of states increases
55state_list = {}
56bookmark_list = {}
57# list of input parameters (will be filled up on panel init) used by __str__
58input_list = {'background_tcl':0,
59        'scale_tcl':0,
60        'contrast_tcl':0,
61        'porod_constant_tcl':'',
62        'npts_low_tcl':0,
63        'npts_high_tcl':0,
64        'power_high_tcl':0,
65        'power_low_tcl': 0} 
66# list of output parameters (order sensitive) used by __str__   
67output_list = [["qstar_low",                  "Q* from low Q extrapolation [1/(cm*A)]"],
68               ["qstar_low_err",             "dQ* from low Q extrapolation"],
69               ["qstar_low_percent",  "Q* percent from low Q extrapolation"],
70               ["qstar",                                     "Q* from data [1/(cm*A)]"],
71               ["qstar_err",                                "dQ* from data"],
72               ["qstar_percent",                     "Q* percent from data"],
73               ["qstar_high",                "Q* from high Q extrapolation [1/(cm*A)]"],
74               ["qstar_high_err",           "dQ* from high Q extrapolation"],
75               ["qstar_high_percent", "Q* percent from low Q extrapolation"],
76               ["qstar_total",                                   "total Q* [1/(cm*A)]"],
77               ["qstar_total_err",                              "total dQ*"],
78               ["volume",                                 "volume fraction"],
79               ["volume_err",                       "volume fraction error"],
80               ["surface",                               "specific surface"],
81               ["surface_err",                     "specific surface error"]]
82
83   
84
85class InvariantState(object):
86    """
87    Class to hold the state information of the InversionControl panel.
88    """
89    def __init__(self):
90        """
91        Default values
92        """
93        # Input
94        self.file  = None
95        self.data = Data1D(x=[], y=[], dx=None, dy=None)
96        self.theory_lowQ =  Theory1D(x=[], y=[], dy=None)
97        self.theory_highQ = Theory1D(x=[], y=[], dy=None)
98        #self.is_time_machine = False
99        self.saved_state = list
100        self.state_list = state_list
101        self.bookmark_list = bookmark_list
102        self.input_list = input_list
103        self.output_list = output_list
104       
105        self.compute_num = 0
106        self.state_num = 0
107        self.timestamp = ('00:00:00', '00/00/0000')
108        self.container = None
109        #plot image
110        self.wximbmp = None
111        # report_html strings
112        import sans.perspectives.invariant as invariant
113        path = invariant.get_data_path(media='media')
114        path_report_html= os.path.join(path,"report_template.html")
115        html_template=open(path_report_html,"r")
116        self.template_str = html_template.read()
117        self.report_str = self.template_str
118        #self.report_str_save = None
119        html_template.close()
120       
121
122       
123    def __str__(self):
124        """
125        Pretty print
126           
127        : return: string representing the state
128        """
129        # Input string
130        compute_num = self.saved_state['compute_num']
131        compute_state = self.state_list[str(compute_num)]
132        my_time, date = self.timestamp
133        file_name = self.file
134
135        state_num = int(self.saved_state['state_num'])
136        state = "\n[Invariant computation for %s: "% file_name
137        state += "performed at %s on %s] \n"%(my_time, date)
138        state += "State No.: %d \n"% state_num
139        state += "\n=== Inputs ===\n"
140       
141        # text ctl general inputs ( excluding extrapolation text ctl)
142        for key,value in self.input_list.iteritems(): 
143            if value == '':
144                continue
145            key_split = key.split('_') 
146            max_ind = len(key_split)-1
147            if key_split[max_ind] == 'tcl': 
148                name =""
149                if key_split[1]== 'low' or key_split[1]== 'high':
150                    continue
151                for ind in range(0,max_ind):
152                    name +=" %s"%key_split[ind]
153                state += "%s:   %s\n"% (name.lstrip(" "),value)
154               
155        # other input parameters       
156        extra_lo = compute_state['enable_low_cbox']
157        if compute_state['enable_low_cbox']:
158            if compute_state['guinier']:
159                extra_lo = 'Guinier'
160            else:
161                extra_lo = 'Power law'
162        extra_hi = compute_state['enable_high_cbox']
163        if compute_state['enable_high_cbox']:
164            extra_hi = 'Power law'
165        state += "\nExtrapolation:  High=%s; Low=%s\n" %(extra_hi,extra_lo)   
166        low_off = False
167        high_off = False
168        for key,value in self.input_list.iteritems(): 
169            key_split = key.split('_') 
170            max_ind = len(key_split)-1   
171            if key_split[max_ind] == 'tcl': 
172                name ="" 
173                # check each buttons whether or not ON or OFF
174                if key_split[1]== 'low' or key_split[1]== 'high':
175                    if not compute_state['enable_low_cbox'] and key_split[max_ind-1] == 'low':
176                        low_off = True
177                        continue             
178                    elif not compute_state['enable_high_cbox'] and key_split[max_ind-1]== 'high':
179                        high_off = True
180                        continue
181                    elif extra_lo == 'Guinier' and key_split[0]== 'power' and key_split[max_ind-1]== 'low':
182                        continue
183                    for ind in range(0,max_ind):
184                        name +=" %s"%key_split[ind]
185                    name = name.lstrip(" ")
186                    if name == "power low" :
187                        if compute_state['fix_enable_low']:
188                            name += ' (Fixed)'
189                        else:
190                            name += ' (Fitted)'
191                    if name == "power high" :
192                        if compute_state['fix_enable_high']:
193                            name += ' (Fixed)'
194                        else:
195                            name += ' (Fitted)'
196                    state += "%s:   %s\n"% (name,value)
197        # Outputs
198        state += "\n=== Outputs ==="
199        for item in output_list:
200            item_split = item[0].split('_') 
201            # Exclude the extrapolation that turned off
202            if len(item_split)>1:
203                if low_off and item_split[1] == 'low': continue
204                if high_off and item_split[1] == 'high': continue
205            max_ind = len(item_split)-1
206            value = None
207            try:
208                # Q* outputs
209                exec "value = self.container.%s\n"% item[0]
210            except:
211                # other outputs than Q*
212                name = item[0]+"_tcl"
213                exec "value = self.saved_state['%s']"% name
214               
215            # Exclude the outputs w/''   
216            if value == '': continue   
217           
218            # Error outputs
219            if item_split[max_ind] == 'err':
220                state += "+- %s "%format_number(value)
221               
222            # Percentage outputs
223            elif item_split[max_ind] == 'percent':
224                try:
225                    value = float(value)*100
226                except:
227                    pass
228                state += "(%s %s)"%(format_number(value),'o/o')
229            # Outputs
230            else:
231                state += "\n%s:   %s "%(item[1],format_number(value,high=True))
232        # Include warning msg
233        state += "\n\nNote:\n" + self.container.warning_msg
234       
235        return state
236
237   
238    def clone_state(self):
239        """
240        deepcopy the state
241        """
242        return copy.deepcopy(self.saved_state)
243   
244
245    def toXML(self, file="inv_state.inv", doc=None, entry_node=None):
246        """
247        Writes the state of the InversionControl panel to file, as XML.
248       
249        Compatible with standalone writing, or appending to an
250        already existing XML document. In that case, the XML document
251        is required. An optional entry node in the XML document may also be given.
252       
253        : param file: file to write to
254        : param doc: XML document object [optional]
255        : param entry_node: XML node within the XML document at which we will append the data [optional]   
256        """
257        from xml.dom.minidom import getDOMImplementation
258        import time
259        timestamp = time.time()
260        # Check whether we have to write a standalone XML file
261        if doc is None:
262            impl = getDOMImplementation()
263       
264            doc_type = impl.createDocumentType(INVNODE_NAME, "1.0", "1.0")     
265       
266            newdoc = impl.createDocument(None, INVNODE_NAME, doc_type)
267            top_element = newdoc.documentElement
268        else:
269            # We are appending to an existing document
270            newdoc = doc
271            top_element = newdoc.createElement(INVNODE_NAME)
272            if entry_node is None:
273                newdoc.documentElement.appendChild(top_element)
274            else:
275                entry_node.appendChild(top_element)
276           
277        attr = newdoc.createAttribute("version")
278        attr.nodeValue = '1.0'
279        top_element.setAttributeNode(attr)
280       
281        # File name
282        element = newdoc.createElement("filename")
283        if self.file is not None:
284            element.appendChild(newdoc.createTextNode(str(self.file)))
285        else:
286            element.appendChild(newdoc.createTextNode(str(file)))
287        top_element.appendChild(element)
288       
289        element = newdoc.createElement("timestamp")
290        element.appendChild(newdoc.createTextNode(time.ctime(timestamp)))
291        attr = newdoc.createAttribute("epoch")
292        attr.nodeValue = str(timestamp)
293        element.setAttributeNode(attr)
294        top_element.appendChild(element)
295       
296        # Current state
297        state = newdoc.createElement("state")
298        top_element.appendChild(state)
299       
300        for name,value in self.saved_state.iteritems():
301            element = newdoc.createElement(str(name))
302            element.appendChild(newdoc.createTextNode(str(value)))
303            state.appendChild(element)
304             
305        # State history list
306        history = newdoc.createElement("history")
307        top_element.appendChild(history)
308       
309        for name, value in self.state_list.iteritems():
310            history_element = newdoc.createElement('state_'+str(name))
311            for state_name,state_value in value.iteritems():
312                state_element = newdoc.createElement(str(state_name))
313                state_element.appendChild(newdoc.createTextNode(str(state_value)))
314                history_element.appendChild(state_element)
315            #history_element.appendChild(state_list_element)
316            history.appendChild(history_element)
317
318        # Bookmarks  bookmark_list[self.bookmark_num] = [my_time,date,state,comp_state]
319        bookmark = newdoc.createElement("bookmark")
320        top_element.appendChild(bookmark)
321        item_list = ['time','date','state','comp_state']
322        for name, value_list in self.bookmark_list.iteritems():
323            element = newdoc.createElement('mark_'+ str(name))
324            time,date,state,comp_state = value_list
325            time_element = newdoc.createElement('time')
326            time_element.appendChild(newdoc.createTextNode(str(value_list[0])))
327            date_element = newdoc.createElement('date')
328            date_element.appendChild(newdoc.createTextNode(str(value_list[1])))
329            state_list_element = newdoc.createElement('state')
330            comp_state_list_element = newdoc.createElement('comp_state')
331            for state_name,state_value in value_list[2].iteritems():
332                state_element = newdoc.createElement(str(state_name))
333                state_element.appendChild(newdoc.createTextNode(str(state_value)))
334                state_list_element.appendChild(state_element)
335            for comp_name,comp_value in value_list[3].iteritems():
336                comp_element = newdoc.createElement(str(comp_name))
337                comp_element.appendChild(newdoc.createTextNode(str(comp_value)))
338                comp_state_list_element.appendChild(comp_element)
339            element.appendChild(time_element)
340            element.appendChild(date_element)
341            element.appendChild(state_list_element)
342            element.appendChild(comp_state_list_element)
343            bookmark.appendChild(element)
344
345        # Save the file
346        if doc is None:
347            fd = open('test000', 'w')
348            fd.write(newdoc.toprettyxml())
349            fd.close()
350            return None
351        else:
352            return newdoc.toprettyxml()
353       
354    def fromXML(self, file=None, node=None):
355        """
356        Load invariant states from a file
357           
358        : param file: .inv file
359        : param node: node of a XML document to read from       
360        """
361        if file is not None:
362            raise RuntimeError, "InvariantSate no longer supports non-CanSAS format for invariant files"
363       
364        if node.get('version')\
365            and node.get('version') == '1.0':
366
367            # Get file name
368            entry = get_content('ns:filename', node)
369            if entry is not None:
370                self.file = entry.text.strip()
371           
372            # Get time stamp
373            entry = get_content('ns:timestamp', node)
374            if entry is not None and entry.get('epoch'):
375                try:
376                    timestamp = (entry.get('epoch'))
377                except:
378                    logging.error("InvariantSate.fromXML: Could not read timestamp\n %s" % sys.exc_value)
379           
380            # Parse bookmarks
381            entry_bookmark = get_content('ns:bookmark', node)
382
383            for ind in range(1,len(entry_bookmark)+1):
384                temp_state = {}
385                temp_bookmark = {}
386                entry = get_content('ns:mark_%s' % ind, entry_bookmark) 
387                               
388                if entry is not None:
389                    time = get_content('ns:time', entry )
390                    val_time = str(time.text.strip())
391                    date = get_content('ns:date', entry )
392                    val_date = str(date.text.strip())
393                    state_entry = get_content('ns:state', entry )
394                    for item in list:
395
396                        input_field = get_content('ns:%s' % item, state_entry )
397                        val = str(input_field.text.strip())
398
399                        if input_field is not None:
400                            try:
401                                exec "temp_state['%s'] = %s"% (item,val)     
402                            except:
403                                exec "temp_state['%s'] = '%s'"% (item,val)
404                           
405                    comp_entry = get_content('ns:comp_state', entry )
406                   
407                    for item in list:
408                        input_field = get_content('ns:%s' % item, comp_entry )
409                        val = str(input_field.text.strip())
410                        if input_field is not None:
411                            try:
412                                exec "temp_bookmark['%s'] = %s"% (item,val)     
413                            except:
414                                exec "temp_bookmark['%s'] = '%s'"% (item,val)
415                    try:
416                        exec "self.bookmark_list[%s] = [val_time,val_date,temp_state,temp_bookmark]"% ind
417
418                    except:
419                        raise "missing components of bookmarks..."
420   
421            # Parse histories
422            entry_history = get_content('ns:history', node)
423
424            for ind in range(0,len(entry_history)):
425                temp_state = {}
426                entry = get_content('ns:state_%s' % ind, entry_history) 
427
428                if entry is not None:
429                    for item in list:
430                        input_field = get_content('ns:%s' % item, entry )
431                        val = str(input_field.text.strip())
432
433                        if input_field is not None:
434                            try:
435                                exec "temp_state['%s'] = %s"% (item,val)         
436                            except:
437                                exec "temp_state['%s'] = '%s'"% (item,val)
438                            finally:
439                                exec "self.state_list['%s'] = temp_state"% ind
440           
441            # Parse current state (ie, saved_state)
442            entry = get_content('ns:state', node)           
443            if entry is not None:
444                for item in list:
445                    input_field = get_content('ns:%s' % item, entry)
446                    val = str(input_field.text.strip())
447                    if input_field is not None:
448                        self.set_saved_state(name=item, value=val)
449
450    def set_report_string(self):
451        """
452        Get the values (strings) from __str__ for report
453        """
454        strings = self.__str__()
455   
456        # default string values
457        for num in range (1,19):
458            exec "s_%s = 'NA'"% str(num)
459        lines = strings.split('\n')
460        # get all string values from __str__()
461        for line in range(0,len(lines)):
462            if line == 1:
463                s_1 = lines[1]
464            elif line == 2:
465                s_2 = lines[2]
466            else:
467                item = lines[line].split(':')
468                item[0] = item[0].strip()
469                if item[0]== "scale":
470                    s_3 = item[1]
471                elif item[0] == "porod constant":
472                    s_4 = item[1]
473                elif item[0] == "background":
474                    s_5 = item[1]
475                elif item[0] == "contrast":
476                    s_6 = item[1]
477                elif item[0] == "Extrapolation":
478                    extra = item[1].split(";")
479                    bool_0 = extra[0].split("=")
480                    bool_1 = extra[1].split("=")
481                    s_7 = " "+bool_0[0]+"Q region = "+bool_0[1]
482                    s_8 = " "+bool_1[0]+"Q region = "+bool_1[1]
483                elif item[0]=="npts low":
484                    s_9 = item[1]
485                elif item[0]=="npts high":
486                    s_10 = item[1]
487                elif item[0] == "volume fraction":
488                    s_17 = item[1]
489                elif item[0] == "specific surface":
490                    s_18 = item[1]
491                elif item[0].split("(")[0].strip()=="power high":
492                    s_11 = item[0]+" ="+item[1]
493                elif item[0].split("(")[0].strip()=="power low":
494                    s_12 = item[0]+" ="+item[1]
495                elif item[0].split("[")[0].strip()=="Q* from low Q extrapolation":
496                    s_13 = item[1]
497                elif item[0].split("[")[0].strip()=="Q* from data":
498                    s_14 = item[1]
499                elif item[0].split("[")[0].strip()=="Q* from high Q extrapolation":
500                    s_15 = item[1]
501                elif item[0].split("[")[0].strip()=="total Q*":
502                    s_16 = item[1]
503                else:
504                    continue
505
506        # make plot image
507        self.set_plot_state(extra_high=bool_0[1],extra_low=bool_1[1])
508        # get ready for report with setting all the html strings
509        self.report_str =  str(self.template_str)% (s_1,s_2,s_3,s_4,s_5,s_6,s_7,s_8,s_9,s_10,s_11,s_12,s_13,s_14,s_15,s_16,s_17,s_18,self.file,"%s")
510
511
512    def set_saved_state(self, name, value):
513        """
514        Set the state list
515                   
516        : param name: name of the state component
517        : param value: value of the state component
518        """
519        rb_list = [['power_law_low','guinier'],['fit_enable_low','fix_enable_low'],['fit_enable_high','fix_enable_high']]
520
521        try:
522            if value == None or value.lstrip().rstrip() =='':
523                exec "self.%s = '%s'" % (name, value)
524                exec "self.saved_state['%s'] = '%s'" %  (name, value)
525            else:
526                exec 'self.%s = %s' % (name, value)
527                exec "self.saved_state['%s'] = %s" %  (name, value)
528
529           
530            # set the count part of radio button clicked False for the saved_state
531            for title,content in rb_list:
532                if name ==  title:
533                    name = content
534                    value = False     
535                elif name == content:
536                    name = title
537                    value = False 
538            exec "self.saved_state['%s'] = '%s'" %  (name, value)     
539            self.state_num = self.saved_state['state_num']
540        except:           
541            pass
542
543    def set_plot_state(self,extra_high=False,extra_low=False):
544        """
545        Build image state that wx.html understand
546        by plotting, putting it into wx.FileSystem image object
547       
548        : extrap_high,extra_low: low/high extrapolations are possible extra-plots
549        """
550        # some imports
551        import cStringIO
552        import matplotlib,wx
553        import matplotlib.pyplot as plt
554        from matplotlib.backends.backend_agg import FigureCanvasAgg
555
556        #we use simple plot, not plotpanel
557        #make matlab figure
558        fig = plt.figure()
559        fig.set_facecolor('w')
560        graph = fig.add_subplot(111)
561
562        #data plot
563        graph.errorbar(self.data.x, self.data.y, yerr=self.data.dy, fmt='o')
564        #low Q extrapolation fit plot
565        if not extra_low == 'False':
566            graph.plot(self.theory_lowQ.x,self.theory_lowQ.y)
567        #high Q extrapolation fit plot
568        if not extra_high == 'False':
569            graph.plot(self.theory_highQ.x,self.theory_highQ.y)
570        graph.set_xscale("log", nonposx='clip')
571        graph.set_yscale("log", nonposy='clip')
572        graph.set_xlabel('$\\rm{Q}(\\AA^{-1})$', fontsize = 12)
573        graph.set_ylabel('$\\rm{Intensity}(cm^{-1})$', fontsize = 12)
574        canvas = FigureCanvasAgg(fig)
575        #actually make image
576        canvas.draw()
577       
578        #make python.Image object
579        #size
580        w,h =canvas.get_width_height()
581        #convert to wx.Image
582        wximg = wx.EmptyImage(w,h)
583        #wxim.SetData(img.convert('RGB').tostring() )
584        wximg.SetData(canvas.tostring_rgb()) 
585        #get the dynamic image for the htmlwindow
586        wximgbmp = wx.BitmapFromImage(wximg)
587        #store the image in wx.FileSystem Object
588        wx.FileSystem.AddHandler(wx.MemoryFSHandler())
589        # use wx.MemoryFSHandler
590        self.imgRAM = wx.MemoryFSHandler()
591        #AddFile, image can be retrieved with 'memory:filename'
592        self.imgRAM.AddFile('img_inv.png',wximgbmp, wx.BITMAP_TYPE_PNG)
593       
594        self.wximgbmp = 'memory:img_inv.png'
595        self.image = fig
596
597class Reader(CansasReader):
598    """
599    Class to load a .inv invariant file
600    """
601    ## File type
602    type_name = "Invariant"
603   
604    ## Wildcards
605    type = ["Invariant file (*.inv)|*.inv"]
606    ## List of allowed extensions
607    ext=['.inv', '.INV'] 
608   
609    def __init__(self, call_back, cansas=True):
610        """
611        Initialize the call-back method to be called
612        after we load a file
613       
614        : param call_back: call-back method
615        : param cansas:  True = files will be written/read in CanSAS format
616                        False = write CanSAS format 
617        """
618        ## Call back method to be executed after a file is read
619        self.call_back = call_back
620        ## CanSAS format flag
621        self.cansas = cansas
622
623    def read(self, path):
624        """
625        Load a new invariant state from file
626       
627        : param path: file path
628        : return: None
629        """
630        if self.cansas==True:
631            return self._read_cansas(path)
632        else:
633            return self._read_standalone(path)
634       
635    def _read_standalone(self, path):
636        """
637        Load a new invariant state from file.
638        The invariant node is assumed to be the top element.
639       
640        : param path: file path
641        : return: None
642        """
643        # Read the new state from file
644        state = InvariantState()
645
646        state.fromXML(file=path)
647       
648        # Call back to post the new state
649        self.call_back(state)
650        return None
651   
652    def _parse_state(self, entry):
653        """
654        Read an invariant result from an XML node
655       
656        : param entry: XML node to read from
657        : return: InvariantState object
658        """
659        # Create an empty state
660        state = InvariantState()
661
662        # Locate the invariant node
663        try:
664            nodes = entry.xpath('ns:%s' % INVNODE_NAME, namespaces={'ns': CANSAS_NS})
665            state.fromXML(node=nodes[0])
666        except:
667            logging.info("XML document does not contain invariant information.\n %s" % sys.exc_value) 
668        return state
669   
670    def _read_cansas(self, path):
671        """
672        Load data and invariant information from a CanSAS XML file.
673       
674        : param path: file path
675        : return: Data1D object if a single SASentry was found,
676                    or a list of Data1D objects if multiple entries were found,
677                    or None of nothing was found
678        : raise RuntimeError: when the file can't be opened
679        : raise ValueError: when the length of the data vectors are inconsistent
680        """
681        output = []
682       
683        if os.path.isfile(path):
684            basename  = os.path.basename(path)
685            root, extension = os.path.splitext(basename)
686           
687            if  extension.lower() in self.ext or \
688                extension.lower() == '.xml':
689                tree = etree.parse(path, parser=etree.ETCompatXMLParser())
690       
691                # Check the format version number
692                # Specifying the namespace will take care of the file format version
693                root = tree.getroot()
694               
695                entry_list = root.xpath('/ns:SASroot/ns:SASentry', namespaces={'ns': CANSAS_NS})
696               
697                for entry in entry_list:
698                   
699                    sas_entry = self._parse_entry(entry)
700                    invstate = self._parse_state(entry)
701                    sas_entry.meta_data['invstate'] = invstate
702
703                    sas_entry.filename = invstate.file
704                    output.append(sas_entry)
705               
706        else:
707            raise RuntimeError, "%s is not a file" % path
708
709        # Return output consistent with the loader's api
710        if len(output)==0:
711            return None
712        elif len(output)==1:
713            # Call back to post the new state
714
715            self.call_back(state=output[0].meta_data['invstate'], datainfo = output[0])
716            return output[0]
717        else:
718            return output               
719   
720   
721    def write(self, filename, datainfo=None, invstate=None):
722        """
723        Write the content of a Data1D as a CanSAS XML file
724       
725        : param filename: name of the file to write
726        : param datainfo: Data1D object
727        : param invstate: InvariantState object
728        """
729
730        # Sanity check
731        if self.cansas == True:
732            if datainfo is None:
733                datainfo = DataLoader.data_info.Data1D(x=[], y=[])   
734            elif not issubclass(datainfo.__class__, DataLoader.data_info.Data1D):
735                raise RuntimeError, "The cansas writer expects a Data1D instance: %s" % str(datainfo.__class__.__name__)
736       
737            # Create basic XML document
738            doc, sasentry = self._to_xml_doc(datainfo)
739       
740            # Add the invariant information to the XML document
741            if invstate is not None:
742                invstate.toXML(doc=doc, entry_node=sasentry)
743       
744            # Write the XML document
745            fd = open(filename, 'w')
746            fd.write(doc.toprettyxml())
747            fd.close()
748        else:
749            invstate.toXML(file=filename)
750       
751   
752   
Note: See TracBrowser for help on using the repository browser.