Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 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
12 changes: 11 additions & 1 deletion Tests/test_imagecms.py
Original file line number Diff line number Diff line change
Expand Up @@ -710,8 +710,18 @@ def test_deprecation() -> None:
with pytest.warns(DeprecationWarning):
assert isinstance(ImageCms.FLAGS, dict)

profile = ImageCmsProfile(ImageCms.createProfile("sRGB"))
p = ImageCms.createProfile("sRGB")
profile = ImageCmsProfile(p)
with pytest.warns(DeprecationWarning):
ImageCms.ImageCmsTransform(profile, profile, "RGBA;16B", "RGB")
with pytest.warns(DeprecationWarning):
ImageCms.ImageCmsTransform(profile, profile, "RGB", "RGBA;16B")

with pytest.warns(DeprecationWarning):
profile.product_name
with pytest.warns(DeprecationWarning):
profile.product_info
with pytest.warns(DeprecationWarning):
profile._set(p)
with pytest.raises(AttributeError):
profile.this_attribute_does_not_exist
23 changes: 23 additions & 0 deletions docs/deprecations.rst
Original file line number Diff line number Diff line change
Expand Up @@ -193,6 +193,29 @@ Image.Image.get_child_images()
method uses an image's file pointer, and so child images could only be retrieved from
an :py:class:`PIL.ImageFile.ImageFile` instance.

ImageCms.ImageCmsProfile._set
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

.. deprecated:: 11.3.0

``ImageCms.ImageCmsProfile._set()`` has been deprecated, and will be removed in
Pillow 13 (2026-10-15). You should construct a new ``ImageCmsProfile`` instance
instead.

ImageCms.ImageCmsProfile.product_name and .product_info
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

.. deprecated:: 11.3.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.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not following this.

>>> from PIL import ImageCms
>>> profile = ImageCms.ImageCmsProfile(ImageCms.createProfile("sRGB"))
>>> profile.profile.product_name
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'PIL.ImageCms.core.CmsProfile' object has no attribute 'product_name'

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've pushed commits to remove the replacement suggestion.


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
----------------

Expand Down
34 changes: 28 additions & 6 deletions src/PIL/ImageCms.py
Original file line number Diff line number Diff line change
Expand Up @@ -241,13 +241,17 @@


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,
a file like object containing a profile or a
low-level profile object
"""
self.filename = None

if isinstance(profile, str):
if sys.platform == "win32":
Expand All @@ -256,22 +260,40 @@
profile_bytes_path.decode("ascii")
except UnicodeDecodeError:
with open(profile, "rb") as f:
self._set(core.profile_frombytes(f.read()))
self.profile = core.profile_frombytes(f.read())

Check warning on line 263 in src/PIL/ImageCms.py

View check run for this annotation

Codecov / codecov/patch

src/PIL/ImageCms.py#L263

Added line #L263 was not covered by tests
return
self._set(core.profile_open(profile), profile)
self.filename = profile
self.profile = core.profile_open(profile)
elif hasattr(profile, "read"):
self._set(core.profile_frombytes(profile.read()))
self.profile = core.profile_frombytes(profile.read())
elif isinstance(profile, core.CmsProfile):
self._set(profile)
self.profile = profile
else:
msg = "Invalid type for Profile" # type: ignore[unreachable]
raise TypeError(msg)

def __getattr__(self, attr: str) -> Any:
if attr in ("product_name", "product_info"):
deprecate(
f"ImageCms.ImageCmsProfile.{attr}",
13,
action=(
f"Use ImageCms.ImageCmsProfile.profile.{attr} instead. "
f"Note that {attr} has been set to 'None' since Pillow 2.3.0."
),
)
return None
msg = f"'{self.__class__.__name__}' has no attribute '{attr}'"
raise AttributeError(msg)

def _set(self, profile: core.CmsProfile, filename: str | None = None) -> None:
deprecate(
"ImageCmsProfile._set",
13,
action="Set the 'profile' and 'filename' attributes directly instead.",
)
self.profile = profile
self.filename = filename
self.product_name = None # profile.product_name
self.product_info = None # profile.product_info

def tobytes(self) -> bytes:
"""
Expand Down
Loading