From 3656bf9b40509db3cdbb107aaf0ff2ab454a5835 Mon Sep 17 00:00:00 2001 From: Oscar Gustafsson Date: Thu, 3 Mar 2022 18:47:22 +0100 Subject: [PATCH 1/4] Convert path to str in FontManager.addpath --- lib/matplotlib/font_manager.py | 2 ++ lib/matplotlib/tests/test_font_manager.py | 7 +++++++ 2 files changed, 9 insertions(+) diff --git a/lib/matplotlib/font_manager.py b/lib/matplotlib/font_manager.py index e17d847ea87c..05ef4e6dc3ec 100644 --- a/lib/matplotlib/font_manager.py +++ b/lib/matplotlib/font_manager.py @@ -1091,6 +1091,8 @@ def addfont(self, path): ---------- path : str or path-like """ + path = str(path) # Convert to string in case of a path as + # afmFontProperty and FT2Font expect this if Path(path).suffix.lower() == ".afm": with open(path, "rb") as fh: font = _afm.AFM(fh) diff --git a/lib/matplotlib/tests/test_font_manager.py b/lib/matplotlib/tests/test_font_manager.py index fb1119e33489..a20cbd85e197 100644 --- a/lib/matplotlib/tests/test_font_manager.py +++ b/lib/matplotlib/tests/test_font_manager.py @@ -176,6 +176,13 @@ def test_user_fonts_linux(tmpdir, monkeypatch): _get_fontconfig_fonts.cache_clear() +def test_addfont(): + font_test_file = 'mpltest.ttf' + path = Path(__file__).parent / font_test_file + # Add font using Path, which should not produce an error. See #22582 + fontManager.addfont(path) + + @pytest.mark.skipif(sys.platform != 'win32', reason='Windows only') def test_user_fonts_win32(): if not (os.environ.get('APPVEYOR') or os.environ.get('TF_BUILD')): From 25d2d559e3a8d2141b98b7532758d615d47a9194 Mon Sep 17 00:00:00 2001 From: Oscar Gustafsson Date: Thu, 3 Mar 2022 19:10:59 +0100 Subject: [PATCH 2/4] Improve documentation of FontManager --- lib/matplotlib/font_manager.py | 81 ++++++++++++++++++++++------------ 1 file changed, 52 insertions(+), 29 deletions(-) diff --git a/lib/matplotlib/font_manager.py b/lib/matplotlib/font_manager.py index 05ef4e6dc3ec..d8da217a0e36 100644 --- a/lib/matplotlib/font_manager.py +++ b/lib/matplotlib/font_manager.py @@ -627,32 +627,33 @@ class FontProperties: - family: A list of font names in decreasing order of priority. The items may include a generic font family name, either - 'sans-serif' (default), 'serif', 'cursive', 'fantasy', or 'monospace'. + 'sans-serif', 'serif', 'cursive', 'fantasy', or 'monospace'. In that case, the actual font to be used will be looked up - from the associated rcParam. + from the associated rcParam. Default: :rc:`font.family` - - style: Either 'normal' (default), 'italic' or 'oblique'. + - style: Either 'normal', 'italic' or 'oblique'. + Default: :rc:`font.style` - - variant: Either 'normal' (default) or 'small-caps'. + - variant: Either 'normal' or 'small-caps'. + Default: :rc:`font.variant` - stretch: A numeric value in the range 0-1000 or one of 'ultra-condensed', 'extra-condensed', 'condensed', - 'semi-condensed', 'normal' (default), 'semi-expanded', 'expanded', - 'extra-expanded' or 'ultra-expanded'. + 'semi-condensed', 'normal', 'semi-expanded', 'expanded', + 'extra-expanded' or 'ultra-expanded'. Default: :rc:`font.stretch` - weight: A numeric value in the range 0-1000 or one of - 'ultralight', 'light', 'normal' (default), 'regular', 'book', 'medium', + 'ultralight', 'light', 'normal', 'regular', 'book', 'medium', 'roman', 'semibold', 'demibold', 'demi', 'bold', 'heavy', - 'extra bold', 'black'. + 'extra bold', 'black'. Default: :rc:`font.weight` - size: Either an relative value of 'xx-small', 'x-small', 'small', 'medium', 'large', 'x-large', 'xx-large' or an - absolute font size, e.g., 10 (default). + absolute font size, e.g., 10. Default: :rc:`font.size` - - math_fontfamily: The family of fonts used to render math text; overrides - :rc:`mathtext.fontset`. Supported values are the same as the ones - supported by :rc:`mathtext.fontset`: 'dejavusans', 'dejavuserif', 'cm', - 'stix', 'stixsans' and 'custom'. + - math_fontfamily: The family of fonts used to render math text. + Supported values are: 'dejavusans', 'dejavuserif', 'cm', + 'stix', 'stixsans' and 'custom'. Default: :rc:`mathtext.fontset` Alternatively, a font may be specified using the absolute path to a font file, by using the *fname* kwarg. However, in this case, it is typically @@ -807,7 +808,7 @@ def set_family(self, family): is CSS parlance), such as: 'serif', 'sans-serif', 'cursive', 'fantasy', or 'monospace', a real font name or a list of real font names. Real font names are not supported when - :rc:`text.usetex` is `True`. + :rc:`text.usetex` is `True`. Default: :rc:`font.family` """ if family is None: family = rcParams['font.family'] @@ -817,7 +818,11 @@ def set_family(self, family): def set_style(self, style): """ - Set the font style. Values are: 'normal', 'italic' or 'oblique'. + Set the font style. + + Parameters + ---------- + style : {'normal', 'italic', 'oblique'}, default: :rc:`font.style` """ if style is None: style = rcParams['font.style'] @@ -826,7 +831,11 @@ def set_style(self, style): def set_variant(self, variant): """ - Set the font variant. Values are: 'normal' or 'small-caps'. + Set the font variant. + + Parameters + ---------- + variant : {'normal', 'small-caps'}, default: :rc:`font.variant` """ if variant is None: variant = rcParams['font.variant'] @@ -835,10 +844,14 @@ def set_variant(self, variant): def set_weight(self, weight): """ - Set the font weight. May be either a numeric value in the - range 0-1000 or one of 'ultralight', 'light', 'normal', - 'regular', 'book', 'medium', 'roman', 'semibold', 'demibold', - 'demi', 'bold', 'heavy', 'extra bold', 'black' + Set the font weight. + + Parameters + ---------- + weight : int or {'ultralight', 'light', 'normal', 'regular', 'book', \ +'medium', 'roman', 'semibold', 'demibold', 'demi', 'bold', 'heavy', \ +'extra bold', 'black'}, default: :rc:`font.weight` + If int, must be in the range 0-1000. """ if weight is None: weight = rcParams['font.weight'] @@ -853,10 +866,14 @@ def set_weight(self, weight): def set_stretch(self, stretch): """ - Set the font stretch or width. Options are: 'ultra-condensed', - 'extra-condensed', 'condensed', 'semi-condensed', 'normal', - 'semi-expanded', 'expanded', 'extra-expanded' or - 'ultra-expanded', or a numeric value in the range 0-1000. + Set the font stretch or width. + + Parameters + ---------- + stretch : int or {'ultra-condensed', 'extra-condensed', 'condensed', \ +'semi-condensed', 'normal', 'semi-expanded', 'expanded', 'extra-expanded', \ +'ultra-expanded'}, default: :rc:`font.stretch` + If int, must be in the range 0-1000. """ if stretch is None: stretch = rcParams['font.stretch'] @@ -871,9 +888,14 @@ def set_stretch(self, stretch): def set_size(self, size): """ - Set the font size. Either an relative value of 'xx-small', - 'x-small', 'small', 'medium', 'large', 'x-large', 'xx-large' - or an absolute font size, e.g., 12. + Set the font size. + + Parameters + ---------- + size : float or {'xx-small', 'x-small', 'small', 'medium', \ +'large', 'x-large', 'xx-large'}, default: :rc:`font.size` + If float, the font size in points. The string values denote sizes + relative to the default font size. """ if size is None: size = rcParams['font.size'] @@ -1091,8 +1113,9 @@ def addfont(self, path): ---------- path : str or path-like """ - path = str(path) # Convert to string in case of a path as - # afmFontProperty and FT2Font expect this + # Convert to string in case of a path as + # afmFontProperty and FT2Font expect this + path = str(path) if Path(path).suffix.lower() == ".afm": with open(path, "rb") as fh: font = _afm.AFM(fh) From 337765628104959ca509e8451df3e5588e4565f0 Mon Sep 17 00:00:00 2001 From: Oscar Gustafsson Date: Thu, 3 Mar 2022 21:00:05 +0100 Subject: [PATCH 3/4] Add documention for fontManager. Closes #22586 --- lib/matplotlib/font_manager.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/lib/matplotlib/font_manager.py b/lib/matplotlib/font_manager.py index d8da217a0e36..c620f292af1f 100644 --- a/lib/matplotlib/font_manager.py +++ b/lib/matplotlib/font_manager.py @@ -1,7 +1,7 @@ """ A module for finding, managing, and using fonts across platforms. -This module provides a single `FontManager` instance that can +This module provides a single `FontManager` instance, `fontManager`, that can be shared across backends and platforms. The `findfont` function returns the best TrueType (TTF) font file in the local or system font path that matches the specified `FontProperties` @@ -11,6 +11,10 @@ The design is based on the `W3C Cascading Style Sheet, Level 1 (CSS1) font specification `_. Future versions may implement the Level 2 or 2.1 specifications. + +.. data:: fontManager + + The singleton instance of `FontManager`. """ # KNOWN ISSUES From 7f21bcab3265daa5b72fbc7f11fa81e327cd9c32 Mon Sep 17 00:00:00 2001 From: Oscar Gustafsson Date: Fri, 4 Mar 2022 20:07:57 +0100 Subject: [PATCH 4/4] Add validation for fontstretch --- doc/api/font_manager_api.rst | 4 ++++ lib/matplotlib/font_manager.py | 8 ++------ lib/matplotlib/rcsetup.py | 16 +++++++++++++++- lib/matplotlib/tests/test_font_manager.py | 4 ++-- lib/matplotlib/tests/test_rcparams.py | 21 +++++++++++++++++++++ 5 files changed, 44 insertions(+), 9 deletions(-) diff --git a/doc/api/font_manager_api.rst b/doc/api/font_manager_api.rst index 8b698bacf0fe..3e043112380b 100644 --- a/doc/api/font_manager_api.rst +++ b/doc/api/font_manager_api.rst @@ -7,5 +7,9 @@ :undoc-members: :show-inheritance: + .. data:: fontManager + + The global instance of `FontManager`. + .. autoclass:: FontEntry :no-undoc-members: diff --git a/lib/matplotlib/font_manager.py b/lib/matplotlib/font_manager.py index c620f292af1f..d582bc936902 100644 --- a/lib/matplotlib/font_manager.py +++ b/lib/matplotlib/font_manager.py @@ -1,7 +1,7 @@ """ A module for finding, managing, and using fonts across platforms. -This module provides a single `FontManager` instance, `fontManager`, that can +This module provides a single `FontManager` instance, ``fontManager``, that can be shared across backends and platforms. The `findfont` function returns the best TrueType (TTF) font file in the local or system font path that matches the specified `FontProperties` @@ -11,10 +11,6 @@ The design is based on the `W3C Cascading Style Sheet, Level 1 (CSS1) font specification `_. Future versions may implement the Level 2 or 2.1 specifications. - -.. data:: fontManager - - The singleton instance of `FontManager`. """ # KNOWN ISSUES @@ -1119,7 +1115,7 @@ def addfont(self, path): """ # Convert to string in case of a path as # afmFontProperty and FT2Font expect this - path = str(path) + path = os.fsdecode(path) if Path(path).suffix.lower() == ".afm": with open(path, "rb") as fh: font = _afm.AFM(fh) diff --git a/lib/matplotlib/rcsetup.py b/lib/matplotlib/rcsetup.py index 0eafec792b04..37015bc0d76a 100644 --- a/lib/matplotlib/rcsetup.py +++ b/lib/matplotlib/rcsetup.py @@ -387,6 +387,20 @@ def validate_fontweight(s): raise ValueError(f'{s} is not a valid font weight.') from e +def validate_fontstretch(s): + stretchvalues = [ + 'ultra-condensed', 'extra-condensed', 'condensed', 'semi-condensed', + 'normal', 'semi-expanded', 'expanded', 'extra-expanded', + 'ultra-expanded'] + # Note: Historically, stretchvalues have been case-sensitive in Matplotlib + if s in stretchvalues: + return s + try: + return int(s) + except (ValueError, TypeError) as e: + raise ValueError(f'{s} is not a valid font stretch.') from e + + def validate_font_properties(s): parse_fontconfig_pattern(s) return s @@ -900,7 +914,7 @@ def _convert_validator_spec(key, conv): "font.family": validate_stringlist, # used by text object "font.style": validate_string, "font.variant": validate_string, - "font.stretch": validate_string, + "font.stretch": validate_fontstretch, "font.weight": validate_fontweight, "font.size": validate_float, # Base font size in points "font.serif": validate_stringlist, diff --git a/lib/matplotlib/tests/test_font_manager.py b/lib/matplotlib/tests/test_font_manager.py index a20cbd85e197..254b9fdff38b 100644 --- a/lib/matplotlib/tests/test_font_manager.py +++ b/lib/matplotlib/tests/test_font_manager.py @@ -176,10 +176,10 @@ def test_user_fonts_linux(tmpdir, monkeypatch): _get_fontconfig_fonts.cache_clear() -def test_addfont(): +def test_addfont_as_path(): + """Smoke test that addfont() accepts pathlib.Path.""" font_test_file = 'mpltest.ttf' path = Path(__file__).parent / font_test_file - # Add font using Path, which should not produce an error. See #22582 fontManager.addfont(path) diff --git a/lib/matplotlib/tests/test_rcparams.py b/lib/matplotlib/tests/test_rcparams.py index 75b6f727f799..6f0edf3ae1f3 100644 --- a/lib/matplotlib/tests/test_rcparams.py +++ b/lib/matplotlib/tests/test_rcparams.py @@ -20,6 +20,7 @@ _validate_color_or_linecolor, validate_cycler, validate_float, + validate_fontstretch, validate_fontweight, validate_hatch, validate_hist_bins, @@ -469,6 +470,26 @@ def test_validate_fontweight(weight, parsed_weight): assert validate_fontweight(weight) == parsed_weight +@pytest.mark.parametrize('stretch, parsed_stretch', [ + ('expanded', 'expanded'), + ('EXPANDED', ValueError), # stretch is case-sensitive + (100, 100), + ('100', 100), + (np.array(100), 100), + # fractional fontweights are not defined. This should actually raise a + # ValueError, but historically did not. + (20.6, 20), + ('20.6', ValueError), + ([100], ValueError), +]) +def test_validate_fontstretch(stretch, parsed_stretch): + if parsed_stretch is ValueError: + with pytest.raises(ValueError): + validate_fontstretch(stretch) + else: + assert validate_fontstretch(stretch) == parsed_stretch + + def test_keymaps(): key_list = [k for k in mpl.rcParams if 'keymap' in k] for k in key_list: 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