Ignore:
Timestamp:
Jan 14, 2014 3:53:36 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:
16bd5ca
Parents:
083e993
Message:

Fix for the datainfo window not loading and bug fixes for the cansas data reader.

Fixes/changes:
(1) datainfo window is now loading for every data file I can test
(2) transmission spectrum information (but not data) is listed in datainfo window
(3) more than one transmission spectra can be loaded for each Data1D object
(4) fixed a bug in the cansas reader that allowed any file to be loaded as data if and only if another data file was already loaded
(5) fixed the cansas writer to include transmission spectrum data and output data in strict canSAS format
(6) increased the pylint score of cansas_constants.py to above 7
(7) increased the pylint score for all files I have modified

File:
1 edited

Legend:

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

    r1ce36f37 r76cd1ae  
    11""" 
    2     CanSAS data reader - new recursive cansasVersion. 
     2    CanSAS data reader - new recursive cansas_version. 
    33""" 
    44############################################################################ 
     
    1919from sans.dataloader.data_info import Data1D 
    2020from sans.dataloader.data_info import Collimation 
     21from sans.dataloader.data_info import TransmissionSpectrum 
    2122from sans.dataloader.data_info import Detector 
    2223from sans.dataloader.data_info import Process 
    2324from sans.dataloader.data_info import Aperture 
    24 import xml_reader 
     25import sans.dataloader.readers.xml_reader as xml_reader 
    2526import xml.dom.minidom 
    26 from cansas_constants import cansasConstants 
     27from sans.dataloader.readers.cansas_constants import cansasConstants 
    2728 
    2829_ZERO = 1e-16 
     
    3233except: 
    3334    HAS_CONVERTER = False 
    34      
    35 CANSAS_FORMAT = cansasConstants.CANSAS_FORMAT 
    36 CANSAS_NS = cansasConstants.CANSAS_NS 
     35 
     36constants = cansasConstants()     
     37CANSAS_FORMAT = constants.format 
     38CANSAS_NS = constants.ns 
    3739ALLOW_ALL = True 
    3840 
     
    118120    """ 
    119121    ##CanSAS version - defaults to version 1.0 
    120     cansasVersion = "1.0" 
     122    cansas_version = "1.0" 
    121123    ##Data reader 
    122124    reader = xml_reader.XMLreader() 
     
    137139        self.errors = [] 
    138140         
    139     def isCansas(self): 
     141    def is_cansas(self): 
    140142        """ 
    141143        Checks to see if the xml file is a CanSAS file 
     
    143145        if self.reader.validateXML(): 
    144146            xmlns = self.reader.xmlroot.keys() 
    145             if (CANSAS_NS.get(self.cansasVersion).get("ns") == self.reader.xmlroot.get(xmlns[1]).rsplit(" ")[0]): 
     147            if (CANSAS_NS.get(self.cansas_version).get("ns") == \ 
     148                    self.reader.xmlroot.get(xmlns[1]).rsplit(" ")[0]): 
    146149                return True 
    147150        return False 
     
    176179                base = base_name.split("/sans/")[0] 
    177180                 
    178                 # Load in the xml file and get the cansas version from the header 
     181                # Load in xml file and get the cansas version from the header 
    179182                self.reader.setXMLFile(xml) 
    180183                root = self.reader.xmlroot 
    181184                if root is None: 
    182185                    root = {} 
    183                 self.cansasVersion = root.get("version", "1.0") 
     186                self.cansas_version = root.get("version", "1.0") 
    184187                 
    185188                # Generic values for the cansas file based on the version 
    186                 cansas_defaults = CANSAS_NS.get(self.cansasVersion, "1.0") 
    187                 schema_path = "{0}/sans/dataloader/readers/schema/{1}".format(base, cansas_defaults.get("schema")).replace("\\", "/") 
     189                cansas_defaults = CANSAS_NS.get(self.cansas_version, "1.0") 
     190                schema_path = "{0}/sans/dataloader/readers/schema/{1}".format\ 
     191                        (base, cansas_defaults.get("schema")).replace("\\", "/") 
    188192                 
    189193                # Link a schema to the XML file. 
     
    193197                # Check the file matches the XML schema 
    194198                try: 
    195                     if self.isCansas(): 
    196                         # Get each SASentry from the XML file and add it to a list. 
     199                    if self.is_cansas(): 
     200                        # Get each SASentry from XML file and add it to a list. 
    197201                        entry_list = root.xpath('/ns:SASroot/ns:SASentry', 
    198                                                      namespaces={'ns': cansas_defaults.get("ns")}) 
     202                                namespaces={'ns': cansas_defaults.get("ns")}) 
    199203                        ns.append("SASentry") 
    200204                         
    201                         # If there are multiple files, modify the name for each is unique 
    202                         multipleFiles = len(entry_list) - 1 
    203                         n = 0 
     205                        # If multiple files, modify the name for each is unique 
     206                        multiple_files = len(entry_list) - 1 
     207                        increment = 0 
    204208                        name = basename 
    205209                        # Parse each SASentry item 
    206210                        for entry in entry_list: 
     211                            # Define a new Data1D object with zeroes for x and y 
     212                            data1d = Data1D(x,y,dx,dy) 
     213                            data1d.dxl = dxl 
     214                            data1d.dxw = dxw 
    207215                             
    208                             # Define a new Data1D object with zeroes for x and y 
    209                             data1D = Data1D(x,y,dx,dy) 
    210                             data1D.dxl = dxl 
    211                             data1D.dxw = dxw 
     216                            # If more than one SASentry, increment each in order 
     217                            if multiple_files: 
     218                                name += "_{0}".format(increment) 
     219                                increment += 1 
    212220                             
    213                             # If more than one SASentry, number each in order 
    214                             if multipleFiles: 
    215                                 name += "_{0}".format(n) 
    216                                 n += 1 
    217                              
    218                             # Set the Data1D name and then parse the entry. The entry is appended to a list of entry values 
    219                             data1D.filename = name 
    220                             data1D.meta_data["loader"] = "CanSAS 1D" 
    221                             return_value, extras = self._parse_entry(entry, ns, data1D) 
     221                            # Set the Data1D name and then parse the entry.  
     222                            # The entry is appended to a list of entry values 
     223                            data1d.filename = name 
     224                            data1d.meta_data["loader"] = "CanSAS 1D" 
     225                            return_value, extras = \ 
     226                                self._parse_entry(entry, ns, data1d) 
    222227                            del extras[:] 
    223228                             
    224                             #Final cleanup - Remove empty nodes, verify array sizes are correct 
     229                            # Final cleanup 
     230                            # Remove empty nodes, verify array sizes are correct 
    225231                            for error in self.errors: 
    226232                                return_value.errors.append(error) 
     
    241247                                numpy.trim_zeros(return_value.dxl) 
    242248                                numpy.trim_zeros(return_value.dxw) 
    243                              
    244249                            output.append(return_value) 
    245250                    else: 
     
    248253                except: 
    249254                    # If the file does not match the schema, raise this error 
    250                     raise RuntimeError, "%s cannot be read \n" % xml 
     255                    raise RuntimeError, "%s cannot be read \increment" % xml 
    251256                return output 
    252257        # Return a list of parsed entries that dataloader can manage 
     
    254259     
    255260    def _create_unique_key(self, dictionary, name, i): 
     261        """ 
     262        Create a unique key value for any dictionary to prevent overwriting 
     263         
     264         
     265        :param dictionary: A dictionary with any number of entries 
     266        :param name: The index of the item to be added to dictionary 
     267        :param i: The number to be appended to the name 
     268        """ 
    256269        if dictionary.get(name) is not None: 
    257270            i += 1 
     
    261274        return name 
    262275     
    263     def _iterate_namespace(self, ns): 
     276    def _iterate_namespace(self, namespace): 
     277        """ 
     278        Method to iterate through a cansas constants tree based on a list of 
     279        names 
     280         
     281        :param namespace: A list of names that match the tree structure of 
     282            cansas_constants 
     283        """ 
    264284        # The current level to look through in cansas_constants. 
    265285        current_level = CANSAS_FORMAT.get("SASentry") 
     
    268288        ns_datatype = "content" 
    269289        ns_optional = True 
    270         for name in ns: 
     290        for name in namespace: 
    271291            if name != "SASentry": 
    272292                current_level = current_level.get("children").get(name, "") 
     
    277297                cl_units_optional = current_level.get("units_required", "") 
    278298                # Where are how to store the variable for the given namespace 
    279                 # The CANSAS_CONSTANTS tree is hierarchical, so is no value, inherit 
     299                # CANSAS_CONSTANTS tree is hierarchical, so is no value, inherit 
    280300                ns_variable = cl_variable if cl_variable != "" else ns_variable 
    281301                ns_datatype = cl_datatype if cl_datatype != "" else ns_datatype 
    282                 ns_optional = cl_units_optional if cl_units_optional != ns_optional else ns_optional 
     302                ns_optional = cl_units_optional if cl_units_optional != \ 
     303                                    ns_optional else ns_optional 
    283304        return current_level, ns_variable, ns_datatype, ns_optional 
    284305     
    285     def _unit_conversion(self, new_current_level, attr, data1D, node_value, optional = True): 
     306     
     307    def _unit_conversion(self, new_current_level, attr, data1d, \ 
     308                                    node_value, optional = True): 
     309        """ 
     310        A unit converter method used to convert the data included in the file 
     311        to the default units listed in data_info 
     312         
     313        :param new_current_level: cansas_constants level as returned by  
     314            _iterate_namespace 
     315        :param attr: The attributes of the node 
     316        :param data1d: Where the values will be saved 
     317        :param node_value: The value of the current dom node 
     318        :param optional: Boolean that says if the units are required 
     319        """ 
    286320        value_unit = '' 
    287321        if 'unit' in attr and new_current_level.get('unit') is not None: 
     
    291325                default_unit = None 
    292326                unitname = new_current_level.get("unit") 
    293                 exec "default_unit = data1D.{0}".format(unitname) 
     327                exec "default_unit = data1d.{0}".format(unitname) 
    294328                local_unit = attr['unit'] 
    295                 if local_unit.lower() != default_unit.lower() and local_unit is not None\ 
    296                     and local_unit.lower() != "none" and default_unit is not None: 
     329                if local_unit.lower() != default_unit.lower() and \ 
     330                    local_unit is not None and local_unit.lower() != "none" and\ 
     331                     default_unit is not None: 
    297332                    if HAS_CONVERTER == True: 
    298333                        try: 
    299334                            data_conv_q = Converter(attr['unit']) 
    300335                            value_unit = default_unit 
    301                             exec "node_value = data_conv_q(node_value, units=data1D.{0})".format(unitname) 
     336                            exec "node_value = data_conv_q(node_value, units=data1d.{0})".format(unitname) 
    302337                        except: 
    303338                            err_msg = "CanSAS reader: could not convert " 
    304339                            err_msg += "Q unit {0}; ".format(local_unit) 
    305                             intermediate = "err_msg += \"expecting [{1}]  {2}\".format(data1D.{0}, sys.exc_info()[1])".format(unitname, "{0}", "{1}") 
     340                            intermediate = "err_msg += \"expecting [{1}]  {2}\".format(data1d.{0}, sys.exc_info()[1])".format(unitname, "{0}", "{1}") 
    306341                            exec intermediate 
    307342                            self.errors.append(err_msg) 
     
    325360                err_msg = "CanSAS reader: could not convert " 
    326361                err_msg += "Q unit [%s]; " % attr['unit'], 
    327                 exec "err_msg += \"expecting [%s]\n  %s\" % (data1D.{0}, sys.exc_info()[1])".format(unitname) 
     362                exec "err_msg += \"expecting [%s]\n  %s\" % (data1d.{0}, sys.exc_info()[1])".format(unitname) 
    328363                self.errors.append(err_msg) 
    329364                if optional: 
     
    336371        return node_value, value_unit 
    337372     
    338     def _parse_entry(self, dom, ns, data1D, extras = []): 
     373    def _parse_entry(self, dom, ns, data1d, extras = []): 
    339374        """ 
    340375        Parse a SASEntry - new recursive method for parsing the dom of 
     
    344379        :param dom: dom object with a namespace base of ns 
    345380        :param ns: A list of element names that lead up to the dom object 
    346         :param data1D: The data1D object that will be modified 
     381        :param data1d: The data1d object that will be modified 
     382        :param extras: Any values that should go into meta_data when data1d 
     383            is not a Data1D object 
    347384        """ 
    348385          
    349386        # A portion of every namespace entry 
    350         base_ns = "{0}{1}{2}".format("{", CANSAS_NS.get(self.cansasVersion).get("ns"), "}") 
     387        base_ns = "{0}{1}{2}".format("{", \ 
     388                            CANSAS_NS.get(self.cansas_version).get("ns"), "}") 
    351389        unit = '' 
    352390         
     
    361399                 
    362400                # Look for special cases 
    363                 save_data1D = data1D 
     401                save_data1d = data1d 
    364402                if tagname == "SASdetector": 
    365                     data1D = Detector() 
     403                    data1d = Detector() 
    366404                elif tagname == "SAScollimation": 
    367                     data1D = Collimation() 
     405                    data1d = Collimation() 
     406                elif tagname == "SAStransmission_spectrum": 
     407                    data1d = TransmissionSpectrum() 
    368408                elif tagname == "SASprocess": 
    369                     data1D = Process() 
     409                    data1d = Process() 
    370410                    for child in node: 
    371411                        if child.tag.replace(base_ns, "") == "term": 
    372412                            term_attr = {} 
    373413                            for attr in child.keys(): 
    374                                 term_attr[attr] = ' '.join(child.get(attr).split()) 
     414                                term_attr[attr] = \ 
     415                                    ' '.join(child.get(attr).split()) 
    375416                            if child.text is not None: 
    376                                 term_attr['value'] = ' '.join(child.text.split()) 
    377                             data1D.term.append(term_attr) 
     417                                term_attr['value'] = \ 
     418                                    ' '.join(child.text.split()) 
     419                            data1d.term.append(term_attr) 
    378420                elif tagname == "aperture": 
    379                     data1D = Aperture() 
     421                    data1d = Aperture() 
    380422                 
    381423                # Get where to store content 
    382                 new_current_level, ns_variable, ns_datatype, optional = self._iterate_namespace(ns) 
     424                new_current_level, ns_var, ns_datatype, \ 
     425                                    optional = self._iterate_namespace(ns) 
    383426                # If the element is a child element, recurse 
    384427                if node.getchildren() is not None: 
    385428                    # Returned value is new Data1D object with all previous and new values in it. 
    386                     data1D, extras = self._parse_entry(node, ns, data1D, extras) 
     429                    data1d, extras = self._parse_entry(node, ns, data1d, extras) 
    387430                     
    388431                #Get the information from the node 
     
    396439                if ns_datatype == "float": 
    397440                    # If an empty value is given, store as zero. 
    398                     if node_value is None or node_value.isspace() or node_value.lower() == "nan": 
     441                    if node_value is None or node_value.isspace() \ 
     442                                            or node_value.lower() == "nan": 
    399443                        node_value = "0.0" 
    400                     node_value, unit = self._unit_conversion(new_current_level, attr, data1D, node_value, optional) 
     444                    node_value, unit = self._unit_conversion(new_current_level,\ 
     445                                             attr, data1d, node_value, optional) 
    401446                     
    402447                # If appending to a dictionary (meta_data | run_name), name sure the key is unique 
    403                 if ns_variable == "{0}.meta_data[\"{2}\"] = \"{1}\"": 
    404                     # If we are within a Process, Detector, Collimation or Aperture instance, pull out old data1D 
    405                     tagname = self._create_unique_key(data1D.meta_data, tagname, 0) 
    406                     if isinstance(data1D, Data1D) == False: 
    407                         store_me = ns_variable.format("data1D", node_value, tagname) 
     448                if ns_var == "{0}.meta_data[\"{2}\"] = \"{1}\"": 
     449                    # If we are within a Process, Detector, Collimation or Aperture instance, pull out old data1d 
     450                    tagname = self._create_unique_key(data1d.meta_data, tagname, 0) 
     451                    if isinstance(data1d, Data1D) == False: 
     452                        store_me = ns_var.format("data1d", node_value, tagname) 
    408453                        extras.append(store_me) 
    409                         ns_variable = None 
    410                 if ns_variable == "{0}.run_name[\"{2}\"] = \"{1}\"": 
    411                     tagname = self._create_unique_key(data1D.run_name, tagname, 0) 
     454                        ns_var = None 
     455                if ns_var == "{0}.run_name[\"{2}\"] = \"{1}\"": 
     456                    tagname = self._create_unique_key(data1d.run_name, tagname, 0) 
    412457                 
    413458                # Check for Data1D object and any extra commands to save 
    414                 if isinstance(data1D, Data1D): 
     459                if isinstance(data1d, Data1D): 
    415460                    for item in extras: 
    416461                        exec item 
    417462                # Don't bother saving empty information unless it is a float 
    418                 if ns_variable is not None and node_value is not None and node_value.isspace() == False: 
     463                if ns_var is not None and node_value is not None and \ 
     464                            node_value.isspace() == False: 
    419465                    # Format a string and then execute it. 
    420                     store_me = ns_variable.format("data1D", node_value, tagname) 
     466                    store_me = ns_var.format("data1d", node_value, tagname) 
    421467                    exec store_me 
    422468                # Get attributes and process them 
     
    430476                            else: 
    431477                                attrib_value = node.attrib[key] 
    432                             store_attr = attrib_variable.format("data1D", attrib_value, key) 
     478                            store_attr = attrib_variable.format("data1d", \ 
     479                                                            attrib_value, key) 
    433480                            exec store_attr 
    434481                        except AttributeError as e: 
     
    441488                print(e, exc_type, fname, exc_tb.tb_lineno, tagname, exc_obj) 
    442489            finally: 
    443                 # Save special cases in original data1D object and then restore the data1D 
     490                # Save special cases in original data1d object 
     491                # then restore the data1d 
    444492                if tagname_original == "SASdetector": 
    445                     save_data1D.detector.append(data1D) 
     493                    save_data1d.detector.append(data1d) 
    446494                elif tagname_original == "SAScollimation": 
    447                     save_data1D.collimation.append(data1D) 
     495                    save_data1d.collimation.append(data1d) 
     496                elif tagname == "SAStransmission_spectrum": 
     497                    save_data1d.trans_spectrum.append(data1d) 
    448498                elif tagname_original == "SASprocess": 
    449                     save_data1D.process.append(data1D) 
     499                    save_data1d.process.append(data1d) 
    450500                elif tagname_original == "aperture": 
    451                     save_data1D.aperture.append(data1D) 
     501                    save_data1d.aperture.append(data1d) 
    452502                else: 
    453                     save_data1D = data1D 
    454                 data1D = save_data1D 
     503                    save_data1d = data1d 
     504                data1d = save_data1d 
    455505                # Remove tagname from ns to restore original base 
    456506                ns.remove(tagname_original) 
    457507         
    458         return data1D, extras 
     508        return data1d, extras 
    459509         
    460510    def _to_xml_doc(self, datainfo): 
     
    468518            raise RuntimeError, "The cansas writer expects a Data1D instance" 
    469519         
    470         ns = CANSAS_NS.get(self.cansasVersion).get("ns") 
     520        ns = CANSAS_NS.get(self.cansas_version).get("ns") 
    471521        doc = xml.dom.minidom.Document() 
    472522        main_node = doc.createElement("SASroot") 
    473         main_node.setAttribute("version", self.cansasVersion) 
     523        main_node.setAttribute("version", self.cansas_version) 
    474524        main_node.setAttribute("xmlns", ns) 
    475525        main_node.setAttribute("xmlns:xsi", 
     
    502552                write_node(doc, pt, "I", datainfo.y[i], 
    503553                            {'unit': datainfo.y_unit}) 
    504             if datainfo.dy != None and len(datainfo.dy) >= i: 
     554            if datainfo.dy != None and len(datainfo.dy) > i: 
    505555                write_node(doc, pt, "Idev", datainfo.dy[i], 
    506556                            {'unit': datainfo.y_unit}) 
    507             if datainfo.dx != None and len(datainfo.dx) >= i: 
     557            if datainfo.dx != None and len(datainfo.dx) > i: 
    508558                write_node(doc, pt, "Qdev", datainfo.dx[i], 
    509559                            {'unit': datainfo.x_unit}) 
    510             if datainfo.dxw != None and len(datainfo.dxw) >= i: 
     560            if datainfo.dxw != None and len(datainfo.dxw) > i: 
    511561                write_node(doc, pt, "dQw", datainfo.dxw[i], 
    512562                            {'unit': datainfo.x_unit}) 
    513             if datainfo.dxl != None and len(datainfo.dxl) >= i: 
     563            if datainfo.dxl != None and len(datainfo.dxl) > i: 
    514564                write_node(doc, pt, "dQl", datainfo.dxl[i], 
    515565                            {'unit': datainfo.x_unit}) 
    516566 
    517567        # Transmission Spectrum Info 
    518         if len(datainfo.trans_spectrum.wavelength) > 0: 
     568        for i in range(len(datainfo.trans_spectrum)): 
     569            spectrum = datainfo.trans_spectrum[i] 
    519570            node = doc.createElement("SAStransmission_spectrum") 
    520571            entry_node.appendChild(node) 
    521             for i in range(len(datainfo.trans_spectrum.wavelength)): 
     572            for i in range(len(spectrum.wavelength)): 
    522573                pt = doc.createElement("Tdata") 
    523574                node.appendChild(pt) 
    524                 write_node(doc, pt, "Lambda", datainfo.trans_spectrum.wavelength[i],  
    525                            {'unit': datainfo.trans_spectrum.wavelength_unit}) 
    526                 write_node(doc, pt, "T", datainfo.trans_spectrum.transmission[i],  
    527                            {'unit': datainfo.trans_spectrum.transmission_unit}) 
    528                 if datainfo.trans_spectrum.transmission_deviation != None \ 
    529                 and len(datainfo.trans_spectrum.transmission_deviation) >= i: 
    530                     write_node(doc, pt, "Tdev", datainfo.trans_spectrum.transmission_deviation[i],  
    531                                {'unit': datainfo.trans_spectrum.transmission_deviation_unit}) 
     575                write_node(doc, pt, "Lambda", spectrum.wavelength[i],  
     576                           {'unit': spectrum.wavelength_unit}) 
     577                write_node(doc, pt, "T", spectrum.transmission[i],  
     578                           {'unit': spectrum.transmission_unit}) 
     579                if spectrum.transmission_deviation != None \ 
     580                and len(spectrum.transmission_deviation) >= i: 
     581                    write_node(doc, pt, "Tdev", \ 
     582                               spectrum.transmission_deviation[i], \ 
     583                               {'unit': spectrum.transmission_deviation_unit}) 
    532584 
    533585        # Sample info 
Note: See TracChangeset for help on using the changeset viewer.