2023-12-21 14:13:31 +03:00
|
|
|
from __future__ import annotations
|
2024-01-20 14:23:03 +03:00
|
|
|
|
2019-05-25 21:11:33 +03:00
|
|
|
import io
|
2020-06-15 16:32:30 +03:00
|
|
|
import re
|
2024-02-17 07:00:38 +03:00
|
|
|
from typing import Callable
|
2019-05-25 21:11:33 +03:00
|
|
|
|
2020-01-27 14:46:52 +03:00
|
|
|
import pytest
|
2020-08-07 13:28:33 +03:00
|
|
|
|
2015-05-15 00:33:17 +03:00
|
|
|
from PIL import features
|
|
|
|
|
2020-02-18 01:03:32 +03:00
|
|
|
from .helper import skip_unless_feature
|
|
|
|
|
2015-05-15 00:33:17 +03:00
|
|
|
|
2024-01-31 12:12:58 +03:00
|
|
|
def test_check() -> None:
|
2020-01-27 14:46:52 +03:00
|
|
|
# Check the correctness of the convenience function
|
|
|
|
for module in features.modules:
|
|
|
|
assert features.check_module(module) == features.check(module)
|
|
|
|
for codec in features.codecs:
|
|
|
|
assert features.check_codec(codec) == features.check(codec)
|
|
|
|
for feature in features.features:
|
2024-08-14 11:41:39 +03:00
|
|
|
if "webp" in feature:
|
|
|
|
with pytest.warns(DeprecationWarning):
|
|
|
|
assert features.check_feature(feature) == features.check(feature)
|
|
|
|
else:
|
|
|
|
assert features.check_feature(feature) == features.check(feature)
|
2020-01-27 14:46:52 +03:00
|
|
|
|
|
|
|
|
2024-01-31 12:12:58 +03:00
|
|
|
def test_version() -> None:
|
2020-06-15 16:32:30 +03:00
|
|
|
# Check the correctness of the convenience function
|
|
|
|
# and the format of version numbers
|
|
|
|
|
2024-05-30 05:00:50 +03:00
|
|
|
def test(name: str, function: Callable[[str], str | None]) -> None:
|
2020-06-15 16:32:30 +03:00
|
|
|
version = features.version(name)
|
|
|
|
if not features.check(name):
|
|
|
|
assert version is None
|
|
|
|
else:
|
|
|
|
assert function(name) == version
|
|
|
|
if name != "PIL":
|
2024-04-24 16:45:25 +03:00
|
|
|
if name == "zlib" and version is not None:
|
2024-06-10 10:38:17 +03:00
|
|
|
version = re.sub(".zlib-ng$", "", version)
|
|
|
|
elif name == "libtiff" and version is not None:
|
|
|
|
version = re.sub("t$", "", version)
|
2020-06-15 16:32:30 +03:00
|
|
|
assert version is None or re.search(r"\d+(\.\d+)*$", version)
|
|
|
|
|
|
|
|
for module in features.modules:
|
|
|
|
test(module, features.version_module)
|
|
|
|
for codec in features.codecs:
|
|
|
|
test(codec, features.version_codec)
|
|
|
|
for feature in features.features:
|
2024-08-14 11:41:39 +03:00
|
|
|
if "webp" in feature:
|
|
|
|
with pytest.warns(DeprecationWarning):
|
|
|
|
test(feature, features.version_feature)
|
|
|
|
else:
|
|
|
|
test(feature, features.version_feature)
|
2020-06-15 16:32:30 +03:00
|
|
|
|
|
|
|
|
2024-07-08 19:07:43 +03:00
|
|
|
def test_webp_transparency() -> None:
|
2024-08-14 11:41:39 +03:00
|
|
|
with pytest.warns(DeprecationWarning):
|
2024-10-11 12:59:15 +03:00
|
|
|
assert (features.check("transp_webp") or False) == features.check_module("webp")
|
2024-07-08 19:07:43 +03:00
|
|
|
|
|
|
|
|
|
|
|
def test_webp_mux() -> None:
|
2024-08-14 11:41:39 +03:00
|
|
|
with pytest.warns(DeprecationWarning):
|
2024-10-11 12:59:15 +03:00
|
|
|
assert (features.check("webp_mux") or False) == features.check_module("webp")
|
2024-07-08 19:07:43 +03:00
|
|
|
|
|
|
|
|
|
|
|
def test_webp_anim() -> None:
|
2024-08-14 11:41:39 +03:00
|
|
|
with pytest.warns(DeprecationWarning):
|
2024-10-11 12:59:15 +03:00
|
|
|
assert (features.check("webp_anim") or False) == features.check_module("webp")
|
2024-07-08 19:07:43 +03:00
|
|
|
|
|
|
|
|
2020-06-15 16:32:30 +03:00
|
|
|
@skip_unless_feature("libjpeg_turbo")
|
2024-01-31 12:12:58 +03:00
|
|
|
def test_libjpeg_turbo_version() -> None:
|
2024-05-30 05:00:50 +03:00
|
|
|
version = features.version("libjpeg_turbo")
|
|
|
|
assert version is not None
|
|
|
|
assert re.search(r"\d+\.\d+\.\d+$", version)
|
2020-06-15 16:32:30 +03:00
|
|
|
|
|
|
|
|
|
|
|
@skip_unless_feature("libimagequant")
|
2024-01-31 12:12:58 +03:00
|
|
|
def test_libimagequant_version() -> None:
|
2024-05-30 05:00:50 +03:00
|
|
|
version = features.version("libimagequant")
|
|
|
|
assert version is not None
|
|
|
|
assert re.search(r"\d+\.\d+\.\d+$", version)
|
2020-06-15 16:32:30 +03:00
|
|
|
|
|
|
|
|
2022-10-03 08:57:42 +03:00
|
|
|
@pytest.mark.parametrize("feature", features.modules)
|
2024-02-17 07:00:38 +03:00
|
|
|
def test_check_modules(feature: str) -> None:
|
2022-10-03 08:57:42 +03:00
|
|
|
assert features.check_module(feature) in [True, False]
|
2020-06-15 16:32:30 +03:00
|
|
|
|
|
|
|
|
2022-10-03 08:57:42 +03:00
|
|
|
@pytest.mark.parametrize("feature", features.codecs)
|
2024-02-17 07:00:38 +03:00
|
|
|
def test_check_codecs(feature: str) -> None:
|
2022-10-03 08:57:42 +03:00
|
|
|
assert features.check_codec(feature) in [True, False]
|
2020-01-27 14:46:52 +03:00
|
|
|
|
|
|
|
|
2024-01-31 12:12:58 +03:00
|
|
|
def test_check_warns_on_nonexistent() -> None:
|
2020-02-18 01:22:15 +03:00
|
|
|
with pytest.warns(UserWarning) as cm:
|
|
|
|
has_feature = features.check("typo")
|
|
|
|
assert has_feature is False
|
|
|
|
assert str(cm[-1].message) == "Unknown feature 'typo'."
|
|
|
|
|
|
|
|
|
2024-01-31 12:12:58 +03:00
|
|
|
def test_supported_modules() -> None:
|
2020-01-27 14:46:52 +03:00
|
|
|
assert isinstance(features.get_supported_modules(), list)
|
|
|
|
assert isinstance(features.get_supported_codecs(), list)
|
|
|
|
assert isinstance(features.get_supported_features(), list)
|
|
|
|
assert isinstance(features.get_supported(), list)
|
|
|
|
|
|
|
|
|
2024-01-31 12:12:58 +03:00
|
|
|
def test_unsupported_codec() -> None:
|
2020-01-27 14:46:52 +03:00
|
|
|
# Arrange
|
|
|
|
codec = "unsupported_codec"
|
|
|
|
# Act / Assert
|
|
|
|
with pytest.raises(ValueError):
|
|
|
|
features.check_codec(codec)
|
2020-06-15 16:32:30 +03:00
|
|
|
with pytest.raises(ValueError):
|
|
|
|
features.version_codec(codec)
|
2020-01-27 14:46:52 +03:00
|
|
|
|
|
|
|
|
2024-01-31 12:12:58 +03:00
|
|
|
def test_unsupported_module() -> None:
|
2020-01-27 14:46:52 +03:00
|
|
|
# Arrange
|
|
|
|
module = "unsupported_module"
|
|
|
|
# Act / Assert
|
|
|
|
with pytest.raises(ValueError):
|
|
|
|
features.check_module(module)
|
2020-06-15 16:32:30 +03:00
|
|
|
with pytest.raises(ValueError):
|
|
|
|
features.version_module(module)
|
2020-01-27 14:46:52 +03:00
|
|
|
|
|
|
|
|
2024-03-09 16:58:05 +03:00
|
|
|
@pytest.mark.parametrize("supported_formats", (True, False))
|
2024-06-05 15:27:23 +03:00
|
|
|
def test_pilinfo(supported_formats: bool) -> None:
|
2020-01-27 14:46:52 +03:00
|
|
|
buf = io.StringIO()
|
2024-03-09 16:58:05 +03:00
|
|
|
features.pilinfo(buf, supported_formats=supported_formats)
|
2020-01-27 14:46:52 +03:00
|
|
|
out = buf.getvalue()
|
|
|
|
lines = out.splitlines()
|
|
|
|
assert lines[0] == "-" * 68
|
|
|
|
assert lines[1].startswith("Pillow ")
|
|
|
|
assert lines[2].startswith("Python ")
|
|
|
|
lines = lines[3:]
|
|
|
|
while lines[0].startswith(" "):
|
|
|
|
lines = lines[1:]
|
|
|
|
assert lines[0] == "-" * 68
|
2024-02-20 22:37:33 +03:00
|
|
|
assert lines[1].startswith("Python executable is")
|
|
|
|
lines = lines[2:]
|
|
|
|
if lines[0].startswith("Environment Python files loaded from"):
|
|
|
|
lines = lines[1:]
|
|
|
|
assert lines[0].startswith("System Python files loaded from")
|
|
|
|
assert lines[1] == "-" * 68
|
|
|
|
assert lines[2].startswith("Python Pillow modules loaded from ")
|
|
|
|
assert lines[3].startswith("Binary Pillow modules loaded from ")
|
|
|
|
assert lines[4] == "-" * 68
|
2020-01-27 14:46:52 +03:00
|
|
|
jpeg = (
|
|
|
|
"\n"
|
|
|
|
+ "-" * 68
|
|
|
|
+ "\n"
|
|
|
|
+ "JPEG image/jpeg\n"
|
|
|
|
+ "Extensions: .jfif, .jpe, .jpeg, .jpg\n"
|
|
|
|
+ "Features: open, save\n"
|
|
|
|
+ "-" * 68
|
|
|
|
+ "\n"
|
|
|
|
)
|
2024-03-09 16:58:05 +03:00
|
|
|
assert supported_formats == (jpeg in out)
|