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 ):
@@ -241,17 +247,16 @@ def make_tex(cls, tex, fontsize):
241247
242248 Return the file name.
243249 """
244- texfile = cls .get_basefile (tex , fontsize ) + ".tex"
245- Path (texfile ).write_text (cls ._get_tex_source (tex , fontsize ),
246- encoding = 'utf-8' )
247- return texfile
250+ texpath = cls ._get_base_path (tex , fontsize ).with_suffix (".tex" )
251+ texpath .write_text (cls ._get_tex_source (tex , fontsize ), encoding = 'utf-8' )
252+ return str (texpath )
248253
249254 @classmethod
250255 def _run_checked_subprocess (cls , command , tex , * , cwd = None ):
251256 _log .debug (cbook ._pformat_subprocess (command ))
252257 try :
253258 report = subprocess .check_output (
254- command , cwd = cwd if cwd is not None else cls ._texcache ,
259+ command , cwd = cwd if cwd is not None else cls ._cache_dir ,
255260 stderr = subprocess .STDOUT )
256261 except FileNotFoundError as exc :
257262 raise RuntimeError (
@@ -279,8 +284,8 @@ def make_dvi(cls, tex, fontsize):
279284
280285 Return the file name.
281286 """
282- dvifile = Path ( cls .get_basefile (tex , fontsize ) ).with_suffix (".dvi" )
283- if not dvifile .exists ():
287+ dvipath = cls ._get_base_path (tex , fontsize ).with_suffix (".dvi" )
288+ if not dvipath .exists ():
284289 # Generate the tex and dvi in a temporary directory to avoid race
285290 # conditions e.g. if multiple processes try to process the same tex
286291 # string at the same time. Having tmpdir be a subdirectory of the
@@ -290,17 +295,17 @@ def make_dvi(cls, tex, fontsize):
290295 # the absolute path may contain characters (e.g. ~) that TeX does
291296 # not support; n.b. relative paths cannot traverse parents, or it
292297 # will be blocked when `openin_any = p` in texmf.cnf).
293- with TemporaryDirectory (dir = dvifile .parent ) as tmpdir :
298+ with TemporaryDirectory (dir = dvipath .parent ) as tmpdir :
294299 Path (tmpdir , "file.tex" ).write_text (
295300 cls ._get_tex_source (tex , fontsize ), encoding = 'utf-8' )
296301 cls ._run_checked_subprocess (
297302 ["latex" , "-interaction=nonstopmode" , "--halt-on-error" ,
298303 "file.tex" ], tex , cwd = tmpdir )
299- Path (tmpdir , "file.dvi" ).replace (dvifile )
304+ Path (tmpdir , "file.dvi" ).replace (dvipath )
300305 # Also move the tex source to the main cache directory, but
301306 # only for backcompat.
302- Path (tmpdir , "file.tex" ).replace (dvifile .with_suffix (".tex" ))
303- return str (dvifile )
307+ Path (tmpdir , "file.tex" ).replace (dvipath .with_suffix (".tex" ))
308+ return str (dvipath )
304309
305310 @classmethod
306311 def make_png (cls , tex , fontsize , dpi ):
@@ -309,13 +314,12 @@ def make_png(cls, tex, fontsize, dpi):
309314
310315 Return the file name.
311316 """
312- pngfile = Path (cls .get_basefile (tex , fontsize )).with_suffix (".png" )
313- # see get_rgba for a discussion of the background
314- if not pngfile .exists ():
315- dvifile = cls .make_dvi (tex , fontsize )
316- with TemporaryDirectory (dir = pngfile .parent ) as tmpdir :
317+ pngpath = cls ._get_base_path (tex , fontsize , dpi ).with_suffix (".png" )
318+ if not pngpath .exists ():
319+ dvipath = cls .make_dvi (tex , fontsize )
320+ with TemporaryDirectory (dir = pngpath .parent ) as tmpdir :
317321 cmd = ["dvipng" , "-bg" , "Transparent" , "-D" , str (dpi ),
318- "-T" , "tight" , "-o" , "file.png" , dvifile ]
322+ "-T" , "tight" , "-o" , "file.png" , dvipath ]
319323 # When testing, disable FreeType rendering for reproducibility;
320324 # but dvipng 1.16 has a bug (fixed in f3ff241) that breaks
321325 # --freetype0 mode, so for it we keep FreeType enabled; the
@@ -324,8 +328,8 @@ def make_png(cls, tex, fontsize, dpi):
324328 mpl ._get_executable_info ("dvipng" ).raw_version != "1.16" ):
325329 cmd .insert (1 , "--freetype0" )
326330 cls ._run_checked_subprocess (cmd , tex , cwd = tmpdir )
327- Path (tmpdir , "file.png" ).replace (pngfile )
328- return str (pngfile )
331+ Path (tmpdir , "file.png" ).replace (pngpath )
332+ return str (pngpath )
329333
330334 @classmethod
331335 def get_grey (cls , tex , fontsize = None , dpi = None ):
@@ -336,7 +340,7 @@ def get_grey(cls, tex, fontsize=None, dpi=None):
336340 alpha = cls ._grey_arrayd .get (key )
337341 if alpha is None :
338342 pngfile = cls .make_png (tex , fontsize , dpi )
339- rgba = mpl .image .imread (os . path . join ( cls . _texcache , pngfile ) )
343+ rgba = mpl .image .imread (pngfile )
340344 cls ._grey_arrayd [key ] = alpha = rgba [:, :, - 1 ]
341345 return alpha
342346
@@ -362,9 +366,9 @@ def get_text_width_height_descent(cls, tex, fontsize, renderer=None):
362366 """Return width, height and descent of the text."""
363367 if tex .strip () == '' :
364368 return 0 , 0 , 0
365- dvifile = cls .make_dvi (tex , fontsize )
369+ dvipath = cls .make_dvi (tex , fontsize )
366370 dpi_fraction = renderer .points_to_pixels (1. ) if renderer else 1
367- with dviread .Dvi (dvifile , 72 * dpi_fraction ) as dvi :
371+ with dviread .Dvi (dvipath , 72 * dpi_fraction ) as dvi :
368372 page , = dvi
369373 # A total height (including the descent) needs to be returned.
370374 return page .width , page .height + page .descent , page .descent
0 commit comments