source: sasview/DataLoader/loader.py @ 0b12abb5

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 0b12abb5 was 0997158f, checked in by Gervaise Alina <gervyh@…>, 15 years ago

working on documentation

  • Property mode set to 100644
File size: 13.5 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
25from data_util.registry import ExtensionRegistry
26import os 
27import sys
[a916ccc]28import logging
[daa56d0]29import time
[84545dd]30from zipfile import ZipFile
[d22da51]31
[bbc8013]32# Default readers are defined in the readers sub-module
33import readers
[88e289c]34from readers import ascii_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       
57        #TODO: remove the following line when ready to switch to the new default readers
58        #readers.register_readers(self._identify_plugin)
59       
60        # Look for plug-in readers
61        self.find_plugins('plugins')
62
[daa56d0]63       
[88e289c]64    def load(self, path, format=None):
65        """
[0997158f]66        Call the loader for the file type of path.
67
68        :param path: file path
69        :param format: explicit extension, to force the use of a particular reader
70
71        Defaults to the ascii (multi-column) reader
72        if no reader was registered for the file's
73        extension.   
[88e289c]74        """
75        try:
76            return super(Registry, self).load(path, format=format)
77        except:
78            # No reader was found. Default to the ascii reader.
79            ascii_loader = ascii_reader.Reader()
80            return ascii_loader.read(path)
81       
[daa56d0]82    def find_plugins(self, dir):
83        """
[0997158f]84        Find readers in a given directory. This method
85        can be used to inspect user plug-in directories to
86        find new readers/writers.
87       
88        :param dir: directory to search into
89       
90        :return: number of readers found
[daa56d0]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        """
[0997158f]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
[07f8d9a]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        """
[0997158f]182        Append a reader object to readers
183       
184        :param ext: file extension [string]
185        :param module: reader object
[fd4b6f8]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        """
[0997158f]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       
[84545dd]218        """
219        reader_found = False
220       
221        if hasattr(module, "Reader"):
222            try:
223                # Find supported extensions
224                loader = module.Reader()
225                for ext in loader.ext:
226                    if ext not in self.loaders:
227                        self.loaders[ext] = []
[07f8d9a]228                    # When finding a reader at run time, treat this reader as the new
229                    # default
230                    self.loaders[ext].insert(0,loader.read)
[954c045]231
[84545dd]232                    reader_found = True
[954c045]233                   
[1ed9c57]234                    # Keep track of wildcards
[07f8d9a]235                    type_name = module.__name__
236                    if hasattr(loader, 'type_name'):
237                        type_name = loader.type_name
238                    wcard = "%s files (*%s)|*%s" % (type_name, ext.lower(), ext.lower())
239                    if wcard not in self.wildcards:
240                        self.wildcards.append(wcard)
[1ed9c57]241                           
[84545dd]242                # Check whether writing is supported
243                if hasattr(loader, 'write'):
244                    for ext in loader.ext:
245                        if ext not in self.writers:
246                            self.writers[ext] = []
247                        self.writers[ext].insert(0,loader.write)
[954c045]248                       
[84545dd]249            except:
[07f8d9a]250                logging.error("Loader: Error accessing Reader in %s\n  %s" % (module.__name__, sys.exc_value))
[84545dd]251        return reader_found
[d22da51]252
[daa56d0]253    def lookup_writers(self, path):
254        """
[0997158f]255        :return: the loader associated with the file type of path.
[daa56d0]256       
[0997158f]257        :Raises ValueError: if file type is not known.
[daa56d0]258        """       
259        # Find matching extensions
260        extlist = [ext for ext in self.extensions() if path.endswith(ext)]
261        # Sort matching extensions by decreasing order of length
262        extlist.sort(lambda a,b: len(a)<len(b))
263        # Combine loaders for matching extensions into one big list
264        writers = []
265        for L in [self.writers[ext] for ext in extlist]:
266            writers.extend(L)
267        # Remove duplicates if they exist
268        if len(writers) != len(set(writers)):
269            result = []
270            for L in writers:
271                if L not in result: result.append(L)
272            writers = L
273        # Raise an error if there are no matching extensions
274        if len(writers) == 0:
275            raise ValueError, "Unknown file type for "+path
276        # All done
277        return writers
278
279    def save(self, path, data, format=None):
280        """
281        Call the writer for the file type of path.
[d22da51]282
[daa56d0]283        Raises ValueError if no writer is available.
284        Raises KeyError if format is not available.
[0997158f]285       
[daa56d0]286        May raise a writer-defined exception if writer fails.       
287        """
288        if format is None:
289            writers = self.lookup_writers(path)
290        else:
291            writers = self.writers[format]
292        for fn in writers:
293            try:
294                return fn(path, data)
295            except:
296                pass # give other loaders a chance to succeed
297        # If we get here it is because all loaders failed
298        raise # reraises last exception
299
300       
[1b0b3ca]301class Loader(object):
[d22da51]302    """
[0997158f]303    Utility class to use the Registry as a singleton.
[d22da51]304    """
[daa56d0]305    ## Registry instance
306    __registry = Registry()
307   
[07f8d9a]308    def associate_file_type(self, ext, module):
309        """
[0997158f]310        Look into a module to find whether it contains a
311        Reader class. If so, append it to readers and (potentially)
312        to the list of writers for the given extension
313       
314        :param ext: file extension [string]
315        :param module: module object
[07f8d9a]316        """
317        return self.__registry.associate_file_type(ext, module)
318
[fd4b6f8]319    def associate_file_reader(self, ext, loader):
320        """
[0997158f]321        Append a reader object to readers
322       
323        :param ext: file extension [string]
324        :param module: reader object
[fd4b6f8]325        """
326        return self.__registry.associate_file_reader(ext, loader)
327
[daa56d0]328    def load(self, file, format=None):
329        """
[0997158f]330        Load a file
331       
332        :param file: file name (path)
333        :param format: specified format to use (optional)
334        :return: DataInfo object
[daa56d0]335        """
336        return self.__registry.load(file, format)
[d22da51]337   
[daa56d0]338    def save(self, file, data, format):
339        """
[0997158f]340        Save a DataInfo object to file
341        :param file: file name (path)
342        :param data: DataInfo object
343        :param format: format to write the data in
[daa56d0]344        """
345        return self.__registry.save(file, data, format)
346       
347    def _get_registry_creation_time(self):
348        """
[0997158f]349        Internal method used to test the uniqueness
350        of the registry object
[daa56d0]351        """
352        return self.__registry._created
[d22da51]353   
[daa56d0]354    def find_plugins(self, dir):
355        """
[0997158f]356        Find plugins in a given directory
357       
358        :param dir: directory to look into to find new readers/writers
[daa56d0]359        """
360        return self.__registry.find_plugins(dir)
[a916ccc]361   
[1ed9c57]362    def get_wildcards(self):
363        return self.__registry.wildcards
[a916ccc]364       
[daa56d0]365if __name__ == "__main__": 
366    logging.basicConfig(level=logging.INFO,
367                        format='%(asctime)s %(levelname)s %(message)s',
368                        filename='loader.log',
369                        filemode='w')
370    l = Loader()
371    data = l.load('test/cansas1d.xml')
[1ed9c57]372    l.save('test_file.xml', data, '.xml')
373   
374    print l.get_wildcards()
[a916ccc]375       
376       
[daa56d0]377   
Note: See TracBrowser for help on using the repository browser.