Added type hints

This commit is contained in:
Andrew Murray 2024-05-29 22:51:02 +10:00
parent 759ab28757
commit a6d1daeb4b
5 changed files with 52 additions and 31 deletions

View File

@ -174,12 +174,13 @@ def skip_unless_feature(feature: str) -> pytest.MarkDecorator:
def skip_unless_feature_version(
feature: str, required: str, reason: str | None = None
) -> pytest.MarkDecorator:
if not features.check(feature):
version = features.version(feature)
if version is None:
return pytest.mark.skip(f"{feature} not available")
if reason is None:
reason = f"{feature} is older than {required}"
version_required = parse_version(required)
version_available = parse_version(features.version(feature))
version_available = parse_version(version)
return pytest.mark.skipif(version_available < version_required, reason=reason)
@ -189,12 +190,13 @@ def mark_if_feature_version(
version_blacklist: str,
reason: str | None = None,
) -> pytest.MarkDecorator:
if not features.check(feature):
version = features.version(feature)
if version is None:
return pytest.mark.pil_noop_mark()
if reason is None:
reason = f"{feature} is {version_blacklist}"
version_required = parse_version(version_blacklist)
version_available = parse_version(features.version(feature))
version_available = parse_version(version)
if (
version_available.major == version_required.major
and version_available.minor == version_required.minor
@ -220,16 +222,11 @@ class PillowLeakTestCase:
from resource import RUSAGE_SELF, getrusage
mem = getrusage(RUSAGE_SELF).ru_maxrss
if sys.platform == "darwin":
# man 2 getrusage:
# ru_maxrss
# This is the maximum resident set size utilized (in bytes).
return mem / 1024 # Kb
# linux
# man 2 getrusage
# ru_maxrss (since Linux 2.6.32)
# This is the maximum resident set size used (in kilobytes).
return mem # Kb
# man 2 getrusage:
# ru_maxrss
# This is the maximum resident set size utilized
# in bytes on macOS, in kilobytes on Linux
return mem / 1024 if sys.platform == "darwin" else mem
def _test_leak(self, core: Callable[[], None]) -> None:
start_mem = self._get_mem_usage()

View File

@ -52,8 +52,9 @@ def test_write_animation_L(tmp_path: Path) -> None:
assert_image_similar(im, orig.convert("RGBA"), 32.9)
if is_big_endian():
webp = parse_version(features.version_module("webp"))
if webp < parse_version("1.2.2"):
version = features.version_module("webp")
assert version is not None
if parse_version(version) < parse_version("1.2.2"):
pytest.skip("Fails with libwebp earlier than 1.2.2")
orig.seek(orig.n_frames - 1)
im.seek(im.n_frames - 1)
@ -78,8 +79,9 @@ def test_write_animation_RGB(tmp_path: Path) -> None:
# Compare second frame to original
if is_big_endian():
webp = parse_version(features.version_module("webp"))
if webp < parse_version("1.2.2"):
version = features.version_module("webp")
assert version is not None
if parse_version(version) < parse_version("1.2.2"):
pytest.skip("Fails with libwebp earlier than 1.2.2")
im.seek(1)
im.load()

View File

@ -60,10 +60,13 @@ def test_sanity() -> None:
assert list(map(type, v)) == [str, str, str, str]
# internal version number
assert re.search(r"\d+\.\d+(\.\d+)?$", features.version_module("littlecms2"))
version = features.version_module("littlecms2")
assert version is not None
assert re.search(r"\d+\.\d+(\.\d+)?$", version)
skip_missing()
i = ImageCms.profileToProfile(hopper(), SRGB, SRGB)
assert i is not None
assert_image(i, "RGB", (128, 128))
i = hopper()
@ -72,23 +75,27 @@ def test_sanity() -> None:
t = ImageCms.buildTransform(SRGB, SRGB, "RGB", "RGB")
i = ImageCms.applyTransform(hopper(), t)
assert i is not None
assert_image(i, "RGB", (128, 128))
with hopper() as i:
t = ImageCms.buildTransform(SRGB, SRGB, "RGB", "RGB")
ImageCms.applyTransform(hopper(), t, inPlace=True)
assert i is not None
assert_image(i, "RGB", (128, 128))
p = ImageCms.createProfile("sRGB")
o = ImageCms.getOpenProfile(SRGB)
t = ImageCms.buildTransformFromOpenProfiles(p, o, "RGB", "RGB")
i = ImageCms.applyTransform(hopper(), t)
assert i is not None
assert_image(i, "RGB", (128, 128))
t = ImageCms.buildProofTransform(SRGB, SRGB, SRGB, "RGB", "RGB")
assert t.inputMode == "RGB"
assert t.outputMode == "RGB"
i = ImageCms.applyTransform(hopper(), t)
assert i is not None
assert_image(i, "RGB", (128, 128))
# test PointTransform convenience API
@ -260,7 +267,7 @@ def test_simple_lab() -> None:
t = ImageCms.buildTransform(psRGB, pLab, "RGB", "LAB")
i_lab = ImageCms.applyTransform(i, t)
assert i_lab is not None
assert i_lab.mode == "LAB"
k = i_lab.getpixel((0, 0))
@ -284,6 +291,7 @@ def test_lab_color() -> None:
# Need to add a type mapping for some PIL type to TYPE_Lab_8 in findLCMSType, and
# have that mapping work back to a PIL mode (likely RGB).
i = ImageCms.applyTransform(hopper(), t)
assert i is not None
assert_image(i, "LAB", (128, 128))
# i.save('temp.lab.tif') # visually verified vs PS.
@ -298,6 +306,7 @@ def test_lab_srgb() -> None:
with Image.open("Tests/images/hopper.Lab.tif") as img:
img_srgb = ImageCms.applyTransform(img, t)
assert img_srgb is not None
# img_srgb.save('temp.srgb.tif') # visually verified vs ps.
@ -317,11 +326,11 @@ def test_lab_roundtrip() -> None:
t2 = ImageCms.buildTransform(pLab, psRGB, "LAB", "RGB")
i = ImageCms.applyTransform(hopper(), t)
assert i is not None
assert i.info["icc_profile"] == ImageCmsProfile(pLab).tobytes()
out = ImageCms.applyTransform(i, t2)
assert out is not None
assert_image_similar(hopper(), out, 2)
@ -657,7 +666,7 @@ def test_auxiliary_channels_isolated() -> None:
reference_image = ImageCms.applyTransform(
source_image.convert(src_format[2]), reference_transform
)
assert reference_image is not None
assert_image_equal(test_image.convert(dst_format[2]), reference_image)

View File

@ -202,6 +202,8 @@ class TestImageFile:
class MockPyDecoder(ImageFile.PyDecoder):
last: MockPyDecoder
def __init__(self, mode: str, *args: Any) -> None:
MockPyDecoder.last = self
@ -213,6 +215,8 @@ class MockPyDecoder(ImageFile.PyDecoder):
class MockPyEncoder(ImageFile.PyEncoder):
last: MockPyEncoder | None
def __init__(self, mode: str, *args: Any) -> None:
MockPyEncoder.last = self
@ -315,6 +319,7 @@ class TestPyEncoder(CodecsTest):
im, fp, [("MOCK", (xoff, yoff, xoff + xsize, yoff + ysize), 0, "RGB")]
)
assert MockPyEncoder.last
assert MockPyEncoder.last.state.xoff == xoff
assert MockPyEncoder.last.state.yoff == yoff
assert MockPyEncoder.last.state.xsize == xsize
@ -329,6 +334,7 @@ class TestPyEncoder(CodecsTest):
fp = BytesIO()
ImageFile._save(im, fp, [("MOCK", None, 0, "RGB")])
assert MockPyEncoder.last
assert MockPyEncoder.last.state.xoff == 0
assert MockPyEncoder.last.state.yoff == 0
assert MockPyEncoder.last.state.xsize == 200

