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

Last change on this file since afb311e was a26f67f, checked in by Paul Kienzle <pkienzle@…>, 7 years ago

fixup api doc errors

  • 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
[dc8d1c2]103        extlist.sort(key=len)
[4bae1ef]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
[a26f67f]123        :raises ValueError: if no loader is available.
124        :raises KeyError: if format is not available.
125
[7f75a3f]126        May raise a loader-defined exception if loader fails.
[4bae1ef]127        """
[7f75a3f]128        loaders = []
[4bae1ef]129        if format is None:
[270c882b]130            try:
131                loaders = self.lookup(path)
132            except ValueError as e:
133                pass
[4bae1ef]134        else:
[270c882b]135            try:
136                loaders = self.loaders[format]
137            except KeyError as e:
138                pass
[3ece5dd]139        last_exc = None
[4bae1ef]140        for fn in loaders:
141            try:
142                return fn(path)
[270c882b]143            except Exception as e:
[3ece5dd]144                last_exc = e
[270c882b]145                pass  # give other loaders a chance to succeed
[4bae1ef]146        # If we get here it is because all loaders failed
[3ece5dd]147        if last_exc is not None and len(loaders) != 0:
148            # If file has associated loader(s) and they;ve failed
149            raise last_exc
[270c882b]150        raise NoKnownLoaderException(e.message)  # raise generic exception
Note: See TracBrowser for help on using the repository browser.