diff --git a/lib/matplotlib/__init__.py b/lib/matplotlib/__init__.py index baf3b6fb2c06..e45a5b0e98bb 100644 --- a/lib/matplotlib/__init__.py +++ b/lib/matplotlib/__init__.py @@ -1401,7 +1401,7 @@ def use(arg, warn=True, force=False): if 'matplotlib.backends' in sys.modules: # Warn only if called with a different name if (rcParams['backend'] != name) and warn: - warnings.warn(_use_error_msg) + warnings.warn(_use_error_msg, stacklevel=2) # Unless we've been told to force it, just return if not force: @@ -1586,70 +1586,17 @@ def _init_tests(): ) ) - try: - import nose - try: - from unittest import mock - except: - import mock - except ImportError: - print("matplotlib.test requires nose and mock to run.") - raise - - -def _get_extra_test_plugins(): - from .testing.performgc import PerformGC - from .testing.noseclasses import KnownFailure - from nose.plugins import attrib + from .testing.nose import check_deps + check_deps() - return [PerformGC, KnownFailure, attrib.Plugin] - -def _get_nose_env(): - env = {'NOSE_COVER_PACKAGE': ['matplotlib', 'mpl_toolkits'], - 'NOSE_COVER_HTML': 1, - 'NOSE_COVER_NO_PRINT': 1} - return env - - -def test(verbosity=1, coverage=False): +def test(verbosity=1, coverage=False, **kwargs): """run the matplotlib test suite""" _init_tests() - old_backend = rcParams['backend'] - try: - use('agg') - import nose - import nose.plugins.builtin - from nose.plugins.manager import PluginManager - from nose.plugins import multiprocess - - # store the old values before overriding - plugins = _get_extra_test_plugins() - plugins.extend([plugin for plugin in nose.plugins.builtin.plugins]) - - manager = PluginManager(plugins=[x() for x in plugins]) - config = nose.config.Config(verbosity=verbosity, plugins=manager) - - # Nose doesn't automatically instantiate all of the plugins in the - # child processes, so we have to provide the multiprocess plugin with - # a list. - multiprocess._instantiate_plugins = plugins - - env = _get_nose_env() - if coverage: - env['NOSE_WITH_COVERAGE'] = 1 - - success = nose.run( - defaultTest=default_test_modules, - config=config, - env=env, - ) - finally: - if old_backend.lower() != 'agg': - use(old_backend) + from .testing.nose import test as nose_test + return nose_test(verbosity, coverage, **kwargs) - return success test.__test__ = False # nose: this function is not a test diff --git a/lib/matplotlib/testing/__init__.py b/lib/matplotlib/testing/__init__.py index 76de517f18a1..f47171652d10 100644 --- a/lib/matplotlib/testing/__init__.py +++ b/lib/matplotlib/testing/__init__.py @@ -1,6 +1,7 @@ from __future__ import (absolute_import, division, print_function, unicode_literals) +import inspect import warnings from contextlib import contextmanager @@ -13,6 +14,49 @@ def _is_list_like(obj): return not is_string_like(obj) and iterable(obj) +def xfail(msg=""): + """Explicitly fail an currently-executing test with the given message.""" + from .nose import knownfail + knownfail(msg) + + +def skip(msg=""): + """Skip an executing test with the given message.""" + from nose import SkipTest + raise SkipTest(msg) + + +# stolen from pytest +def getrawcode(obj, trycall=True): + """Return code object for given function.""" + try: + return obj.__code__ + except AttributeError: + obj = getattr(obj, 'im_func', obj) + obj = getattr(obj, 'func_code', obj) + obj = getattr(obj, 'f_code', obj) + obj = getattr(obj, '__code__', obj) + if trycall and not hasattr(obj, 'co_firstlineno'): + if hasattr(obj, '__call__') and not inspect.isclass(obj): + x = getrawcode(obj.__call__, trycall=False) + if hasattr(x, 'co_firstlineno'): + return x + return obj + + +def copy_metadata(src_func, tgt_func): + """Replicates metadata of the function. Returns target function.""" + tgt_func.__dict__ = src_func.__dict__ + tgt_func.__doc__ = src_func.__doc__ + tgt_func.__module__ = src_func.__module__ + tgt_func.__name__ = src_func.__name__ + if hasattr(src_func, '__qualname__'): + tgt_func.__qualname__ = src_func.__qualname__ + if not hasattr(tgt_func, 'compat_co_firstlineno'): + tgt_func.compat_co_firstlineno = getrawcode(src_func).co_firstlineno + return tgt_func + + # stolen from pandas @contextmanager def assert_produces_warning(expected_warning=Warning, filter_level="always", diff --git a/lib/matplotlib/testing/decorators.py b/lib/matplotlib/testing/decorators.py index 6b7ddba03a3e..e2dd9bcaee06 100644 --- a/lib/matplotlib/testing/decorators.py +++ b/lib/matplotlib/testing/decorators.py @@ -4,7 +4,6 @@ import six import functools -import gc import inspect import os import sys @@ -16,8 +15,6 @@ # allows other functions here to be used by pytest-based testing suites without # requiring nose to be installed. -import numpy as np - import matplotlib as mpl import matplotlib.style import matplotlib.units @@ -27,13 +24,23 @@ from matplotlib import pyplot as plt from matplotlib import ft2font from matplotlib import rcParams -from matplotlib.testing.noseclasses import KnownFailureTest, \ - KnownFailureDidNotFailTest, ImageComparisonFailure from matplotlib.testing.compare import comparable_formats, compare_images, \ make_test_filename +from . import copy_metadata, skip, xfail +from .exceptions import ImageComparisonFailure + + +def skipif(condition, *args, **kwargs): + """Skip the given test function if eval(condition) results in a True + value. + + Optionally specify a reason for better reporting. + """ + from .nose.decorators import skipif + return skipif(condition, *args, **kwargs) -def knownfailureif(fail_condition, msg=None, known_exception_class=None ): +def knownfailureif(fail_condition, msg=None, known_exception_class=None): """ Assume a will fail if *fail_condition* is True. *fail_condition* @@ -45,32 +52,8 @@ def knownfailureif(fail_condition, msg=None, known_exception_class=None ): if the exception is an instance of this class. (Default = None) """ - # based on numpy.testing.dec.knownfailureif - if msg is None: - msg = 'Test known to fail' - def known_fail_decorator(f): - # Local import to avoid a hard nose dependency and only incur the - # import time overhead at actual test-time. - import nose - def failer(*args, **kwargs): - try: - # Always run the test (to generate images). - result = f(*args, **kwargs) - except Exception as err: - if fail_condition: - if known_exception_class is not None: - if not isinstance(err,known_exception_class): - # This is not the expected exception - raise - # (Keep the next ultra-long comment so in shows in console.) - raise KnownFailureTest(msg) # An error here when running nose means that you don't have the matplotlib.testing.noseclasses:KnownFailure plugin in use. - else: - raise - if fail_condition and fail_condition != 'indeterminate': - raise KnownFailureDidNotFailTest(msg) - return result - return nose.tools.make_decorator(f)(failer) - return known_fail_decorator + from .nose.decorators import knownfailureif + return knownfailureif(fail_condition, msg, known_exception_class) def _do_cleanup(original_units_registry, original_settings): @@ -214,7 +197,7 @@ def remove_text(figure): def test(self): baseline_dir, result_dir = _image_directories(self._func) if self._style != 'classic': - raise KnownFailureTest('temporarily disabled until 2.0 tag') + xfail('temporarily disabled until 2.0 tag') for fignum, baseline in zip(plt.get_fignums(), self._baseline_images): for extension in self._extensions: will_fail = not extension in comparable_formats() @@ -266,13 +249,14 @@ def do_test(): '(RMS %(rms).3f)'%err) except ImageComparisonFailure: if not check_freetype_version(self._freetype_version): - raise KnownFailureTest( + xfail( "Mismatched version of freetype. Test requires '%s', you have '%s'" % (self._freetype_version, ft2font.__freetype_version__)) raise yield (do_test,) + def image_comparison(baseline_images=None, extensions=None, tol=0, freetype_version=None, remove_text=False, savefig_kwarg=None, style='classic'): @@ -420,9 +404,6 @@ def find_dotted_module(module_name, path=None): def switch_backend(backend): - # Local import to avoid a hard nose dependency and only incur the - # import time overhead at actual test-time. - import nose def switch_backend_decorator(func): def backend_switcher(*args, **kwargs): try: @@ -434,7 +415,7 @@ def backend_switcher(*args, **kwargs): plt.switch_backend(prev_backend) return result - return nose.tools.make_decorator(func)(backend_switcher) + return copy_metadata(func, backend_switcher) return switch_backend_decorator @@ -453,7 +434,6 @@ def skip_if_command_unavailable(cmd): try: check_output(cmd) except: - from nose import SkipTest - raise SkipTest('missing command: %s' % cmd[0]) + skip('missing command: %s' % cmd[0]) return lambda f: f diff --git a/lib/matplotlib/testing/exceptions.py b/lib/matplotlib/testing/exceptions.py index b549d89205ec..c39a39207747 100644 --- a/lib/matplotlib/testing/exceptions.py +++ b/lib/matplotlib/testing/exceptions.py @@ -1,15 +1,3 @@ -class KnownFailureTest(Exception): - """ - Raise this exception to mark a test as a known failing test. - """ - - -class KnownFailureDidNotFailTest(Exception): - """ - Raise this exception to mark a test should have failed but did not. - """ - - class ImageComparisonFailure(AssertionError): """ Raise this exception to mark a test as a comparison between two images. diff --git a/lib/matplotlib/testing/nose/__init__.py b/lib/matplotlib/testing/nose/__init__.py new file mode 100644 index 000000000000..0d4f1e19e100 --- /dev/null +++ b/lib/matplotlib/testing/nose/__init__.py @@ -0,0 +1,70 @@ +from __future__ import (absolute_import, division, print_function, + unicode_literals) + + +def get_extra_test_plugins(): + from .plugins.performgc import PerformGC + from .plugins.knownfailure import KnownFailure + from nose.plugins import attrib + + return [PerformGC, KnownFailure, attrib.Plugin] + + +def get_env(): + env = {'NOSE_COVER_PACKAGE': ['matplotlib', 'mpl_toolkits'], + 'NOSE_COVER_HTML': 1, + 'NOSE_COVER_NO_PRINT': 1} + return env + + +def check_deps(): + try: + import nose + try: + from unittest import mock + except ImportError: + import mock + except ImportError: + print("matplotlib.test requires nose and mock to run.") + raise + + +def test(verbosity=None, coverage=False, switch_backend_warn=True, **kwargs): + from ... import default_test_modules, get_backend, use + + old_backend = get_backend() + try: + use('agg') + import nose + from nose.plugins import multiprocess + + # Nose doesn't automatically instantiate all of the plugins in the + # child processes, so we have to provide the multiprocess plugin with + # a list. + extra_plugins = get_extra_test_plugins() + multiprocess._instantiate_plugins = extra_plugins + + env = get_env() + if coverage: + env['NOSE_WITH_COVERAGE'] = 1 + + if verbosity is not None: + env['NOSE_VERBOSE'] = verbosity + + success = nose.run( + addplugins=[plugin() for plugin in extra_plugins], + env=env, + defaultTest=default_test_modules, + **kwargs + ) + finally: + if old_backend.lower() != 'agg': + use(old_backend, warn=switch_backend_warn) + + return success + + +def knownfail(msg): + from .exceptions import KnownFailureTest + # Keep the next ultra-long comment so it shows in console. + raise KnownFailureTest(msg) # An error here when running nose means that you don't have the matplotlib.testing.nose.plugins:KnownFailure plugin in use. # noqa diff --git a/lib/matplotlib/testing/nose/decorators.py b/lib/matplotlib/testing/nose/decorators.py new file mode 100644 index 000000000000..d6456b76424e --- /dev/null +++ b/lib/matplotlib/testing/nose/decorators.py @@ -0,0 +1,74 @@ +from __future__ import (absolute_import, division, print_function, + unicode_literals) + +import os +import six +import sys +from .. import copy_metadata, skip +from . import knownfail +from .exceptions import KnownFailureDidNotFailTest + + +def skipif(skip_condition, *args, **kwargs): + if isinstance(skip_condition, bool) and 'reason' not in kwargs: + raise ValueError("you need to specify reason=STRING " + "when using booleans as conditions.") + + def skip_decorator(func): + import inspect + + def skipper(*_args, **_kwargs): + condition, msg = skip_condition, kwargs.get('reason') # local copy + if isinstance(condition, six.string_types): + globs = {'os': os, 'sys': sys} + try: + globs.update(func.__globals__) + except AttributeError: + globs.update(func.func_globals) + if msg is None: + msg = condition + condition = eval(condition, globs) + else: + condition = bool(condition) + + if condition: + skip(msg) + else: + return func(*_args, **_kwargs) + + if inspect.isclass(func): + setup = getattr(func, 'setup_class', classmethod(lambda _: None)) + setup = skip_decorator(setup.__func__) + setup = setup.__get__(func) + setattr(func, 'setup_class', setup) + return func + + return copy_metadata(func, skipper) + + return skip_decorator + + +def knownfailureif(fail_condition, msg=None, known_exception_class=None): + # based on numpy.testing.dec.knownfailureif + if msg is None: + msg = 'Test known to fail' + + def known_fail_decorator(f): + def failer(*args, **kwargs): + try: + # Always run the test (to generate images). + result = f(*args, **kwargs) + except Exception as err: + if fail_condition: + if known_exception_class is not None: + if not isinstance(err, known_exception_class): + # This is not the expected exception + raise + knownfail(msg) + else: + raise + if fail_condition and fail_condition != 'indeterminate': + raise KnownFailureDidNotFailTest(msg) + return result + return copy_metadata(f, failer) + return known_fail_decorator diff --git a/lib/matplotlib/testing/nose/exceptions.py b/lib/matplotlib/testing/nose/exceptions.py new file mode 100644 index 000000000000..51fc6f782d78 --- /dev/null +++ b/lib/matplotlib/testing/nose/exceptions.py @@ -0,0 +1,10 @@ +class KnownFailureTest(Exception): + """ + Raise this exception to mark a test as a known failing test. + """ + + +class KnownFailureDidNotFailTest(Exception): + """ + Raise this exception to mark a test should have failed but did not. + """ diff --git a/lib/matplotlib/testing/nose/plugins/__init__.py b/lib/matplotlib/testing/nose/plugins/__init__.py new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/lib/matplotlib/testing/noseclasses.py b/lib/matplotlib/testing/nose/plugins/knownfailure.py similarity index 90% rename from lib/matplotlib/testing/noseclasses.py rename to lib/matplotlib/testing/nose/plugins/knownfailure.py index 8bcb09d28a29..3a5c86c35048 100644 --- a/lib/matplotlib/testing/noseclasses.py +++ b/lib/matplotlib/testing/nose/plugins/knownfailure.py @@ -1,13 +1,9 @@ from __future__ import (absolute_import, division, print_function, unicode_literals) -import six - import os from nose.plugins.errorclass import ErrorClass, ErrorClassPlugin -from matplotlib.testing.exceptions import (KnownFailureTest, - KnownFailureDidNotFailTest, - ImageComparisonFailure) +from ..exceptions import KnownFailureTest class KnownFailure(ErrorClassPlugin): diff --git a/lib/matplotlib/testing/performgc.py b/lib/matplotlib/testing/nose/plugins/performgc.py similarity index 100% rename from lib/matplotlib/testing/performgc.py rename to lib/matplotlib/testing/nose/plugins/performgc.py diff --git a/lib/matplotlib/tests/test_animation.py b/lib/matplotlib/tests/test_animation.py index 7a63de9d640f..c6373584ce2d 100644 --- a/lib/matplotlib/tests/test_animation.py +++ b/lib/matplotlib/tests/test_animation.py @@ -8,14 +8,12 @@ import tempfile import numpy as np from numpy.testing import assert_equal -from nose import with_setup from nose.tools import assert_false, assert_true import matplotlib as mpl from matplotlib import pyplot as plt from matplotlib import animation -from matplotlib.testing.noseclasses import KnownFailureTest -from matplotlib.testing.decorators import cleanup -from matplotlib.testing.decorators import CleanupTest +from ..testing import xfail, skip +from ..testing.decorators import cleanup class NullMovieWriter(animation.AbstractMovieWriter): @@ -113,8 +111,7 @@ def test_save_animation_smoketest(): @cleanup def check_save_animation(writer, extension='mp4'): if not animation.writers.is_available(writer): - raise KnownFailureTest("writer '%s' not available on this system" - % writer) + skip("writer '%s' not available on this system" % writer) fig, ax = plt.subplots() line, = ax.plot([], []) @@ -138,9 +135,8 @@ def animate(i): try: anim.save(F.name, fps=30, writer=writer, bitrate=500) except UnicodeDecodeError: - raise KnownFailureTest("There can be errors in the numpy " + - "import stack, " + - "see issues #1891 and #2679") + xfail("There can be errors in the numpy import stack, " + "see issues #1891 and #2679") finally: try: os.remove(F.name) diff --git a/lib/matplotlib/tests/test_axes.py b/lib/matplotlib/tests/test_axes.py index 650b6078631a..c56dc621eb16 100644 --- a/lib/matplotlib/tests/test_axes.py +++ b/lib/matplotlib/tests/test_axes.py @@ -22,8 +22,7 @@ import warnings import matplotlib -from matplotlib.testing.decorators import image_comparison, cleanup -from matplotlib.testing.noseclasses import KnownFailureTest +from matplotlib.testing.decorators import image_comparison, cleanup, skipif import matplotlib.pyplot as plt import matplotlib.markers as mmarkers import matplotlib.patches as mpatches @@ -87,10 +86,10 @@ def test_formatter_ticker(): ax.autoscale_view() +@skipif(LooseVersion(np.__version__) >= LooseVersion('1.11.0'), + reason="Fall out from a fixed numpy bug") @image_comparison(baseline_images=["formatter_large_small"]) def test_formatter_large_small(): - if LooseVersion(np.__version__) >= LooseVersion('1.11.0'): - raise KnownFailureTest("Fall out from a fixed numpy bug") # github issue #617, pull #619 fig, ax = plt.subplots(1) x = [0.500000001, 0.500000002] diff --git a/lib/matplotlib/tests/test_backend_pgf.py b/lib/matplotlib/tests/test_backend_pgf.py index 36315d185262..a86f4de53226 100644 --- a/lib/matplotlib/tests/test_backend_pgf.py +++ b/lib/matplotlib/tests/test_backend_pgf.py @@ -2,13 +2,10 @@ from __future__ import (absolute_import, division, print_function, unicode_literals) -import six - import os import shutil import numpy as np -import nose from nose.plugins.skip import SkipTest import matplotlib as mpl @@ -17,7 +14,7 @@ from matplotlib.testing.compare import compare_images, ImageComparisonFailure from matplotlib.testing.decorators import (_image_directories, switch_backend, cleanup) -from matplotlib.testing.noseclasses import KnownFailureTest +from ..testing import xfail baseline_dir, result_dir = _image_directories(lambda: 'dummy func') @@ -44,7 +41,7 @@ def check_for(texsystem): def compare_figure(fname, savefig_kwargs={}, tol=0): # TODO remove this before tagging 2.0 - raise KnownFailureTest('temporarily disabled until 2.0 tag') + xfail('temporarily disabled until 2.0 tag') actual = os.path.join(result_dir, fname) plt.savefig(actual, **savefig_kwargs) diff --git a/lib/matplotlib/tests/test_basic.py b/lib/matplotlib/tests/test_basic.py index d5f23ba868aa..a5f3a33ba785 100644 --- a/lib/matplotlib/tests/test_basic.py +++ b/lib/matplotlib/tests/test_basic.py @@ -5,10 +5,17 @@ from nose.tools import assert_equal -from matplotlib.testing.decorators import knownfailureif +from ..testing.decorators import knownfailureif, skipif from pylab import * +SKIPIF_CONDITION = [] + + +def setup_module(): + SKIPIF_CONDITION.append(None) + + def test_simple(): assert_equal(1 + 1, 2) @@ -19,8 +26,41 @@ def test_simple_knownfail(): assert_equal(1 + 1, 3) +@skipif(True, reason="skipif decorator test with bool condition passed") +def test_skipif_bool(): + assert False, "skipif decorator does not work with bool condition" + + +@skipif('SKIPIF_CONDITION', + reason="skipif decorator test with string condition passed") +def test_skipif_string(): + assert False, "skipif decorator does not work with string condition" + + +@skipif(True, reason="skipif decorator on class test passed") +class Test_skipif_on_class(object): + def test(self): + assert False, "skipif decorator does not work on classes" + + +class Test_skipif_on_method(object): + @skipif(True, reason="skipif decorator on method test passed") + def test(self): + assert False, "skipif decorator does not work on methods" + + +@skipif(True, reason="skipif decorator on classmethod test passed") +class Test_skipif_on_classmethod(object): + @classmethod + def setup_class(cls): + pass + + def test(self): + assert False, "skipif decorator does not work on classmethods" + + def test_override_builtins(): - ok_to_override = set([ + ok_to_override = { '__name__', '__doc__', '__package__', @@ -29,7 +69,7 @@ def test_override_builtins(): 'any', 'all', 'sum' - ]) + } # We could use six.moves.builtins here, but that seems # to do a little more than just this. diff --git a/lib/matplotlib/tests/test_coding_standards.py b/lib/matplotlib/tests/test_coding_standards.py index f1aff0e589e1..6862ee2fed99 100644 --- a/lib/matplotlib/tests/test_coding_standards.py +++ b/lib/matplotlib/tests/test_coding_standards.py @@ -6,7 +6,7 @@ from nose.tools import assert_equal from nose.plugins.skip import SkipTest -from matplotlib.testing.noseclasses import KnownFailureTest +from ..testing import xfail try: import pep8 @@ -256,9 +256,8 @@ def test_pep8_conformance_examples(): fp, tail = os.path.split(fp) if mpldir is None: - raise KnownFailureTest("can not find the examples, set env " - "MPL_REPO_DIR to point to the top-level path " - "of the source tree") + xfail("can not find the examples, set env MPL_REPO_DIR to point " + "to the top-level path of the source tree") exdir = os.path.join(mpldir, 'examples') blacklist = () diff --git a/lib/matplotlib/tests/test_image.py b/lib/matplotlib/tests/test_image.py index e06328440f2a..851f9cffb775 100644 --- a/lib/matplotlib/tests/test_image.py +++ b/lib/matplotlib/tests/test_image.py @@ -22,7 +22,6 @@ from nose.tools import assert_raises from numpy.testing import ( assert_array_equal, assert_array_almost_equal, assert_allclose) -from matplotlib.testing.noseclasses import KnownFailureTest from copy import copy from numpy import ma import matplotlib.colors as colors diff --git a/tests.py b/tests.py index db19f5572772..d6c179ed31e5 100755 --- a/tests.py +++ b/tests.py @@ -9,43 +9,19 @@ # See https://nose.readthedocs.org/ for a detailed description of # these options. -import os import sys -import time -import matplotlib -matplotlib.use('agg') - -import nose -from matplotlib import default_test_modules - - -def run(extra_args): - from nose.plugins import multiprocess - - env = matplotlib._get_nose_env() - - matplotlib._init_tests() - - # Nose doesn't automatically instantiate all of the plugins in the - # child processes, so we have to provide the multiprocess plugin with - # a list. - plugins = matplotlib._get_extra_test_plugins() - multiprocess._instantiate_plugins = plugins - - nose.main(addplugins=[x() for x in plugins], - defaultTest=default_test_modules, - argv=sys.argv + extra_args, - env=env) if __name__ == '__main__': + from matplotlib import default_test_modules, test + extra_args = [] if '--no-pep8' in sys.argv: default_test_modules.remove('matplotlib.tests.test_coding_standards') sys.argv.remove('--no-pep8') elif '--pep8' in sys.argv: - default_test_modules = ['matplotlib.tests.test_coding_standards'] + default_test_modules[:] = ['matplotlib.tests.test_coding_standards'] sys.argv.remove('--pep8') if '--no-network' in sys.argv: from matplotlib.testing import disable_internet @@ -55,4 +31,5 @@ def run(extra_args): print('Python byte-compilation optimization level: %d' % sys.flags.optimize) - run(extra_args) + success = test(argv=sys.argv + extra_args, switch_backend_warn=False) + sys.exit(not success) pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy