Skip to content

Commit d4cd2ae

Browse files
authored
Merge pull request #60 from astrofrog/close-figure
Make sure running the tests without --mpl still results in figures getting closed
2 parents 78ab284 + d78fc88 commit d4cd2ae

File tree

4 files changed

+75
-15
lines changed

4 files changed

+75
-15
lines changed

.travis.yml

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ os:
1010
env:
1111
global:
1212
- SETUP_XVFB=True
13-
- CONDA_DEPENDENCIES="pytest matplotlib nose coverage"
13+
- CONDA_DEPENDENCIES="pytest matplotlib nose coverage freetype=2.5.5"
1414
- PIP_DEPENDENCIES="pytest-cov coveralls"
1515
matrix:
1616
- PYTHON_VERSION=3.4 MATPLOTLIB_VERSION=1.5
@@ -21,7 +21,7 @@ env:
2121
- PYTHON_VERSION=3.6 MATPLOTLIB_VERSION=2.0
2222

2323
# The following build is meant to check that dependencies get set up correctly, but currently
24-
# the image tests fail, which should be investigated.
24+
# the image tests fail, which should be investigated.
2525
# - PYTHON_VERSION=3.5 CONDA_DEPENDENCIES="coverage freetype libpng"
2626

2727
install:
@@ -37,6 +37,9 @@ install:
3737
script:
3838
- python -c 'import pytest_mpl.plugin'
3939
- pytest -vv --mpl --cov pytest_mpl tests
40+
# Make sure that the tests run ok even without the --mpl option (we close
41+
# figures anyway in this case)
42+
- pytest -vv --cov pytest_mpl --cov-append tests
4043
- python setup.py check --restructuredtext
4144

4245
after_success:

CHANGES.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,14 @@
11
0.9 (unreleased)
22
----------------
33

