diff --git a/Tests/helper.py b/Tests/helper.py index c8cbb80e1..3da2571f2 100644 --- a/Tests/helper.py +++ b/Tests/helper.py @@ -11,6 +11,7 @@ import tempfile from io import BytesIO import pytest +from packaging.version import parse as parse_version from PIL import Image, ImageMath, features @@ -162,6 +163,16 @@ def skip_unless_feature(feature): return pytest.mark.skipif(not features.check(feature), reason=reason) +def skip_unless_feature_version(feature, version_required, reason=None): + if not features.check(feature): + return pytest.mark.skip(f"{feature} not available") + if reason is None: + reason = f"{feature} is older than {version_required}" + version_required = parse_version(version_required) + version_available = parse_version(features.version(feature)) + return pytest.mark.skipif(version_available < version_required, reason=reason) + + @pytest.mark.skipif(sys.platform.startswith("win32"), reason="Requires Unix or macOS") class PillowLeakTestCase: # requires unix/macOS diff --git a/Tests/test_imagefont.py b/Tests/test_imagefont.py index 9780b7b57..389df9151 100644 --- a/Tests/test_imagefont.py +++ b/Tests/test_imagefont.py @@ -18,6 +18,7 @@ from .helper import ( is_pypy, is_win32, skip_unless_feature, + skip_unless_feature_version, ) FONT_PATH = "Tests/fonts/FreeMono.ttf" @@ -870,10 +871,9 @@ class TestImageFont: with Image.open("Tests/images/standard_embedded.png") as expected: assert_image_similar(im, expected, max(self.metrics["multiline"], 3)) + @skip_unless_feature_version("freetype2", "2.5.0") @pytest.mark.xfail(is_pypy(), reason="failing on PyPy with Raqm") def test_cbdt(self): - if parse_version(features.version_module("freetype2")) < parse_version("2.5.0"): - pytest.skip("Freetype 2.5.0 or newer required") try: font = ImageFont.truetype( "Tests/fonts/NotoColorEmoji.ttf", @@ -892,10 +892,9 @@ class TestImageFont: assert str(e) in ("unimplemented feature", "unknown file format") pytest.skip("freetype compiled without libpng or unsupported") + @skip_unless_feature_version("freetype2", "2.5.0") @pytest.mark.xfail(is_pypy(), reason="failing on PyPy with Raqm") def test_cbdt_mask(self): - if parse_version(features.version_module("freetype2")) < parse_version("2.5.0"): - pytest.skip("Freetype 2.5.0 or newer required") try: font = ImageFont.truetype( "Tests/fonts/NotoColorEmoji.ttf", @@ -914,12 +913,8 @@ class TestImageFont: assert str(e) in ("unimplemented feature", "unknown file format") pytest.skip("freetype compiled without libpng or unsupported") + @skip_unless_feature_version("freetype2", "2.10.0") def test_colr(self): - if parse_version(features.version_module("freetype2")) < parse_version( - "2.10.0" - ): - pytest.skip("Freetype 2.10.0 or newer required") - font = ImageFont.truetype( "Tests/fonts/BungeeColor-Regular_colr_Windows.ttf", size=64, @@ -934,12 +929,8 @@ class TestImageFont: with Image.open("Tests/images/colr_bungee.png") as expected: assert_image_similar(im, expected, 21) + @skip_unless_feature_version("freetype2", "2.10.0") def test_colr_mask(self): - if parse_version(features.version_module("freetype2")) < parse_version( - "2.10.0" - ): - pytest.skip("Freetype 2.10.0 or newer required") - font = ImageFont.truetype( "Tests/fonts/BungeeColor-Regular_colr_Windows.ttf", size=64, @@ -960,12 +951,10 @@ class TestImageFont_RaqmLayout(TestImageFont): LAYOUT_ENGINE = ImageFont.LAYOUT_RAQM +@skip_unless_feature_version("freetype2", "2.4", "Different metrics") def test_render_mono_size(): # issue 4177 - if parse_version(ImageFont.core.freetype2_version) < parse_version("2.4"): - pytest.skip("Different metrics") - im = Image.new("P", (100, 30), "white") draw = ImageDraw.Draw(im) ttf = ImageFont.truetype( diff --git a/Tests/test_imagefontctl.py b/Tests/test_imagefontctl.py index 0012d6bd0..3fa227e62 100644 --- a/Tests/test_imagefontctl.py +++ b/Tests/test_imagefontctl.py @@ -3,7 +3,11 @@ from packaging.version import parse as parse_version from PIL import Image, ImageDraw, ImageFont, features -from .helper import assert_image_similar, skip_unless_feature +from .helper import ( + assert_image_similar, + skip_unless_feature, + skip_unless_feature_version, +) FONT_SIZE = 20 FONT_PATH = "Tests/fonts/DejaVuSans.ttf" @@ -209,13 +213,13 @@ def test_language(): assert_image_similar(im, target_img, 0.5) +# FreeType 2.5.1 README: Miscellaneous Changes: +# Improved computation of emulated vertical metrics for TrueType fonts. +@skip_unless_feature_version( + "freetype2", "2.5.1", "FreeType <2.5.1 has incompatible ttb metrics" +) @pytest.mark.parametrize("anchor", ("lt", "mm", "rb", "sm")) def test_anchor_ttb(anchor): - if parse_version(features.version_module("freetype2")) < parse_version("2.5.1"): - # FreeType 2.5.1 README: Miscellaneous Changes: - # Improved computation of emulated vertical metrics for TrueType fonts. - pytest.skip("FreeType <2.5.1 has incompatible ttb metrics") - text = "f" path = f"Tests/images/test_anchor_ttb_{text}_{anchor}.png" f = ImageFont.truetype("Tests/fonts/NotoSans-Regular.ttf", 120)