source: sasview/DataLoader/loader.py @ 9d091ed

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 9d091ed was 07f8d9a, checked in by Mathieu Doucet <doucetm@…>, 15 years ago

Improved hierarchical reader structure, put back reader plugin, minor fixes.

  • Property mode set to 100644
File size: 11.5 KB
Line 
1"""
2    File handler to support different file extensions.
3    Uses reflectometry's registry utility.
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.
14"""
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
29import logging
30import time
31from zipfile import ZipFile
32
33# Default readers are defined in the readers sub-module
34import readers
35
36class Registry(ExtensionRegistry):
37    """
38        Registry class for file format extensions.
39        Readers and writers are supported.
40    """
41   
42    def __init__(self):
43        super(Registry, self).__init__()
44       
45        ## Writers
46        self.writers = {}
47       
48        ## List of wildcards
49        self.wildcards = ['All (*.*)|*.*']
50       
51        ## Creation time, for testing
52        self._created = time.time()
53       
54        # Register default readers
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
63       
64    def find_plugins(self, dir):
65        """
66            Find readers in a given directory. This method
67            can be used to inspect user plug-in directories to
68            find new readers/writers.
69           
70            @param dir: directory to search into
71            @return: number of readers found
72        """
73        readers_found = 0
74       
75        # Check whether the directory exists
76        if not os.path.isdir(dir): 
77            logging.warning("DataLoader couldn't load from %s" % dir)
78            return readers_found
79       
80        for item in os.listdir(dir):
81            full_path = os.path.join(dir, item)
82            if os.path.isfile(full_path):
83               
84                # Process python files
85                if item.endswith('.py'):
86                    toks = os.path.splitext(os.path.basename(item))
87                    try:
88                        sys.path.insert(0, os.path.abspath(dir))
89                        module = __import__(toks[0], globals(), locals())
90                        if self._identify_plugin(module):
91                            readers_found += 1
92                    except :
93                        logging.error("Loader: Error importing %s\n  %s" % (item, sys.exc_value))
94                           
95                # Process zip files
96                elif item.endswith('.zip'):
97                    try:
98                        # Find the modules in the zip file
99                        zfile = ZipFile(item)
100                        nlist = zfile.namelist()
101                       
102                        sys.path.insert(0, item)
103                        for mfile in nlist:
104                            try:
105                                # Change OS path to python path
106                                fullname = mfile.replace('/', '.')
107                                fullname = os.path.splitext(fullname)[0]
108                                module = __import__(fullname, globals(), locals(), [""])
109                                if self._identify_plugin(module):
110                                    readers_found += 1
111                            except:
112                                logging.error("Loader: Error importing %s\n  %s" % (mfile, sys.exc_value))
113                           
114                    except:
115                        logging.error("Loader: Error importing %s\n  %s" % (item, sys.exc_value))
116                     
117        return readers_found
118   
119    def associate_file_type(self, ext, module):
120        """
121            Look into a module to find whether it contains a
122            Reader class. If so, APPEND it to readers and (potentially)
123            to the list of writers for the given extension
124           
125            @param ext: file extension [string]
126            @param module: module object
127        """
128        reader_found = False
129       
130        if hasattr(module, "Reader"):
131            try:
132                # Find supported extensions
133                loader = module.Reader()
134                if ext not in self.loaders:
135                    self.loaders[ext] = []
136                # Append the new reader to the list
137                self.loaders[ext].append(loader.read)
138
139                reader_found = True
140               
141                # Keep track of wildcards
142                type_name = module.__name__
143                if hasattr(loader, 'type_name'):
144                    type_name = loader.type_name
145                   
146                wcard = "%s files (*%s)|*%s" % (type_name, ext.lower(), ext.lower())
147                if wcard not in self.wildcards:
148                    self.wildcards.append(wcard)
149                           
150                # Check whether writing is supported
151                if hasattr(loader, 'write'):
152                    if ext not in self.writers:
153                        self.writers[ext] = []
154                    # Append the new writer to the list
155                    self.writers[ext].append(loader.write)
156                       
157            except:
158                logging.error("Loader: Error accessing Reader in %s\n  %s" % (module.__name__, sys.exc_value))
159        return reader_found
160
161   
162    def _identify_plugin(self, module):
163        """
164            Look into a module to find whether it contains a
165            Reader class. If so, add it to readers and (potentially)
166            to the list of writers.
167            @param module: module object
168        """
169        reader_found = False
170       
171        if hasattr(module, "Reader"):
172            try:
173                # Find supported extensions
174                loader = module.Reader()
175                for ext in loader.ext:
176                    if ext not in self.loaders:
177                        self.loaders[ext] = []
178                    # When finding a reader at run time, treat this reader as the new
179                    # default
180                    self.loaders[ext].insert(0,loader.read)
181
182                    reader_found = True
183                   
184                    # Keep track of wildcards
185                    type_name = module.__name__
186                    if hasattr(loader, 'type_name'):
187                        type_name = loader.type_name
188                    wcard = "%s files (*%s)|*%s" % (type_name, ext.lower(), ext.lower())
189                    if wcard not in self.wildcards:
190                        self.wildcards.append(wcard)
191                           
192                # Check whether writing is supported
193                if hasattr(loader, 'write'):
194                    for ext in loader.ext:
195                        if ext not in self.writers:
196                            self.writers[ext] = []
197                        self.writers[ext].insert(0,loader.write)
198                       
199            except:
200                logging.error("Loader: Error accessing Reader in %s\n  %s" % (module.__name__, sys.exc_value))
201        return reader_found
202
203    def lookup_writers(self, path):
204        """
205        Return the loader associated with the file type of path.
206       
207        Raises ValueError if file type is not known.
208        """       
209        # Find matching extensions
210        extlist = [ext for ext in self.extensions() if path.endswith(ext)]
211        # Sort matching extensions by decreasing order of length
212        extlist.sort(lambda a,b: len(a)<len(b))
213        # Combine loaders for matching extensions into one big list
214        writers = []
215        for L in [self.writers[ext] for ext in extlist]:
216            writers.extend(L)
217        # Remove duplicates if they exist
218        if len(writers) != len(set(writers)):
219            result = []
220            for L in writers:
221                if L not in result: result.append(L)
222            writers = L
223        # Raise an error if there are no matching extensions
224        if len(writers) == 0:
225            raise ValueError, "Unknown file type for "+path
226        # All done
227        return writers
228
229    def save(self, path, data, format=None):
230        """
231        Call the writer for the file type of path.
232
233        Raises ValueError if no writer is available.
234        Raises KeyError if format is not available.
235        May raise a writer-defined exception if writer fails.       
236        """
237        if format is None:
238            writers = self.lookup_writers(path)
239        else:
240            writers = self.writers[format]
241        for fn in writers:
242            try:
243                return fn(path, data)
244            except:
245                pass # give other loaders a chance to succeed
246        # If we get here it is because all loaders failed
247        raise # reraises last exception
248
249       
250class Loader(object):
251    """
252        Utility class to use the Registry as a singleton.
253    """
254    ## Registry instance
255    __registry = Registry()
256   
257    def associate_file_type(self, ext, module):
258        """
259            Look into a module to find whether it contains a
260            Reader class. If so, append it to readers and (potentially)
261            to the list of writers for the given extension
262           
263            @param ext: file extension [string]
264            @param module: module object
265        """
266        return self.__registry.associate_file_type(ext, module)
267
268    def load(self, file, format=None):
269        """
270            Load a file
271           
272            @param file: file name (path)
273            @param format: specified format to use (optional)
274            @return: DataInfo object
275        """
276        return self.__registry.load(file, format)
277   
278    def save(self, file, data, format):
279        """
280            Save a DataInfo object to file
281            @param file: file name (path)
282            @param data: DataInfo object
283            @param format: format to write the data in
284        """
285        return self.__registry.save(file, data, format)
286       
287    def _get_registry_creation_time(self):
288        """
289            Internal method used to test the uniqueness
290            of the registry object
291        """
292        return self.__registry._created
293   
294    def find_plugins(self, dir):
295        """
296            Find plugins in a given directory
297            @param dir: directory to look into to find new readers/writers
298        """
299        return self.__registry.find_plugins(dir)
300   
301    def get_wildcards(self):
302        return self.__registry.wildcards
303       
304if __name__ == "__main__": 
305    logging.basicConfig(level=logging.INFO,
306                        format='%(asctime)s %(levelname)s %(message)s',
307                        filename='loader.log',
308                        filemode='w')
309    l = Loader()
310    data = l.load('test/cansas1d.xml')
311    l.save('test_file.xml', data, '.xml')
312   
313    print l.get_wildcards()
314       
315       
316   
Note: See TracBrowser for help on using the repository browser.