8
8
import tempfile
9
9
import codecs
10
10
import subprocess
11
+ import atexit
12
+ import weakref
11
13
12
14
import matplotlib as mpl
13
15
from matplotlib .backend_bases import RendererBase , GraphicsContextBase ,\
@@ -228,6 +230,7 @@ class LatexManager:
228
230
determining the metrics of text elements. The LaTeX environment can be
229
231
modified by setting fonts and/or a custem preamble in the rc parameters.
230
232
"""
233
+ _unclean_instances = weakref .WeakSet ()
231
234
232
235
@staticmethod
233
236
def _build_latex_header ():
@@ -244,6 +247,12 @@ def _build_latex_header():
244
247
r"\typeout{pgf_backend_query_start}" ]
245
248
return "\n " .join (latex_header )
246
249
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
+
247
256
def _stdin_writeln (self , s ):
248
257
self .latex_stdin_utf8 .write (s )
249
258
self .latex_stdin_utf8 .write ("\n " )
@@ -265,23 +274,26 @@ def _expect_prompt(self):
265
274
return self ._expect ("\n *" )
266
275
267
276
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
268
282
self .texcommand = get_texcommand ()
269
283
self .latex_header = LatexManager ._build_latex_header ()
270
284
latex_end = "\n \\ makeatletter\n \\ @@end\n "
271
-
272
- # test the LaTeX setup to ensure a clean startup of the subprocess
273
285
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 )
276
288
test_input = self .latex_header + latex_end
277
289
stdout , stderr = latex .communicate (test_input .encode ("utf-8" ))
278
290
if latex .returncode != 0 :
279
291
raise LatexError ("LaTeX returned an error, probably missing font or error in preamble:\n %s" % stdout )
280
292
281
293
# open LaTeX process for real work
282
294
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 )
285
297
self .latex = latex
286
298
self .latex_stdin_utf8 = codecs .getwriter ("utf8" )(self .latex .stdin )
287
299
# write header with 'pgf_backend_query_start' token
@@ -293,19 +305,25 @@ def __init__(self):
293
305
# cache for strings already processed
294
306
self .str_cache = {}
295
307
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
299
311
try :
300
312
self .latex_stdin_utf8 .close ()
301
313
self .latex .communicate ()
314
+ self .latex .wait ()
302
315
except :
303
316
pass
304
317
try :
305
- os . remove ( "texput.log" )
306
- os . remove ( "texput.aux" )
318
+ shutil . rmtree ( self . tmpdir )
319
+ LatexManager . _unclean_instances . discard ( self )
307
320
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 ()
309
327
310
328
def get_width_height_descent (self , text , prop ):
311
329
"""
@@ -723,13 +741,14 @@ def _print_pdf_to_fh(self, fh):
723
741
w , h = self .figure .get_figwidth (), self .figure .get_figheight ()
724
742
725
743
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" )
730
749
731
750
# print figure to pgf and compile it with latex
732
- self .print_pgf ("figure.pgf" )
751
+ self .print_pgf (fname_pgf )
733
752
734
753
latex_preamble = get_preamble ()
735
754
latex_fontspec = get_fontspec ()
@@ -744,26 +763,25 @@ def _print_pdf_to_fh(self, fh):
744
763
\centering
745
764
\input{figure.pgf}
746
765
\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 :
748
767
fh_tex .write (latexcode )
749
768
750
769
texcommand = get_texcommand ()
751
770
cmdargs = [texcommand , "-interaction=nonstopmode" ,
752
771
"-halt-on-error" , "figure.tex" ]
753
772
try :
754
- check_output (cmdargs , stderr = subprocess .STDOUT )
773
+ check_output (cmdargs , stderr = subprocess .STDOUT , cwd = tmpdir )
755
774
except subprocess .CalledProcessError as e :
756
775
raise RuntimeError ("%s was not able to process your file.\n \n Full log:\n %s" % (texcommand , e .output ))
757
776
758
777
# copy file contents to target
759
- with open ("figure.pdf" , "rb" ) as fh_src :
778
+ with open (fname_pdf , "rb" ) as fh_src :
760
779
shutil .copyfileobj (fh_src , fh )
761
780
finally :
762
- os .chdir (cwd )
763
781
try :
764
782
shutil .rmtree (tmpdir )
765
783
except :
766
- sys .stderr .write ("could not delete tmp directory %s\n " % tmpdir )
784
+ sys .stderr .write ("error deleting tmp directory %s\n " % tmpdir )
767
785
768
786
def print_pdf (self , fname_or_fh , * args , ** kwargs ):
769
787
"""
@@ -782,22 +800,21 @@ def _print_png_to_fh(self, fh):
782
800
converter = make_pdf_to_png_converter ()
783
801
784
802
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" )
789
807
# 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 )
792
810
# copy file contents to target
793
- with open ("figure.png" , "rb" ) as fh_src :
811
+ with open (fname_png , "rb" ) as fh_src :
794
812
shutil .copyfileobj (fh_src , fh )
795
813
finally :
796
- os .chdir (cwd )
797
814
try :
798
815
shutil .rmtree (tmpdir )
799
816
except :
800
- sys .stderr .write ("could not delete tmp directory %s\n " % tmpdir )
817
+ sys .stderr .write ("error deleting tmp directory %s\n " % tmpdir )
801
818
802
819
def print_png (self , fname_or_fh , * args , ** kwargs ):
803
820
"""
@@ -869,3 +886,5 @@ def __init__(self, *args):
869
886
########################################################################
870
887
871
888
FigureManager = FigureManagerPgf
889
+
890
+ atexit .register (LatexManager ._cleanup_remaining_instances )
0 commit comments