Merge remote-tracking branch 'upstream/master' into pytest.importorskip

This commit is contained in:
Hugo 2020-02-19 19:26:52 +02:00
commit 2d5e479bcc
29 changed files with 138 additions and 272 deletions

View File

@ -3,22 +3,18 @@ from io import BytesIO
from PIL import Image from PIL import Image
from .helper import PillowTestCase, is_win32 from .helper import PillowTestCase, is_win32, skip_unless_feature
# Limits for testing the leak # Limits for testing the leak
mem_limit = 1024 * 1048576 mem_limit = 1024 * 1048576
stack_size = 8 * 1048576 stack_size = 8 * 1048576
iterations = int((mem_limit / stack_size) * 2) iterations = int((mem_limit / stack_size) * 2)
codecs = dir(Image.core)
test_file = "Tests/images/rgb_trns_ycbc.jp2" test_file = "Tests/images/rgb_trns_ycbc.jp2"
@unittest.skipIf(is_win32(), "requires Unix or macOS") @unittest.skipIf(is_win32(), "requires Unix or macOS")
@skip_unless_feature("jpg_2000")
class TestJpegLeaks(PillowTestCase): class TestJpegLeaks(PillowTestCase):
def setUp(self):
if "jpeg2k_encoder" not in codecs or "jpeg2k_decoder" not in codecs:
self.skipTest("JPEG 2000 support not available")
def test_leak_load(self): def test_leak_load(self):
from resource import setrlimit, RLIMIT_AS, RLIMIT_STACK from resource import setrlimit, RLIMIT_AS, RLIMIT_STACK

View File

@ -12,7 +12,7 @@ import unittest
from io import BytesIO from io import BytesIO
import pytest import pytest
from PIL import Image, ImageMath from PIL import Image, ImageMath, features
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
@ -172,6 +172,11 @@ def skip_known_bad_test(msg=None):
pytest.skip(msg or "Known bad test") pytest.skip(msg or "Known bad test")
def skip_unless_feature(feature):
reason = "%s not available" % feature
return pytest.mark.skipif(not features.check(feature), reason=reason)
class PillowTestCase(unittest.TestCase): class PillowTestCase(unittest.TestCase):
def delete_tempfile(self, path): def delete_tempfile(self, path):
try: try:

View File

@ -3,12 +3,12 @@ import io
import pytest import pytest
from PIL import features from PIL import features
from .helper import skip_unless_feature
try: try:
from PIL import _webp from PIL import _webp
HAVE_WEBP = True
except ImportError: except ImportError:
HAVE_WEBP = False pass
def test_check(): def test_check():
@ -21,18 +21,18 @@ def test_check():
assert features.check_feature(feature) == features.check(feature) assert features.check_feature(feature) == features.check(feature)
@pytest.mark.skipif(not HAVE_WEBP, reason="WebP not available") @skip_unless_feature("webp")
def test_webp_transparency(): def test_webp_transparency():
assert features.check("transp_webp") != _webp.WebPDecoderBuggyAlpha() assert features.check("transp_webp") != _webp.WebPDecoderBuggyAlpha()
assert features.check("transp_webp") == _webp.HAVE_TRANSPARENCY assert features.check("transp_webp") == _webp.HAVE_TRANSPARENCY
@pytest.mark.skipif(not HAVE_WEBP, reason="WebP not available") @skip_unless_feature("webp")
def test_webp_mux(): def test_webp_mux():
assert features.check("webp_mux") == _webp.HAVE_WEBPMUX assert features.check("webp_mux") == _webp.HAVE_WEBPMUX
@pytest.mark.skipif(not HAVE_WEBP, reason="WebP not available") @skip_unless_feature("webp")
def test_webp_anim(): def test_webp_anim():
assert features.check("webp_anim") == _webp.HAVE_WEBPANIM assert features.check("webp_anim") == _webp.HAVE_WEBPANIM

View File

@ -1,9 +1,9 @@
import io import io
import unittest import unittest
from PIL import EpsImagePlugin, Image from PIL import EpsImagePlugin, Image, features
from .helper import PillowTestCase, assert_image_similar, hopper from .helper import PillowTestCase, assert_image_similar, hopper, skip_unless_feature
HAS_GHOSTSCRIPT = EpsImagePlugin.has_ghostscript() HAS_GHOSTSCRIPT = EpsImagePlugin.has_ghostscript()
@ -67,7 +67,7 @@ class TestFileEps(PillowTestCase):
cmyk_image.load() cmyk_image.load()
self.assertEqual(cmyk_image.mode, "RGB") self.assertEqual(cmyk_image.mode, "RGB")
if "jpeg_decoder" in dir(Image.core): if features.check("jpg"):
with Image.open("Tests/images/pil_sample_rgb.jpg") as target: with Image.open("Tests/images/pil_sample_rgb.jpg") as target:
assert_image_similar(cmyk_image, target, 10) assert_image_similar(cmyk_image, target, 10)
@ -114,11 +114,9 @@ class TestFileEps(PillowTestCase):
self.assertRaises(ValueError, im.save, tmpfile) self.assertRaises(ValueError, im.save, tmpfile)
@unittest.skipUnless(HAS_GHOSTSCRIPT, "Ghostscript not available") @unittest.skipUnless(HAS_GHOSTSCRIPT, "Ghostscript not available")
@skip_unless_feature("zlib")
def test_render_scale1(self): def test_render_scale1(self):
# We need png support for these render test # We need png support for these render test
codecs = dir(Image.core)
if "zip_encoder" not in codecs or "zip_decoder" not in codecs:
self.skipTest("zip/deflate support not available")
# Zero bounding box # Zero bounding box
with Image.open(file1) as image1_scale1: with Image.open(file1) as image1_scale1:
@ -137,11 +135,9 @@ class TestFileEps(PillowTestCase):
assert_image_similar(image2_scale1, image2_scale1_compare, 10) assert_image_similar(image2_scale1, image2_scale1_compare, 10)
@unittest.skipUnless(HAS_GHOSTSCRIPT, "Ghostscript not available") @unittest.skipUnless(HAS_GHOSTSCRIPT, "Ghostscript not available")
@skip_unless_feature("zlib")
def test_render_scale2(self): def test_render_scale2(self):
# We need png support for these render test # We need png support for these render test
codecs = dir(Image.core)
if "zip_encoder" not in codecs or "zip_decoder" not in codecs:
self.skipTest("zip/deflate support not available")
# Zero bounding box # Zero bounding box
with Image.open(file1) as image1_scale2: with Image.open(file1) as image1_scale2:

