From 926c3473589b1eaac6d3b008b323f8c7172fd243 Mon Sep 17 00:00:00 2001 From: Antony Lee Date: Sun, 16 Feb 2020 20:47:16 +0100 Subject: [PATCH] Delay checking for existence of postscript distillers. Currently, if one has `ps.usedistiller` set in their matplotlibrc, matplotlib will immediately check for the presence of ghostscript (and possibly pstopdf) at import time and run them in subprocesses to check their version, even though they may not be needed at all (if the user is not going to save a postscript image); this can quite slow down import time. Compare e.g. with `text.usetex` which requires the presence of a `tex` install, but doesn't check for its presence until it is actually needed. Delay the checking for the presence of the distillers until we actually need them. For consistency with the old behavior, don't error out if they are missing, but just emit a warning. --- lib/matplotlib/backends/backend_ps.py | 24 +++++++++++++++++++----- lib/matplotlib/rcsetup.py | 19 +------------------ 2 files changed, 20 insertions(+), 23 deletions(-) diff --git a/lib/matplotlib/backends/backend_ps.py b/lib/matplotlib/backends/backend_ps.py index e1ef94010c06..d7b6dd6f6cff 100644 --- a/lib/matplotlib/backends/backend_ps.py +++ b/lib/matplotlib/backends/backend_ps.py @@ -981,9 +981,11 @@ def print_figure_impl(fh): with open(tmpfile, 'w', encoding='latin-1') as fh: print_figure_impl(fh) if mpl.rcParams['ps.usedistiller'] == 'ghostscript': - gs_distill(tmpfile, is_eps, ptype=papertype, bbox=bbox) + _try_distill(gs_distill, + tmpfile, is_eps, ptype=papertype, bbox=bbox) elif mpl.rcParams['ps.usedistiller'] == 'xpdf': - xpdf_distill(tmpfile, is_eps, ptype=papertype, bbox=bbox) + _try_distill(xpdf_distill, + tmpfile, is_eps, ptype=papertype, bbox=bbox) _move_path_to_path_or_stream(tmpfile, outfile) else: @@ -1141,10 +1143,12 @@ def write(self, *args, **kwargs): if (mpl.rcParams['ps.usedistiller'] == 'ghostscript' or mpl.rcParams['text.usetex']): - gs_distill(tmpfile, is_eps, ptype=papertype, bbox=bbox, - rotated=psfrag_rotated) + _try_distill(gs_distill, + tmpfile, is_eps, ptype=papertype, bbox=bbox, + rotated=psfrag_rotated) elif mpl.rcParams['ps.usedistiller'] == 'xpdf': - xpdf_distill(tmpfile, is_eps, ptype=papertype, bbox=bbox, + _try_distill(xpdf_distill, + tmpfile, is_eps, ptype=papertype, bbox=bbox, rotated=psfrag_rotated) _move_path_to_path_or_stream(tmpfile, outfile) @@ -1198,6 +1202,13 @@ def convert_psfrags(tmpfile, psfrags, font_preamble, custom_preamble, return psfrag_rotated +def _try_distill(func, *args, **kwargs): + try: + func(*args, **kwargs) + except mpl.ExecutableNotFoundError as exc: + _log.warning("%s. Distillation step skipped.", exc) + + def gs_distill(tmpfile, eps=False, ptype='letter', bbox=None, rotated=False): """ Use ghostscript's pswrite or epswrite device to distill a file. @@ -1239,6 +1250,9 @@ def xpdf_distill(tmpfile, eps=False, ptype='letter', bbox=None, rotated=False): operators. This distiller is preferred, generating high-level postscript output that treats text as text. """ + mpl._get_executable_info("gs") # Effectively checks for ps2pdf. + mpl._get_executable_info("pdftops") + pdffile = tmpfile + '.pdf' psfile = tmpfile + '.ps' diff --git a/lib/matplotlib/rcsetup.py b/lib/matplotlib/rcsetup.py index 8b2ee0991edd..7ae169f17ec6 100644 --- a/lib/matplotlib/rcsetup.py +++ b/lib/matplotlib/rcsetup.py @@ -24,7 +24,6 @@ import numpy as np -import matplotlib as mpl from matplotlib import animation, cbook from matplotlib.cbook import ls_mapper from matplotlib.fontconfig_pattern import parse_fontconfig_pattern @@ -486,24 +485,8 @@ def validate_ps_distiller(s): s = s.lower() if s in ('none', None, 'false', False): return None - elif s in ('ghostscript', 'xpdf'): - try: - mpl._get_executable_info("gs") - except mpl.ExecutableNotFoundError: - _log.warning("Setting rcParams['ps.usedistiller'] requires " - "ghostscript.") - return None - if s == "xpdf": - try: - mpl._get_executable_info("pdftops") - except mpl.ExecutableNotFoundError: - _log.warning("Setting rcParams['ps.usedistiller'] to 'xpdf' " - "requires xpdf.") - return None - return s else: - raise ValueError('matplotlibrc ps.usedistiller must either be none, ' - 'ghostscript or xpdf') + return ValidateInStrings('ps.usedistiller', ['ghostscript', 'xpdf'])(s) # A validator dedicated to the named line styles, based on the items in