Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 27 additions & 0 deletions Tests/test_imagefont.py
Original file line number Diff line number Diff line change
Expand Up @@ -460,6 +460,17 @@ def test_free_type_font_get_mask(font: ImageFont.FreeTypeFont) -> None:
assert mask.size == (108, 13)


def test_load_raises_if_image_not_found(tmp_path) -> None:
font_path = tmp_path / "file.font"
font_path.write_bytes(b"")
with pytest.raises(OSError) as excinfo:
ImageFont.load(font_path)

pre = tmp_path / "file"
msg = f"cannot find glyph data file {pre}.{{png|gif|pbm}}"
assert msg in str(excinfo.value)


def test_load_path_not_found() -> None:
# Arrange
filename = "somefilenamethatdoesntexist.ttf"
Expand All @@ -471,6 +482,22 @@ def test_load_path_not_found() -> None:
ImageFont.truetype(filename)


def test_load_path_exisitng_path(tmp_path) -> None:
# First, the file doens't exist, so we don't suggest `load`
some_path = tmp_path / "file.ttf"
with pytest.raises(OSError) as excinfo:
ImageFont.load_path(str(some_path))
assert str(some_path) in str(excinfo.value)
assert "did you mean" not in str(excinfo.value)

# The file exists, so the error message suggests to use `load` instead
some_path.write_bytes(b"")
with pytest.raises(OSError) as excinfo:
ImageFont.load_path(str(some_path))
assert str(some_path) in str(excinfo.value)
assert " did you mean" in str(excinfo.value)


def test_load_non_font_bytes() -> None:
with open("Tests/images/hopper.jpg", "rb") as f:
with pytest.raises(OSError):
Expand Down
19 changes: 15 additions & 4 deletions src/PIL/ImageFont.py
Original file line number Diff line number Diff line change
Expand Up @@ -98,11 +98,13 @@ class ImageFont:
def _load_pilfont(self, filename: str) -> None:
with open(filename, "rb") as fp:
image: ImageFile.ImageFile | None = None
filename_body = os.path.splitext(filename)[0]

for ext in (".png", ".gif", ".pbm"):
if image:
image.close()
try:
fullname = os.path.splitext(filename)[0] + ext
fullname = filename_body + ext
image = Image.open(fullname)
except Exception:
pass
Expand All @@ -112,7 +114,9 @@ def _load_pilfont(self, filename: str) -> None:
else:
if image:
image.close()
msg = "cannot find glyph data file"

pre = filename_body
msg = f"cannot find glyph data file {pre}.{{png|gif|pbm}}"
raise OSError(msg)

self.file = fullname
Expand Down Expand Up @@ -224,7 +228,7 @@ def __init__(
raise core.ex

if size <= 0:
msg = "font size must be greater than 0"
msg = f"font size must be greater than 0, not {size}"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Was this also a source of confusion for you? I'm not sure why this wouldn't be suitably obvious.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No this happened more on auto-pilot while coding in the evening -- I pretty much always try to include the incorrect value in error messages if it fails on input-validation as I find it makes debugging quite a lot easier for me (especially if the error is several frames down the stack from where I'm working).

Feel free to remove it, no hard feelings there :)

raise ValueError(msg)

self.path = font
Expand Down Expand Up @@ -774,6 +778,8 @@ def load(filename: str) -> ImageFont:
:param filename: Name of font file.
:return: A font object.
:exception OSError: If the file could not be read.

.. seealso:: :py:func:`PIL.ImageFont.truetype`
"""
f = ImageFont()
f._load_pilfont(filename)
Expand Down Expand Up @@ -850,6 +856,8 @@ def truetype(
:return: A font object.
:exception OSError: If the file could not be read.
:exception ValueError: If the font size is not greater than zero.

.. seealso:: :py:func:`PIL.ImageFont.load`
"""

def freetype(font: StrOrBytesPath | BinaryIO | None) -> FreeTypeFont:
Expand Down Expand Up @@ -927,7 +935,10 @@ def load_path(filename: str | bytes) -> ImageFont:
return load(os.path.join(directory, filename))
except OSError:
pass
msg = "cannot find font file"
msg = f"cannot find font file '{filename}' in `sys.path`"
if os.path.exists(filename):
msg += f" did you mean `ImageFont.load({filename})` instead?"

raise OSError(msg)


Expand Down