Skip to content

Commit be68dfe

Browse files
authored
Merge pull request matplotlib#30426 from anntzer/mdr
Fix a race condition in TexManager.make_dvi.
2 parents 77a16b9 + cae6696 commit be68dfe

File tree

1 file changed

+27
-26
lines changed

1 file changed

+27
-26
lines changed

lib/matplotlib/texmanager.py

Lines changed: 27 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -279,11 +279,9 @@ def make_dvi(cls, tex, fontsize):
279279
280280
Return the file name.
281281
"""
282-
basefile = cls.get_basefile(tex, fontsize)
283-
dvifile = '%s.dvi' % basefile
284-
if not os.path.exists(dvifile):
285-
texfile = Path(cls.make_tex(tex, fontsize))
286-
# Generate the dvi in a temporary directory to avoid race
282+
dvifile = Path(cls.get_basefile(tex, fontsize)).with_suffix(".dvi")
283+
if not dvifile.exists():
284+
# Generate the tex and dvi in a temporary directory to avoid race
287285
# conditions e.g. if multiple processes try to process the same tex
288286
# string at the same time. Having tmpdir be a subdirectory of the
289287
# final output dir ensures that they are on the same filesystem,
@@ -292,15 +290,17 @@ def make_dvi(cls, tex, fontsize):
292290
# the absolute path may contain characters (e.g. ~) that TeX does
293291
# not support; n.b. relative paths cannot traverse parents, or it
294292
# will be blocked when `openin_any = p` in texmf.cnf).
295-
cwd = Path(dvifile).parent
296-
with TemporaryDirectory(dir=cwd) as tmpdir:
297-
tmppath = Path(tmpdir)
293+
with TemporaryDirectory(dir=dvifile.parent) as tmpdir:
294+
Path(tmpdir, "file.tex").write_text(
295+
cls._get_tex_source(tex, fontsize), encoding='utf-8')
298296
cls._run_checked_subprocess(
299297
["latex", "-interaction=nonstopmode", "--halt-on-error",
300-
f"--output-directory={tmppath.name}",
301-
f"{texfile.name}"], tex, cwd=cwd)
302-
(tmppath / Path(dvifile).name).replace(dvifile)
303-
return dvifile
298+
"file.tex"], tex, cwd=tmpdir)
299+
Path(tmpdir, "file.dvi").replace(dvifile)
300+
# Also move the tex source to the main cache directory, but
301+
# only for backcompat.
302+
Path(tmpdir, "file.tex").replace(dvifile.with_suffix(".tex"))
303+
return str(dvifile)
304304

305305
@classmethod
306306
def make_png(cls, tex, fontsize, dpi):
@@ -309,22 +309,23 @@ def make_png(cls, tex, fontsize, dpi):
309309
310310
Return the file name.
311311
"""
312-
basefile = cls.get_basefile(tex, fontsize, dpi)
313-
pngfile = '%s.png' % basefile
312+
pngfile = Path(cls.get_basefile(tex, fontsize)).with_suffix(".png")
314313
# see get_rgba for a discussion of the background
315-
if not os.path.exists(pngfile):
314+
if not pngfile.exists():
316315
dvifile = cls.make_dvi(tex, fontsize)
317-
cmd = ["dvipng", "-bg", "Transparent", "-D", str(dpi),
318-
"-T", "tight", "-o", pngfile, dvifile]
319-
# When testing, disable FreeType rendering for reproducibility; but
320-
# dvipng 1.16 has a bug (fixed in f3ff241) that breaks --freetype0
321-
# mode, so for it we keep FreeType enabled; the image will be
322-
# slightly off.
323-
if (getattr(mpl, "_called_from_pytest", False) and
324-
mpl._get_executable_info("dvipng").raw_version != "1.16"):
325-
cmd.insert(1, "--freetype0")
326-
cls._run_checked_subprocess(cmd, tex)
327-
return pngfile
316+
with TemporaryDirectory(dir=pngfile.parent) as tmpdir:
317+
cmd = ["dvipng", "-bg", "Transparent", "-D", str(dpi),
318+
"-T", "tight", "-o", "file.png", dvifile]
319+
# When testing, disable FreeType rendering for reproducibility;
320+
# but dvipng 1.16 has a bug (fixed in f3ff241) that breaks
321+
# --freetype0 mode, so for it we keep FreeType enabled; the
322+
# image will be slightly off.
323+
if (getattr(mpl, "_called_from_pytest", False) and
324+
mpl._get_executable_info("dvipng").raw_version != "1.16"):
325+
cmd.insert(1, "--freetype0")
326+
cls._run_checked_subprocess(cmd, tex, cwd=tmpdir)
327+
Path(tmpdir, "file.png").replace(pngfile)
328+
return str(pngfile)
328329

329330
@classmethod
330331
def get_grey(cls, tex, fontsize=None, dpi=None):

0 commit comments

Comments
 (0)