Skip to content

Finish removing nose #7935

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 7 commits into from
Jan 28, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 3 additions & 25 deletions lib/matplotlib/testing/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,30 +20,8 @@ def is_called_from_pytest():
return getattr(matplotlib, '_called_from_pytest', False)


def xfail(msg=""):
"""Explicitly fail an currently-executing test with the given message."""
__tracebackhide__ = True
if is_called_from_pytest():
import pytest
pytest.xfail(msg)
else:
from .nose import knownfail
knownfail(msg)


def skip(msg=""):
"""Skip an executing test with the given message."""
__tracebackhide__ = True
if is_called_from_pytest():
import pytest
pytest.skip(msg)
else:
from nose import SkipTest
raise SkipTest(msg)


# stolen from pytest
def getrawcode(obj, trycall=True):
def _getrawcode(obj, trycall=True):
"""Return code object for given function."""
try:
return obj.__code__
Expand All @@ -60,7 +38,7 @@ def getrawcode(obj, trycall=True):
return obj


def copy_metadata(src_func, tgt_func):
def _copy_metadata(src_func, tgt_func):
"""Replicates metadata of the function. Returns target function."""
tgt_func.__dict__.update(src_func.__dict__)
tgt_func.__doc__ = src_func.__doc__
Expand All @@ -69,7 +47,7 @@ def copy_metadata(src_func, tgt_func):
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
tgt_func.compat_co_firstlineno = _getrawcode(src_func).co_firstlineno
return tgt_func


Expand Down
43 changes: 2 additions & 41 deletions lib/matplotlib/testing/_nose/decorators.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,50 +4,11 @@
import os
import six
import sys
from .. import copy_metadata, skip
from .. import _copy_metadata
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:
Expand All @@ -70,5 +31,5 @@ def failer(*args, **kwargs):
if fail_condition and fail_condition != 'indeterminate':
raise KnownFailureDidNotFailTest(msg)
return result
return copy_metadata(f, failer)
return _copy_metadata(f, failer)
return known_fail_decorator
10 changes: 8 additions & 2 deletions lib/matplotlib/testing/compare.py
Original file line number Diff line number Diff line change
Expand Up @@ -174,8 +174,14 @@ def convert(filename, cache):
"""
base, extension = filename.rsplit('.', 1)
if extension not in converter:
from nose import SkipTest
raise SkipTest("Don't know how to convert %s files to png" % extension)
reason = "Don't know how to convert %s files to png" % extension
from . import is_called_from_pytest
if is_called_from_pytest():
import pytest
pytest.skip(reason)
else:
from nose import SkipTest
raise SkipTest(reason)
newname = base + '_' + extension + '.png'
if not os.path.exists(filename):
raise IOError("'%s' does not exist" % filename)
Expand Down
74 changes: 37 additions & 37 deletions lib/matplotlib/testing/decorators.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,25 +26,11 @@
from matplotlib import ft2font
from matplotlib.testing.compare import comparable_formats, compare_images, \
make_test_filename
from . import copy_metadata, is_called_from_pytest, xfail
from . import _copy_metadata, is_called_from_pytest
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.
"""
if is_called_from_pytest():
import pytest
return pytest.mark.skipif(condition, *args, **kwargs)
else:
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*
Expand All @@ -69,6 +55,12 @@ def knownfailureif(fail_condition, msg=None, known_exception_class=None):
return knownfailureif(fail_condition, msg, known_exception_class)


@cbook.deprecated('2.1',
alternative='pytest.xfail or import the plugin')
def knownfailureif(fail_condition, msg=None, known_exception_class=None):
_knownfailureif(fail_condition, msg, known_exception_class)


def _do_cleanup(original_units_registry, original_settings):
plt.close('all')

Expand Down Expand Up @@ -175,15 +167,15 @@ def check_freetype_version(ver):
return found >= ver[0] and found <= ver[1]


def checked_on_freetype_version(required_freetype_version):
def _checked_on_freetype_version(required_freetype_version):
if check_freetype_version(required_freetype_version):
return lambda f: f

