egl-create-largest-pbuffer-surface: Don't call eglSwapBuffers
[piglit.git] / framework / backends / __init__.py
blob488ad5515492af0269adacd21d8bddcb36437d16
1 # Copyright (c) 2014-2016 Intel Corporation
3 # Permission is hereby granted, free of charge, to any person obtaining a copy
4 # of this software and associated documentation files (the "Software"), to deal
5 # in the Software without restriction, including without limitation the rights
6 # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7 # copies of the Software, and to permit persons to whom the Software is
8 # furnished to do so, subject to the following conditions:
10 # The above copyright notice and this permission notice shall be included in
11 # all copies or substantial portions of the Software.
13 # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18 # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
19 # SOFTWARE.
21 """Provides a module like interface for backends.
23 This package provides an abstract interface for working with backends, which
24 implement various functions as provided in the Registry class, and then provide
25 a Registry instance as REGISTRY, which maps individual objects to objects that
26 piglit expects to use. This module then provides a thin abstraction layer so
27 that piglit is never aware of what backend it's using, it just asks for an
28 object and receives one.
30 Most consumers will want to import framework.backends and work directly with
31 the helper functions here. For some more detailed uses (test cases especially)
32 the modules themselves may be used.
34 When this module is loaded it will search through framework/backends for python
35 modules (those ending in .py), and attempt to import them. Then it will look
36 for an attribute REGISTRY in those modules, and if it as a
37 framework.register.Registry instance, it will add the name of that module (sans
38 .py) as a key, and the instance as a value to the BACKENDS dictionary. Each of
39 the helper functions in this module uses that dictionary to find the function
40 that a user actually wants.
42 """
44 from __future__ import (
45 absolute_import, division, print_function, unicode_literals
47 import os
48 import importlib
50 import six
52 from .register import Registry
53 from .compression import COMPRESSION_SUFFIXES
55 __all__ = [
56 'BACKENDS',
57 'BackendError',
58 'BackendNotImplementedError',
59 'get_backend',
60 'load',
61 'set_meta',
65 class BackendError(Exception):
66 pass
69 class BackendNotImplementedError(NotImplementedError):
70 pass
73 def _register():
74 """Register backends.
76 Walk through the list of backends and register them to a name in a
77 dictionary, so that they can be referenced from helper functions.
79 """
80 registry = {}
82 for module in os.listdir(os.path.dirname(os.path.abspath(__file__))):
83 module, extension = os.path.splitext(module)
84 if extension == '.py':
85 mod = importlib.import_module('framework.backends.{}'.format(module))
86 if hasattr(mod, 'REGISTRY') and isinstance(mod.REGISTRY, Registry):
87 registry[module] = mod.REGISTRY
89 return registry
92 BACKENDS = _register()
95 def get_backend(backend):
96 """Returns a BackendInstance based on the string passed.
98 If the backend isn't a known module, then a BackendError will be raised, it
99 is the responsibility of the caller to handle this error.
101 If the backend module exists, but there is not active implementation then a
102 BackendNotImplementedError will be raised, it is also the responsibility of
103 the caller to handle this error.
106 try:
107 inst = BACKENDS[backend].backend
108 except KeyError:
109 raise BackendError('Unknown backend: {}'.format(backend))
111 if inst is None:
112 raise BackendNotImplementedError(
113 'Backend for {} is not implemented'.format(backend))
115 return inst
118 def load(file_path):
119 """Wrapper for loading runs.
121 This function will attempt to determine how to load the file (based on file
122 extension), and then pass the file path into the appropriate loader, and
123 then return the TestrunResult instance.
126 def get_extension(file_path):
127 """Get the extension name to use when searching for a loader.
129 This function correctly handles compression suffixes, as long as they
130 are valid.
133 def _extension(file_path):
134 """Helper function to get the extension string."""
135 compression = 'none'
136 name, extension = os.path.splitext(file_path)
138 # If we hit a compressed suffix, get an additional suffix to test
139 # with.
140 # i.e: Use .json.gz rather that .gz
141 if extension in COMPRESSION_SUFFIXES:
142 compression = extension[1:] # Drop the leading '.'
143 # Remove any trailing '.', this fixes a bug where the filename
144 # is 'foo.json..xz, or similar
145 extension = os.path.splitext(name.rstrip('.'))[1]
147 return extension, compression
149 if not os.path.isdir(file_path):
150 return _extension(file_path)
151 else:
152 for file_ in os.listdir(file_path):
153 if file_.startswith('result') and not file_.endswith('.old'):
154 return _extension(file_)
156 tests = os.path.join(file_path, 'tests')
157 if os.path.exists(tests):
158 return _extension(os.listdir(tests)[0])
159 else:
160 # At this point we have failed to find any sort of backend, just
161 # except and die
162 raise BackendError("No backend found for any file in {}".format(
163 file_path))
165 extension, compression = get_extension(file_path)
167 for backend in six.itervalues(BACKENDS):
168 if extension in backend.extensions:
169 loader = backend.load
171 if loader is None:
172 raise BackendNotImplementedError(
173 'Loader for {} is not implemented'.format(extension))
175 return loader(file_path, compression)
177 raise BackendError(
178 'No module supports file extensions "{}"'.format(extension))
181 def set_meta(backend, result):
182 """Wrapper around meta that gets the right meta function."""
183 try:
184 BACKENDS[backend].meta(result)
185 except KeyError:
186 raise BackendError('No backend {}'.format(backend))
187 except TypeError as e:
188 # Since we initialize non-implemented backends as None, and None isn't
189 # callable then we'll get a TypeError, and we're looking for NoneType
190 # in the message. If we get that we really want a
191 # BackendNotImplementedError
192 if str(e) == "'NoneType' object is not callable":
193 raise BackendNotImplementedError(
194 'meta function for {} not implemented.'.format(backend))
195 else:
196 # Otherwise re-raise the error
197 raise