diff --git a/Tests/test_file_apng.py b/Tests/test_file_apng.py index f5c767082..d1d5c85c1 100644 --- a/Tests/test_file_apng.py +++ b/Tests/test_file_apng.py @@ -635,3 +635,13 @@ def test_apng_save_blend(tmp_path): with Image.open(test_file) as im: im.seek(2) assert im.getpixel((0, 0)) == (0, 255, 0, 255) + + +def test_constants_deprecation(): + for enum, prefix in { + PngImagePlugin.Disposal: "APNG_DISPOSE_", + PngImagePlugin.Blend: "APNG_BLEND_", + }.items(): + for name in enum.__members__: + with pytest.warns(DeprecationWarning): + assert getattr(PngImagePlugin, prefix + name) == enum[name] diff --git a/Tests/test_file_blp.py b/Tests/test_file_blp.py index 15bd7e4f8..917f39530 100644 --- a/Tests/test_file_blp.py +++ b/Tests/test_file_blp.py @@ -1,6 +1,6 @@ import pytest -from PIL import Image +from PIL import BlpImagePlugin, Image from .helper import assert_image_equal_tofile @@ -37,3 +37,14 @@ def test_crashes(test_file): with Image.open(f) as im: with pytest.raises(OSError): im.load() + + +def test_constants_deprecation(): + for enum, prefix in { + BlpImagePlugin.Format: "BLP_FORMAT_", + BlpImagePlugin.Encoding: "BLP_ENCODING_", + BlpImagePlugin.AlphaEncoding: "BLP_ALPHA_ENCODING_", + }.items(): + for name in enum.__members__: + with pytest.warns(DeprecationWarning): + assert getattr(BlpImagePlugin, prefix + name) == enum[name] diff --git a/Tests/test_file_ftex.py b/Tests/test_file_ftex.py index f76fd895a..5447dc740 100644 --- a/Tests/test_file_ftex.py +++ b/Tests/test_file_ftex.py @@ -1,4 +1,6 @@ -from PIL import Image +import pytest + +from PIL import FtexImagePlugin, Image from .helper import assert_image_equal_tofile, assert_image_similar @@ -12,3 +14,12 @@ def test_load_dxt1(): with Image.open("Tests/images/ftex_dxt1.ftc") as im: with Image.open("Tests/images/ftex_dxt1.png") as target: assert_image_similar(im, target.convert("RGBA"), 15) + + +def test_constants_deprecation(): + for enum, prefix in { + FtexImagePlugin.Format: "FORMAT_", + }.items(): + for name in enum.__members__: + with pytest.warns(DeprecationWarning): + assert getattr(FtexImagePlugin, prefix + name) == enum[name] diff --git a/Tests/test_image.py b/Tests/test_image.py index 2d46d760d..1c30ca9fa 100644 --- a/Tests/test_image.py +++ b/Tests/test_image.py @@ -802,6 +802,31 @@ class TestImage: with pytest.warns(DeprecationWarning): assert Image.CONTAINER == 2 + def test_constants_deprecation(self): + with pytest.warns(DeprecationWarning): + assert Image.NEAREST == 0 + with pytest.warns(DeprecationWarning): + assert Image.NONE == 0 + + with pytest.warns(DeprecationWarning): + assert Image.LINEAR == Image.Resampling.BILINEAR + with pytest.warns(DeprecationWarning): + assert Image.CUBIC == Image.Resampling.BICUBIC + with pytest.warns(DeprecationWarning): + assert Image.ANTIALIAS == Image.Resampling.LANCZOS + + for enum in ( + Image.Transpose, + Image.Transform, + Image.Resampling, + Image.Dither, + Image.Palette, + Image.Quantize, + ): + for name in enum.__members__: + with pytest.warns(DeprecationWarning): + assert getattr(Image, name) == enum[name] + @pytest.mark.parametrize( "path", [ diff --git a/Tests/test_imagecms.py b/Tests/test_imagecms.py index 09af11389..e0093739c 100644 --- a/Tests/test_imagecms.py +++ b/Tests/test_imagecms.py @@ -593,3 +593,13 @@ def test_auxiliary_channels_isolated(): ) assert_image_equal(test_image.convert(dst_format[2]), reference_image) + + +def test_constants_deprecation(): + for enum, prefix in { + ImageCms.Intent: "INTENT_", + ImageCms.Direction: "DIRECTION_", + }.items(): + for name in enum.__members__: + with pytest.warns(DeprecationWarning): + assert getattr(ImageCms, prefix + name) == enum[name] diff --git a/Tests/test_imagefont.py b/Tests/test_imagefont.py index 8e2c61848..23bfda816 100644 --- a/Tests/test_imagefont.py +++ b/Tests/test_imagefont.py @@ -1022,3 +1022,12 @@ def test_oom(test_file): font = ImageFont.truetype(BytesIO(f.read())) with pytest.raises(Image.DecompressionBombError): font.getmask("Test Text") + + +def test_constants_deprecation(): + for enum, prefix in { + ImageFont.Layout: "LAYOUT_", + }.items(): + for name in enum.__members__: + with pytest.warns(DeprecationWarning): + assert getattr(ImageFont, prefix + name) == enum[name] diff --git a/src/PIL/BlpImagePlugin.py b/src/PIL/BlpImagePlugin.py index 111f03ae6..dc68b95b5 100644 --- a/src/PIL/BlpImagePlugin.py +++ b/src/PIL/BlpImagePlugin.py @@ -30,6 +30,7 @@ BLP files come in many different flavours: """ import struct +import warnings from enum import IntEnum from io import BytesIO @@ -52,11 +53,31 @@ class AlphaEncoding(IntEnum): DXT5 = 7 -globals().update({"BLP_FORMAT_" + k: v for k, v in Format.__members__.items()}) -globals().update({"BLP_ENCODING_" + k: v for k, v in Encoding.__members__.items()}) -globals().update( - {"BLP_ALPHA_ENCODING_" + k: v for k, v in AlphaEncoding.__members__.items()} -) +def __getattr__(name): + deprecated = "deprecated and will be removed in Pillow 10 (2023-07-01). " + for enum, prefix in { + Format: "BLP_FORMAT_", + Encoding: "BLP_ENCODING_", + AlphaEncoding: "BLP_ALPHA_ENCODING_", + }.items(): + if name.startswith(prefix): + name = name[len(prefix) :] + if name in enum.__members__: + warnings.warn( + prefix + + name + + " is " + + deprecated + + "Use " + + enum.__name__ + + "." + + name + + " instead.", + DeprecationWarning, + stacklevel=2, + ) + return enum[name] + raise AttributeError(f"module '{__name__}' has no attribute '{name}'") def unpack_565(i): diff --git a/src/PIL/FtexImagePlugin.py b/src/PIL/FtexImagePlugin.py index de5859ba5..8629dcf64 100644 --- a/src/PIL/FtexImagePlugin.py +++ b/src/PIL/FtexImagePlugin.py @@ -52,6 +52,7 @@ Note: All data is stored in little-Endian (Intel) byte order. """ import struct +import warnings from enum import IntEnum from io import BytesIO @@ -65,7 +66,27 @@ class Format(IntEnum): UNCOMPRESSED = 1 -globals().update({"FORMAT_" + k: v for k, v in Format.__members__.items()}) +def __getattr__(name): + deprecated = "deprecated and will be removed in Pillow 10 (2023-07-01). " + for enum, prefix in {Format: "FORMAT_"}.items(): + if name.startswith(prefix): + name = name[len(prefix) :] + if name in enum.__members__: + warnings.warn( + prefix + + name + + " is " + + deprecated + + "Use " + + enum.__name__ + + "." + + name + + " instead.", + DeprecationWarning, + stacklevel=2, + ) + return enum[name] + raise AttributeError(f"module '{__name__}' has no attribute '{name}'") class FtexImageFile(ImageFile.ImageFile): diff --git a/src/PIL/Image.py b/src/PIL/Image.py index 30ee34c6b..c10e6d9cd 100644 --- a/src/PIL/Image.py +++ b/src/PIL/Image.py @@ -54,15 +54,57 @@ from ._util import deferred_error, isPath def __getattr__(name): + deprecated = "deprecated and will be removed in Pillow 10 (2023-07-01). " categories = {"NORMAL": 0, "SEQUENCE": 1, "CONTAINER": 2} if name in categories: warnings.warn( - "Image categories are deprecated and will be removed in Pillow 10 " - "(2023-07-01). Use is_animated instead.", + "Image categories are " + deprecated + "Use is_animated instead.", DeprecationWarning, stacklevel=2, ) return categories[name] + elif name in ("NEAREST", "NONE"): + warnings.warn( + name + + " is " + + deprecated + + "Use Resampling.NEAREST or Dither.NONE instead.", + DeprecationWarning, + stacklevel=2, + ) + return 0 + old_resampling = { + "LINEAR": "BILINEAR", + "CUBIC": "BICUBIC", + "ANTIALIAS": "LANCZOS", + } + if name in old_resampling: + warnings.warn( + name + + " is " + + deprecated + + "Use Resampling." + + old_resampling[name] + + " instead.", + DeprecationWarning, + stacklevel=2, + ) + return Resampling[old_resampling[name]] + for enum in (Transpose, Transform, Resampling, Dither, Palette, Quantize): + if name in enum.__members__: + warnings.warn( + name + + " is " + + deprecated + + "Use " + + enum.__name__ + + "." + + name + + " instead.", + DeprecationWarning, + stacklevel=2, + ) + return enum[name] raise AttributeError(f"module '{__name__}' has no attribute '{name}'") @@ -199,10 +241,6 @@ class Quantize(IntEnum): LIBIMAGEQUANT = 3 -for enum in (Transpose, Transform, Resampling, Dither, Palette, Quantize): - globals().update(enum.__members__) -NEAREST = NONE = 0 - if hasattr(core, "DEFAULT_STRATEGY"): DEFAULT_STRATEGY = core.DEFAULT_STRATEGY FILTERED = core.FILTERED diff --git a/src/PIL/ImageCms.py b/src/PIL/ImageCms.py index 1f104133d..ea328e149 100644 --- a/src/PIL/ImageCms.py +++ b/src/PIL/ImageCms.py @@ -16,6 +16,7 @@ # below for the original description. import sys +import warnings from enum import IntEnum from PIL import Image @@ -115,8 +116,28 @@ class Direction(IntEnum): PROOF = 2 -globals().update({"INTENT_" + k: v for k, v in Intent.__members__.items()}) -globals().update({"DIRECTION_" + k: v for k, v in Direction.__members__.items()}) +def __getattr__(name): + deprecated = "deprecated and will be removed in Pillow 10 (2023-07-01). " + for enum, prefix in {Intent: "INTENT_", Direction: "DIRECTION_"}.items(): + if name.startswith(prefix): + name = name[len(prefix) :] + if name in enum.__members__: + warnings.warn( + prefix + + name + + " is " + + deprecated + + "Use " + + enum.__name__ + + "." + + name + + " instead.", + DeprecationWarning, + stacklevel=2, + ) + return enum[name] + raise AttributeError(f"module '{__name__}' has no attribute '{name}'") + # # flags diff --git a/src/PIL/ImageFont.py b/src/PIL/ImageFont.py index 9282d5279..84c9b430d 100644 --- a/src/PIL/ImageFont.py +++ b/src/PIL/ImageFont.py @@ -28,6 +28,7 @@ import base64 import os import sys +import warnings from enum import IntEnum from io import BytesIO @@ -40,7 +41,27 @@ class Layout(IntEnum): RAQM = 1 -globals().update({"LAYOUT_" + k: v for k, v in Layout.__members__.items()}) +def __getattr__(name): + deprecated = "deprecated and will be removed in Pillow 10 (2023-07-01). " + for enum, prefix in {Layout: "LAYOUT_"}.items(): + if name.startswith(prefix): + name = name[len(prefix) :] + if name in enum.__members__: + warnings.warn( + prefix + + name + + " is " + + deprecated + + "Use " + + enum.__name__ + + "." + + name + + " instead.", + DeprecationWarning, + stacklevel=2, + ) + return enum[name] + raise AttributeError(f"module '{__name__}' has no attribute '{name}'") class _imagingft_not_installed: diff --git a/src/PIL/PngImagePlugin.py b/src/PIL/PngImagePlugin.py index 94ca933b0..9d86afe34 100644 --- a/src/PIL/PngImagePlugin.py +++ b/src/PIL/PngImagePlugin.py @@ -130,8 +130,27 @@ class Blend(IntEnum): """ -globals().update({"APNG_DISPOSE_" + k: v for k, v in Disposal.__members__.items()}) -globals().update(Blend.__members__) +def __getattr__(name): + deprecated = "deprecated and will be removed in Pillow 10 (2023-07-01). " + for enum, prefix in {Disposal: "APNG_DISPOSE_", Blend: "APNG_BLEND_"}.items(): + if name.startswith(prefix): + name = name[len(prefix) :] + if name in enum.__members__: + warnings.warn( + prefix + + name + + " is " + + deprecated + + "Use " + + enum.__name__ + + "." + + name + + " instead.", + DeprecationWarning, + stacklevel=2, + ) + return enum[name] + raise AttributeError(f"module '{__name__}' has no attribute '{name}'") def _safe_zlib_decompress(s):