reason = ("Mismatched version of freetype. "
"Test requires '%s', you have '%s'" %
(required_freetype_version, ft2font.__freetype_version__))
return knownfailureif('indeterminate', msg=reason,
known_exception_class=ImageComparisonFailure)
return _knownfailureif('indeterminate', msg=reason,
known_exception_class=ImageComparisonFailure)


def remove_ticks_and_titles(figure):
Expand All @@ -202,7 +194,7 @@ def remove_ticks_and_titles(figure):
pass


def raise_on_image_difference(expected, actual, tol):
def _raise_on_image_difference(expected, actual, tol):
__tracebackhide__ = True

err = compare_images(expected, actual, tol, in_decorator=True)
Expand All @@ -216,18 +208,18 @@ def raise_on_image_difference(expected, actual, tol):
'(RMS %(rms).3f)' % err)


def xfail_if_format_is_uncomparable(extension):
def _xfail_if_format_is_uncomparable(extension):
will_fail = extension not in comparable_formats()
if will_fail:
fail_msg = 'Cannot compare %s files on this system' % extension
else:
fail_msg = 'No failure expected'

return knownfailureif(will_fail, fail_msg,
known_exception_class=ImageComparisonFailure)
return _knownfailureif(will_fail, fail_msg,
known_exception_class=ImageComparisonFailure)


def mark_xfail_if_format_is_uncomparable(extension):
def _mark_xfail_if_format_is_uncomparable(extension):
will_fail = extension not in comparable_formats()
if will_fail:
fail_msg = 'Cannot compare %s files on this system' % extension
Expand Down Expand Up @@ -284,9 +276,15 @@ def copy_baseline(self, baseline, extension):
if os.path.exists(orig_expected_fname):
shutil.copyfile(orig_expected_fname, expected_fname)
else:
xfail("Do not have baseline image {0} because this "
"file does not exist: {1}".format(expected_fname,
orig_expected_fname))
reason = ("Do not have baseline image {0} because this "
"file does not exist: {1}".format(expected_fname,
orig_expected_fname))
if is_called_from_pytest():
import pytest
pytest.xfail(reason)
else:
from ._nose import knownfail
knownfail(reason)
return expected_fname

def compare(self, idx, baseline, extension):
Expand All @@ -306,12 +304,12 @@ def compare(self, idx, baseline, extension):
fig.savefig(actual_fname, **kwargs)

expected_fname = self.copy_baseline(baseline, extension)
raise_on_image_difference(expected_fname, actual_fname, self.tol)
_raise_on_image_difference(expected_fname, actual_fname, self.tol)

