Removed PillowTestCase helper class

This commit is contained in:
Andrew Murray 2020-03-28 12:51:28 +11:00
parent a8637449b9
commit b602f365ae
22 changed files with 392 additions and 461 deletions

View File

@ -1,9 +1,8 @@
import time import time
import unittest
from PIL import PyAccess from PIL import PyAccess
from .helper import PillowTestCase, hopper from .helper import hopper
# Not running this test by default. No DOS against Travis CI. # Not running this test by default. No DOS against Travis CI.
@ -41,8 +40,7 @@ def timer(func, label, *args):
) )
class BenchCffiAccess(PillowTestCase): def test_direct():
def test_direct(self):
im = hopper() im = hopper()
im.load() im.load()
# im = Image.new( "RGB", (2000, 2000), (1, 3, 2)) # im = Image.new( "RGB", (2000, 2000), (1, 3, 2))
@ -56,7 +54,3 @@ class BenchCffiAccess(PillowTestCase):
timer(iterate_set, "PyAccess - set", im.size, access) timer(iterate_set, "PyAccess - set", im.size, access)
timer(iterate_get, "C-api - get", im.size, caccess) timer(iterate_get, "C-api - get", im.size, caccess)
timer(iterate_set, "C-api - set", im.size, caccess) timer(iterate_set, "C-api - set", im.size, caccess)
if __name__ == "__main__":
unittest.main()

View File

@ -1,19 +1,10 @@
import unittest
from PIL import Image from PIL import Image
from .helper import PillowTestCase
TEST_FILE = "Tests/images/fli_overflow.fli" TEST_FILE = "Tests/images/fli_overflow.fli"
class TestFliOverflow(PillowTestCase): def test_fli_overflow():
def test_fli_overflow(self):
# this should not crash with a malloc error or access violation # this should not crash with a malloc error or access violation
with Image.open(TEST_FILE) as im: with Image.open(TEST_FILE) as im:
im.load() im.load()
if __name__ == "__main__":
unittest.main()

View File

@ -1,46 +1,44 @@
#!/usr/bin/env python #!/usr/bin/env python
import unittest import pytest
from PIL import Image from PIL import Image
from .helper import PillowTestCase, is_win32 from .helper import is_win32
min_iterations = 100 min_iterations = 100
max_iterations = 10000 max_iterations = 10000
pytestmark = pytest.mark.skipif(is_win32(), reason="requires Unix or macOS")
@unittest.skipIf(is_win32(), "requires Unix or macOS")
class TestImagingLeaks(PillowTestCase): def _get_mem_usage():
def _get_mem_usage(self):
from resource import getpagesize, getrusage, RUSAGE_SELF from resource import getpagesize, getrusage, RUSAGE_SELF
mem = getrusage(RUSAGE_SELF).ru_maxrss mem = getrusage(RUSAGE_SELF).ru_maxrss
return mem * getpagesize() / 1024 / 1024 return mem * getpagesize() / 1024 / 1024
def _test_leak(self, min_iterations, max_iterations, fn, *args, **kwargs):
def _test_leak(min_iterations, max_iterations, fn, *args, **kwargs):
mem_limit = None mem_limit = None
for i in range(max_iterations): for i in range(max_iterations):
fn(*args, **kwargs) fn(*args, **kwargs)
mem = self._get_mem_usage() mem = _get_mem_usage()
if i < min_iterations: if i < min_iterations:
mem_limit = mem + 1 mem_limit = mem + 1
continue continue
msg = "memory usage limit exceeded after %d iterations" % (i + 1) msg = "memory usage limit exceeded after %d iterations" % (i + 1)
assert mem <= mem_limit, msg assert mem <= mem_limit, msg
def test_leak_putdata(self):
im = Image.new("RGB", (25, 25))
self._test_leak(min_iterations, max_iterations, im.putdata, im.getdata())
def test_leak_getlist(self): def test_leak_putdata():
im = Image.new("RGB", (25, 25))
_test_leak(min_iterations, max_iterations, im.putdata, im.getdata())
def test_leak_getlist():
im = Image.new("P", (25, 25)) im = Image.new("P", (25, 25))
self._test_leak( _test_leak(
min_iterations, min_iterations,
max_iterations, max_iterations,
# Pass a new list at each iteration. # Pass a new list at each iteration.
lambda: im.point(range(256)), lambda: im.point(range(256)),
) )
if __name__ == "__main__":
unittest.main()

View File

