source: sasview/sansview/perspectives/fitting/pagestate.py @ ef16f59

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 ef16f59 was ef16f59, checked in by Jae Cho <jhjcho@…>, 14 years ago

Now it saves and opens all states of fitv taps.

  • Property mode set to 100644
File size: 54.1 KB
Line 
1
2
3################################################################################
4#This software was developed by the University of Tennessee as part of the
5#Distributed Data Analysis of Neutron Scattering Experiments (DANSE)
6#project funded by the US National Science Foundation.
7#
8#See the license text in license.txt
9#
10#copyright 2009, University of Tennessee
11################################################################################
12
13import time
14import os
15import sys
16import copy
17import logging
18import numpy
19
20import xml.dom.minidom
21from xml.dom.minidom import parse
22from lxml import etree
23
24import DataLoader
25from DataLoader.readers.cansas_reader import Reader as CansasReader
26from DataLoader.readers.cansas_reader import get_content, write_node
27from DataLoader.data_info import Data2D, Detector
28
29#Information to read/write state as xml
30FITTING_NODE_NAME = 'fitting_plug_in'
31CANSAS_NS = "cansas1d/1.0"
32
33list_of_data_attributes = [["is_data", "is_data", "bool"],
34                      ["group_id", "data_group_id", "string"],
35                      ["data_name", "data_name", "string"],
36                      ["data_id", "data_id", "string"],
37                      ["name", "name", "string"],
38                      ["data_name", "data_name", "string"]]
39list_of_state_attributes = [["engine_type", "engine_type", "string"],
40                       ["qmin", "qmin", "float"],
41                      ["qmax", "qmax", "float"],
42                      ["npts", "npts", "float"],
43                      ["shape_rbutton", "shape_rbutton", "bool"],
44                      ["shape_indep_rbutton", "shape_indep_rbutton", "bool"],
45                      ["plugin_rbutton", "plugin_rbutton","bool"],
46                      ["struct_rbutton", "struct_rbutton", "bool"],
47                      ["formfactorcombobox", "formfactorcombobox", "float"],
48                      ["structurecombobox", "structurecombobox", "float"],
49                      ["disp_box", "disp_box", "float"],
50                      ["enable_smearer","enable_smearer","bool"],
51                      ["disable_smearer","disable_smearer","bool"],
52                      ["pinhole_smearer","pinhole_smearer","bool"],
53                      ["slit_smearer","slit_smearer","bool"],
54                      ["enable_disp","enable_disp","bool"],
55                      ["disable_disp","disable_disp","bool"],
56                      ["slit_smearer","slit_smearer","bool"],
57                      ["enable2D","enable2D","bool"],
58                      ["cb1","cb1","bool"],
59                      ["tcChi","tcChi","float"],
60                     ["smearer", "smearer", "float"],
61                     ["smear_type","smear_type", "string"],
62                     ["dq_l", "dq_l", "string"],
63                     ["dq_r","dq_r", "string"]]
64
65list_of_model_attributes = [["values", "values"],
66                            ["weights", "weights"]]
67
68list_of_state_parameters = [["parameters", "parameters"] ,                     
69                            ["orientation_parameters", "orientation_params"],
70                            ["dispersity_parameters", "orientation_params_disp"],
71                            ["fixed_param", "fixed_param"],                     
72                            ["fittable_param","fittable_param"]]
73list_of_data_2d_attr = [["xmin", "xmin","float"],
74                        ["xmax","xmax","float"],
75                        ["ymin","ymin","float"],
76                        ["ymax","ymax","float"],
77                        ["_xaxis","_xaxis", "string"],
78                        ["_xunit", "_xunit", "string"],
79                        ["_yaxis","_yaxis","string"],
80                        ["_yunit","_yunit","string"],
81                        ["_zaxis","_zaxis","string"],
82                        ["_zunit","_zunit","string"]]
83list_of_data2d_values = [["qx_data","qx_data","float"],
84                         ["qy_data","qy_data","float"],
85                         ["dqx_data","dqx_data","float"],
86                         ["dqy_data","dqy_data","float"],
87                         ["data","data","float"],
88                         ["q_data","q_data","float"],
89                         ["err_data","err_data","float"],
90                         ["mask","mask","bool"]]
91
92def parse_entry_helper( node, item):
93    """
94    Create a numpy list from value extrated from the node
95   
96    :param node: node from each the value is stored
97    :param item: list name of three strings.the two first are name of data
98        attribute and the third one is the type of the value of that
99        attribute. type can be string, float, bool, etc.
100   
101    : return: numpy array
102    """
103    if node is not None:
104        if item[2] == "string":
105            return str(node.get(item[0]).strip())
106        elif item[2] == "bool":
107            try:
108                return node.get(item[0]).strip() == "True"
109               
110            except:
111                return None
112        else:
113            try:
114                return float(node.get(item[0]))
115            except:
116                return None
117           
118           
119class PageState(object):
120    """
121    Contains information to reconstruct a page of the fitpanel.
122    """
123    def __init__(self, parent=None, model=None, data=None):
124       
125        """
126        Initialize the current state
127       
128        :param model: a selected model within a page
129        :param data:
130       
131        """
132        self.file = None
133        #Time of state creation
134        self.timestamp = time.time()
135        ## Data member to store the dispersion object created
136        self._disp_obj_dict = {}
137        #------------------------
138        #Data used for fitting
139        self.data = data
140        #save additional information on data that dataloader.reader does not read
141        self.is_data = None
142        self.data_name = ""
143       
144        if self.data is not None:
145            self.data_name = self.data.name
146        self.data_id = None
147        if self.data is not None and hasattr(self.data, "id"):
148            self.data_id = self.data.id
149        self.data_group_id = None
150        if self.data is not None and hasattr(self.data, "group_id"):
151            self.data_group_id = self.data.group_id
152       
153        ## reset True change the state of exsiting button
154        self.reset = False
155       
156        #engine type
157        self.engine_type = None
158        # flag to allow data2D plot
159        self.enable2D = False
160        # model on which the fit would be performed
161        self.model = model
162       
163        #fit page manager
164        self.manager = None
165        #Store the parent of this panel parent
166        # For this application fitpanel is the parent
167        self.parent  = parent
168        # Event_owner is the owner of model event
169        self.event_owner = None
170        ##page name
171        self.page_name = ""
172        # Contains link between  model ,all its parameters, and panel organization
173        self.parameters = []
174        # Contains list of parameters that cannot be fitted and reference to
175        #panel objects
176        self.fixed_param = []
177        # Contains list of parameters with dispersity and reference to
178        #panel objects
179        self.fittable_param = []
180        ## orientation parameters
181        self.orientation_params = []
182        ## orientation parmaters for gaussian dispersity
183        self.orientation_params_disp = []
184        ## smearer info
185        self.smearer = None
186        self.smear_type = None
187        self.dq_l = None
188        self.dq_r = None
189
190        #list of dispersion paramaters
191        self.disp_list =[]
192        if self.model is not None:
193            self.disp_list = self.model.getDispParamList()
194        self._disp_obj_dict = {}
195        self.disp_cb_dict = {}
196        self.values = []
197        self.weights = []
198                   
199        #contains link between a model and selected parameters to fit
200        self.param_toFit = []
201        ##dictionary of model type and model class
202        self.model_list_box = None
203        ## save the state of the context menu
204        self.saved_states = {}
205        ## save selection of combobox
206        self.formfactorcombobox = None
207        self.structurecombobox  = None
208        ## radio box to select type of model
209        self.shape_rbutton = False
210        self.shape_indep_rbutton = False
211        self.struct_rbutton = False
212        self.plugin_rbutton = False
213        ## the indice of the current selection
214        self.disp_box = 0
215        ## Qrange
216        ## Q range
217        self.qmin = 0.001
218        self.qmax = 0.1
219        #reset data range
220        self.qmax_x = None
221        self.qmin_x = None
222       
223        self.npts = None
224        self.name = ""
225        ## enable smearering state
226        self.enable_smearer = False
227        self.disable_smearer = True
228        self.pinhole_smearer = False
229        self.slit_smearer   = False
230        ## disperity selection
231        self.enable_disp = False
232        self.disable_disp = True
233       
234        ## state of selected all check button
235        self.cb1 = False
236        ## store value of chisqr
237        self.tcChi = None
238   
239    def clone(self):
240        """
241        Create a new copy of the current object
242        """
243        model = None
244        if self.model is not None:
245            model = self.model.clone()
246            model.name = self.model.name
247        obj = PageState(self.parent, model=model)
248        obj.file = copy.deepcopy(self.file)
249        obj.data = copy.deepcopy(self.data)
250        if self.data is not None:
251            self.data_name = self.data.name
252        obj.data_name = self.data_name
253        obj.is_data = self.is_data
254        obj.model_list_box = copy.deepcopy(self.model_list_box)
255        obj.engine_type = copy.deepcopy(self.engine_type)
256       
257        obj.formfactorcombobox = self.formfactorcombobox
258        obj.structurecombobox  = self.structurecombobox 
259       
260        obj.shape_rbutton = self.shape_rbutton
261        obj.shape_indep_rbutton = self.shape_indep_rbutton
262        obj.struct_rbutton = self.struct_rbutton
263        obj.plugin_rbutton = self.plugin_rbutton
264       
265        obj.manager = self.manager
266        obj.event_owner = self.event_owner
267        obj.disp_list = copy.deepcopy(self.disp_list)
268       
269        obj.enable2D = copy.deepcopy(self.enable2D)
270        obj.parameters = copy.deepcopy(self.parameters)
271        obj.fixed_param = copy.deepcopy(self.fixed_param)
272        obj.fittable_param = copy.deepcopy(self.fittable_param)
273        obj.orientation_params =  copy.deepcopy(self.orientation_params)
274        obj.orientation_params_disp =  copy.deepcopy(self.orientation_params_disp)
275        obj.enable_disp = copy.deepcopy(self.enable_disp)
276        obj.disable_disp = copy.deepcopy(self.disable_disp)
277        obj.tcChi = self.tcChi
278 
279        if len(self._disp_obj_dict)>0:
280            for k , v in self._disp_obj_dict.iteritems():
281                obj._disp_obj_dict[k]= v
282        if len(self.disp_cb_dict)>0:
283            for k , v in self.disp_cb_dict.iteritems():
284                obj.disp_cb_dict[k]= v
285               
286        obj.values = copy.deepcopy(self.values)
287        obj.weights = copy.deepcopy(self.weights)
288        obj.enable_smearer = copy.deepcopy(self.enable_smearer)
289        obj.disable_smearer = copy.deepcopy(self.disable_smearer)
290        obj.pinhole_smearer = copy.deepcopy(self.pinhole_smearer)
291        obj.slit_smearer = copy.deepcopy(self.slit_smearer)
292        obj.smear_type = copy.deepcopy(self.smear_type)
293        obj.dq_l = copy.deepcopy(self.dq_l)
294        obj.dq_r = copy.deepcopy(self.dq_r)
295
296        obj.disp_box = copy.deepcopy(self.disp_box)
297        obj.qmin = copy.deepcopy(self.qmin)
298        obj.qmax = copy.deepcopy(self.qmax)
299        obj.npts = copy.deepcopy(self.npts )
300        obj.cb1 = copy.deepcopy(self.cb1)
301        obj.smearer = copy.deepcopy(self.smearer)
302       
303        for name, state in self.saved_states.iteritems():
304            copy_name = copy.deepcopy(name)
305            copy_state = state.clone()
306            obj.saved_states[copy_name]= copy_state
307        return obj
308   
309    def _repr_helper(self, list, rep):
310        """
311        Helper method to print a state
312        """
313        for item in list:
314            rep += "parameter name: %s \n"%str(item[1])
315            rep += "value: %s\n"%str(item[2])
316            rep += "selected: %s\n"%str(item[0])
317            rep += "error displayed : %s \n"%str(item[4][0])
318            rep += "error value:%s \n"%str(item[4][1])
319            rep += "minimum displayed : %s \n"%str(item[5][0])
320            rep += "minimum value : %s \n"%str(item[5][1])
321            rep += "maximum displayed : %s \n"%str(item[6][0])
322            rep += "maximum value : %s \n"%str(item[6][1])
323            rep += "parameter unit: %s\n\n"%str(item[7])
324        return rep
325   
326    def __repr__(self):
327        """
328        output string for printing
329        """
330        rep = "\nState name: %s\n"%self.file
331        t = time.localtime(self.timestamp)
332        time_str = time.strftime("%b %d %H:%M", t)
333        rep += "State created on : %s\n"%time_str
334        rep += "State form factor combobox selection: %s\n"%self.formfactorcombobox
335        rep += "State structure factor combobox selection: %s\n"%self.structurecombobox
336        rep += "is data : %s\n"%self.is_data
337        rep += "data's name : %s\n"%self.data_name
338        rep += "data's id : %s\n"%self.data_id
339        rep += "model type (form factor) selected: %s\n"%self.shape_rbutton
340        rep += "model type (shape independent) selected: %s\n"%self.shape_indep_rbutton
341        rep += "model type (structure factor) selected: %s\n"%self.struct_rbutton
342        rep += "model type (plug-in ) selected: %s\n"%self.plugin_rbutton
343        rep += "data : %s\n"% str(self.data)
344        rep += "Plotting Range: min: %s, max: %s, steps: %s\n"%(str(self.qmin),
345                                                str(self.qmax),str(self.npts))
346        rep += "Dispersion selection : %s\n"%str(self.disp_box)
347        rep += "Smearing enable : %s\n"%str(self.enable_smearer)
348        rep += "Smearing disable : %s\n"%str(self.disable_smearer)
349        rep += "Pinhole smearer enable : %s\n"%str(self.pinhole_smearer)
350        rep += "Slit smearer enable : %s\n"%str(self.slit_smearer)
351        rep += "Dispersity enable : %s\n"%str(self.enable_disp)
352        rep += "Dispersity disable : %s\n"%str(self.disable_disp)
353        rep += "Slit smearer enable: %s\n"%str(self.slit_smearer)
354        rep += "2D enable : %s\n"%str(self.enable2D)
355        rep += "All parameters checkbox selected: %s\n"%(self.cb1)
356        rep += "Value of Chisqr : %s\n"%str(self.tcChi)
357        rep += "Smear object : %s\n"%str(self.smearer)
358        rep += "Smear type : %s\n"%(self.smear_type)
359        rep += "dq_l  : %s\n"%self.dq_l
360        rep += "dq_r  : %s\n"%self.dq_r
361       
362        rep += "model  : %s\n\n"% str(self.model)
363        rep += "number parameters(self.parameters): %s\n"%len(self.parameters)
364        rep = self._repr_helper( list=self.parameters, rep=rep)
365        rep += "number orientation parameters"
366        rep += "(self.orientation_params): %s\n"%len(self.orientation_params)
367        rep = self._repr_helper( list=self.orientation_params, rep=rep)
368        rep += "number dispersity parameters"
369        rep += "(self.orientation_params_disp): %s\n"%len(self.orientation_params_disp)
370        rep = self._repr_helper( list=self.orientation_params_disp, rep=rep)
371       
372        return rep
373   
374    def _toXML_helper(self, list, element, newdoc):
375        """
376        Helper method to create xml file for saving state
377        """
378        for item in list:
379            sub_element = newdoc.createElement('parameter')
380            sub_element.setAttribute('name', str(item[1]))
381            sub_element.setAttribute('value', str(item[2]))
382            sub_element.setAttribute('selected_to_fit', str(item[0]))
383            sub_element.setAttribute('error_displayed', str(item[4][0]))
384            sub_element.setAttribute('error_value', str(item[4][1]))
385            sub_element.setAttribute('minimum_displayed', str(item[5][0]))
386            sub_element.setAttribute('minimum_value', str(item[5][1]))
387            sub_element.setAttribute('maximum_displayed', str(item[6][0]))
388            sub_element.setAttribute('maximum_value', str(item[6][1]))
389            sub_element.setAttribute('unit', str(item[7]))
390            element.appendChild(sub_element)
391       
392    def toXML(self, file="fitting_state.fitv", doc=None, entry_node=None):
393        """
394        Writes the state of the InversionControl panel to file, as XML.
395       
396        Compatible with standalone writing, or appending to an
397        already existing XML document. In that case, the XML document
398        is required. An optional entry node in the XML document may also be given.
399       
400        :param file: file to write to
401        :param doc: XML document object [optional]
402        :param entry_node: XML node within the XML document at which we will append the data [optional]
403       
404        """
405        from xml.dom.minidom import getDOMImplementation
406
407        # Check whether we have to write a standalone XML file
408        if doc is None:
409            impl = getDOMImplementation()
410            doc_type = impl.createDocumentType(FITTING_NODE_NAME, "1.0", "1.0")     
411            newdoc = impl.createDocument(None, FITTING_NODE_NAME, doc_type)
412            top_element = newdoc.documentElement
413        else:
414            # We are appending to an existing document
415            newdoc = doc
416            top_element = newdoc.createElement(FITTING_NODE_NAME)
417            if entry_node is None:
418                newdoc.documentElement.appendChild(top_element)
419            else:
420                entry_node.appendChild(top_element)
421           
422        attr = newdoc.createAttribute("version")
423        attr.nodeValue = '1.0'
424        top_element.setAttributeNode(attr)
425       
426        # File name
427        element = newdoc.createElement("filename")
428        if self.file is not None:
429            element.appendChild(newdoc.createTextNode(str(self.file)))
430        else:
431            element.appendChild(newdoc.createTextNode(str(file)))
432        top_element.appendChild(element)
433       
434        element = newdoc.createElement("timestamp")
435        element.appendChild(newdoc.createTextNode(time.ctime(self.timestamp)))
436        attr = newdoc.createAttribute("epoch")
437        attr.nodeValue = str(self.timestamp)
438        element.setAttributeNode(attr)
439        top_element.appendChild(element)
440        # Inputs
441        inputs = newdoc.createElement("Attributes")
442        top_element.appendChild(inputs)
443       
444
445        if self.data is not None and hasattr(self.data, "group_id"):
446            self.data_group_id = self.data.group_id
447        if self.data is not None and hasattr(self.data, "is_data"):
448            self.is_data = self.data.is_data
449        if self.data is not None:
450            self.data_name = self.data.name
451        if self.data is not None and hasattr(self.data, "id"):
452            self.data_id = self.data.id
453       
454        for item in list_of_data_attributes:
455            element = newdoc.createElement(item[0])
456            exec "element.setAttribute(item[0], str(self.%s))"%(item[1])
457            inputs.appendChild(element)   
458       
459        for item in list_of_state_attributes:
460            element = newdoc.createElement(item[0])
461            exec "element.setAttribute(item[0], str(self.%s))"%(item[1])
462            inputs.appendChild(element)
463           
464        for item in list_of_model_attributes:
465            element = newdoc.createElement(item[0])
466            exec "list = self.%s"%item[1]
467            for value in list:
468                exec "element.appendChild(newdoc.createTextNode(str(%s)))"%value
469            inputs.appendChild(element)
470           
471        for item in list_of_state_parameters:
472            element = newdoc.createElement(item[0])
473            exec "self._toXML_helper(list=self.%s, element=element, newdoc=newdoc)"%item[1]                       
474            inputs.appendChild(element)
475       
476        # Save the file
477        if doc is None:
478            fd = open(file, 'w')
479            fd.write(newdoc.toprettyxml())
480            fd.close()
481            return None
482        else:
483            return newdoc.toprettyxml()
484       
485    def _fromXML_helper(self, node, list):
486        """
487        Helper function to write state to xml
488        """
489        for item in node:
490            try:
491                name = item.get('name')
492            except:
493                name = None
494            try:
495                value = item.get('value')
496            except:
497                value = None
498            try:
499                selected_to_fit = (item.get('selected_to_fit') == "True")
500            except:
501                selected_to_fit = None
502            try:
503                error_displayed = (item.get('error_displayed') == "True")
504            except:
505                error_displayed = None
506            try: 
507                error_value = item.get('error_value')
508            except:
509                error_value = None
510            try:
511                minimum_displayed = (item.get('minimum_displayed')== "True")
512            except:
513                minimum_displayed = None
514            try:
515                minimum_value = item.get('minimum_value')
516            except:
517                minimum_value = None
518            try:
519                maximum_displayed = (item.get('maximum_displayed') == "True")
520            except:
521                maximum_displayed = None
522            try:
523                maximum_value = item.get('maximum_value')
524            except:
525                maximum_value = None
526            try:
527                unit = item.get('unit')
528            except:
529                unit = None
530            list.append([selected_to_fit, name, value, "+/-",[error_displayed, error_value],
531                         [minimum_displayed,minimum_value],[maximum_displayed,maximum_value], unit])
532       
533    def fromXML(self, file=None, node=None):
534        """
535        Load fitting state from a file
536       
537        :param file: .fitv file
538        :param node: node of a XML document to read from
539       
540        """
541        if file is not None:
542            msg = "PageState no longer supports non-CanSAS"
543            msg += " format for fitting files"
544            raise RuntimeError, msg
545           
546        if node.get('version')and node.get('version') == '1.0':
547           
548            # Get file name
549            entry = get_content('ns:filename', node)
550            if entry is not None:
551                self.file = entry.text.strip()
552               
553            # Get time stamp
554            entry = get_content('ns:timestamp', node)
555            if entry is not None and entry.get('epoch'):
556                try:
557                    self.timestamp = float(entry.get('epoch'))
558                except:
559                    msg = "PageState.fromXML: Could not"
560                    msg += " read timestamp\n %s" % sys.exc_value
561                    logging.error(msg)
562           
563            # Parse fitting attributes
564            entry = get_content('ns:Attributes', node)
565            for item in list_of_data_attributes:
566                node = get_content('ns:%s'%item[0], entry)
567                try:
568                    exec "self.%s = parse_entry_helper(node, item)"%item[0]
569                   
570                except:
571                    raise
572           
573            if entry is not None:
574               
575                for item in list_of_state_attributes:
576                    node = get_content('ns:%s'%item[0], entry)
577                    try:
578                        exec "self.%s = parse_entry_helper(node, item)"%str(item[0])
579                    except:
580                        raise
581                   
582                for item in list_of_model_attributes:
583                    node = get_content("ns:%s"%item[0], entry)
584                    list = []
585                    for value in node:
586                        try:
587                            list.append(float(value)) 
588                        except:
589                            list.append(None)
590                    exec "self.%s = list"%item[1]
591               
592                for item in list_of_state_parameters:
593                    node = get_content("ns:%s"%item[0], entry)
594                    exec "self._fromXML_helper(node=node, list=self.%s)"%item[1]
595                   
596
597class Reader(CansasReader):
598    """
599    Class to load a .fitv fitting file
600    """
601    ## File type
602    type_name = "Fitting"
603   
604    ## Wildcards
605    type = ["Fitting files (*.fitv)|*.fitv"
606            "SANSView file (*.svs)|*.svs"]
607    ## List of allowed extensions
608    ext=['.fitv', '.FITV', '.svs', 'SVS']   
609   
610    def __init__(self, call_back=None, cansas=True):
611        CansasReader.__init__(self)
612        """
613        Initialize the call-back method to be called
614        after we load a file
615       
616        :param call_back: call-back method
617        :param cansas:  True = files will be written/read in CanSAS format
618                        False = write CanSAS format
619           
620        """
621        ## Call back method to be executed after a file is read
622        self.call_back = call_back
623        ## CanSAS format flag
624        self.cansas = cansas
625       
626    def read(self, path):
627        """
628        Load a new P(r) inversion state from file
629       
630        :param path: file path
631       
632        """
633        if self.cansas == True:
634            return self._read_cansas(path)
635     
636    def _data2d_to_xml_doc(self, datainfo):
637        """
638        Create an XML document to contain the content of a Data2D
639       
640        :param datainfo: Data2D object
641       
642        """
643        if not issubclass(datainfo.__class__, Data2D):
644            raise RuntimeError, "The cansas writer expects a Data2D instance"
645       
646        doc = xml.dom.minidom.Document()
647        main_node = doc.createElement("SASroot")
648        main_node.setAttribute("version", self.version)
649        main_node.setAttribute("xmlns", "cansas1d/%s" % self.version)
650        main_node.setAttribute("xmlns:xsi", "http://www.w3.org/2001/XMLSchema-instance")
651        main_node.setAttribute("xsi:schemaLocation", "cansas1d/%s http://svn.smallangles.net/svn/canSAS/1dwg/trunk/cansas1d.xsd" % self.version)
652       
653        doc.appendChild(main_node)
654       
655        entry_node = doc.createElement("SASentry")
656        main_node.appendChild(entry_node)
657       
658        write_node(doc, entry_node, "Title", datainfo.title)
659        if datainfo is not None:
660            write_node(doc, entry_node, "data_class", datainfo.__class__.__name__)
661        for item in datainfo.run:
662            runname = {}
663            if datainfo.run_name.has_key(item) and len(str(datainfo.run_name[item]))>1:
664                runname = {'name': datainfo.run_name[item] }
665            write_node(doc, entry_node, "Run", item, runname)
666        # Data info
667        new_node = doc.createElement("SASdata")
668        entry_node.appendChild(new_node)
669        for item in list_of_data_2d_attr:
670            element = doc.createElement(item[0])
671            exec "element.setAttribute(item[0], str(datainfo.%s))"%(item[1])
672            new_node.appendChild(element)
673           
674        for item in list_of_data2d_values:
675            root_node = doc.createElement(item[0])
676            new_node.appendChild(root_node)
677           
678            exec "temp_list = datainfo.%s"%item[1]
679
680            if temp_list is None or len(temp_list)== 0:
681                element = doc.createElement(item[0])
682                exec "element.appendChild(doc.createTextNode(str(%s)))"%temp_list
683                root_node.appendChild(element)
684            else:
685                for value in temp_list:
686                    element = doc.createElement(item[0])
687                    exec "element.setAttribute(item[0], str(%s))"%value
688                    root_node.appendChild(element)
689       
690        # Sample info
691        sample = doc.createElement("SASsample")
692        if datainfo.sample.name is not None:
693            sample.setAttribute("name", str(datainfo.sample.name))
694        entry_node.appendChild(sample)
695        write_node(doc, sample, "ID", str(datainfo.sample.ID))
696        write_node(doc, sample, "thickness", datainfo.sample.thickness, {"unit":datainfo.sample.thickness_unit})
697        write_node(doc, sample, "transmission", datainfo.sample.transmission)
698        write_node(doc, sample, "temperature", datainfo.sample.temperature, {"unit":datainfo.sample.temperature_unit})
699       
700        for item in datainfo.sample.details:
701            write_node(doc, sample, "details", item)
702       
703        pos = doc.createElement("position")
704        written = write_node(doc, pos, "x", datainfo.sample.position.x, {"unit":datainfo.sample.position_unit})
705        written = written | write_node(doc, pos, "y", datainfo.sample.position.y, {"unit":datainfo.sample.position_unit})
706        written = written | write_node(doc, pos, "z", datainfo.sample.position.z, {"unit":datainfo.sample.position_unit})
707        if written == True:
708            sample.appendChild(pos)
709       
710        ori = doc.createElement("orientation")
711        written = write_node(doc, ori, "roll",  datainfo.sample.orientation.x, {"unit":datainfo.sample.orientation_unit})
712        written = written | write_node(doc, ori, "pitch", datainfo.sample.orientation.y, {"unit":datainfo.sample.orientation_unit})
713        written = written | write_node(doc, ori, "yaw",   datainfo.sample.orientation.z, {"unit":datainfo.sample.orientation_unit})
714        if written == True:
715            sample.appendChild(ori)
716       
717        # Instrument info
718        instr = doc.createElement("SASinstrument")
719        entry_node.appendChild(instr)
720       
721        write_node(doc, instr, "name", datainfo.instrument)
722       
723        #   Source
724        source = doc.createElement("SASsource")
725        if datainfo.source.name is not None:
726            source.setAttribute("name", str(datainfo.source.name))
727        instr.appendChild(source)
728       
729        write_node(doc, source, "radiation", datainfo.source.radiation)
730        write_node(doc, source, "beam_shape", datainfo.source.beam_shape)
731        size = doc.createElement("beam_size")
732        if datainfo.source.beam_size_name is not None:
733            size.setAttribute("name", str(datainfo.source.beam_size_name))
734        written = write_node(doc, size, "x", datainfo.source.beam_size.x, {"unit":datainfo.source.beam_size_unit})
735        written = written | write_node(doc, size, "y", datainfo.source.beam_size.y, {"unit":datainfo.source.beam_size_unit})
736        written = written | write_node(doc, size, "z", datainfo.source.beam_size.z, {"unit":datainfo.source.beam_size_unit})
737        if written == True:
738            source.appendChild(size)
739           
740        write_node(doc, source, "wavelength", datainfo.source.wavelength, {"unit":datainfo.source.wavelength_unit})
741        write_node(doc, source, "wavelength_min", datainfo.source.wavelength_min, {"unit":datainfo.source.wavelength_min_unit})
742        write_node(doc, source, "wavelength_max", datainfo.source.wavelength_max, {"unit":datainfo.source.wavelength_max_unit})
743        write_node(doc, source, "wavelength_spread", datainfo.source.wavelength_spread, {"unit":datainfo.source.wavelength_spread_unit})
744       
745        #   Collimation
746        for item in datainfo.collimation:
747            coll = doc.createElement("SAScollimation")
748            if item.name is not None:
749                coll.setAttribute("name", str(item.name))
750            instr.appendChild(coll)
751           
752            write_node(doc, coll, "length", item.length, {"unit":item.length_unit})
753           
754            for apert in item.aperture:
755                ap = doc.createElement("aperture")
756                if apert.name is not None:
757                    ap.setAttribute("name", str(apert.name))
758                if apert.type is not None:
759                    ap.setAttribute("type", str(apert.type))
760                coll.appendChild(ap)
761               
762                write_node(doc, ap, "distance", apert.distance, {"unit":apert.distance_unit})
763               
764                size = doc.createElement("size")
765                if apert.size_name is not None:
766                    size.setAttribute("name", str(apert.size_name))
767                written = write_node(doc, size, "x", apert.size.x, {"unit":apert.size_unit})
768                written = written | write_node(doc, size, "y", apert.size.y, {"unit":apert.size_unit})
769                written = written | write_node(doc, size, "z", apert.size.z, {"unit":apert.size_unit})
770                if written == True:
771                    ap.appendChild(size)
772
773        #   Detectors
774        for item in datainfo.detector:
775            det = doc.createElement("SASdetector")
776            written = write_node(doc, det, "name", item.name)
777            written = written | write_node(doc, det, "SDD", item.distance, {"unit":item.distance_unit})
778            written = written | write_node(doc, det, "slit_length", item.slit_length, {"unit":item.slit_length_unit})
779            if written == True:
780                instr.appendChild(det)
781           
782            off = doc.createElement("offset")
783            written = write_node(doc, off, "x", item.offset.x, {"unit":item.offset_unit})
784            written = written | write_node(doc, off, "y", item.offset.y, {"unit":item.offset_unit})
785            written = written | write_node(doc, off, "z", item.offset.z, {"unit":item.offset_unit})
786            if written == True:
787                det.appendChild(off)
788           
789            center = doc.createElement("beam_center")
790            written = write_node(doc, center, "x", item.beam_center.x, {"unit":item.beam_center_unit})
791            written = written | write_node(doc, center, "y", item.beam_center.y, {"unit":item.beam_center_unit})
792            written = written | write_node(doc, center, "z", item.beam_center.z, {"unit":item.beam_center_unit})
793            if written == True:
794                det.appendChild(center)
795               
796            pix = doc.createElement("pixel_size")
797            written = write_node(doc, pix, "x", item.pixel_size.x, {"unit":item.pixel_size_unit})
798            written = written | write_node(doc, pix, "y", item.pixel_size.y, {"unit":item.pixel_size_unit})
799            written = written | write_node(doc, pix, "z", item.pixel_size.z, {"unit":item.pixel_size_unit})
800            if written == True:
801                det.appendChild(pix)
802               
803            ori = doc.createElement("orientation")
804            written = write_node(doc, ori, "roll",  item.orientation.x, {"unit":item.orientation_unit})
805            written = written | write_node(doc, ori, "pitch", item.orientation.y, {"unit":item.orientation_unit})
806            written = written | write_node(doc, ori, "yaw",   item.orientation.z, {"unit":item.orientation_unit})
807            if written == True:
808                det.appendChild(ori)
809               
810        # Processes info
811        for item in datainfo.process:
812            node = doc.createElement("SASprocess")
813            entry_node.appendChild(node)
814
815            write_node(doc, node, "name", item.name)
816            write_node(doc, node, "date", item.date)
817            write_node(doc, node, "description", item.description)
818            for term in item.term:
819                value = term['value']
820                del term['value']
821                write_node(doc, node, "term", value, term)
822            for note in item.notes:
823                write_node(doc, node, "SASprocessnote", note)
824        # Return the document, and the SASentry node associated with
825        # the data we just wrote
826        return doc, entry_node
827   
828    def _parse_state(self, entry):
829        """
830        Read a fit result from an XML node
831       
832        :param entry: XML node to read from
833       
834        :return: PageState object
835        """
836        # Create an empty state
837        state = None   
838        # Locate the P(r) node
839        try:
840            nodes = entry.xpath('ns:%s' % FITTING_NODE_NAME, namespaces={'ns': CANSAS_NS})
841            if nodes !=[]:
842                # Create an empty state
843                state =  PageState()
844                state.fromXML(node=nodes[0])
845        except:
846            logging.info("XML document does not contain fitting information.\n %s" % sys.exc_value)
847           
848        return state
849   
850   
851                   
852    def _parse_entry(self, dom):
853        """
854        Parse a SASentry
855       
856        :param node: SASentry node
857       
858        :return: Data1D/Data2D object
859       
860        """
861        node = dom.xpath('ns:data_class', namespaces={'ns': CANSAS_NS})
862        if not node or node[0].text.lstrip().rstrip() != "Data2D":
863            return CansasReader._parse_entry(self, dom)
864       
865        #Parse 2D
866        data_info = Data2D()
867       
868        # Look up title     
869        self._store_content('ns:Title', dom, 'title', data_info)
870       
871        # Look up run number   
872        nodes = dom.xpath('ns:Run', namespaces={'ns': CANSAS_NS})
873        for item in nodes:   
874            if item.text is not None:
875                value = item.text.strip()
876                if len(value) > 0:
877                    data_info.run.append(value)
878                    if item.get('name') is not None:
879                        data_info.run_name[value] = item.get('name')
880                           
881        # Look up instrument name             
882        self._store_content('ns:SASinstrument/ns:name', dom, 'instrument', data_info)
883
884        # Notes
885        note_list = dom.xpath('ns:SASnote', namespaces={'ns': CANSAS_NS})
886        for note in note_list:
887            try:
888                if note.text is not None:
889                    note_value = note.text.strip()
890                    if len(note_value) > 0:
891                        data_info.notes.append(note_value)
892            except:
893                err_mess = "cansas_reader.read: error processing entry notes\n  %s" % sys.exc_value
894                self.errors.append(err_mess)
895                logging.error(err_mess)
896       
897        # Sample info ###################
898        entry = get_content('ns:SASsample', dom)
899        if entry is not None:
900            data_info.sample.name = entry.get('name')
901           
902        self._store_content('ns:SASsample/ns:ID', 
903                     dom, 'ID', data_info.sample)                   
904        self._store_float('ns:SASsample/ns:thickness', 
905                     dom, 'thickness', data_info.sample)
906        self._store_float('ns:SASsample/ns:transmission', 
907                     dom, 'transmission', data_info.sample)
908        self._store_float('ns:SASsample/ns:temperature', 
909                     dom, 'temperature', data_info.sample)
910       
911        nodes = dom.xpath('ns:SASsample/ns:details', namespaces={'ns': CANSAS_NS})
912        for item in nodes:
913            try:
914                if item.text is not None:
915                    detail_value = item.text.strip()
916                    if len(detail_value) > 0:
917                        data_info.sample.details.append(detail_value)
918            except:
919                err_mess = "cansas_reader.read: error processing sample details\n  %s" % sys.exc_value
920                self.errors.append(err_mess)
921                logging.error(err_mess)
922       
923        # Position (as a vector)
924        self._store_float('ns:SASsample/ns:position/ns:x', 
925                     dom, 'position.x', data_info.sample)         
926        self._store_float('ns:SASsample/ns:position/ns:y', 
927                     dom, 'position.y', data_info.sample)         
928        self._store_float('ns:SASsample/ns:position/ns:z', 
929                     dom, 'position.z', data_info.sample)         
930       
931        # Orientation (as a vector)
932        self._store_float('ns:SASsample/ns:orientation/ns:roll', 
933                     dom, 'orientation.x', data_info.sample)         
934        self._store_float('ns:SASsample/ns:orientation/ns:pitch', 
935                     dom, 'orientation.y', data_info.sample)         
936        self._store_float('ns:SASsample/ns:orientation/ns:yaw', 
937                     dom, 'orientation.z', data_info.sample)         
938       
939        # Source info ###################
940        entry = get_content('ns:SASinstrument/ns:SASsource', dom)
941        if entry is not None:
942            data_info.source.name = entry.get('name')
943       
944        self._store_content('ns:SASinstrument/ns:SASsource/ns:radiation', 
945                     dom, 'radiation', data_info.source)                   
946        self._store_content('ns:SASinstrument/ns:SASsource/ns:beam_shape', 
947                     dom, 'beam_shape', data_info.source)                   
948        self._store_float('ns:SASinstrument/ns:SASsource/ns:wavelength', 
949                     dom, 'wavelength', data_info.source)         
950        self._store_float('ns:SASinstrument/ns:SASsource/ns:wavelength_min', 
951                     dom, 'wavelength_min', data_info.source)         
952        self._store_float('ns:SASinstrument/ns:SASsource/ns:wavelength_max', 
953                     dom, 'wavelength_max', data_info.source)         
954        self._store_float('ns:SASinstrument/ns:SASsource/ns:wavelength_spread', 
955                     dom, 'wavelength_spread', data_info.source)   
956       
957        # Beam size (as a vector)   
958        entry = get_content('ns:SASinstrument/ns:SASsource/ns:beam_size', dom)
959        if entry is not None:
960            data_info.source.beam_size_name = entry.get('name')
961           
962        self._store_float('ns:SASinstrument/ns:SASsource/ns:beam_size/ns:x', 
963                     dom, 'beam_size.x', data_info.source)   
964        self._store_float('ns:SASinstrument/ns:SASsource/ns:beam_size/ns:y', 
965                     dom, 'beam_size.y', data_info.source)   
966        self._store_float('ns:SASinstrument/ns:SASsource/ns:beam_size/ns:z', 
967                     dom, 'beam_size.z', data_info.source)   
968       
969        # Collimation info ###################
970        nodes = dom.xpath('ns:SASinstrument/ns:SAScollimation', namespaces={'ns': CANSAS_NS})
971        for item in nodes:
972            collim = Collimation()
973            if item.get('name') is not None:
974                collim.name = item.get('name')
975            self._store_float('ns:length', item, 'length', collim) 
976           
977            # Look for apertures
978            apert_list = item.xpath('ns:aperture', namespaces={'ns': CANSAS_NS})
979            for apert in apert_list:
980                aperture =  Aperture()
981               
982                # Get the name and type of the aperture
983                aperture.name = apert.get('name')
984                aperture.type = apert.get('type')
985                   
986                self._store_float('ns:distance', apert, 'distance', aperture)   
987               
988                entry = get_content('ns:size', apert)
989                if entry is not None:
990                    aperture.size_name = entry.get('name')
991               
992                self._store_float('ns:size/ns:x', apert, 'size.x', aperture)   
993                self._store_float('ns:size/ns:y', apert, 'size.y', aperture)   
994                self._store_float('ns:size/ns:z', apert, 'size.z', aperture)
995               
996                collim.aperture.append(aperture)
997               
998            data_info.collimation.append(collim)
999       
1000        # Detector info ######################
1001        nodes = dom.xpath('ns:SASinstrument/ns:SASdetector', namespaces={'ns': CANSAS_NS})
1002        for item in nodes:
1003           
1004            detector = Detector()
1005           
1006            self._store_content('ns:name', item, 'name', detector)
1007            self._store_float('ns:SDD', item, 'distance', detector)   
1008           
1009            # Detector offset (as a vector)
1010            self._store_float('ns:offset/ns:x', item, 'offset.x', detector)   
1011            self._store_float('ns:offset/ns:y', item, 'offset.y', detector)   
1012            self._store_float('ns:offset/ns:z', item, 'offset.z', detector)   
1013           
1014            # Detector orientation (as a vector)
1015            self._store_float('ns:orientation/ns:roll',  item, 'orientation.x', detector)   
1016            self._store_float('ns:orientation/ns:pitch', item, 'orientation.y', detector)   
1017            self._store_float('ns:orientation/ns:yaw',   item, 'orientation.z', detector)   
1018           
1019            # Beam center (as a vector)
1020            self._store_float('ns:beam_center/ns:x', item, 'beam_center.x', detector)   
1021            self._store_float('ns:beam_center/ns:y', item, 'beam_center.y', detector)   
1022            self._store_float('ns:beam_center/ns:z', item, 'beam_center.z', detector)   
1023           
1024            # Pixel size (as a vector)
1025            self._store_float('ns:pixel_size/ns:x', item, 'pixel_size.x', detector)   
1026            self._store_float('ns:pixel_size/ns:y', item, 'pixel_size.y', detector)   
1027            self._store_float('ns:pixel_size/ns:z', item, 'pixel_size.z', detector)   
1028           
1029            self._store_float('ns:slit_length', item, 'slit_length', detector)
1030           
1031            data_info.detector.append(detector)   
1032
1033        # Processes info ######################
1034        nodes = dom.xpath('ns:SASprocess', namespaces={'ns': CANSAS_NS})
1035        for item in nodes:
1036            process = Process()
1037            self._store_content('ns:name', item, 'name', process)
1038            self._store_content('ns:date', item, 'date', process)
1039            self._store_content('ns:description', item, 'description', process)
1040           
1041            term_list = item.xpath('ns:term', namespaces={'ns': CANSAS_NS})
1042            for term in term_list:
1043                try:
1044                    term_attr = {}
1045                    for attr in term.keys():
1046                        term_attr[attr] = term.get(attr).strip()
1047                    if term.text is not None:
1048                        term_attr['value'] = term.text.strip()
1049                        process.term.append(term_attr)
1050                except:
1051                    err_mess = "cansas_reader.read: error processing process term\n  %s" % sys.exc_value
1052                    self.errors.append(err_mess)
1053                    logging.error(err_mess)
1054           
1055            note_list = item.xpath('ns:SASprocessnote', namespaces={'ns': CANSAS_NS})
1056            for note in note_list:
1057                if note.text is not None:
1058                    process.notes.append(note.text.strip())
1059           
1060            data_info.process.append(process)
1061           
1062           
1063        # Data info ######################
1064        nodes = dom.xpath('ns:SASdata', namespaces={'ns': CANSAS_NS})
1065        if len(nodes)>1:
1066            raise RuntimeError, "CanSAS reader is not compatible with multiple SASdata entries"
1067       
1068        for entry in nodes:
1069            for item in list_of_data_2d_attr:
1070                #get node
1071                node = get_content('ns:%s'%item[0], entry)
1072                exec "data_info.%s = parse_entry_helper(node, item)"%(item[1])
1073                   
1074            for item in list_of_data2d_values:
1075                field = get_content('ns:%s'%item[0], entry)
1076                list = []
1077                if field is not None:
1078                    list = [parse_entry_helper(node, item) for node in field]
1079                exec "data_info.%s = numpy.array(list)"%item[0]
1080       
1081        return data_info
1082
1083    def _read_cansas(self, path):
1084        """
1085        Load data and P(r) information from a CanSAS XML file.
1086       
1087        :param path: file path
1088       
1089        :return: Data1D object if a single SASentry was found,
1090                    or a list of Data1D objects if multiple entries were found,
1091                    or None of nothing was found
1092                   
1093        :raise RuntimeError: when the file can't be opened
1094        :raise ValueError: when the length of the data vectors are inconsistent
1095       
1096        """
1097        output = []
1098        try:
1099            if os.path.isfile(path):
1100                basename  = os.path.basename(path)
1101                root, extension = os.path.splitext(basename)
1102                #TODO: eventually remove the check for .xml once
1103                # the P(r) writer/reader is truly complete.
1104                if  extension.lower() in self.ext or \
1105                    extension.lower() == '.xml':
1106                   
1107                    tree = etree.parse(path, parser=etree.ETCompatXMLParser())
1108                    # Check the format version number
1109                    # Specifying the namespace will take care of the file format version
1110                    root = tree.getroot()
1111                    entry_list = root.xpath('ns:SASentry', namespaces={'ns': CANSAS_NS})
1112                    for entry in entry_list:   
1113                        try:
1114                            sas_entry = self._parse_entry(entry)
1115                        except:
1116                            raise
1117                        fitstate = self._parse_state(entry)
1118                       
1119                        #state could be None when .svs file is loaded
1120                        #in this case, skip appending to output
1121                        if fitstate != None:
1122                            sas_entry.meta_data['fitstate'] = fitstate
1123                            sas_entry.filename = fitstate.file
1124                            output.append(sas_entry)
1125            else:
1126                raise RuntimeError, "%s is not a file" % path
1127
1128            # Return output consistent with the loader's api
1129            if len(output)==0:
1130                return None
1131            else:
1132                for ind in range(len(output)):
1133                    # Call back to post the new state
1134                    state = output[ind].meta_data['fitstate']
1135                    t = time.localtime(state.timestamp)
1136                    time_str = time.strftime("%b %d %H:%M", t)
1137                    # Check that no time stamp is already appended
1138                    max_char = state.file.find("[")
1139                    if max_char < 0:
1140                        max_char = len(state.file)
1141                    original_fname = state.file[0:max_char]
1142                    state.file = original_fname +' [' + time_str + ']'
1143                   
1144                       
1145                    if state is not None and state.is_data is not None:
1146                        exec 'output[%d].is_data = state.is_data'% ind
1147                     
1148                    output[ind].filename = state.file
1149                    state.data = output[ind]
1150                    state.data.name = output[ind].filename #state.data_name
1151                    state.data.id = state.data_id
1152                    if state.is_data is not None:
1153                        state.data.is_data = state.is_data
1154                    if output[ind].run_name is not None and len(output[ind].run_name) != 0 :
1155                        name = output[ind].run_name
1156                    else: 
1157                        name=original_fname
1158                    state.data.group_id = name
1159                    #store state in fitting
1160                    self.call_back(state=state, datainfo=output[ind])
1161                   
1162                return output
1163             
1164        except:
1165            raise
1166           
1167    def write(self, filename, datainfo=None, fitstate=None):
1168        """
1169        Write the content of a Data1D as a CanSAS XML file only for standalone
1170       
1171        :param filename: name of the file to write
1172        :param datainfo: Data1D object
1173        :param fitstate: PageState object
1174       
1175        """
1176        # Sanity check
1177        if self.cansas == True:
1178           
1179            # Add fitting information to the XML document
1180            doc = self.write_toXML(datainfo, fitstate)
1181            # Write the XML document
1182            fd = open(filename, 'w')
1183            fd.write(doc.toprettyxml())
1184            fd.close()
1185        else:
1186            fitstate.toXML(file=filename)
1187       
1188    def write_toXML(self, datainfo=None, state=None):
1189        """
1190        Write toXML, a helper for write() , could be used by guimanager._on_save()
1191       
1192        : return: xml doc
1193        """
1194
1195        if state.data is None:
1196            data = DataLoader.data_info.Data1D(x=[], y=[]) 
1197        else: 
1198            #make sure title and data run is filled up.
1199            if state.data.title == None or state.data.title=='': state.data.title = state.data.name
1200            if state.data.run_name == None or state.data.run_name=={}: 
1201                state.data.run = [str(state.data.name)]
1202                state.data.run_name[0] = state.data.name
1203   
1204            if issubclass(state.data.__class__, DataLoader.data_info.Data1D):
1205
1206                data = state.data
1207                doc, sasentry = self._to_xml_doc(data)
1208            else:
1209                data = state.data
1210                doc, sasentry = self._data2d_to_xml_doc(data)
1211           
1212
1213        if state is not None:
1214            state.toXML(doc=doc, file=data.name, entry_node=sasentry)
1215           
1216        return doc
1217 
1218if __name__ == "__main__":
1219    state = PageState(parent=None)
1220    #state.toXML()
1221    """
1222   
1223    file = open("test_state", "w")
1224    pickle.dump(state, file)
1225    print pickle.dumps(state)
1226    state.data_name = "hello---->"
1227    pickle.dump(state, file)
1228    file = open("test_state", "r")
1229    new_state= pickle.load(file)
1230    print "new state", new_state
1231    new_state= pickle.load(file)
1232    print "new state", new_state
1233    #print "state", state
1234    """
1235    import bsddb
1236    import pickle
1237    db= bsddb.btopen('file_state.db', 'c')
1238    val = (pickle.dumps(state), "hello", "hi")
1239    db['state1']= pickle.dumps(val)
1240    print pickle.loads(db['state1'])
1241    state.data_name = "hello---->22"
1242    db['state2']= pickle.dumps(state)
1243    state.data_name = "hello---->2"
1244    db['state3']= pickle.dumps(state)
1245    del db['state3']
1246    state.data_name = "hello---->3"
1247    db['state4']= pickle.dumps(state)
1248    new_state = pickle.loads(db['state1'])
1249    #print db.last()
1250    db.set_location('state2')
1251    state.data_name = "hello---->5"
1252    db['aastate5']= pickle.dumps(state)
1253    db.keys().sort()
1254    print pickle.loads(db['state2'])
1255 
1256    db.close()
Note: See TracBrowser for help on using the repository browser.