4+
- Fix compatibility with Matplotlib 2.1. [#54]
5+
46
- Allow baseline_dir to be comma-separated URL list to allow mirrors to
57
be specified. [#59]
68

9+
- Make sure figures get closed even if not running with the --mpl
10+
option, and only close actual Matplotlib Figure objects. [#60]
11+
712
0.8 (2017-07-19)
813
----------------
914

appveyor.yml

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,17 +10,16 @@ environment:
1010
PYTHON_ARCH: "64" # needs to be set for CMD_IN_ENV to succeed. If a mix
1111
# of 32 bit and 64 bit builds are needed, move this
1212
# to the matrix section.
13-
CONDA_DEPENDENCIES: "pytest matplotlib nose"
1413

1514
matrix:
1615
- PYTHON_VERSION: "2.7"
17-
MATPLOTLIB_VERSION: "1.5"
16+
CONDA_DEPENDENCIES: "matplotlib=1.5 nose"
1817

1918
- PYTHON_VERSION: "3.5"
20-
MATPLOTLIB_VERSION: "1.5"
19+
CONDA_DEPENDENCIES: "matplotlib=1.5 nose"
2120

2221
- PYTHON_VERSION: "3.6"
23-
MATPLOTLIB_VERSION: "2.0"
22+
CONDA_DEPENDENCIES: "matplotlib=2.0.1 nose"
2423

2524
platform:
2625
-x64

pytest_mpl/plugin.py

Lines changed: 62 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434
import os
3535
import sys
3636
import shutil
37+
import inspect
3738
import tempfile
3839
import warnings
3940
from distutils.version import LooseVersion
@@ -42,7 +43,7 @@
4243

4344
if sys.version_info[0] == 2:
4445
from urllib import urlopen
45-
string_types = basestring
46+
string_types = basestring # noqa
4647
else:
4748
from urllib.request import urlopen
4849
string_types = str
@@ -70,7 +71,7 @@ def _download_file(baseline, filename):
7071

7172

7273
def pytest_addoption(parser):
73-
group = parser.getgroup("general")
74+
group = parser.getgroup("matplotlib image comparison")
7475
group.addoption('--mpl', action='store_true',
7576
help="Enable comparison of matplotlib figures to reference files")
7677
group.addoption('--mpl-generate-path',
@@ -117,6 +118,10 @@ def pytest_configure(config):
117118
generate_dir=generate_dir,
118119
results_dir=results_dir))
119120

121+
else:
122+
123+
config.pluginmanager.register(FigureCloser(config))
124+
120125

121126
@contextlib.contextmanager
122127
def switch_backend(backend):
@@ -143,8 +148,14 @@ def __init__(self, config, baseline_dir=None, generate_dir=None, results_dir=Non
143148

144149
def pytest_runtest_setup(self, item):
145150

151+
compare = item.keywords.get('mpl_image_compare')
152+
153+
if compare is None:
154+
return
155+
146156
import matplotlib
147157
import matplotlib.pyplot as plt
158+
from matplotlib.figure import Figure
148159
from matplotlib.testing.compare import compare_images
149160
from matplotlib.testing.decorators import ImageComparisonTest as MplImageComparisonTest
150161
try:
@@ -154,11 +165,6 @@ def pytest_runtest_setup(self, item):
154165

155166
MPL_LT_15 = LooseVersion(matplotlib.__version__) < LooseVersion('1.5')
156167

157-
compare = item.keywords.get('mpl_image_compare')
158-
159-
if compare is None:
160-
return
161-
162168
tolerance = compare.kwargs.get('tolerance', 2)
163169
savefig_kwargs = compare.kwargs.get('savefig_kwargs', {})
164170
style = compare.kwargs.get('style', 'classic')
@@ -188,7 +194,6 @@ def item_function_wrapper(*args, **kwargs):
188194
with plt.style.context(style), switch_backend(backend):
189195

190196
# Run test and get figure object
191-
import inspect
192197
if inspect.ismethod(original): # method
193198
# In some cases, for example if setup_method is used,
194199
# original appears to belong to an instance of the test
@@ -219,7 +224,13 @@ def item_function_wrapper(*args, **kwargs):
219224
test_image = os.path.abspath(os.path.join(result_dir, filename))
220225

221226
fig.savefig(test_image, **savefig_kwargs)
222-
plt.close(fig)
227+
228+
# We only need to close actual Matplotlib figure objects. If
229+
# we are dealing with a figure-like object that provides
230+
# savefig but is not a real Matplotlib object, we shouldn't
231+
# try closing it here.
232+
if isinstance(fig, Figure):
233+
plt.close(fig)
223234

224235
# Find path to baseline image
225236
if baseline_remote:
@@ -257,3 +268,45 @@ def item_function_wrapper(*args, **kwargs):
257268
setattr(item.cls, item.function.__name__, item_function_wrapper)
258269
else:
259270
item.obj = item_function_wrapper
271+
272+
273+
class FigureCloser(object):
274+
"""
275+
This is used in place of ImageComparison when the --mpl option is not used,
276+
to make sure that we still close figures returned by tests.
277+
"""
278+
279+
def __init__(self, config):
280+
self.config = config
281+
282+
def pytest_runtest_setup(self, item):
283+
284+
compare = item.keywords.get('mpl_image_compare')
285+
286+
if compare is None:
287+
return
288+
289+
import matplotlib.pyplot as plt
290+
from matplotlib.figure import Figure
291+
292+
original = item.function
293+
294+
@wraps(item.function)
295+
def item_function_wrapper(*args, **kwargs):
296+
297+
if inspect.ismethod(original): # method
298+
fig = original.__func__(*args, **kwargs)
299+
else: # function
300+
fig = original(*args, **kwargs)
301+
302+
# We only need to close actual Matplotlib figure objects. If
303+
# we are dealing with a figure-like object that provides
304+
# savefig but is not a real Matplotlib object, we shouldn't
305+
# try closing it here.
306+
if isinstance(fig, Figure):
307+
plt.close(fig)
308+
309+
if item.cls is not None:
310+
setattr(item.cls, item.function.__name__, item_function_wrapper)
311+
else:
312+
item.obj = item_function_wrapper

0 commit comments

Comments
 (0)