Skip to content

Commit 45e4408

Browse files
authored
Merge pull request #7609 from bgilbert/encoder-errors
Translate encoder error codes to strings; deprecate `ImageFile.raise_oserror()`
2 parents 4c7eeec + e1fb1ab commit 45e4408

File tree

5 files changed

+47
-10
lines changed

5 files changed

+47
-10
lines changed

Tests/test_imagefile.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -115,8 +115,9 @@ def test_safeblock(self):
115115
assert_image_equal(im1, im2)
116116

117117
def test_raise_oserror(self):
118-
with pytest.raises(OSError):
119-
ImageFile.raise_oserror(1)
118+
with pytest.warns(DeprecationWarning):
119+
with pytest.raises(OSError):
120+
ImageFile.raise_oserror(1)
120121

121122
def test_raise_typeerror(self):
122123
with pytest.raises(TypeError):

docs/deprecations.rst

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,16 @@ Since Pillow's C API is now faster than PyAccess on PyPy,
3434
``Image.USE_CFFI_ACCESS``, for switching from the C API to PyAccess, is
3535
similarly deprecated.
3636

37+
ImageFile.raise_oserror
38+
~~~~~~~~~~~~~~~~~~~~~~~
39+
40+
.. deprecated:: 10.2.0
41+
42+
``ImageFile.raise_oserror()`` has been deprecated and will be removed in Pillow
43+
12.0.0 (2025-10-15). The function is undocumented and is only useful for translating
44+
error codes returned by a codec's ``decode()`` method, which ImageFile already does
45+
automatically.
46+
3747
Removed features
3848
----------------
3949

docs/releasenotes/10.2.0.rst

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,14 @@ TODO
1212
Deprecations
1313
============
1414

15+
ImageFile.raise_oserror
16+
^^^^^^^^^^^^^^^^^^^^^^^
17+
18+
``ImageFile.raise_oserror()`` has been deprecated and will be removed in Pillow
19+
12.0.0 (2025-10-15). The function is undocumented and is only useful for translating
20+
error codes returned by a codec's ``decode()`` method, which ImageFile already does
21+
automatically.
22+
1523
TODO
1624
^^^^
1725

@@ -77,3 +85,9 @@ Calculating the :py:attr:`~PIL.ImageStat.Stat.count` and
7785
:py:attr:`~PIL.ImageStat.Stat.extrema` statistics is now faster. After the
7886
histogram is created in ``st = ImageStat.Stat(im)``, ``st.count`` is 3x as fast
7987
on average and ``st.extrema`` is 12x as fast on average.
88+
89+
Encoder errors now report error detail as string
90+
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
91+
92+
:py:exc:`OSError` exceptions from image encoders now include a textual description of
93+
the error instead of a numeric error code.

src/PIL/ImageFile.py

Lines changed: 18 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@
3535
from typing import NamedTuple
3636

3737
from . import Image
38+
from ._deprecate import deprecate
3839
from ._util import is_path
3940

4041
MAXBLOCK = 65536
@@ -63,15 +64,25 @@
6364
# Helpers
6465

6566

66-
def raise_oserror(error):
67+
def _get_oserror(error, *, encoder):
6768
try:
6869
msg = Image.core.getcodecstatus(error)
6970
except AttributeError:
7071
msg = ERRORS.get(error)
7172
if not msg:
72-
msg = f"decoder error {error}"
73-
msg += " when reading image file"
74-
raise OSError(msg)
73+
msg = f"{'encoder' if encoder else 'decoder'} error {error}"
74+
msg += f" when {'writing' if encoder else 'reading'} image file"
75+
return OSError(msg)
76+
77+
78+
def raise_oserror(error):
79+
deprecate(
80+
"raise_oserror",
81+
12,
82+
action="It is only useful for translating error codes returned by a codec's "
83+
"decode() method, which ImageFile already does automatically.",
84+
)
85+
raise _get_oserror(error, encoder=False)
7586

7687

7788
def _tilesort(t):
@@ -294,7 +305,7 @@ def load(self):
294305

295306
if not self.map and not LOAD_TRUNCATED_IMAGES and err_code < 0:
296307
# still raised if decoder fails to return anything
297-
raise_oserror(err_code)
308+
raise _get_oserror(err_code, encoder=False)
298309

299310
return Image.Image.load(self)
300311

@@ -421,7 +432,7 @@ def feed(self, data):
421432
if e < 0:
422433
# decoding error
423434
self.image = None
424-
raise_oserror(e)
435+
raise _get_oserror(e, encoder=False)
425436
else:
426437
# end of image
427438
return
@@ -551,8 +562,7 @@ def _encode_tile(im, fp, tile: list[_Tile], bufsize, fh, exc=None):
551562
# slight speedup: compress to real file object
552563
errcode = encoder.encode_to_file(fh, bufsize)
553564
if errcode < 0:
554-
msg = f"encoder error {errcode} when writing image file"
555-
raise OSError(msg) from exc
565+
raise _get_oserror(errcode, encoder=True) from exc
556566
finally:
557567
encoder.cleanup()
558568

src/PIL/_deprecate.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,8 @@ def deprecate(
4747
raise RuntimeError(msg)
4848
elif when == 11:
4949
removed = "Pillow 11 (2024-10-15)"
50+
elif when == 12:
51+
removed = "Pillow 12 (2025-10-15)"
5052
else:
5153
msg = f"Unknown removal version: {when}. Update {__name__}?"
5254
raise ValueError(msg)

0 commit comments

Comments
 (0)