From da911546c68adc6cebabc5288d91fcf859edd487 Mon Sep 17 00:00:00 2001 From: Antony Lee Date: Wed, 7 Oct 2020 15:46:24 +0200 Subject: [PATCH] Further simplify pgf tmpdir cleanup. By carefully tearing down components of LatexManager in the right order (first the subprocess), we avoid the need for a global registry of things that need to be cleared at process termination. --- .../deprecations/18679-AL.rst | 3 + lib/matplotlib/backends/backend_pgf.py | 71 +++++++------------ 2 files changed, 30 insertions(+), 44 deletions(-) create mode 100644 doc/api/next_api_changes/deprecations/18679-AL.rst diff --git a/doc/api/next_api_changes/deprecations/18679-AL.rst b/doc/api/next_api_changes/deprecations/18679-AL.rst new file mode 100644 index 000000000000..417dd6a35a77 --- /dev/null +++ b/doc/api/next_api_changes/deprecations/18679-AL.rst @@ -0,0 +1,3 @@ +``backend_pgf.TmpDirCleaner`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +... is deprecated, with no replacement. diff --git a/lib/matplotlib/backends/backend_pgf.py b/lib/matplotlib/backends/backend_pgf.py index 2288397343a0..5c9ad776ec22 100644 --- a/lib/matplotlib/backends/backend_pgf.py +++ b/lib/matplotlib/backends/backend_pgf.py @@ -11,7 +11,6 @@ import shutil import subprocess import sys -import tempfile from tempfile import TemporaryDirectory import weakref @@ -200,7 +199,6 @@ class LatexManager: determining the metrics of text elements. The LaTeX environment can be modified by setting fonts and/or a custom preamble in `.rcParams`. """ - _unclean_instances = weakref.WeakSet() @staticmethod def _build_latex_header(): @@ -237,12 +235,6 @@ def _get_cached_or_new(cls): def _get_cached_or_new_impl(cls, header): # Helper for _get_cached_or_new. return cls() - @staticmethod - def _cleanup_remaining_instances(): - unclean_instances = list(LatexManager._unclean_instances) - for latex_manager in unclean_instances: - latex_manager._cleanup() - def _stdin_writeln(self, s): if self.latex is None: self._setup_latex_process() @@ -268,13 +260,10 @@ def _expect_prompt(self): return self._expect("\n*") def __init__(self): - # store references for __del__ - self._os_path = os.path - self._shutil = shutil - - # create a tmp directory for running latex, remember to cleanup - self.tmpdir = tempfile.mkdtemp(prefix="mpl_pgf_lm_") - LatexManager._unclean_instances.add(self) + # create a tmp directory for running latex, register it for deletion + self._tmpdir = TemporaryDirectory() + self.tmpdir = self._tmpdir.name + self._finalize_tmpdir = weakref.finalize(self, self._tmpdir.cleanup) # test the LaTeX setup to ensure a clean startup of the subprocess self.texcommand = mpl.rcParams["pgf.texsystem"] @@ -303,11 +292,21 @@ def __init__(self): self.str_cache = {} # cache for strings already processed def _setup_latex_process(self): - # open LaTeX process for real work + # Open LaTeX process for real work; register it for deletion. On + # Windows, we must ensure that the subprocess has quit before being + # able to delete the tmpdir in which it runs; in order to do so, we + # must first `kill()` it, and then `communicate()` with it. self.latex = subprocess.Popen( [self.texcommand, "-halt-on-error"], stdin=subprocess.PIPE, stdout=subprocess.PIPE, encoding="utf-8", cwd=self.tmpdir) + + def finalize_latex(latex): + latex.kill() + latex.communicate() + + self._finalize_latex = weakref.finalize( + self, finalize_latex, self.latex) # write header with 'pgf_backend_query_start' token self._stdin_writeln(self._build_latex_header()) # read all lines until our 'pgf_backend_query_start' token appears @@ -318,23 +317,6 @@ def _setup_latex_process(self): def latex_stdin_utf8(self): return self.latex.stdin - def _cleanup(self): - if not self._os_path.isdir(self.tmpdir): - return - try: - self.latex.communicate() - except Exception: - pass - try: - self._shutil.rmtree(self.tmpdir) - LatexManager._unclean_instances.discard(self) - except Exception: - sys.stderr.write("error deleting tmp directory %s\n" % self.tmpdir) - - def __del__(self): - _log.debug("deleting LatexManager") - self._cleanup() - def get_width_height_descent(self, text, prop): """ Get the width, total height and descent for a text typeset by the @@ -766,16 +748,25 @@ class GraphicsContextPgf(GraphicsContextBase): pass +@cbook.deprecated("3.4") class TmpDirCleaner: - remaining_tmpdirs = set() + _remaining_tmpdirs = set() + + @cbook._classproperty + @cbook.deprecated("3.4") + def remaining_tmpdirs(cls): + return cls._remaining_tmpdirs @staticmethod + @cbook.deprecated("3.4") def add(tmpdir): - TmpDirCleaner.remaining_tmpdirs.add(tmpdir) + TmpDirCleaner._remaining_tmpdirs.add(tmpdir) @staticmethod + @cbook.deprecated("3.4") + @atexit.register def cleanup_remaining_tmpdirs(): - for tmpdir in TmpDirCleaner.remaining_tmpdirs: + for tmpdir in TmpDirCleaner._remaining_tmpdirs: error_message = "error deleting tmp directory {}".format(tmpdir) shutil.rmtree( tmpdir, @@ -930,14 +921,6 @@ class _BackendPgf(_Backend): FigureCanvas = FigureCanvasPgf -def _cleanup_all(): - LatexManager._cleanup_remaining_instances() - TmpDirCleaner.cleanup_remaining_tmpdirs() - - -atexit.register(_cleanup_all) - - class PdfPages: """ A multi-page PDF file using the pgf backend pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy