diff --git a/Tests/test_imagecms.py b/Tests/test_imagecms.py index 55a4a87fb..8b5d88ac8 100644 --- a/Tests/test_imagecms.py +++ b/Tests/test_imagecms.py @@ -690,3 +690,17 @@ def test_cmyk_lab() -> None: im = Image.new("CMYK", (1, 1)) converted_im = im.convert("LAB") assert converted_im.getpixel((0, 0)) == (255, 128, 128) + + +def test_deprecation() -> None: + profile = ImageCmsProfile(ImageCms.createProfile("sRGB")) + with pytest.warns( + DeprecationWarning, match="ImageCms.ImageCmsProfile.product_name" + ): + profile.product_name + with pytest.warns( + DeprecationWarning, match="ImageCms.ImageCmsProfile.product_info" + ): + profile.product_info + with pytest.raises(AttributeError): + profile.this_attribute_does_not_exist diff --git a/docs/deprecations.rst b/docs/deprecations.rst index 4e65dc807..1e82615d1 100644 --- a/docs/deprecations.rst +++ b/docs/deprecations.rst @@ -52,6 +52,20 @@ another mode before saving:: im = Image.new("I", (1, 1)) im.convert("I;16").save("out.png") +ImageCms.ImageCmsProfile.product_name and .product_info +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +.. deprecated:: 12.0.0 + +``ImageCms.ImageCmsProfile.product_name`` and the corresponding +``.product_info`` attributes have been deprecated, and will be removed in +Pillow 13 (2026-10-15). These attributes can be accessed on the ``.profile`` +attribute of ``ImageCmsProfile`` instead. + +Note that ``.product_name`` and ``.product_info`` have been set to ``None`` on +``ImageCmsProfile`` since Pillow 2.3.0 (2014-01-01), so any working code that +makes use of this data will already access it on ``.profile``. + Removed features ---------------- diff --git a/src/PIL/ImageCms.py b/src/PIL/ImageCms.py index d3555694a..71a5a5376 100644 --- a/src/PIL/ImageCms.py +++ b/src/PIL/ImageCms.py @@ -23,9 +23,10 @@ import operator import sys from enum import IntEnum, IntFlag from functools import reduce -from typing import Literal, SupportsFloat, SupportsInt, Union +from typing import Any, Literal, SupportsFloat, SupportsInt, Union from . import Image +from ._deprecate import deprecate from ._typing import SupportsRead try: @@ -226,6 +227,9 @@ _FLAGS = { class ImageCmsProfile: + profile: core.CmsProfile + filename: str | None + def __init__(self, profile: str | SupportsRead[bytes] | core.CmsProfile) -> None: """ :param profile: Either a string representing a filename, @@ -234,8 +238,6 @@ class ImageCmsProfile: """ self.filename = None - self.product_name = None # profile.product_name - self.product_info = None # profile.product_info if isinstance(profile, str): if sys.platform == "win32": @@ -256,6 +258,20 @@ class ImageCmsProfile: msg = "Invalid type for Profile" # type: ignore[unreachable] raise TypeError(msg) + def __getattr__(self, name: str) -> Any: + if name in ("product_name", "product_info"): + deprecate( + f"ImageCms.ImageCmsProfile.{name}", + 13, + action=( + f"Use ImageCms.ImageCmsProfile.profile.{name} instead. " + f"Note that {name} has been set to 'None' since Pillow 2.3.0." + ), + ) + return None + msg = f"'{self.__class__.__name__}' has no attribute '{name}'" + raise AttributeError(msg) + def tobytes(self) -> bytes: """ Returns the profile in a format suitable for embedding in