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

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

Remove unused imports and minor code cleanup.

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