From a4ffb68885fb6d1005b43455530546b046da0eaf Mon Sep 17 00:00:00 2001 From: Thomas A Caswell Date: Fri, 25 Oct 2019 00:09:33 -0400 Subject: [PATCH 1/6] FIX: do not consider webagg and nbagg "interactive" for fallback There is logic in pyplot to determine if the user has is some way selected a backend which is incompatible with the interactive framework that we detect is running. This helps prevent issues where the user is already using one GUI frame work (ex tk) before Matplotlib is imported and has Matplotlib configured to use Qt. The other place this behavior is desired is if Matplotlib is configured to use a GUI framework by default, but is then imported on a headless server. By detecting there is no DISPLAY we fall back to Agg rather than failing to import. From the point of view of having UI events, webagg and nbagg are interactive backends, however from the point of view of requiring DISPLAY they are not. This is the minimal fix, filtering out these two backends in pyplot rather than changing this in rcsetup, incase anyone is relying on those lists for other purposes. closes #14903 --- lib/matplotlib/pyplot.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/matplotlib/pyplot.py b/lib/matplotlib/pyplot.py index 378dfef082b6..aa0f7c03bdb4 100644 --- a/lib/matplotlib/pyplot.py +++ b/lib/matplotlib/pyplot.py @@ -2244,7 +2244,8 @@ def getname_val(identifier): # requested, ignore rcParams['backend'] and force selection of a backend that # is compatible with the current running interactive framework. if (rcParams["backend_fallback"] - and dict.__getitem__(rcParams, "backend") in _interactive_bk + and dict.__getitem__(rcParams, "backend") in [ + k for k in _interactive_bk if k not in ['WebAgg', 'nbAgg']] and cbook._get_running_interactive_framework()): dict.__setitem__(rcParams, "backend", rcsetup._auto_backend_sentinel) # Set up the backend. From 0eaa2db9b22e1f96a39b8a6d43888264f66a0106 Mon Sep 17 00:00:00 2001 From: Thomas A Caswell Date: Fri, 25 Oct 2019 08:25:34 -0400 Subject: [PATCH 2/6] MNT: use set rather than list comprehension to filter backend list Co-Authored-By: Elliott Sales de Andrade --- lib/matplotlib/pyplot.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/matplotlib/pyplot.py b/lib/matplotlib/pyplot.py index aa0f7c03bdb4..3a08cec7ad1c 100644 --- a/lib/matplotlib/pyplot.py +++ b/lib/matplotlib/pyplot.py @@ -2244,8 +2244,8 @@ def getname_val(identifier): # requested, ignore rcParams['backend'] and force selection of a backend that # is compatible with the current running interactive framework. if (rcParams["backend_fallback"] - and dict.__getitem__(rcParams, "backend") in [ - k for k in _interactive_bk if k not in ['WebAgg', 'nbAgg']] + and dict.__getitem__(rcParams, "backend") in ( + set(_interactive_bk) - {'WebAgg', 'nbAgg'}) and cbook._get_running_interactive_framework()): dict.__setitem__(rcParams, "backend", rcsetup._auto_backend_sentinel) # Set up the backend. From f6279ac84784865bd19bf01c82dd9ce9ca409933 Mon Sep 17 00:00:00 2001 From: Thomas A Caswell Date: Sun, 27 Oct 2019 21:46:52 -0400 Subject: [PATCH 3/6] TST: correct webagg fallback behavior on headless machine --- lib/matplotlib/tests/test_backend_webagg.py | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) create mode 100644 lib/matplotlib/tests/test_backend_webagg.py diff --git a/lib/matplotlib/tests/test_backend_webagg.py b/lib/matplotlib/tests/test_backend_webagg.py new file mode 100644 index 000000000000..6d81259f2adc --- /dev/null +++ b/lib/matplotlib/tests/test_backend_webagg.py @@ -0,0 +1,16 @@ +import subprocess +import sys +import pytest + + +@pytest.mark.parametrize('backend', ['webagg', 'nbagg']) +def test_webagg_fallback(backend): + test_code = ("import matplotlib.pyplot as plt; " + + "print(plt.get_backend());" + f"assert '{backend}' == plt.get_backend().lower();") + ret = subprocess.call( + [sys.executable, "-c", test_code], + env={"MPLBACKEND": backend, "DISPLAY": ""} + ) + + assert ret == 0 From 8271e612e9d76bb23a894ddf60b4210ff3b5ff20 Mon Sep 17 00:00:00 2001 From: Thomas A Caswell Date: Sun, 27 Oct 2019 22:32:33 -0400 Subject: [PATCH 4/6] TST: try to fix windows by directly setting mplbackend env --- lib/matplotlib/tests/test_backend_webagg.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/lib/matplotlib/tests/test_backend_webagg.py b/lib/matplotlib/tests/test_backend_webagg.py index 6d81259f2adc..d5886a340998 100644 --- a/lib/matplotlib/tests/test_backend_webagg.py +++ b/lib/matplotlib/tests/test_backend_webagg.py @@ -5,7 +5,9 @@ @pytest.mark.parametrize('backend', ['webagg', 'nbagg']) def test_webagg_fallback(backend): - test_code = ("import matplotlib.pyplot as plt; " + + test_code = ("import os;" + + f"os.environ['MPLBACKEND'] = '{backend}';" + + "import matplotlib.pyplot as plt; " + "print(plt.get_backend());" f"assert '{backend}' == plt.get_backend().lower();") ret = subprocess.call( From fd9f102e1a5fd6dacb9af697c8249b3493450ae6 Mon Sep 17 00:00:00 2001 From: Thomas A Caswell Date: Wed, 30 Oct 2019 22:00:03 -0400 Subject: [PATCH 5/6] TST: skip the nbagg test if we don't have IPython installed --- lib/matplotlib/tests/test_backend_webagg.py | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/lib/matplotlib/tests/test_backend_webagg.py b/lib/matplotlib/tests/test_backend_webagg.py index d5886a340998..b5d8528fc2fc 100644 --- a/lib/matplotlib/tests/test_backend_webagg.py +++ b/lib/matplotlib/tests/test_backend_webagg.py @@ -3,13 +3,17 @@ import pytest -@pytest.mark.parametrize('backend', ['webagg', 'nbagg']) +@pytest.mark.parametrize("backend", ["webagg", "nbagg"]) def test_webagg_fallback(backend): - test_code = ("import os;" + - f"os.environ['MPLBACKEND'] = '{backend}';" + - "import matplotlib.pyplot as plt; " + - "print(plt.get_backend());" - f"assert '{backend}' == plt.get_backend().lower();") + if backend == "nbagg": + pytest.importorskip("IPython") + test_code = ( + "import os;" + + f"os.environ['MPLBACKEND'] = '{backend}';" + + "import matplotlib.pyplot as plt; " + + "print(plt.get_backend());" + f"assert '{backend}' == plt.get_backend().lower();" + ) ret = subprocess.call( [sys.executable, "-c", test_code], env={"MPLBACKEND": backend, "DISPLAY": ""} From 557e56f85b60032fe39eea22ab59056269e9eb24 Mon Sep 17 00:00:00 2001 From: Thomas A Caswell Date: Wed, 30 Oct 2019 23:16:19 -0400 Subject: [PATCH 6/6] TST: fix sub process usage on windows thanks to @story645 for sorting this out --- lib/matplotlib/tests/test_backend_webagg.py | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/lib/matplotlib/tests/test_backend_webagg.py b/lib/matplotlib/tests/test_backend_webagg.py index b5d8528fc2fc..220670aa4da2 100644 --- a/lib/matplotlib/tests/test_backend_webagg.py +++ b/lib/matplotlib/tests/test_backend_webagg.py @@ -1,4 +1,5 @@ import subprocess +import os import sys import pytest @@ -7,16 +8,21 @@ def test_webagg_fallback(backend): if backend == "nbagg": pytest.importorskip("IPython") + env = {} + if os.name == "nt": + env = dict(os.environ) + else: + env = {"DISPLAY": ""} + + env["MPLBACKEND"] = backend + test_code = ( "import os;" - + f"os.environ['MPLBACKEND'] = '{backend}';" + + f"assert os.environ['MPLBACKEND'] == '{backend}';" + "import matplotlib.pyplot as plt; " + "print(plt.get_backend());" f"assert '{backend}' == plt.get_backend().lower();" ) - ret = subprocess.call( - [sys.executable, "-c", test_code], - env={"MPLBACKEND": backend, "DISPLAY": ""} - ) + ret = subprocess.call([sys.executable, "-c", test_code], env=env) assert ret == 0