Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit e3c8195

Browse files
authored
Merge pull request #22591 from oscargus/fontmanageraddpathstr
Fix Path/str-discrepancy in FontManager.addpath and improve documentation
2 parents e7a6fbe + 7f21bca commit e3c8195

File tree

5 files changed

+100
-29
lines changed

5 files changed

+100
-29
lines changed

doc/api/font_manager_api.rst

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,5 +7,9 @@
77
:undoc-members:
88
:show-inheritance:
99

10+
.. data:: fontManager
11+
12+
The global instance of `FontManager`.
13+
1014
.. autoclass:: FontEntry
1115
:no-undoc-members:

lib/matplotlib/font_manager.py

Lines changed: 53 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
"""
22
A module for finding, managing, and using fonts across platforms.
33
4-
This module provides a single `FontManager` instance that can
4+
This module provides a single `FontManager` instance, ``fontManager``, that can
55
be shared across backends and platforms. The `findfont`
66
function returns the best TrueType (TTF) font file in the local or
77
system font path that matches the specified `FontProperties`
@@ -627,32 +627,33 @@ class FontProperties:
627627
628628
- family: A list of font names in decreasing order of priority.
629629
The items may include a generic font family name, either
630-
'sans-serif' (default), 'serif', 'cursive', 'fantasy', or 'monospace'.
630+
'sans-serif', 'serif', 'cursive', 'fantasy', or 'monospace'.
631631
In that case, the actual font to be used will be looked up
632-
from the associated rcParam.
632+
from the associated rcParam. Default: :rc:`font.family`
633633
634-
- style: Either 'normal' (default), 'italic' or 'oblique'.
634+
- style: Either 'normal', 'italic' or 'oblique'.
635+
Default: :rc:`font.style`
635636
636-
- variant: Either 'normal' (default) or 'small-caps'.
637+
- variant: Either 'normal' or 'small-caps'.
638+
Default: :rc:`font.variant`
637639
638640
- stretch: A numeric value in the range 0-1000 or one of
639641
'ultra-condensed', 'extra-condensed', 'condensed',
640-
'semi-condensed', 'normal' (default), 'semi-expanded', 'expanded',
641-
'extra-expanded' or 'ultra-expanded'.
642+
'semi-condensed', 'normal', 'semi-expanded', 'expanded',
643+
'extra-expanded' or 'ultra-expanded'. Default: :rc:`font.stretch`
642644
643645
- weight: A numeric value in the range 0-1000 or one of
644-
'ultralight', 'light', 'normal' (default), 'regular', 'book', 'medium',
646+
'ultralight', 'light', 'normal', 'regular', 'book', 'medium',
645647
'roman', 'semibold', 'demibold', 'demi', 'bold', 'heavy',
646-
'extra bold', 'black'.
648+
'extra bold', 'black'. Default: :rc:`font.weight`
647649
648650
- size: Either an relative value of 'xx-small', 'x-small',
649651
'small', 'medium', 'large', 'x-large', 'xx-large' or an
650-
absolute font size, e.g., 10 (default).
652+
absolute font size, e.g., 10. Default: :rc:`font.size`
651653
652-
- math_fontfamily: The family of fonts used to render math text; overrides
653-
:rc:`mathtext.fontset`. Supported values are the same as the ones
654-
supported by :rc:`mathtext.fontset`: 'dejavusans', 'dejavuserif', 'cm',
655-
'stix', 'stixsans' and 'custom'.
654+
- math_fontfamily: The family of fonts used to render math text.
655+
Supported values are: 'dejavusans', 'dejavuserif', 'cm',
656+
'stix', 'stixsans' and 'custom'. Default: :rc:`mathtext.fontset`
656657
657658
Alternatively, a font may be specified using the absolute path to a font
658659
file, by using the *fname* kwarg. However, in this case, it is typically
@@ -807,7 +808,7 @@ def set_family(self, family):
807808
is CSS parlance), such as: 'serif', 'sans-serif', 'cursive',
808809
'fantasy', or 'monospace', a real font name or a list of real
809810
font names. Real font names are not supported when
810-
:rc:`text.usetex` is `True`.
811+
:rc:`text.usetex` is `True`. Default: :rc:`font.family`
811812
"""
812813
if family is None:
813814
family = rcParams['font.family']
@@ -817,7 +818,11 @@ def set_family(self, family):
817818

818819
def set_style(self, style):
819820
"""
820-
Set the font style. Values are: 'normal', 'italic' or 'oblique'.
821+
Set the font style.
822+
823+
Parameters
824+
----------
825+
style : {'normal', 'italic', 'oblique'}, default: :rc:`font.style`
821826
"""
822827
if style is None:
823828
style = rcParams['font.style']
@@ -826,7 +831,11 @@ def set_style(self, style):
826831

827832
def set_variant(self, variant):
828833
"""
829-
Set the font variant. Values are: 'normal' or 'small-caps'.
834+
Set the font variant.
835+
836+
Parameters
837+
----------
838+
variant : {'normal', 'small-caps'}, default: :rc:`font.variant`
830839
"""
831840
if variant is None:
832841
variant = rcParams['font.variant']
@@ -835,10 +844,14 @@ def set_variant(self, variant):
835844

836845
def set_weight(self, weight):
837846
"""
838-
Set the font weight. May be either a numeric value in the
839-
range 0-1000 or one of 'ultralight', 'light', 'normal',
840-
'regular', 'book', 'medium', 'roman', 'semibold', 'demibold',
841-
'demi', 'bold', 'heavy', 'extra bold', 'black'
847+
Set the font weight.
848+
849+
Parameters
850+
----------
851+
weight : int or {'ultralight', 'light', 'normal', 'regular', 'book', \
852+
'medium', 'roman', 'semibold', 'demibold', 'demi', 'bold', 'heavy', \
853+
'extra bold', 'black'}, default: :rc:`font.weight`
854+
If int, must be in the range 0-1000.
842855
"""
843856
if weight is None:
844857
weight = rcParams['font.weight']
@@ -853,10 +866,14 @@ def set_weight(self, weight):
853866

