source: sasview/DataLoader/loader.py @ 3ba03a4c

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 3ba03a4c was 88e289c, checked in by Mathieu Doucet <doucetm@…>, 16 years ago

Modified the file extension associations for release 1.0. Modified the loader to default to the n-col ascii reader when no reader is found.

  • Property mode set to 100644
File size: 12.2 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
180   
[84545dd]181    def _identify_plugin(self, module):
182        """
183            Look into a module to find whether it contains a
184            Reader class. If so, add it to readers and (potentially)
185            to the list of writers.
186            @param module: module object
187        """
188        reader_found = False
189       
190        if hasattr(module, "Reader"):
191            try:
192                # Find supported extensions
193                loader = module.Reader()
194                for ext in loader.ext:
195                    if ext not in self.loaders:
196                        self.loaders[ext] = []
[07f8d9a]197                    # When finding a reader at run time, treat this reader as the new
198                    # default
199                    self.loaders[ext].insert(0,loader.read)
[954c045]200
[84545dd]201                    reader_found = True
[954c045]202                   
[1ed9c57]203                    # Keep track of wildcards
[07f8d9a]204                    type_name = module.__name__
205                    if hasattr(loader, 'type_name'):
206                        type_name = loader.type_name
207                    wcard = "%s files (*%s)|*%s" % (type_name, ext.lower(), ext.lower())
208                    if wcard not in self.wildcards:
209                        self.wildcards.append(wcard)
[1ed9c57]210                           
[84545dd]211                # Check whether writing is supported
212                if hasattr(loader, 'write'):
213                    for ext in loader.ext:
214                        if ext not in self.writers:
215                            self.writers[ext] = []
216                        self.writers[ext].insert(0,loader.write)
[954c045]217                       
[84545dd]218            except:
[07f8d9a]219                logging.error("Loader: Error accessing Reader in %s\n  %s" % (module.__name__, sys.exc_value))
[84545dd]220        return reader_found
[d22da51]221
[daa56d0]222    def lookup_writers(self, path):
223        """
224        Return the loader associated with the file type of path.
225       
226        Raises ValueError if file type is not known.
227        """       
228        # Find matching extensions
229        extlist = [ext for ext in self.extensions() if path.endswith(ext)]
230        # Sort matching extensions by decreasing order of length
231        extlist.sort(lambda a,b: len(a)<len(b))
232        # Combine loaders for matching extensions into one big list
233        writers = []
234        for L in [self.writers[ext] for ext in extlist]:
235            writers.extend(L)
236        # Remove duplicates if they exist
237        if len(writers) != len(set(writers)):
238            result = []
239            for L in writers:
240                if L not in result: result.append(L)
241            writers = L
242        # Raise an error if there are no matching extensions
243        if len(writers) == 0:
244            raise ValueError, "Unknown file type for "+path
245        # All done
246        return writers
247
248    def save(self, path, data, format=None):
249        """
250        Call the writer for the file type of path.
[d22da51]251
[daa56d0]252        Raises ValueError if no writer is available.
253        Raises KeyError if format is not available.
254        May raise a writer-defined exception if writer fails.       
255        """
256        if format is None:
257            writers = self.lookup_writers(path)
258        else:
259            writers = self.writers[format]
260        for fn in writers:
261            try:
262                return fn(path, data)
263            except:
264                pass # give other loaders a chance to succeed
265        # If we get here it is because all loaders failed
266        raise # reraises last exception
267
268       
[1b0b3ca]269class Loader(object):
[d22da51]270    """
[daa56d0]271        Utility class to use the Registry as a singleton.
[d22da51]272    """
[daa56d0]273    ## Registry instance
274    __registry = Registry()
275   
[07f8d9a]276    def associate_file_type(self, ext, module):
277        """
278            Look into a module to find whether it contains a
279            Reader class. If so, append it to readers and (potentially)
280            to the list of writers for the given extension
281           
282            @param ext: file extension [string]
283            @param module: module object
284        """
285        return self.__registry.associate_file_type(ext, module)
286
[daa56d0]287    def load(self, file, format=None):
288        """
289            Load a file
290           
291            @param file: file name (path)
292            @param format: specified format to use (optional)
293            @return: DataInfo object
294        """
295        return self.__registry.load(file, format)
[d22da51]296   
[daa56d0]297    def save(self, file, data, format):
298        """
299            Save a DataInfo object to file
300            @param file: file name (path)
301            @param data: DataInfo object
302            @param format: format to write the data in
303        """
304        return self.__registry.save(file, data, format)
305       
306    def _get_registry_creation_time(self):
307        """
308            Internal method used to test the uniqueness
309            of the registry object
310        """
311        return self.__registry._created
[d22da51]312   
[daa56d0]313    def find_plugins(self, dir):
314        """
315            Find plugins in a given directory
316            @param dir: directory to look into to find new readers/writers
317        """
318        return self.__registry.find_plugins(dir)
[a916ccc]319   
[1ed9c57]320    def get_wildcards(self):
321        return self.__registry.wildcards
[a916ccc]322       
[daa56d0]323if __name__ == "__main__": 
324    logging.basicConfig(level=logging.INFO,
325                        format='%(asctime)s %(levelname)s %(message)s',
326                        filename='loader.log',
327                        filemode='w')
328    l = Loader()
329    data = l.load('test/cansas1d.xml')
[1ed9c57]330    l.save('test_file.xml', data, '.xml')
331   
332    print l.get_wildcards()
[a916ccc]333       
334       
[daa56d0]335   
Note: See TracBrowser for help on using the repository browser.