Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
91 changes: 91 additions & 0 deletions Tests/test_deprecate.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
import pytest

from PIL import _deprecate


@pytest.mark.parametrize(
"version, expected",
[
(
10,
"Old thing is deprecated and will be removed in Pillow 10 "
r"\(2023-07-01\)\. Use new thing instead\.",
),
(
None,
r"Old thing is deprecated and will be removed in a future version\. "
r"Use new thing instead\.",
),
],
)
def test_version(version, expected):
with pytest.warns(DeprecationWarning, match=expected):
_deprecate.deprecate("Old thing", version, "new thing")


def test_unknown_version():
expected = r"Unknown removal version, update PIL\._deprecate\?"
with pytest.raises(ValueError, match=expected):
_deprecate.deprecate("Old thing", 12345, "new thing")


@pytest.mark.parametrize(
"deprecated, plural, expected",
[
(
"Old thing",
False,
r"Old thing is deprecated and should be removed\.",
),
(
"Old things",
True,
r"Old things are deprecated and should be removed\.",
),
],
)
def test_old_version(deprecated, plural, expected):
expected = r""
with pytest.raises(RuntimeError, match=expected):
_deprecate.deprecate(deprecated, 1, plural=plural)


def test_plural():
expected = (
r"Old things are deprecated and will be removed in Pillow 10 \(2023-07-01\)\. "
r"Use new thing instead\."
)
with pytest.warns(DeprecationWarning, match=expected):
_deprecate.deprecate("Old things", 10, "new thing", plural=True)


def test_replacement_and_action():
expected = "Use only one of 'replacement' and 'action'"
with pytest.raises(ValueError, match=expected):
_deprecate.deprecate(
"Old thing", 10, replacement="new thing", action="Upgrade to new thing"
)


@pytest.mark.parametrize(
"action",
[
"Upgrade to new thing",
"Upgrade to new thing.",
],
)
def test_action(action):
expected = (
r"Old thing is deprecated and will be removed in Pillow 10 \(2023-07-01\)\. "
r"Upgrade to new thing\."
)
with pytest.warns(DeprecationWarning, match=expected):
_deprecate.deprecate("Old thing", 10, action=action)


def test_no_replacement_or_action():
expected = (
r"Old thing is deprecated and will be removed in Pillow 10 \(2023-07-01\)"
)
with pytest.warns(DeprecationWarning, match=expected):
_deprecate.deprecate("Old thing", 10)
8 changes: 8 additions & 0 deletions docs/reference/internal_modules.rst
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,14 @@ Internal Modules
:undoc-members:
:show-inheritance:

:mod:`~PIL._deprecate` Module
-----------------------------

.. automodule:: PIL._deprecate
:members:
:undoc-members:
:show-inheritance:

:mod:`~PIL._tkinter_finder` Module
----------------------------------

Expand Down
17 changes: 2 additions & 15 deletions src/PIL/BlpImagePlugin.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,11 +31,11 @@

import os
import struct
import warnings
from enum import IntEnum
from io import BytesIO

from . import Image, ImageFile
from ._deprecate import deprecate


class Format(IntEnum):
Expand All @@ -55,7 +55,6 @@ class AlphaEncoding(IntEnum):


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_",
Expand All @@ -64,19 +63,7 @@ def __getattr__(name):
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,
)
deprecate(f"{prefix}{name}", 10, f"{enum.__name__}.{name}")
return enum[name]
raise AttributeError(f"module '{__name__}' has no attribute '{name}'")

Expand Down
13 changes: 6 additions & 7 deletions src/PIL/FitsStubImagePlugin.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,8 @@
# See the README file for information on usage and redistribution.
#

import warnings

from . import FitsImagePlugin, Image, ImageFile
from ._deprecate import deprecate

_handler = None

Expand All @@ -25,11 +24,11 @@ def register_handler(handler):
global _handler
_handler = handler

