diff --git a/doc/advanced.rst b/doc/advanced.rst index c68fbc292..6745c0cbb 100644 --- a/doc/advanced.rst +++ b/doc/advanced.rst @@ -143,12 +143,16 @@ Write a custom image scraper By default, Sphinx-Gallery supports image scraping for Matplotlib (:func:`~sphinx_gallery.scrapers.matplotlib_scraper`). If you wish to capture output from other python packages, first determine if the object you wish to -capture has a ``_repr_html_`` method. If so, you can use the configuration -``capture_repr`` (:ref:`capture_repr`) to control the display of the object, -without the need to write a custom scraper. This configuration allows capture -of the raw html output, in a process similar to other html-based displays such -as `jupyter `_. If the first option does not work, -this section describes how to write a custom scraper. +capture has any of the other supported capture methods: ``_repr_html_``, +``_repr_png_``, ``_repr_jpeg_``, and ``_repr_svg_``. If so, you can use the +configuration ``capture_repr`` (:ref:`capture_repr`) to control the display of +the object, without the need to write a custom scraper. This configuration allows +capture of the raw html/png/jpeg/svg output, in a process similar to other enriched +displays such as `jupyter `_. If the object supports +``_repr_mimebundle_``, adding, e.g., ``_repr_svg_`` to ``capture_repr`` will also +look for SVG in the returned MIME-bundle. + +If the first option does not work, this section describes how to write a custom scraper. Image scrapers are functions (or callable class instances) that do the following things: diff --git a/doc/conf.py b/doc/conf.py index 103839104..3a22bbeb6 100644 --- a/doc/conf.py +++ b/doc/conf.py @@ -327,6 +327,7 @@ def setup(app): 'sklearn': ('https://scikit-learn.org/stable', None), 'sphinx': ('https://www.sphinx-doc.org/en/master', None), 'pandas': ('https://pandas.pydata.org/pandas-docs/stable/', None), + 'ipython': ('https://ipython.readthedocs.io/en/stable/', None), } examples_dirs = ['../examples', '../tutorials'] diff --git a/doc/configuration.rst b/doc/configuration.rst index de3530a6e..7a2a337e5 100644 --- a/doc/configuration.rst +++ b/doc/configuration.rst @@ -1856,8 +1856,21 @@ are: * ``__str__`` - returns a string containing a nicely printable representation of an object. This is what is used when you ``print()`` an object or pass it to ``format()``. -* ``_repr_html_`` - returns a HTML version of the object. This method is only - present in some objects, for example, pandas dataframes. +* ``_repr_html_`` - returns an HTML version of the object. +* ``_repr_png_`` - returns a PNG version of the object. +* ``_repr_jpeg_`` - returns a JPEG version of the object. +* ``_repr_svg_`` - returns an SVG version of the object. + +Note that the last four methods are only available for some objects. For example, +Pandas dataframes, SymPy expressions, and GraphViz graphs, support one or more of +these formats. + +.. note:: + + Some objects support :py:meth:`~MyObject._repr_mimebundle_`, which is the preferred + way to access enriched representations. By specifying, e.g., ``_repr_svg_``, + Sphinx-Gallery will first look for an SVG in the MIME bundle. + If not, it will call ``_repr_svg_`` if available. Output capture can be controlled globally by the ``capture_repr`` configuration setting or file-by-file by adding a comment to the example file, which overrides diff --git a/examples/no_output/just_code.py b/examples/no_output/just_code.py index 49e65c697..3a75d2db9 100644 --- a/examples/no_output/just_code.py +++ b/examples/no_output/just_code.py @@ -4,7 +4,7 @@ This demonstrates an example ``.py`` file that is not executed when gallery is generated (see :ref:`build_pattern`) but nevertheless gets included as an -example. Note that no output is capture as this file is not executed. +example. Note that no output is captured as this file is not executed. """ # Code source: Óscar Nájera diff --git a/examples/plot_3_capture_repr.py b/examples/plot_3_capture_repr.py index 1a81cb47b..3849acf45 100644 --- a/examples/plot_3_capture_repr.py +++ b/examples/plot_3_capture_repr.py @@ -111,7 +111,7 @@ # default ``capture_repr`` setting, ``_repr_html_`` is attempted to be captured # first. If this method does not exist, the ``__repr__`` method would be # captured. If the ``__repr__`` also does not exist (unlikely for non-user -# defined objects), nothing would be captured. For example, if the the +# defined objects), nothing would be captured. For example, if the # configuration was set to ``'capture_repr': ('_repr_html_')`` nothing would be # captured for example 2 as ``b`` does not have a ``_repr_html_``. # You can change the 'representations' in the ``capture_repr`` tuple to finely diff --git a/sphinx_gallery/directives.py b/sphinx_gallery/directives.py index f12f12385..8d2e186d7 100644 --- a/sphinx_gallery/directives.py +++ b/sphinx_gallery/directives.py @@ -128,7 +128,7 @@ class ImageSg(images.Image): /plot_types/basic/images/sphx_glr_bar_001_2_00x.png 2.00x :class: sphx-glr-single-img - The resulting html is:: + The resulting HTML is:: " + "" + "") + +class_inst = repr_and_svg_class() +class_inst +""" + def _clean_output(output): is_text = '.. rst-class:: sphx-glr-script-out' in output @@ -879,6 +896,8 @@ def _clean_output(output): pytest.param(('_repr_html_', '__repr__'), code_repr_only, 'This is the __repr__', id='repr_only,(html,repr)'), pytest.param(('_repr_html_',), code_plt, '', id='html_none'), + pytest.param(('__repr__', '_repr_svg_'), code_repr_and_svg, + 'This is the __repr__', id='repr_and_svg,(repr,svg)'), ]) def test_capture_repr(gallery_conf, capture_repr, code, expected_out, req_mpl, req_pil, script_vars): diff --git a/sphinx_gallery/tests/tinybuild/examples/plot_mime_bundle.py b/sphinx_gallery/tests/tinybuild/examples/plot_mime_bundle.py new file mode 100644 index 000000000..b0acaf3d7 --- /dev/null +++ b/sphinx_gallery/tests/tinybuild/examples/plot_mime_bundle.py @@ -0,0 +1,72 @@ +""" +Test using _repr_mimebundle_ +===================================== +Test repr capturing via ``_repr_mimebundle_`` and make sure that the +``capture_repr`` ordering is honored as well as ``_repr_mimebundle_`` +over other ``_repr_*_`` having precedence. +""" +# sphinx_gallery_capture_repr = ('_repr_svg_', '_repr_html_') +# %% +# First define a class with only an SVG in the MIME bundle + + +class A: + def _repr_mimebundle_(self, **kwargs): + return {"image/svg+xml": """ + + + +"""} + + +A() + + +# %% +# Then, only a HTML representation, but both ``_repr_html_`` and +# ``_repr_mimebundle_``. +class B: + def _repr_html_(self): + return '