def nose_runner(self):
func = self.compare
func = checked_on_freetype_version(self.freetype_version)(func)
funcs = {extension: xfail_if_format_is_uncomparable(extension)(func)
func = _checked_on_freetype_version(self.freetype_version)(func)
funcs = {extension: _xfail_if_format_is_uncomparable(extension)(func)
for extension in self.extensions}
for idx, baseline in enumerate(self.baseline_images):
for extension in self.extensions:
Expand All @@ -320,19 +318,20 @@ def nose_runner(self):
def pytest_runner(self):
from pytest import mark

extensions = map(mark_xfail_if_format_is_uncomparable, self.extensions)
extensions = map(_mark_xfail_if_format_is_uncomparable,
self.extensions)

if len(set(self.baseline_images)) == len(self.baseline_images):
@mark.parametrize("extension", extensions)
@mark.parametrize("idx,baseline", enumerate(self.baseline_images))
@checked_on_freetype_version(self.freetype_version)
@_checked_on_freetype_version(self.freetype_version)
def wrapper(idx, baseline, extension):
__tracebackhide__ = True
self.compare(idx, baseline, extension)
else:
# Some baseline images are repeated, so run this in serial.
@mark.parametrize("extension", extensions)
@checked_on_freetype_version(self.freetype_version)
@_checked_on_freetype_version(self.freetype_version)
def wrapper(extension):
__tracebackhide__ = True
for idx, baseline in enumerate(self.baseline_images):
Expand All @@ -348,7 +347,7 @@ def wrapper(extension):
def __call__(self, func):
self.delayed_init(func)
if is_called_from_pytest():
return copy_metadata(func, self.pytest_runner())
return _copy_metadata(func, self.pytest_runner())
else:
import nose.tools

Expand All @@ -361,7 +360,7 @@ def runner_wrapper():
# nose bug...
self.teardown()

return copy_metadata(func, runner_wrapper)
return _copy_metadata(func, runner_wrapper)


def image_comparison(baseline_images=None, extensions=None, tol=0,
Expand Down Expand Up @@ -497,7 +496,7 @@ def backend_switcher(*args, **kwargs):
plt.switch_backend(prev_backend)
return result

return copy_metadata(func, backend_switcher)
return _copy_metadata(func, backend_switcher)
return switch_backend_decorator


Expand All @@ -516,6 +515,7 @@ def skip_if_command_unavailable(cmd):
try:
check_output(cmd)
except:
return skipif(True, reason='missing command: %s' % cmd[0])
import pytest
return pytest.mark.skip(reason='missing command: %s' % cmd[0])

return lambda f: f
4 changes: 0 additions & 4 deletions lib/matplotlib/tests/test_agg.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@
from matplotlib.image import imread
from matplotlib.backends.backend_agg import FigureCanvasAgg as FigureCanvas
from matplotlib.figure import Figure
from matplotlib.testing import skip
from matplotlib.testing.decorators import cleanup, image_comparison
from matplotlib import pyplot as plt
from matplotlib import collections
Expand Down Expand Up @@ -180,9 +179,6 @@ def process_image(self, padded_src, dpi):
t2 = self.offset_filter.process_image(t1, dpi)
return t2

if LooseVersion(np.__version__) < LooseVersion('1.7.0'):
skip('Disabled on Numpy < 1.7.0')

fig = plt.figure()
ax = fig.add_subplot(111)

Expand Down
7 changes: 3 additions & 4 deletions lib/matplotlib/tests/test_animation.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@
import matplotlib as mpl
from matplotlib import pyplot as plt
from matplotlib import animation
from matplotlib.testing import xfail, skip
from matplotlib.testing.decorators import cleanup


Expand Down Expand Up @@ -121,7 +120,7 @@ def test_save_animation_smoketest(tmpdir, writer, extension):
except AttributeError:
pass
if not animation.writers.is_available(writer):
skip("writer '%s' not available on this system" % writer)
pytest.skip("writer '%s' not available on this system" % writer)
fig, ax = plt.subplots()
line, = ax.plot([], [])

Expand All @@ -145,8 +144,8 @@ def animate(i):
try:
anim.save('movie.' + extension, fps=30, writer=writer, bitrate=500)
except UnicodeDecodeError:
xfail("There can be errors in the numpy import stack, "
"see issues #1891 and #2679")
pytest.xfail("There can be errors in the numpy import stack, "
"see issues #1891 and #2679")


@cleanup
Expand Down
3 changes: 1 addition & 2 deletions lib/matplotlib/tests/test_axes.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@

import matplotlib
from matplotlib.testing.decorators import image_comparison, cleanup
from matplotlib.testing import skip
import matplotlib.pyplot as plt
import matplotlib.markers as mmarkers
import matplotlib.patches as mpatches
Expand Down Expand Up @@ -90,7 +89,7 @@ def test_formatter_ticker():
def test_formatter_large_small():
# github issue #617, pull #619
if LooseVersion(np.__version__) >= LooseVersion('1.11.0'):
skip("Fall out from a fixed numpy bug")
pytest.skip("Fall out from a fixed numpy bug")
fig, ax = plt.subplots(1)
x = [0.500000001, 0.500000002]
y = [1e64, 1.1e64]
Expand Down
Loading