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
Line 
1"""
2File extension registry.
3
4This provides routines for opening files based on extension,
5and registers the built-in file extensions.
6"""
7from __future__ import print_function
8
9from sas.sascalc.dataloader.loader_exceptions import NoKnownLoaderException
10
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
18    Example: ::
19
20        registry = ExtensionRegistry()
21
22        # Add an association by setting an element
23        registry['.zip'] = unzip
24
25        # Multiple extensions for one loader
26        registry['.tgz'] = untar
27        registry['.tar.gz'] = untar
28
29        # Generic extensions to use after trying more specific extensions;
30        # these will be checked after the more specific extensions fail.
31        registry['.gz'] = gunzip
32
33        # Multiple loaders for one extension
34        registry['.cx'] = cx1
35        registry['.cx'] = cx2
36        registry['.cx'] = cx3
37
38        # Show registered extensions
39        print registry.extensions()
40
41        # Can also register a format name for explicit control from caller
42        registry['cx3'] = cx3
43        print registry.formats()
44
45        # Retrieve loaders for a file name
46        registry.lookup('hello.cx') -> [cx3,cx2,cx1]
47
48        # Run loader on a filename
49        registry.load('hello.cx') ->
50            try:
51                return cx3('hello.cx')
52            except:
53                try:
54                    return cx2('hello.cx')
55                except:
56                    return cx1('hello.cx')
57
58        # Load in a specific format ignoring extension
59        registry.load('hello.cx',format='cx3') ->
60            return cx3('hello.cx')
61    """
62    def __init__(self, **kw):
63        self.loaders = {}
64
65    def __setitem__(self, ext, loader):
66        if ext not in self.loaders:
67            self.loaders[ext] = []
68        self.loaders[ext].insert(0,loader)
69
70    def __getitem__(self, ext):
71        return self.loaders[ext]
72
73    def __contains__(self, ext):
74        return ext in self.loaders
75
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
83
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
91
92    def lookup(self, path):
93        """
94        Return the loader associated with the file type of path.
95
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
99        """
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(key=len)
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:
116            raise ValueError("Unknown file type for "+path)
117        return loaders
118
119    def load(self, path, format=None):
120        """
121        Call the loader for the file type of path.
122
123        :raises ValueError: if no loader is available.
124        :raises KeyError: if format is not available.
125
126        May raise a loader-defined exception if loader fails.
127        """
128        loaders = []
129        if format is None:
130            try:
131                loaders = self.lookup(path)
132            except ValueError as e:
133                pass
134        else:
135            try:
136                loaders = self.loaders[format]
137            except KeyError as e:
138                pass
139        last_exc = None
140        for fn in loaders:
141            try:
142                return fn(path)
143            except Exception as e:
144                last_exc = e
145                pass  # give other loaders a chance to succeed
146        # If we get here it is because all loaders failed
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
150        raise NoKnownLoaderException(e.message)  # raise generic exception
Note: See TracBrowser for help on using the repository browser.