View File

@ -34,7 +34,9 @@ pytestmark = skip_unless_feature("freetype2")
def test_sanity() -> None:
assert re.search(r"\d+\.\d+\.\d+$", features.version_module("freetype2"))
version = features.version_module("freetype2")
assert version is not None
assert re.search(r"\d+\.\d+\.\d+$", version)
@pytest.fixture(
@ -547,11 +549,10 @@ def test_find_font(
def loadable_font(
filepath: str, size: int, index: int, encoding: str, *args: Any
):
_freeTypeFont = getattr(ImageFont, "_FreeTypeFont")
if filepath == path_to_fake:
return ImageFont._FreeTypeFont(
FONT_PATH, size, index, encoding, *args
)
return ImageFont._FreeTypeFont(filepath, size, index, encoding, *args)
return _freeTypeFont(FONT_PATH, size, index, encoding, *args)
return _freeTypeFont(filepath, size, index, encoding, *args)
m.setattr(ImageFont, "FreeTypeFont", loadable_font)
font = ImageFont.truetype(fontname)
@ -630,7 +631,9 @@ def test_complex_font_settings() -> None:
def test_variation_get(font: ImageFont.FreeTypeFont) -> None:
freetype = parse_version(features.version_module("freetype2"))
version = features.version_module("freetype2")
assert version is not None
freetype = parse_version(version)
if freetype < parse_version("2.9.1"):
with pytest.raises(NotImplementedError):
font.get_variation_names()
@ -700,7 +703,9 @@ def _check_text(font: ImageFont.FreeTypeFont, path: str, epsilon: float) -> None
def test_variation_set_by_name(font: ImageFont.FreeTypeFont) -> None:
freetype = parse_version(features.version_module("freetype2"))
version = features.version_module("freetype2")
assert version is not None
freetype = parse_version(version)
if freetype < parse_version("2.9.1"):
with pytest.raises(NotImplementedError):
font.set_variation_by_name("Bold")
@ -725,7 +730,9 @@ def test_variation_set_by_name(font: ImageFont.FreeTypeFont) -> None:
def test_variation_set_by_axes(font: ImageFont.FreeTypeFont) -> None:
freetype = parse_version(features.version_module("freetype2"))
version = features.version_module("freetype2")
assert version is not None
freetype = parse_version(version)
if freetype < parse_version("2.9.1"):
with pytest.raises(NotImplementedError):
font.set_variation_by_axes([100])