[Piglit] [PATCH 43/49] framework: remove unused nose bits
Dylan Baker
dylan at pnwbakers.com
Fri Jul 29 18:39:29 UTC 2016
This deletes the quite extensive nose framework that was built up in
piglit, and the tox dependencies. These have all been replaced with a
combination of mock and pytest features instead.
Signed-off-by: Dylan Baker <dylanx.c.baker at intel.com>
---
tox.ini | 7 +-
unittests/utils/__init__.py | 1 -
unittests/utils/nose.py | 417 --------------------------------------------
unittests/utils/piglit.py | 189 --------------------
4 files changed, 2 insertions(+), 612 deletions(-)
delete mode 100644 unittests/utils/__init__.py
delete mode 100644 unittests/utils/nose.py
delete mode 100644 unittests/utils/piglit.py
diff --git a/tox.ini b/tox.ini
index f8836ed..12cdddb 100644
--- a/tox.ini
+++ b/tox.ini
@@ -28,10 +28,7 @@ deps =
pytest-timeout
py{27,33,34}: mako==0.8.0
six==1.5.2
- wrapt
- {accel,noaccel}: nose
{accel,noaccel}: jsonschema
commands =
- {accel,noaccel}: nosetests unittests -e generators -e framework -e suites []
- {accel,noaccel}: py.test -rw unittests/framework unittests/suites
- generator: py.test -rw unittests/generators
+ {accel,noaccel}: py.test -rw unittests/framework unittests/suites []
+ generator: py.test -rw unittests/generators []
diff --git a/unittests/utils/__init__.py b/unittests/utils/__init__.py
deleted file mode 100644
index 1ad988f..0000000
--- a/unittests/utils/__init__.py
+++ /dev/null
@@ -1 +0,0 @@
-from . import nose, piglit
diff --git a/unittests/utils/nose.py b/unittests/utils/nose.py
deleted file mode 100644
index 02a7bf5..0000000
--- a/unittests/utils/nose.py
+++ /dev/null
@@ -1,417 +0,0 @@
-# encoding=utf-8
-# Copyright (c) 2014-2016 Intel Coporation
-
-# Permission is hereby granted, free of charge, to any person obtaining a copy
-# of this software and associated documentation files (the "Software"), to deal
-# in the Software without restriction, including without limitation the rights
-# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-# copies of the Software, and to permit persons to whom the Software is
-# furnished to do so, subject to the following conditions:
-
-# The above copyright notice and this permission notice shall be included in
-# all copies or substantial portions of the Software.
-
-# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
-# SOFTWARE.
-
-"""Nose extenders for framework tests.
-
-This module collects useful tools that extend the functionality ro fix issues
-in the nose suite. None of these features are piglit specific, they're all
-generic.
-
-"""
-
-from __future__ import (
- absolute_import, division, print_function, unicode_literals
-)
-import errno
-import functools
-import importlib
-import os
-import shutil
-import subprocess
-import sys
-import tempfile as tempfile_
-from contextlib import contextmanager
-
-from nose.plugins.skip import SkipTest
-import six
-import wrapt
-try:
- from six.moves import getcwd
-except ImportError:
- # pylint: disable=no-member
- if six.PY2:
- getcwd = os.getcwdu
- elif six.PY3:
- getcwd = os.getcwd
- # pylint: enable=no-member
-
-from framework import compat
-
-_WRITE_MODE = 'w'
-_READ_MODE = 'r'
-
-
- at compat.python_2_unicode_compatible
-class TestFailure(AssertionError):
- """An exception to be raised when a test fails.
-
- Nose expects an AssertionError for test failures, so this is a sublcass of
- AssertionError.
-
- It provides the benefit of being able to take either a text message to
- print, or an exception instance. When passed text it will print the message
- exactly, when passed an exception it will print the exception type and the
- str() value of that exception.
-
- """
- def __init__(self, arg):
- super(TestFailure, self).__init__(self)
- self.__arg = arg
-
- def __str__(self):
- if isinstance(self.__arg, Exception):
- return u'exception type "{}" with message "{}" raised.'.format(
- type(self.__arg), str(self.__arg))
- else:
- return self.__arg
-
-
-class UtilsError(Exception):
- """ An exception to be raised by utils """
- pass
-
-
-class SentinalException(Exception):
- """An exception to be used as a sentinal."""
- pass
-
-
-class StaticDirectory(object):
- """ Helper class providing shared files creation and cleanup
-
- One should override the setup_class method in a child class, call super(),
- and then add files to cls.dir.
-
- Tests in this class should NOT modify the contents of tidr, if you want
- that functionality you want a different class
-
- """
- @classmethod
- def setup_class(cls):
- """ Create a temperary directory that will be removed in teardown_class
- """
- cls.tdir = tempfile_.mkdtemp()
-
- @classmethod
- def teardown_class(cls):
- """ Remove the temporary directory """
- shutil.rmtree(cls.tdir)
-
-
-class DocFormatter(object):
- """Decorator for formatting object docstrings.
-
- This class is designed to be initialized once per test module, and then one
- instance used as a decorator for all functions.
-
- Works as follows:
- >>> doc_formatter = DocFormatter({'format': 'foo', 'name': 'bar'})
- >>>
- >>> @doc_formatter
- ... def foo():
- ... '''a docstring for {format} and {name}'''
- ... pass
- ...
- >>> foo.__doc__
- 'a docstring for foo and bar'
-
- This allows tests that can be dynamically updated by changing a single
- constant to have the test descriptions alos updated by the same constant.
-
- Arguments:
- table -- a dictionary of key value pairs to be converted
-
- """
- def __init__(self, table):
- self.__table = table
-
- def __call__(self, func):
- try:
- func.__doc__ = func.__doc__.format(**self.__table)
- except KeyError as e:
- # We want to catch this to ensure that a test that is looking for a
- # KeyError doesn't pass when it shouldn't
- raise UtilsError(e)
-
- return func
-
-
-class GeneratedTestWrapper(object):
- """ An object proxy for nose test instances
-
- Nose uses python generators to create test generators, the drawback of this
- is that unless the generator is very specifically engineered it yeilds the
- same instance multiple times. Since nose uses an instance attribute to
- display the name of the test on a failure, and it prints the failure
- dialogue after the run is complete all failing tests from a single
- generator will end up with the name of the last test generated. This
- generator is used in conjunction with the nose_generator() decorator to
- create multiple objects each with a unique description attribute, working
- around the bug.
- Upstream bug: https://code.google.com/p/python-nose/issues/detail?id=244
-
- This uses functoos.update_wrapper to proxy the underlying object, and
- provides a __call__ method (which allows it to be called like a function)
- that calls the underling function.
-
- This class can also be used to wrap a class, but that class needs to
- provide a __call__ method, and use that to return results.
-
- Arguments:
- wrapped -- A function or function-like-class
-
- """
- def __init__(self, wrapped):
- self._wrapped = wrapped
- functools.update_wrapper(self, self._wrapped)
-
- def __call__(self, *args, **kwargs):
- """ calls the wrapped function
-
- Arguments:
- *args -- arguments to be passed to the wrapped function
- **kwargs -- keyword arguments to be passed to the wrapped function
- """
- return self._wrapped(*args, **kwargs)
-
-
- at contextmanager
-def tempfile(contents):
- """ Provides a context manager for a named tempfile
-
- This contextmanager creates a named tempfile, writes data into that
- tempfile, then closes it and yields the filepath. After the context is
- returned it closes and removes the tempfile.
-
- Arguments:
- contests -- This should be a string (unicode or str), in which case it is
- written directly into the file.
-
- """
- # It is tempting to use NamedTemporaryFile here (the original
- # implementation did, in fact), but this won't work on windows beacuse of
- # implementation details. Since the goal isn't security anyway, just a
- # unique filename this is implemented in terms of tempdir.
- with tempdir() as t:
- name = os.path.join(t, 'tempfile')
- with open(name, mode=_WRITE_MODE) as f:
- f.write(contents)
- yield name
-
-
- at contextmanager
-def tempdir():
- """ Creates a temporary directory, returns it, and then deletes it """
- tdir = tempfile_.mkdtemp()
- try:
- yield tdir
- finally:
- shutil.rmtree(tdir)
-
-
-def generator(func):
- """ Decorator for nose test generators to us GeneratedTestWrapper
-
- This decorator replaces each function yeilded by a test generator with a
- GeneratedTestWrapper reverse-proxy object
-
- """
-
- @functools.wraps(func)
- def test_wrapper(*args, **kwargs):
- for x in func(*args, **kwargs):
- x = list(x)
- x[0] = GeneratedTestWrapper(x[0])
- yield tuple(x) # This must be a tuple for some reason
-
- return test_wrapper
-
-
- at wrapt.decorator
-def passthrough(wrapped, _, args, kwargs):
- return wrapped(*args, **kwargs)
-
-
-class Skip(object):
- """Class providing conditional skipping support.
-
- Provides a number of class methods as alternate constructors for special
- skip conditions, these are merely convenience methods.
-
- """
- def __init__(self, condition, description):
- self.__skip = condition
- self.__description = description
-
- @classmethod
- def py3(cls, _=None):
- """Skip if the interpreter python 3."""
- return cls(six.PY3, 'Test is not relevant on python 3.x')
-
- @classmethod
- def py2(cls, _=None):
- """Skip if the interpreter is python 2."""
- return cls(six.PY2, 'Test is not relevant on python 2.x')
-
- @classmethod
- def module(cls, name, available=False):
- """Skip if the provided external module is (not) available."""
- assert isinstance(available, bool), 'avilable must be bool'
- def check():
- try:
- importlib.import_module(name)
- except ImportError:
- return False
- return True
-
- return cls(check() is not available,
- 'Test requires that module {} is {}available'.format(
- name, '' if available else 'not '))
-
- @classmethod
- def backport(cls, version, name):
- """Skip if the interpreter needs a backport that isn't available.
-
- Arguments:
- version -- The minimum version that doesn't require the backport
- name -- the name of the required module
-
- """
- assert isinstance(version, float), 'version must be float'
- if float('.'.join(str(v) for v in sys.version_info[:2])) < version:
- return cls.module(name, True)
- return passthrough
-
- @classmethod
- def binary(cls, name):
- """Skip if the requested binary isn't available."""
- def check():
- with open(os.devnull, 'w') as null:
- try:
- # Pass the bogus arg in case the program tries to read
- # stdin, like xz
- subprocess.check_call([name, 'totallymadeupdoesntexistarg'],
- stdout=null, stderr=null)
- except OSError as e:
- if e.errno == errno.ENOENT:
- return True
- except subprocess.CalledProcessError as e:
- pass
- return False
-
- return cls(
- check(), 'Test requires that binary {} is available'.format(name))
-
- @classmethod
- def platform(cls, name, is_=False):
- return cls(sys.platform.startswith(name) is is_,
- 'Platform {} is not supported'.format(sys.platform))
-
- @wrapt.decorator
- def __call__(self, wrapped, instance, args, kwargs):
- if self.__skip:
- raise SkipTest(self.__description)
- return wrapped(*args, **kwargs)
-
-
-def test_in_tempdir(func):
- """Decorator that moves to a new directory to run a test.
-
- This decorator ensures that the test moves to a new directory, and then
- returns to the original directory after the test completes.
-
- """
- @functools.wraps(func)
- def wrapper(*args, **kwargs):
- with tempdir() as tdir:
- with chdir(tdir):
- return func(*args, **kwargs)
-
- return wrapper
-
-
-def not_raises(exceptions):
- """Decorator that causes a test to fail if it raises an exception.
-
- Without arguments this will raise a TestFailure if Exception is raised.
- arguments are passed those will be handed directly to the except keyword,
- and a TestFailure will be raised only for those exceptions.
-
- Uncaught exceptions will still be handled by nose and return an error.
-
- """
-
- def _wrapper(func):
- """wrapper that wraps the actual functiion definition."""
-
- @functools.wraps(func)
- def _inner(*args, **kwargs):
- """Wrapper for the function call."""
- try:
- func(*args, **kwargs)
- except exceptions as e:
- raise TestFailure(e)
-
- return _inner
-
- return _wrapper
-
-
-def no_error(func):
- """Convenience wrapper around not_raises when any error is an exception
-
- """
- return not_raises(Exception)(func)
-
-
-def capture_stderr(func):
- """Redirect stderr to stdout for nose capture.
-
- It would probably be better to implement a full stderr handler as a
- plugin...
-
- """
- @functools.wraps(func)
- def _inner(*args, **kwargs):
- restore = sys.stderr
- sys.stderr = sys.stdout
- try:
- func(*args, **kwargs)
- finally:
- sys.stderr = restore
-
- return _inner
-
-
- at contextmanager
-def chdir(goto):
- """chdir to a directory and back, guaranteed.
-
- This contextmanager ensures that after changing directory you cahgne back,
- using a try/finally block.
-
- """
- returnto = getcwd()
- os.chdir(goto)
- try:
- yield
- finally:
- os.chdir(returnto)
diff --git a/unittests/utils/piglit.py b/unittests/utils/piglit.py
deleted file mode 100644
index 34edc6e..0000000
--- a/unittests/utils/piglit.py
+++ /dev/null
@@ -1,189 +0,0 @@
-#encoding=utf-8
-# Copyright (c) 2014-2016 Intel Coporation
-
-# Permission is hereby granted, free of charge, to any person obtaining a copy
-# of this software and associated documentation files (the "Software"), to deal
-# in the Software without restriction, including without limitation the rights
-# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-# copies of the Software, and to permit persons to whom the Software is
-# furnished to do so, subject to the following conditions:
-
-# The above copyright notice and this permission notice shall be included in
-# all copies or substantial portions of the Software.
-
-# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
-# SOFTWARE.
-
-"""Piglit specific helpers
-
-These helpers are all piglit specific tools.
-
-"""
-
-from __future__ import (
- absolute_import, division, print_function, unicode_literals
-)
-from contextlib import contextmanager
-import copy
-import functools
-import os
-import tempfile as tempfile_
-
-try:
- import simplejson as json
-except ImportError:
- import json
-
-from framework import test, backends, core, results
-
-core.get_config()
-
-_WRITE_MODE = 'w'
-_READ_MODE = 'r'
-
-
-class _Tree(dict):
- """Private helper to make JSON_DATA easier to work with."""
- def __getitem__(self, key):
- try:
- return super(_Tree, self).__getitem__(key)
- except KeyError:
- ret = self[key] = _Tree()
- return ret
-
-
-JSON_DATA = {
- "options": {
- "profile": "tests/fake.py",
- "filter": [],
- "exclude_filter": []
- },
- "results_version": backends.json.CURRENT_JSON_VERSION,
- "name": "fake-tests",
- "lspci": "fake",
- "glxinfo": "fake",
- "tests": _Tree({
- "sometest": {
- 'result': 'pass',
- 'time': 1.2,
- }
- })
-}
-
-_SAVED_COMPRESSION = os.environ.get('PIGLIT_COMPRESSION')
-
-
-class Test(test.Test):
- """A basic dmmmy Test class that can be used in places a test is required.
-
- This provides dummy version of abstract methods in
- framework.test.base.Test, which allows it to be initialized and run, but is
- unlikely to be useful for running.
-
- This is mainly intended for testing where a Test class is required, but
- doesn't need to be run.
-
- """
- def interpret_result(self):
- pass
-
-
- at contextmanager
-def resultfile():
- """ Create a stringio with some json in it and pass that as results """
- data = copy.deepcopy(JSON_DATA)
- data['tests']['sometest'] = results.TestResult('pass')
- data['tests']['sometest'].time = 1.2
- data = results.TestrunResult.from_dict(data)
- with tempfile_.NamedTemporaryFile(mode=_WRITE_MODE, delete=False) as f:
- json.dump(data, f, default=backends.json.piglit_encoder)
-
- try:
- yield f
- finally:
- os.remove(f.name)
-
-
-def set_piglit_conf(*values):
- """Decorator that sets and then usets values from core.PIGLIT_CONF.
-
- This decorator takes arguments for sections and options to overwrite in
- piglit.conf. It will first backup any options to be overwritten, and store
- any options that don't exist. Then it will set those options, run the test,
- and finally restore any options overwritten, and delete any new options
- added. If value is set to NoneType the option will be removed.
-
- Arguments:
- Values -- tuples containing a section, option, and value in the form:
- (<section>, <option>, <value>)
-
- """
- def _decorator(func):
- """The actual decorator."""
-
- @functools.wraps(func)
- def _inner(*args, **kwargs):
- """The function returned by the decorator."""
- backup = set()
- remove = set()
-
- for section, key, value in values:
- get = core.PIGLIT_CONFIG.safe_get(section, key)
- # If there is a value, save that value to restore it, if there
- # is not a value AND if there is a value to set (IE: we're not
- # clearing a value if it exsists), the add it to remove
- if get is not None:
- backup.add((section, key, get))
- elif value is not None:
- remove.add((section, key))
-
- # set any new values, and remove any values that are set to
- # None
- if value is not None:
- if not core.PIGLIT_CONFIG.has_section(section):
- core.PIGLIT_CONFIG.add_section(section)
- core.PIGLIT_CONFIG.set(section, key, value)
- elif (core.PIGLIT_CONFIG.has_section(section) and
- core.PIGLIT_CONFIG.has_option(section, key)):
- core.PIGLIT_CONFIG.remove_option(section, key)
-
- try:
- func(*args, **kwargs)
- finally:
- # Restore all values
- for section, key, value in backup:
- core.PIGLIT_CONFIG.set(section, key, value)
- for section, key in remove:
- core.PIGLIT_CONFIG.remove_option(section, key)
-
- return _inner
- return _decorator
-
-
-def set_compression(mode):
- """lock piglit compression mode to specifed value.
-
- Meant to be called from setup_module function.
-
- """
- # The implimentation details of this is that the environment value is the
- # first value looked at for setting compression, so if it's set all other
- # values will be ignored.
- os.environ['PIGLIT_COMPRESSION'] = mode
-
-
-def unset_compression():
- """Restore compression to the origonal value.
-
- Counterpart to set_compression. Should be called from teardown_module.
-
- """
- if _SAVED_COMPRESSION is not None:
- os.environ['PIGLIT_COMPRESSION'] = _SAVED_COMPRESSION
- else:
- del os.environ['PIGLIT_COMPRESSION']
--
2.9.0
More information about the Piglit
mailing list