2323import functools
2424import hashlib
2525import logging
26- import os
2726from pathlib import Path
2827import subprocess
2928from tempfile import TemporaryDirectory
@@ -63,7 +62,7 @@ class TexManager:
6362 Repeated calls to this constructor always return the same instance.
6463 """
6564
66- _texcache = os . path . join (mpl .get_cachedir (), 'tex.cache' )
65+ _cache_dir = Path (mpl .get_cachedir (), 'tex.cache' )
6766 _grey_arrayd = {}
6867
6968 _font_families = ('serif' , 'sans-serif' , 'cursive' , 'monospace' )
@@ -109,7 +108,7 @@ class TexManager:
109108
110109 @functools .lru_cache # Always return the same instance.
111110 def __new__ (cls ):
112- Path ( cls ._texcache ) .mkdir (parents = True , exist_ok = True )
111+ cls ._cache_dir .mkdir (parents = True , exist_ok = True )
113112 return object .__new__ (cls )
114113
115114 @classmethod
@@ -167,23 +166,30 @@ def _get_font_preamble_and_command(cls):
167166 return preamble , fontcmd
168167
169168 @classmethod
170- def get_basefile (cls , tex , fontsize , dpi = None ):
169+ def _get_base_path (cls , tex , fontsize , dpi = None ):
171170 """
172- Return a filename based on a hash of the string, fontsize, and dpi.
171+ Return a file path based on a hash of the string, fontsize, and dpi.
173172 """
174173 src = cls ._get_tex_source (tex , fontsize ) + str (dpi )
175174 filehash = hashlib .sha256 (
176175 src .encode ('utf-8' ),
177176 usedforsecurity = False
178177 ).hexdigest ()
179- filepath = Path ( cls ._texcache )
178+ filepath = cls ._cache_dir
180179
181180 num_letters , num_levels = 2 , 2
182181 for i in range (0 , num_letters * num_levels , num_letters ):
183- filepath = filepath / Path ( filehash [i :i + 2 ])
182+ filepath = filepath / filehash [i :i + 2 ]
184183
185184 filepath .mkdir (parents = True , exist_ok = True )
186- return os .path .join (filepath , filehash )
185+ return filepath / filehash
186+
187+ @classmethod
188+ def get_basefile (cls , tex , fontsize , dpi = None ): # Kept for backcompat.
189+ """
190+ Return a filename based on a hash of the string, fontsize, and dpi.
191+ """
192+ return str (cls ._get_base_path (tex , fontsize , dpi ))
187193
188194 @classmethod
189195 def get_font_preamble (cls ):
@@ -243,17 +249,16 @@ def make_tex(cls, tex, fontsize):
243249
244250 Return the file name.
245251 """
246- texfile = cls .get_basefile (tex , fontsize ) + ".tex"
247- Path (texfile ).write_text (cls ._get_tex_source (tex , fontsize ),
248- encoding = 'utf-8' )
249- return texfile
252+ texpath = cls ._get_base_path (tex , fontsize ).with_suffix (".tex" )
253+ texpath .write_text (cls ._get_tex_source (tex , fontsize ), encoding = 'utf-8' )
254+ return str (texpath )
250255
251256 @classmethod
252257 def _run_checked_subprocess (cls , command , tex , * , cwd = None ):
253258 _log .debug (cbook ._pformat_subprocess (command ))
254259 try :
255260 report = subprocess .check_output (
256- command , cwd = cwd if cwd is not None else cls ._texcache ,
261+ command , cwd = cwd if cwd is not None else cls ._cache_dir ,
257262 stderr = subprocess .STDOUT )
258263 except FileNotFoundError as exc :
259264 raise RuntimeError (
@@ -281,8 +286,8 @@ def make_dvi(cls, tex, fontsize):
281286
282287 Return the file name.
283288 """
284- dvifile = Path ( cls .get_basefile (tex , fontsize ) ).with_suffix (".dvi" )
285- if not dvifile .exists ():
289+ dvipath = cls ._get_base_path (tex , fontsize ).with_suffix (".dvi" )
290+ if not dvipath .exists ():
286291 # Generate the tex and dvi in a temporary directory to avoid race
287292 # conditions e.g. if multiple processes try to process the same tex
288293 # string at the same time. Having tmpdir be a subdirectory of the
@@ -292,17 +297,17 @@ def make_dvi(cls, tex, fontsize):
292297 # the absolute path may contain characters (e.g. ~) that TeX does
293298 # not support; n.b. relative paths cannot traverse parents, or it
294299 # will be blocked when `openin_any = p` in texmf.cnf).
295- with TemporaryDirectory (dir = dvifile .parent ) as tmpdir :
300+ with TemporaryDirectory (dir = dvipath .parent ) as tmpdir :
296301 Path (tmpdir , "file.tex" ).write_text (
297302 cls ._get_tex_source (tex , fontsize ), encoding = 'utf-8' )
298303 cls ._run_checked_subprocess (
299304 ["latex" , "-interaction=nonstopmode" , "--halt-on-error" ,
300305 "file.tex" ], tex , cwd = tmpdir )
301- Path (tmpdir , "file.dvi" ).replace (dvifile )
306+ Path (tmpdir , "file.dvi" ).replace (dvipath )
302307 # Also move the tex source to the main cache directory, but
303308 # only for backcompat.
304- Path (tmpdir , "file.tex" ).replace (dvifile .with_suffix (".tex" ))
305- return str (dvifile )
309+ Path (tmpdir , "file.tex" ).replace (dvipath .with_suffix (".tex" ))
310+ return str (dvipath )
306311
307312 @classmethod
308313 def make_png (cls , tex , fontsize , dpi ):
@@ -311,13 +316,12 @@ def make_png(cls, tex, fontsize, dpi):
311316
312317 Return the file name.
313318 """
314- pngfile = Path (cls .get_basefile (tex , fontsize )).with_suffix (".png" )
315- # see get_rgba for a discussion of the background
316- if not pngfile .exists ():
317- dvifile = cls .make_dvi (tex , fontsize )
318- with TemporaryDirectory (dir = pngfile .parent ) as tmpdir :
319+ pngpath = cls ._get_base_path (tex , fontsize , dpi ).with_suffix (".png" )
320+ if not pngpath .exists ():
321+ dvipath = cls .make_dvi (tex , fontsize )
322+ with TemporaryDirectory (dir = pngpath .parent ) as tmpdir :
319323 cmd = ["dvipng" , "-bg" , "Transparent" , "-D" , str (dpi ),
320- "-T" , "tight" , "-o" , "file.png" , dvifile ]
324+ "-T" , "tight" , "-o" , "file.png" , dvipath ]
321325 # When testing, disable FreeType rendering for reproducibility;
322326 # but dvipng 1.16 has a bug (fixed in f3ff241) that breaks
323327 # --freetype0 mode, so for it we keep FreeType enabled; the
@@ -326,8 +330,8 @@ def make_png(cls, tex, fontsize, dpi):
326330 mpl ._get_executable_info ("dvipng" ).raw_version != "1.16" ):
327331 cmd .insert (1 , "--freetype0" )
328332 cls ._run_checked_subprocess (cmd , tex , cwd = tmpdir )
329- Path (tmpdir , "file.png" ).replace (pngfile )
330- return str (pngfile )
333+ Path (tmpdir , "file.png" ).replace (pngpath )
334+ return str (pngpath )
331335
332336 @classmethod
333337 def get_grey (cls , tex , fontsize = None , dpi = None ):
@@ -338,7 +342,7 @@ def get_grey(cls, tex, fontsize=None, dpi=None):
338342 alpha = cls ._grey_arrayd .get (key )
339343 if alpha is None :
340344 pngfile = cls .make_png (tex , fontsize , dpi )
341- rgba = mpl .image .imread (os . path . join ( cls . _texcache , pngfile ) )
345+ rgba = mpl .image .imread (pngfile )
342346 cls ._grey_arrayd [key ] = alpha = rgba [:, :, - 1 ]
343347 return alpha
344348
@@ -364,9 +368,9 @@ def get_text_width_height_descent(cls, tex, fontsize, renderer=None):
364368 """Return width, height and descent of the text."""
365369 if tex .strip () == '' :
366370 return 0 , 0 , 0
367- dvifile = cls .make_dvi (tex , fontsize )
371+ dvipath = cls .make_dvi (tex , fontsize )
368372 dpi_fraction = renderer .points_to_pixels (1. ) if renderer else 1
369- with dviread .Dvi (dvifile , 72 * dpi_fraction ) as dvi :
373+ with dviread .Dvi (dvipath , 72 * dpi_fraction ) as dvi :
370374 page , = dvi
371375 # A total height (including the descent) needs to be returned.
372376 return page .width , page .height + page .descent , page .descent
0 commit comments