8000 backend_pgf: improve handling of temporary directories · matplotlib/matplotlib@6957dbd · GitHub
[go: up one dir, main page]

Skip to content

Commit 6957dbd

Browse files
author
pwuertz
committed
backend_pgf: improve handling of temporary directories
1 parent cd84c99 commit 6957dbd

File tree

1 file changed

+50
-31
lines changed

1 file changed

+50
-31
lines changed

lib/matplotlib/backends/backend_pgf.py

Lines changed: 50 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@
88
import tempfile
99
import codecs
1010
import subprocess
11+
import atexit
12+
import weakref
1113

1214
import matplotlib as mpl
1315
from matplotlib.backend_bases import RendererBase, GraphicsContextBase,\
@@ -228,6 +230,7 @@ class LatexManager:
228230
determining the metrics of text elements. The LaTeX environment can be
229231
modified by setting fonts and/or a custem preamble in the rc parameters.
230232
"""
233+
_unclean_instances = weakref.WeakSet()
231234

232235
@staticmethod
233236
def _build_latex_header():
@@ -244,6 +247,12 @@ def _build_latex_header():
244247
r"\typeout{pgf_backend_query_start}"]
245248
return "\n".join(latex_header)
246249

250+
@staticmethod
251+
def _cleanup_remaining_instances():
252+
unclean_instances = list(LatexManager._unclean_instances)
253+
for latex_manager in unclean_instances:
254+
latex_manager._cleanup()
255+
247256
def _stdin_writeln(self, s):
248257
self.latex_stdin_utf8.write(s)
249258
self.latex_stdin_utf8.write("\n")
@@ -265,23 +274,26 @@ def _expect_prompt(self):
265274
return self._expect("\n*")
266275

267276
def __init__(self):
277+
# create a tmp directory for running latex, remember to cleanup
278+
self.tmpdir = tempfile.mkdtemp(prefix="mpl_pgf_lm_")
279+
LatexManager._unclean_instances.add(self)
280+
281+
# test the LaTeX setup to ensure a clean startup of the subprocess
268282
self.texcommand = get_texcommand()
269283
self.latex_header = LatexManager._build_latex_header()
270284
latex_end = "\n\\makeatletter\n\\@@end\n"
271-
272-
# test the LaTeX setup to ensure a clean startup of the subprocess
273285
latex = subprocess.Popen([self.texcommand, "-halt-on-error"],
274-
stdin=subprocess.PIPE,
275-
stdout=subprocess.PIPE)
286+
stdin=subprocess.PIPE, stdout=subprocess.PIPE,
287+
cwd=self.tmpdir)
276288
test_input = self.latex_header + latex_end
277289
stdout, stderr = latex.communicate(test_input.encode("utf-8"))
278290
if latex.returncode != 0:
279291
raise LatexError("LaTeX returned an error, probably missing font or error in preamble:\n%s" % stdout)
280292

281293
# open LaTeX process for real work
282294
latex = subprocess.Popen([self.texcommand, "-halt-on-error"],
283-
stdin=subprocess.PIPE,
284-
stdout=subprocess.PIPE)
295+
stdin=subprocess.PIPE, stdout=subprocess.PIPE,
296+
cwd=self.tmpdir)
285297
self.latex = latex
286298
self.latex_stdin_utf8 = codecs.getwriter("utf8")(self.latex.stdin)
287299
# write header with 'pgf_backend_query_start' token
@@ -293,19 +305,25 @@ def __init__(self):
293305
# cache for strings already processed
294306
self.str_cache = {}
295307

296-
def __del__(self):
297-
if rcParams.get("pgf.debug", False):
298-
print "deleting LatexManager"
308+
def _cleanup(self):
309+
if not os.path.isdir(self.tmpdir):
310+
return
299311
try:
300312
self.latex_stdin_utf8.close()
301313
self.latex.communicate()
314+
self.latex.wait()
302315
except:
303316
pass
304317
try:
305-
os.remove("texput.log")
306-
os.remove("texput.aux")
318+
shutil.rmtree(self.tmpdir)
319+
LatexManager._unclean_instances.discard(self)
307320
except:
308-
pass
321+
sys.stderr.write("error deleting tmp directory %s\n" % self.tmpdir)
322+
323+
def __del__(self):
324+
if rcParams.get("pgf.debug", False):
325+
print "deleting LatexManager"
326+
self._cleanup()
309327

310328
def get_width_height_descent(self, text, prop):
311329
"""
@@ -723,13 +741,14 @@ def _print_pdf_to_fh(self, fh):
723741
w, h = self.figure.get_figwidth(), self.figure.get_figheight()
724742