View File

@ -2,7 +2,7 @@ import unittest
from io import BytesIO from io import BytesIO
import pytest import pytest
from PIL import GifImagePlugin, Image, ImageDraw, ImagePalette from PIL import GifImagePlugin, Image, ImageDraw, ImagePalette, features
from .helper import ( from .helper import (
PillowTestCase, PillowTestCase,
@ -13,15 +13,6 @@ from .helper import (
netpbm_available, netpbm_available,
) )
try:
from PIL import _webp
HAVE_WEBP = True
except ImportError:
HAVE_WEBP = False
codecs = dir(Image.core)
# sample gif stream # sample gif stream
TEST_GIF = "Tests/images/hopper.gif" TEST_GIF = "Tests/images/hopper.gif"
@ -30,10 +21,6 @@ with open(TEST_GIF, "rb") as f:
class TestFileGif(PillowTestCase): class TestFileGif(PillowTestCase):
def setUp(self):
if "gif_encoder" not in codecs or "gif_decoder" not in codecs:
self.skipTest("gif support not available") # can this happen?
def test_sanity(self): def test_sanity(self):
with Image.open(TEST_GIF) as im: with Image.open(TEST_GIF) as im:
im.load() im.load()
@ -562,7 +549,7 @@ class TestFileGif(PillowTestCase):
self.assertEqual(reread.info["background"], im.info["background"]) self.assertEqual(reread.info["background"], im.info["background"])
if HAVE_WEBP and _webp.HAVE_WEBPANIM: if features.check("webp") and features.check("webp_anim"):
with Image.open("Tests/images/hopper.webp") as im: with Image.open("Tests/images/hopper.webp") as im:
self.assertIsInstance(im.info["background"], tuple) self.assertIsInstance(im.info["background"], tuple)
im.save(out) im.save(out)

View File

@ -13,19 +13,15 @@ from .helper import (
djpeg_available, djpeg_available,
hopper, hopper,
is_win32, is_win32,
skip_unless_feature,
unittest, unittest,
) )
codecs = dir(Image.core)
TEST_FILE = "Tests/images/hopper.jpg" TEST_FILE = "Tests/images/hopper.jpg"
@skip_unless_feature("jpg")
class TestFileJpeg(PillowTestCase): class TestFileJpeg(PillowTestCase):
def setUp(self):
if "jpeg_encoder" not in codecs or "jpeg_decoder" not in codecs:
self.skipTest("jpeg support not available")
def roundtrip(self, im, **options): def roundtrip(self, im, **options):
out = BytesIO() out = BytesIO()
im.save(out, "JPEG", **options) im.save(out, "JPEG", **options)
@ -687,11 +683,8 @@ class TestFileJpeg(PillowTestCase):
@unittest.skipUnless(is_win32(), "Windows only") @unittest.skipUnless(is_win32(), "Windows only")
@skip_unless_feature("jpg")
class TestFileCloseW32(PillowTestCase): class TestFileCloseW32(PillowTestCase):
def setUp(self):
if "jpeg_encoder" not in codecs or "jpeg_decoder" not in codecs:
self.skipTest("jpeg support not available")
def test_fd_leak(self): def test_fd_leak(self):
tmpfile = self.tempfile("temp.jpg") tmpfile = self.tempfile("temp.jpg")

View File

@ -9,10 +9,9 @@ from .helper import (
assert_image_similar, assert_image_similar,
is_big_endian, is_big_endian,
on_ci, on_ci,
skip_unless_feature,
) )
codecs = dir(Image.core)
test_card = Image.open("Tests/images/test-card.png") test_card = Image.open("Tests/images/test-card.png")
test_card.load() test_card.load()
@ -21,11 +20,8 @@ test_card.load()
# 'Not enough memory to handle tile data' # 'Not enough memory to handle tile data'
@skip_unless_feature("jpg_2000")
class TestFileJpeg2k(PillowTestCase): class TestFileJpeg2k(PillowTestCase):
def setUp(self):
if "jpeg2k_encoder" not in codecs or "jpeg2k_decoder" not in codecs:
self.skipTest("JPEG 2000 support not available")
def roundtrip(self, im, **options): def roundtrip(self, im, **options):
out = BytesIO() out = BytesIO()
im.save(out, "JPEG2000", **options) im.save(out, "JPEG2000", **options)

View File

@ -6,7 +6,7 @@ import os
from collections import namedtuple from collections import namedtuple
from ctypes import c_float from ctypes import c_float
from PIL import Image, ImageFilter, TiffImagePlugin, TiffTags, features from PIL import Image, ImageFilter, TiffImagePlugin, TiffTags
from .helper import ( from .helper import (
PillowTestCase, PillowTestCase,
@ -15,16 +15,14 @@ from .helper import (
assert_image_similar, assert_image_similar,
assert_image_similar_tofile, assert_image_similar_tofile,
hopper, hopper,
skip_unless_feature,
) )
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
@skip_unless_feature("libtiff")
class LibTiffTestCase(PillowTestCase): class LibTiffTestCase(PillowTestCase):
def setUp(self):
if not features.check("libtiff"):
self.skipTest("tiff support not available")
def _assert_noerr(self, im): def _assert_noerr(self, im):
"""Helper tests that assert basic sanity about the g4 tiff reading""" """Helper tests that assert basic sanity about the g4 tiff reading"""
# 1 bit # 1 bit
@ -727,13 +725,9 @@ class TestFileLibTiff(LibTiffTestCase):
assert_image_equal_tofile(im, "Tests/images/tiff_16bit_RGBa_target.png") assert_image_equal_tofile(im, "Tests/images/tiff_16bit_RGBa_target.png")
@skip_unless_feature("jpg")
def test_gimp_tiff(self): def test_gimp_tiff(self):
# Read TIFF JPEG images from GIMP [@PIL168] # Read TIFF JPEG images from GIMP [@PIL168]
codecs = dir(Image.core)
if "jpeg_decoder" not in codecs:
self.skipTest("jpeg support not available")
filename = "Tests/images/pil168.tif" filename = "Tests/images/pil168.tif"
with Image.open(filename) as im: with Image.open(filename) as im:
self.assertEqual(im.mode, "RGB") self.assertEqual(im.mode, "RGB")

View File

@ -1,16 +1,12 @@
import pytest import pytest
from PIL import Image, ImagePalette, features from PIL import Image, ImagePalette
from .helper import assert_image_similar, hopper from .helper import assert_image_similar, hopper, skip_unless_feature
MicImagePlugin = pytest.importorskip( MicImagePlugin = pytest.importorskip(
"PIL.MicImagePlugin", reason="olefile not installed" "PIL.MicImagePlugin", reason="olefile not installed"
) )
pytestmark = skip_unless_feature("libtiff")
pytestmark = pytest.mark.skipif(
not features.check("libtiff"), reason="libtiff not installed"
)
TEST_FILE = "Tests/images/hopper.mic" TEST_FILE = "Tests/images/hopper.mic"

View File

@ -3,15 +3,11 @@ from io import BytesIO
import pytest import pytest
from PIL import Image from PIL import Image
from .helper import assert_image_similar, is_pypy from .helper import assert_image_similar, is_pypy, skip_unless_feature
test_files = ["Tests/images/sugarshack.mpo", "Tests/images/frozenpond.mpo"] test_files = ["Tests/images/sugarshack.mpo", "Tests/images/frozenpond.mpo"]
pytestmark = skip_unless_feature("jpg")
def setup_module():
codecs = dir(Image.core)
if "jpeg_encoder" not in codecs or "jpeg_decoder" not in codecs:
pytest.skip("jpeg support not available")
def frame_roundtrip(im, **options): def frame_roundtrip(im, **options):

View File

@ -15,18 +15,9 @@ from .helper import (
is_big_endian, is_big_endian,
is_win32, is_win32,
on_ci, on_ci,
skip_unless_feature,
) )
try:
from PIL import _webp
HAVE_WEBP = True
except ImportError:
HAVE_WEBP = False
codecs = dir(Image.core)
# sample png stream # sample png stream
TEST_PNG_FILE = "Tests/images/hopper.png" TEST_PNG_FILE = "Tests/images/hopper.png"
@ -63,11 +54,8 @@ def roundtrip(im, **options):
return Image.open(out) return Image.open(out)
@skip_unless_feature("zlib")
class TestFilePng(PillowTestCase): class TestFilePng(PillowTestCase):
def setUp(self):
if "zip_encoder" not in codecs or "zip_decoder" not in codecs:
self.skipTest("zip/deflate support not available")
def get_chunks(self, filename): def get_chunks(self, filename):
chunks = [] chunks = []
with open(filename, "rb") as fp: with open(filename, "rb") as fp:
@ -632,9 +620,8 @@ class TestFilePng(PillowTestCase):
with Image.open(test_file) as reloaded: with Image.open(test_file) as reloaded:
self.assertEqual(reloaded.info["exif"], b"Exif\x00\x00exifstring") self.assertEqual(reloaded.info["exif"], b"Exif\x00\x00exifstring")
@unittest.skipUnless( @skip_unless_feature("webp")
HAVE_WEBP and _webp.HAVE_WEBPANIM, "WebP support not installed with animation" @skip_unless_feature("webp_anim")
)
def test_apng(self): def test_apng(self):
with Image.open("Tests/images/iss634.apng") as im: with Image.open("Tests/images/iss634.apng") as im:
self.assertEqual(im.get_format_mimetype(), "image/apng") self.assertEqual(im.get_format_mimetype(), "image/apng")
@ -645,14 +632,11 @@ class TestFilePng(PillowTestCase):
@unittest.skipIf(is_win32(), "requires Unix or macOS") @unittest.skipIf(is_win32(), "requires Unix or macOS")
@skip_unless_feature("zlib")
class TestTruncatedPngPLeaks(PillowLeakTestCase): class TestTruncatedPngPLeaks(PillowLeakTestCase):
mem_limit = 2 * 1024 # max increase in K mem_limit = 2 * 1024 # max increase in K
iterations = 100 # Leak is 56k/iteration, this will leak 5.6megs iterations = 100 # Leak is 56k/iteration, this will leak 5.6megs
def setUp(self):
if "zip_encoder" not in codecs or "zip_decoder" not in codecs:
self.skipTest("zip/deflate support not available")
def test_leak_load(self): def test_leak_load(self):
with open("Tests/images/hopper.png", "rb") as f: with open("Tests/images/hopper.png", "rb") as f:
DATA = BytesIO(f.read(16 * 1024)) DATA = BytesIO(f.read(16 * 1024))

View File

@ -1,25 +1,18 @@
import pytest import pytest
from PIL import Image, TarIO from PIL import Image, TarIO, features
from .helper import is_pypy from .helper import is_pypy
codecs = dir(Image.core)
# Sample tar archive # Sample tar archive
TEST_TAR_FILE = "Tests/images/hopper.tar" TEST_TAR_FILE = "Tests/images/hopper.tar"
def setup_module():
if "zip_decoder" not in codecs and "jpeg_decoder" not in codecs:
pytest.skip("neither jpeg nor zip support available")
def test_sanity(): def test_sanity():
for codec, test_path, format in [ for codec, test_path, format in [
["zip_decoder", "hopper.png", "PNG"], ["zlib", "hopper.png", "PNG"],
["jpeg_decoder", "hopper.jpg", "JPEG"], ["jpg", "hopper.jpg", "JPEG"],
]: ]:
if codec in codecs: if features.check(codec):
with TarIO.TarIO(TEST_TAR_FILE, test_path) as tar: with TarIO.TarIO(TEST_TAR_FILE, test_path) as tar:
with Image.open(tar) as im: with Image.open(tar) as im:
im.load() im.load()

View File

@ -1,5 +1,3 @@
import unittest
import pytest import pytest
from PIL import Image, WebPImagePlugin from PIL import Image, WebPImagePlugin
@ -8,6 +6,7 @@ from .helper import (
assert_image_similar, assert_image_similar,
assert_image_similar_tofile, assert_image_similar_tofile,
hopper, hopper,
skip_unless_feature,
) )
try: try:
@ -32,7 +31,7 @@ class TestUnsupportedWebp(PillowTestCase):
WebPImagePlugin.SUPPORTED = True WebPImagePlugin.SUPPORTED = True
@unittest.skipUnless(HAVE_WEBP, "WebP support not installed") @skip_unless_feature("webp")
class TestFileWebp(PillowTestCase): class TestFileWebp(PillowTestCase):
def setUp(self): def setUp(self):
self.rgb_mode = "RGB" self.rgb_mode = "RGB"
@ -155,9 +154,8 @@ class TestFileWebp(PillowTestCase):
Image.open(blob).load() Image.open(blob).load()
Image.open(blob).load() Image.open(blob).load()
@unittest.skipUnless( @skip_unless_feature("webp")
HAVE_WEBP and _webp.HAVE_WEBPANIM, "WebP save all not available" @skip_unless_feature("webp_anim")
)
def test_background_from_gif(self): def test_background_from_gif(self):
with Image.open("Tests/images/chi.gif") as im: with Image.open("Tests/images/chi.gif") as im:
original_value = im.convert("RGB").getpixel((1, 1)) original_value = im.convert("RGB").getpixel((1, 1))

View File

@ -1,16 +1,18 @@
import pytest import pytest
from PIL import Image from PIL import Image
from .helper import assert_image_equal, assert_image_similar, is_big_endian, on_ci from .helper import (
assert_image_equal,
assert_image_similar,
is_big_endian,
on_ci,
skip_unless_feature,
)
_webp = pytest.importorskip("PIL._webp", reason="WebP support not installed") pytestmark = [
skip_unless_feature("webp"),
skip_unless_feature("webp_anim"),
def setup_module(): ]
if not _webp.HAVE_WEBPANIM:
pytest.skip(
"WebP library does not contain animation support, not testing animation"
)
def test_n_frames(): def test_n_frames():

View File

@ -4,7 +4,6 @@ from PIL import Image
from .helper import assert_image_equal, hopper from .helper import assert_image_equal, hopper
_webp = pytest.importorskip("PIL._webp", reason="WebP support not installed") _webp = pytest.importorskip("PIL._webp", reason="WebP support not installed")
RGB_MODE = "RGB" RGB_MODE = "RGB"

View File

@ -3,12 +3,13 @@ from io import BytesIO
import pytest import pytest
from PIL import Image from PIL import Image
from .helper import skip_unless_feature
_webp = pytest.importorskip("PIL._webp", reason="WebP support not installed") _webp = pytest.importorskip("PIL._webp", reason="WebP support not installed")
pytestmark = [
skip_unless_feature("webp"),
def setup_module(): skip_unless_feature("webp_mux"),
if not _webp.HAVE_WEBPMUX: ]
pytest.skip("WebPMux support not installed")
def test_read_exif_metadata(): def test_read_exif_metadata():
@ -93,10 +94,8 @@ def test_read_no_exif():
assert not webp_image._getexif() assert not webp_image._getexif()
@skip_unless_feature("webp_anim")
def test_write_animated_metadata(tmp_path): def test_write_animated_metadata(tmp_path):
if not _webp.HAVE_WEBPANIM:
pytest.skip("WebP animation support not available")
iccp_data = b"<iccp_data>" iccp_data = b"<iccp_data>"
exif_data = b"<exif_data>" exif_data = b"<exif_data>"
xmp_data = b"<xmp_data>" xmp_data = b"<xmp_data>"

View File

@ -1,8 +1,6 @@
import unittest from PIL import Image, ImageDraw, ImageFont
from PIL import Image, ImageDraw, ImageFont, features from .helper import PillowLeakTestCase, skip_unless_feature
from .helper import PillowLeakTestCase
class TestTTypeFontLeak(PillowLeakTestCase): class TestTTypeFontLeak(PillowLeakTestCase):
@ -19,7 +17,7 @@ class TestTTypeFontLeak(PillowLeakTestCase):
) )
) )
@unittest.skipUnless(features.check("freetype2"), "Test requires freetype2") @skip_unless_feature("freetype2")
def test_leak(self): def test_leak(self):
ttype = ImageFont.truetype("Tests/fonts/FreeMono.ttf", 20) ttype = ImageFont.truetype("Tests/fonts/FreeMono.ttf", 20)
self._test_font(ttype) self._test_font(ttype)

View File

@ -1,19 +1,19 @@
from PIL import FontFile, Image, ImageDraw, ImageFont, PcfFontFile from PIL import FontFile, Image, ImageDraw, ImageFont, PcfFontFile
from .helper import PillowTestCase, assert_image_equal, assert_image_similar from .helper import (
PillowTestCase,
codecs = dir(Image.core) assert_image_equal,
assert_image_similar,
skip_unless_feature,
)
fontname = "Tests/fonts/10x20-ISO8859-1.pcf" fontname = "Tests/fonts/10x20-ISO8859-1.pcf"
message = "hello, world" message = "hello, world"
@skip_unless_feature("zlib")
class TestFontPcf(PillowTestCase): class TestFontPcf(PillowTestCase):
def setUp(self):
if "zip_encoder" not in codecs or "zip_decoder" not in codecs:
self.skipTest("zlib support not available")
def save_font(self): def save_font(self):
with open(fontname, "rb") as test_file: with open(fontname, "rb") as test_file:
font = PcfFontFile.PcfFontFile(test_file) font = PcfFontFile.PcfFontFile(test_file)

View File

@ -1,13 +1,8 @@
import pytest
from PIL import Image from PIL import Image
from .helper import fromstring, tostring from .helper import fromstring, skip_unless_feature, tostring
pytestmark = skip_unless_feature("jpg")
def setup_module():
codecs = dir(Image.core)
if "jpeg_encoder" not in codecs or "jpeg_decoder" not in codecs:
pytest.skip("jpeg support not available")
def draft_roundtrip(in_mode, in_size, req_mode, req_size): def draft_roundtrip(in_mode, in_size, req_mode, req_size):

View File

@ -1,4 +1,4 @@
from PIL import Image from PIL import Image, features
from .helper import PillowTestCase, assert_image_equal, hopper from .helper import PillowTestCase, assert_image_equal, hopper
@ -44,9 +44,7 @@ class TestImageSplit(PillowTestCase):
assert_image_equal(hopper("YCbCr"), split_merge("YCbCr")) assert_image_equal(hopper("YCbCr"), split_merge("YCbCr"))
def test_split_open(self): def test_split_open(self):
codecs = dir(Image.core) if features.check("zlib"):
if "zip_encoder" in codecs:
test_file = self.tempfile("temp.png") test_file = self.tempfile("temp.png")
else: else:
test_file = self.tempfile("temp.pcx") test_file = self.tempfile("temp.pcx")
@ -60,5 +58,5 @@ class TestImageSplit(PillowTestCase):
self.assertEqual(split_open("L"), 1) self.assertEqual(split_open("L"), 1)
self.assertEqual(split_open("P"), 1) self.assertEqual(split_open("P"), 1)
self.assertEqual(split_open("RGB"), 3) self.assertEqual(split_open("RGB"), 3)
if "zip_encoder" in codecs: if features.check("zlib"):
self.assertEqual(split_open("RGBA"), 4) self.assertEqual(split_open("RGBA"), 4)

View File

@ -1,9 +1,14 @@
import os.path import os.path
import pytest import pytest
from PIL import Image, ImageColor, ImageDraw, ImageFont, features from PIL import Image, ImageColor, ImageDraw, ImageFont
from .helper import assert_image_equal, assert_image_similar, hopper from .helper import (
assert_image_equal,
assert_image_similar,
hopper,
skip_unless_feature,
)
BLACK = (0, 0, 0) BLACK = (0, 0, 0)
WHITE = (255, 255, 255) WHITE = (255, 255, 255)
@ -30,8 +35,6 @@ POINTS2 = [10, 10, 20, 40, 30, 30]
KITE_POINTS = [(10, 50), (70, 10), (90, 50), (70, 90), (10, 50)] KITE_POINTS = [(10, 50), (70, 10), (90, 50), (70, 90), (10, 50)]
HAS_FREETYPE = features.check("freetype2")
def test_sanity(): def test_sanity():
im = hopper("RGB").copy() im = hopper("RGB").copy()
@ -912,7 +915,7 @@ def test_textsize_empty_string():
draw.textsize("test\n") draw.textsize("test\n")
@pytest.mark.skipif(not HAS_FREETYPE, reason="ImageFont not available") @skip_unless_feature("freetype2")
def test_textsize_stroke(): def test_textsize_stroke():
# Arrange # Arrange
im = Image.new("RGB", (W, H)) im = Image.new("RGB", (W, H))
@ -924,7 +927,7 @@ def test_textsize_stroke():
assert draw.multiline_textsize("ABC\nAaaa", font, stroke_width=2) == (52, 44) assert draw.multiline_textsize("ABC\nAaaa", font, stroke_width=2) == (52, 44)
@pytest.mark.skipif(not HAS_FREETYPE, reason="ImageFont not available") @skip_unless_feature("freetype2")
def test_stroke(): def test_stroke():
for suffix, stroke_fill in {"same": None, "different": "#0f0"}.items(): for suffix, stroke_fill in {"same": None, "different": "#0f0"}.items():
# Arrange # Arrange
@ -941,7 +944,7 @@ def test_stroke():
) )
@pytest.mark.skipif(not HAS_FREETYPE, reason="ImageFont not available") @skip_unless_feature("freetype2")
def test_stroke_multiline(): def test_stroke_multiline():
# Arrange # Arrange
im = Image.new("RGB", (100, 250)) im = Image.new("RGB", (100, 250))

View File

@ -1,9 +1,13 @@
import os.path import os.path
import pytest from PIL import Image, ImageDraw, ImageDraw2
from PIL import Image, ImageDraw, ImageDraw2, features
from .helper import assert_image_equal, assert_image_similar, hopper from .helper import (
assert_image_equal,
assert_image_similar,
hopper,
skip_unless_feature,
)
BLACK = (0, 0, 0) BLACK = (0, 0, 0)
WHITE = (255, 255, 255) WHITE = (255, 255, 255)
@ -30,7 +34,6 @@ POINTS2 = [10, 10, 20, 40, 30, 30]
KITE_POINTS = [(10, 50), (70, 10), (90, 50), (70, 90), (10, 50)] KITE_POINTS = [(10, 50), (70, 10), (90, 50), (70, 90), (10, 50)]
HAS_FREETYPE = features.check("freetype2")
FONT_PATH = "Tests/fonts/FreeMono.ttf" FONT_PATH = "Tests/fonts/FreeMono.ttf"
@ -178,7 +181,7 @@ def test_big_rectangle():
assert_image_similar(im, Image.open(expected), 1) assert_image_similar(im, Image.open(expected), 1)
@pytest.mark.skipif(not HAS_FREETYPE, reason="ImageFont not available") @skip_unless_feature("freetype2")
def test_text(): def test_text():
# Arrange # Arrange
im = Image.new("RGB", (W, H)) im = Image.new("RGB", (W, H))
@ -193,7 +196,7 @@ def test_text():
assert_image_similar(im, Image.open(expected), 13) assert_image_similar(im, Image.open(expected), 13)
@pytest.mark.skipif(not HAS_FREETYPE, reason="ImageFont not available") @skip_unless_feature("freetype2")
def test_textsize(): def test_textsize():
# Arrange # Arrange
im = Image.new("RGB", (W, H)) im = Image.new("RGB", (W, H))
@ -207,7 +210,7 @@ def test_textsize():
assert size[1] == 12 assert size[1] == 12
@pytest.mark.skipif(not HAS_FREETYPE, reason="ImageFont not available") @skip_unless_feature("freetype2")
def test_textsize_empty_string(): def test_textsize_empty_string():
# Arrange # Arrange
im = Image.new("RGB", (W, H)) im = Image.new("RGB", (W, H))
@ -222,7 +225,7 @@ def test_textsize_empty_string():
draw.textsize("test\n", font) draw.textsize("test\n", font)
@pytest.mark.skipif(not HAS_FREETYPE, reason="ImageFont not available") @skip_unless_feature("freetype2")
def test_flush(): def test_flush():
# Arrange # Arrange
im = Image.new("RGB", (W, H)) im = Image.new("RGB", (W, H))

View File

@ -1,7 +1,6 @@
import unittest
from io import BytesIO from io import BytesIO
from PIL import EpsImagePlugin, Image, ImageFile from PIL import EpsImagePlugin, Image, ImageFile, features
from .helper import ( from .helper import (
PillowTestCase, PillowTestCase,
@ -10,19 +9,10 @@ from .helper import (
assert_image_similar, assert_image_similar,
fromstring, fromstring,
hopper, hopper,
skip_unless_feature,
tostring, tostring,
) )
try:
from PIL import _webp
HAVE_WEBP = True
except ImportError:
HAVE_WEBP = False
codecs = dir(Image.core)
# save original block sizes # save original block sizes
MAXBLOCK = ImageFile.MAXBLOCK MAXBLOCK = ImageFile.MAXBLOCK
SAFEBLOCK = ImageFile.SAFEBLOCK SAFEBLOCK = ImageFile.SAFEBLOCK
@ -53,7 +43,7 @@ class TestImageFile(PillowTestCase):
assert_image_similar(im1.convert("P"), im2, 1) assert_image_similar(im1.convert("P"), im2, 1)
assert_image_equal(*roundtrip("IM")) assert_image_equal(*roundtrip("IM"))
assert_image_equal(*roundtrip("MSP")) assert_image_equal(*roundtrip("MSP"))
if "zip_encoder" in codecs: if features.check("zlib"):
try: try:
# force multiple blocks in PNG driver # force multiple blocks in PNG driver
ImageFile.MAXBLOCK = 8192 ImageFile.MAXBLOCK = 8192
@ -77,7 +67,7 @@ class TestImageFile(PillowTestCase):
# EPS comes back in RGB: # EPS comes back in RGB:
assert_image_similar(im1, im2.convert("L"), 20) assert_image_similar(im1, im2.convert("L"), 20)
if "jpeg_encoder" in codecs: if features.check("jpg"):
im1, im2 = roundtrip("JPEG") # lossy compression im1, im2 = roundtrip("JPEG") # lossy compression
assert_image(im1, im2.mode, im2.size) assert_image(im1, im2.mode, im2.size)
@ -90,10 +80,8 @@ class TestImageFile(PillowTestCase):
p.feed(data) p.feed(data)
self.assertEqual((48, 48), p.image.size) self.assertEqual((48, 48), p.image.size)
@skip_unless_feature("zlib")
def test_safeblock(self): def test_safeblock(self):
if "zip_encoder" not in codecs:
self.skipTest("PNG (zlib) encoder not available")
im1 = hopper() im1 = hopper()
try: try:
@ -120,10 +108,8 @@ class TestImageFile(PillowTestCase):
with self.assertRaises(IOError): with self.assertRaises(IOError):
p.close() p.close()
@skip_unless_feature("zlib")
def test_truncated_with_errors(self): def test_truncated_with_errors(self):
if "zip_encoder" not in codecs:
self.skipTest("PNG (zlib) encoder not available")
with Image.open("Tests/images/truncated_image.png") as im: with Image.open("Tests/images/truncated_image.png") as im:
with self.assertRaises(IOError): with self.assertRaises(IOError):
im.load() im.load()
@ -132,10 +118,8 @@ class TestImageFile(PillowTestCase):
with self.assertRaises(IOError): with self.assertRaises(IOError):
im.load() im.load()
@skip_unless_feature("zlib")
def test_truncated_without_errors(self): def test_truncated_without_errors(self):
if "zip_encoder" not in codecs:
self.skipTest("PNG (zlib) encoder not available")
with Image.open("Tests/images/truncated_image.png") as im: with Image.open("Tests/images/truncated_image.png") as im:
ImageFile.LOAD_TRUNCATED_IMAGES = True ImageFile.LOAD_TRUNCATED_IMAGES = True
try: try:
@ -143,18 +127,14 @@ class TestImageFile(PillowTestCase):
finally: finally:
ImageFile.LOAD_TRUNCATED_IMAGES = False ImageFile.LOAD_TRUNCATED_IMAGES = False
@skip_unless_feature("zlib")
def test_broken_datastream_with_errors(self): def test_broken_datastream_with_errors(self):
if "zip_encoder" not in codecs:
self.skipTest("PNG (zlib) encoder not available")
with Image.open("Tests/images/broken_data_stream.png") as im: with Image.open("Tests/images/broken_data_stream.png") as im:
with self.assertRaises(IOError): with self.assertRaises(IOError):
im.load() im.load()
@skip_unless_feature("zlib")
def test_broken_datastream_without_errors(self): def test_broken_datastream_without_errors(self):
if "zip_encoder" not in codecs:
self.skipTest("PNG (zlib) encoder not available")
with Image.open("Tests/images/broken_data_stream.png") as im: with Image.open("Tests/images/broken_data_stream.png") as im:
ImageFile.LOAD_TRUNCATED_IMAGES = True ImageFile.LOAD_TRUNCATED_IMAGES = True
try: try:
@ -292,10 +272,8 @@ class TestPyDecoder(PillowTestCase):
self.assertEqual(reloaded_exif[40963], 455) self.assertEqual(reloaded_exif[40963], 455)
self.assertEqual(exif[305], "Pillow test") self.assertEqual(exif[305], "Pillow test")
@unittest.skipIf( @skip_unless_feature("webp")
not HAVE_WEBP or not _webp.HAVE_WEBPANIM, @skip_unless_feature("webp_anim")
"WebP support not installed with animation",
)
def test_exif_webp(self): def test_exif_webp(self):
with Image.open("Tests/images/hopper.webp") as im: with Image.open("Tests/images/hopper.webp") as im:
exif = im.getexif() exif = im.getexif()

View File

@ -3,11 +3,11 @@ import distutils.version
import os import os
import re import re
import shutil import shutil
import sys
import unittest import unittest
from io import BytesIO from io import BytesIO
from unittest import mock
from PIL import Image, ImageDraw, ImageFont, features from PIL import Image, ImageDraw, ImageFont
from .helper import ( from .helper import (
PillowTestCase, PillowTestCase,
@ -16,6 +16,7 @@ from .helper import (
assert_image_similar_tofile, assert_image_similar_tofile,
is_pypy, is_pypy,
is_win32, is_win32,
skip_unless_feature,
) )
FONT_PATH = "Tests/fonts/FreeMono.ttf" FONT_PATH = "Tests/fonts/FreeMono.ttf"
@ -23,37 +24,8 @@ FONT_SIZE = 20
TEST_TEXT = "hey you\nyou are awesome\nthis looks awkward" TEST_TEXT = "hey you\nyou are awesome\nthis looks awkward"
HAS_FREETYPE = features.check("freetype2")
HAS_RAQM = features.check("raqm")
@skip_unless_feature("freetype2")
class SimplePatcher:
def __init__(self, parent_obj, attr_name, value):
self._parent_obj = parent_obj
self._attr_name = attr_name
self._saved = None
self._is_saved = False
self._value = value
def __enter__(self):
# Patch the attr on the object
if hasattr(self._parent_obj, self._attr_name):
self._saved = getattr(self._parent_obj, self._attr_name)
setattr(self._parent_obj, self._attr_name, self._value)
self._is_saved = True
else:
setattr(self._parent_obj, self._attr_name, self._value)
self._is_saved = False
def __exit__(self, type, value, traceback):
# Restore the original value
if self._is_saved:
setattr(self._parent_obj, self._attr_name, self._saved)
else:
delattr(self._parent_obj, self._attr_name)
@unittest.skipUnless(HAS_FREETYPE, "ImageFont not available")
class TestImageFont(PillowTestCase): class TestImageFont(PillowTestCase):
LAYOUT_ENGINE = ImageFont.LAYOUT_BASIC LAYOUT_ENGINE = ImageFont.LAYOUT_BASIC
@ -491,7 +463,7 @@ class TestImageFont(PillowTestCase):
def _test_fake_loading_font(self, path_to_fake, fontname): def _test_fake_loading_font(self, path_to_fake, fontname):
# Make a copy of FreeTypeFont so we can patch the original # Make a copy of FreeTypeFont so we can patch the original
free_type_font = copy.deepcopy(ImageFont.FreeTypeFont) free_type_font = copy.deepcopy(ImageFont.FreeTypeFont)
with SimplePatcher(ImageFont, "_FreeTypeFont", free_type_font): with mock.patch.object(ImageFont, "_FreeTypeFont", free_type_font, create=True):
def loadable_font(filepath, size, index, encoding, *args, **kwargs): def loadable_font(filepath, size, index, encoding, *args, **kwargs):
if filepath == path_to_fake: if filepath == path_to_fake:
@ -502,7 +474,7 @@ class TestImageFont(PillowTestCase):
filepath, size, index, encoding, *args, **kwargs filepath, size, index, encoding, *args, **kwargs
) )
with SimplePatcher(ImageFont, "FreeTypeFont", loadable_font): with mock.patch.object(ImageFont, "FreeTypeFont", loadable_font):
font = ImageFont.truetype(fontname) font = ImageFont.truetype(fontname)
# Make sure it's loaded # Make sure it's loaded
name = font.getname() name = font.getname()
@ -513,10 +485,9 @@ class TestImageFont(PillowTestCase):
# A lot of mocking here - this is more for hitting code and # A lot of mocking here - this is more for hitting code and
# catching syntax like errors # catching syntax like errors
font_directory = "/usr/local/share/fonts" font_directory = "/usr/local/share/fonts"
with SimplePatcher(sys, "platform", "linux"): with mock.patch("sys.platform", "linux"):
patched_env = copy.deepcopy(os.environ) patched_env = {"XDG_DATA_DIRS": "/usr/share/:/usr/local/share/"}
patched_env["XDG_DATA_DIRS"] = "/usr/share/:/usr/local/share/" with mock.patch.dict(os.environ, patched_env):
with SimplePatcher(os, "environ", patched_env):
def fake_walker(path): def fake_walker(path):
if path == font_directory: if path == font_directory:
@ -534,7 +505,7 @@ class TestImageFont(PillowTestCase):
] ]
return [(path, [], ["some_random_font.ttf"])] return [(path, [], ["some_random_font.ttf"])]
with SimplePatcher(os, "walk", fake_walker): with mock.patch("os.walk", fake_walker):
# Test that the font loads both with and without the # Test that the font loads both with and without the
# extension # extension
self._test_fake_loading_font( self._test_fake_loading_font(
@ -559,7 +530,7 @@ class TestImageFont(PillowTestCase):
# Like the linux test, more cover hitting code rather than testing # Like the linux test, more cover hitting code rather than testing
# correctness. # correctness.
font_directory = "/System/Library/Fonts" font_directory = "/System/Library/Fonts"
with SimplePatcher(sys, "platform", "darwin"): with mock.patch("sys.platform", "darwin"):
def fake_walker(path): def fake_walker(path):
if path == font_directory: if path == font_directory:
@ -577,7 +548,7 @@ class TestImageFont(PillowTestCase):
] ]
return [(path, [], ["some_random_font.ttf"])] return [(path, [], ["some_random_font.ttf"])]
with SimplePatcher(os, "walk", fake_walker): with mock.patch("os.walk", fake_walker):
self._test_fake_loading_font(font_directory + "/Arial.ttf", "Arial.ttf") self._test_fake_loading_font(font_directory + "/Arial.ttf", "Arial.ttf")
self._test_fake_loading_font(font_directory + "/Arial.ttf", "Arial") self._test_fake_loading_font(font_directory + "/Arial.ttf", "Arial")
self._test_fake_loading_font(font_directory + "/Single.otf", "Single") self._test_fake_loading_font(font_directory + "/Single.otf", "Single")
@ -752,6 +723,6 @@ class TestImageFont(PillowTestCase):
_check_text(font, "Tests/images/variation_tiny_axes.png", 32.5) _check_text(font, "Tests/images/variation_tiny_axes.png", 32.5)
@unittest.skipUnless(HAS_RAQM, "Raqm not Available") @skip_unless_feature("raqm")
class TestImageFont_RaqmLayout(TestImageFont): class TestImageFont_RaqmLayout(TestImageFont):
LAYOUT_ENGINE = ImageFont.LAYOUT_RAQM LAYOUT_ENGINE = ImageFont.LAYOUT_RAQM

View File

@ -1,14 +1,12 @@
import unittest from PIL import Image, ImageDraw, ImageFont
from PIL import Image, ImageDraw, ImageFont, features from .helper import PillowTestCase, assert_image_similar, skip_unless_feature
from .helper import PillowTestCase, assert_image_similar
FONT_SIZE = 20 FONT_SIZE = 20
FONT_PATH = "Tests/fonts/DejaVuSans.ttf" FONT_PATH = "Tests/fonts/DejaVuSans.ttf"
@unittest.skipUnless(features.check("raqm"), "Raqm Library is not installed.") @skip_unless_feature("raqm")
class TestImagecomplextext(PillowTestCase): class TestImagecomplextext(PillowTestCase):
def test_english(self): def test_english(self):
# smoke test, this should not fail # smoke test, this should not fail

View File

@ -1,5 +1,5 @@
import pytest import pytest
from PIL import Image, ImageOps from PIL import Image, ImageOps, features
from .helper import ( from .helper import (
assert_image_equal, assert_image_equal,
@ -8,13 +8,6 @@ from .helper import (
hopper, hopper,
) )
try:
from PIL import _webp
HAVE_WEBP = True
except ImportError:
HAVE_WEBP = False
class Deformer: class Deformer:
def getmesh(self, im): def getmesh(self, im):
@ -274,7 +267,7 @@ def test_colorize_3color_offset():
def test_exif_transpose(): def test_exif_transpose():
exts = [".jpg"] exts = [".jpg"]
if HAVE_WEBP and _webp.HAVE_WEBPANIM: if features.check("webp") and features.check("webp_anim"):
exts.append(".webp") exts.append(".webp")
for ext in exts: for ext in exts:
with Image.open("Tests/images/hopper" + ext) as base_im: with Image.open("Tests/images/hopper" + ext) as base_im:

View File

@ -1,6 +1,6 @@
from PIL import Image, ImageSequence, TiffImagePlugin from PIL import Image, ImageSequence, TiffImagePlugin
from .helper import PillowTestCase, assert_image_equal, hopper from .helper import PillowTestCase, assert_image_equal, hopper, skip_unless_feature
class TestImageSequence(PillowTestCase): class TestImageSequence(PillowTestCase):
@ -47,12 +47,8 @@ class TestImageSequence(PillowTestCase):
def test_tiff(self): def test_tiff(self):
self._test_multipage_tiff() self._test_multipage_tiff()
@skip_unless_feature("libtiff")
def test_libtiff(self): def test_libtiff(self):
codecs = dir(Image.core)
if "libtiff_encoder" not in codecs or "libtiff_decoder" not in codecs:
self.skipTest("tiff support not available")
TiffImagePlugin.READ_LIBTIFF = True TiffImagePlugin.READ_LIBTIFF = True
self._test_multipage_tiff() self._test_multipage_tiff()
TiffImagePlugin.READ_LIBTIFF = False TiffImagePlugin.READ_LIBTIFF = False

View File

@ -1,6 +1,6 @@
from fractions import Fraction from fractions import Fraction
from PIL import Image, TiffImagePlugin from PIL import Image, TiffImagePlugin, features
from PIL.TiffImagePlugin import IFDRational from PIL.TiffImagePlugin import IFDRational
from .helper import PillowTestCase, hopper from .helper import PillowTestCase, hopper
@ -43,7 +43,7 @@ class Test_IFDRational(PillowTestCase):
def test_ifd_rational_save(self): def test_ifd_rational_save(self):
methods = (True, False) methods = (True, False)
if "libtiff_encoder" not in dir(Image.core): if not features.check("libtiff"):
methods = (False,) methods = (False,)
for libtiff in methods: for libtiff in methods:

View File

@ -1,14 +1,13 @@
import unittest
from io import BytesIO from io import BytesIO
from PIL import Image, features from PIL import Image
from .helper import PillowLeakTestCase from .helper import PillowLeakTestCase, skip_unless_feature
test_file = "Tests/images/hopper.webp" test_file = "Tests/images/hopper.webp"
@unittest.skipUnless(features.check("webp"), "WebP is not installed") @skip_unless_feature("webp")
class TestWebPLeaks(PillowLeakTestCase): class TestWebPLeaks(PillowLeakTestCase):
mem_limit = 3 * 1024 # kb mem_limit = 3 * 1024 # kb