Skip to content

Commit

Permalink
Merge pull request #7609 from bgilbert/encoder-errors
Browse files Browse the repository at this point in the history
Translate encoder error codes to strings; deprecate `ImageFile.raise_oserror()`
  • Loading branch information
radarhere committed Dec 13, 2023
2 parents 4c7eeec + e1fb1ab commit 45e4408
Show file tree
Hide file tree
Showing 5 changed files with 47 additions and 10 deletions.
5 changes: 3 additions & 2 deletions Tests/test_imagefile.py
Expand Up @@ -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):
Expand Down
10 changes: 10 additions & 0 deletions docs/deprecations.rst
Expand Up @@ -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
----------------

Expand Down
14 changes: 14 additions & 0 deletions docs/releasenotes/10.2.0.rst
Expand Up @@ -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
^^^^

Expand Down Expand Up @@ -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.
26 changes: 18 additions & 8 deletions src/PIL/ImageFile.py
Expand Up @@ -35,6 +35,7 @@
from typing import NamedTuple

from . import Image
from ._deprecate import deprecate
from ._util import is_path

MAXBLOCK = 65536
Expand Down Expand Up @@ -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):
Expand Down Expand Up @@ -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)

Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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()

Expand Down
2 changes: 2 additions & 0 deletions src/PIL/_deprecate.py
Expand Up @@ -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)
Expand Down

0 comments on commit 45e4408

Please sign in to comment.