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

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 62b9793 was 62b9793, checked in by krzywon, 7 years ago

Direct error message when a data file cannot be loaded by any reader.

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