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 method uses an image's file pointer, and so child images could only be retrieved from
an :py:class:`PIL.ImageFile.ImageFile` instance. 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 Removed features
---------------- ----------------

View File

@ -241,6 +241,9 @@ _FLAGS = {
class ImageCmsProfile: class ImageCmsProfile:
profile: core.CmsProfile
filename: str | None
def __init__(self, profile: str | SupportsRead[bytes] | core.CmsProfile) -> None: def __init__(self, profile: str | SupportsRead[bytes] | core.CmsProfile) -> None:
""" """
:param profile: Either a string representing a filename, :param profile: Either a string representing a filename,
@ -248,6 +251,7 @@ class ImageCmsProfile:
low-level profile object low-level profile object
""" """
self.filename = None
if isinstance(profile, str): if isinstance(profile, str):
if sys.platform == "win32": if sys.platform == "win32":
@ -256,22 +260,40 @@ class ImageCmsProfile:
profile_bytes_path.decode("ascii") profile_bytes_path.decode("ascii")
except UnicodeDecodeError: except UnicodeDecodeError:
with open(profile, "rb") as f: with open(profile, "rb") as f:
self._set(core.profile_frombytes(f.read())) self.profile = core.profile_frombytes(f.read())
return return
self._set(core.profile_open(profile), profile) self.filename = profile
self.profile = core.profile_open(profile)
elif hasattr(profile, "read"): elif hasattr(profile, "read"):
self._set(core.profile_frombytes(profile.read())) self.profile = core.profile_frombytes(profile.read())
elif isinstance(profile, core.CmsProfile): elif isinstance(profile, core.CmsProfile):
self._set(profile) self.profile = profile
else: else:
msg = "Invalid type for Profile" # type: ignore[unreachable] msg = "Invalid type for Profile" # type: ignore[unreachable]
raise TypeError(msg) 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: 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.profile = profile
self.filename = filename self.filename = filename
self.product_name = None # profile.product_name
self.product_info = None # profile.product_info
def tobytes(self) -> bytes: def tobytes(self) -> bytes:
""" """