This should not print

' + + def _repr_mimebundle_(self, **kwargs): + # Breaking the string here, so one can use the sentence to + # check the correct HTML output + return {"text/html": '

This should' + ' actually print

'} + + +B() + + +# %% +# Then, both SVG and HTML. The SVG should be selected based on the order. +class C: + def _repr_mimebundle_(self, **kwargs): + return {"image/svg+xml": """ + + + +""", + "text/html": '

This should not print

'} + + +C() + + +# %% +# Finally, a separate ``_repr_svg_`` that should be selected since +# ``_repr_mimebundle_`` only includes HTML. +class D: + def _repr_svg_(self): + return """ + + + + """ + + def _repr_mimebundle_(self, **kwargs): + return {"text/html": '

This should not print

'} + + +D() diff --git a/sphinx_gallery/tests/tinybuild/examples/plot_random_jpg.py b/sphinx_gallery/tests/tinybuild/examples/plot_random_jpg.py new file mode 100644 index 000000000..5feffab72 --- /dev/null +++ b/sphinx_gallery/tests/tinybuild/examples/plot_random_jpg.py @@ -0,0 +1,26 @@ +""" +Capture JPG test +================ +Test that it is possible to capture a JPG from a class with a ``_repr_jpeg__`` +method. +""" + + +# sphinx_gallery_capture_repr = ('_repr_jpeg_',) +import io +import numpy +from PIL import Image + + +class RandomImage: + def __init__(self): + imarray = numpy.random.rand(160, 160, 3) * 255 + self._image = Image.fromarray(imarray.astype('uint8')).convert('RGB') + + def _repr_jpeg_(self): + b = io.BytesIO() + self._image.save(b, "JPEG") + return b.getvalue() + + +RandomImage() diff --git a/sphinx_gallery/tests/tinybuild/examples/plot_random_png.py b/sphinx_gallery/tests/tinybuild/examples/plot_random_png.py new file mode 100644 index 000000000..6ec544c86 --- /dev/null +++ b/sphinx_gallery/tests/tinybuild/examples/plot_random_png.py @@ -0,0 +1,15 @@ +""" +Capture PNG test +================ +Test that it is possible to capture a PNG of a Pillow Image +(which has a ``_repr_png_`` method). +""" + + +# sphinx_gallery_capture_repr = ('_repr_png_',) +import numpy +from PIL import Image + + +imarray = numpy.random.rand(160, 160, 3) * 255 +Image.fromarray(imarray.astype('uint8')).convert('RGB') diff --git a/sphinx_gallery/tests/tinybuild/examples/plot_svg_repr.py b/sphinx_gallery/tests/tinybuild/examples/plot_svg_repr.py new file mode 100644 index 000000000..bcc6678d6 --- /dev/null +++ b/sphinx_gallery/tests/tinybuild/examples/plot_svg_repr.py @@ -0,0 +1,20 @@ +""" +SVG repr test +============= +Test SVG repr capturing and specifying capture_repr in file. + +""" + +# sphinx_gallery_capture_repr = ('_repr_svg_',) + + +class B: + def _repr_svg_(self): + return """ + + + +""" + + +B()