Skip to content

Handle None entries in sys.modules. #19601

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Mar 1, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 7 additions & 5 deletions lib/matplotlib/backends/qt_compat.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
8 changes: 5 additions & 3 deletions lib/matplotlib/cbook/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -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():
Expand All @@ -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
Expand Down
71 changes: 30 additions & 41 deletions lib/matplotlib/pyplot.py
Original file line number Diff line number Diff line change
Expand Up @@ -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::

Expand All @@ -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
Expand Down
4 changes: 2 additions & 2 deletions lib/matplotlib/testing/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
Expand Down