Skip to content

Commit 743ddc7

Browse files
authored
Merge pull request #8338 from yngvem/improve-error-messages
2 parents e80cada + 9adb476 commit 743ddc7

File tree

2 files changed

+45
-10
lines changed

2 files changed

+45
-10
lines changed

Tests/test_imagefont.py

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
import re
66
import shutil
77
import sys
8+
import tempfile
89
from io import BytesIO
910
from pathlib import Path
1011
from typing import Any, BinaryIO
@@ -460,17 +461,43 @@ def test_free_type_font_get_mask(font: ImageFont.FreeTypeFont) -> None:
460461
assert mask.size == (108, 13)
461462

462463

464+
def test_load_when_image_not_found() -> None:
465+
with tempfile.NamedTemporaryFile(delete=False) as tmp:
466+
pass
467+
with pytest.raises(OSError) as e:
468+
ImageFont.load(tmp.name)
469+
470+
os.unlink(tmp.name)
471+
472+
root = os.path.splitext(tmp.name)[0]
473+
assert str(e.value) == f"cannot find glyph data file {root}.{{gif|pbm|png}}"
474+
475+
463476
def test_load_path_not_found() -> None:
464477
# Arrange
465478
filename = "somefilenamethatdoesntexist.ttf"
466479

467480
# Act/Assert
468-
with pytest.raises(OSError):
481+
with pytest.raises(OSError) as e:
469482
ImageFont.load_path(filename)
483+
484+
# The file doesn't exist, so don't suggest `load`
485+
assert filename in str(e.value)
486+
assert "did you mean" not in str(e.value)
470487
with pytest.raises(OSError):
471488
ImageFont.truetype(filename)
472489

473490

491+
def test_load_path_existing_path() -> None:
492+
with tempfile.NamedTemporaryFile() as tmp:
493+
with pytest.raises(OSError) as e:
494+
ImageFont.load_path(tmp.name)
495+
496+
# The file exists, so the error message suggests to use `load` instead
497+
assert tmp.name in str(e.value)
498+
assert " did you mean" in str(e.value)
499+
500+
474501
def test_load_non_font_bytes() -> None:
475502
with open("Tests/images/hopper.jpg", "rb") as f:
476503
with pytest.raises(OSError):

src/PIL/ImageFont.py

Lines changed: 17 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -98,11 +98,13 @@ class ImageFont:
9898
def _load_pilfont(self, filename: str) -> None:
9999
with open(filename, "rb") as fp:
100100
image: ImageFile.ImageFile | None = None
101+
root = os.path.splitext(filename)[0]
102+
101103
for ext in (".png", ".gif", ".pbm"):
102104
if image:
103105
image.close()
104106
try:
105-
fullname = os.path.splitext(filename)[0] + ext
107+
fullname = root + ext
106108
image = Image.open(fullname)
107109
except Exception:
108110
pass
@@ -112,7 +114,8 @@ def _load_pilfont(self, filename: str) -> None:
112114
else:
113115
if image:
114116
image.close()
115-
msg = "cannot find glyph data file"
117+
118+
msg = f"cannot find glyph data file {root}.{{gif|pbm|png}}"
116119
raise OSError(msg)
117120

118121
self.file = fullname
@@ -224,7 +227,7 @@ def __init__(
224227
raise core.ex
225228

226229
if size <= 0:
227-
msg = "font size must be greater than 0"
230+
msg = f"font size must be greater than 0, not {size}"
228231
raise ValueError(msg)
229232

230233
self.path = font
@@ -783,8 +786,9 @@ def getlength(self, text: str | bytes, *args: Any, **kwargs: Any) -> float:
783786

784787
def load(filename: str) -> ImageFont:
785788
"""
786-
Load a font file. This function loads a font object from the given
787-
bitmap font file, and returns the corresponding font object.
789+
Load a font file. This function loads a font object from the given
790+
bitmap font file, and returns the corresponding font object. For loading TrueType
791+
or OpenType fonts instead, see :py:func:`~PIL.ImageFont.truetype`.
788792
789793
:param filename: Name of font file.
790794
:return: A font object.
@@ -804,9 +808,10 @@ def truetype(
804808
) -> FreeTypeFont:
805809
"""
806810
Load a TrueType or OpenType font from a file or file-like object,
807-
and create a font object.
808-
This function loads a font object from the given file or file-like
809-
object, and creates a font object for a font of the given size.
811+
and create a font object. This function loads a font object from the given
812+
file or file-like object, and creates a font object for a font of the given
813+
size. For loading bitmap fonts instead, see :py:func:`~PIL.ImageFont.load`
814+
and :py:func:`~PIL.ImageFont.load_path`.
810815
811816
Pillow uses FreeType to open font files. On Windows, be aware that FreeType
812817
will keep the file open as long as the FreeTypeFont object exists. Windows
@@ -942,7 +947,10 @@ def load_path(filename: str | bytes) -> ImageFont:
942947
return load(os.path.join(directory, filename))
943948
except OSError:
944949
pass
945-
msg = "cannot find font file"
950+
msg = f'cannot find font file "{filename}" in sys.path'
951+
if os.path.exists(filename):
952+
msg += f', did you mean ImageFont.load("{filename}") instead?'
953+
946954
raise OSError(msg)
947955

948956

0 commit comments

Comments
 (0)