Add typing information to ImageCmsProfile, and deprecate product_name/product_info

The _set method is no longer necessary, since we no longer compute any
attributes from the profile. In most cases, we only set the profile, and
in only one branch do we set the filename to anything non-None.

product_name/product_info were set to None at some point during what
appears to be a batch of changes for Python 3 compatibility
(ce041fd199), and never set back. Given
this, let's deprecate these and schedule them for removal in Pillow 13.
This commit is contained in:
Luke Granger-Brown 2025-06-03 12:00:05 +01:00 committed by Luke Granger-Brown
parent 070e1eba62
commit ab75ef6629
2 changed files with 51 additions and 6 deletions

View File

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

View File

@ -241,6 +241,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,
@ -248,6 +251,7 @@ class ImageCmsProfile:
low-level profile object
"""
self.filename = None
if isinstance(profile, str):
if sys.platform == "win32":
@ -256,22 +260,40 @@ class ImageCmsProfile:
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())
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:
"""