Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Translate encoder error codes to strings; deprecate ImageFile.raise_oserror() #7609

Merged
merged 2 commits into from Dec 13, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
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)
bgilbert marked this conversation as resolved.
Show resolved Hide resolved


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