warnings.warn(
"FitsStubImagePlugin is deprecated and will be removed in Pillow "
"10 (2023-07-01). FITS images can now be read without a handler through "
"FitsImagePlugin instead.",
DeprecationWarning,
deprecate(
"FitsStubImagePlugin",
10,
action="FITS images can now be read without "
"a handler through FitsImagePlugin instead",
)

# Override FitsImagePlugin with this handler
Expand Down
17 changes: 2 additions & 15 deletions src/PIL/FtexImagePlugin.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,11 +52,11 @@
"""

import struct
import warnings
from enum import IntEnum
from io import BytesIO

from . import Image, ImageFile
from ._deprecate import deprecate

MAGIC = b"FTEX"

Expand All @@ -67,24 +67,11 @@ class Format(IntEnum):


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,
)
deprecate(f"{prefix}{name}", 10, f"{enum.__name__}.{name}")
return enum[name]
raise AttributeError(f"module '{__name__}' has no attribute '{name}'")

Expand Down
48 changes: 6 additions & 42 deletions src/PIL/Image.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,60 +50,29 @@
# Use __version__ instead.
from . import ImageMode, TiffTags, UnidentifiedImageError, __version__, _plugins
from ._binary import i32le, o32be, o32le
from ._deprecate import deprecate
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 + "Use is_animated instead.",
DeprecationWarning,
stacklevel=2,
)
deprecate("Image categories", 10, "is_animated", plural=True)
return categories[name]
elif name in ("NEAREST", "NONE"):
warnings.warn(
name
+ " is "
+ deprecated
+ "Use Resampling.NEAREST or Dither.NONE instead.",
DeprecationWarning,
stacklevel=2,
)
deprecate(name, 10, "Resampling.NEAREST or Dither.NONE")
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,
)
deprecate(name, 10, f"Resampling.{old_resampling[name]}")
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,
)
deprecate(name, 10, f"{enum.__name__}.{name}")
return enum[name]
raise AttributeError(f"module '{__name__}' has no attribute '{name}'")

Expand Down Expand Up @@ -538,12 +507,7 @@ def __init__(self):

def __getattr__(self, name):
if name == "category":
warnings.warn(
"Image categories are deprecated and will be removed in Pillow 10 "
"(2023-07-01). Use is_animated instead.",
DeprecationWarning,
stacklevel=2,
)
deprecate("Image categories", 10, "is_animated", plural=True)
return self._category
raise AttributeError(name)

Expand Down
18 changes: 3 additions & 15 deletions src/PIL/ImageCms.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,12 @@
# below for the original description.

import sys
import warnings
from enum import IntEnum

from PIL import Image

from ._deprecate import deprecate

try:
from PIL import _imagingcms
except ImportError as ex:
Expand Down Expand Up @@ -117,24 +118,11 @@ class Direction(IntEnum):


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,
)
deprecate(f"{prefix}{name}", 10, f"{enum.__name__}.{name}")
return enum[name]
raise AttributeError(f"module '{__name__}' has no attribute '{name}'")

Expand Down
18 changes: 2 additions & 16 deletions src/PIL/ImageFont.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
from io import BytesIO

from . import Image
from ._deprecate import deprecate
from ._util import isDirectory, isPath


Expand All @@ -42,24 +43,11 @@ class Layout(IntEnum):


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,
)
deprecate(f"{prefix}{name}", 10, f"{enum.__name__}.{name}")
return enum[name]
raise AttributeError(f"module '{__name__}' has no attribute '{name}'")

Expand Down Expand Up @@ -196,8 +184,6 @@ def __init__(self, font=None, size=10, index=0, encoding="", layout_engine=None)
if core.HAVE_RAQM:
layout_engine = Layout.RAQM
elif layout_engine == Layout.RAQM and not core.HAVE_RAQM:
import warnings

warnings.warn(
"Raqm layout was requested, but Raqm is not available. "
"Falling back to basic layout."
Expand Down
Loading