Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Creating @skipif_font_missing #27128

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
Empty file added a.out
Empty file.
24 changes: 24 additions & 0 deletions lib/matplotlib/testing/decorators.py
Expand Up @@ -8,6 +8,7 @@
import string
import sys
import warnings
import matplotlib.font_manager as fm

from packaging.version import parse as parse_version

Expand All @@ -18,6 +19,8 @@
from .compare import comparable_formats, compare_images, make_test_filename
from .exceptions import ImageComparisonFailure

import pytest


@contextlib.contextmanager
def _cleanup_cm():
Expand Down Expand Up @@ -462,3 +465,24 @@
result_dir = Path().resolve() / "result_images" / module_path.stem
result_dir.mkdir(parents=True, exist_ok=True)
return baseline_dir, result_dir


def skipif_font_missing(fonts):
"""
Decorator to skip a test if any of the specified fonts are missing.

Usage example:
@skipif_font_missing(['Dejavu Sans', 'Noto SansTC'])
def test_font(family_name):
# testing code
"""
def decorator(func):
def wrapper(family_name):
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should probably use functools.wraps here, as we do not wish to assume the signature of the wrapped function

for font in fonts:
fp = fm.FontProperties(family=[font])
found_file_name = Path(fm.findfont(fp)).name

Check warning on line 483 in lib/matplotlib/testing/decorators.py

View check run for this annotation

Codecov / codecov/patch

lib/matplotlib/testing/decorators.py#L482-L483

Added lines #L482 - L483 were not covered by tests
if found_file_name not in fonts:
pytest.skip(f"Font {font} is missing")
return func(family_name)

Check warning on line 486 in lib/matplotlib/testing/decorators.py

View check run for this annotation

Codecov / codecov/patch

lib/matplotlib/testing/decorators.py#L485-L486

Added lines #L485 - L486 were not covered by tests
return wrapper
return decorator
1 change: 1 addition & 0 deletions lib/matplotlib/testing/decorators.pyi
Expand Up @@ -23,3 +23,4 @@ def check_figures_equal(
*, extensions: Sequence[str] = ..., tol: float = ...
) -> Callable[[Callable[_P, _R]], Callable[_P, _R]]: ...
def _image_directories(func: Callable) -> tuple[Path, Path]: ...
def skipif_font_missing(fonts: list[str]) -> Callable[[Callable], Callable]: ...
8 changes: 3 additions & 5 deletions lib/matplotlib/tests/test_ft2font.py
Expand Up @@ -4,7 +4,7 @@
import pytest

from matplotlib import ft2font
from matplotlib.testing.decorators import check_figures_equal
from matplotlib.testing.decorators import check_figures_equal, skipif_font_missing
import matplotlib.font_manager as fm
import matplotlib.pyplot as plt

Expand Down Expand Up @@ -55,15 +55,14 @@ def test_fallback_smoke():
fig.savefig(io.BytesIO(), format=fmt)


@skipif_font_missing(['WenQuanYi Zen Hei', 'Noto Sans CJK JP'])
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't like that this will skip both parameterized versions of this test if only one of the fonts is missing... The implementation where it is checked in the method is more verbose, but allows for these parameterizations to still test when only some fonts are available.

@pytest.mark.parametrize('family_name, file_name',
[("WenQuanYi Zen Hei", "wqy-zenhei"),
("Noto Sans CJK JP", "NotoSansCJK")]
)
@check_figures_equal(extensions=["png", "pdf", "eps", "svg"])
def test_font_fallback_chinese(fig_test, fig_ref, family_name, file_name):
fp = fm.FontProperties(family=[family_name])
PaMeirelles marked this conversation as resolved.
Show resolved Hide resolved
if file_name not in Path(fm.findfont(fp)).name:
pytest.skip(f"Font {family_name} ({file_name}) is missing")

text = ["There are", "几个汉字", "in between!"]

Expand All @@ -78,6 +77,7 @@ def test_font_fallback_chinese(fig_test, fig_ref, family_name, file_name):
fig_test.text(0.05, .85 - 0.15*j, txt, family=test_font)


@skipif_font_missing(['WenQuanYi Zen Hei', 'Noto Sans CJK JP'])
@pytest.mark.parametrize(
"family_name, file_name",
[
Expand All @@ -88,8 +88,6 @@ def test_font_fallback_chinese(fig_test, fig_ref, family_name, file_name):
def test__get_fontmap(family_name, file_name):
fp = fm.FontProperties(family=[family_name])
found_file_name = Path(fm.findfont(fp)).name
if file_name not in found_file_name:
pytest.skip(f"Font {family_name} ({file_name}) is missing")

text = "There are 几个汉字 in between!"
ft = fm.get_font(
Expand Down