Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit 00e6c38

Browse filesBrowse files
authored
Merge pull request #6920 from Kojoley/prepare-for-cross-framework-test-suite
TST: Prepare for cross-framework test suite
2 parents b7b3445 + f20efb9 commit 00e6c38
Copy full SHA for 00e6c38
Expand file treeCollapse file tree

17 files changed

+286
-170
lines changed

‎lib/matplotlib/__init__.py

Copy file name to clipboardExpand all lines: lib/matplotlib/__init__.py
+6-59Lines changed: 6 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -1401,7 +1401,7 @@ def use(arg, warn=True, force=False):
14011401
if 'matplotlib.backends' in sys.modules:
14021402
# Warn only if called with a different name
14031403
if (rcParams['backend'] != name) and warn:
1404-
warnings.warn(_use_error_msg)
1404+
warnings.warn(_use_error_msg, stacklevel=2)
14051405

14061406
# Unless we've been told to force it, just return
14071407
if not force:
@@ -1586,70 +1586,17 @@ def _init_tests():
15861586
)
15871587
)
15881588

1589-
try:
1590-
import nose
1591-
try:
1592-
from unittest import mock
1593-
except:
1594-
import mock
1595-
except ImportError:
1596-
print("matplotlib.test requires nose and mock to run.")
1597-
raise
1598-
1599-
1600-
def _get_extra_test_plugins():
1601-
from .testing.performgc import PerformGC
1602-
from .testing.noseclasses import KnownFailure
1603-
from nose.plugins import attrib
1589+
from .testing.nose import check_deps
1590+
check_deps()
16041591

1605-
return [PerformGC, KnownFailure, attrib.Plugin]
16061592

1607-
1608-
def _get_nose_env():
1609-
env = {'NOSE_COVER_PACKAGE': ['matplotlib', 'mpl_toolkits'],
1610-
'NOSE_COVER_HTML': 1,
1611-
'NOSE_COVER_NO_PRINT': 1}
1612-
return env
1613-
1614-
1615-
def test(verbosity=1, coverage=False):
1593+
def test(verbosity=1, coverage=False, **kwargs):
16161594
"""run the matplotlib test suite"""
16171595
_init_tests()
16181596

1619-
old_backend = rcParams['backend']
1620-
try:
1621-
use('agg')
1622-
import nose
1623-
import nose.plugins.builtin
1624-
from nose.plugins.manager import PluginManager
1625-
from nose.plugins import multiprocess
1626-
1627-
# store the old values before overriding
1628-
plugins = _get_extra_test_plugins()
1629-
plugins.extend([plugin for plugin in nose.plugins.builtin.plugins])
1630-
1631-
manager = PluginManager(plugins=[x() for x in plugins])
1632-
config = nose.config.Config(verbosity=verbosity, plugins=manager)
1633-
1634-
# Nose doesn't automatically instantiate all of the plugins in the
1635-
# child processes, so we have to provide the multiprocess plugin with
1636-
# a list.
1637-
multiprocess._instantiate_plugins = plugins
1638-
1639-
env = _get_nose_env()
1640-
if coverage:
1641-
env['NOSE_WITH_COVERAGE'] = 1
1642-
1643-
success = nose.run(
1644-
defaultTest=default_test_modules,
1645-
config=config,
1646-
env=env,
1647-
)
1648-
finally:
1649-
if old_backend.lower() != 'agg':
1650-
use(old_backend)
1597+
from .testing.nose import test as nose_test
1598+
return nose_test(verbosity, coverage, **kwargs)
16511599

1652-
return success
16531600

16541601
test.__test__ = False # nose: this function is not a test
16551602

‎lib/matplotlib/testing/__init__.py

Copy file name to clipboardExpand all lines: lib/matplotlib/testing/__init__.py
+44Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
from __future__ import (absolute_import, division, print_function,
22
unicode_literals)
33

4+
import inspect
45
import warnings
56
from contextlib import contextmanager
67

@@ -13,6 +14,49 @@ def _is_list_like(obj):
1314
return not is_string_like(obj) and iterable(obj)
1415

1516

