From 05aee33c5ea5ea2096c2cab17ca73cf3684db46b Mon Sep 17 00:00:00 2001 From: Andrew Murray Date: Thu, 8 May 2025 00:02:02 +1000 Subject: [PATCH] Use monkeypatch --- Tests/test_file_jxl.py | 32 +++++++++----------------------- Tests/test_file_jxl_alpha.py | 23 ++++++++++------------- Tests/test_file_jxl_animated.py | 10 ++-------- Tests/test_file_jxl_metadata.py | 4 +--- src/PIL/JpegXlImagePlugin.py | 17 ++++++++++------- 5 files changed, 32 insertions(+), 54 deletions(-) diff --git a/Tests/test_file_jxl.py b/Tests/test_file_jxl.py index 96b6b0ea5..36a9c0aa2 100644 --- a/Tests/test_file_jxl.py +++ b/Tests/test_file_jxl.py @@ -6,17 +6,12 @@ import pytest from PIL import Image, JpegXlImagePlugin, features -from .helper import ( - assert_image_similar_tofile, - skip_unless_feature, -) +from .helper import assert_image_similar_tofile, skip_unless_feature try: from PIL import _jpegxl - - HAVE_JPEGXL = True except ImportError: - HAVE_JPEGXL = False + pass # cjxl v0.9.2 41b8cdab # hopper.jxl: cjxl hopper.png hopper.jxl -q 75 -e 8 @@ -24,25 +19,16 @@ except ImportError: class TestUnsupportedJpegXl: - def test_unsupported(self) -> None: - if HAVE_JPEGXL: - JpegXlImagePlugin.SUPPORTED = False + def test_unsupported(self, monkeypatch: pytest.MonkeyPatch) -> None: + monkeypatch.setattr(JpegXlImagePlugin, "SUPPORTED", False) - file_path = "Tests/images/hopper.jxl" with pytest.raises(OSError): - with Image.open(file_path): + with Image.open("Tests/images/hopper.jxl"): pass - if HAVE_JPEGXL: - JpegXlImagePlugin.SUPPORTED = True - @skip_unless_feature("jpegxl") class TestFileJpegXl: - def setup_method(self) -> None: - self.rgb_mode = "RGB" - self.i16_mode = "I;16" - def test_version(self) -> None: _jpegxl.JpegXlDecoderVersion() version = features.version_module("jpegxl") @@ -56,7 +42,7 @@ class TestFileJpegXl: """ with Image.open("Tests/images/hopper.jxl") as image: - assert image.mode == self.rgb_mode + assert image.mode == "RGB" assert image.size == (128, 128) assert image.format == "JPEG XL" image.load() @@ -64,7 +50,7 @@ class TestFileJpegXl: # generated with: # djxl hopper.jxl hopper_jxl_bits.ppm - assert_image_similar_tofile(image, "Tests/images/hopper_jxl_bits.ppm", 1.0) + assert_image_similar_tofile(image, "Tests/images/hopper_jxl_bits.ppm", 1) def test_read_i16(self) -> None: """ @@ -72,14 +58,14 @@ class TestFileJpegXl: """ with Image.open("Tests/images/jxl/16bit_subcutaneous.cropped.jxl") as image: - assert image.mode == self.i16_mode + assert image.mode == "I;16" assert image.size == (128, 64) assert image.format == "JPEG XL" image.load() image.getdata() assert_image_similar_tofile( - image, "Tests/images/jxl/16bit_subcutaneous.cropped.png", 1.0 + image, "Tests/images/jxl/16bit_subcutaneous.cropped.png", 1 ) def test_JpegXlDecode_with_invalid_args(self) -> None: diff --git a/Tests/test_file_jxl_alpha.py b/Tests/test_file_jxl_alpha.py index 8c3ab2b71..b7cb1998f 100644 --- a/Tests/test_file_jxl_alpha.py +++ b/Tests/test_file_jxl_alpha.py @@ -1,12 +1,10 @@ from __future__ import annotations -import pytest - from PIL import Image -from .helper import assert_image_similar_tofile +from .helper import assert_image_similar_tofile, skip_unless_feature -_jpegxl = pytest.importorskip("PIL._jpegxl", reason="JPEG XL support not installed") +pytestmark = [skip_unless_feature("jpegxl")] def test_read_rgba() -> None: @@ -16,14 +14,13 @@ def test_read_rgba() -> None: """ # Generated with `cjxl transparent.png transparent.jxl -q 100 -e 8` - file_path = "Tests/images/transparent.jxl" - with Image.open(file_path) as image: - assert image.mode == "RGBA" - assert image.size == (200, 150) - assert image.format == "JPEG XL" - image.load() - image.getdata() + with Image.open("Tests/images/transparent.jxl") as im: + assert im.mode == "RGBA" + assert im.size == (200, 150) + assert im.format == "JPEG XL" + im.load() + im.getdata() - image.tobytes() + im.tobytes() - assert_image_similar_tofile(image, "Tests/images/transparent.png", 1.0) + assert_image_similar_tofile(im, "Tests/images/transparent.png", 1) diff --git a/Tests/test_file_jxl_animated.py b/Tests/test_file_jxl_animated.py index 02aca5eb0..cd502b30a 100644 --- a/Tests/test_file_jxl_animated.py +++ b/Tests/test_file_jxl_animated.py @@ -4,14 +4,9 @@ import pytest from PIL import Image -from .helper import ( - assert_image_equal, - skip_unless_feature, -) +from .helper import assert_image_equal, skip_unless_feature -pytestmark = [ - skip_unless_feature("jpegxl"), -] +pytestmark = [skip_unless_feature("jpegxl")] def test_n_frames() -> None: @@ -27,7 +22,6 @@ def test_n_frames() -> None: def test_float_duration() -> None: - with Image.open("Tests/images/iss634.jxl") as im: im.load() assert im.info["duration"] == 70 diff --git a/Tests/test_file_jxl_metadata.py b/Tests/test_file_jxl_metadata.py index bf21be993..d0b26b672 100644 --- a/Tests/test_file_jxl_metadata.py +++ b/Tests/test_file_jxl_metadata.py @@ -8,9 +8,7 @@ from PIL import Image, JpegXlImagePlugin from .helper import skip_unless_feature -pytestmark = [ - skip_unless_feature("jpegxl"), -] +pytestmark = [skip_unless_feature("jpegxl")] ElementTree: ModuleType | None try: diff --git a/src/PIL/JpegXlImagePlugin.py b/src/PIL/JpegXlImagePlugin.py index a89aefe09..e69e3d1b1 100644 --- a/src/PIL/JpegXlImagePlugin.py +++ b/src/PIL/JpegXlImagePlugin.py @@ -41,12 +41,18 @@ class JpegXlImageFile(ImageFile.ImageFile): def _open(self) -> None: self._decoder = _jpegxl.PILJpegXlDecoder(self.fp.read()) - width, height, mode, has_anim, tps_num, tps_denom, n_loops, n_frames = ( - self._decoder.get_info() - ) + ( + width, + height, + self._mode, + self.is_animated, + tps_num, + tps_denom, + n_loops, + n_frames, + ) = self._decoder.get_info() self._size = width, height self.info["loop"] = n_loops - self.is_animated = has_anim self._tps_dur_secs = 1 self.n_frames: int | None = 1 @@ -59,8 +65,6 @@ class JpegXlImageFile(ImageFile.ImageFile): # TODO: handle libjxl time codes self.__timestamp = 0 - self._mode = mode - if icc := self._decoder.get_icc(): self.info["icc_profile"] = icc if exif := self._decoder.get_exif(): @@ -115,7 +119,6 @@ class JpegXlImageFile(ImageFile.ImageFile): return self.tell() != frame def _seek(self, frame: int) -> None: - # print("_seek: phy: {}, fr: {}".format(self.__physical_frame, frame)) if frame == self.__physical_frame: return # Nothing to do if frame < self.__physical_frame: