Merge pull request #4436 from hugovk/pytest.importorskip

Use pytest.importorskip to skip on a missing import dependency
This commit is contained in:
Andrew Murray 2020-02-21 06:53:04 +11:00 committed by GitHub
commit f87505cbd2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 344 additions and 379 deletions

View File

@ -1,15 +1,8 @@
import pytest import pytest
from PIL import Image from PIL import Image
try: FpxImagePlugin = pytest.importorskip(
from PIL import FpxImagePlugin "PIL.FpxImagePlugin", reason="olefile not installed"
except ImportError:
olefile_installed = False
else:
olefile_installed = True
pytestmark = pytest.mark.skipif(
not olefile_installed, reason="olefile package not installed"
) )

View File

@ -3,22 +3,13 @@ from PIL import Image, ImagePalette
from .helper import assert_image_similar, hopper, skip_unless_feature from .helper import assert_image_similar, hopper, skip_unless_feature
try: MicImagePlugin = pytest.importorskip(
from PIL import MicImagePlugin "PIL.MicImagePlugin", reason="olefile not installed"
except ImportError: )
olefile_installed = False pytestmark = skip_unless_feature("libtiff")
else:
olefile_installed = True
TEST_FILE = "Tests/images/hopper.mic" TEST_FILE = "Tests/images/hopper.mic"
pytestmark = [
pytest.mark.skipif(not olefile_installed, reason="olefile package not installed"),
skip_unless_feature("libtiff"),
]
def test_sanity(): def test_sanity():
with Image.open(TEST_FILE) as im: with Image.open(TEST_FILE) as im:
im.load() im.load()

View File

@ -1,24 +1,17 @@
import unittest 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
try: _webp = pytest.importorskip("PIL._webp", reason="WebP support not installed")
from PIL import _webp
except ImportError:
_webp = None
@unittest.skipIf(_webp is None, "WebP support not installed") def setup_module():
class TestFileWebpAlpha(PillowTestCase): if _webp.WebPDecoderBuggyAlpha():
def setUp(self): pytest.skip("Buggy early version of WebP installed, not testing transparency")
if _webp.WebPDecoderBuggyAlpha(self):
self.skipTest(
"Buggy early version of WebP installed, not testing transparency"
)
def test_read_rgba(self):
def test_read_rgba():
""" """
Can we read an RGBA mode file without error? Can we read an RGBA mode file without error?
Does it have the bits we expect? Does it have the bits we expect?
@ -27,9 +20,9 @@ class TestFileWebpAlpha(PillowTestCase):
# Generated with `cwebp transparent.png -o transparent.webp` # Generated with `cwebp transparent.png -o transparent.webp`
file_path = "Tests/images/transparent.webp" file_path = "Tests/images/transparent.webp"
with Image.open(file_path) as image: with Image.open(file_path) as image:
self.assertEqual(image.mode, "RGBA") assert image.mode == "RGBA"
self.assertEqual(image.size, (200, 150)) assert image.size == (200, 150)
self.assertEqual(image.format, "WEBP") assert image.format == "WEBP"
image.load() image.load()
image.getdata() image.getdata()
@ -38,13 +31,14 @@ class TestFileWebpAlpha(PillowTestCase):
with Image.open("Tests/images/transparent.png") as target: with Image.open("Tests/images/transparent.png") as target:
assert_image_similar(image, target, 20.0) assert_image_similar(image, target, 20.0)
def test_write_lossless_rgb(self):
def test_write_lossless_rgb(tmp_path):
""" """
Can we write an RGBA mode file with lossless compression without Can we write an RGBA mode file with lossless compression without error?
error? Does it have the bits we expect? Does it have the bits we expect?
""" """
temp_file = self.tempfile("temp.webp") temp_file = str(tmp_path / "temp.webp")
# temp_file = "temp.webp" # temp_file = "temp.webp"
pil_image = hopper("RGBA") pil_image = hopper("RGBA")
@ -58,58 +52,60 @@ class TestFileWebpAlpha(PillowTestCase):
with Image.open(temp_file) as image: with Image.open(temp_file) as image:
image.load() image.load()
self.assertEqual(image.mode, "RGBA") assert image.mode == "RGBA"
self.assertEqual(image.size, pil_image.size) assert image.size == pil_image.size
self.assertEqual(image.format, "WEBP") assert image.format == "WEBP"
image.load() image.load()
image.getdata() image.getdata()
assert_image_equal(image, pil_image) assert_image_equal(image, pil_image)
def test_write_rgba(self):
def test_write_rgba(tmp_path):
""" """
Can we write a RGBA mode file to webp without error. Can we write a RGBA mode file to WebP without error.
Does it have the bits we expect? Does it have the bits we expect?
""" """
temp_file = self.tempfile("temp.webp") temp_file = str(tmp_path / "temp.webp")
pil_image = Image.new("RGBA", (10, 10), (255, 0, 0, 20)) pil_image = Image.new("RGBA", (10, 10), (255, 0, 0, 20))
pil_image.save(temp_file) pil_image.save(temp_file)
if _webp.WebPDecoderBuggyAlpha(self): if _webp.WebPDecoderBuggyAlpha():
return return
with Image.open(temp_file) as image: with Image.open(temp_file) as image:
image.load() image.load()
self.assertEqual(image.mode, "RGBA") assert image.mode == "RGBA"
self.assertEqual(image.size, (10, 10)) assert image.size == (10, 10)
self.assertEqual(image.format, "WEBP") assert image.format == "WEBP"
image.load() image.load()
image.getdata() image.getdata()
# early versions of webp are known to produce higher deviations: # Early versions of WebP are known to produce higher deviations:
# deal with it # deal with it
if _webp.WebPDecoderVersion(self) <= 0x201: if _webp.WebPDecoderVersion() <= 0x201:
assert_image_similar(image, pil_image, 3.0) assert_image_similar(image, pil_image, 3.0)
else: else:
assert_image_similar(image, pil_image, 1.0) assert_image_similar(image, pil_image, 1.0)
def test_write_unsupported_mode_PA(self):
def test_write_unsupported_mode_PA(tmp_path):
""" """
Saving a palette-based file with transparency to WebP format Saving a palette-based file with transparency to WebP format
should work, and be similar to the original file. should work, and be similar to the original file.
""" """
temp_file = self.tempfile("temp.webp") temp_file = str(tmp_path / "temp.webp")
file_path = "Tests/images/transparent.gif" file_path = "Tests/images/transparent.gif"
with Image.open(file_path) as im: with Image.open(file_path) as im:
im.save(temp_file) im.save(temp_file)
with Image.open(temp_file) as image: with Image.open(temp_file) as image:
self.assertEqual(image.mode, "RGBA") assert image.mode == "RGBA"
self.assertEqual(image.size, (200, 150)) assert image.size == (200, 150)
self.assertEqual(image.format, "WEBP") assert image.format == "WEBP"
image.load() image.load()
image.getdata() image.getdata()

View File

@ -2,7 +2,6 @@ import pytest
from PIL import Image from PIL import Image
from .helper import ( from .helper import (
PillowTestCase,
assert_image_equal, assert_image_equal,
assert_image_similar, assert_image_similar,
is_big_endian, is_big_endian,
@ -10,39 +9,38 @@ from .helper import (
skip_unless_feature, skip_unless_feature,
) )
pytestmark = [
skip_unless_feature("webp"),
skip_unless_feature("webp_anim"),
]
@skip_unless_feature("webp")
@skip_unless_feature("webp_anim") def test_n_frames():
class TestFileWebpAnimation(PillowTestCase): """Ensure that WebP format sets n_frames and is_animated attributes correctly."""
def test_n_frames(self):
"""
Ensure that WebP format sets n_frames and is_animated
attributes correctly.
"""
with Image.open("Tests/images/hopper.webp") as im: with Image.open("Tests/images/hopper.webp") as im:
self.assertEqual(im.n_frames, 1) assert im.n_frames == 1
self.assertFalse(im.is_animated) assert not im.is_animated
with Image.open("Tests/images/iss634.webp") as im: with Image.open("Tests/images/iss634.webp") as im:
self.assertEqual(im.n_frames, 42) assert im.n_frames == 42
self.assertTrue(im.is_animated) assert im.is_animated
@pytest.mark.xfail(is_big_endian() and on_ci(), reason="Fails on big-endian")
def test_write_animation_L(self): @pytest.mark.xfail(is_big_endian() and on_ci(), reason="Fails on big-endian")
def test_write_animation_L(tmp_path):
""" """
Convert an animated GIF to animated WebP, then compare the Convert an animated GIF to animated WebP, then compare the frame count, and first
frame count, and first and last frames to ensure they're and last frames to ensure they're visually similar.
visually similar.
""" """
with Image.open("Tests/images/iss634.gif") as orig: with Image.open("Tests/images/iss634.gif") as orig:
self.assertGreater(orig.n_frames, 1) assert orig.n_frames > 1
temp_file = self.tempfile("temp.webp") temp_file = str(tmp_path / "temp.webp")
orig.save(temp_file, save_all=True) orig.save(temp_file, save_all=True)
with Image.open(temp_file) as im: with Image.open(temp_file) as im:
self.assertEqual(im.n_frames, orig.n_frames) assert im.n_frames == orig.n_frames
# Compare first and last frames to the original animated GIF # Compare first and last frames to the original animated GIF
orig.load() orig.load()
@ -54,8 +52,9 @@ class TestFileWebpAnimation(PillowTestCase):
im.load() im.load()
assert_image_similar(im, orig.convert("RGBA"), 25.0) assert_image_similar(im, orig.convert("RGBA"), 25.0)
@pytest.mark.xfail(is_big_endian() and on_ci(), reason="Fails on big-endian")
def test_write_animation_RGB(self): @pytest.mark.xfail(is_big_endian() and on_ci(), reason="Fails on big-endian")
def test_write_animation_RGB(tmp_path):
""" """
Write an animated WebP from RGB frames, and ensure the frames Write an animated WebP from RGB frames, and ensure the frames
are visually similar to the originals. are visually similar to the originals.
@ -63,7 +62,7 @@ class TestFileWebpAnimation(PillowTestCase):
def check(temp_file): def check(temp_file):
with Image.open(temp_file) as im: with Image.open(temp_file) as im:
self.assertEqual(im.n_frames, 2) assert im.n_frames == 2
# Compare first frame to original # Compare first frame to original
im.load() im.load()
@ -76,7 +75,7 @@ class TestFileWebpAnimation(PillowTestCase):
with Image.open("Tests/images/anim_frame1.webp") as frame1: with Image.open("Tests/images/anim_frame1.webp") as frame1:
with Image.open("Tests/images/anim_frame2.webp") as frame2: with Image.open("Tests/images/anim_frame2.webp") as frame2:
temp_file1 = self.tempfile("temp.webp") temp_file1 = str(tmp_path / "temp.webp")
frame1.copy().save( frame1.copy().save(
temp_file1, save_all=True, append_images=[frame2], lossless=True temp_file1, save_all=True, append_images=[frame2], lossless=True
) )
@ -86,7 +85,7 @@ class TestFileWebpAnimation(PillowTestCase):
def imGenerator(ims): def imGenerator(ims):
yield from ims yield from ims
temp_file2 = self.tempfile("temp_generator.webp") temp_file2 = str(tmp_path / "temp_generator.webp")
frame1.copy().save( frame1.copy().save(
temp_file2, temp_file2,
save_all=True, save_all=True,
@ -95,14 +94,15 @@ class TestFileWebpAnimation(PillowTestCase):
) )
check(temp_file2) check(temp_file2)
def test_timestamp_and_duration(self):
def test_timestamp_and_duration(tmp_path):
""" """
Try passing a list of durations, and make sure the encoded Try passing a list of durations, and make sure the encoded
timestamps and durations are correct. timestamps and durations are correct.
""" """
durations = [0, 10, 20, 30, 40] durations = [0, 10, 20, 30, 40]
temp_file = self.tempfile("temp.webp") temp_file = str(tmp_path / "temp.webp")
with Image.open("Tests/images/anim_frame1.webp") as frame1: with Image.open("Tests/images/anim_frame1.webp") as frame1:
with Image.open("Tests/images/anim_frame2.webp") as frame2: with Image.open("Tests/images/anim_frame2.webp") as frame2:
frame1.save( frame1.save(
@ -113,27 +113,27 @@ class TestFileWebpAnimation(PillowTestCase):
) )
with Image.open(temp_file) as im: with Image.open(temp_file) as im:
self.assertEqual(im.n_frames, 5) assert im.n_frames == 5
self.assertTrue(im.is_animated) assert im.is_animated
# Check that timestamps and durations match original values specified # Check that timestamps and durations match original values specified
ts = 0 ts = 0
for frame in range(im.n_frames): for frame in range(im.n_frames):
im.seek(frame) im.seek(frame)
im.load() im.load()
self.assertEqual(im.info["duration"], durations[frame]) assert im.info["duration"] == durations[frame]
self.assertEqual(im.info["timestamp"], ts) assert im.info["timestamp"] == ts
ts += durations[frame] ts += durations[frame]
def test_seeking(self):
def test_seeking(tmp_path):
""" """
Create an animated WebP file, and then try seeking through Create an animated WebP file, and then try seeking through frames in reverse-order,
frames in reverse-order, verifying the timestamps and durations verifying the timestamps and durations are correct.
are correct.
""" """
dur = 33 dur = 33
temp_file = self.tempfile("temp.webp") temp_file = str(tmp_path / "temp.webp")
with Image.open("Tests/images/anim_frame1.webp") as frame1: with Image.open("Tests/images/anim_frame1.webp") as frame1:
with Image.open("Tests/images/anim_frame2.webp") as frame2: with Image.open("Tests/images/anim_frame2.webp") as frame2:
frame1.save( frame1.save(
@ -144,22 +144,23 @@ class TestFileWebpAnimation(PillowTestCase):
) )
with Image.open(temp_file) as im: with Image.open(temp_file) as im:
self.assertEqual(im.n_frames, 5) assert im.n_frames == 5
self.assertTrue(im.is_animated) assert im.is_animated
# Traverse frames in reverse, checking timestamps and durations # Traverse frames in reverse, checking timestamps and durations
ts = dur * (im.n_frames - 1) ts = dur * (im.n_frames - 1)
for frame in reversed(range(im.n_frames)): for frame in reversed(range(im.n_frames)):
im.seek(frame) im.seek(frame)
im.load() im.load()
self.assertEqual(im.info["duration"], dur) assert im.info["duration"] == dur
self.assertEqual(im.info["timestamp"], ts) assert im.info["timestamp"] == ts
ts -= dur ts -= dur
def test_seek_errors(self):
def test_seek_errors():
with Image.open("Tests/images/iss634.webp") as im: with Image.open("Tests/images/iss634.webp") as im:
with self.assertRaises(EOFError): with pytest.raises(EOFError):
im.seek(-1) im.seek(-1)
with self.assertRaises(EOFError): with pytest.raises(EOFError):
im.seek(42) im.seek(42)

View File

@ -1,33 +1,27 @@
import pytest
from PIL import Image from PIL import Image
from .helper import PillowTestCase, assert_image_equal, hopper, skip_unless_feature from .helper import assert_image_equal, hopper
try: _webp = pytest.importorskip("PIL._webp", reason="WebP support not installed")
from PIL import _webp RGB_MODE = "RGB"
except ImportError:
pass
@skip_unless_feature("webp") def test_write_lossless_rgb(tmp_path):
class TestFileWebpLossless(PillowTestCase):
def setUp(self):
if _webp.WebPDecoderVersion() < 0x0200: if _webp.WebPDecoderVersion() < 0x0200:
self.skipTest("lossless not included") pytest.skip("lossless not included")
self.rgb_mode = "RGB" temp_file = str(tmp_path / "temp.webp")
def test_write_lossless_rgb(self): hopper(RGB_MODE).save(temp_file, lossless=True)
temp_file = self.tempfile("temp.webp")
hopper(self.rgb_mode).save(temp_file, lossless=True)
with Image.open(temp_file) as image: with Image.open(temp_file) as image:
image.load() image.load()
self.assertEqual(image.mode, self.rgb_mode) assert image.mode == RGB_MODE
self.assertEqual(image.size, (128, 128)) assert image.size == (128, 128)
self.assertEqual(image.format, "WEBP") assert image.format == "WEBP"
image.load() image.load()
image.getdata() image.getdata()
assert_image_equal(image, hopper(self.rgb_mode)) assert_image_equal(image, hopper(RGB_MODE))

View File

@ -2,32 +2,35 @@ from io import BytesIO
from PIL import Image from PIL import Image
from .helper import PillowTestCase, skip_unless_feature from .helper import skip_unless_feature
pytestmark = [
skip_unless_feature("webp"),
skip_unless_feature("webp_mux"),
]
@skip_unless_feature("webp") def test_read_exif_metadata():
@skip_unless_feature("webp_mux")
class TestFileWebpMetadata(PillowTestCase):
def test_read_exif_metadata(self):
file_path = "Tests/images/flower.webp" file_path = "Tests/images/flower.webp"
with Image.open(file_path) as image: with Image.open(file_path) as image:
self.assertEqual(image.format, "WEBP") assert image.format == "WEBP"
exif_data = image.info.get("exif", None) exif_data = image.info.get("exif", None)
self.assertTrue(exif_data) assert exif_data
exif = image._getexif() exif = image._getexif()
# camera make # Camera make
self.assertEqual(exif[271], "Canon") assert exif[271] == "Canon"
with Image.open("Tests/images/flower.jpg") as jpeg_image: with Image.open("Tests/images/flower.jpg") as jpeg_image:
expected_exif = jpeg_image.info["exif"] expected_exif = jpeg_image.info["exif"]
self.assertEqual(exif_data, expected_exif) assert exif_data == expected_exif
def test_write_exif_metadata(self):
def test_write_exif_metadata():
file_path = "Tests/images/flower.jpg" file_path = "Tests/images/flower.jpg"
test_buffer = BytesIO() test_buffer = BytesIO()
with Image.open(file_path) as image: with Image.open(file_path) as image:
@ -38,26 +41,28 @@ class TestFileWebpMetadata(PillowTestCase):
test_buffer.seek(0) test_buffer.seek(0)
with Image.open(test_buffer) as webp_image: with Image.open(test_buffer) as webp_image:
webp_exif = webp_image.info.get("exif", None) webp_exif = webp_image.info.get("exif", None)
self.assertTrue(webp_exif) assert webp_exif
if webp_exif: if webp_exif:
self.assertEqual(webp_exif, expected_exif, "WebP EXIF didn't match") assert webp_exif == expected_exif, "WebP EXIF didn't match"
def test_read_icc_profile(self):
def test_read_icc_profile():
file_path = "Tests/images/flower2.webp" file_path = "Tests/images/flower2.webp"
with Image.open(file_path) as image: with Image.open(file_path) as image:
self.assertEqual(image.format, "WEBP") assert image.format == "WEBP"
self.assertTrue(image.info.get("icc_profile", None)) assert image.info.get("icc_profile", None)
icc = image.info["icc_profile"] icc = image.info["icc_profile"]
with Image.open("Tests/images/flower2.jpg") as jpeg_image: with Image.open("Tests/images/flower2.jpg") as jpeg_image:
expected_icc = jpeg_image.info["icc_profile"] expected_icc = jpeg_image.info["icc_profile"]
self.assertEqual(icc, expected_icc) assert icc == expected_icc
def test_write_icc_metadata(self):
def test_write_icc_metadata():
file_path = "Tests/images/flower2.jpg" file_path = "Tests/images/flower2.jpg"
test_buffer = BytesIO() test_buffer = BytesIO()
with Image.open(file_path) as image: with Image.open(file_path) as image:
@ -69,31 +74,31 @@ class TestFileWebpMetadata(PillowTestCase):
with Image.open(test_buffer) as webp_image: with Image.open(test_buffer) as webp_image:
webp_icc_profile = webp_image.info.get("icc_profile", None) webp_icc_profile = webp_image.info.get("icc_profile", None)
self.assertTrue(webp_icc_profile) assert webp_icc_profile
if webp_icc_profile: if webp_icc_profile:
self.assertEqual( assert webp_icc_profile == expected_icc_profile, "Webp ICC didn't match"
webp_icc_profile, expected_icc_profile, "Webp ICC didn't match"
)
def test_read_no_exif(self):
def test_read_no_exif():
file_path = "Tests/images/flower.jpg" file_path = "Tests/images/flower.jpg"
test_buffer = BytesIO() test_buffer = BytesIO()
with Image.open(file_path) as image: with Image.open(file_path) as image:
self.assertIn("exif", image.info) assert "exif" in image.info
image.save(test_buffer, "webp") image.save(test_buffer, "webp")
test_buffer.seek(0) test_buffer.seek(0)
with Image.open(test_buffer) as webp_image: with Image.open(test_buffer) as webp_image:
self.assertFalse(webp_image._getexif()) assert not webp_image._getexif()
@skip_unless_feature("webp_anim")
def test_write_animated_metadata(self): @skip_unless_feature("webp_anim")
def test_write_animated_metadata(tmp_path):
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>"
temp_file = self.tempfile("temp.webp") temp_file = str(tmp_path / "temp.webp")
with Image.open("Tests/images/anim_frame1.webp") as frame1: with Image.open("Tests/images/anim_frame1.webp") as frame1:
with Image.open("Tests/images/anim_frame2.webp") as frame2: with Image.open("Tests/images/anim_frame2.webp") as frame2:
frame1.save( frame1.save(
@ -106,9 +111,9 @@ class TestFileWebpMetadata(PillowTestCase):
) )
with Image.open(temp_file) as image: with Image.open(temp_file) as image:
self.assertIn("icc_profile", image.info) assert "icc_profile" in image.info
self.assertIn("exif", image.info) assert "exif" in image.info
self.assertIn("xmp", image.info) assert "xmp" in image.info
self.assertEqual(iccp_data, image.info.get("icc_profile", None)) assert iccp_data == image.info.get("icc_profile", None)
self.assertEqual(exif_data, image.info.get("exif", None)) assert exif_data == image.info.get("exif", None)
self.assertEqual(xmp_data, image.info.get("xmp", None)) assert xmp_data == image.info.get("xmp", None)

View File

@ -5,11 +5,6 @@ from PIL import Image
from .helper import is_win32 from .helper import is_win32
try:
import numpy
except ImportError:
numpy = None
pytestmark = pytest.mark.skipif(is_win32(), reason="Win32 does not call map_buffer") pytestmark = pytest.mark.skipif(is_win32(), reason="Win32 does not call map_buffer")
@ -32,8 +27,9 @@ def test_overflow():
@pytest.mark.skipif(sys.maxsize <= 2 ** 32, reason="Requires 64-bit system") @pytest.mark.skipif(sys.maxsize <= 2 ** 32, reason="Requires 64-bit system")
@pytest.mark.skipif(numpy is None, reason="NumPy is not installed")
def test_ysize(): def test_ysize():
numpy = pytest.importorskip("numpy", reason="NumPy not installed")
# Should not raise 'Integer overflow in ysize' # Should not raise 'Integer overflow in ysize'
arr = numpy.zeros((46341, 46341), dtype=numpy.uint8) arr = numpy.zeros((46341, 46341), dtype=numpy.uint8)
Image.fromarray(arr) Image.fromarray(arr)

View File

@ -3,18 +3,11 @@ from PIL import Image
from .helper import assert_deep_equal, assert_image, hopper from .helper import assert_deep_equal, assert_image, hopper
try: numpy = pytest.importorskip("numpy", reason="NumPy not installed")
import numpy
except ImportError:
numpy = None
TEST_IMAGE_SIZE = (10, 10) TEST_IMAGE_SIZE = (10, 10)
pytestmark = pytest.mark.skipif(numpy is None, reason="NumPy is not installed")
def test_numpy_to_image(): def test_numpy_to_image():
def to_image(dtype, bands=1, boolean=0): def to_image(dtype, bands=1, boolean=0):
if bands == 1: if bands == 1:

View File

@ -1,13 +1,9 @@
import pytest import pytest
from PIL import __version__ from PIL import __version__
try: pyroma = pytest.importorskip("pyroma", reason="Pyroma not installed")
import pyroma
except ImportError:
pyroma = None
@pytest.mark.skipif(pyroma is None, reason="Pyroma is not installed")
def test_pyroma(): def test_pyroma():
# Arrange # Arrange
data = pyroma.projectdata.get_data(".") data = pyroma.projectdata.get_data(".")