Skip to content

Log a warning if selected font weight differs from requested #30272

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

Merged
merged 1 commit into from
Jul 15, 2025
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.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions doc/api/next_api_changes/behavior/30272-ES.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
``font_manager.findfont`` logs if selected font weight does not match requested
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Comment on lines +1 to +2
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
``font_manager.findfont`` logs if selected font weight does not match requested
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
``font_manager.findfont`` warns if selected the font weight does not match requested
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Copy link
Member Author

Choose a reason for hiding this comment

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

No, it's not a warning.

14 changes: 11 additions & 3 deletions lib/matplotlib/font_manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@
from io import BytesIO
import json
import logging
from numbers import Number
from numbers import Integral
import os
from pathlib import Path
import plistlib
Expand Down Expand Up @@ -172,6 +172,10 @@
]


def _normalize_weight(weight):
return weight if isinstance(weight, Integral) else weight_dict[weight]


def get_fontext_synonyms(fontext):
"""
Return a list of file extensions that are synonyms for
Expand Down Expand Up @@ -1256,8 +1260,8 @@ def score_weight(self, weight1, weight2):
# exact match of the weight names, e.g. weight1 == weight2 == "regular"
if cbook._str_equal(weight1, weight2):
return 0.0
w1 = weight1 if isinstance(weight1, Number) else weight_dict[weight1]
w2 = weight2 if isinstance(weight2, Number) else weight_dict[weight2]
w1 = _normalize_weight(weight1)
w2 = _normalize_weight(weight2)
return 0.95 * (abs(w1 - w2) / 1000) + 0.05

def score_size(self, size1, size2):
Expand Down Expand Up @@ -1480,6 +1484,10 @@ def _findfont_cached(self, prop, fontext, directory, fallback_to_default,
best_font = font
if score == 0:
break
if best_font is not None and (_normalize_weight(prop.get_weight()) !=
_normalize_weight(best_font.weight)):
_log.warning('findfont: Failed to find font weight %s, now using %s.',
prop.get_weight(), best_font.weight)

if best_font is None or best_score >= 10.0:
if fallback_to_default:
Expand Down
10 changes: 5 additions & 5 deletions lib/matplotlib/font_manager.pyi
Original file line number Diff line number Diff line change
@@ -1,14 +1,13 @@
from collections.abc import Iterable
from dataclasses import dataclass
from numbers import Integral
import os
from pathlib import Path
from typing import Any, Literal

from matplotlib._afm import AFM
from matplotlib import ft2font

from pathlib import Path

from collections.abc import Iterable
from typing import Any, Literal

font_scalings: dict[str | None, float]
stretch_dict: dict[str, int]
weight_dict: dict[str, int]
Expand All @@ -19,6 +18,7 @@ MSUserFontDirectories: list[str]
X11FontDirectories: list[str]
OSXFontDirectories: list[str]

def _normalize_weight(weight: str | Integral) -> Integral: ...
def get_fontext_synonyms(fontext: str) -> list[str]: ...
def list_fonts(directory: str, extensions: Iterable[str]) -> list[str]: ...
def win32FontDirectory() -> str: ...
Expand Down
29 changes: 28 additions & 1 deletion lib/matplotlib/tests/test_font_manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,8 @@
from matplotlib.font_manager import (
findfont, findSystemFonts, FontEntry, FontProperties, fontManager,
json_dump, json_load, get_font, is_opentype_cff_font,
MSUserFontDirectories, _get_fontconfig_fonts, ttfFontProperty)
MSUserFontDirectories, ttfFontProperty,
_get_fontconfig_fonts, _normalize_weight)
from matplotlib import cbook, ft2font, pyplot as plt, rc_context, figure as mfigure
from matplotlib.testing import subprocess_run_helper, subprocess_run_for_testing

Expand Down Expand Up @@ -407,3 +408,29 @@ def test_fontproperties_init_deprecation():
# Since this case is not covered by docs, I've refrained from jumping
# extra hoops to detect this possible API misuse.
FontProperties(family="serif-24:style=oblique:weight=bold")


def test_normalize_weights():
assert _normalize_weight(300) == 300 # passthrough
assert _normalize_weight('ultralight') == 100
assert _normalize_weight('light') == 200
assert _normalize_weight('normal') == 400
assert _normalize_weight('regular') == 400
assert _normalize_weight('book') == 400
assert _normalize_weight('medium') == 500
assert _normalize_weight('roman') == 500
assert _normalize_weight('semibold') == 600
assert _normalize_weight('demibold') == 600
assert _normalize_weight('demi') == 600
assert _normalize_weight('bold') == 700
assert _normalize_weight('heavy') == 800
assert _normalize_weight('extra bold') == 800
assert _normalize_weight('black') == 900
with pytest.raises(KeyError):
_normalize_weight('invalid')


def test_font_match_warning(caplog):
findfont(FontProperties(family=["DejaVu Sans"], weight=750))
logs = [rec.message for rec in caplog.records]
assert 'findfont: Failed to find font weight 750, now using 700.' in logs
Copy link
Member

Choose a reason for hiding this comment

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

Just for my own interest, is there a reason to check the logs, instead of using a pytest.warns context?

Copy link
Member Author

Choose a reason for hiding this comment

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

Same reason as above.

Loading
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy