Repository: pystiche/pystiche

Issue:
Display demo images in documentation
Currently our documentation for `demo.images()` simply states

https://github.com/pystiche/pystiche/blob/f379fa9601a387f40882db2212a73179083f63ec/pystiche/demo.py#L21-L29

It would be a lot better to simply display all images in a table.


Discussion:

Resolving patch:
diff --git a/docs/source/conf.py b/docs/source/conf.py
--- a/docs/source/conf.py
+++ b/docs/source/conf.py
@@ -1,6 +1,7 @@
 import contextlib
 import importlib
 import io
+import itertools
 import os
 import pathlib
 import re
@@ -10,7 +11,6 @@
 from datetime import datetime
 from distutils.util import strtobool
 from importlib_metadata import metadata as extract_metadata
-from os import path
 from types import SimpleNamespace
 from unittest import mock
 from urllib.parse import urljoin
@@ -21,11 +21,14 @@
 
 import torch
 
+import pystiche
 from pystiche._cli import main as cli_entrypoint
+from pystiche.image import extract_aspect_ratio
 from pystiche.misc import download_file
 
-HERE = path.dirname(__file__)
-PROJECT_ROOT = path.abspath(path.join(HERE, "..", ".."))
+HERE = pathlib.Path(__file__).parent
+GRAPHICS = HERE / "graphics"
+PROJECT_ROOT = HERE.parent.parent
 
 
 def get_bool_env_var(name, default=False):
@@ -122,7 +125,7 @@ def html():
 def latex():
     extension = None
 
-    with open(path.join(HERE, "custom_cmds.tex"), "r") as fh:
+    with open(HERE / "custom_cmds.tex", "r") as fh:
         custom_cmds = fh.read()
     config = dict(
         latex_elements={"preamble": custom_cmds},
@@ -195,7 +198,7 @@ def download():
         download_file(url, file)
 
         with contextlib.suppress(FileNotFoundError):
-            shutil.rmtree(path.join(HERE, "galleries"))
+            shutil.rmtree(HERE / "galleries")
         shutil.unpack_archive(file, extract_dir=".")
         os.remove(file)
 
@@ -275,8 +278,8 @@ def filter_warnings():
         print(msg)
 
     sphinx_gallery_conf = {
-        "examples_dirs": path.join(PROJECT_ROOT, "examples"),
-        "gallery_dirs": path.join("galleries", "examples"),
+        "examples_dirs": PROJECT_ROOT / "examples",
+        "gallery_dirs": pathlib.Path("galleries") / "examples",
         "filename_pattern": re.escape(os.sep) + r"example_\w+[.]py$",
         "ignore_pattern": re.escape(os.sep) + r"_\w+[.]py$",
         "line_numbers": True,
@@ -284,7 +287,7 @@ def filter_warnings():
         "plot_gallery": plot_gallery,
         "subsection_order": ExplicitOrder(
             [
-                path.join("..", "..", "examples", sub_gallery)
+                pathlib.Path("..") / ".." / "examples" / sub_gallery
                 for sub_gallery in ("beginner", "advanced")
             ]
         ),
@@ -295,7 +298,7 @@ def filter_warnings():
     config = dict(sphinx_gallery_conf=sphinx_gallery_conf)
     filter_warnings()
 
-    patch_tqdm()
+    # patch_tqdm()
     filter_warnings()
 
     return extension, config
@@ -304,7 +307,7 @@ def filter_warnings():
 def logo():
     extension = None
 
-    config = dict(html_logo="../../logo.svg")
+    config = dict(html_logo=str(PROJECT_ROOT / "logo.svg"))
 
     return extension, config
 
@@ -339,6 +342,64 @@ def capture_cli_output(*args):
     return None, None
 
 
+def demo_images():
+    cache_path = pathlib.Path(pystiche.home())
+    graphics_path = GRAPHICS / "demo_images"
+    graphics_path.mkdir(exist_ok=True)
+    api_path = HERE / "api"
+
+    images = pystiche.demo.images()
+    images.download()
+
+    entries = {}
+    for name, image in images:
+        entries[name] = (image.file, extract_aspect_ratio(image.read()))
+        if not (graphics_path / image.file).exists():
+            (graphics_path / image.file).symlink_to(cache_path / image.file)
+
+    field_len = max(max(len(name) for name in entries.keys()) + 2, len("images"))
+
+    def sep(char):
+        return "+" + char * (field_len + 2) + "+" + char * (field_len + 2) + "+"
+
+    def row(name, image):
+        key = f"{name:{field_len}}"
+        value = image or f"|{name}|"
+        value += " " * (field_len - len(image or name))
+        return f"| {key} | {value} |"
+
+    images_table = [
+        sep("-"),
+        row("name", "image"),
+        sep("="),
+        *itertools.chain(
+            *[(row(name, f"|{name}|"), sep("-")) for name in sorted(entries.keys())]
+        ),
+    ]
+
+    width = 300
+    aliases = [
+        f".. |{name}|\n"
+        f"  image:: ../graphics/demo_images/{file}\n"
+        f"    :width: {width}px\n"
+        f"    :height: {width / aspect_ratio:.0f}px\n"
+        for name, (file, aspect_ratio) in entries.items()
+    ]
+
+    loader = jinja2.FileSystemLoader(searchpath=api_path)
+    env = jinja2.Environment(loader=loader)
+    template = env.get_template("pystiche.demo.rst.template")
+
+    with open(api_path / "pystiche.demo.rst", "w") as fh:
+        fh.write(
+            template.render(
+                images_table="\n".join(images_table), aliases="\n".join(aliases),
+            )
+        )
+
+    return None, None
+
+
 extensions = []
 for loader in (
     project,
@@ -351,6 +412,7 @@ def capture_cli_output(*args):
     sphinx_gallery,
     logo,
     cli,
+    demo_images,
 ):
     extension, config = loader()
 
diff --git a/pystiche/demo.py b/pystiche/demo.py
--- a/pystiche/demo.py
+++ b/pystiche/demo.py
@@ -16,18 +16,7 @@
 
 
 def images() -> DownloadableImageCollection:
-    """Collection of images used in the usage examples.
-
-    .. note::
-
-        You can use
-
-        .. code-block:: python
-
-            print(images())
-
-        to get a list of all available images.
-    """
+    """Collection of images used in the usage examples."""
     return DownloadableImageCollection(
         {
             "bird1": DownloadableImage(


Test patch:
diff --git a/tests/galleries/test_galleries.py b/tests/galleries/test_galleries.py
--- a/tests/galleries/test_galleries.py
+++ b/tests/galleries/test_galleries.py
@@ -1,4 +1,5 @@
 import os
+import pathlib
 import re
 import unittest.mock
 import warnings
@@ -24,8 +25,8 @@ def collect_sphinx_gallery_scripts():
     sphinx_gallery_config, filters = extract_sphinx_gallery_config()
 
     examples_dirs = sphinx_gallery_config["examples_dirs"]
-    if isinstance(examples_dirs, str):
-        examples_dirs = (examples_dirs,)
+    if isinstance(examples_dirs, (pathlib.Path, str)):
+        examples_dirs = (str(examples_dirs),)
 
     filename_pattern = re.compile(sphinx_gallery_config["filename_pattern"])
     ignore_pattern = re.compile(sphinx_gallery_config["ignore_pattern"])