diff --git a/Tests/test_imagefile.py b/Tests/test_imagefile.py index ff75b8c2a69..2389c471748 100644 --- a/Tests/test_imagefile.py +++ b/Tests/test_imagefile.py @@ -115,8 +115,9 @@ def test_safeblock(self): assert_image_equal(im1, im2) def test_raise_oserror(self): - with pytest.raises(OSError): - ImageFile.raise_oserror(1) + with pytest.warns(DeprecationWarning): + with pytest.raises(OSError): + ImageFile.raise_oserror(1) def test_raise_typeerror(self): with pytest.raises(TypeError): diff --git a/docs/deprecations.rst b/docs/deprecations.rst index b4fbb8d5053..75c0b73ebed 100644 --- a/docs/deprecations.rst +++ b/docs/deprecations.rst @@ -34,6 +34,16 @@ Since Pillow's C API is now faster than PyAccess on PyPy, ``Image.USE_CFFI_ACCESS``, for switching from the C API to PyAccess, is similarly deprecated. +ImageFile.raise_oserror +~~~~~~~~~~~~~~~~~~~~~~~ + +.. deprecated:: 10.2.0 + +``ImageFile.raise_oserror()`` has been deprecated and will be removed in Pillow +12.0.0 (2025-10-15). The function is undocumented and is only useful for translating +error codes returned by a codec's ``decode()`` method, which ImageFile already does +automatically. + Removed features ---------------- diff --git a/docs/releasenotes/10.2.0.rst b/docs/releasenotes/10.2.0.rst index bd06e09fc4e..9883f10baf3 100644 --- a/docs/releasenotes/10.2.0.rst +++ b/docs/releasenotes/10.2.0.rst @@ -12,6 +12,14 @@ TODO Deprecations ============ +ImageFile.raise_oserror +^^^^^^^^^^^^^^^^^^^^^^^ + +``ImageFile.raise_oserror()`` has been deprecated and will be removed in Pillow +12.0.0 (2025-10-15). The function is undocumented and is only useful for translating +error codes returned by a codec's ``decode()`` method, which ImageFile already does +automatically. + TODO ^^^^ @@ -77,3 +85,9 @@ Calculating the :py:attr:`~PIL.ImageStat.Stat.count` and :py:attr:`~PIL.ImageStat.Stat.extrema` statistics is now faster. After the histogram is created in ``st = ImageStat.Stat(im)``, ``st.count`` is 3x as fast on average and ``st.extrema`` is 12x as fast on average. + +Encoder errors now report error detail as string +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +:py:exc:`OSError` exceptions from image encoders now include a textual description of +the error instead of a numeric error code. diff --git a/src/PIL/ImageFile.py b/src/PIL/ImageFile.py index 8bca19a4b8d..1bc11af0f26 100644 --- a/src/PIL/ImageFile.py +++ b/src/PIL/ImageFile.py @@ -35,6 +35,7 @@ from typing import NamedTuple from . import Image +from ._deprecate import deprecate from ._util import is_path MAXBLOCK = 65536 @@ -63,15 +64,25 @@ # Helpers -def raise_oserror(error): +def _get_oserror(error, *, encoder): try: msg = Image.core.getcodecstatus(error) except AttributeError: msg = ERRORS.get(error) if not msg: - msg = f"decoder error {error}" - msg += " when reading image file" - raise OSError(msg) + msg = f"{'encoder' if encoder else 'decoder'} error {error}" + msg += f" when {'writing' if encoder else 'reading'} image file" + return OSError(msg) + + +def raise_oserror(error): + deprecate( + "raise_oserror", + 12, + action="It is only useful for translating error codes returned by a codec's " + "decode() method, which ImageFile already does automatically.", + ) + raise _get_oserror(error, encoder=False) def _tilesort(t): @@ -294,7 +305,7 @@ def load(self): if not self.map and not LOAD_TRUNCATED_IMAGES and err_code < 0: # still raised if decoder fails to return anything - raise_oserror(err_code) + raise _get_oserror(err_code, encoder=False) return Image.Image.load(self) @@ -421,7 +432,7 @@ def feed(self, data): if e < 0: # decoding error self.image = None - raise_oserror(e) + raise _get_oserror(e, encoder=False) else: # end of image return @@ -551,8 +562,7 @@ def _encode_tile(im, fp, tile: list[_Tile], bufsize, fh, exc=None): # slight speedup: compress to real file object errcode = encoder.encode_to_file(fh, bufsize) if errcode < 0: - msg = f"encoder error {errcode} when writing image file" - raise OSError(msg) from exc + raise _get_oserror(errcode, encoder=True) from exc finally: encoder.cleanup() diff --git a/src/PIL/_deprecate.py b/src/PIL/_deprecate.py index 2f2a3df13e3..33a0e07b3f4 100644 --- a/src/PIL/_deprecate.py +++ b/src/PIL/_deprecate.py @@ -47,6 +47,8 @@ def deprecate( raise RuntimeError(msg) elif when == 11: removed = "Pillow 11 (2024-10-15)" + elif when == 12: + removed = "Pillow 12 (2025-10-15)" else: msg = f"Unknown removal version: {when}. Update {__name__}?" raise ValueError(msg)