725743
try:
726-
# create and switch to temporary directory
727-
tmpdir = tempfile.mkdtemp()
728-
cwd = os.getcwd()
729-
os.chdir(tmpdir)
744+
# create temporary directory for compiling the figure
745+
tmpdir = tempfile.mkdtemp(prefix="mpl_pgf_")
746+
fname_pgf = os.path.join(tmpdir, "figure.pgf")
747+
fname_tex = os.path.join(tmpdir, "figure.tex")
748+
fname_pdf = os.path.join(tmpdir, "figure.pdf")
730749

731750
# print figure to pgf and compile it with latex
732-
self.print_pgf("figure.pgf")
751+
self.print_pgf(fname_pgf)
733752

734753
latex_preamble = get_preamble()
735754
latex_fontspec = get_fontspec()
@@ -744,26 +763,25 @@ def _print_pdf_to_fh(self, fh):
744763
\centering
745764
\input{figure.pgf}
746765
\end{document}""" % (w, h, latex_preamble, latex_fontspec)
747-
with codecs.open("figure.tex", "w", "utf-8") as fh_tex:
766+
with codecs.open(fname_tex, "w", "utf-8") as fh_tex:
748767
fh_tex.write(latexcode)
749768

750769
texcommand = get_texcommand()
751770
cmdargs = [texcommand, "-interaction=nonstopmode",
752771
"-halt-on-error", "figure.tex"]
753772
try:
754-
check_output(cmdargs, stderr=subprocess.STDOUT)
773+
check_output(cmdargs, stderr=subprocess.STDOUT, cwd=tmpdir)
755774
except subprocess.CalledProcessError as e:
756775
raise RuntimeError("%s was not able to process your file.\n\nFull log:\n%s" % (texcommand, e.output))
757776

758777
# copy file contents to target
759-
with open("figure.pdf", "rb") as fh_src:
778+
with open(fname_pdf, "rb") as fh_src:
760779
shutil.copyfileobj(fh_src, fh)
761780
finally:
762-
os.chdir(cwd)
763781
try:
764782
shutil.rmtree(tmpdir)
765783
except:
766-
sys.stderr.write("could not delete tmp directory %s\n" % tmpdir)
784+
sys.stderr.write("error deleting tmp directory %s\n" % tmpdir)
767785

768786
def print_pdf(self, fname_or_fh, *args, **kwargs):
769787
"""
@@ -782,22 +800,21 @@ def _print_png_to_fh(self, fh):
782800
converter = make_pdf_to_png_converter()
783801

784802
try:
785-
# create and switch to temporary directory
786-
tmpdir = tempfile.mkdtemp()
787-
cwd = os.getcwd()
788-
os.chdir(tmpdir)
803+
# create temporary directory for pdf creation and png conversion
804+
tmpdir = tempfile.mkdtemp(prefix="mpl_pgf_")
805+
fname_pdf = os.path.join(tmpdir, "figure.pdf")
806+
fname_png = os.path.join(tmpdir, "figure.png")
789807
# create pdf and try to convert it to png
790-
self.print_pdf("figure.pdf")
791-
converter("figure.pdf", "figure.png", dpi=self.figure.dpi)
808+
self.print_pdf(fname_pdf)
809+
converter(fname_pdf, fname_png, dpi=self.figure.dpi)
792810
# copy file contents to target
793-
with open("figure.png", "rb") as fh_src:
811+
with open(fname_png, "rb") as fh_src:
794812
shutil.copyfileobj(fh_src, fh)
795813
finally:
796-
os.chdir(cwd)
797814
try:
798815
shutil.rmtree(tmpdir)
799816
except:
800-
sys.stderr.write("could not delete tmp directory %s\n" % tmpdir)
817+
sys.stderr.write("error deleting tmp directory %s\n" % tmpdir)
801818

802819
def print_png(self, fname_or_fh, *args, **kwargs):
803820
"""
@@ -869,3 +886,5 @@ def __init__(self, *args):
869886
########################################################################
870887

871888
FigureManager = FigureManagerPgf
889+
890+
atexit.register(LatexManager._cleanup_remaining_instances)

0 commit comments

Comments
 (0)
0