From 0b078ad140aef83b6bad81c48d6483afdf9fde15 Mon Sep 17 00:00:00 2001 From: Antony Lee Date: Fri, 2 Apr 2021 22:52:59 +0200 Subject: [PATCH] Correct handle default backend. See comments in `matplotlib/__init__.py` and `setup.py`. Test by updating your local repo to this branch and `pip install git+file:///path/to/repo` (doing so with the current master throws `ValueError: Key backend: '' is not a valid value for backend`. --- lib/matplotlib/__init__.py | 6 ++++++ lib/matplotlib/mpl-data/matplotlibrc | 2 +- lib/matplotlib/rcsetup.py | 3 +-- setup.py | 10 ++++++---- 4 files changed, 14 insertions(+), 7 deletions(-) diff --git a/lib/matplotlib/__init__.py b/lib/matplotlib/__init__.py index 856686e4f1de..70008e80e910 100644 --- a/lib/matplotlib/__init__.py +++ b/lib/matplotlib/__init__.py @@ -842,6 +842,12 @@ def rc_params_from_file(fname, fail_on_error=False, use_default_template=True): transform=lambda line: line[1:] if line.startswith("#") else line, fail_on_error=True) dict.update(rcParamsDefault, rcsetup._hardcoded_defaults) +# Normally, the default matplotlibrc file contains *no* entry for backend (the +# corresponding line starts with ##, not #; we fill on _auto_backend_sentinel +# in that case. However, packagers can set a different default backend +# (resulting in a normal `#backend: foo` line) in which case we should *not* +# fill in _auto_backend_sentinel. +dict.setdefault(rcParamsDefault, "backend", rcsetup._auto_backend_sentinel) rcParams = RcParams() # The global instance. dict.update(rcParams, dict.items(rcParamsDefault)) dict.update(rcParams, _rc_params_in_file(matplotlib_fname())) diff --git a/lib/matplotlib/mpl-data/matplotlibrc b/lib/matplotlib/mpl-data/matplotlibrc index 27a2a144bedd..01b1bf160abf 100644 --- a/lib/matplotlib/mpl-data/matplotlibrc +++ b/lib/matplotlib/mpl-data/matplotlibrc @@ -78,7 +78,7 @@ ## PS PDF SVG Template ## You can also deploy your own backend outside of Matplotlib by referring to ## the module name (which must be in the PYTHONPATH) as 'module://my_backend'. -#backend: Agg +##backend: Agg ## The port to use for the web server in the WebAgg backend. #webagg.port: 8988 diff --git a/lib/matplotlib/rcsetup.py b/lib/matplotlib/rcsetup.py index edb8683d1f26..1ad83bc84469 100644 --- a/lib/matplotlib/rcsetup.py +++ b/lib/matplotlib/rcsetup.py @@ -1411,14 +1411,13 @@ def _convert_validator_spec(key, conv): "_internal.classic_mode": validate_bool } _hardcoded_defaults = { # Defaults not inferred from matplotlibrc.template... - # ... because it can"t be: - "backend": _auto_backend_sentinel, # ... because they are private: "_internal.classic_mode": False, # ... because they are deprecated: "animation.avconv_path": "avconv", "animation.avconv_args": [], "animation.html_args": [], + # backend is handled separately when constructing rcParamsDefault. } _validators = {k: _convert_validator_spec(k, conv) for k, conv in _validators.items()} diff --git a/setup.py b/setup.py index 120ba41468d3..87add76da8d7 100644 --- a/setup.py +++ b/setup.py @@ -194,16 +194,18 @@ def build_extensions(self): def update_matplotlibrc(path): - # Update the matplotlibrc file if packagers want to change the default - # backend. + # If packagers want to change the default backend, insert a `#backend: ...` + # line. Otherwise, use the default `##backend: Agg` which has no effect + # even after decommenting, which allows _auto_backend_sentinel to be filled + # in at import time. template_lines = path.read_text().splitlines(True) backend_line_idx, = [ # Also asserts that there is a single such line. idx for idx, line in enumerate(template_lines) - if line.startswith("#backend:")] + if "#backend:" in line] template_lines[backend_line_idx] = ( "#backend: {}".format(setupext.options["backend"]) if setupext.options["backend"] - else "#backend:") + else "##backend: Agg") path.write_text("".join(template_lines))