source: sasview/src/sas/sascalc/data_util/registry.py @ be51cf6

ESS_GUIESS_GUI_DocsESS_GUI_batch_fittingESS_GUI_bumps_abstractionESS_GUI_iss1116ESS_GUI_iss879ESS_GUI_iss959ESS_GUI_openclESS_GUI_orderingESS_GUI_sync_sascalcmagnetic_scattrelease-4.2.2ticket-1009ticket-1094-headlessticket-1242-2d-resolutionticket-1243ticket-1249ticket885unittest-saveload
Last change on this file since be51cf6 was 5a8cdbb, checked in by lewis, 7 years ago

Merge branch 'master' into ticket-876

  • Property mode set to 100644
File size: 4.6 KB
RevLine 
[4bae1ef]1"""
2File extension registry.
3
4This provides routines for opening files based on extension,
5and registers the built-in file extensions.
6"""
[a1b8fee]7from __future__ import print_function
[4bae1ef]8
[270c882b]9from sas.sascalc.dataloader.loader_exceptions import NoKnownLoaderException
10
[4bae1ef]11
12class ExtensionRegistry(object):
13    """
14    Associate a file loader with an extension.
15
16    Note that there may be multiple loaders for the same extension.
17
[51f14603]18    Example: ::
[4bae1ef]19
[51f14603]20        registry = ExtensionRegistry()
[4bae1ef]21
[51f14603]22        # Add an association by setting an element
23        registry['.zip'] = unzip
[5d8f9b3]24
[51f14603]25        # Multiple extensions for one loader
26        registry['.tgz'] = untar
27        registry['.tar.gz'] = untar
[4bae1ef]28
[3ece5dd]29        # Generic extensions to use after trying more specific extensions;
[51f14603]30        # these will be checked after the more specific extensions fail.
31        registry['.gz'] = gunzip
[4bae1ef]32
[51f14603]33        # Multiple loaders for one extension
34        registry['.cx'] = cx1
35        registry['.cx'] = cx2
36        registry['.cx'] = cx3
[4bae1ef]37
[51f14603]38        # Show registered extensions
39        print registry.extensions()
[5d8f9b3]40
[51f14603]41        # Can also register a format name for explicit control from caller
42        registry['cx3'] = cx3
43        print registry.formats()
[4bae1ef]44
[51f14603]45        # Retrieve loaders for a file name
46        registry.lookup('hello.cx') -> [cx3,cx2,cx1]
[4bae1ef]47
[51f14603]48        # Run loader on a filename
49        registry.load('hello.cx') ->
[4bae1ef]50            try:
[51f14603]51                return cx3('hello.cx')
[4bae1ef]52            except:
[51f14603]53                try:
54                    return cx2('hello.cx')
55                except:
56                    return cx1('hello.cx')
[4bae1ef]57
[51f14603]58        # Load in a specific format ignoring extension
59        registry.load('hello.cx',format='cx3') ->
60            return cx3('hello.cx')
[4bae1ef]61    """
62    def __init__(self, **kw):
63        self.loaders = {}
[270c882b]64
[4bae1ef]65    def __setitem__(self, ext, loader):
66        if ext not in self.loaders:
67            self.loaders[ext] = []
68        self.loaders[ext].insert(0,loader)
[270c882b]69
[4bae1ef]70    def __getitem__(self, ext):
71        return self.loaders[ext]
[270c882b]72
[4bae1ef]73    def __contains__(self, ext):
74        return ext in self.loaders
[270c882b]75
[4bae1ef]76    def formats(self):
77        """
78        Return a sorted list of the registered formats.
79        """
80        names = [a for a in self.loaders.keys() if not a.startswith('.')]
81        names.sort()
82        return names
[270c882b]83
[4bae1ef]84    def extensions(self):
85        """
86        Return a sorted list of registered extensions.
87        """
88        exts = [a for a in self.loaders.keys() if a.startswith('.')]
89        exts.sort()
90        return exts
[270c882b]91
[4bae1ef]92    def lookup(self, path):
93        """
94        Return the loader associated with the file type of path.
[3ece5dd]95
[7f75a3f]96        :param path: Data file path
97        :raises ValueError: When no loaders are found for the file.
98        :return: List of available readers for the file extension
[3ece5dd]99        """
[4bae1ef]100        # Find matching extensions
101        extlist = [ext for ext in self.extensions() if path.endswith(ext)]
102        # Sort matching extensions by decreasing order of length
103        extlist.sort(lambda a,b: len(a)<len(b))
104        # Combine loaders for matching extensions into one big list
105        loaders = []
106        for L in [self.loaders[ext] for ext in extlist]:
107            loaders.extend(L)
108        # Remove duplicates if they exist
109        if len(loaders) != len(set(loaders)):
110            result = []
111            for L in loaders:
112                if L not in result: result.append(L)
113            loaders = L
114        # Raise an error if there are no matching extensions
115        if len(loaders) == 0:
[270c882b]116            raise ValueError("Unknown file type for "+path)
[4bae1ef]117        return loaders
[270c882b]118
[4bae1ef]119    def load(self, path, format=None):
120        """
121        Call the loader for the file type of path.
122
[7f75a3f]123        :raise ValueError: if no loader is available.
124        :raise KeyError: if format is not available.
125        May raise a loader-defined exception if loader fails.
[4bae1ef]126        """
[7f75a3f]127        loaders = []
[4bae1ef]128        if format is None:
[270c882b]129            try:
130                loaders = self.lookup(path)
131            except ValueError as e:
132                pass
[4bae1ef]133        else:
[270c882b]134            try:
135                loaders = self.loaders[format]
136            except KeyError as e:
137                pass
[3ece5dd]138        last_exc = None
[4bae1ef]139        for fn in loaders:
140            try:
141                return fn(path)
[270c882b]142            except Exception as e:
[3ece5dd]143                last_exc = e
[270c882b]144                pass  # give other loaders a chance to succeed
[4bae1ef]145        # If we get here it is because all loaders failed
[3ece5dd]146        if last_exc is not None and len(loaders) != 0:
147            # If file has associated loader(s) and they;ve failed
148            raise last_exc
[270c882b]149        raise NoKnownLoaderException(e.message)  # raise generic exception
Note: See TracBrowser for help on using the repository browser.