@ -1,9 +1,9 @@
import unittest
from io import BytesIO from io import BytesIO
import pytest
from PIL import Image from PIL import Image
from .helper import PillowTestCase, is_win32, skip_unless_feature from .helper import is_win32, skip_unless_feature
# Limits for testing the leak # Limits for testing the leak
mem_limit = 1024 * 1048576 mem_limit = 1024 * 1048576
@ -11,11 +11,13 @@ stack_size = 8 * 1048576
iterations = int((mem_limit / stack_size) * 2) iterations = int((mem_limit / stack_size) * 2)
test_file = "Tests/images/rgb_trns_ycbc.jp2" test_file = "Tests/images/rgb_trns_ycbc.jp2"
pytestmark = [
pytest.mark.skipif(is_win32(), reason="requires Unix or macOS"),
skip_unless_feature("jpg_2000"),
]
@unittest.skipIf(is_win32(), "requires Unix or macOS")
@skip_unless_feature("jpg_2000") def test_leak_load():
class TestJpegLeaks(PillowTestCase):
def test_leak_load(self):
from resource import setrlimit, RLIMIT_AS, RLIMIT_STACK from resource import setrlimit, RLIMIT_AS, RLIMIT_STACK
setrlimit(RLIMIT_STACK, (stack_size, stack_size)) setrlimit(RLIMIT_STACK, (stack_size, stack_size))
@ -24,7 +26,8 @@ class TestJpegLeaks(PillowTestCase):
with Image.open(test_file) as im: with Image.open(test_file) as im:
im.load() im.load()
def test_leak_save(self):
def test_leak_save():
from resource import setrlimit, RLIMIT_AS, RLIMIT_STACK from resource import setrlimit, RLIMIT_AS, RLIMIT_STACK
setrlimit(RLIMIT_STACK, (stack_size, stack_size)) setrlimit(RLIMIT_STACK, (stack_size, stack_size))
@ -36,7 +39,3 @@ class TestJpegLeaks(PillowTestCase):
im.save(test_output, "JPEG2000") im.save(test_output, "JPEG2000")
test_output.seek(0) test_output.seek(0)
test_output.read() test_output.read()
if __name__ == "__main__":
unittest.main()

View File

@ -1,18 +1,9 @@
import unittest import pytest
from PIL import Image from PIL import Image
from .helper import PillowTestCase
class TestJ2kEncodeOverflow(PillowTestCase):
def test_j2k_overflow(self):
def test_j2k_overflow(tmp_path):
im = Image.new("RGBA", (1024, 131584)) im = Image.new("RGBA", (1024, 131584))
target = self.tempfile("temp.jpc") target = str(tmp_path / "temp.jpc")
with self.assertRaises(IOError): with pytest.raises(IOError):
im.save(target) im.save(target)
if __name__ == "__main__":
unittest.main()

View File

