Skip to content

Commit bf6a0a4

Browse files
committed
Another round of test updates.
1 parent ffbd8e9 commit bf6a0a4

File tree

7 files changed

+111
-58
lines changed

7 files changed

+111
-58
lines changed

HACKING.rst

+8
Original file line numberDiff line numberDiff line change
@@ -11,3 +11,11 @@ The following vim settings may be useful::
1111

1212
setlocal cinoptions+=(0,W2,l1,h0
1313
setlocal shiftwidth=2
14+
15+
Reference style
16+
===============
17+
18+
In comments:
19+
20+
- refer to upstream issues as ``FIXME[upstream-name]: ... (#issue-id)``;
21+
- refer to specific Matplotlib tests as ``:mpltest:`test_foo.test_bar```.

ISSUES.rst

+23-12
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ Crashes
22
=======
33

44
::
5+
56
gca(); savefig("/tmp/test.cairoscript")
67

78
Seems to be due to cairo trying to call ``write`` during shutdown when the
@@ -12,33 +13,42 @@ Fix needed
1213
==========
1314

1415
test_image
16+
test_figimage0[pdf], test_figimage1[pdf], test_interp_nearest_vs_none[pdf,svg], test_rasterize_dpi[pdf,svg]
17+
Invalid dpi manipulations in vector output.
18+
1519
test_jpeg_alpha
1620
Not respecting savefig.facecolor.
1721

18-
test_interp_nearest_vs_none[pdf,svg], test_rasterize_dpi[pdf,svg]
19-
Not respecting dpi in vector output.
20-
2122
test_text
2223
test_multiline
2324
Bad multiline rendering.
2425

2526
test_text_alignment
2627
Bad alignment.
2728

29+
text_labels_and_annotations/usetex_baseline_test
30+
Bad layout of mathtext.
31+
2832
Upstream issues
2933
===============
3034

3135
Issues with Matplotlib
3236
----------------------
3337

34-
Matplotlib's software alpha compositor is incorrect (#8847). ::
35-
36-
test_image::test_image_composite_alpha[pdf,svg]
37-
3838
Matplotlib's hatching is inconsistent across backends (#10034). ::
3939

4040
test_artist::test_clipping
4141

42+
Matplotlib fails to drop the alpha channel when saving comparison failure diffs
43+
(#11075) (and the baseline images are lacking an alpha channel). ::
44+
45+
test_axes::test_log_scales[png]
46+
test_scale::test_logscale_mask[png]
47+
48+
Matplotlib's SVG backend does not implement Gouraud shading. ::
49+
50+
test_axes::test_pcolormesh[svg]
51+
4252
Matplotlib's partially transparent markers with edges are inconsistent across
4353
backends (#10035). ::
4454

@@ -48,16 +58,17 @@ Matplotlib's PDFPages is coupled too tightly with the PDF backend (#9114). ::
4858

4959
test_backend_pdf::test_composite_image, test_multipage_*
5060

51-
Matplotlib's SVG backend does not implement Gouraud shading. ::
52-
53-
test_axes::test_pcolormesh[svg]
54-
5561
Matplotlib does not write SVGs with ``image-rendering: pixelated`` (#10112). ::
5662

5763
test_backend_svg::test_noscale[svg]
5864
test_image::test_rotate_image[svg]
5965
test_tightlayout::test_tight_layout5[svg]
6066

67+
Matplotlib's software alpha compositor is incorrect (#8847). ::
68+
69+
test_image::test_image_composite_alpha[pdf,svg]
70+
71+
6172
Issues with cairo
6273
-----------------
6374

@@ -115,7 +126,7 @@ Tight bboxes are different. ::
115126

116127
test_bbox_tight::test_bbox_inches_tight_suptile_legend
117128

118-
``--infinite-tolerance`` subverts Matplotlib's test interface. ::
129+
``--tolerance`` subverts Matplotlib's test interface. ::
119130

120131
test_compare_image::*
121132

README.rst

+3-2
Original file line numberDiff line numberDiff line change
@@ -283,8 +283,9 @@ PyPI or from source.
283283

284284
Nearly all image comparison tests "fail" as the renderers are fundamentally
285285
different; currently, the intent is to manually check the diff images. Passing
286-
``--infinite-tolerance`` marks these tests as "passed" so that one can spot
287-
issues not related to rendering differences.
286+
``--tolerance=inf`` marks these tests as "passed" (while still textually
287+
reporting the image differences) so that one can spot issues not related to
288+
rendering differences.
288289

289290
Some other (non-image-comparison) tests are also known to fail (they are listed
290291
in ``ISSUES.rst``, with the relevant explanations), and automatically skipped.

lib/mplcairo/base.py

+9-7
Original file line numberDiff line numberDiff line change
@@ -118,10 +118,14 @@ def draw_tex(self, gc, x, y, s, prop, angle, ismath="TeX!", mtext=None):
118118
page = next(iter(dvi))
119119
mb = _mplcairo.MathtextBackendCairo()
120120
for x1, y1, dvifont, glyph, width in page.text:
121+
texfont = _get_tex_font_map()[dvifont.texname]
122+
if texfont.filename is None:
123+
# Not TypeError:
124+
# :mpltest:`test_backend_svg.test_missing_psfont`.
125+
raise ValueError("No font file found for {} ({!a})"
126+
.format(texfont.psname, texfont.texname))
121127
mb._render_usetex_glyph(
122-
x1, -y1,
123-
_get_tex_font_map()[dvifont.texname].filename, dvifont.size,
124-
glyph)
128+
x1, -y1, texfont.filename, dvifont.size, glyph)
125129
for x1, y1, h, w in page.boxes:
126130
mb.render_rect_filled(x1, -y1, x1 + w, -(y1 + h))
127131
mb._draw(self, x, y, angle)
@@ -212,10 +216,8 @@ def _get_cached_or_new_renderer(
212216
def get_renderer(self, *, _draw_if_new=False):
213217
return self._get_cached_or_new_renderer(
214218
GraphicsContextRendererCairo,
215-
*(np.array([self.figure.bbox.width, self.figure.bbox.height])
216-
* getattr(self, "_dpi_ratio", 1)),
217-
# Py3.4 support: use kwarg for dpi.
218-
dpi=self.figure.dpi, _draw_if_new=_draw_if_new)
219+
self.figure.bbox.width, self.figure.bbox.height, self.figure.dpi,
220+
_draw_if_new=_draw_if_new)
219221

220222
renderer = property(get_renderer) # NOTE: Needed for FigureCanvasAgg.
221223

run-mpl-test-suite.py

+61-30
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@
88

99
from argparse import ArgumentParser
1010
import os
11-
import inspect
1211
from pathlib import Path
1312
import shutil
1413
import subprocess
@@ -18,31 +17,41 @@
1817

1918
import matplotlib as mpl
2019
import matplotlib.backends.backend_agg
21-
import matplotlib.testing.compare
20+
import matplotlib.testing.decorators
2221
import mplcairo.base
2322

2423
import pytest
2524

2625

26+
_IGNORED_FAILURES = {}
27+
28+
2729
def main(argv=None):
2830
parser = ArgumentParser(
2931
description="""\
3032
Run the Matplotlib test suite, using the mplcairo backend to patch out
3133
Matplotlib's agg backend.
3234
""",
3335
epilog="Other arguments are forwarded to pytest.")
34-
parser.add_argument("--infinite-tolerance", action="store_true",
35-
help="Set image comparison tolerance to infinity.")
36+
parser.add_argument("--tolerance", type=float,
37+
help="Set image comparison tolerance.")
3638
args, rest = parser.parse_known_args(argv)
3739

38-
if args.infinite_tolerance:
39-
sig = inspect.signature(mpl.testing.compare.compare_images)
40-
def compare_images(*args, **kwargs):
41-
ba = sig.bind(*args, **kwargs)
42-
ba.arguments["tol"] = float("inf")
43-
return compare_images.__wrapped__(*ba.args, **ba.kwargs)
44-
compare_images.__wrapped__ = mpl.testing.compare.compare_images
45-
mpl.testing.compare.compare_images = compare_images
40+
if args.tolerance is not None:
41+
def _raise_on_image_difference(expected, actual, tol):
42+
cmp = mpl.testing.compare.compare_images(
43+
expected, actual, tol, in_decorator=True)
44+
if cmp:
45+
if cmp["rms"] < args.tolerance:
46+
expected = Path(expected)
47+
expected = expected.relative_to(expected.parent.parent)
48+
_IGNORED_FAILURES[expected] = cmp["rms"]
49+
else:
50+
__orig_raise_on_image_tolerance(expected, actual, tol)
51+
__orig_raise_on_image_tolerance = \
52+
mpl.testing.decorators._raise_on_image_difference
53+
mpl.testing.decorators._raise_on_image_difference = \
54+
_raise_on_image_difference
4655

4756
mplcairo.base.get_hinting_flag = mpl.backends.backend_agg.get_hinting_flag
4857
mplcairo.base.FigureCanvasAgg = \
@@ -51,8 +60,20 @@ def compare_images(*args, **kwargs):
5160
mplcairo.base.GraphicsContextRendererCairo
5261
mpl.backends.backend_agg = \
5362
sys.modules["matplotlib.backends.backend_agg"] = mplcairo.base
63+
5464
mpl.use("agg", warn=False, force=True)
55-
import matplotlib.pyplot as plt
65+
from matplotlib import pyplot as plt
66+
67+
__orig_switch_backend = plt.switch_backend
68+
def switch_backend(backend):
69+
__orig_switch_backend({
70+
"gtk3agg": "module://mplcairo.gtk",
71+
"qt5agg": "module://mplcairo.qt",
72+
"tkagg": "module://mplcairo.tk",
73+
"wxagg": "module://mplcairo.wx",
74+
}.get(backend.lower(), backend))
75+
plt.switch_backend = switch_backend
76+
5677
plt.switch_backend("agg")
5778

5879
return pytest.main([
@@ -68,13 +89,14 @@ def pytest_collection_modifyitems(session, config, items):
6889
if len(items) == 0:
6990
pytest.exit("No tests found; Matplotlib was likely installed without "
7091
"test data.")
71-
excluded_modules = {
92+
xfail_modules = {
7293
"matplotlib.tests.test_compare_images",
7394
}
74-
excluded_nodeids = {
95+
xfail_nodeids = {
7596
"matplotlib/tests/" + name for name in [
7697
"test_agg.py::test_repeated_save_with_alpha",
7798
"test_artist.py::test_cull_markers",
99+
"test_axes.py::test_log_scales[png]",
78100
"test_backend_pdf.py::test_composite_image",
79101
"test_backend_pdf.py::test_multipage_keep_empty",
80102
"test_backend_pdf.py::test_multipage_pagecount",
@@ -92,25 +114,34 @@ def pytest_collection_modifyitems(session, config, items):
92114
"test_bbox_tight.py::test_bbox_inches_tight_suptile_legend[svg]",
93115
"test_image.py::test_composite[True-1-ps- colorimage]",
94116
"test_image.py::test_composite[False-2-ps- colorimage]",
117+
"test_scale.py::test_logscale_mask[png]",
95118
"test_simplification.py::test_throw_rendering_complexity_exceeded",
96119
]
97120
}
98-
selected = []
99-
deselected = []
121+
xfails = []
100122
for item in items:
101-
if (item.module.__name__ in excluded_modules
102-
or item.nodeid in excluded_nodeids):
103-
deselected.append(item)
104-
else:
105-
selected.append(item)
106-
items[:] = selected
107-
config.hook.pytest_deselected(items=deselected)
108-
invalid_exclusions = (
109-
(excluded_modules - {item.module.__name__ for item in deselected})
110-
| (excluded_nodeids - {item.nodeid for item in deselected}))
111-
if invalid_exclusions:
112-
warnings.warn("Unused exclusions:\n {}"
113-
.format("\n ".join(sorted(invalid_exclusions))))
123+
if (item.module.__name__ in xfail_modules
124+
or item.nodeid in xfail_nodeids):
125+
xfails.append(item)
126+
item.add_marker(
127+
pytest.mark.xfail(reason="Test known to fail with mplcairo"))
128+
invalid_xfails = (
129+
(xfail_modules - {item.module.__name__ for item in xfails})
130+
| (xfail_nodeids - {item.nodeid for item in xfails}))
131+
if invalid_xfails:
132+
warnings.warn("Unused xfails:\n {}"
133+
.format("\n ".join(sorted(invalid_xfails))))
134+
135+
136+
def pytest_terminal_summary(terminalreporter, exitstatus):
137+
write = terminalreporter.write
138+
if _IGNORED_FAILURES:
139+
write("\n"
140+
"Ignored the following image comparison failures:\n"
141+
"RMS\texpected\n")
142+
for rms, expected in sorted(
143+
((v, k) for k, v in _IGNORED_FAILURES.items()), reverse=True):
144+
write("{:#.2f}\t{}\n".format(rms, expected))
114145

115146

116147
if __name__ == "__main__":

src/_pattern_cache.cpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -168,7 +168,7 @@ void PatternCache::mask(
168168
// matrix. 1x threshold will be added by the patterns_ cache.
169169
// If the entire object is within the threshold of the origin in either
170170
// direction, then draw it directly, as doing otherwise would be highly
171-
// inaccurate (see e.g. test_mplot3d.test_quiver3d).
171+
// inaccurate (see e.g. :mpltest:`test_mplot3d.test_quiver3d`).
172172
auto const& bbox = it_bboxes->second;
173173
// Here, gcc 7.2 fails to extend the lifetime of the temporaries whose
174174
// references are bound to constant *references* (various issues on bugzilla;

src/_util.cpp

+6-6
Original file line numberDiff line numberDiff line change
@@ -157,9 +157,9 @@ AdditionalState& get_additional_state(cairo_t* cr)
157157
// if desired.
158158
// FIXME[cairo]: cairo requires coordinates to fit within a 24-bit signed
159159
// integer (https://bugs.freedesktop.org/show_bug.cgi?id=20091 and
160-
// test_simplification.test_overflow). We simply clamp the values in the
161-
// general case (with codes) -- proper handling would involve clipping
162-
// of polygons and of Beziers -- and use a simple clippling algorithm
160+
// :mpltest:`test_simplification.test_overflow`). We simply clamp the
161+
// values in the general case (with codes) -- proper handling would involve
162+
// clipping of polygons and of Beziers -- and use a simple clippling algorithm
163163
// (Cohen-Sutherland) in the simple (codeless) case as we expect most segments
164164
// to be within the clip rectangle -- cairo will run its own clipping later
165165
// anyways.
@@ -267,9 +267,9 @@ void load_path_exact(
267267
}
268268
break;
269269
// The semantics of nonfinite control points are tested in
270-
// test_simplification.test_simplify_curve: if the last point is finite,
271-
// it sets the current point for the next curve; otherwise, a new
272-
// sub-path is created.
270+
// :mpltest:`test_simplification.test_simplify_curve`: if the last point
271+
// is finite, it sets the current point for the next curve; otherwise, a
272+
// new sub-path is created.
273273
case PathCode::CURVE3: {
274274
auto x1 = vertices(i + 1, 0), y1 = vertices(i + 1, 1);
275275
cairo_matrix_transform_point(matrix, &x1, &y1);

0 commit comments

Comments
 (0)