|
12 | 12 | from functools import lru_cache
|
13 | 13 | import re
|
14 | 14 | import numpy as np
|
15 |
| -from pyparsing import (Literal, ZeroOrMore, Optional, Regex, StringEnd, |
16 |
| - ParseException, Suppress) |
17 | 15 |
|
18 | 16 | family_punc = r'\\\-:,'
|
19 | 17 | family_unescape = re.compile(r'\\([%s])' % family_punc).sub
|
|
23 | 21 | value_unescape = re.compile(r'\\([%s])' % value_punc).sub
|
24 | 22 | value_escape = re.compile(r'([%s])' % value_punc).sub
|
25 | 23 |
|
| 24 | +_SIMPLE_PATTERN_CACHE = { |
| 25 | + 'cursive': {'family': ['cursive']}, |
| 26 | + 'sans': {'family': ['sans']}, |
| 27 | + 'monospace': {'family': ['monospace']}, |
| 28 | + 'sans:italic': {'family': ['sans'], 'slant': ['italic']}, |
| 29 | + 'sans:bold': {'family': ['sans'], 'weight': ['bold']}, |
| 30 | +} |
| 31 | + |
26 | 32 |
|
27 | 33 | class FontconfigPatternParser:
|
28 | 34 | """
|
@@ -60,6 +66,9 @@ class FontconfigPatternParser:
|
60 | 66 | }
|
61 | 67 |
|
62 | 68 | def __init__(self):
|
| 69 | + # delayed import. Only executed when needed |
| 70 | + from pyparsing import (Literal, ZeroOrMore, Optional, Regex, StringEnd, |
| 71 | + ParseException, Suppress) |
63 | 72 |
|
64 | 73 | family = Regex(
|
65 | 74 | r'([^%s]|(\\[%s]))*' % (family_punc, family_punc)
|
@@ -167,11 +176,33 @@ def _property(self, s, loc, tokens):
|
167 | 176 | return []
|
168 | 177 |
|
169 | 178 |
|
| 179 | +@lru_cache(maxsize=1) |
| 180 | +def _get_parser(): |
| 181 | + """Return a cached FontconfigPatternParser instance.""" |
| 182 | + return FontconfigPatternParser() |
| 183 | + |
| 184 | + |
170 | 185 | # `parse_fontconfig_pattern` is a bottleneck during the tests because it is
|
171 | 186 | # repeatedly called when the rcParams are reset (to validate the default
|
172 | 187 | # fonts). In practice, the cache size doesn't grow beyond a few dozen entries
|
173 | 188 | # during the test suite.
|
174 |
| -parse_fontconfig_pattern = lru_cache()(FontconfigPatternParser().parse) |
| 189 | +@lru_cache() |
| 190 | +def parse_fontconfig_pattern(pattern): |
| 191 | + """ |
| 192 | + Parse the given fontconfig *pattern* and return a dictionary |
| 193 | + of key/value pairs useful for initializing a |
| 194 | + :class:`font_manager.FontProperties` object. |
| 195 | + """ |
| 196 | + |
| 197 | + # Try a lookup on simple patterns first. This can prevent the need to |
| 198 | + # create a full parser and to import pyparsing. If only patterns from |
| 199 | + # _SIMPLE_PATTERN_CACHE are used in the matplotlibrc file, this will |
| 200 | + # speed up the import of matplotlib. |
| 201 | + parsed = _SIMPLE_PATTERN_CACHE.get(pattern) |
| 202 | + if parsed is not None: |
| 203 | + return parsed |
| 204 | + |
| 205 | + return _get_parser().parse(pattern) |
175 | 206 |
|
176 | 207 |
|
177 | 208 | def _escape_val(val, escape_func):
|
|
0 commit comments