Changeset 786685e in sasview for src/sans/dataloader


Ignore:
Timestamp:
May 15, 2014 5:08:38 PM (10 years ago)
Author:
pkienzle
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:
4a0dc427
Parents:
4e9f227 (diff), bb1b892 (diff)
Note: this is a merge changeset, the changes displayed below correspond to the merge itself.
Use the (diff) links above to see all the changes relative to each parent.
Message:

merge from trunk

Location:
src/sans/dataloader/readers
Files:
3 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 rbb1b892  
    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" or tagname == "pr_inversion" or\ 
     375                    tagname == "invariant": 
     376                    continue 
     377                names.append(tagname) 
    372378                attr = node.attrib 
    373379                children = node.getchildren() 
     380                if len(children) == 0: 
     381                    children = None 
    374382                save_data1d = data1d 
    375383                 
     
    410418                                 
    411419                # Get where to store content 
    412                 cs_values = constants._iterate_namespace(ns) 
     420                cs_values = CONSTANTS.iterate_namespace(names) 
    413421                # If the element is a child element, recurse 
    414422                if children is not None: 
    415423                    # Returned value is new Data1D object with all previous and  
    416424                    # new values in it. 
    417                     data1d, extras = self._parse_entry(node, ns, data1d, extras) 
     425                    data1d, extras = self._parse_entry(node,  
     426                                                       names, data1d, extras) 
    418427                     
    419428                #Get the information from the node 
     
    488497                            pass 
    489498             
    490             except TypeError: 
     499            except TypeError as e: 
    491500                pass 
    492501            except Exception as e: 
     
    509518                else: 
    510519                    save_data1d = data1d 
    511                 data1d = save_data1d 
    512                 # Remove tagname from ns to restore original base 
    513                 ns.remove(tagname_original) 
    514          
     520                if tagname_original == "fitting_plug_in" or \ 
     521                    tagname_original == "invariant" or \ 
     522                    tagname_original == "pr_inversion": 
     523                    pass 
     524                else: 
     525                    data1d = save_data1d 
     526                    # Remove tagname from names to restore original base 
     527                    names.remove(tagname_original) 
    515528        return data1d, extras 
    516529         
     530     
    517531    def _to_xml_doc(self, datainfo): 
    518532        """ 
     
    521535        :param datainfo: Data1D object 
    522536        """ 
    523          
    524537        if not issubclass(datainfo.__class__, Data1D): 
    525538            raise RuntimeError, "The cansas writer expects a Data1D instance" 
    526539         
    527540        # 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) 
     541        pis = self.return_processing_instructions() 
     542        if len(pis) > 0: 
     543            pi_tree = self.create_tree(pis[0]) 
     544            i = 1 
     545            for i in range(1,len(pis) - 1): 
     546                pi_tree = self.append(pis[i], pi_tree) 
     547            pi_string = self.to_string(pi_tree) 
     548        else: 
     549            pi_string = "" 
    533550         
    534551        # Define namespaces and create SASroot object 
     
    540557        else: 
    541558            url = "http://svn.smallangles.net/svn/canSAS/1dwg/trunk/" 
    542         schemaLocation = "{0} {1}cansas1d.xsd".format(ns, url) 
    543         attrib = {"{" + xsi + "}schemaLocation" : schemaLocation, 
     559        schema_location = "{0} {1}cansas1d.xsd".format(ns, url) 
     560        attrib = {"{" + xsi + "}schemaLocation" : schema_location, 
    544561                  "version" : version} 
    545562        nsmap = {'xsi' : xsi, None: ns} 
    546563         
    547         main_node = self.reader.create_element("{" + ns + "}SASroot", \ 
     564        main_node = self.create_element("{" + ns + "}SASroot", \ 
    548565                                               attrib = attrib, \ 
    549566                                               nsmap = nsmap) 
    550567         
    551568        # 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) 
     569        base_string = pi_string + self.to_string(main_node) 
     570        base_element = self.create_element_from_string(base_string) 
     571        doc = self.create_tree(base_element) 
    556572         
    557573        # Create SASentry Element 
    558         entry_node = self.reader.create_element("SASentry") 
     574        entry_node = self.create_element("SASentry") 
    559575        root = doc.getroot() 
    560576        root.append(entry_node) 
     
    576592         
    577593        # Data info 
    578         node = self.reader.create_element("SASdata") 
    579         self.reader.append(node, entry_node) 
     594        node = self.create_element("SASdata") 
     595        self.append(node, entry_node) 
    580596         
    581597        for i in range(len(datainfo.x)): 
    582             pt = self.reader.create_element("Idata") 
     598            pt = self.create_element("Idata") 
    583599            node.append(pt) 
    584600            self.write_node(pt, "Q", datainfo.x[i], {'unit': datainfo.x_unit}) 
     
    598614                self.write_node(pt, "dQl", datainfo.dxl[i], 
    599615                            {'unit': datainfo.x_unit}) 
    600  
     616         
    601617        # Transmission Spectrum Info 
    602618        for i in range(len(datainfo.trans_spectrum)): 
    603619            spectrum = datainfo.trans_spectrum[i] 
    604             node = self.reader.create_element("SAStransmission_spectrum", 
     620            node = self.create_element("SAStransmission_spectrum", 
    605621                                              {"name" : spectrum.name}) 
    606             self.reader.append(node, entry_node) 
     622            self.append(node, entry_node) 
    607623            if isinstance(spectrum.timestamp, datetime.datetime): 
    608624                node.setAttribute("timestamp", spectrum.timestamp) 
    609625            for i in range(len(spectrum.wavelength)): 
    610                 pt = self.reader.create_element("Tdata") 
     626                pt = self.create_element("Tdata") 
    611627                node.append(pt) 
    612628                self.write_node(pt, "Lambda", spectrum.wavelength[i],  
     
    621637 
    622638        # Sample info 
    623         sample = self.reader.create_element("SASsample") 
     639        sample = self.create_element("SASsample") 
    624640        if datainfo.sample.name is not None: 
    625             self.reader.write_attribute(sample,  
     641            self.write_attribute(sample,  
    626642                                        "name",  
    627643                                        str(datainfo.sample.name)) 
    628         self.reader.append(sample, entry_node) 
     644        self.append(sample, entry_node) 
    629645        self.write_node(sample, "ID", str(datainfo.sample.ID)) 
    630646        self.write_node(sample, "thickness", datainfo.sample.thickness, 
     
    634650                   {"unit": datainfo.sample.temperature_unit}) 
    635651         
    636         pos = self.reader.create_element("position") 
     652        pos = self.create_element("position") 
    637653        written = self.write_node(pos,  
    638654                                  "x",  
     
    648664                                       {"unit": datainfo.sample.position_unit}) 
    649665        if written == True: 
    650             self.reader.append(pos, sample) 
    651          
    652         ori = self.reader.create_element("orientation") 
     666            self.append(pos, sample) 
     667         
     668        ori = self.create_element("orientation") 
    653669        written = self.write_node(ori, "roll", 
    654670                                  datainfo.sample.orientation.x, 
     
    661677                                    {"unit": datainfo.sample.orientation_unit}) 
    662678        if written == True: 
    663             self.reader.append(ori, sample) 
     679            self.append(ori, sample) 
    664680         
    665681        for item in datainfo.sample.details: 
     
    667683         
    668684        # Instrument info 
    669         instr = self.reader.create_element("SASinstrument") 
    670         self.reader.append(instr, entry_node) 
     685        instr = self.create_element("SASinstrument") 
     686        self.append(instr, entry_node) 
    671687         
    672688        self.write_node(instr, "name", datainfo.instrument) 
    673689         
    674690        #   Source 
    675         source = self.reader.create_element("SASsource") 
     691        source = self.create_element("SASsource") 
    676692        if datainfo.source.name is not None: 
    677             self.reader.write_attribute(source, 
     693            self.write_attribute(source, 
    678694                                        "name", 
    679695                                        str(datainfo.source.name)) 
    680         self.reader.append(source, instr) 
     696        self.append(source, instr) 
    681697        if datainfo.source.radiation == None or datainfo.source.radiation == '': 
    682698            datainfo.source.radiation = "neutron" 
    683699        self.write_node(source, "radiation", datainfo.source.radiation) 
    684700         
    685         size = self.reader.create_element("beam_size") 
     701        size = self.create_element("beam_size") 
    686702        if datainfo.source.beam_size_name is not None: 
    687             self.reader.write_attribute(size, 
     703            self.write_attribute(size, 
    688704                                        "name", 
    689705                                        str(datainfo.source.beam_size_name)) 
     
    697713                                       {"unit": datainfo.source.beam_size_unit}) 
    698714        if written == True: 
    699             self.reader.append(size, source) 
     715            self.append(size, source) 
    700716             
    701717        self.write_node(source, "beam_shape", datainfo.source.beam_shape) 
     
    718734            datainfo.collimation.append(coll) 
    719735        for item in datainfo.collimation: 
    720             coll = self.reader.create_element("SAScollimation") 
     736            coll = self.create_element("SAScollimation") 
    721737            if item.name is not None: 
    722                 self.reader.write_attribute(coll, "name", str(item.name)) 
    723             self.reader.append(coll, instr) 
     738                self.write_attribute(coll, "name", str(item.name)) 
     739            self.append(coll, instr) 
    724740             
    725741            self.write_node(coll, "length", item.length, 
     
    727743             
    728744            for apert in item.aperture: 
    729                 ap = self.reader.create_element("aperture") 
     745                ap = self.create_element("aperture") 
    730746                if apert.name is not None: 
    731                     self.reader.write_attribute(ap, "name", str(apert.name)) 
     747                    self.write_attribute(ap, "name", str(apert.name)) 
    732748                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") 
     749                    self.write_attribute(ap, "type", str(apert.type)) 
     750                self.append(ap, coll) 
     751                 
     752                size = self.create_element("size") 
    737753                if apert.size_name is not None: 
    738                     self.reader.write_attribute(size,  
     754                    self.write_attribute(size,  
    739755                                                "name",  
    740756                                                str(apert.size_name)) 
     
    746762                                               {"unit": apert.size_unit}) 
    747763                if written == True: 
    748                     self.reader.append(size, ap) 
     764                    self.append(size, ap) 
    749765                 
    750766                self.write_node(ap, "distance", apert.distance, 
     
    758774                 
    759775        for item in datainfo.detector: 
    760             det = self.reader.create_element("SASdetector") 
     776            det = self.create_element("SASdetector") 
    761777            written = self.write_node(det, "name", item.name) 
    762778            written = written | self.write_node(det, "SDD", item.distance, 
    763779                                           {"unit": item.distance_unit}) 
    764780            if written == True: 
    765                 self.reader.append(det, instr) 
     781                self.append(det, instr) 
    766782             
    767             off = self.reader.create_element("offset") 
     783            off = self.create_element("offset") 
    768784            written = self.write_node(off, "x", item.offset.x, 
    769785                                 {"unit": item.offset_unit}) 
     
    773789                                           {"unit": item.offset_unit}) 
    774790            if written == True: 
    775                 self.reader.append(off, det) 
    776                  
    777             ori = self.reader.create_element("orientation") 
     791                self.append(off, det) 
     792                 
     793            ori = self.create_element("orientation") 
    778794            written = self.write_node(ori, "roll", item.orientation.x, 
    779795                                 {"unit": item.orientation_unit}) 
     
    785801                                           {"unit": item.orientation_unit}) 
    786802            if written == True: 
    787                 self.reader.append(ori, det) 
     803                self.append(ori, det) 
    788804             
    789             center = self.reader.create_element("beam_center") 
     805            center = self.create_element("beam_center") 
    790806            written = self.write_node(center, "x", item.beam_center.x, 
    791807                                 {"unit": item.beam_center_unit}) 
     
    797813                                           {"unit": item.beam_center_unit}) 
    798814            if written == True: 
    799                 self.reader.append(center, det) 
    800                  
    801             pix = self.reader.create_element("pixel_size") 
     815                self.append(center, det) 
     816                 
     817            pix = self.create_element("pixel_size") 
    802818            written = self.write_node(pix, "x", item.pixel_size.x, 
    803819                                 {"unit": item.pixel_size_unit}) 
     
    810826                                           {"unit": item.slit_length_unit}) 
    811827            if written == True: 
    812                 self.reader.append(pix, det) 
     828                self.append(pix, det) 
    813829             
    814830        # Processes info 
    815831        for item in datainfo.process: 
    816             node = self.reader.create_element("SASprocess") 
    817             self.reader.append(node, entry_node) 
     832            node = self.create_element("SASprocess") 
     833            self.append(node, entry_node) 
    818834 
    819835            self.write_node(node, "name", item.name) 
     
    831847        # Note info 
    832848        if len(datainfo.notes) == 0: 
    833             node = self.reader.create_element("SASnote") 
    834             self.reader.append(node, entry_node) 
     849            node = self.create_element("SASnote") 
     850            self.append(node, entry_node) 
    835851        else: 
    836852            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) 
     853                node = self.create_element("SASnote") 
     854                self.write_text(node, item) 
     855                self.append(node, entry_node) 
    840856                 
    841857         
    842858        # Return the document, and the SASentry node associated with 
    843         # the data we just wrote 
     859        #      the data we just wrote 
     860        # If the calling function was not the cansas reader, return a minidom 
     861        #      object rather than an lxml object.         
     862         
     863        frm = inspect.stack()[1] 
     864        mod_name = frm[1].replace("\\", "/").replace(".pyc", "") 
     865        mod_name = mod_name.replace(".py", "") 
     866        mod = mod_name.split("/readers/") 
     867        mod_name = mod[1] 
     868        if mod_name != "cansas_reader": 
     869            string = self.to_string(doc, pp=False) 
     870            doc = parseString(string) 
     871            node_name = entry_node.tag 
     872            node_list = doc.getElementsByTagName(node_name) 
     873            entry_node = node_list.item(0) 
     874             
    844875        return doc, entry_node 
    845876     
    846877     
    847     def write_node(self, parent, name, value, attr={}): 
     878    def write_node(self, parent, name, value, attr=None): 
    848879        """ 
    849880        :param doc: document DOM 
     
    856887        """ 
    857888        if value is not None: 
    858             parent = self.reader.ebuilder(parent, name, value, attr) 
     889            parent = self.ebuilder(parent, name, value, attr) 
    859890            return True 
    860891        return False 
     
    872903        # Write the file 
    873904        fd = open(filename, 'w') 
    874         if self.reader.encoding == None: 
    875             self.reader.encoding = "UTF-8" 
    876         doc.write(fd, encoding=self.reader.encoding, 
     905        if self.encoding == None: 
     906            self.encoding = "UTF-8" 
     907        doc.write(fd, encoding=self.encoding, 
    877908                  pretty_print=True, xml_declaration=True) 
    878909        fd.close() 
    879910     
     911     
     912    # DO NOT REMOVE - used in saving and loading panel states. 
     913    def _store_float(self, location, node, variable, storage, optional=True): 
     914        """ 
     915        Get the content of a xpath location and store 
     916        the result. Check that the units are compatible 
     917        with the destination. The value is expected to 
     918        be a float. 
     919         
     920        The xpath location might or might not exist. 
     921        If it does not exist, nothing is done 
     922        
     923        :param location: xpath location to fetch 
     924        :param node: node to read the data from 
     925        :param variable: name of the data member to store it in [string] 
     926        :param storage: data object that has the 'variable' data member 
     927        :param optional: if True, no exception will be raised 
     928            if unit conversion can't be done 
     929 
     930        :raise ValueError: raised when the units are not recognized 
     931        """ 
     932        entry = get_content(location, node) 
     933        try: 
     934            value = float(entry.text) 
     935        except: 
     936            value = None 
     937             
     938        if value is not None: 
     939            # If the entry has units, check to see that they are 
     940            # compatible with what we currently have in the data object 
     941            units = entry.get('unit') 
     942            if units is not None: 
     943                toks = variable.split('.') 
     944                local_unit = None 
     945                exec "local_unit = storage.%s_unit" % toks[0] 
     946                if local_unit != None and units.lower() != local_unit.lower(): 
     947                    if HAS_CONVERTER == True: 
     948                        try: 
     949                            conv = Converter(units) 
     950                            exec "storage.%s = %g" % (variable, 
     951                                           conv(value, units=local_unit)) 
     952                        except: 
     953                            exc_type, exc_value, exc_traceback = sys.exc_info() 
     954                            err_mess = "CanSAS reader: could not convert" 
     955                            err_mess += " %s unit [%s]; expecting [%s]\n  %s" \ 
     956                                % (variable, units, local_unit, exc_value) 
     957                            self.errors.append(err_mess) 
     958                            if optional: 
     959                                logging.info(err_mess) 
     960                            else: 
     961                                raise ValueError, err_mess 
     962                    else: 
     963                        err_mess = "CanSAS reader: unrecognized %s unit [%s];"\ 
     964                        % (variable, units) 
     965                        err_mess += " expecting [%s]" % local_unit 
     966                        self.errors.append(err_mess) 
     967                        if optional: 
     968                            logging.info(err_mess) 
     969                        else: 
     970                            raise ValueError, err_mess 
     971                else: 
     972                    exec "storage.%s = value" % variable 
     973            else: 
     974                exec "storage.%s = value" % variable 
     975                 
     976     
     977    # DO NOT REMOVE - used in saving and loading panel states. 
     978    def _store_content(self, location, node, variable, storage): 
     979        """ 
     980        Get the content of a xpath location and store 
     981        the result. The value is treated as a string. 
     982         
     983        The xpath location might or might not exist. 
     984        If it does not exist, nothing is done 
     985         
     986        :param location: xpath location to fetch 
     987        :param node: node to read the data from 
     988        :param variable: name of the data member to store it in [string] 
     989        :param storage: data object that has the 'variable' data member 
     990         
     991        :return: return a list of errors 
     992        """ 
     993        entry = get_content(location, node) 
     994        if entry is not None and entry.text is not None: 
     995            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) 
Note: See TracChangeset for help on using the changeset viewer.