Use monkeypatch

This commit is contained in:
Andrew Murray 2025-05-08 00:02:02 +10:00
parent 7125fe4096
commit 05aee33c5e
5 changed files with 32 additions and 54 deletions

View File

@ -6,17 +6,12 @@ import pytest
from PIL import Image, JpegXlImagePlugin, features from PIL import Image, JpegXlImagePlugin, features
from .helper import ( from .helper import assert_image_similar_tofile, skip_unless_feature
assert_image_similar_tofile,
skip_unless_feature,
)
try: try:
from PIL import _jpegxl from PIL import _jpegxl
HAVE_JPEGXL = True
except ImportError: except ImportError:
HAVE_JPEGXL = False pass
# cjxl v0.9.2 41b8cdab # cjxl v0.9.2 41b8cdab
# hopper.jxl: cjxl hopper.png hopper.jxl -q 75 -e 8 # hopper.jxl: cjxl hopper.png hopper.jxl -q 75 -e 8
@ -24,25 +19,16 @@ except ImportError:
class TestUnsupportedJpegXl: class TestUnsupportedJpegXl:
def test_unsupported(self) -> None: def test_unsupported(self, monkeypatch: pytest.MonkeyPatch) -> None:
if HAVE_JPEGXL: monkeypatch.setattr(JpegXlImagePlugin, "SUPPORTED", False)
JpegXlImagePlugin.SUPPORTED = False
file_path = "Tests/images/hopper.jxl"
with pytest.raises(OSError): with pytest.raises(OSError):
with Image.open(file_path): with Image.open("Tests/images/hopper.jxl"):
pass pass
if HAVE_JPEGXL:
JpegXlImagePlugin.SUPPORTED = True
@skip_unless_feature("jpegxl") @skip_unless_feature("jpegxl")
class TestFileJpegXl: class TestFileJpegXl:
def setup_method(self) -> None:
self.rgb_mode = "RGB"
self.i16_mode = "I;16"
def test_version(self) -> None: def test_version(self) -> None:
_jpegxl.JpegXlDecoderVersion() _jpegxl.JpegXlDecoderVersion()
version = features.version_module("jpegxl") version = features.version_module("jpegxl")
@ -56,7 +42,7 @@ class TestFileJpegXl:
""" """
with Image.open("Tests/images/hopper.jxl") as image: 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.size == (128, 128)
assert image.format == "JPEG XL" assert image.format == "JPEG XL"
image.load() image.load()
@ -64,7 +50,7 @@ class TestFileJpegXl:
# generated with: # generated with:
# djxl hopper.jxl hopper_jxl_bits.ppm # 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: def test_read_i16(self) -> None:
""" """
@ -72,14 +58,14 @@ class TestFileJpegXl:
""" """
with Image.open("Tests/images/jxl/16bit_subcutaneous.cropped.jxl") as image: 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.size == (128, 64)
assert image.format == "JPEG XL" assert image.format == "JPEG XL"
image.load() image.load()
image.getdata() image.getdata()
assert_image_similar_tofile( 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: def test_JpegXlDecode_with_invalid_args(self) -> None:

View File

@ -1,12 +1,10 @@
from __future__ import annotations from __future__ import annotations
import pytest
from PIL import Image 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: 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` # Generated with `cjxl transparent.png transparent.jxl -q 100 -e 8`
file_path = "Tests/images/transparent.jxl" with Image.open("Tests/images/transparent.jxl") as im:
with Image.open(file_path) as image: assert im.mode == "RGBA"
assert image.mode == "RGBA" assert im.size == (200, 150)
assert image.size == (200, 150) assert im.format == "JPEG XL"
assert image.format == "JPEG XL" im.load()
image.load() im.getdata()
image.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)

View File

@ -4,14 +4,9 @@ import pytest
from PIL import Image from PIL import Image
from .helper import ( from .helper import assert_image_equal, skip_unless_feature
assert_image_equal,
skip_unless_feature,
)
pytestmark = [ pytestmark = [skip_unless_feature("jpegxl")]
skip_unless_feature("jpegxl"),
]
def test_n_frames() -> None: def test_n_frames() -> None:
@ -27,7 +22,6 @@ def test_n_frames() -> None:
def test_float_duration() -> None: def test_float_duration() -> None:
with Image.open("Tests/images/iss634.jxl") as im: with Image.open("Tests/images/iss634.jxl") as im:
im.load() im.load()
assert im.info["duration"] == 70 assert im.info["duration"] == 70

View File

@ -8,9 +8,7 @@ from PIL import Image, JpegXlImagePlugin
from .helper import skip_unless_feature from .helper import skip_unless_feature
pytestmark = [ pytestmark = [skip_unless_feature("jpegxl")]
skip_unless_feature("jpegxl"),
]
ElementTree: ModuleType | None ElementTree: ModuleType | None
try: try:

View File

@ -41,12 +41,18 @@ class JpegXlImageFile(ImageFile.ImageFile):
def _open(self) -> None: def _open(self) -> None:
self._decoder = _jpegxl.PILJpegXlDecoder(self.fp.read()) 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._size = width, height
self.info["loop"] = n_loops self.info["loop"] = n_loops
self.is_animated = has_anim
self._tps_dur_secs = 1 self._tps_dur_secs = 1
self.n_frames: int | None = 1 self.n_frames: int | None = 1
@ -59,8 +65,6 @@ class JpegXlImageFile(ImageFile.ImageFile):
# TODO: handle libjxl time codes # TODO: handle libjxl time codes
self.__timestamp = 0 self.__timestamp = 0
self._mode = mode
if icc := self._decoder.get_icc(): if icc := self._decoder.get_icc():
self.info["icc_profile"] = icc self.info["icc_profile"] = icc
if exif := self._decoder.get_exif(): if exif := self._decoder.get_exif():
@ -115,7 +119,6 @@ class JpegXlImageFile(ImageFile.ImageFile):
return self.tell() != frame return self.tell() != frame
def _seek(self, frame: int) -> None: def _seek(self, frame: int) -> None:
# print("_seek: phy: {}, fr: {}".format(self.__physical_frame, frame))
if frame == self.__physical_frame: if frame == self.__physical_frame:
return # Nothing to do return # Nothing to do
if frame < self.__physical_frame: if frame < self.__physical_frame: