1- About
2- -----
3-
41This is a plugin to facilitate image comparison for
52`Matplotlib <http://www.matplotlib.org >`__ figures in pytest.
63
@@ -9,361 +6,3 @@ generated image, and the RMS of the residual is compared to a
96user-specified tolerance. If the residual is too large, the test will
107fail (this is implemented using helper functions from
118``matplotlib.testing ``).
12-
13- For more information on how to write tests to do this, see the **Using **
14- section below.
15-
16- Installing
17- ----------
18-
19- This plugin is compatible with Python 3.6 and later, and
20- requires `pytest <http://pytest.org >`__ and
21- `matplotlib <http://www.matplotlib.org >`__ to be installed.
22-
23- To install, you can do::
24-
25- pip install pytest-mpl
26-
27- You can check that the plugin is registered with pytest by doing::
28-
29- pytest --version
30-
31- which will show a list of plugins:
32-
33- ::
34-
35- This is pytest version 2.7.1, imported from ...
36- setuptools registered plugins:
37- pytest-mpl-0.1 at ...
38-
39- Using
40- -----
41-
42- With Baseline Images
43- ^^^^^^^^^^^^^^^^^^^^
44-
45- To use, you simply need to mark the function where you want to compare
46- images using ``@pytest.mark.mpl_image_compare ``, and make sure that the
47- function returns a Matplotlib figure (or any figure object that has a
48- ``savefig `` method):
49-
50- .. code :: python
51-
52- import pytest
53- import matplotlib.pyplot as plt
54-
55- @pytest.mark.mpl_image_compare
56- def test_succeeds ():
57- fig = plt.figure()
58- ax = fig.add_subplot(1 ,1 ,1 )
59- ax.plot([1 ,2 ,3 ])
60- return fig
61-
62- To generate the baseline images, run the tests with the
63- ``--mpl-generate-path `` option with the name of the directory where the
64- generated images should be placed::
65-
66- pytest --mpl-generate-path=baseline
67-
68- If the directory does not exist, it will be created. The directory will
69- be interpreted as being relative to where you are running ``pytest ``.
70- Once you are happy with the generated images, you should move them to a
71- sub-directory called ``baseline `` relative to the test files (this name
72- is configurable, see below). You can also generate the baseline image
73- directly in the right directory.
74-
75- With a Hash Library
76- ^^^^^^^^^^^^^^^^^^^
77-
78- Instead of comparing to baseline images, you can instead compare against a JSON
79- library of SHA-256 hashes. This has the advantage of not having to check baseline
80- images into the repository with the tests, or download them from a remote
81- source.
82-
83- The hash library can be generated with
84- ``--mpl-generate-hash-library=path_to_file.json ``. The hash library to be used
85- can either be specified via the ``--mpl-hash-library= `` command line argument,
86- or via the ``hash_library= `` keyword argument to the
87- ``@pytest.mark.mpl_image_compare `` decorator.
88-
89- When generating a hash library, the tests will also be run as usual against the
90- existing hash library specified by ``--mpl-hash-library `` or the keyword argument.
91- However, generating baseline images will always result in the tests being skipped.
92-
93- Hybrid Mode: Hashes and Images
94- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
95-
96- It is possible to configure both hashes and baseline images. In this scenario
97- only the hash comparison can determine the test result. If the hash comparison
98- fails, the test will fail, however a comparison to the baseline image will be
99- carried out so the actual difference can be seen. If the hash comparison passes,
100- the comparison to the baseline image is skipped (unless **results always ** is
101- configured).
102-
103- This is especially useful if the baseline images are external to the repository
104- containing the tests, and are accessed via HTTP. In this situation, if the hashes
105- match, the baseline images won't be retrieved, saving time and bandwidth. Also, it
106- allows the tests to be modified and the hashes updated to reflect the changes
107- without having to modify the external images.
108-
109-
110- Running Tests
111- ^^^^^^^^^^^^^
112-
113- Once tests are written with baseline images, a hash library, or both to compare
114- against, the tests can be run with::
115-
116- pytest --mpl
117-
118- and the tests will pass if the images are the same. If you omit the
119- ``--mpl `` option, the tests will run but will only check that the code
120- runs, without checking the output images.
121-
122- If pytest-mpl is not installed, the image comparison tests will cause pytest
123- to show a warning, ``PytestReturnNotNoneWarning ``. Installing pytest-mpl will
124- solve this issue. Alternativly, the image comparison tests can be deselected
125- by running pytest with ``-m "not mpl_image_compare" ``.
126-
127-
128- Generating a Test Summary
129- ^^^^^^^^^^^^^^^^^^^^^^^^^
130-
131- By specifying the ``--mpl-generate-summary=html `` CLI argument, a HTML summary
132- page will be generated showing the test result, log entry and generated result
133- image. When in the (default) image comparison mode, the baseline image, diff
134- image and RMS (if any), and tolerance of each test will also be shown.
135- When in the hash comparison mode, the baseline hash and result hash will
136- also be shown. When in hybrid mode, all of these are included.
137-
138- When generating a HTML summary, the ``--mpl-results-always `` option is
139- automatically applied (see section below). Therefore images for passing
140- tests will also be shown.
141-
142- +---------------+---------------+---------------+
143- | |html all | | |html filter | | |html result | |
144- +---------------+---------------+---------------+
145-
146- As well as ``html ``, ``basic-html `` can be specified for an alternative HTML
147- summary which does not rely on JavaScript or external resources. A ``json ``
148- summary can also be saved. Multiple options can be specified comma-separated.
149-
150- Options
151- -------
152-
153- Tolerance
154- ^^^^^^^^^
155-
156- The RMS tolerance for the image comparison (which defaults to 2) can be
157- specified in the ``mpl_image_compare `` decorator with the ``tolerance ``
158- argument:
159-
160- .. code :: python
161-
162- @pytest.mark.mpl_image_compare (tolerance = 20 )
163- def test_image ():
164- ...
165-
166- Savefig options
167- ^^^^^^^^^^^^^^^
168-
169- You can pass keyword arguments to ``savefig `` by using
170- ``savefig_kwargs `` in the ``mpl_image_compare `` decorator:
171-
172- .. code :: python
173-
174- @pytest.mark.mpl_image_compare (savefig_kwargs = {' dpi' :300 })
175- def test_image ():
176- ...
177-
178- Baseline images
179- ^^^^^^^^^^^^^^^
180-
181- The baseline directory (which defaults to ``baseline `` ) and the
182- filename of the plot (which defaults to the name of the test with a
183- ``.png `` suffix) can be customized with the ``baseline_dir `` and
184- ``filename `` arguments in the ``mpl_image_compare `` decorator:
185-
186- .. code :: python
187-
188- @pytest.mark.mpl_image_compare (baseline_dir = ' baseline_images' ,
189- filename = ' other_name.png' )
190- def test_image ():
191- ...
192-
193- The baseline directory in the decorator above will be interpreted as
194- being relative to the test file. Note that the baseline directory can
195- also be a URL (which should start with ``http:// `` or ``https:// `` and
196- end in a slash). If you want to specify mirrors, set ``baseline_dir `` to
197- a comma-separated list of URLs (real commas in the URL should be encoded
198- as ``%2C ``).
199-
200- Finally, you can also set a custom baseline directory globally when
201- running tests by running ``pytest `` with::
202-
203- pytest --mpl --mpl-baseline-path=baseline_images
204-
205- This directory will be interpreted as being relative to where pytest
206- is run. However, if the ``--mpl-baseline-relative `` option is also
207- included, this directory will be interpreted as being relative to
208- the current test directory.
209- In addition, if both this option and the ``baseline_dir ``
210- option in the ``mpl_image_compare `` decorator are used, the one in the
211- decorator takes precedence.
212-
213- Results always
214- ^^^^^^^^^^^^^^
215-
216- By default, result images are only saved for tests that fail.
217- Passing ``--mpl-results-always `` to pytest will force result images
218- to be saved for all tests, even for tests that pass.
219-
220- When in **hybrid mode **, even if a test passes hash comparison,
221- a comparison to the baseline image will also be carried out,
222- with the baseline image and diff image (if image comparison fails)
223- saved for all tests. This secondary comparison will not affect
224- the success status of the test.
225-
226- This option is useful for always *comparing * the result images against
227- the baseline images, while only *assessing * the tests against the
228- hash library.
229- If you only update your baseline images after merging a PR, this
230- option means that the generated summary will always show how the
231- PR affects the baseline images, with the success status of each
232- test (based on the hash library) also shown in the generated
233- summary. This option is applied automatically when generating
234- a HTML summary.
235-
236- When the ``--mpl-results-always `` option is active, and some hash
237- comparison tests are performed, a hash library containing all the
238- result hashes will also be saved to the root of the results directory.
239- The filename will be extracted from ``--mpl-generate-hash-library ``,
240- ``--mpl-hash-library `` or ``hash_library= `` in that order.
241-
242- Base style
243- ^^^^^^^^^^
244-
245- By default, tests will be run using the Matplotlib 'classic' style
246- (ignoring any locally defined RC parameters). This can be overridden by
247- using the ``style `` argument:
248-
249- .. code :: python
250-
251- @pytest.mark.mpl_image_compare (style = ' fivethirtyeight' )
252- def test_image ():
253- ...
254-
255- Package version dependencies
256- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
257- Different versions of Matplotlib and FreeType may result in slightly
258- different images. When testing on multiple platforms or as part of a
259- pipeline, it is important to ensure that the versions of these
260- packages match the versions used to generate the images used for
261- comparison. It can be useful to pin versions of Matplotlib and FreeType
262- so as to avoid automatic updates that fail tests.
263-
264- Removing text
265- ^^^^^^^^^^^^^
266-
267- If you are running a test for which you are not interested in comparing
268- the text labels, you can use the ``remove_text `` argument to the
269- decorator:
270-
271- .. code :: python
272-
273- @pytest.mark.mpl_image_compare (remove_text = True )
274- def test_image ():
275- ...
276-
277- This will make the test insensitive to changes in e.g. the freetype
278- library.
279-
280- Supported formats and deterministic output
281- ------------------------------------------
282-
283- By default, pytest-mpl will save and compare figures in PNG format. However,
284- it is possible to set the format to use by setting e.g. ``savefig_kwargs={'format': 'pdf'} ``
285- in ``mpl_image_compare ``. Supported formats are ``'eps' ``, ``'pdf' ``, ``'png' ``, and ``'svg' ``.
286- Note that Ghostscript is required to be installed for comparing PDF and EPS figures, while
287- Inkscape is required for SVG comparison.
288-
289- By default, Matplotlib does not produce deterministic output that will have a
290- consistent hash every time it is run, or over different Matplotlib versions. In
291- order to enforce that the output is deterministic, you can set the ``deterministic ``
292- keyword argument in ``mpl_image_compare ``:
293-
294- .. code :: python
295-
296- @pytest.mark.mpl_image_compare (deterministic = True )
297-
298- This does a number of things such as e.g., setting the creation date in the
299- metadata to be constant, and avoids hard-coding the Matplotlib in the files.
300-
301- Test failure example
302- --------------------
303-
304- If the images produced by the tests are correct, then the test will
305- pass, but if they are not, the test will fail with a message similar to
306- the following::
307-
308- E Exception: Error: Image files did not match.
309- E RMS Value: 142.2287807767823
310- E Expected:
311- E /var/folders/zy/t1l3sx310d3d6p0kyxqzlrnr0000gr/T/tmp4h4oxr7y/baseline-coords_overlay_auto_coord_meta.png
312- E Actual:
313- E /var/folders/zy/t1l3sx310d3d6p0kyxqzlrnr0000gr/T/tmp4h4oxr7y/coords_overlay_auto_coord_meta.png
314- E Difference:
315- E /var/folders/zy/t1l3sx310d3d6p0kyxqzlrnr0000gr/T/tmp4h4oxr7y/coords_overlay_auto_coord_meta-failed-diff.png
316- E Tolerance:
317- E 10
318-
319- The image paths included in the exception are then available for
320- inspection:
321-
322- +----------------+----------------+-------------+
323- | Expected | Actual | Difference |
324- +================+================+=============+
325- | |expected | | |actual | | |diff | |
326- +----------------+----------------+-------------+
327-
328- In this case, the differences are very clear, while in some cases it may
329- be necessary to use the difference image, or blink the expected and
330- actual images, in order to see what changed.
331-
332- The default tolerance is 2, which is very strict. In some cases, you may
333- want to relax this to account for differences in fonts across different
334- systems.
335-
336- By default, the expected, actual and difference files are written to a
337- temporary directory with a non-deterministic path. If you want to instead
338- write them to a specific directory, you can use::
339-
340- pytest --mpl --mpl-results-path=results
341-
342- The ``results `` directory will then contain one sub-directory per test, and each
343- sub-directory will contain the three files mentioned above. If you are using a
344- continuous integration service, you can then use the option to upload artifacts
345- to upload these results to somewhere where you can view them. For more
346- information, see:
347-
348- * `Uploading artifacts on Travis-CI <https://docs.travis-ci.com/user/uploading-artifacts/ >`_
349- * `Build Artifacts (CircleCI) <https://circleci.com/docs/1.0/build-artifacts/ >`_
350- * `Packaging Artifacts (AppVeyor) <https://www.appveyor.com/docs/packaging-artifacts/ >`_
351-
352- Running the tests for pytest-mpl
353- --------------------------------
354-
355- If you are contributing some changes and want to run the tests, first
356- install the latest version of the plugin then do::
357-
358- cd tests
359- pytest --mpl
360-
361- The reason for having to install the plugin first is to ensure that the
362- plugin is correctly loaded as part of the test suite.
363-
364- .. |html all | image :: images/html_all.png
365- .. |html filter | image :: images/html_filter.png
366- .. |html result | image :: images/html_result.png
367- .. |expected | image :: images/baseline-coords_overlay_auto_coord_meta.png
368- .. |actual | image :: images/coords_overlay_auto_coord_meta.png
369- .. |diff | image :: images/coords_overlay_auto_coord_meta-failed-diff.png
0 commit comments