diff --git a/.gitignore b/.gitignore index 9ea28cf8520..ea1bbb4167f 100644 --- a/.gitignore +++ b/.gitignore @@ -75,4 +75,6 @@ $RECYCLE.BIN/ .hypothesis/ .pytest_cache/ sunpydata.sqlite + v/ +result_images* diff --git a/sunpy/conftest.py b/sunpy/conftest.py index 2881005a876..5675d7da645 100644 --- a/sunpy/conftest.py +++ b/sunpy/conftest.py @@ -14,7 +14,7 @@ matplotlib.use('Agg') from sunpy.tests.hash import HASH_LIBRARY_NAME -from sunpy.tests.helpers import new_hash_library, figure_test_pngfiles +from sunpy.tests.helpers import new_hash_library, test_fig_dir from sunpy.extern import six import pytest @@ -47,17 +47,11 @@ def pytest_runtest_setup(item): def pytest_unconfigure(config): - if len(figure_test_pngfiles) > 0: - tempdir = tempfile.mkdtemp(suffix="_figures") - - # Rename each PNG with the name of the corresponding test - for test_name in figure_test_pngfiles: - os.rename(figure_test_pngfiles[test_name], os.path.join(tempdir, test_name + '.png')) - + if len(new_hash_library) > 0: # Write the new hash library in JSON - hashfile = os.path.join(tempdir, HASH_LIBRARY_NAME) + hashfile = os.path.join(test_fig_dir, HASH_LIBRARY_NAME) with open(hashfile, 'w') as outfile: json.dump(new_hash_library, outfile, sort_keys=True, indent=4, separators=(',', ': ')) - print('All test files for figure hashes can be found in {0}'.format(tempdir)) + print('All images from image tests can be found in {0}'.format(test_fig_dir)) print("The corresponding hash library is {0}".format(hashfile)) diff --git a/sunpy/tests/hash.py b/sunpy/tests/hash.py index 6ad0281a082..71235f79a11 100644 --- a/sunpy/tests/hash.py +++ b/sunpy/tests/hash.py @@ -46,11 +46,18 @@ def hash_figure(figure=None, out_stream=None): figure.savefig(imgdata, format='png') - imgdata.seek(0) - buf = imgdata.read() + out = _hash_file(imgdata) if out_stream is None: imgdata.close() + return out + +def _hash_file(in_stream): + """ + Hashes an already opened file + """ + in_stream.seek(0) + buf = in_stream.read() hasher = hashlib.sha256() hasher.update(buf) return hasher.hexdigest() diff --git a/sunpy/tests/helpers.py b/sunpy/tests/helpers.py index c9cb0550ef2..8920df6cb62 100644 --- a/sunpy/tests/helpers.py +++ b/sunpy/tests/helpers.py @@ -7,6 +7,7 @@ import tempfile import platform import os +import datetime import pytest import numpy as np @@ -40,9 +41,7 @@ SKIP_ANA = False skip_windows = pytest.mark.skipif(platform.system() == 'Windows', reason="Windows") - skip_glymur = pytest.mark.skipif(SKIP_GLYMUR, reason="Glymur can not be imported") - skip_ana = pytest.mark.skipif(SKIP_ANA, reason="ANA is not available") @@ -52,19 +51,21 @@ def warnings_as_errors(request): request.addfinalizer(lambda *args: warnings.resetwarnings()) -new_hash_library = {} -figure_test_pngfiles = {} +hash_library = hash.hash_library +new_hash_library = {} +test_fig_dir = 'result_images_{:%H%M%S}'.format(datetime.datetime.now()) def figure_test(test_function): """ A decorator for a test that verifies the hash of the current figure or the returned figure, with the name of the test function as the hash identifier in the library. - A PNG is also created with a temporary filename, with the lookup stored in the - `figure_test_pngfiles` dictionary. + A PNG is also created in the 'result_image' directory, which is created + on the current path. - All such decorated tests are marked with `pytest.mark.figure` for convenient filtering. + All such decorated tests are marked with `pytest.mark.figure` for + convenient filtering. Examples -------- @@ -77,16 +78,33 @@ def test_simple_plot(): def wrapper(*args, **kwargs): if not os.path.exists(hash.HASH_LIBRARY_FILE): pytest.xfail('Could not find a figure hash library at {}'.format(hash.HASH_LIBRARY_FILE)) + + name = "{0}.{1}".format(test_function.__module__, + test_function.__name__) + # Run the test function and get the figure plt.figure() - name = "{0}.{1}".format(test_function.__module__, test_function.__name__) - pngfile = tempfile.NamedTemporaryFile(delete=False) - figure_hash = hash.hash_figure(test_function(*args, **kwargs), out_stream=pngfile) - figure_test_pngfiles[name] = pngfile.name - pngfile.close() + fig = test_function(*args, **kwargs) + if fig is None: + fig = plt.gcf() + + # Save the image that was generated + if not os.path.exists(test_fig_dir): + os.mkdir(test_fig_dir) + result_image_loc = os.path.join(test_fig_dir, '{}.png'.format(name)) + plt.savefig(result_image_loc) + plt.close() + + # Create hash + imgdata = open(result_image_loc, "rb") + figure_hash = hash._hash_file(imgdata) + imgdata.close() + new_hash_library[name] = figure_hash - if name not in hash.hash_library: + if name not in hash_library: pytest.fail("Hash not present: {0}".format(name)) - else: - assert hash.hash_library[name] == figure_hash - plt.close() + + if hash_library[name] != figure_hash: + raise RuntimeError('Figure hash does not match expected hash.\n' + 'New image generated and placed at {}'.format(result_image_loc)) + return wrapper