From e13b9e4fee0563aacbce465a3b3e67c448c1dc6e Mon Sep 17 00:00:00 2001 From: Tim Hoffmann <2836374+timhoffm@users.noreply.github.com> Date: Tue, 29 Oct 2024 15:49:19 +0100 Subject: [PATCH] MNT: Add provisional get_backend(resolve=False) flag The default is `resolve=True` for now, so that this introduction is completely backward-compatible. The provisional introduction anticipates planned changes for the backend resolution (https://github.com/matplotlib/matplotlib/issues/26406#issuecomment-2442816302). If all plays out as intended, this prolongs the range of releases for the migration: If we start deprecating `rcParams._get("backend")` say in 3.11, people can immediately switch to `get_backend(resolve=False)` and their code still runs on 3.10 without version gating. The worst that can happen is that the introduced flag was not helpful and we remove it again, which is easy because it's provisional. --- lib/matplotlib/__init__.py | 26 ++++++++++++++++++++++++-- lib/matplotlib/__init__.pyi | 7 +++++-- lib/matplotlib/tests/test_rcparams.py | 1 + 3 files changed, 30 insertions(+), 4 deletions(-) diff --git a/lib/matplotlib/__init__.py b/lib/matplotlib/__init__.py index 23643a53d811..5f964e0b34de 100644 --- a/lib/matplotlib/__init__.py +++ b/lib/matplotlib/__init__.py @@ -1296,15 +1296,37 @@ def use(backend, *, force=True): rcParams['backend'] = os.environ.get('MPLBACKEND') -def get_backend(): +def get_backend(*, auto_select=True): """ Return the name of the current backend. + Parameters + ---------- + auto_select : bool, default: True + Whether to trigger backend resolution if no backend has been + selected so far. If True, this ensures that a valid backend + is returned. If False, this returns None if no backend has been + selected so far. + + .. versionadded:: 3.10 + + .. admonition:: Provisional + + The *auto_select* flag is provisional. It may be changed or removed + without prior warning. + See Also -------- matplotlib.use """ - return rcParams['backend'] + if auto_select: + return rcParams['backend'] + else: + backend = rcParams._get('backend') + if backend is rcsetup._auto_backend_sentinel: + return None + else: + return backend def interactive(b): diff --git a/lib/matplotlib/__init__.pyi b/lib/matplotlib/__init__.pyi index 5b6797d3a7da..88058ffd7def 100644 --- a/lib/matplotlib/__init__.pyi +++ b/lib/matplotlib/__init__.pyi @@ -37,7 +37,7 @@ import contextlib from packaging.version import Version from matplotlib._api import MatplotlibDeprecationWarning -from typing import Any, NamedTuple +from typing import Any, Literal, NamedTuple, overload class _VersionInfo(NamedTuple): major: int @@ -104,7 +104,10 @@ def rc_context( rc: dict[str, Any] | None = ..., fname: str | Path | os.PathLike | None = ... ) -> Generator[None, None, None]: ... def use(backend: str, *, force: bool = ...) -> None: ... -def get_backend() -> str: ... +@overload +def get_backend(*, auto_select: Literal[True] = True) -> str: ... +@overload +def get_backend(*, auto_select: Literal[False]) -> str | None: ... def interactive(b: bool) -> None: ... def is_interactive() -> bool: ... diff --git a/lib/matplotlib/tests/test_rcparams.py b/lib/matplotlib/tests/test_rcparams.py index 0aa3ec0ba603..13633956c349 100644 --- a/lib/matplotlib/tests/test_rcparams.py +++ b/lib/matplotlib/tests/test_rcparams.py @@ -554,6 +554,7 @@ def test_backend_fallback_headful(tmp_path): # Check that access on another instance does not resolve the sentinel. "assert mpl.RcParams({'backend': sentinel})['backend'] == sentinel; " "assert mpl.rcParams._get('backend') == sentinel; " + "assert mpl.get_backend(auto_select=False) is None; " "import matplotlib.pyplot; " "print(matplotlib.get_backend())"], env=env, text=True, check=True, capture_output=True).stdout