From 627ae26e47372ce6138a51705fd7606ccf07f2ed Mon Sep 17 00:00:00 2001 From: Antony Lee Date: Sat, 29 Oct 2022 14:19:36 +0200 Subject: [PATCH] Simplify generate_fontconfig_pattern. - Switch _family_escape, _value_escape to be more similar to _family_escape, _value_escape. - generate_fontconfig_pattern doesn't need to go through the generic escape_val, but instead rely on the fact that prop.get_family() always returns a list whereas the other getters always return a scalar value, and directly do the escaping and joining as needed. --- lib/matplotlib/_fontconfig_pattern.py | 50 +++++++-------------------- 1 file changed, 13 insertions(+), 37 deletions(-) diff --git a/lib/matplotlib/_fontconfig_pattern.py b/lib/matplotlib/_fontconfig_pattern.py index caf0a085b29c..304261475fb0 100644 --- a/lib/matplotlib/_fontconfig_pattern.py +++ b/lib/matplotlib/_fontconfig_pattern.py @@ -12,7 +12,6 @@ from functools import lru_cache, partial import re -import numpy as np from pyparsing import ( Optional, ParseException, Regex, StringEnd, Suppress, ZeroOrMore) @@ -21,16 +20,17 @@ family_punc = r'\\\-:,' _family_unescape = partial(re.compile(r'\\(?=[%s])' % family_punc).sub, '') -family_escape = re.compile(r'([%s])' % family_punc).sub - +_family_escape = partial(re.compile(r'(?=[%s])' % family_punc).sub, r'\\') value_punc = r'\\=_:,' _value_unescape = partial(re.compile(r'\\(?=[%s])' % value_punc).sub, '') -value_escape = re.compile(r'([%s])' % value_punc).sub +_value_escape = partial(re.compile(r'(?=[%s])' % value_punc).sub, r'\\') # Remove after module deprecation elapses (3.8); then remove underscores -# from _family_unescape and _value_unescape. +# from _{family,value}_{un,}escape. family_unescape = re.compile(r'\\([%s])' % family_punc).sub value_unescape = re.compile(r'\\([%s])' % value_punc).sub +family_escape = re.compile(r'([%s])' % family_punc).sub +value_escape = re.compile(r'([%s])' % value_punc).sub class FontconfigPatternParser: @@ -127,36 +127,12 @@ def parse(self, pattern): parse_fontconfig_pattern = lru_cache()(FontconfigPatternParser().parse) -def _escape_val(val, escape_func): - """ - Given a string value or a list of string values, run each value through - the input escape function to make the values into legal font config - strings. The result is returned as a string. - """ - if not np.iterable(val) or isinstance(val, str): - val = [val] - - return ','.join(escape_func(r'\\\1', str(x)) for x in val - if x is not None) - - def generate_fontconfig_pattern(d): - """ - Given a dictionary of key/value pairs, generates a fontconfig - pattern string. - """ - props = [] - - # Family is added first w/o a keyword - family = d.get_family() - if family is not None and family != []: - props.append(_escape_val(family, family_escape)) - - # The other keys are added as key=value - for key in ['style', 'variant', 'weight', 'stretch', 'file', 'size']: - val = getattr(d, 'get_' + key)() - # Don't use 'if not val' because 0 is a valid input. - if val is not None and val != []: - props.append(":%s=%s" % (key, _escape_val(val, value_escape))) - - return ''.join(props) + """Convert a `.FontProperties` to a fontconfig pattern string.""" + kvs = [(k, getattr(d, f"get_{k}")()) + for k in ["style", "variant", "weight", "stretch", "file", "size"]] + # Families is given first without a leading keyword. Other entries (which + # are necessarily scalar) are given as key=value, skipping Nones. + return (",".join(_family_escape(f) for f in d.get_family()) + + "".join(f":{k}={_value_escape(str(v))}" + for k, v in kvs if v is not None))