diff --git a/lib/matplotlib/backends/qt_compat.py b/lib/matplotlib/backends/qt_compat.py index 21b89125d88e..26ddcc46c27e 100644 --- a/lib/matplotlib/backends/qt_compat.py +++ b/lib/matplotlib/backends/qt_compat.py @@ -35,14 +35,16 @@ _ETS = {"pyqt5": QT_API_PYQT5, "pyside2": QT_API_PYSIDE2, "pyqt": QT_API_PYQTv2, "pyside": QT_API_PYSIDE, None: None} -# First, check if anything is already imported. -if "PyQt5.QtCore" in sys.modules: +# First, check if anything is already imported. Use ``sys.modules.get(name)`` +# rather than ``name in sys.modules`` as entries can also have been explicitly +# set to None. +if sys.modules.get("PyQt5.QtCore"): QT_API = QT_API_PYQT5 -elif "PySide2.QtCore" in sys.modules: +elif sys.modules.get("PySide2.QtCore"): QT_API = QT_API_PYSIDE2 -elif "PyQt4.QtCore" in sys.modules: +elif sys.modules.get("PyQt4.QtCore"): QT_API = QT_API_PYQTv2 -elif "PySide.QtCore" in sys.modules: +elif sys.modules.get("PySide.QtCore"): QT_API = QT_API_PYSIDE # Otherwise, check the QT_API environment variable (from Enthought). This can # only override the binding, not the backend (in other words, we check that the diff --git a/lib/matplotlib/cbook/__init__.py b/lib/matplotlib/cbook/__init__.py index 79da52c7434c..d1e3d9238ac7 100644 --- a/lib/matplotlib/cbook/__init__.py +++ b/lib/matplotlib/cbook/__init__.py @@ -54,6 +54,8 @@ def _get_running_interactive_framework(): One of the following values: "qt5", "qt4", "gtk3", "wx", "tk", "macosx", "headless", ``None``. """ + # Use ``sys.modules.get(name)`` rather than ``name in sys.modules`` as + # entries can also have been explicitly set to None. QtWidgets = (sys.modules.get("PyQt5.QtWidgets") or sys.modules.get("PySide2.QtWidgets")) if QtWidgets and QtWidgets.QApplication.instance(): @@ -76,9 +78,9 @@ def _get_running_interactive_framework(): if frame.f_code in codes: return "tk" frame = frame.f_back - if 'matplotlib.backends._macosx' in sys.modules: - if sys.modules["matplotlib.backends._macosx"].event_loop_is_running(): - return "macosx" + macosx = sys.modules.get("matplotlib.backends._macosx") + if macosx and macosx.event_loop_is_running(): + return "macosx" if not _c_internal_utils.display_is_valid(): return "headless" return None diff --git a/lib/matplotlib/pyplot.py b/lib/matplotlib/pyplot.py index 86f6e9f8795d..ba2e1ad4156e 100644 --- a/lib/matplotlib/pyplot.py +++ b/lib/matplotlib/pyplot.py @@ -119,52 +119,41 @@ def install_repl_displayhook(): global _IP_REGISTERED global _INSTALL_FIG_OBSERVER - class _NotIPython(Exception): - pass - - # see if we have IPython hooks around, if use them - - try: - if 'IPython' in sys.modules: - from IPython import get_ipython - ip = get_ipython() - if ip is None: - raise _NotIPython() - - if _IP_REGISTERED: - return - - def post_execute(): - if matplotlib.is_interactive(): - draw_all() - - # IPython >= 2 - try: - ip.events.register('post_execute', post_execute) - except AttributeError: - # IPython 1.x - ip.register_post_execute(post_execute) - - _IP_REGISTERED = post_execute - _INSTALL_FIG_OBSERVER = False + if _IP_REGISTERED: + return + # See if we have IPython hooks around, if so use them. + # Use ``sys.modules.get(name)`` rather than ``name in sys.modules`` as + # entries can also have been explicitly set to None. + mod_ipython = sys.modules.get("IPython") + if not mod_ipython: + _INSTALL_FIG_OBSERVER = True + return + ip = mod_ipython.get_ipython() + if not ip: + _INSTALL_FIG_OBSERVER = True + return - # trigger IPython's eventloop integration, if available - from IPython.core.pylabtools import backend2gui + def post_execute(): + if matplotlib.is_interactive(): + draw_all() - ipython_gui_name = backend2gui.get(get_backend()) - if ipython_gui_name: - ip.enable_gui(ipython_gui_name) - else: - _INSTALL_FIG_OBSERVER = True + try: # IPython >= 2 + ip.events.register("post_execute", post_execute) + except AttributeError: # IPython 1.x + ip.register_post_execute(post_execute) + _IP_REGISTERED = post_execute + _INSTALL_FIG_OBSERVER = False - # import failed or ipython is not running - except (ImportError, _NotIPython): - _INSTALL_FIG_OBSERVER = True + from IPython.core.pylabtools import backend2gui + # trigger IPython's eventloop integration, if available + ipython_gui_name = backend2gui.get(get_backend()) + if ipython_gui_name: + ip.enable_gui(ipython_gui_name) def uninstall_repl_displayhook(): """ - Uninstall the matplotlib display hook. + Uninstall the Matplotlib display hook. .. warning:: @@ -174,8 +163,8 @@ def uninstall_repl_displayhook(): .. warning:: If you are using vanilla python and have installed another - display hook this will reset ``sys.displayhook`` to what ever - function was there when matplotlib installed it's displayhook, + display hook, this will reset ``sys.displayhook`` to what ever + function was there when Matplotlib installed its displayhook, possibly discarding your changes. """ global _IP_REGISTERED diff --git a/lib/matplotlib/testing/conftest.py b/lib/matplotlib/testing/conftest.py index 902d8f42bdc7..7a1ac10ecde3 100644 --- a/lib/matplotlib/testing/conftest.py +++ b/lib/matplotlib/testing/conftest.py @@ -48,7 +48,7 @@ def mpl_test_settings(request): # special case Qt backend importing to avoid conflicts if backend.lower().startswith('qt4'): - if any(k in sys.modules for k in ('PyQt5', 'PySide2')): + if any(sys.modules.get(k) for k in ('PyQt5', 'PySide2')): pytest.skip('Qt5 binding already imported') try: import PyQt4 @@ -59,7 +59,7 @@ def mpl_test_settings(request): except ImportError: pytest.skip("Failed to import a Qt4 binding.") elif backend.lower().startswith('qt5'): - if any(k in sys.modules for k in ('PyQt4', 'PySide')): + if any(sys.modules.get(k) for k in ('PyQt4', 'PySide')): pytest.skip('Qt4 binding already imported') try: import PyQt5