@ -1,7 +1,8 @@
import unittest
from io import BytesIO from io import BytesIO
from .helper import PillowTestCase, hopper, is_win32 import pytest
from .helper import hopper, is_win32
iterations = 5000 iterations = 5000
@ -15,10 +16,9 @@ valgrind --tool=massif python test-installed.py -s -v Tests/check_jpeg_leaks.py
""" """
@unittest.skipIf(is_win32(), "requires Unix or macOS") pytestmark = pytest.mark.skipif(is_win32(), reason="requires Unix or macOS")
class TestJpegLeaks(PillowTestCase):
""" """
pre patch: pre patch:
MB MB
@ -74,7 +74,8 @@ post-patch:
""" """
def test_qtables_leak(self):
def test_qtables_leak():
im = hopper("RGB") im = hopper("RGB")
standard_l_qtable = [ standard_l_qtable = [
@ -115,7 +116,8 @@ post-patch:
test_output = BytesIO() test_output = BytesIO()
im.save(test_output, "JPEG", qtables=qtables) im.save(test_output, "JPEG", qtables=qtables)
def test_exif_leak(self):
def test_exif_leak():
""" """
pre patch: pre patch:
@ -178,7 +180,8 @@ post patch:
test_output = BytesIO() test_output = BytesIO()
im.save(test_output, "JPEG", exif=exif) im.save(test_output, "JPEG", exif=exif)
def test_base_save(self):
def test_base_save():
""" """
base case: base case:
MB MB
@ -210,7 +213,3 @@ base case:
for _ in range(iterations): for _ in range(iterations):
test_output = BytesIO() test_output = BytesIO()
im.save(test_output, "JPEG") im.save(test_output, "JPEG")
if __name__ == "__main__":
unittest.main()

View File

@ -1,10 +1,8 @@
import sys import sys
import unittest
import pytest
from PIL import Image from PIL import Image
from .helper import PillowTestCase
# This test is not run automatically. # This test is not run automatically.
# #
# It requires > 2gb memory for the >2 gigapixel image generated in the # It requires > 2gb memory for the >2 gigapixel image generated in the
@ -24,26 +22,26 @@ YDIM = 32769
XDIM = 48000 XDIM = 48000
@unittest.skipIf(sys.maxsize <= 2 ** 32, "requires 64-bit system") pytestmark = pytest.mark.skipif(sys.maxsize <= 2 ** 32, reason="requires 64-bit system")
class LargeMemoryTest(PillowTestCase):
def _write_png(self, xdim, ydim):
f = self.tempfile("temp.png") def _write_png(tmp_path, xdim, ydim):
f = str(tmp_path / "temp.png")
im = Image.new("L", (xdim, ydim), 0) im = Image.new("L", (xdim, ydim), 0)
im.save(f) im.save(f)
def test_large(self):
def test_large(tmp_path):
""" succeeded prepatch""" """ succeeded prepatch"""
self._write_png(XDIM, YDIM) _write_png(tmp_path, XDIM, YDIM)
def test_2gpx(self):
def test_2gpx(tmp_path):
"""failed prepatch""" """failed prepatch"""
self._write_png(XDIM, XDIM) _write_png(tmp_path, XDIM, XDIM)
@unittest.skipIf(numpy is None, "Numpy is not installed")
def test_size_greater_than_int(self): @pytest.mark.skipif(numpy is None, reason="Numpy is not installed")
def test_size_greater_than_int():
arr = numpy.ndarray(shape=(16394, 16394)) arr = numpy.ndarray(shape=(16394, 16394))
Image.fromarray(arr) Image.fromarray(arr)
if __name__ == "__main__":
unittest.main()

View File

@ -1,10 +1,8 @@
import sys import sys
import unittest
import pytest
from PIL import Image from PIL import Image
from .helper import PillowTestCase
# This test is not run automatically. # This test is not run automatically.
# #
# It requires > 2gb memory for the >2 gigapixel image generated in the # It requires > 2gb memory for the >2 gigapixel image generated in the
@ -14,32 +12,28 @@ from .helper import PillowTestCase
# Raspberry Pis). # Raspberry Pis).
try: np = pytest.importorskip("numpy", reason="NumPy not installed")
import numpy as np
except ImportError:
raise unittest.SkipTest("numpy not installed")
YDIM = 32769 YDIM = 32769
XDIM = 48000 XDIM = 48000
@unittest.skipIf(sys.maxsize <= 2 ** 32, "requires 64-bit system") pytestmark = pytest.mark.skipif(sys.maxsize <= 2 ** 32, reason="requires 64-bit system")
class LargeMemoryNumpyTest(PillowTestCase):
def _write_png(self, xdim, ydim):
def _write_png(tmp_path, xdim, ydim):
dtype = np.uint8 dtype = np.uint8
a = np.zeros((xdim, ydim), dtype=dtype) a = np.zeros((xdim, ydim), dtype=dtype)
f = self.tempfile("temp.png") f = str(tmp_path / "temp.png")
im = Image.fromarray(a, "L") im = Image.fromarray(a, "L")
im.save(f) im.save(f)
def test_large(self):
def test_large(tmp_path):
""" succeeded prepatch""" """ succeeded prepatch"""
self._write_png(XDIM, YDIM) _write_png(tmp_path, XDIM, YDIM)
def test_2gpx(self):
def test_2gpx(tmp_path):
"""failed prepatch""" """failed prepatch"""
self._write_png(XDIM, XDIM) _write_png(tmp_path, XDIM, XDIM)
if __name__ == "__main__":
unittest.main()

View File

@ -1,15 +1,10 @@
import unittest
import pytest import pytest
from PIL import Image from PIL import Image
from .helper import PillowTestCase
TEST_FILE = "Tests/images/libtiff_segfault.tif" TEST_FILE = "Tests/images/libtiff_segfault.tif"
class TestLibtiffSegfault(PillowTestCase): def test_libtiff_segfault():
def test_segfault(self):
""" This test should not segfault. It will on Pillow <= 3.1.0 and """ This test should not segfault. It will on Pillow <= 3.1.0 and
libtiff >= 4.0.0 libtiff >= 4.0.0
""" """
@ -17,7 +12,3 @@ class TestLibtiffSegfault(PillowTestCase):
with pytest.raises(IOError): with pytest.raises(IOError):
with Image.open(TEST_FILE) as im: with Image.open(TEST_FILE) as im:
im.load() im.load()
if __name__ == "__main__":
unittest.main()

View File

@ -1,16 +1,12 @@
import unittest
import zlib import zlib
from io import BytesIO from io import BytesIO
from PIL import Image, ImageFile, PngImagePlugin from PIL import Image, ImageFile, PngImagePlugin
from .helper import PillowTestCase
TEST_FILE = "Tests/images/png_decompression_dos.png" TEST_FILE = "Tests/images/png_decompression_dos.png"
class TestPngDos(PillowTestCase): def test_ignore_dos_text():
def test_ignore_dos_text(self):
ImageFile.LOAD_TRUNCATED_IMAGES = True ImageFile.LOAD_TRUNCATED_IMAGES = True
try: try:
@ -25,7 +21,8 @@ class TestPngDos(PillowTestCase):
for s in im.info.values(): for s in im.info.values():
assert len(s) < 1024 * 1024, "Text chunk larger than 1M" assert len(s) < 1024 * 1024, "Text chunk larger than 1M"
def test_dos_text(self):
def test_dos_text():
try: try:
im = Image.open(TEST_FILE) im = Image.open(TEST_FILE)
@ -37,7 +34,8 @@ class TestPngDos(PillowTestCase):
for s in im.text.values(): for s in im.text.values():
assert len(s) < 1024 * 1024, "Text chunk larger than 1M" assert len(s) < 1024 * 1024, "Text chunk larger than 1M"
def test_dos_total_memory(self):
def test_dos_total_memory():
im = Image.new("L", (1, 1)) im = Image.new("L", (1, 1))
compressed_data = zlib.compress(b"a" * 1024 * 1023) compressed_data = zlib.compress(b"a" * 1024 * 1023)
@ -61,7 +59,3 @@ class TestPngDos(PillowTestCase):
for txt in im2.text.values(): for txt in im2.text.values():
total_len += len(txt) total_len += len(txt)
assert total_len < 64 * 1024 * 1024, "Total text chunks greater than 64M" assert total_len < 64 * 1024 * 1024, "Total text chunks greater than 64M"
if __name__ == "__main__":
unittest.main()

View File

@ -7,7 +7,6 @@ import os
import shutil import shutil
import sys import sys
import tempfile import tempfile
import unittest
from io import BytesIO from io import BytesIO
import pytest import pytest
@ -176,22 +175,6 @@ def skip_unless_feature(feature):
return pytest.mark.skipif(not features.check(feature), reason=reason) return pytest.mark.skipif(not features.check(feature), reason=reason)
class PillowTestCase(unittest.TestCase):
def delete_tempfile(self, path):
try:
os.remove(path)
except OSError:
pass # report?
def tempfile(self, template):
assert template[:5] in ("temp.", "temp_")
fd, path = tempfile.mkstemp(template[4:], template[:4])
os.close(fd)
self.addCleanup(self.delete_tempfile, path)
return path
@pytest.mark.skipif(sys.platform.startswith("win32"), reason="Requires Unix or macOS") @pytest.mark.skipif(sys.platform.startswith("win32"), reason="Requires Unix or macOS")
class PillowLeakTestCase: class PillowLeakTestCase:
# requires unix/macOS # requires unix/macOS

View File

@ -1,15 +1,16 @@
import pytest import pytest
from PIL import Image from PIL import Image
from .helper import PillowTestCase, hopper from .helper import hopper
TEST_FILE = "Tests/images/hopper.ppm" TEST_FILE = "Tests/images/hopper.ppm"
ORIGINAL_LIMIT = Image.MAX_IMAGE_PIXELS ORIGINAL_LIMIT = Image.MAX_IMAGE_PIXELS
class TestDecompressionBomb(PillowTestCase): class TestDecompressionBomb:
def tearDown(self): @classmethod
def teardown_class(self):
Image.MAX_IMAGE_PIXELS = ORIGINAL_LIMIT Image.MAX_IMAGE_PIXELS = ORIGINAL_LIMIT
def test_no_warning_small_file(self): def test_no_warning_small_file(self):
@ -59,12 +60,14 @@ class TestDecompressionBomb(PillowTestCase):
Image.open("Tests/images/decompression_bomb.gif") Image.open("Tests/images/decompression_bomb.gif")
class TestDecompressionCrop(PillowTestCase): class TestDecompressionCrop:
def setUp(self): @classmethod
def setup_class(self):
width, height = 128, 128 width, height = 128, 128
Image.MAX_IMAGE_PIXELS = height * width * 4 - 1 Image.MAX_IMAGE_PIXELS = height * width * 4 - 1
def tearDown(self): @classmethod
def teardown_class(self):
Image.MAX_IMAGE_PIXELS = ORIGINAL_LIMIT Image.MAX_IMAGE_PIXELS = ORIGINAL_LIMIT
def testEnlargeCrop(self): def testEnlargeCrop(self):

View File

@ -1,11 +1,10 @@
import pytest import pytest
from PIL import Image, WmfImagePlugin from PIL import Image, WmfImagePlugin
from .helper import PillowTestCase, assert_image_similar, hopper from .helper import assert_image_similar, hopper
class TestFileWmf(PillowTestCase): def test_load_raw():
def test_load_raw(self):
# Test basic EMF open and rendering # Test basic EMF open and rendering
with Image.open("Tests/images/drawing.emf") as im: with Image.open("Tests/images/drawing.emf") as im:
@ -27,7 +26,8 @@ class TestFileWmf(PillowTestCase):
imref.load() imref.load()
assert_image_similar(im, imref, 2.0) assert_image_similar(im, imref, 2.0)
def test_register_handler(self):
def test_register_handler(tmp_path):
class TestHandler: class TestHandler:
methodCalled = False methodCalled = False
@ -38,14 +38,15 @@ class TestFileWmf(PillowTestCase):
WmfImagePlugin.register_handler(handler) WmfImagePlugin.register_handler(handler)
im = hopper() im = hopper()
tmpfile = self.tempfile("temp.wmf") tmpfile = str(tmp_path / "temp.wmf")
im.save(tmpfile) im.save(tmpfile)
assert handler.methodCalled assert handler.methodCalled
# Restore the state before this test # Restore the state before this test
WmfImagePlugin.register_handler(None) WmfImagePlugin.register_handler(None)
def test_load_dpi_rounding(self):
def test_load_dpi_rounding():
# Round up # Round up
with Image.open("Tests/images/drawing.emf") as im: with Image.open("Tests/images/drawing.emf") as im:
assert im.info["dpi"] == 1424 assert im.info["dpi"] == 1424
@ -54,7 +55,8 @@ class TestFileWmf(PillowTestCase):
with Image.open("Tests/images/drawing_roundDown.emf") as im: with Image.open("Tests/images/drawing_roundDown.emf") as im:
assert im.info["dpi"] == 1426 assert im.info["dpi"] == 1426
def test_load_set_dpi(self):
def test_load_set_dpi():
with Image.open("Tests/images/drawing.wmf") as im: with Image.open("Tests/images/drawing.wmf") as im:
assert im.size == (82, 82) assert im.size == (82, 82)
@ -65,10 +67,11 @@ class TestFileWmf(PillowTestCase):
with Image.open("Tests/images/drawing_wmf_ref_144.png") as expected: with Image.open("Tests/images/drawing_wmf_ref_144.png") as expected:
assert_image_similar(im, expected, 2.0) assert_image_similar(im, expected, 2.0)
def test_save(self):
def test_save(tmp_path):
im = hopper() im = hopper()
for ext in [".wmf", ".emf"]: for ext in [".wmf", ".emf"]:
tmpfile = self.tempfile("temp" + ext) tmpfile = str(tmp_path / ("temp" + ext))
with pytest.raises(IOError): with pytest.raises(IOError):
im.save(tmpfile) im.save(tmpfile)

View File

@ -1,12 +1,9 @@
import os import os
import pytest import pytest
from PIL import FontFile, Image, ImageDraw, ImageFont, PcfFontFile from PIL import FontFile, Image, ImageDraw, ImageFont, PcfFontFile
from .helper import ( from .helper import assert_image_equal, assert_image_similar, skip_unless_feature
assert_image_equal,
assert_image_similar,
skip_unless_feature,
)
fontname = "Tests/fonts/10x20-ISO8859-1.pcf" fontname = "Tests/fonts/10x20-ISO8859-1.pcf"

View File

@ -2,10 +2,10 @@ import pytest
from PIL import Image, ImageQt from PIL import Image, ImageQt
from .helper import assert_image_equal, hopper from .helper import assert_image_equal, hopper
from .test_imageqt import skip_if_qt_is_not_installed
pytestmark = pytest.mark.skipif(
pytestmark = skip_if_qt_is_not_installed() not ImageQt.qt_is_installed, reason="Qt bindings are not installed"
)
@pytest.fixture @pytest.fixture
@ -18,7 +18,7 @@ def test_images():
try: try:
yield ims yield ims
finally: finally:
for im in ims.values(): for im in ims:
im.close() im.close()

View File

@ -1,9 +1,9 @@
from PIL import Image from PIL import Image
from .helper import PillowTestCase, assert_image_equal, cached_property from .helper import assert_image_equal, cached_property
class TestImagingPaste(PillowTestCase): class TestImagingPaste:
masks = {} masks = {}
size = 128 size = 128

View File

@ -6,10 +6,10 @@ from itertools import permutations
import pytest import pytest
from PIL import Image from PIL import Image
from .helper import PillowTestCase, assert_image_equal, assert_image_similar, hopper from .helper import assert_image_equal, assert_image_similar, hopper
class TestImagingCoreResize(PillowTestCase): class TestImagingCoreResize:
def resize(self, im, size, f): def resize(self, im, size, f):
# Image class independent version of resize. # Image class independent version of resize.
im.load() im.load()
@ -135,31 +135,36 @@ class TestImagingCoreResize(PillowTestCase):
self.resize(hopper(), (10, 10), 9) self.resize(hopper(), (10, 10), 9)
class TestReducingGapResize(PillowTestCase): @pytest.fixture
@classmethod def gradients_image():
def setUpClass(cls): im = Image.open("Tests/images/radial_gradients.png")
cls.gradients_image = Image.open("Tests/images/radial_gradients.png") im.load()
cls.gradients_image.load() try:
yield im
finally:
im.close()
def test_reducing_gap_values(self):
ref = self.gradients_image.resize((52, 34), Image.BICUBIC, reducing_gap=None) class TestReducingGapResize:
im = self.gradients_image.resize((52, 34), Image.BICUBIC) def test_reducing_gap_values(self, gradients_image):
ref = gradients_image.resize((52, 34), Image.BICUBIC, reducing_gap=None)
im = gradients_image.resize((52, 34), Image.BICUBIC)
assert_image_equal(ref, im) assert_image_equal(ref, im)
with pytest.raises(ValueError): with pytest.raises(ValueError):
self.gradients_image.resize((52, 34), Image.BICUBIC, reducing_gap=0) gradients_image.resize((52, 34), Image.BICUBIC, reducing_gap=0)
with pytest.raises(ValueError): with pytest.raises(ValueError):
self.gradients_image.resize((52, 34), Image.BICUBIC, reducing_gap=0.99) gradients_image.resize((52, 34), Image.BICUBIC, reducing_gap=0.99)
def test_reducing_gap_1(self): def test_reducing_gap_1(self, gradients_image):
for box, epsilon in [ for box, epsilon in [
(None, 4), (None, 4),
((1.1, 2.2, 510.8, 510.9), 4), ((1.1, 2.2, 510.8, 510.9), 4),
((3, 10, 410, 256), 10), ((3, 10, 410, 256), 10),
]: ]:
ref = self.gradients_image.resize((52, 34), Image.BICUBIC, box=box) ref = gradients_image.resize((52, 34), Image.BICUBIC, box=box)
im = self.gradients_image.resize( im = gradients_image.resize(
(52, 34), Image.BICUBIC, box=box, reducing_gap=1.0 (52, 34), Image.BICUBIC, box=box, reducing_gap=1.0
) )
@ -168,14 +173,14 @@ class TestReducingGapResize(PillowTestCase):
assert_image_similar(ref, im, epsilon) assert_image_similar(ref, im, epsilon)
def test_reducing_gap_2(self): def test_reducing_gap_2(self, gradients_image):
for box, epsilon in [ for box, epsilon in [
(None, 1.5), (None, 1.5),
((1.1, 2.2, 510.8, 510.9), 1.5), ((1.1, 2.2, 510.8, 510.9), 1.5),
((3, 10, 410, 256), 1), ((3, 10, 410, 256), 1),
]: ]:
ref = self.gradients_image.resize((52, 34), Image.BICUBIC, box=box) ref = gradients_image.resize((52, 34), Image.BICUBIC, box=box)
im = self.gradients_image.resize( im = gradients_image.resize(
(52, 34), Image.BICUBIC, box=box, reducing_gap=2.0 (52, 34), Image.BICUBIC, box=box, reducing_gap=2.0
) )
@ -184,14 +189,14 @@ class TestReducingGapResize(PillowTestCase):
assert_image_similar(ref, im, epsilon) assert_image_similar(ref, im, epsilon)
def test_reducing_gap_3(self): def test_reducing_gap_3(self, gradients_image):
for box, epsilon in [ for box, epsilon in [
(None, 1), (None, 1),
((1.1, 2.2, 510.8, 510.9), 1), ((1.1, 2.2, 510.8, 510.9), 1),
((3, 10, 410, 256), 0.5), ((3, 10, 410, 256), 0.5),
]: ]:
ref = self.gradients_image.resize((52, 34), Image.BICUBIC, box=box) ref = gradients_image.resize((52, 34), Image.BICUBIC, box=box)
im = self.gradients_image.resize( im = gradients_image.resize(
(52, 34), Image.BICUBIC, box=box, reducing_gap=3.0 (52, 34), Image.BICUBIC, box=box, reducing_gap=3.0
) )
@ -200,29 +205,27 @@ class TestReducingGapResize(PillowTestCase):
assert_image_similar(ref, im, epsilon) assert_image_similar(ref, im, epsilon)
def test_reducing_gap_8(self): def test_reducing_gap_8(self, gradients_image):
for box in [None, (1.1, 2.2, 510.8, 510.9), (3, 10, 410, 256)]: for box in [None, (1.1, 2.2, 510.8, 510.9), (3, 10, 410, 256)]:
ref = self.gradients_image.resize((52, 34), Image.BICUBIC, box=box) ref = gradients_image.resize((52, 34), Image.BICUBIC, box=box)
im = self.gradients_image.resize( im = gradients_image.resize(
(52, 34), Image.BICUBIC, box=box, reducing_gap=8.0 (52, 34), Image.BICUBIC, box=box, reducing_gap=8.0
) )
assert_image_equal(ref, im) assert_image_equal(ref, im)
def test_box_filter(self): def test_box_filter(self, gradients_image):
for box, epsilon in [ for box, epsilon in [
((0, 0, 512, 512), 5.5), ((0, 0, 512, 512), 5.5),
((0.9, 1.7, 128, 128), 9.5), ((0.9, 1.7, 128, 128), 9.5),
]: ]:
ref = self.gradients_image.resize((52, 34), Image.BOX, box=box) ref = gradients_image.resize((52, 34), Image.BOX, box=box)
im = self.gradients_image.resize( im = gradients_image.resize((52, 34), Image.BOX, box=box, reducing_gap=1.0)
(52, 34), Image.BOX, box=box, reducing_gap=1.0
)
assert_image_similar(ref, im, epsilon) assert_image_similar(ref, im, epsilon)
class TestImageResize(PillowTestCase): class TestImageResize:
def test_resize(self): def test_resize(self):
def resize(mode, size): def resize(mode, size):
out = hopper(mode).resize(size) out = hopper(mode).resize(size)

View File

@ -10,7 +10,6 @@ import pytest
from PIL import Image, ImageDraw, ImageFont from PIL import Image, ImageDraw, ImageFont
from .helper import ( from .helper import (
PillowTestCase,
assert_image_equal, assert_image_equal,
assert_image_similar, assert_image_similar,
assert_image_similar_tofile, assert_image_similar_tofile,
@ -25,8 +24,10 @@ FONT_SIZE = 20
TEST_TEXT = "hey you\nyou are awesome\nthis looks awkward" TEST_TEXT = "hey you\nyou are awesome\nthis looks awkward"
@skip_unless_feature("freetype2") pytestmark = skip_unless_feature("freetype2")
class TestImageFont(PillowTestCase):
class TestImageFont:
LAYOUT_ENGINE = ImageFont.LAYOUT_BASIC LAYOUT_ENGINE = ImageFont.LAYOUT_BASIC
# Freetype has different metrics depending on the version. # Freetype has different metrics depending on the version.
@ -37,7 +38,8 @@ class TestImageFont(PillowTestCase):
"Default": {"multiline": 0.5, "textsize": 0.5, "getters": (12, 16)}, "Default": {"multiline": 0.5, "textsize": 0.5, "getters": (12, 16)},
} }
def setUp(self): @classmethod
def setup_class(self):
freetype = distutils.version.StrictVersion(ImageFont.core.freetype2_version) freetype = distutils.version.StrictVersion(ImageFont.core.freetype2_version)
self.metrics = self.METRICS["Default"] self.metrics = self.METRICS["Default"]
@ -107,12 +109,12 @@ class TestImageFont(PillowTestCase):
with open(FONT_PATH, "rb") as f: with open(FONT_PATH, "rb") as f:
self._render(f) self._render(f)
def test_non_unicode_path(self): def test_non_unicode_path(self, tmp_path):
tempfile = str(tmp_path / ("temp_" + chr(128) + ".ttf"))
try: try:
tempfile = self.tempfile("temp_" + chr(128) + ".ttf")
except UnicodeEncodeError:
self.skipTest("Unicode path could not be created")
shutil.copy(FONT_PATH, tempfile) shutil.copy(FONT_PATH, tempfile)
except UnicodeEncodeError:
pytest.skip("Unicode path could not be created")
ImageFont.truetype(tempfile, FONT_SIZE) ImageFont.truetype(tempfile, FONT_SIZE)

View File

@ -6,11 +6,11 @@ from .helper import hopper
if ImageQt.qt_is_installed: if ImageQt.qt_is_installed:
from PIL.ImageQt import qRgba from PIL.ImageQt import qRgba
def skip_if_qt_is_not_installed():
pass
@pytest.fixture @pytest.mark.skipif(not ImageQt.qt_is_installed, reason="Qt bindings are not installed")
def qpixmap_app(): class PillowQPixmapTestCase:
@classmethod
def setup_class(self):
try: try:
if ImageQt.qt_version == "5": if ImageQt.qt_version == "5":
from PyQt5.QtGui import QGuiApplication from PyQt5.QtGui import QGuiApplication
@ -20,22 +20,15 @@ if ImageQt.qt_is_installed:
pytest.skip("QGuiApplication not installed") pytest.skip("QGuiApplication not installed")
return return
app = QGuiApplication([]) self.app = QGuiApplication([])
try:
yield @classmethod
finally: def teardown_class(self):
app.quit() self.app.quit()
self.app = None
else:
def skip_if_qt_is_not_installed():
return pytest.mark.skip(reason="Qt bindings are not installed")
pytestmark = skip_if_qt_is_not_installed()
@pytest.mark.skipif(not ImageQt.qt_is_installed, reason="Qt bindings are not installed")
def test_rgb(): def test_rgb():
# from https://doc.qt.io/archives/qt-4.8/qcolor.html # from https://doc.qt.io/archives/qt-4.8/qcolor.html
# typedef QRgb # typedef QRgb
@ -61,6 +54,7 @@ def test_rgb():
checkrgb(0, 0, 255) checkrgb(0, 0, 255)
@pytest.mark.skipif(not ImageQt.qt_is_installed, reason="Qt bindings are not installed")
def test_image(): def test_image():
for mode in ("1", "RGB", "RGBA", "L", "P"): for mode in ("1", "RGB", "RGBA", "L", "P"):
ImageQt.ImageQt(hopper(mode)) ImageQt.ImageQt(hopper(mode))

View File

@ -1,18 +1,15 @@
import pytest
from PIL import ImageQt from PIL import ImageQt
from .helper import assert_image_equal, hopper from .helper import assert_image_equal, hopper
from .test_imageqt import qpixmap_app, skip_if_qt_is_not_installed from .test_imageqt import PillowQPixmapTestCase
pytestmark = skip_if_qt_is_not_installed()
def roundtrip(expected): class TestFromQPixmap(PillowQPixmapTestCase):
def roundtrip(self, expected):
result = ImageQt.fromqpixmap(ImageQt.toqpixmap(expected)) result = ImageQt.fromqpixmap(ImageQt.toqpixmap(expected))
# Qt saves all pixmaps as rgb # Qt saves all pixmaps as rgb
assert_image_equal(result, expected.convert("RGB")) assert_image_equal(result, expected.convert("RGB"))
def test_sanity(self):
def test_sanity(qpixmap_app):
for mode in ("1", "RGB", "RGBA", "L", "P"): for mode in ("1", "RGB", "RGBA", "L", "P"):
roundtrip(hopper(mode)) self.roundtrip(hopper(mode))

View File

@ -1,9 +1,11 @@
import pytest
from PIL import Image, ImageQt from PIL import Image, ImageQt
from .helper import assert_image_equal, hopper from .helper import assert_image_equal, hopper
from .test_imageqt import skip_if_qt_is_not_installed
pytestmark = skip_if_qt_is_not_installed() pytestmark = pytest.mark.skipif(
not ImageQt.qt_is_installed, reason="Qt bindings are not installed"
)
if ImageQt.qt_is_installed: if ImageQt.qt_is_installed:
from PIL.ImageQt import QImage from PIL.ImageQt import QImage

View File

@ -1,16 +1,14 @@
import pytest
from PIL import ImageQt from PIL import ImageQt
from .helper import hopper from .helper import hopper
from .test_imageqt import qpixmap_app, skip_if_qt_is_not_installed from .test_imageqt import PillowQPixmapTestCase
if ImageQt.qt_is_installed: if ImageQt.qt_is_installed:
from PIL.ImageQt import QPixmap from PIL.ImageQt import QPixmap
pytestmark = skip_if_qt_is_not_installed()
class TestToQPixmap(PillowQPixmapTestCase):
def test_sanity(qpixmap, tmp_path): def test_sanity(self, tmp_path):
for mode in ("1", "RGB", "RGBA", "L", "P"): for mode in ("1", "RGB", "RGBA", "L", "P"):
data = ImageQt.toqpixmap(hopper(mode)) data = ImageQt.toqpixmap(hopper(mode))