source: sasview/DataLoader/loader.py @ 6d7bfe76

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 6d7bfe76 was fd4b6f8, checked in by Mathieu Doucet <doucetm@…>, 16 years ago

dataloader: add a method to associate a reader object to an extension type (as opposed to letting the Loader inspect a module).

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