Skip to content

Commit a77ef75

Browse files
committed
Remove font preamble caching in TexManager.
TexManager has a complex caching machinery (... among other caching layers) to map font-related rcParams to a tex preamble (see `_rc_cache`, `_rc_cache_keys`, `_reinit`) but that's just a matter of a few dict lookups which are negligible compared to invoking the subprocess; so just strip out that caching and always regenerate the font-related preamble. That caching also set some attributes (`texmanager.serif`, etc.) as a side-effect via `setattr`/`getattr`, which are used nowhere else (and it's hard to know they even exist other than figuring out the relevant `setattr` calls); just deprecate them.
1 parent 769dddd commit a77ef75

File tree

2 files changed

+44
-41
lines changed

2 files changed

+44
-41
lines changed
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
Deprecations
2+
````````````
3+
4+
The ``TexManager.serif``, ``TexManager.sans_serif``, ``TexManager.cursive`` and
5+
``TexManager.monospace`` attributes are deprecated.

lib/matplotlib/texmanager.py

Lines changed: 39 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -89,25 +89,40 @@ class TexManager(object):
8989
'monospace': ('cmtt', ''),
9090
'computer modern roman': ('cmr', ''),
9191
'computer modern sans serif': ('cmss', ''),
92-
'computer modern typewriter': ('cmtt', '')}
93-
94-
_rc_cache = None
95-
_rc_cache_keys = (
96-
('text.latex.preamble', 'text.latex.unicode', 'text.latex.preview',
97-
'font.family') + tuple('font.' + n for n in font_families))
92+
'computer modern typewriter': ('cmtt', ''),
93+
}
9894

9995
@functools.lru_cache() # Always return the same instance.
10096
def __new__(cls):
101-
self = object.__new__(cls)
102-
self._reinit()
103-
return self
104-
105-
def _reinit(self):
106-
if self.texcache is None:
97+
if cls.texcache is None:
10798
raise RuntimeError('Cannot create TexManager, as there is no '
10899
'cache directory available')
100+
Path(cls.texcache).mkdir(parents=True, exist_ok=True)
101+
return object.__new__(cls)
102+
103+
_fonts = {} # Only for deprecation period.
104+
105+
@cbook.deprecated("3.2")
106+
@property
107+
def serif(self):
108+
return self._fonts["serif"]
109+
110+
@cbook.deprecated("3.2")
111+
@property
112+
def sans_serif(self):
113+
return self._fonts["sans-serif"]
114+
115+
@cbook.deprecated("3.2")
116+
@property
117+
def cursive(self):
118+
return self._fonts["cursive"]
109119

110-
Path(self.texcache).mkdir(parents=True, exist_ok=True)
120+
@cbook.deprecated("3.2")
121+
@property
122+
def monospace(self):
123+
return self._fonts["monospace"]
124+
125+
def get_font_config(self):
111126
ff = rcParams['font.family']
112127
if len(ff) == 1 and ff[0].lower() in self.font_families:
113128
self.font_family = ff[0].lower()
@@ -121,11 +136,9 @@ def _reinit(self):
121136

122137
fontconfig = [self.font_family]
123138
for font_family in self.font_families:
124-
font_family_attr = font_family.replace('-', '_')
125139
for font in rcParams['font.' + font_family]:
126140
if font.lower() in self.font_info:
127-
setattr(self, font_family_attr,
128-
self.font_info[font.lower()])
141+
self._fonts[font_family] = self.font_info[font.lower()]
129142
_log.debug('family: %s, font: %s, info: %s',
130143
font_family, font, self.font_info[font.lower()])
131144
break
@@ -135,22 +148,25 @@ def _reinit(self):
135148
else:
136149
_log.info('No LaTeX-compatible font found for the %s font '
137150
'family in rcParams. Using default.', font_family)
138-
setattr(self, font_family_attr, self.font_info[font_family])
139-
fontconfig.append(getattr(self, font_family_attr)[0])
140-
# Add a hash of the latex preamble to self._fontconfig so that the
151+
self._fonts[font_family] = self.font_info[font_family]
152+
fontconfig.append(self._fonts[font_family][0])
153+
# Add a hash of the latex preamble to fontconfig so that the
141154
# correct png is selected for strings rendered with same font and dpi
142155
# even if the latex preamble changes within the session
143156
preamble_bytes = self.get_custom_preamble().encode('utf-8')
144157
fontconfig.append(hashlib.md5(preamble_bytes).hexdigest())
145-
self._fontconfig = ''.join(fontconfig)
146158

147159
# The following packages and commands need to be included in the latex
148160
# file's preamble:
149-
cmd = [self.serif[1], self.sans_serif[1], self.monospace[1]]
161+
cmd = [self._fonts['serif'][1],
162+
self._fonts['sans-serif'][1],
163+
self._fonts['monospace'][1]]
150164
if self.font_family == 'cursive':
151-
cmd.append(self.cursive[1])
165+
cmd.append(self._fonts['cursive'][1])
152166
self._font_preamble = '\n'.join(
153-
[r'\usepackage{type1cm}'] + cmd + [r'\usepackage{textcomp}'])
167+
[r'\usepackage{type1cm}', *cmd, r'\usepackage{textcomp}'])
168+
169+
return ''.join(fontconfig)
154170

155171
def get_basefile(self, tex, fontsize, dpi=None):
156172
"""
@@ -161,24 +177,6 @@ def get_basefile(self, tex, fontsize, dpi=None):
161177
return os.path.join(
162178
self.texcache, hashlib.md5(s.encode('utf-8')).hexdigest())
163179

164-
def get_font_config(self):
165-
"""Reinitializes self if relevant rcParams on have changed."""
166-
if self._rc_cache is None:
167-
self._rc_cache = dict.fromkeys(self._rc_cache_keys)
168-
changed = [par for par in self._rc_cache_keys
169-
if rcParams[par] != self._rc_cache[par]]
170-
if changed:
171-
_log.debug('following keys changed: %s', changed)
172-
for k in changed:
173-
_log.debug('%-20s: %-10s -> %-10s',
174-
k, self._rc_cache[k], rcParams[k])
175-
# deepcopy may not be necessary, but feels more future-proof
176-
self._rc_cache[k] = copy.deepcopy(rcParams[k])
177-
_log.debug('RE-INIT\nold fontconfig: %s', self._fontconfig)
178-
self._reinit()
179-
_log.debug('fontconfig: %s', self._fontconfig)
180-
return self._fontconfig
181-
182180
def get_font_preamble(self):
183181
"""
184182
Return a string containing font configuration for the tex preamble.

0 commit comments

Comments
 (0)