Changeset ac5b69d in sasview for src


Ignore:
Timestamp:
May 5, 2014 3:41:43 PM (11 years ago)
Author:
Jeff Krzywon <jeffery.krzywon@…>
Branches:
master, ESS_GUI, ESS_GUI_Docs, ESS_GUI_batch_fitting, ESS_GUI_bumps_abstraction, ESS_GUI_iss1116, ESS_GUI_iss879, ESS_GUI_iss959, ESS_GUI_opencl, ESS_GUI_ordering, ESS_GUI_sync_sascalc, costrafo411, magnetic_scatt, release-4.1.1, release-4.1.2, release-4.2.2, release_4.0.1, ticket-1009, ticket-1094-headless, ticket-1242-2d-resolution, ticket-1243, ticket-1249, ticket885, unittest-saveload
Children:
c81aa18
Parents:
0089be3
Message:

Ticket #249 fix: Saving and loading projects and analysis is now working.

Location:
src/sans
Files:
4 edited

Legend:

Unmodified
Added
Removed
  • src/sans/dataloader/readers/cansas_constants.py

    r9e2bc6c rac5b69d  
    33the cansas_reader.py file to read in any version of the cansas format. 
    44""" 
    5 class cansasConstants: 
    6      
    7     ns = '' 
     5class CansasConstants: 
     6    """ 
     7    The base class to define where all of the data is to be saved by 
     8    cansas_reader.py. 
     9    """ 
     10     
     11    names = '' 
    812    format = '' 
    913     
    1014     
    1115    def __init__(self): 
    12         self.ns = self.CANSAS_NS 
     16        self.names = self.CANSAS_NS 
    1317        self.format = self.CANSAS_FORMAT 
    1418     
    1519     
    16     def _iterate_namespace(self, namespace): 
     20    def iterate_namespace(self, namespace): 
    1721        """ 
    1822        Method to iterate through a cansas constants tree based on a list of 
     
    2327        """ 
    2428        # The current level to look through in cansas_constants. 
    25         return_me = currentLevel() 
     29        return_me = CurrentLevel() 
    2630        return_me.current_level = self.CANSAS_FORMAT.get("SASentry") 
    2731        # Defaults for variable and datatype 
     
    3034        return_me.ns_optional = True 
    3135        for name in namespace: 
    32             if name != "SASentry": 
    33                 return_me.current_level = \ 
    34                         return_me.current_level.get("children").get(name, "") 
    35                 if return_me.current_level == "": 
     36            try: 
     37                if name != "SASentry": 
    3638                    return_me.current_level = \ 
    37                             return_me.current_level.get("<any>", "") 
    38                 cl_variable = return_me.current_level.get("variable", "") 
    39                 cl_datatype = return_me.current_level.get("storeas", "") 
    40                 cl_units_optional = \ 
    41                             return_me.current_level.get("units_required", "") 
    42                 # Where are how to store the variable for the given namespace 
    43                 # CANSAS_CONSTANTS tree is hierarchical, so is no value, inherit 
    44                 return_me.ns_variable = cl_variable if cl_variable != "" else \ 
    45                                     return_me.ns_variable 
    46                 return_me.ns_datatype = cl_datatype if cl_datatype != "" else \ 
    47                                     return_me.ns_datatype 
    48                 return_me.ns_optional = cl_units_optional if \ 
    49                                     cl_units_optional != return_me.ns_optional \ 
    50                                     else return_me.ns_optional 
     39                            return_me.current_level.get("children").get(name, "") 
     40                    if return_me.current_level == "": 
     41                        return_me.current_level = \ 
     42                                return_me.current_level.get("<any>", "") 
     43                    cl_variable = return_me.current_level.get("variable", "") 
     44                    cl_datatype = return_me.current_level.get("storeas", "") 
     45                    cl_units_optional = \ 
     46                                return_me.current_level.get("units_required", "") 
     47                    # Where are how to store the variable for the given namespace 
     48                    # CANSAS_CONSTANTS tree is hierarchical, so is no value, inherit 
     49                    return_me.ns_variable = cl_variable if cl_variable != "" else \ 
     50                                        return_me.ns_variable 
     51                    return_me.ns_datatype = cl_datatype if cl_datatype != "" else \ 
     52                                        return_me.ns_datatype 
     53                    return_me.ns_optional = cl_units_optional if \ 
     54                                        cl_units_optional != return_me.ns_optional \ 
     55                                        else return_me.ns_optional 
     56            except AttributeError: 
     57                return_me.ns_variable = "{0}.meta_data[\"{2}\"] = \"{1}\"" 
     58                return_me.ns_datatype = "content" 
     59                return_me.ns_optional = True 
    5160        return return_me     
    5261     
     
    454463                           } 
    455464    SASINSTR_SRC = { 
    456                     "attributes" : {"name" : {"variable" : "{0}.source.name = \"{1}\""}}, 
     465                    "attributes" : {"name" : {"variable" : \ 
     466                                              "{0}.source.name = \"{1}\""}}, 
    457467                    "variable" : None, 
    458468                    "children" : { 
    459                                   "radiation" : {"variable" : "{0}.source.radiation = \"{1}\""}, 
     469                                  "radiation" : {"variable" : \ 
     470                                            "{0}.source.radiation = \"{1}\""}, 
    460471                                  "beam_size" : SASINSTR_SRC_BEAMSIZE, 
    461472                                  "beam_shape" : {"variable" : \ 
     
    647658                        "unit" : "pixel_size_unit", 
    648659                        "attributes" : { 
    649                                         "unit" : "{0}.pixel_size_unit = \"{1}\"", 
     660                                        "unit" : \ 
     661                                            "{0}.pixel_size_unit = \"{1}\"", 
    650662                                        "storeas" : "content" 
    651663                                        } 
     
    655667                        "unit" : "pixel_size_unit", 
    656668                        "attributes" : { 
    657                                         "unit" : "{0}.pixel_size_unit = \"{1}\"", 
     669                                        "unit" : \ 
     670                                            "{0}.pixel_size_unit = \"{1}\"", 
    658671                                        "storeas" : "content" 
    659672                                        } 
     
    663676                        "unit" : "pixel_size_unit", 
    664677                        "attributes" : { 
    665                                         "unit" : "{0}.pixel_size_unit = \"{1}\"", 
     678                                        "unit" : \ 
     679                                            "{0}.pixel_size_unit = \"{1}\"", 
    666680                                        "storeas" : "content" 
    667681                                        } 
     
    740754                     } 
    741755    
    742 class currentLevel: 
     756class CurrentLevel: 
     757    """ 
     758    A helper class to hold information on where you are in the constants tree 
     759    """ 
    743760      
    744761    current_level = '' 
     
    748765      
    749766    def __init__(self): 
    750         self.current_level = '' 
     767        self.current_level = {} 
    751768        self.ns_variable = '' 
    752769        self.ns_datatype = "content" 
  • src/sans/dataloader/readers/cansas_reader.py

    r2e3b055 rac5b69d  
    1818import sys 
    1919import datetime 
     20import inspect 
     21# For saving individual sections of data 
    2022from sans.dataloader.data_info import Data1D 
    2123from sans.dataloader.data_info import Collimation 
     
    2426from sans.dataloader.data_info import Process 
    2527from sans.dataloader.data_info import Aperture 
     28# Both imports used. Do not remove either. 
     29from xml.dom.minidom import parseString 
    2630import sans.dataloader.readers.xml_reader as xml_reader 
    27 from sans.dataloader.readers.cansas_constants import cansasConstants 
     31from sans.dataloader.readers.xml_reader import XMLreader 
     32from sans.dataloader.readers.cansas_constants import CansasConstants 
    2833 
    2934_ZERO = 1e-16 
     
    3641    HAS_CONVERTER = False 
    3742 
    38 constants = cansasConstants()     
    39 CANSAS_FORMAT = constants.format 
    40 CANSAS_NS = constants.ns 
     43CONSTANTS = CansasConstants()     
     44CANSAS_FORMAT = CONSTANTS.format 
     45CANSAS_NS = CONSTANTS.names 
    4146ALLOW_ALL = True 
    4247 
    4348 
     49# minidom used in functions called by outside classes 
     50import xml.dom.minidom 
     51# DO NOT REMOVE 
     52# Called by outside packages: 
     53#    sans.perspectives.invariant.invariant_state 
     54#    sans.perspectives.fitting.pagestate 
    4455def get_content(location, node): 
    4556    """ 
     
    5162    :return: Element, or None 
    5263    """ 
    53     nodes = node.xpath(location, namespaces={'ns': CANSAS_NS}) 
     64    nodes = node.xpath(location,  
     65                       namespaces={'ns': CANSAS_NS.get("1.0").get("ns")}) 
    5466     
    5567    if len(nodes) > 0: 
     
    5971 
    6072 
    61 def get_float(location, node): 
    62     """ 
    63     Get the content of a node as a float 
    64      
    65     :param location: xpath location 
    66     :param node: node to start at 
    67     """ 
    68     nodes = node.xpath(location, namespaces={'ns': CANSAS_NS}) 
    69      
    70     value = None 
    71     attr = {} 
    72     if len(nodes) > 0: 
    73         try: 
    74             value = float(nodes[0].text) 
    75         except: 
    76             # Could not pass, skip and return None 
    77             msg = "cansas_reader.get_float: could not " 
    78             msg += " convert '%s' to float" % nodes[0].text 
    79             logging.error(msg) 
    80         if nodes[0].get('unit') is not None: 
    81             attr['unit'] = nodes[0].get('unit') 
    82     return value, attr 
    83  
    84  
    85 # This is called by sans.perspectives.fitting.pagestate.py 
    86 # Do not remove 
     73# DO NOT REMOVE 
     74# Called by outside packages: 
     75#    sans.perspectives.fitting.pagestate 
    8776def write_node(doc, parent, name, value, attr={}): 
    8877    """ 
     
    10594                 
    10695 
    107 class Reader(): 
     96class Reader(XMLreader): 
    10897    """ 
    10998    Class to load cansas 1D XML files 
     
    114103    ##CanSAS version - defaults to version 1.0 
    115104    cansas_version = "1.0" 
    116     ##Data reader 
    117     # TODO: make the reader extend the XMLreader class? 
    118     reader = xml_reader.XMLreader() 
     105     
     106    logging = [] 
    119107    errors = [] 
    120108     
    121109    type_name = "canSAS" 
    122      
    123110    ## Wildcards 
    124     type = ["XML files (*.xml)|*.xml"] 
     111    type = ["XML files (*.xml)|*.xml", "SasView Save Files (*.svs)|*.svs"] 
    125112    ## List of allowed extensions 
    126     ext = ['.xml', '.XML'] 
     113    ext = ['.xml', '.XML', '.svs', '.SVS'] 
    127114     
    128115    ## Flag to bypass extension check 
     
    133120        self.errors = [] 
    134121         
    135     def is_cansas(self): 
     122    def is_cansas(self, ext="xml"): 
    136123        """ 
    137124        Checks to see if the xml file is a CanSAS file 
    138125        """ 
    139         if self.reader.validateXML(): 
     126        if self.validate_xml(): 
    140127            name = "{http://www.w3.org/2001/XMLSchema-instance}schemaLocation" 
    141             value = self.reader.xmlroot.get(name) 
    142             if (CANSAS_NS.get(self.cansas_version).get("ns") == \ 
    143                     value.rsplit(" ")[0]): 
     128            value = self.xmlroot.get(name) 
     129            if CANSAS_NS.get(self.cansas_version).get("ns") == \ 
     130                    value.rsplit(" ")[0]: 
    144131                return True 
     132        if ext == "svs": 
     133            return True 
    145134        return False 
    146135     
     
    152141        """ 
    153142        # X - Q value; Y - Intensity (Abs) 
    154         x = numpy.empty(0) 
    155         y = numpy.empty(0) 
    156         dx = numpy.empty(0) 
    157         dy = numpy.empty(0) 
     143        x_vals = numpy.empty(0) 
     144        y_vals = numpy.empty(0) 
     145        dx_vals = numpy.empty(0) 
     146        dy_vals = numpy.empty(0) 
    158147        dxl = numpy.empty(0) 
    159148        dxw = numpy.empty(0) 
     
    162151        output = [] 
    163152        # ns - Namespace hierarchy for current xml object 
    164         ns = [] 
     153        ns_list = [] 
    165154         
    166155        # Check that the file exists 
     
    168157            basename = os.path.basename(xml) 
    169158            _, extension = os.path.splitext(basename) 
    170             # If the fiel type is not allowed, return nothing 
     159            # If the file type is not allowed, return nothing 
    171160            if extension in self.ext or self.allow_all: 
     161                # Get the file location of  
    172162                base_name = xml_reader.__file__ 
    173163                base_name = base_name.replace("\\","/") 
     
    175165                 
    176166                # Load in xml file and get the cansas version from the header 
    177                 self.reader.setXMLFile(xml) 
    178                 root = self.reader.xmlroot 
     167                self.set_xml_file(xml) 
     168                root = self.xmlroot 
    179169                if root is None: 
    180170                    root = {} 
     
    187177                 
    188178                # Link a schema to the XML file. 
    189                 self.reader.setSchema(schema_path) 
     179                self.set_schema(schema_path) 
    190180                 
    191181                # Try to load the file, but raise an error if unable to. 
    192182                # Check the file matches the XML schema 
    193183                try: 
    194                     if self.is_cansas(): 
     184                    if self.is_cansas(extension): 
    195185                        # Get each SASentry from XML file and add it to a list. 
    196186                        entry_list = root.xpath('/ns:SASroot/ns:SASentry', 
    197187                                namespaces={'ns': cansas_defaults.get("ns")}) 
    198                         ns.append("SASentry") 
     188                        ns_list.append("SASentry") 
    199189                         
    200190                        # If multiple files, modify the name for each is unique 
     
    204194                        # Parse each SASentry item 
    205195                        for entry in entry_list: 
    206                             # Define a new Data1D object with zeroes for x and y 
    207                             data1d = Data1D(x,y,dx,dy) 
     196                            # Define a new Data1D object with zeroes for  
     197                            # x_vals and y_vals 
     198                            data1d = Data1D(x_vals, y_vals, dx_vals, dy_vals) 
    208199                            data1d.dxl = dxl 
    209200                            data1d.dxw = dxw 
     
    220211                             
    221212                            # Get all preprocessing events and encoding 
    222                             self.reader.setProcessingInstructions() 
     213                            self.set_processing_instructions() 
    223214                            data1d.meta_data[PREPROCESS] = \ 
    224                                     self.reader.processingInstructions 
     215                                    self.processing_instructions 
    225216                             
    226217                            # Parse the XML file 
    227218                            return_value, extras = \ 
    228                                 self._parse_entry(entry, ns, data1d) 
     219                                self._parse_entry(entry, ns_list, data1d) 
    229220                            del extras[:] 
    230221                             
     
    251242                            output.append(return_value) 
    252243                    else: 
    253                         value = self.reader.findInvalidXML() 
     244                        value = self.find_invalid_xml() 
    254245                        output.append("Invalid XML at: {0}".format(value)) 
    255246                except: 
    256247                    # If the file does not match the schema, raise this error 
    257                     raise RuntimeError, "%s cannot be read \increment" % xml 
     248                    raise RuntimeError, "%s cannot be read" % xml 
    258249                return output 
    259250        # Return a list of parsed entries that dataloader can manage 
    260251        return None 
    261252     
    262     def _create_unique_key(self, dictionary, name, i = 0): 
     253    def _create_unique_key(self, dictionary, name, numb = 0): 
    263254        """ 
    264255        Create a unique key value for any dictionary to prevent overwriting 
     
    267258        :param dictionary: A dictionary with any number of entries 
    268259        :param name: The index of the item to be added to dictionary 
    269         :param i: The number to be appended to the name, starts at 0 
     260        :param numb: The number to be appended to the name, starts at 0 
    270261        """ 
    271262        if dictionary.get(name) is not None: 
    272             i += 1 
     263            numb += 1 
    273264            name = name.split("_")[0] 
    274             name += "_{0}".format(i) 
    275             name = self._create_unique_key(dictionary, name, i) 
     265            name += "_{0}".format(numb) 
     266            name = self._create_unique_key(dictionary, name, numb) 
    276267        return name 
    277268     
     
    284275         
    285276        :param new_current_level: cansas_constants level as returned by  
    286             _iterate_namespace 
     277            iterate_namespace 
    287278        :param attr: The attributes of the node 
    288279        :param data1d: Where the values will be saved 
     
    318309                            return 
    319310                        except: 
    320                             err_msg = "CanSAS reader: could not convert the units" 
     311                            err_msg = \ 
     312                                "CanSAS reader: could not convert the units" 
    321313                            self.errors.append(err_msg) 
    322314                            return 
     
    343335        return node_value, value_unit 
    344336     
    345     def _parse_entry(self, dom, ns, data1d, extras = []): 
     337    def _parse_entry(self, dom, names=["SASentry"], data1d=None, extras=[]): 
    346338        """ 
    347339        Parse a SASEntry - new recursive method for parsing the dom of 
     
    349341            and extra nodes to be read in simultaneously. 
    350342         
    351         :param dom: dom object with a namespace base of ns 
    352         :param ns: A list of element names that lead up to the dom object 
     343        :param dom: dom object with a namespace base of names 
     344        :param names: A list of element names that lead up to the dom object 
    353345        :param data1d: The data1d object that will be modified 
    354346        :param extras: Any values that should go into meta_data when data1d 
    355347            is not a Data1D object 
    356348        """ 
    357           
     349         
    358350        # A portion of every namespace entry 
     351        if data1d == None: 
     352            x_vals = numpy.empty(0) 
     353            y_vals = numpy.empty(0) 
     354            dx_vals = numpy.empty(0) 
     355            dy_vals = numpy.empty(0) 
     356            dxl = numpy.empty(0) 
     357            dxw = numpy.empty(0) 
     358            data1d = Data1D(x_vals, y_vals, dx_vals, dy_vals) 
     359            data1d.dxl = dxl 
     360            data1d.dxw = dxw 
     361                             
    359362        base_ns = "{0}{1}{2}".format("{", \ 
    360363                            CANSAS_NS.get(self.cansas_version).get("ns"), "}") 
     
    366369        for node in dom: 
    367370            try: 
    368                 # Get the element name and set the current ns level 
     371                # Get the element name and set the current names level 
    369372                tagname = node.tag.replace(base_ns, "") 
    370373                tagname_original = tagname 
    371                 ns.append(tagname) 
     374                if tagname == "fitting_plug_in": 
     375                    continue 
     376                names.append(tagname) 
    372377                attr = node.attrib 
    373378                children = node.getchildren() 
     379                if len(children) == 0: 
     380                    children = None 
    374381                save_data1d = data1d 
    375382                 
     
    410417                                 
    411418                # Get where to store content 
    412                 cs_values = constants._iterate_namespace(ns) 
     419                cs_values = CONSTANTS.iterate_namespace(names) 
    413420                # If the element is a child element, recurse 
    414421                if children is not None: 
    415422                    # Returned value is new Data1D object with all previous and  
    416423                    # new values in it. 
    417                     data1d, extras = self._parse_entry(node, ns, data1d, extras) 
     424                    data1d, extras = self._parse_entry(node,  
     425                                                       names, data1d, extras) 
    418426                     
    419427                #Get the information from the node 
     
    488496                            pass 
    489497             
    490             except TypeError: 
     498            except TypeError as e: 
    491499                pass 
    492500            except Exception as e: 
     
    509517                else: 
    510518                    save_data1d = data1d 
    511                 data1d = save_data1d 
    512                 # Remove tagname from ns to restore original base 
    513                 ns.remove(tagname_original) 
    514          
     519                if tagname_original != "fitting_plug_in": 
     520                    data1d = save_data1d 
     521                    # Remove tagname from names to restore original base 
     522                    names.remove(tagname_original) 
    515523        return data1d, extras 
    516524         
     525     
    517526    def _to_xml_doc(self, datainfo): 
    518527        """ 
     
    526535         
    527536        # Get PIs and create root element 
    528         pis = self.reader.return_processing_instructions() 
    529         doc = self.reader.create_tree(pis[0]) 
    530         i = 1 
    531         for i in range(1,len(pis) - 1): 
    532             doc = self.reader.append(pis[i], doc) 
     537        pis = self.return_processing_instructions() 
     538        if len(pis) > 0: 
     539            pi_tree = self.create_tree(pis[0]) 
     540            i = 1 
     541            for i in range(1,len(pis) - 1): 
     542                pi_tree = self.append(pis[i], pi_tree) 
     543            pi_string = self.to_string(pi_tree) 
     544        else: 
     545            pi_string = "" 
    533546         
    534547        # Define namespaces and create SASroot object 
     
    540553        else: 
    541554            url = "http://svn.smallangles.net/svn/canSAS/1dwg/trunk/" 
    542         schemaLocation = "{0} {1}cansas1d.xsd".format(ns, url) 
    543         attrib = {"{" + xsi + "}schemaLocation" : schemaLocation, 
     555        schema_location = "{0} {1}cansas1d.xsd".format(ns, url) 
     556        attrib = {"{" + xsi + "}schemaLocation" : schema_location, 
    544557                  "version" : version} 
    545558        nsmap = {'xsi' : xsi, None: ns} 
    546559         
    547         main_node = self.reader.create_element("{" + ns + "}SASroot", \ 
     560        main_node = self.create_element("{" + ns + "}SASroot", \ 
    548561                                               attrib = attrib, \ 
    549562                                               nsmap = nsmap) 
    550563         
    551564        # Create ElementTree, append SASroot and apply processing instructions 
    552         base_string = self.reader.toString(doc) + \ 
    553                     self.reader.toString(main_node) 
    554         base_element = self.reader.create_element_from_string(base_string) 
    555         doc = self.reader.create_tree(base_element) 
     565        base_string = pi_string + self.to_string(main_node) 
     566        base_element = self.create_element_from_string(base_string) 
     567        doc = self.create_tree(base_element) 
    556568         
    557569        # Create SASentry Element 
    558         entry_node = self.reader.create_element("SASentry") 
     570        entry_node = self.create_element("SASentry") 
    559571        root = doc.getroot() 
    560572        root.append(entry_node) 
     
    576588         
    577589        # Data info 
    578         node = self.reader.create_element("SASdata") 
    579         self.reader.append(node, entry_node) 
     590        node = self.create_element("SASdata") 
     591        self.append(node, entry_node) 
    580592         
    581593        for i in range(len(datainfo.x)): 
    582             pt = self.reader.create_element("Idata") 
     594            pt = self.create_element("Idata") 
    583595            node.append(pt) 
    584596            self.write_node(pt, "Q", datainfo.x[i], {'unit': datainfo.x_unit}) 
     
    598610                self.write_node(pt, "dQl", datainfo.dxl[i], 
    599611                            {'unit': datainfo.x_unit}) 
    600  
     612         
    601613        # Transmission Spectrum Info 
    602614        for i in range(len(datainfo.trans_spectrum)): 
    603615            spectrum = datainfo.trans_spectrum[i] 
    604             node = self.reader.create_element("SAStransmission_spectrum", 
     616            node = self.create_element("SAStransmission_spectrum", 
    605617                                              {"name" : spectrum.name}) 
    606             self.reader.append(node, entry_node) 
     618            self.append(node, entry_node) 
    607619            if isinstance(spectrum.timestamp, datetime.datetime): 
    608620                node.setAttribute("timestamp", spectrum.timestamp) 
    609621            for i in range(len(spectrum.wavelength)): 
    610                 pt = self.reader.create_element("Tdata") 
     622                pt = self.create_element("Tdata") 
    611623                node.append(pt) 
    612624                self.write_node(pt, "Lambda", spectrum.wavelength[i],  
     
    621633 
    622634        # Sample info 
    623         sample = self.reader.create_element("SASsample") 
     635        sample = self.create_element("SASsample") 
    624636        if datainfo.sample.name is not None: 
    625             self.reader.write_attribute(sample,  
     637            self.write_attribute(sample,  
    626638                                        "name",  
    627639                                        str(datainfo.sample.name)) 
    628         self.reader.append(sample, entry_node) 
     640        self.append(sample, entry_node) 
    629641        self.write_node(sample, "ID", str(datainfo.sample.ID)) 
    630642        self.write_node(sample, "thickness", datainfo.sample.thickness, 
     
    634646                   {"unit": datainfo.sample.temperature_unit}) 
    635647         
    636         pos = self.reader.create_element("position") 
     648        pos = self.create_element("position") 
    637649        written = self.write_node(pos,  
    638650                                  "x",  
     
    648660                                       {"unit": datainfo.sample.position_unit}) 
    649661        if written == True: 
    650             self.reader.append(pos, sample) 
    651          
    652         ori = self.reader.create_element("orientation") 
     662            self.append(pos, sample) 
     663         
     664        ori = self.create_element("orientation") 
    653665        written = self.write_node(ori, "roll", 
    654666                                  datainfo.sample.orientation.x, 
     
    661673                                    {"unit": datainfo.sample.orientation_unit}) 
    662674        if written == True: 
    663             self.reader.append(ori, sample) 
     675            self.append(ori, sample) 
    664676         
    665677        for item in datainfo.sample.details: 
     
    667679         
    668680        # Instrument info 
    669         instr = self.reader.create_element("SASinstrument") 
    670         self.reader.append(instr, entry_node) 
     681        instr = self.create_element("SASinstrument") 
     682        self.append(instr, entry_node) 
    671683         
    672684        self.write_node(instr, "name", datainfo.instrument) 
    673685         
    674686        #   Source 
    675         source = self.reader.create_element("SASsource") 
     687        source = self.create_element("SASsource") 
    676688        if datainfo.source.name is not None: 
    677             self.reader.write_attribute(source, 
     689            self.write_attribute(source, 
    678690                                        "name", 
    679691                                        str(datainfo.source.name)) 
    680         self.reader.append(source, instr) 
     692        self.append(source, instr) 
    681693        if datainfo.source.radiation == None or datainfo.source.radiation == '': 
    682694            datainfo.source.radiation = "neutron" 
    683695        self.write_node(source, "radiation", datainfo.source.radiation) 
    684696         
    685         size = self.reader.create_element("beam_size") 
     697        size = self.create_element("beam_size") 
    686698        if datainfo.source.beam_size_name is not None: 
    687             self.reader.write_attribute(size, 
     699            self.write_attribute(size, 
    688700                                        "name", 
    689701                                        str(datainfo.source.beam_size_name)) 
     
    697709                                       {"unit": datainfo.source.beam_size_unit}) 
    698710        if written == True: 
    699             self.reader.append(size, source) 
     711            self.append(size, source) 
    700712             
    701713        self.write_node(source, "beam_shape", datainfo.source.beam_shape) 
     
    718730            datainfo.collimation.append(coll) 
    719731        for item in datainfo.collimation: 
    720             coll = self.reader.create_element("SAScollimation") 
     732            coll = self.create_element("SAScollimation") 
    721733            if item.name is not None: 
    722                 self.reader.write_attribute(coll, "name", str(item.name)) 
    723             self.reader.append(coll, instr) 
     734                self.write_attribute(coll, "name", str(item.name)) 
     735            self.append(coll, instr) 
    724736             
    725737            self.write_node(coll, "length", item.length, 
     
    727739             
    728740            for apert in item.aperture: 
    729                 ap = self.reader.create_element("aperture") 
     741                ap = self.create_element("aperture") 
    730742                if apert.name is not None: 
    731                     self.reader.write_attribute(ap, "name", str(apert.name)) 
     743                    self.write_attribute(ap, "name", str(apert.name)) 
    732744                if apert.type is not None: 
    733                     self.reader.write_attribute(ap, "type", str(apert.type)) 
    734                 self.reader.append(ap, coll) 
    735                  
    736                 size = self.reader.create_element("size") 
     745                    self.write_attribute(ap, "type", str(apert.type)) 
     746                self.append(ap, coll) 
     747                 
     748                size = self.create_element("size") 
    737749                if apert.size_name is not None: 
    738                     self.reader.write_attribute(size,  
     750                    self.write_attribute(size,  
    739751                                                "name",  
    740752                                                str(apert.size_name)) 
     
    746758                                               {"unit": apert.size_unit}) 
    747759                if written == True: 
    748                     self.reader.append(size, ap) 
     760                    self.append(size, ap) 
    749761                 
    750762                self.write_node(ap, "distance", apert.distance, 
     
    758770                 
    759771        for item in datainfo.detector: 
    760             det = self.reader.create_element("SASdetector") 
     772            det = self.create_element("SASdetector") 
    761773            written = self.write_node(det, "name", item.name) 
    762774            written = written | self.write_node(det, "SDD", item.distance, 
    763775                                           {"unit": item.distance_unit}) 
    764776            if written == True: 
    765                 self.reader.append(det, instr) 
     777                self.append(det, instr) 
    766778             
    767             off = self.reader.create_element("offset") 
     779            off = self.create_element("offset") 
    768780            written = self.write_node(off, "x", item.offset.x, 
    769781                                 {"unit": item.offset_unit}) 
     
    773785                                           {"unit": item.offset_unit}) 
    774786            if written == True: 
    775                 self.reader.append(off, det) 
    776                  
    777             ori = self.reader.create_element("orientation") 
     787                self.append(off, det) 
     788                 
     789            ori = self.create_element("orientation") 
    778790            written = self.write_node(ori, "roll", item.orientation.x, 
    779791                                 {"unit": item.orientation_unit}) 
     
    785797                                           {"unit": item.orientation_unit}) 
    786798            if written == True: 
    787                 self.reader.append(ori, det) 
     799                self.append(ori, det) 
    788800             
    789             center = self.reader.create_element("beam_center") 
     801            center = self.create_element("beam_center") 
    790802            written = self.write_node(center, "x", item.beam_center.x, 
    791803                                 {"unit": item.beam_center_unit}) 
     
    797809                                           {"unit": item.beam_center_unit}) 
    798810            if written == True: 
    799                 self.reader.append(center, det) 
    800                  
    801             pix = self.reader.create_element("pixel_size") 
     811                self.append(center, det) 
     812                 
     813            pix = self.create_element("pixel_size") 
    802814            written = self.write_node(pix, "x", item.pixel_size.x, 
    803815                                 {"unit": item.pixel_size_unit}) 
     
    810822                                           {"unit": item.slit_length_unit}) 
    811823            if written == True: 
    812                 self.reader.append(pix, det) 
     824                self.append(pix, det) 
    813825             
    814826        # Processes info 
    815827        for item in datainfo.process: 
    816             node = self.reader.create_element("SASprocess") 
    817             self.reader.append(node, entry_node) 
     828            node = self.create_element("SASprocess") 
     829            self.append(node, entry_node) 
    818830 
    819831            self.write_node(node, "name", item.name) 
     
    831843        # Note info 
    832844        if len(datainfo.notes) == 0: 
    833             node = self.reader.create_element("SASnote") 
    834             self.reader.append(node, entry_node) 
     845            node = self.create_element("SASnote") 
     846            self.append(node, entry_node) 
    835847        else: 
    836848            for item in datainfo.notes: 
    837                 node = self.reader.create_element("SASnote") 
    838                 self.reader.write_text(node, item) 
    839                 self.reader.append(node, entry_node) 
     849                node = self.create_element("SASnote") 
     850                self.write_text(node, item) 
     851                self.append(node, entry_node) 
    840852                 
    841853         
    842854        # Return the document, and the SASentry node associated with 
    843855        # the data we just wrote 
     856         
     857        frm = inspect.stack()[1] 
     858        mod = inspect.getmodule(frm[0]) 
     859        mod_name = mod.__name__ 
     860        if mod_name != "sans.dataloader.readers.cansas_reader": 
     861            string = self.to_string(doc, pp=True) 
     862            doc = parseString(string) 
     863            node_name = entry_node.tag 
     864            node_list = doc.getElementsByTagName(node_name) 
     865            entry_node = node_list.item(0) 
     866         
    844867        return doc, entry_node 
    845868     
    846869     
    847     def write_node(self, parent, name, value, attr={}): 
     870    def write_node(self, parent, name, value, attr=None): 
    848871        """ 
    849872        :param doc: document DOM 
     
    856879        """ 
    857880        if value is not None: 
    858             parent = self.reader.ebuilder(parent, name, value, attr) 
     881            parent = self.ebuilder(parent, name, value, attr) 
    859882            return True 
    860883        return False 
     
    872895        # Write the file 
    873896        fd = open(filename, 'w') 
    874         if self.reader.encoding == None: 
    875             self.reader.encoding = "UTF-8" 
    876         doc.write(fd, encoding=self.reader.encoding, 
     897        if self.encoding == None: 
     898            self.encoding = "UTF-8" 
     899        doc.write(fd, encoding=self.encoding, 
    877900                  pretty_print=True, xml_declaration=True) 
    878901        fd.close() 
    879902     
     903     
     904    # DO NOT REMOVE - used in saving and loading panel states. 
     905    def _store_float(self, location, node, variable, storage, optional=True): 
     906        """ 
     907        Get the content of a xpath location and store 
     908        the result. Check that the units are compatible 
     909        with the destination. The value is expected to 
     910        be a float. 
     911         
     912        The xpath location might or might not exist. 
     913        If it does not exist, nothing is done 
     914        
     915        :param location: xpath location to fetch 
     916        :param node: node to read the data from 
     917        :param variable: name of the data member to store it in [string] 
     918        :param storage: data object that has the 'variable' data member 
     919        :param optional: if True, no exception will be raised 
     920            if unit conversion can't be done 
     921 
     922        :raise ValueError: raised when the units are not recognized 
     923        """ 
     924        entry = get_content(location, node) 
     925        try: 
     926            value = float(entry.text) 
     927        except: 
     928            value = None 
     929             
     930        if value is not None: 
     931            # If the entry has units, check to see that they are 
     932            # compatible with what we currently have in the data object 
     933            units = entry.get('unit') 
     934            if units is not None: 
     935                toks = variable.split('.') 
     936                local_unit = None 
     937                exec "local_unit = storage.%s_unit" % toks[0] 
     938                if local_unit != None and units.lower() != local_unit.lower(): 
     939                    if HAS_CONVERTER == True: 
     940                        try: 
     941                            conv = Converter(units) 
     942                            exec "storage.%s = %g" % (variable, 
     943                                           conv(value, units=local_unit)) 
     944                        except: 
     945                            err_mess = "CanSAS reader: could not convert" 
     946                            err_mess += " %s unit [%s]; expecting [%s]\n  %s" \ 
     947                                % (variable, units, local_unit, sys.exc_value) 
     948                            self.errors.append(err_mess) 
     949                            if optional: 
     950                                logging.info(err_mess) 
     951                            else: 
     952                                raise ValueError, err_mess 
     953                    else: 
     954                        err_mess = "CanSAS reader: unrecognized %s unit [%s];"\ 
     955                        % (variable, units) 
     956                        err_mess += " expecting [%s]" % local_unit 
     957                        self.errors.append(err_mess) 
     958                        if optional: 
     959                            logging.info(err_mess) 
     960                        else: 
     961                            raise ValueError, err_mess 
     962                else: 
     963                    exec "storage.%s = value" % variable 
     964            else: 
     965                exec "storage.%s = value" % variable 
     966                 
     967     
     968    # DO NOT REMOVE - used in saving and loading panel states. 
     969    def _store_content(self, location, node, variable, storage): 
     970        """ 
     971        Get the content of a xpath location and store 
     972        the result. The value is treated as a string. 
     973         
     974        The xpath location might or might not exist. 
     975        If it does not exist, nothing is done 
     976         
     977        :param location: xpath location to fetch 
     978        :param node: node to read the data from 
     979        :param variable: name of the data member to store it in [string] 
     980        :param storage: data object that has the 'variable' data member 
     981         
     982        :return: return a list of errors 
     983        """ 
     984        entry = get_content(location, node) 
     985        if entry is not None and entry.text is not None: 
     986            exec "storage.%s = entry.text.strip()" % variable 
  • src/sans/dataloader/readers/xml_reader.py

    r2e3b055 rac5b69d  
    1717from lxml import etree 
    1818from lxml.builder import E 
    19 parser = etree.ETCompatXMLParser(remove_comments=True, remove_pis=False) 
     19 
     20PARSER = etree.ETCompatXMLParser(remove_comments=True, remove_pis=False) 
    2021 
    2122class XMLreader(): 
     23    """ 
     24    Generic XML read and write class. Mostly helper functions. 
     25    Makes reading/writing XML a bit easier than calling lxml libraries directly. 
     26     
     27    :Dependencies: 
     28        This class requires lxml 2.3 or higher. 
     29    """ 
    2230     
    2331    xml = None 
     
    2735    schemadoc = None 
    2836    encoding = None 
    29     processingInstructions = None 
     37    processing_instructions = None 
    3038     
    3139    def __init__(self, xml = None, schema = None, root = None): 
    3240        self.xml = xml 
    3341        self.schema = schema 
    34         self.processingInstructions = {} 
     42        self.processing_instructions = {} 
    3543        if xml is not None: 
    36             self.setXMLFile(xml, root) 
     44            self.set_xml_file(xml, root) 
    3745        else: 
    3846            self.xmldoc = None 
    3947            self.xmlroot = None 
    4048        if schema is not None: 
    41             self.setSchema(schema) 
     49            self.set_schema(schema) 
    4250        else: 
    4351            self.schemadoc = None 
     
    4755        Read in an XML file into memory and return an lxml dictionary 
    4856        """ 
    49         if self.validateXML(): 
    50             self.xmldoc = etree.parse(self.xml, parser = parser) 
     57        if self.validate_xml(): 
     58            self.xmldoc = etree.parse(self.xml, parser = PARSER) 
    5159        else: 
    52             raise etree.ValidationError(self, self.findInvalidXML()) 
     60            raise etree.XMLSchemaValidateError(self, self.find_invalid_xml()) 
    5361        return self.xmldoc 
    5462     
    55     def setXMLFile(self, xml, root = None): 
     63    def set_xml_file(self, xml, root = None): 
    5664        """ 
    5765        Set the XML file and parse 
     
    5967        try: 
    6068            self.xml = xml 
    61             self.xmldoc = etree.parse(self.xml, parser = parser) 
     69            self.xmldoc = etree.parse(self.xml, parser = PARSER) 
    6270            self.xmlroot = self.xmldoc.getroot() 
    6371        except Exception: 
     
    6674            self.xmlroot = None 
    6775     
    68     def setSchema(self, schema): 
     76    def set_schema(self, schema): 
    6977        """ 
    7078        Set the schema file and parse 
     
    7280        try: 
    7381            self.schema = schema 
    74             self.schemadoc = etree.parse(self.schema, parser = parser) 
     82            self.schemadoc = etree.parse(self.schema, parser = PARSER) 
    7583        except Exception: 
    7684            self.schema = None 
    7785            self.schemadoc = None 
    7886     
    79     def validateXML(self): 
     87    def validate_xml(self): 
    8088        """ 
    8189        Checks to see if the XML file meets the schema 
     
    8391        valid = True 
    8492        if self.schema is not None: 
    85             self.parseSchemaAndDoc() 
    86             schemaCheck = etree.XMLSchema(self.schemadoc) 
    87             valid = schemaCheck.validate(self.xmldoc) 
     93            self.parse_schema_and_doc() 
     94            schema_check = etree.XMLSchema(self.schemadoc) 
     95            valid = schema_check.validate(self.xmldoc) 
    8896        return valid 
    8997     
    90     def findInvalidXML(self): 
     98    def find_invalid_xml(self): 
    9199        """ 
    92100        Finds the first offending element that should not be present in XML file 
    93101        """ 
    94         firstError = "" 
    95         self.parseSchemaAndDoc() 
     102        first_error = "" 
     103        self.parse_schema_and_doc() 
    96104        schema = etree.XMLSchema(self.schemadoc) 
    97105        try: 
    98             firstError = schema.assertValid(self.xmldoc) 
     106            first_error = schema.assertValid(self.xmldoc) 
    99107        except etree.DocumentInvalid as e: 
    100             firstError = str(e) 
    101         return firstError 
    102      
    103     def parseSchemaAndDoc(self): 
     108            first_error = str(e) 
     109        return first_error 
     110     
     111    def parse_schema_and_doc(self): 
    104112        """ 
    105113        Creates a dictionary of the parsed schema and xml files. 
    106114        """ 
    107         self.setXMLFile(self.xml) 
    108         self.setSchema(self.schema) 
    109          
    110     def toString(self, elem, pp=False, encoding=None): 
     115        self.set_xml_file(self.xml) 
     116        self.set_schema(self.schema) 
     117         
     118    def to_string(self, elem, pp=False, encoding=None): 
    111119        """ 
    112120        Converts an etree element into a string 
     
    129137        return dic 
    130138     
    131     def setProcessingInstructions(self): 
     139    def set_processing_instructions(self): 
    132140        """ 
    133141        Take out all processing instructions and create a dictionary from them 
     
    135143        """ 
    136144        dic = {} 
    137         pi = self.xmlroot.getprevious() 
    138         while pi is not None: 
    139             pi_string = self.toString(pi) 
     145        proc_instr = self.xmlroot.getprevious() 
     146        while proc_instr is not None: 
     147            pi_string = self.to_string(proc_instr) 
    140148            if "?>\n<?" in pi_string: 
    141149                pi_string = pi_string.split("?>\n<?") 
     
    145153                for item in pi_string: 
    146154                    dic = self.break_processing_instructions(item, dic) 
    147             pi = pi.getprevious() 
     155            proc_instr = proc_instr.getprevious() 
    148156        if 'xml' in dic: 
    149             self.setEncoding(dic['xml']) 
     157            self.set_encoding(dic['xml']) 
    150158            del dic['xml'] 
    151         self.processingInstructions = dic 
    152          
    153     def setEncoding(self, attr_str): 
     159        self.processing_instructions = dic 
     160         
     161    def set_encoding(self, attr_str): 
    154162        """ 
    155163        Find the encoding in the xml declaration and save it as a string 
     
    169177        self.encoding = None 
    170178         
    171     def _create_unique_key(self, dictionary, name, i = 0): 
     179    def _create_unique_key(self, dictionary, name, numb = 0): 
    172180        """ 
    173181        Create a unique key value for any dictionary to prevent overwriting 
     
    176184        :param dictionary: A dictionary with any number of entries 
    177185        :param name: The index of the item to be added to dictionary 
    178         :param i: The number to be appended to the name, starts at 0 
     186        :param numb: The number to be appended to the name, starts at 0 
    179187        """ 
    180188        if dictionary.get(name) is not None: 
    181             i += 1 
     189            numb += 1 
    182190            name = name.split("_")[0] 
    183             name += "_{0}".format(i) 
    184             name = self._create_unique_key(dictionary, name, i) 
     191            name += "_{0}".format(numb) 
     192            name = self._create_unique_key(dictionary, name, numb) 
    185193        return name 
    186194     
     
    193201        return etree.ElementTree(root) 
    194202     
    195     def create_element_from_string(self, s): 
     203    def create_element_from_string(self, xml_string): 
    196204        """ 
    197205        Create an element from an XML string 
    198206         
    199         :param s: A string of xml 
    200         """ 
    201         return etree.fromstring(s) 
    202      
    203     def create_element(self, name, attrib={}, nsmap=None): 
     207        :param xml_string: A string of xml 
     208        """ 
     209        return etree.fromstring(xml_string) 
     210     
     211    def create_element(self, name, attrib=None, nsmap=None): 
    204212        """ 
    205213        Create an XML element for writing to file 
     
    207215        :param name: The name of the element to be created 
    208216        """ 
     217        if attrib == None: 
     218            attrib = {} 
    209219        return etree.Element(name, attrib, nsmap) 
    210220     
     
    237247        """ 
    238248        pi_list = [] 
    239         for key in self.processingInstructions: 
    240             value = self.processingInstructions.get(key) 
    241             pi = etree.ProcessingInstruction(key, value) 
    242             pi_list.append(pi) 
     249        if self.processing_instructions is not None: 
     250            for key in self.processing_instructions: 
     251                value = self.processing_instructions.get(key) 
     252                pi_item = etree.ProcessingInstruction(key, value) 
     253                pi_list.append(pi_item) 
    243254        return pi_list 
    244255     
     
    253264        return tree 
    254265     
    255     def ebuilder(self, parent, elementname, text=None, attrib={}): 
     266    def ebuilder(self, parent, elementname, text=None, attrib=None): 
     267        """ 
     268        Use lxml E builder class with arbitrary inputs. 
     269         
     270        :param parnet: The parent element to append a child to 
     271        :param elementname: The name of the child in string form 
     272        :param text: The element text 
     273        :param attrib: A dictionary of attribute names to attribute values 
     274        """ 
    256275        text = str(text) 
     276        if attrib == None: 
     277            attrib = {} 
    257278        elem = E(elementname, attrib, text) 
    258279        parent = parent.append(elem) 
  • src/sans/perspectives/fitting/pagestate.py

    reddb6ec rac5b69d  
    2020 
    2121import xml.dom.minidom 
     22from xml.dom.minidom import parseString 
    2223from lxml import etree 
    2324 
     
    672673            # We are appending to an existing document 
    673674            newdoc = doc 
    674             top_element = newdoc.createElement(FITTING_NODE_NAME) 
     675            try: 
     676                top_element = newdoc.createElement(FITTING_NODE_NAME) 
     677            except: 
     678                string = etree.tostring(doc, pretty_print=True) 
     679                newdoc = parseString(string) 
     680                top_element = newdoc.createElement(FITTING_NODE_NAME) 
    675681            if entry_node is None: 
    676682                newdoc.documentElement.appendChild(top_element) 
    677683            else: 
    678                 entry_node.appendChild(top_element) 
    679              
     684                try: 
     685                    entry_node.appendChild(top_element) 
     686                except: 
     687                    node_name = entry_node.tag 
     688                    node_list = newdoc.getElementsByTagName(node_name) 
     689                    entry_node = node_list.item(0) 
     690                    entry_node.appendChild(top_element) 
     691                     
    680692        attr = newdoc.createAttribute("version") 
    681693        attr.nodeValue = '1.0' 
     
    750762        for item in list_of_state_parameters: 
    751763            element = newdoc.createElement(item[0]) 
    752             com = "self._toXML_helper(list=self.%s," 
     764            com = "self._toXML_helper(thelist=self.%s," 
    753765            com += " element=element, newdoc=newdoc)" 
    754766            exec com % item[1] 
     
    762774            return None 
    763775        else: 
    764             return newdoc.toprettyxml() 
     776            return newdoc 
    765777         
    766778    def _fromXML_helper(self, node, list): 
     
    12521264                state = PageState() 
    12531265                state.fromXML(node=nodes[0]) 
     1266                 
    12541267        except: 
    12551268            logging.info("XML document does not contain fitting information.\n %s" % sys.exc_value) 
     
    12571270        return state 
    12581271       
    1259     def _parse_entry(self, dom): 
     1272    def _parse_save_state_entry(self, dom): 
    12601273        """ 
    12611274        Parse a SASentry 
     
    12681281        node = dom.xpath('ns:data_class', namespaces={'ns': CANSAS_NS}) 
    12691282        if not node or node[0].text.lstrip().rstrip() != "Data2D": 
    1270             return CansasReader._parse_entry(self, dom) 
     1283            return_value, _ = self._parse_entry(dom) 
     1284            numpy.trim_zeros(return_value.x) 
     1285            numpy.trim_zeros(return_value.y) 
     1286            numpy.trim_zeros(return_value.dy) 
     1287            size_dx = return_value.dx.size 
     1288            size_dxl = return_value.dxl.size 
     1289            size_dxw = return_value.dxw.size 
     1290            if size_dxl == 0 and size_dxw == 0: 
     1291                return_value.dxl = None 
     1292                return_value.dxw = None 
     1293                numpy.trim_zeros(return_value.dx) 
     1294            elif size_dx == 0: 
     1295                return_value.dx = None 
     1296                size_dx = size_dxl 
     1297                numpy.trim_zeros(return_value.dxl) 
     1298                numpy.trim_zeros(return_value.dxw) 
     1299                             
     1300            return return_value, _ 
    12711301         
    12721302        #Parse 2D 
     
    15391569                    for entry in entry_list: 
    15401570                        try: 
    1541                             sas_entry = self._parse_entry(entry) 
     1571                            sas_entry, _ = self._parse_save_state_entry(entry) 
    15421572                        except: 
    15431573                            raise 
     
    16081638        # Sanity check 
    16091639        if self.cansas == True: 
    1610              
    16111640            # Add fitting information to the XML document 
    16121641            doc = self.write_toXML(datainfo, fitstate) 
    16131642            # Write the XML document 
    1614             fd = open(filename, 'w') 
    1615             fd.write(doc.toprettyxml()) 
    1616             fd.close() 
    16171643        else: 
    1618             fitstate.toXML(file=filename) 
     1644            doc = fitstate.toXML(file=filename) 
     1645         
     1646        # Save the document no matter the type 
     1647        fd = open(filename, 'w') 
     1648        fd.write(doc.toprettyxml()) 
     1649        fd.close() 
    16191650         
    16201651    def write_toXML(self, datainfo=None, state=None): 
     
    16381669                state.data.run = [str(state.data.name)] 
    16391670                state.data.run_name[0] = state.data.name 
    1640     
     1671             
    16411672            if issubclass(state.data.__class__, 
    16421673                          sans.dataloader.data_info.Data1D): 
     
    16481679             
    16491680        if state is not None: 
    1650             state.toXML(doc=doc, file=data.filename, entry_node=sasentry) 
    1651              
     1681            doc = state.toXML(doc=doc, file=data.filename, entry_node=sasentry) 
     1682         
    16521683        return doc 
    16531684     
Note: See TracChangeset for help on using the changeset viewer.