source: sasview/src/sans/dataloader/loader.py @ 143c801

ESS_GUIESS_GUI_DocsESS_GUI_batch_fittingESS_GUI_bumps_abstractionESS_GUI_iss1116ESS_GUI_iss879ESS_GUI_iss959ESS_GUI_openclESS_GUI_orderingESS_GUI_sync_sascalccostrafo411magnetic_scattrelease-4.1.1release-4.1.2release-4.2.2release_4.0.1ticket-1009ticket-1094-headlessticket-1242-2d-resolutionticket-1243ticket-1249ticket885unittest-saveload
Last change on this file since 143c801 was ffbe487, checked in by Mathieu Doucet <doucetm@…>, 11 years ago

Update loader imports for latest move

  • Property mode set to 100644
File size: 14.3 KB
RevLine 
[a916ccc]1"""
[daa56d0]2    File handler to support different file extensions.
3    Uses reflectometry's registry utility.
[bbc8013]4   
5    The default readers are found in the 'readers' sub-module
6    and registered by default at initialization time.
7   
8    To add a new default reader, one must register it in
[f60a8c2]9    the register_readers method found in readers/__init__.py.
[bbc8013]10   
[f60a8c2]11    A utility method (find_plugins) is available to inspect
[bbc8013]12    a directory (for instance, a user plug-in directory) and
13    look for new readers/writers.
[a916ccc]14"""
[f60a8c2]15#####################################################################
16#This software was developed by the University of Tennessee as part of the
17#Distributed Data Analysis of Neutron Scattering Experiments (DANSE)
18#project funded by the US National Science Foundation.
19#See the license text in license.txt
20#copyright 2008, University of Tennessee
21######################################################################
[daa56d0]22
[f60a8c2]23import os
[daa56d0]24import sys
[a916ccc]25import logging
[daa56d0]26import time
[84545dd]27from zipfile import ZipFile
[ffbe487]28from sans.data_util.registry import ExtensionRegistry
[bbc8013]29# Default readers are defined in the readers sub-module
30import readers
[a7a5886]31from readers import ascii_reader
32from readers import cansas_reader
[bbc8013]33
[daa56d0]34class Registry(ExtensionRegistry):
35    """
[0997158f]36    Registry class for file format extensions.
37    Readers and writers are supported.
[daa56d0]38    """
39   
40    def __init__(self):
41        super(Registry, self).__init__()
42       
43        ## Writers
44        self.writers = {}
[a916ccc]45       
[1ed9c57]46        ## List of wildcards
47        self.wildcards = ['All (*.*)|*.*']
48       
[daa56d0]49        ## Creation time, for testing
50        self._created = time.time()
51       
[bbc8013]52        # Register default readers
[07f8d9a]53        readers.read_associations(self)
54       
[f60a8c2]55        #TODO: remove the following line when ready to switch to
[a7a5886]56        #the new default readers
[07f8d9a]57        #readers.register_readers(self._identify_plugin)
58       
59        # Look for plug-in readers
[371cb85]60        #self.find_plugins('plugins')
[07f8d9a]61
[88e289c]62    def load(self, path, format=None):
63        """
[0997158f]64        Call the loader for the file type of path.
65
66        :param path: file path
[f60a8c2]67        :param format: explicit extension, to force the use
[a7a5886]68            of a particular reader
[0997158f]69
70        Defaults to the ascii (multi-column) reader
71        if no reader was registered for the file's
[f60a8c2]72        extension.
[88e289c]73        """
74        try:
75            return super(Registry, self).load(path, format=format)
76        except:
[f118fe2f]77            try:
78                # No reader was found. Default to the ascii reader.
79                ascii_loader = ascii_reader.Reader()
80                return ascii_loader.read(path)
81            except:
82                cansas_loader = cansas_reader.Reader()
83                return cansas_loader.read(path)
[a7a5886]84           
[daa56d0]85    def find_plugins(self, dir):
86        """
[0997158f]87        Find readers in a given directory. This method
88        can be used to inspect user plug-in directories to
89        find new readers/writers.
90       
91        :param dir: directory to search into
92       
93        :return: number of readers found
[daa56d0]94        """
95        readers_found = 0
[ed61f2a1]96        temp_path = os.path.abspath(dir)
97        if not os.path.isdir(temp_path):
98            temp_path = os.path.join(os.getcwd(), dir)
99        if not os.path.isdir(temp_path):
100            temp_path = os.path.join(os.path.dirname(__file__), dir)
101        if not os.path.isdir(temp_path):
[4e367f6]102            temp_path = os.path.join(os.path.dirname(sys.path[0]), dir)
[bbc8013]103       
[ed61f2a1]104        dir = temp_path
[bbc8013]105        # Check whether the directory exists
[f60a8c2]106        if not os.path.isdir(dir):
[ed61f2a1]107            msg = "DataLoader couldn't locate DataLoader plugin folder."
108            msg += """ "%s" does not exist""" % dir
109            logging.warning(msg)
[bbc8013]110            return readers_found
111       
[daa56d0]112        for item in os.listdir(dir):
113            full_path = os.path.join(dir, item)
[84545dd]114            if os.path.isfile(full_path):
115               
116                # Process python files
117                if item.endswith('.py'):
118                    toks = os.path.splitext(os.path.basename(item))
119                    try:
120                        sys.path.insert(0, os.path.abspath(dir))
121                        module = __import__(toks[0], globals(), locals())
122                        if self._identify_plugin(module):
[daa56d0]123                            readers_found += 1
[a7a5886]124                    except:
125                        msg = "Loader: Error importing "
126                        msg += "%s\n  %s" % (item, sys.exc_value)
127                        logging.error(msg)
[daa56d0]128                           
[84545dd]129                # Process zip files
130                elif item.endswith('.zip'):
131                    try:
132                        # Find the modules in the zip file
133                        zfile = ZipFile(item)
134                        nlist = zfile.namelist()
135                       
136                        sys.path.insert(0, item)
137                        for mfile in nlist:
138                            try:
139                                # Change OS path to python path
140                                fullname = mfile.replace('/', '.')
141                                fullname = os.path.splitext(fullname)[0]
[a7a5886]142                                module = __import__(fullname, globals(),
143                                                     locals(), [""])
[84545dd]144                                if self._identify_plugin(module):
145                                    readers_found += 1
146                            except:
[a7a5886]147                                msg = "Loader: Error importing"
148                                msg += " %s\n  %s" % (mfile, sys.exc_value)
149                                logging.error(msg)
[84545dd]150                           
151                    except:
[a7a5886]152                        msg = "Loader: Error importing "
153                        msg += " %s\n  %s" % (item, sys.exc_value)
154                        logging.error(msg)
[84545dd]155                     
[f60a8c2]156        return readers_found
[84545dd]157   
[07f8d9a]158    def associate_file_type(self, ext, module):
159        """
[f60a8c2]160        Look into a module to find whether it contains a
[0997158f]161        Reader class. If so, APPEND it to readers and (potentially)
162        to the list of writers for the given extension
163       
164        :param ext: file extension [string]
165        :param module: module object
[07f8d9a]166        """
167        reader_found = False
168       
169        if hasattr(module, "Reader"):
170            try:
171                # Find supported extensions
172                loader = module.Reader()
173                if ext not in self.loaders:
174                    self.loaders[ext] = []
175                # Append the new reader to the list
176                self.loaders[ext].append(loader.read)
177
178                reader_found = True
179               
180                # Keep track of wildcards
181                type_name = module.__name__
182                if hasattr(loader, 'type_name'):
183                    type_name = loader.type_name
184                   
[a7a5886]185                wcard = "%s files (*%s)|*%s" % (type_name, ext.lower(),
186                                                 ext.lower())
[07f8d9a]187                if wcard not in self.wildcards:
188                    self.wildcards.append(wcard)
189                           
190                # Check whether writing is supported
191                if hasattr(loader, 'write'):
192                    if ext not in self.writers:
193                        self.writers[ext] = []
194                    # Append the new writer to the list
195                    self.writers[ext].append(loader.write)
196                       
197            except:
[a7a5886]198                msg = "Loader: Error accessing"
199                msg += " Reader in %s\n  %s" % (module.__name__, sys.exc_value)
200                logging.error(msg)
[07f8d9a]201        return reader_found
202
[fd4b6f8]203    def associate_file_reader(self, ext, loader):
204        """
[0997158f]205        Append a reader object to readers
206       
207        :param ext: file extension [string]
208        :param module: reader object
[fd4b6f8]209        """
210        reader_found = False
211       
212        try:
213            # Find supported extensions
214            if ext not in self.loaders:
215                self.loaders[ext] = []
216            # Append the new reader to the list
217            self.loaders[ext].append(loader.read)
218
219            reader_found = True
220           
221            # Keep track of wildcards
222            if hasattr(loader, 'type_name'):
223                type_name = loader.type_name
224               
[f60a8c2]225                wcard = "%s files (*%s)|*%s" % (type_name, ext.lower(),
[a7a5886]226                                                ext.lower())
[fd4b6f8]227                if wcard not in self.wildcards:
228                    self.wildcards.append(wcard)
229                 
230        except:
[a7a5886]231            msg = "Loader: Error accessing Reader "
[3fc01c5]232            msg += "in %s\n  %s" % (loader.__name__, sys.exc_value)
[a7a5886]233            logging.error(msg)
[fd4b6f8]234        return reader_found
235
[84545dd]236    def _identify_plugin(self, module):
237        """
[0997158f]238        Look into a module to find whether it contains a
239        Reader class. If so, add it to readers and (potentially)
240        to the list of writers.
241        :param module: module object
242       
[84545dd]243        """
244        reader_found = False
245       
246        if hasattr(module, "Reader"):
247            try:
248                # Find supported extensions
249                loader = module.Reader()
250                for ext in loader.ext:
251                    if ext not in self.loaders:
252                        self.loaders[ext] = []
[a7a5886]253                    # When finding a reader at run time,
254                    # treat this reader as the new default
255                    self.loaders[ext].insert(0, loader.read)
[954c045]256
[84545dd]257                    reader_found = True
[954c045]258                   
[1ed9c57]259                    # Keep track of wildcards
[07f8d9a]260                    type_name = module.__name__
261                    if hasattr(loader, 'type_name'):
262                        type_name = loader.type_name
[a7a5886]263                    wcard = "%s files (*%s)|*%s" % (type_name, ext.lower(),
264                                                     ext.lower())
[07f8d9a]265                    if wcard not in self.wildcards:
[f60a8c2]266                        self.wildcards.append(wcard)
[1ed9c57]267                           
[84545dd]268                # Check whether writing is supported
269                if hasattr(loader, 'write'):
270                    for ext in loader.ext:
271                        if ext not in self.writers:
272                            self.writers[ext] = []
[f60a8c2]273                        self.writers[ext].insert(0, loader.write)
[954c045]274                       
[84545dd]275            except:
[a7a5886]276                msg = "Loader: Error accessing Reader"
277                msg += " in %s\n  %s" % (module.__name__, sys.exc_value)
278                logging.error(msg)
[84545dd]279        return reader_found
[d22da51]280
[daa56d0]281    def lookup_writers(self, path):
282        """
[0997158f]283        :return: the loader associated with the file type of path.
[daa56d0]284       
[0997158f]285        :Raises ValueError: if file type is not known.
[f60a8c2]286        """
[daa56d0]287        # Find matching extensions
288        extlist = [ext for ext in self.extensions() if path.endswith(ext)]
289        # Sort matching extensions by decreasing order of length
[a7a5886]290        extlist.sort(lambda a, b: len(a) < len(b))
[daa56d0]291        # Combine loaders for matching extensions into one big list
292        writers = []
293        for L in [self.writers[ext] for ext in extlist]:
294            writers.extend(L)
295        # Remove duplicates if they exist
296        if len(writers) != len(set(writers)):
297            result = []
298            for L in writers:
[f60a8c2]299                if L not in result:
300                    result.append(L)
[daa56d0]301            writers = L
302        # Raise an error if there are no matching extensions
303        if len(writers) == 0:
[a7a5886]304            raise ValueError, "Unknown file type for " + path
[daa56d0]305        # All done
306        return writers
307
308    def save(self, path, data, format=None):
309        """
310        Call the writer for the file type of path.
[d22da51]311
[daa56d0]312        Raises ValueError if no writer is available.
313        Raises KeyError if format is not available.
[0997158f]314       
[f60a8c2]315        May raise a writer-defined exception if writer fails.
[daa56d0]316        """
317        if format is None:
318            writers = self.lookup_writers(path)
319        else:
320            writers = self.writers[format]
321        for fn in writers:
322            try:
323                return fn(path, data)
324            except:
[f60a8c2]325                pass  # give other loaders a chance to succeed
[daa56d0]326        # If we get here it is because all loaders failed
[f60a8c2]327        raise  # reraises last exception
[daa56d0]328
329       
[1b0b3ca]330class Loader(object):
[d22da51]331    """
[0997158f]332    Utility class to use the Registry as a singleton.
[d22da51]333    """
[daa56d0]334    ## Registry instance
335    __registry = Registry()
336   
[07f8d9a]337    def associate_file_type(self, ext, module):
338        """
[f60a8c2]339        Look into a module to find whether it contains a
[0997158f]340        Reader class. If so, append it to readers and (potentially)
341        to the list of writers for the given extension
342       
343        :param ext: file extension [string]
344        :param module: module object
[07f8d9a]345        """
346        return self.__registry.associate_file_type(ext, module)
347
[fd4b6f8]348    def associate_file_reader(self, ext, loader):
349        """
[0997158f]350        Append a reader object to readers
351       
352        :param ext: file extension [string]
353        :param module: reader object
[fd4b6f8]354        """
355        return self.__registry.associate_file_reader(ext, loader)
356
[daa56d0]357    def load(self, file, format=None):
358        """
[0997158f]359        Load a file
360       
361        :param file: file name (path)
362        :param format: specified format to use (optional)
363        :return: DataInfo object
[daa56d0]364        """
365        return self.__registry.load(file, format)
[d22da51]366   
[daa56d0]367    def save(self, file, data, format):
368        """
[0997158f]369        Save a DataInfo object to file
370        :param file: file name (path)
371        :param data: DataInfo object
372        :param format: format to write the data in
[daa56d0]373        """
374        return self.__registry.save(file, data, format)
375       
376    def _get_registry_creation_time(self):
377        """
[0997158f]378        Internal method used to test the uniqueness
379        of the registry object
[daa56d0]380        """
381        return self.__registry._created
[d22da51]382   
[daa56d0]383    def find_plugins(self, dir):
384        """
[0997158f]385        Find plugins in a given directory
386       
387        :param dir: directory to look into to find new readers/writers
[daa56d0]388        """
389        return self.__registry.find_plugins(dir)
[a916ccc]390   
[1ed9c57]391    def get_wildcards(self):
392        return self.__registry.wildcards
Note: See TracBrowser for help on using the repository browser.