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 5ed01ab

Browse filesBrowse files
committed
Use test cache for test result images too.
For image comparison tests in svg/pdf/ps formats, the result images are converted to png for comparison. Previously the conversion results were cached for the baseline images, but not for the test-generated images (because of non-deterministic svg/pdf/etc. results, due to hash-salting, dict ordering, etc.). Now that the test-generated images are generally deterministic, we can enable the cache for baseline images as well. This speeds up `pytest -k '[svg]'` by ~30% (81s initially -> 55s on a seeded cache) and `pytest -k '[pdf]'` by ~10% (62s -> 55s) (there are too few (e)ps image comparison tests to see an effect). Also add logging regarding the cache which may help troubleshooting determinacy problems. A simple cache eviction mechanism prevents the cache from growing without bounds, limiting it to 2x the size of the baseline_images directory. This is a much simpler version of PR7764, which added more sophisticated reporting of cache hits and misses and cache eviction.
1 parent db7cd7e commit 5ed01ab
Copy full SHA for 5ed01ab

File tree

Expand file treeCollapse file tree

1 file changed

+35
-2
lines changed
Filter options
Expand file treeCollapse file tree

1 file changed

+35
-2
lines changed

‎lib/matplotlib/testing/compare.py

Copy file name to clipboardExpand all lines: lib/matplotlib/testing/compare.py
+35-2Lines changed: 35 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
11
"""
22
Provides a collection of utilities for comparing (image) results.
3-
43
"""
54

65
import atexit
6+
import functools
77
import hashlib
8+
import logging
89
import os
910
from pathlib import Path
1011
import re
@@ -19,6 +20,8 @@
1920
import matplotlib as mpl
2021
from matplotlib.testing.exceptions import ImageComparisonFailure
2122

23+
_log = logging.getLogger(__name__)
24+
2225
__all__ = ['compare_images', 'comparable_formats']
2326

2427

@@ -281,21 +284,51 @@ def convert(filename, cache):
281284
cache_dir = None
282285

283286
if cache_dir is not None:
287+
_register_conversion_cache_cleaner_once()
284288
hash_value = get_file_hash(filename)
285289
new_ext = os.path.splitext(newname)[1]
286290
cached_file = os.path.join(cache_dir, hash_value + new_ext)
287291
if os.path.exists(cached_file):
292+
_log.debug("For %s: reusing cached conversion.", filename)
288293
shutil.copyfile(cached_file, newname)
289294
return newname
290295

296+
_log.debug("For %s: converting to png.", filename)
291297
converter[extension](filename, newname)
292298

293299
if cache_dir is not None:
300+
_log.debug("For %s: caching conversion result.", filename)
294301
shutil.copyfile(newname, cached_file)
295302

296303
return newname
297304

298305

306+
def _clean_conversion_cache():
307+
# This will actually ignore mpl_toolkits baseline images, but they're
308+
# relatively small.
309+
baseline_images_size = sum(
310+
path.stat().st_size
311+
for path in Path(mpl.__file__).parent.glob("**/baseline_images/**/*"))
312+
# 2x: one full copy of baselines, and one full copy of test results
313+
# (actually an overestimate: we don't convert png baselines and results).
314+
max_cache_size = 2 * baseline_images_size
315+
# Reduce cache until it fits.
316+
cache_stat = {
317+
path: path.stat() for path in Path(get_cache_dir()).glob("*")}
318+
cache_size = sum(stat.st_size for stat in cache_stat.values())
319+
paths_by_atime = sorted( # Oldest at the end.
320+
cache_stat, key=lambda path: cache_stat[path].st_atime, reverse=True)
321+
while cache_size > max_cache_size:
322+
path = paths_by_atime.pop()
323+
cache_size -= cache_stat[path].st_size
324+
path.unlink()
325+
326+
327+
@functools.lru_cache() # Ensure this is only registered once.
328+
def _register_conversion_cache_cleaner_once():
329+
atexit.register(_clean_conversion_cache)
330+
331+
299332
def crop_to_same(actual_path, actual_image, expected_path, expected_image):
300333
# clip the images to the same size -- this is useful only when
301334
# comparing eps to pdf
@@ -382,7 +415,7 @@ def compare_images(expected, actual, tol, in_decorator=False):
382415
raise IOError('Baseline image %r does not exist.' % expected)
383416
extension = expected.split('.')[-1]
384417
if extension != 'png':
385-
actual = convert(actual, cache=False)
418+
actual = convert(actual, cache=True)
386419
expected = convert(expected, cache=True)
387420

388421
# open the image files and remove the alpha channel (if it exists)

0 commit comments

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