diff --git a/Tests/test_file_pcx.py b/Tests/test_file_pcx.py index 2e999eff6..90740ab57 100644 --- a/Tests/test_file_pcx.py +++ b/Tests/test_file_pcx.py @@ -119,36 +119,36 @@ def test_large_count(tmp_path: Path) -> None: _roundtrip(tmp_path, im) -def _test_buffer_overflow(tmp_path: Path, im: Image.Image, size: int = 1024) -> None: - _last = ImageFile.MAXBLOCK - ImageFile.MAXBLOCK = size - try: - _roundtrip(tmp_path, im) - finally: - ImageFile.MAXBLOCK = _last +def _test_buffer_overflow( + tmp_path: Path, im: Image.Image, monkeypatch: pytest.MonkeyPatch +) -> None: + monkeypatch.setattr(ImageFile, "MAXBLOCK", 1024) + _roundtrip(tmp_path, im) -def test_break_in_count_overflow(tmp_path: Path) -> None: +def test_break_in_count_overflow( + tmp_path: Path, monkeypatch: pytest.MonkeyPatch +) -> None: im = Image.new("L", (256, 5)) px = im.load() assert px is not None for y in range(4): for x in range(256): px[x, y] = x % 128 - _test_buffer_overflow(tmp_path, im) + _test_buffer_overflow(tmp_path, im, monkeypatch) -def test_break_one_in_loop(tmp_path: Path) -> None: +def test_break_one_in_loop(tmp_path: Path, monkeypatch: pytest.MonkeyPatch) -> None: im = Image.new("L", (256, 5)) px = im.load() assert px is not None for y in range(5): for x in range(256): px[x, y] = x % 128 - _test_buffer_overflow(tmp_path, im) + _test_buffer_overflow(tmp_path, im, monkeypatch) -def test_break_many_in_loop(tmp_path: Path) -> None: +def test_break_many_in_loop(tmp_path: Path, monkeypatch: pytest.MonkeyPatch) -> None: im = Image.new("L", (256, 5)) px = im.load() assert px is not None @@ -157,10 +157,10 @@ def test_break_many_in_loop(tmp_path: Path) -> None: px[x, y] = x % 128 for x in range(8): px[x, 4] = 16 - _test_buffer_overflow(tmp_path, im) + _test_buffer_overflow(tmp_path, im, monkeypatch) -def test_break_one_at_end(tmp_path: Path) -> None: +def test_break_one_at_end(tmp_path: Path, monkeypatch: pytest.MonkeyPatch) -> None: im = Image.new("L", (256, 5)) px = im.load() assert px is not None @@ -168,10 +168,10 @@ def test_break_one_at_end(tmp_path: Path) -> None: for x in range(256): px[x, y] = x % 128 px[0, 3] = 128 + 64 - _test_buffer_overflow(tmp_path, im) + _test_buffer_overflow(tmp_path, im, monkeypatch) -def test_break_many_at_end(tmp_path: Path) -> None: +def test_break_many_at_end(tmp_path: Path, monkeypatch: pytest.MonkeyPatch) -> None: im = Image.new("L", (256, 5)) px = im.load() assert px is not None @@ -181,10 +181,10 @@ def test_break_many_at_end(tmp_path: Path) -> None: for x in range(4): px[x * 2, 3] = 128 + 64 px[x + 256 - 4, 3] = 0 - _test_buffer_overflow(tmp_path, im) + _test_buffer_overflow(tmp_path, im, monkeypatch) -def test_break_padding(tmp_path: Path) -> None: +def test_break_padding(tmp_path: Path, monkeypatch: pytest.MonkeyPatch) -> None: im = Image.new("L", (257, 5)) px = im.load() assert px is not None @@ -193,4 +193,4 @@ def test_break_padding(tmp_path: Path) -> None: px[x, y] = x % 128 for x in range(5): px[x, 3] = 0 - _test_buffer_overflow(tmp_path, im) + _test_buffer_overflow(tmp_path, im, monkeypatch) diff --git a/Tests/test_file_png.py b/Tests/test_file_png.py index ed3a91285..2e0af5041 100644 --- a/Tests/test_file_png.py +++ b/Tests/test_file_png.py @@ -654,21 +654,17 @@ class TestFilePng: with pytest.raises(SyntaxError, match="Unknown compression method"): PngImagePlugin.PngImageFile("Tests/images/unknown_compression_method.png") - def test_padded_idat(self) -> None: + def test_padded_idat(self, monkeypatch: pytest.MonkeyPatch) -> None: # This image has been manually hexedited # so that the IDAT chunk has padding at the end # Set MAXBLOCK to the length of the actual data # so that the decoder finishes reading before the chunk ends - MAXBLOCK = ImageFile.MAXBLOCK - ImageFile.MAXBLOCK = 45 - ImageFile.LOAD_TRUNCATED_IMAGES = True + monkeypatch.setattr(ImageFile, "MAXBLOCK", 45) + monkeypatch.setattr(ImageFile, "LOAD_TRUNCATED_IMAGES", True) with Image.open("Tests/images/padded_idat.png") as im: im.load() - ImageFile.MAXBLOCK = MAXBLOCK - ImageFile.LOAD_TRUNCATED_IMAGES = False - assert_image_equal_tofile(im, "Tests/images/bw_gradient.png") @pytest.mark.parametrize( diff --git a/Tests/test_font_leaks.py b/Tests/test_font_leaks.py index ab8a7f9ec..a5da76faa 100644 --- a/Tests/test_font_leaks.py +++ b/Tests/test_font_leaks.py @@ -1,5 +1,7 @@ from __future__ import annotations +import pytest + from PIL import Image, ImageDraw, ImageFont, _util from .helper import PillowLeakTestCase, features, skip_unless_feature @@ -7,11 +9,7 @@ from .helper import PillowLeakTestCase, features, skip_unless_feature original_core = ImageFont.core -class TestTTypeFontLeak(PillowLeakTestCase): - # fails at iteration 3 in main - iterations = 10 - mem_limit = 4096 # k - +class TestFontLeak(PillowLeakTestCase): def _test_font(self, font: ImageFont.FreeTypeFont | ImageFont.ImageFont) -> None: im = Image.new("RGB", (255, 255), "white") draw = ImageDraw.ImageDraw(im) @@ -21,23 +19,29 @@ class TestTTypeFontLeak(PillowLeakTestCase): ) ) + +class TestTTypeFontLeak(TestFontLeak): + # fails at iteration 3 in main + iterations = 10 + mem_limit = 4096 # k + @skip_unless_feature("freetype2") def test_leak(self) -> None: ttype = ImageFont.truetype("Tests/fonts/FreeMono.ttf", 20) self._test_font(ttype) -class TestDefaultFontLeak(TestTTypeFontLeak): +class TestDefaultFontLeak(TestFontLeak): # fails at iteration 37 in main iterations = 100 mem_limit = 1024 # k - def test_leak(self) -> None: + def test_leak(self, monkeypatch: pytest.MonkeyPatch) -> None: if features.check_module("freetype2"): - ImageFont.core = _util.DeferredError(ImportError("Disabled for testing")) - try: - default_font = ImageFont.load_default() - finally: - ImageFont.core = original_core - + monkeypatch.setattr( + ImageFont, + "core", + _util.DeferredError(ImportError("Disabled for testing")), + ) + default_font = ImageFont.load_default() self._test_font(default_font) diff --git a/Tests/test_image.py b/Tests/test_image.py index c064939e8..32c799195 100644 --- a/Tests/test_image.py +++ b/Tests/test_image.py @@ -456,9 +456,11 @@ class TestImage: # Assert assert len(Image.ID) == id_length - def test_registered_extensions_uninitialized(self) -> None: + def test_registered_extensions_uninitialized( + self, monkeypatch: pytest.MonkeyPatch + ) -> None: # Arrange - Image._initialized = 0 + monkeypatch.setattr(Image, "_initialized", 0) # Act Image.registered_extensions() diff --git a/Tests/test_imagedraw.py b/Tests/test_imagedraw.py index 1eae05383..3bcb7b901 100644 --- a/Tests/test_imagedraw.py +++ b/Tests/test_imagedraw.py @@ -1485,21 +1485,15 @@ def test_stroke_multiline() -> None: @skip_unless_feature("freetype2") -def test_setting_default_font() -> None: - # Arrange +def test_setting_default_font(monkeypatch: pytest.MonkeyPatch) -> None: im = Image.new("RGB", (100, 250)) + draw = ImageDraw.Draw(im) + assert isinstance(draw.getfont(), ImageFont.load_default().__class__) + draw = ImageDraw.Draw(im) font = ImageFont.truetype("Tests/fonts/FreeMono.ttf", 120) - - # Act - ImageDraw.ImageDraw.font = font - - # Assert - try: - assert draw.getfont() == font - finally: - ImageDraw.ImageDraw.font = None - assert isinstance(draw.getfont(), ImageFont.load_default().__class__) + monkeypatch.setattr(ImageDraw.ImageDraw, "font", font) + assert draw.getfont() == font def test_default_font_size() -> None: diff --git a/Tests/test_imagefile.py b/Tests/test_imagefile.py index 7dfb3abf9..8a0abbd39 100644 --- a/Tests/test_imagefile.py +++ b/Tests/test_imagefile.py @@ -31,7 +31,7 @@ SAFEBLOCK = ImageFile.SAFEBLOCK class TestImageFile: - def test_parser(self) -> None: + def test_parser(self, monkeypatch: pytest.MonkeyPatch) -> None: def roundtrip(format: str) -> tuple[Image.Image, Image.Image]: im = hopper("L").resize((1000, 1000), Image.Resampling.NEAREST) if format in ("MSP", "XBM"): @@ -55,12 +55,9 @@ class TestImageFile: assert_image_equal(*roundtrip("IM")) assert_image_equal(*roundtrip("MSP")) if features.check("zlib"): - try: - # force multiple blocks in PNG driver - ImageFile.MAXBLOCK = 8192 - assert_image_equal(*roundtrip("PNG")) - finally: - ImageFile.MAXBLOCK = MAXBLOCK + # force multiple blocks in PNG driver + monkeypatch.setattr(ImageFile, "MAXBLOCK", 8192) + assert_image_equal(*roundtrip("PNG")) assert_image_equal(*roundtrip("PPM")) assert_image_equal(*roundtrip("TIFF")) assert_image_equal(*roundtrip("XBM")) @@ -120,14 +117,11 @@ class TestImageFile: assert (128, 128) == p.image.size @skip_unless_feature("zlib") - def test_safeblock(self) -> None: + def test_safeblock(self, monkeypatch: pytest.MonkeyPatch) -> None: im1 = hopper() - try: - ImageFile.SAFEBLOCK = 1 - im2 = fromstring(tostring(im1, "PNG")) - finally: - ImageFile.SAFEBLOCK = SAFEBLOCK + monkeypatch.setattr(ImageFile, "SAFEBLOCK", 1) + im2 = fromstring(tostring(im1, "PNG")) assert_image_equal(im1, im2) diff --git a/Tests/test_imagefontpil.py b/Tests/test_imagefontpil.py index 8c1cb3f58..883df051d 100644 --- a/Tests/test_imagefontpil.py +++ b/Tests/test_imagefontpil.py @@ -38,20 +38,18 @@ def test_invalid_mode() -> None: font._load_pilfont_data(fp, im) -def test_without_freetype() -> None: - original_core = ImageFont.core +def test_without_freetype(monkeypatch: pytest.MonkeyPatch) -> None: if features.check_module("freetype2"): - ImageFont.core = _util.DeferredError(ImportError("Disabled for testing")) - try: - with pytest.raises(ImportError): - ImageFont.truetype("Tests/fonts/FreeMono.ttf") + monkeypatch.setattr( + ImageFont, "core", _util.DeferredError(ImportError("Disabled for testing")) + ) + with pytest.raises(ImportError): + ImageFont.truetype("Tests/fonts/FreeMono.ttf") - assert isinstance(ImageFont.load_default(), ImageFont.ImageFont) + assert isinstance(ImageFont.load_default(), ImageFont.ImageFont) - with pytest.raises(ImportError): - ImageFont.load_default(size=14) - finally: - ImageFont.core = original_core + with pytest.raises(ImportError): + ImageFont.load_default(size=14) @pytest.mark.parametrize("font", fonts) diff --git a/Tests/test_psdraw.py b/Tests/test_psdraw.py index 78f5632c5..e5c6f7d85 100644 --- a/Tests/test_psdraw.py +++ b/Tests/test_psdraw.py @@ -5,6 +5,8 @@ import sys from io import BytesIO from pathlib import Path +import pytest + from PIL import Image, PSDraw @@ -47,21 +49,16 @@ def test_draw_postscript(tmp_path: Path) -> None: assert os.path.getsize(tempfile) > 0 -def test_stdout() -> None: +def test_stdout(monkeypatch: pytest.MonkeyPatch) -> None: # Temporarily redirect stdout - old_stdout = sys.stdout - class MyStdOut: buffer = BytesIO() mystdout = MyStdOut() - sys.stdout = mystdout + monkeypatch.setattr(sys, "stdout", mystdout) ps = PSDraw.PSDraw() _create_document(ps) - # Reset stdout - sys.stdout = old_stdout - assert mystdout.buffer.getvalue() != b""