17+
def xfail(msg=""):
18+
"""Explicitly fail an currently-executing test with the given message."""
19+
from .nose import knownfail
20+
knownfail(msg)
21+
22+
23+
def skip(msg=""):
24+
"""Skip an executing test with the given message."""
25+
from nose import SkipTest
26+
raise SkipTest(msg)
27+
28+
29+
# stolen from pytest
30+
def getrawcode(obj, trycall=True):
31+
"""Return code object for given function."""
32+
try:
33+
return obj.__code__
34+
except AttributeError:
35+
obj = getattr(obj, 'im_func', obj)
36+
obj = getattr(obj, 'func_code', obj)
37+
obj = getattr(obj, 'f_code', obj)
38+
obj = getattr(obj, '__code__', obj)
39+
if trycall and not hasattr(obj, 'co_firstlineno'):
40+
if hasattr(obj, '__call__') and not inspect.isclass(obj):
41+
x = getrawcode(obj.__call__, trycall=False)
42+
if hasattr(x, 'co_firstlineno'):
43+
return x
44+
return obj
45+
46+
47+
def copy_metadata(src_func, tgt_func):
48+
"""Replicates metadata of the function. Returns target function."""
49+
tgt_func.__dict__ = src_func.__dict__
50+
tgt_func.__doc__ = src_func.__doc__
51+
tgt_func.__module__ = src_func.__module__
52+
tgt_func.__name__ = src_func.__name__
53+
if hasattr(src_func, '__qualname__'):
54+
tgt_func.__qualname__ = src_func.__qualname__
55+
if not hasattr(tgt_func, 'compat_co_firstlineno'):
56+
tgt_func.compat_co_firstlineno = getrawcode(src_func).co_firstlineno
57+
return tgt_func
58+
59+
1660
# stolen from pandas
1761
@contextmanager
1862
def assert_produces_warning(expected_warning=Warning, filter_level="always",

‎lib/matplotlib/testing/decorators.py

Copy file name to clipboardExpand all lines: lib/matplotlib/testing/decorators.py
+20-40Lines changed: 20 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44
import six
55

66
import functools
7-
import gc
87
import inspect
98
import os
109
import sys
@@ -16,8 +15,6 @@
1615
# allows other functions here to be used by pytest-based testing suites without
1716
# requiring nose to be installed.
1817

19-
import numpy as np
20-
2118
import matplotlib as mpl
2219
import matplotlib.style
2320
import matplotlib.units
@@ -27,13 +24,23 @@
2724
from matplotlib import pyplot as plt
2825
from matplotlib import ft2font
2926
from matplotlib import rcParams
30-
from matplotlib.testing.noseclasses import KnownFailureTest, \
31-
KnownFailureDidNotFailTest, ImageComparisonFailure
3227
from matplotlib.testing.compare import comparable_formats, compare_images, \
3328
make_test_filename
29+
from . import copy_metadata, skip, xfail
30+
from .exceptions import ImageComparisonFailure
31+
32+
33+
def skipif(condition, *args, **kwargs):
34+
"""Skip the given test function if eval(condition) results in a True
35+
value.
36+
37+
Optionally specify a reason for better reporting.
38+
"""
39+
from .nose.decorators import skipif
40+
return skipif(condition, *args, **kwargs)
3441

3542

36-
def knownfailureif(fail_condition, msg=None, known_exception_class=None ):
43+
def knownfailureif(fail_condition, msg=None, known_exception_class=None):
3744
"""
3845
3946
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 ):
4552
if the exception is an instance of this class. (Default = None)
4653
4754
"""
48-
# based on numpy.testing.dec.knownfailureif
49-
if msg is None:
50-
msg = 'Test known to fail'
51-
def known_fail_decorator(f):
52-
# Local import to avoid a hard nose dependency and only incur the
53-
# import time overhead at actual test-time.
54-
import nose
55-
def failer(*args, **kwargs):
56-
try:
57-
# Always run the test (to generate images).
58-
result = f(*args, **kwargs)
59-
except Exception as err:
60-
if fail_condition:
61-
if known_exception_class is not None:
62-
if not isinstance(err,known_exception_class):
63-
# This is not the expected exception
64-
raise
65-
# (Keep the next ultra-long comment so in shows in console.)
66-
raise KnownFailureTest(msg) # An error here when running nose means that you don't have the matplotlib.testing.noseclasses:KnownFailure plugin in use.
67-
else:
68-
raise
69-
if fail_condition and fail_condition != 'indeterminate':
70-
raise KnownFailureDidNotFailTest(msg)
71-
return result
72-
return nose.tools.make_decorator(f)(failer)
73-
return known_fail_decorator
55+
from .nose.decorators import knownfailureif
56+
return knownfailureif(fail_condition, msg, known_exception_class)
7457

7558

7659
def _do_cleanup(original_units_registry, original_settings):
@@ -214,7 +197,7 @@ def remove_text(figure):
214197
def test(self):
215198
baseline_dir, result_dir = _image_directories(self._func)
216199
if self._style != 'classic':
217-
raise KnownFailureTest('temporarily disabled until 2.0 tag')
200+
xfail('temporarily disabled until 2.0 tag')
218201
for fignum, baseline in zip(plt.get_fignums(), self._baseline_images):
219202
for extension in self._extensions:
220203
will_fail = not extension in comparable_formats()
@@ -266,13 +249,14 @@ def do_test():
266249
'(RMS %(rms).3f)'%err)
267250
except ImageComparisonFailure:
268251
if not check_freetype_version(self._freetype_version):
269-
raise KnownFailureTest(
252+
xfail(
270253
"Mismatched version of freetype. Test requires '%s', you have '%s'" %
271254
(self._freetype_version, ft2font.__freetype_version__))
272255
raise
273256

274257
yield (do_test,)
275258

259+
276260
def image_comparison(baseline_images=None, extensions=None, tol=0,
277261
freetype_version=None, remove_text=False,
278262
savefig_kwarg=None, style='classic'):
@@ -420,9 +404,6 @@ def find_dotted_module(module_name, path=None):
420404

421405

422406
def switch_backend(backend):
423-
# Local import to avoid a hard nose dependency and only incur the
424-
# import time overhead at actual test-time.
425-
import nose
426407
def switch_backend_decorator(func):
427408
def backend_switcher(*args, **kwargs):
428409
try:
@@ -434,7 +415,7 @@ def backend_switcher(*args, **kwargs):
434415
plt.switch_backend(prev_backend)
435416
return result
436417

437-
return nose.tools.make_decorator(func)(backend_switcher)
418+
return copy_metadata(func, backend_switcher)
438419
return switch_backend_decorator
439420

440421

@@ -453,7 +434,6 @@ def skip_if_command_unavailable(cmd):
453434
try:
454435
check_output(cmd)
455436
except:
456-
from nose import SkipTest
457-
raise SkipTest('missing command: %s' % cmd[0])
437+
skip('missing command: %s' % cmd[0])
458438

459439
return lambda f: f

‎lib/matplotlib/testing/exceptions.py

Copy file name to clipboardExpand all lines: lib/matplotlib/testing/exceptions.py
-12Lines changed: 0 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,3 @@
1-
class KnownFailureTest(Exception):
2-
"""
3-
Raise this exception to mark a test as a known failing test.
4-
"""
5-
6-
7-
class KnownFailureDidNotFailTest(Exception):
8-
"""
9-
Raise this exception to mark a test should have failed but did not.
10-
"""
11-
12-
131
class ImageComparisonFailure(AssertionError):
142
"""
153
Raise this exception to mark a test as a comparison between two images.
+70Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
from __future__ import (absolute_import, division, print_function,
2+
unicode_literals)
3+
4+
5+
def get_extra_test_plugins():
6+
from .plugins.performgc import PerformGC
7+
from .plugins.knownfailure import KnownFailure
8+
from nose.plugins import attrib
9+
10+
return [PerformGC, KnownFailure, attrib.Plugin]
11+
12+
13+
def get_env():
14+
env = {'NOSE_COVER_PACKAGE': ['matplotlib', 'mpl_toolkits'],
15+
'NOSE_COVER_HTML': 1,
16+
'NOSE_COVER_NO_PRINT': 1}
17+
return env
18+
19+
20+
def check_deps():
21+
try:
22+
import nose
23+
try:
24+
from unittest import mock
25+
except ImportError:
26+
import mock
27+
except ImportError:
28+
print("matplotlib.test requires nose and mock to run.")
29+
raise
30+
31+
32+
def test(verbosity=None, coverage=False, switch_backend_warn=True, **kwargs):
33+
from ... import default_test_modules, get_backend, use
34+
35+
old_backend = get_backend()
36+
try:
37+
use('agg')
38+
import nose
39+
from nose.plugins import multiprocess
40+
41+
# Nose doesn't automatically instantiate all of the plugins in the
42+
# child processes, so we have to provide the multiprocess plugin with
43+
# a list.
44+
extra_plugins = get_extra_test_plugins()
45+
multiprocess._instantiate_plugins = extra_plugins
46+
47+
env = get_env()
48+
if coverage:
49+
env['NOSE_WITH_COVERAGE'] = 1
50+
51+
if verbosity is not None:
52+
env['NOSE_VERBOSE'] = verbosity
53+
54+
success = nose.run(
55+
addplugins=[plugin() for plugin in extra_plugins],
56+
env=env,
57+
defaultTest=default_test_modules,
58+
**kwargs
59+
)
60+
finally:
61+
if old_backend.lower() != 'agg':
62+
use(old_backend, warn=switch_backend_warn)
63+
64+
return success
65+
66+
67+
def knownfail(msg):
68+
from .exceptions import KnownFailureTest
69+
# Keep the next ultra-long comment so it shows in console.
70+
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

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.