From 9edc946bd7ea2730c95db091804e4472fe826a59 Mon Sep 17 00:00:00 2001 From: Conor MacBride Date: Wed, 5 Apr 2023 20:43:23 +0100 Subject: [PATCH] Migrate docs from README to website --- README.rst | 361 ------------------ docs/configuration.rst | 21 + ...aseline-coords_overlay_auto_coord_meta.png | Bin 27120 -> 0 bytes ...ds_overlay_auto_coord_meta-failed-diff.png | Bin 9353 -> 0 bytes images/coords_overlay_auto_coord_meta.png | Bin 23944 -> 0 bytes images/html_all.png | Bin 61539 -> 0 bytes images/html_filter.png | Bin 57997 -> 0 bytes images/html_result.png | Bin 57638 -> 0 bytes 8 files changed, 21 insertions(+), 361 deletions(-) delete mode 100644 images/baseline-coords_overlay_auto_coord_meta.png delete mode 100644 images/coords_overlay_auto_coord_meta-failed-diff.png delete mode 100644 images/coords_overlay_auto_coord_meta.png delete mode 100644 images/html_all.png delete mode 100644 images/html_filter.png delete mode 100644 images/html_result.png diff --git a/README.rst b/README.rst index a4057557..a521e96f 100644 --- a/README.rst +++ b/README.rst @@ -1,6 +1,3 @@ -About ------ - This is a plugin to facilitate image comparison for `Matplotlib `__ figures in pytest. @@ -9,361 +6,3 @@ generated image, and the RMS of the residual is compared to a user-specified tolerance. If the residual is too large, the test will fail (this is implemented using helper functions from ``matplotlib.testing``). - -For more information on how to write tests to do this, see the **Using** -section below. - -Installing ----------- - -This plugin is compatible with Python 3.6 and later, and -requires `pytest `__ and -`matplotlib `__ to be installed. - -To install, you can do:: - - pip install pytest-mpl - -You can check that the plugin is registered with pytest by doing:: - - pytest --version - -which will show a list of plugins: - -:: - - This is pytest version 2.7.1, imported from ... - setuptools registered plugins: - pytest-mpl-0.1 at ... - -Using ------ - -With Baseline Images -^^^^^^^^^^^^^^^^^^^^ - -To use, you simply need to mark the function where you want to compare -images using ``@pytest.mark.mpl_image_compare``, and make sure that the -function returns a Matplotlib figure (or any figure object that has a -``savefig`` method): - -.. code:: python - - import pytest - import matplotlib.pyplot as plt - - @pytest.mark.mpl_image_compare - def test_succeeds(): - fig = plt.figure() - ax = fig.add_subplot(1,1,1) - ax.plot([1,2,3]) - return fig - -To generate the baseline images, run the tests with the -``--mpl-generate-path`` option with the name of the directory where the -generated images should be placed:: - - pytest --mpl-generate-path=baseline - -If the directory does not exist, it will be created. The directory will -be interpreted as being relative to where you are running ``pytest``. -Once you are happy with the generated images, you should move them to a -sub-directory called ``baseline`` relative to the test files (this name -is configurable, see below). You can also generate the baseline image -directly in the right directory. - -With a Hash Library -^^^^^^^^^^^^^^^^^^^ - -Instead of comparing to baseline images, you can instead compare against a JSON -library of SHA-256 hashes. This has the advantage of not having to check baseline -images into the repository with the tests, or download them from a remote -source. - -The hash library can be generated with -``--mpl-generate-hash-library=path_to_file.json``. The hash library to be used -can either be specified via the ``--mpl-hash-library=`` command line argument, -or via the ``hash_library=`` keyword argument to the -``@pytest.mark.mpl_image_compare`` decorator. - -When generating a hash library, the tests will also be run as usual against the -existing hash library specified by ``--mpl-hash-library`` or the keyword argument. -However, generating baseline images will always result in the tests being skipped. - -Hybrid Mode: Hashes and Images -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -It is possible to configure both hashes and baseline images. In this scenario -only the hash comparison can determine the test result. If the hash comparison -fails, the test will fail, however a comparison to the baseline image will be -carried out so the actual difference can be seen. If the hash comparison passes, -the comparison to the baseline image is skipped (unless **results always** is -configured). - -This is especially useful if the baseline images are external to the repository -containing the tests, and are accessed via HTTP. In this situation, if the hashes -match, the baseline images won't be retrieved, saving time and bandwidth. Also, it -allows the tests to be modified and the hashes updated to reflect the changes -without having to modify the external images. - - -Running Tests -^^^^^^^^^^^^^ - -Once tests are written with baseline images, a hash library, or both to compare -against, the tests can be run with:: - - pytest --mpl - -and the tests will pass if the images are the same. If you omit the -``--mpl`` option, the tests will run but will only check that the code -runs, without checking the output images. - -If pytest-mpl is not installed, the image comparison tests will cause pytest -to show a warning, ``PytestReturnNotNoneWarning``. Installing pytest-mpl will -solve this issue. Alternativly, the image comparison tests can be deselected -by running pytest with ``-m "not mpl_image_compare"``. - - -Generating a Test Summary -^^^^^^^^^^^^^^^^^^^^^^^^^ - -By specifying the ``--mpl-generate-summary=html`` CLI argument, a HTML summary -page will be generated showing the test result, log entry and generated result -image. When in the (default) image comparison mode, the baseline image, diff -image and RMS (if any), and tolerance of each test will also be shown. -When in the hash comparison mode, the baseline hash and result hash will -also be shown. When in hybrid mode, all of these are included. - -When generating a HTML summary, the ``--mpl-results-always`` option is -automatically applied (see section below). Therefore images for passing -tests will also be shown. - -+---------------+---------------+---------------+ -| |html all| | |html filter| | |html result| | -+---------------+---------------+---------------+ - -As well as ``html``, ``basic-html`` can be specified for an alternative HTML -summary which does not rely on JavaScript or external resources. A ``json`` -summary can also be saved. Multiple options can be specified comma-separated. - -Options -------- - -Tolerance -^^^^^^^^^ - -The RMS tolerance for the image comparison (which defaults to 2) can be -specified in the ``mpl_image_compare`` decorator with the ``tolerance`` -argument: - -.. code:: python - - @pytest.mark.mpl_image_compare(tolerance=20) - def test_image(): - ... - -Savefig options -^^^^^^^^^^^^^^^ - -You can pass keyword arguments to ``savefig`` by using -``savefig_kwargs`` in the ``mpl_image_compare`` decorator: - -.. code:: python - - @pytest.mark.mpl_image_compare(savefig_kwargs={'dpi':300}) - def test_image(): - ... - -Baseline images -^^^^^^^^^^^^^^^ - -The baseline directory (which defaults to ``baseline`` ) and the -filename of the plot (which defaults to the name of the test with a -``.png`` suffix) can be customized with the ``baseline_dir`` and -``filename`` arguments in the ``mpl_image_compare`` decorator: - -.. code:: python - - @pytest.mark.mpl_image_compare(baseline_dir='baseline_images', - filename='other_name.png') - def test_image(): - ... - -The baseline directory in the decorator above will be interpreted as -being relative to the test file. Note that the baseline directory can -also be a URL (which should start with ``http://`` or ``https://`` and -end in a slash). If you want to specify mirrors, set ``baseline_dir`` to -a comma-separated list of URLs (real commas in the URL should be encoded -as ``%2C``). - -Finally, you can also set a custom baseline directory globally when -running tests by running ``pytest`` with:: - - pytest --mpl --mpl-baseline-path=baseline_images - -This directory will be interpreted as being relative to where pytest -is run. However, if the ``--mpl-baseline-relative`` option is also -included, this directory will be interpreted as being relative to -the current test directory. -In addition, if both this option and the ``baseline_dir`` -option in the ``mpl_image_compare`` decorator are used, the one in the -decorator takes precedence. - -Results always -^^^^^^^^^^^^^^ - -By default, result images are only saved for tests that fail. -Passing ``--mpl-results-always`` to pytest will force result images -to be saved for all tests, even for tests that pass. - -When in **hybrid mode**, even if a test passes hash comparison, -a comparison to the baseline image will also be carried out, -with the baseline image and diff image (if image comparison fails) -saved for all tests. This secondary comparison will not affect -the success status of the test. - -This option is useful for always *comparing* the result images against -the baseline images, while only *assessing* the tests against the -hash library. -If you only update your baseline images after merging a PR, this -option means that the generated summary will always show how the -PR affects the baseline images, with the success status of each -test (based on the hash library) also shown in the generated -summary. This option is applied automatically when generating -a HTML summary. - -When the ``--mpl-results-always`` option is active, and some hash -comparison tests are performed, a hash library containing all the -result hashes will also be saved to the root of the results directory. -The filename will be extracted from ``--mpl-generate-hash-library``, -``--mpl-hash-library`` or ``hash_library=`` in that order. - -Base style -^^^^^^^^^^ - -By default, tests will be run using the Matplotlib 'classic' style -(ignoring any locally defined RC parameters). This can be overridden by -using the ``style`` argument: - -.. code:: python - - @pytest.mark.mpl_image_compare(style='fivethirtyeight') - def test_image(): - ... - -Package version dependencies -^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -Different versions of Matplotlib and FreeType may result in slightly -different images. When testing on multiple platforms or as part of a -pipeline, it is important to ensure that the versions of these -packages match the versions used to generate the images used for -comparison. It can be useful to pin versions of Matplotlib and FreeType -so as to avoid automatic updates that fail tests. - -Removing text -^^^^^^^^^^^^^ - -If you are running a test for which you are not interested in comparing -the text labels, you can use the ``remove_text`` argument to the -decorator: - -.. code:: python - - @pytest.mark.mpl_image_compare(remove_text=True) - def test_image(): - ... - -This will make the test insensitive to changes in e.g. the freetype -library. - -Supported formats and deterministic output ------------------------------------------- - -By default, pytest-mpl will save and compare figures in PNG format. However, -it is possible to set the format to use by setting e.g. ``savefig_kwargs={'format': 'pdf'}`` -in ``mpl_image_compare``. Supported formats are ``'eps'``, ``'pdf'``, ``'png'``, and ``'svg'``. -Note that Ghostscript is required to be installed for comparing PDF and EPS figures, while -Inkscape is required for SVG comparison. - -By default, Matplotlib does not produce deterministic output that will have a -consistent hash every time it is run, or over different Matplotlib versions. In -order to enforce that the output is deterministic, you can set the ``deterministic`` -keyword argument in ``mpl_image_compare``: - -.. code:: python - - @pytest.mark.mpl_image_compare(deterministic=True) - -This does a number of things such as e.g., setting the creation date in the -metadata to be constant, and avoids hard-coding the Matplotlib in the files. - -Test failure example --------------------- - -If the images produced by the tests are correct, then the test will -pass, but if they are not, the test will fail with a message similar to -the following:: - - E Exception: Error: Image files did not match. - E RMS Value: 142.2287807767823 - E Expected: - E /var/folders/zy/t1l3sx310d3d6p0kyxqzlrnr0000gr/T/tmp4h4oxr7y/baseline-coords_overlay_auto_coord_meta.png - E Actual: - E /var/folders/zy/t1l3sx310d3d6p0kyxqzlrnr0000gr/T/tmp4h4oxr7y/coords_overlay_auto_coord_meta.png - E Difference: - E /var/folders/zy/t1l3sx310d3d6p0kyxqzlrnr0000gr/T/tmp4h4oxr7y/coords_overlay_auto_coord_meta-failed-diff.png - E Tolerance: - E 10 - -The image paths included in the exception are then available for -inspection: - -+----------------+----------------+-------------+ -| Expected | Actual | Difference | -+================+================+=============+ -| |expected| | |actual| | |diff| | -+----------------+----------------+-------------+ - -In this case, the differences are very clear, while in some cases it may -be necessary to use the difference image, or blink the expected and -actual images, in order to see what changed. - -The default tolerance is 2, which is very strict. In some cases, you may -want to relax this to account for differences in fonts across different -systems. - -By default, the expected, actual and difference files are written to a -temporary directory with a non-deterministic path. If you want to instead -write them to a specific directory, you can use:: - - pytest --mpl --mpl-results-path=results - -The ``results`` directory will then contain one sub-directory per test, and each -sub-directory will contain the three files mentioned above. If you are using a -continuous integration service, you can then use the option to upload artifacts -to upload these results to somewhere where you can view them. For more -information, see: - -* `Uploading artifacts on Travis-CI `_ -* `Build Artifacts (CircleCI) `_ -* `Packaging Artifacts (AppVeyor) `_ - -Running the tests for pytest-mpl --------------------------------- - -If you are contributing some changes and want to run the tests, first -install the latest version of the plugin then do:: - - cd tests - pytest --mpl - -The reason for having to install the plugin first is to ensure that the -plugin is correctly loaded as part of the test suite. - -.. |html all| image:: images/html_all.png -.. |html filter| image:: images/html_filter.png -.. |html result| image:: images/html_result.png -.. |expected| image:: images/baseline-coords_overlay_auto_coord_meta.png -.. |actual| image:: images/coords_overlay_auto_coord_meta.png -.. |diff| image:: images/coords_overlay_auto_coord_meta-failed-diff.png diff --git a/docs/configuration.rst b/docs/configuration.rst index 7bc41a13..ccb81e34 100644 --- a/docs/configuration.rst +++ b/docs/configuration.rst @@ -131,6 +131,27 @@ decorator: This will make the test insensitive to changes in e.g. the freetype library. +Supported formats and deterministic output +------------------------------------------ + +By default, pytest-mpl will save and compare figures in PNG format. However, +it is possible to set the format to use by setting e.g. ``savefig_kwargs={'format': 'pdf'}`` +in ``mpl_image_compare``. Supported formats are ``'eps'``, ``'pdf'``, ``'png'``, and ``'svg'``. +Note that Ghostscript is required to be installed for comparing PDF and EPS figures, while +Inkscape is required for SVG comparison. + +By default, Matplotlib does not produce deterministic output that will have a +consistent hash every time it is run, or over different Matplotlib versions. In +order to enforce that the output is deterministic, you can set the ``deterministic`` +keyword argument in ``mpl_image_compare``: + +.. code:: python + + @pytest.mark.mpl_image_compare(deterministic=True) + +This does a number of things such as e.g., setting the creation date in the +metadata to be constant, and avoids hard-coding the Matplotlib in the files. + Test failure example -------------------- diff --git a/images/baseline-coords_overlay_auto_coord_meta.png b/images/baseline-coords_overlay_auto_coord_meta.png deleted file mode 100644 index 06970ddd7d466dec9c0b3a680c1918358679188a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 27120 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 diff --git a/images/coords_overlay_auto_coord_meta-failed-diff.png b/images/coords_overlay_auto_coord_meta-failed-diff.png deleted file mode 100644 index 0d1b7e2dc242d33a014a6dca5fbeaec2ae8fca56..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 9353 zcmd6NWmr^g+wK}llvY8I8YD!K5D=sX=@5{Pp&mkz5&>a=p;SVV7)m82rMsCKN;)KD z012gGfT2g=0ruj3f9zlT+kd}x95ZVj>%Q*3>O9vSrKh7tbM5vu003w-)RpxC01|ik zqoe@egkU8Gz#Ey@6AeR3@Cu}~j|2cHprNd2=$E!ND;LdZl0n?HmaCF2`qKGL#?1J) zjhmwV2OUSj`ZwK7k1HJ{CRy5eOvR%F#o7k0B~-MN*-@#xwoypz@kq2sb+@xVNd9aS z9e$O<{`#Ap8`KjOZQfL)mY z1kfA1SZ{^^A)a?a03ezk1^}v*Pypa2qX$A5NGO3;N(dQX^A;chM4kW;fSK!mp;(w; z;Qai-Sgz|t72o0XeFI|&$}r8tuk6omF3XPw&X*h3>7+Z9uO^`bkN1*s!|5_6F6nlv zfMS^lHLu&;-+aj`TjoCEnV`cWHlhFfu*1((BP`(*AA3hd@qxQ_6{e)BxVYG2I@(s< z!`{Ti#G+JzAXONs)=5O7ce_}VaAL2?=o5>oZ3hKX8O7gk&~%9GAKL3_T*=KoSv;Y< z-ccJsbVp>=pZB0SVvLcr0c^GwXwD8C*4fWH{dV+?kku(aQct4gK`Yc-dt+UPS6wo0wq z;D4bId(QDtW286XZq6M<|FqER>G=sEMc8`C&0|iwuP}jq2-6(hr(MSt z4Lr0T)U{8F%`BFwOlO?go6LxOXW2{hdT!^R7Kpt6fzu!St{riE7GIthQG;ULtNJSD z3JuB9Yk77gTkahui`LesC;Pa*KmGRk1f48-}%!qa2`Js7rfJU1&|b!``#jcHhrk#j_zI`E2u@D9vx!q-G0@b zpT;Vjn>GbnN&KUgDDAtLWMVavqZVs!x%%T!o}t6eFSg{WSE^4}aH>w3iJQR`nL_Lz z*`w`Qi^oxdNxJ$er8y<%RStc8GyT)`&xbSS=AWn1iPF2q%Rj7eioEBN-Q358*5AGQ zu5QUez@D!|R8q3u*|hM%o2QPD;FGb;x|WQ?8F2M+!MZ~cHC*LLNsl>KA2f1J?)@(F z3O6FsedJFQB7&IT|9whz@6i}FkEIDc*}I4>zKcxEya|T|rx9_7Fo(7fxWO-gt3j`K z_^qz2m|GHlaM(k8l6)vU=9K+JZ}j$?XY)_LD!e|H^L3$VLGCC2`)jMP_d?xayM8C@ z1zy(0{%;La)$~hCO4j~8-cK*D7tU~uCj&yvd;Z@}q1BlI*Cg6y+X8wF9Y^R$d)Q5t zQu)^^@fdWFrI%oN!3KBH&SY(kVIllh?Dwv-k)%jg7%^8S8l`9gs(w&Z!xkyvRBhA$v2Ov~1HD>gG&NaMtd4u8J9yJ(R)(^!2P z9^Do)m*RV|Y<*DJ_DbLj&G$}YUZiV*M#8Ei;5=oe5qw;JF&ZZX7s;&~->r_p5%Y3& zgHC_N;NIt-XXY*sE8sp-`1no#&0rgKbq!YQc>RB3iswzbNg}J2Oe@u^wX@4`6G61Any^EfU3;}Gx1p_v^*zVbJjT9Q+s!F8*YaEe zq$J6jqQJbRD81y*sBD9)9H;}Mc^bgKozXXyJA?;bq{oN(eLNz;I$HUVt^<-!tKp9! zs7A9Xncj0yb9{R5RQ*-i4Zx+usyT-1K|RuNXS%XBQ&I7A<*VXfq^!oL?yZsWp-Vl} zS*j=w&1uJGMbbZTHQ;*5rm|FWC_U^NPjkCrL>a0