854867
def set_stretch(self, stretch):
855868
"""
856-
Set the font stretch or width. Options are: 'ultra-condensed',
857-
'extra-condensed', 'condensed', 'semi-condensed', 'normal',
858-
'semi-expanded', 'expanded', 'extra-expanded' or
859-
'ultra-expanded', or a numeric value in the range 0-1000.
869+
Set the font stretch or width.
870+
871+
Parameters
872+
----------
873+
stretch : int or {'ultra-condensed', 'extra-condensed', 'condensed', \
874+
'semi-condensed', 'normal', 'semi-expanded', 'expanded', 'extra-expanded', \
875+
'ultra-expanded'}, default: :rc:`font.stretch`
876+
If int, must be in the range 0-1000.
860877
"""
861878
if stretch is None:
862879
stretch = rcParams['font.stretch']
@@ -871,9 +888,14 @@ def set_stretch(self, stretch):
871888

872889
def set_size(self, size):
873890
"""
874-
Set the font size. Either an relative value of 'xx-small',
875-
'x-small', 'small', 'medium', 'large', 'x-large', 'xx-large'
876-
or an absolute font size, e.g., 12.
891+
Set the font size.
892+
893+
Parameters
894+
----------
895+
size : float or {'xx-small', 'x-small', 'small', 'medium', \
896+
'large', 'x-large', 'xx-large'}, default: :rc:`font.size`
897+
If float, the font size in points. The string values denote sizes
898+
relative to the default font size.
877899
"""
878900
if size is None:
879901
size = rcParams['font.size']
@@ -1091,6 +1113,9 @@ def addfont(self, path):
10911113
----------
10921114
path : str or path-like
10931115
"""
1116+
# Convert to string in case of a path as
1117+
# afmFontProperty and FT2Font expect this
1118+
path = os.fsdecode(path)
10941119
if Path(path).suffix.lower() == ".afm":
10951120
with open(path, "rb") as fh:
10961121
font = _afm.AFM(fh)

lib/matplotlib/rcsetup.py

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -387,6 +387,20 @@ def validate_fontweight(s):
387387
raise ValueError(f'{s} is not a valid font weight.') from e
388388

389389

390+
def validate_fontstretch(s):
391+
stretchvalues = [
392+
'ultra-condensed', 'extra-condensed', 'condensed', 'semi-condensed',
393+
'normal', 'semi-expanded', 'expanded', 'extra-expanded',
394+
'ultra-expanded']
395+
# Note: Historically, stretchvalues have been case-sensitive in Matplotlib
396+
if s in stretchvalues:
397+
return s
398+
try:
399+
return int(s)
400+
except (ValueError, TypeError) as e:
401+
raise ValueError(f'{s} is not a valid font stretch.') from e
402+
403+
390404
def validate_font_properties(s):
391405
parse_fontconfig_pattern(s)
392406
return s
@@ -900,7 +914,7 @@ def _convert_validator_spec(key, conv):
900914
"font.family": validate_stringlist, # used by text object
901915
"font.style": validate_string,
902916
"font.variant": validate_string,
903-
"font.stretch": validate_string,
917+
"font.stretch": validate_fontstretch,
904918
"font.weight": validate_fontweight,
905919
"font.size": validate_float, # Base font size in points
906920
"font.serif": validate_stringlist,

lib/matplotlib/tests/test_font_manager.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -176,6 +176,13 @@ def test_user_fonts_linux(tmpdir, monkeypatch):
176176
_get_fontconfig_fonts.cache_clear()
177177

178178

179+
def test_addfont_as_path():
180+
"""Smoke test that addfont() accepts pathlib.Path."""
181+
font_test_file = 'mpltest.ttf'
182+
path = Path(__file__).parent / font_test_file
183+
fontManager.addfont(path)
184+
185+
179186
@pytest.mark.skipif(sys.platform != 'win32', reason='Windows only')
180187
def test_user_fonts_win32():
181188
if not (os.environ.get('APPVEYOR') or os.environ.get('TF_BUILD')):

lib/matplotlib/tests/test_rcparams.py

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
_validate_color_or_linecolor,
2121
validate_cycler,
2222
validate_float,
23+
validate_fontstretch,
2324
validate_fontweight,
2425
validate_hatch,
2526
validate_hist_bins,
@@ -469,6 +470,26 @@ def test_validate_fontweight(weight, parsed_weight):
469470
assert validate_fontweight(weight) == parsed_weight
470471

471472

473+
@pytest.mark.parametrize('stretch, parsed_stretch', [
474+
('expanded', 'expanded'),
475+
('EXPANDED', ValueError), # stretch is case-sensitive
476+
(100, 100),
477+
('100', 100),
478+
(np.array(100), 100),
479+
# fractional fontweights are not defined. This should actually raise a
480+
# ValueError, but historically did not.
481+
(20.6, 20),
482+
('20.6', ValueError),
483+
([100], ValueError),
484+
])
485+
def test_validate_fontstretch(stretch, parsed_stretch):
486+
if parsed_stretch is ValueError:
487+
with pytest.raises(ValueError):
488+
validate_fontstretch(stretch)
489+
else:
490+
assert validate_fontstretch(stretch) == parsed_stretch
491+
492+
472493
def test_keymaps():
473494
key_list = [k for k in mpl.rcParams if 'keymap' in k]
474495
for k in key_list:

0 commit comments

Comments
 (0)