source: sasview/src/sas/sascalc/dataloader/loader.py @ b9b612a

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.2.2ticket-1009ticket-1094-headlessticket-1242-2d-resolutionticket-1243ticket-1249ticket885unittest-saveload
Last change on this file since b9b612a was b9b612a, checked in by krzywon, 7 years ago

Flatten nested try-except block.

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