source: sasview/DataLoader/loader.py @ cacbd7d

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 cacbd7d was a7a5886, checked in by Gervaise Alina <gervyh@…>, 14 years ago

working pylint

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