GV

GeezerVison

The World Wide Web, restored to 800 pixels of glory.

Home|About|Gaming cabinet|Archives|How it works|Starter sites

On this site

  • Sign in
  • ActionsCI/CD and automation
  • CodespacesCloud development environments
  • All Features
  • Documentation
  • Training
  • Certifications
  • Build with Copilot
  • Customize Copilot
  • Integrations
  • Trending repos
  • GitHub Sponsors
  • Developer articles
  • Enterprises

This view

  • Original page
  • New address

GeezerVison is showing github.com — Installed qt5 event loop hook. · Issue #14006 · ipython/ipython

Installed qt5 event loop hook. #14006

New issue
Copy link
New issue
Copy link
Open
Open
Installed qt5 event loop hook.#14006
Copy link

Description

@forallsunday
forallsunday
opened on Apr 6, 2023
Issue body actions

When I use plt.show() , and run the script,

❯ & D:/Anaconda3/python.exe -m IPython --no-autoindent d:/Documents/C-Project/GeoLocOptim/scripts/estimate.py

The following message showed:

Installed qt5 event loop hook.
Shell is already running a gui event loop for qt5. Call with no arguments to disable the current loop.

What does it mean and how to disable this?

Activity

  1. nodatapoints commented on Apr 7, 2023

    @nodatapoints
    nodatapoints
    on Apr 7, 2023
    More actions

    I think this is due to #13957.
    The print statements seem hardcoded, which I don't like.

    An option to disable these debug messages would be nice, since I do not need to be reminded of the event loop on every startup.

    Reacted by Francesco Boccardo
  2. francescoboc commented on Apr 21, 2023

    @francescoboc
    francescoboc
    on Apr 21, 2023
    More actions

    I agree with @nodatapoints , I would like to suppress the message Installed qt5 event loop hook..

  3. ccordoba12 commented on Apr 28, 2023

    @ccordoba12
    ccordoba12
    on Apr 28, 2023
    Member
    More actions

    @shaperilio, how do you think we should address this issue?

  4. shaperilio commented on Apr 28, 2023

    @shaperilio
    shaperilio
    on Apr 28, 2023
    Contributor
    More actions

    Is there a global "debug" flag?

    The print statements were added precisely because silent failures were happening before; i.e. you run something which is forcing a qt event loop hook without asking, and then you muck around with some tk stuff and nothing works.

    Happy to help make this quieter, and maybe work on something that allows multiple event loop hooks to run in sequence, which I believe should be possible as well.

  5. ccordoba12 commented on Apr 28, 2023

    @ccordoba12
    ccordoba12
    on Apr 28, 2023
    Member
    More actions

    I think the problem is that Matplotlib sets the Qt backend by default in some cases, which generates this message in IPython when users try to set that backend again.

    So, perhaps the message shouldn't be shown when the backend you're trying to set is the same one that you already have.

  6. shaperilio commented on Apr 28, 2023

    @shaperilio
    shaperilio
    on Apr 28, 2023
    Contributor
    More actions

    So, perhaps the message shouldn't be shown when the backend you're trying to set is the same one that you already have.

    This was certainly the intent. Let me take a look at what's going on.

    @forallsunday can you post relevant package versions?

    Reacted by Carlos Cordoba
  7. nodatapoints commented on Apr 29, 2023

    @nodatapoints
    nodatapoints
    on Apr 29, 2023
    More actions

    @forallsunday can you post relevant package versions?

    I run IPython 8.12.0 with Qt5 on Gentoo. In my configuration I set
    c.TerminalIPythonApp.matplotlib = 'qt5'
    otherwise I use default settings except for some prompt configs.

    Reacted by Carlos Cordoba
  8. shaperilio commented on May 1, 2023

    @shaperilio
    shaperilio
    on May 1, 2023
    Contributor
    More actions

    I run IPython 8.12.0 with Qt5 on Gentoo. In my configuration I set c.TerminalIPythonApp.matplotlib = 'qt5' otherwise I use default settings except for some prompt configs.

    What is c?

  9. ccordoba12 commented on May 2, 2023

    @ccordoba12
    ccordoba12
    on May 2, 2023
    Member
    More actions

    It's the IPython config object. See here for more details:

    https://ipython.readthedocs.io/en/stable/config/intro.html

    Reacted by Emilio Graff
  10. shaperilio commented on May 2, 2023

    @shaperilio
    shaperilio
    on May 2, 2023
    Contributor
    More actions

    OK, I reproduced this with a config file containing only

    c = get_config()  #noqa
    c.TerminalIPythonApp.matplotlib = 'qt5'
    

    and a virtualenv containing only matplotlib, pyqt5, and ipython. I'll start working on this.

    My intent is to make an effort to ignore multiple requests for the same GUI event loop, but keep all the messaging. If lots of people are against that, maybe we can add a --verbose flag or something similar to what I did for autoreload (which has -p or -l for showing messages via print or log).

    Reacted by Francesco Boccardo and Carlos Cordoba
  11. ccordoba12 commented on May 2, 2023

    @ccordoba12
    ccordoba12
    on May 2, 2023
    Member
    More actions

    I think ignoring warnings for the same event loop is fine for now.

  12. shaperilio commented on May 2, 2023

    @shaperilio
    shaperilio
    on May 2, 2023
    Contributor
    More actions

    OK, there's a bit of a mess here with Qt versions.

    When IPython starts, the profile configuration is read. After the banner is printed, TerminalIPythonApp.init_gui_pylab() executes.

    The user, in this case, has set matplotlib to qt5 in their config. So init_gui_pylab calls InteractiveShellApp.enable_matplotlib('qt5').

    This, via a call to matplotlib.get_backend(), will eventually call matplotlib.pyplot.switch_backend(xxx) where xxx is the first in the list ["macosx", "qtagg", "gtk4agg", "gtk3agg", "tkagg", "wxagg"] to succeed.

    Note that this call comes from trying to retrieve the value rcParams['backend']; effectively asking for a backend will set it.

    So, for both Windows and Linux, this would be qtagg.

    This causes matplotlib to import the latest Qt in the system.

    At the very end of the call to matplotlib.pyplot.switch_backend('qtagg'), pyplot.install_repl_displayhook() is called, and this effectively calls %gui yyy, where yyy comes from the mappings below.

    pyplot.install_repl_displayhook() goes into IPython.core.pylabtools to look for which GUI event hook goes with which backend. Currently, there is this mapping from GUI->backend:

    backends = {
        "tk": "TkAgg",
        "gtk": "GTKAgg",
        "gtk3": "GTK3Agg",
        "gtk4": "GTK4Agg",
        "wx": "WXAgg",
        "qt4": "Qt4Agg",
        "qt5": "Qt5Agg",
        "qt6": "QtAgg",
        "qt": "Qt5Agg",
        "osx": "MacOSX",
        "nbagg": "nbAgg",
        "webagg": "WebAgg",
        "notebook": "nbAgg",
        "agg": "agg",
        "svg": "svg",
        "pdf": "pdf",
        "ps": "ps",
        "inline": "module://matplotlib_inline.backend_inline",
        "ipympl": "module://ipympl.backend_nbagg",
        "widget": "module://ipympl.backend_nbagg",
    }
    

    I see a discrepancy here: If qt6 maps to QtAgg, why does qt map to Qt5Agg?

    The reverse mapping from backend->GUI has modifications:

    # There needs to be a hysteresis here as the new QtAgg Matplotlib backend
    # supports either Qt5 or Qt6 and the IPython qt event loop support Qt4, Qt5,
    # and Qt6.
    backend2gui["QtAgg"] = "qt"
    backend2gui["Qt4Agg"] = "qt"
    backend2gui["Qt5Agg"] = "qt"
    

    I don't follow these. If there are specifically versioned backends, and the Qt imports on both matplotlib and IPython are specifically versioned, and we assume qt means latest, these shouldn't be here. (I can certainly remove any reference to Qt4 and older since support for it was removed in #13864.)

    Note that this all happens before actually processing whatever the user set TerminalIPythonApp.matplotlib to in their config file. This definition of backend2gui will just return qt, so before even reading the user's config file, we will install an event loop hook for the latest installed version of Qt. For example, in a system with both pyside6 and pyqt5 installed, this will import pyside6 into the session and install a hook for it.

    This entire sequence is being triggered by importing matplotlib_inline.backend_inline. In short, InteractiveShell.enable_matplotlib is first calling %gui qt and then immediately trying to call %gui yyy, where yyy is what the user asked for in their config. If the two Qt versions don't match, this will fail.

    (This is more of a note to self; let me think about this more and see how we can proceed.)

  13. shaperilio commented on May 2, 2023

    @shaperilio
    shaperilio
    on May 2, 2023
    Contributor
    More actions

    @tacaswell do you have any thoughts on the backend<->GUI mapping?

  14. tacaswell commented on May 2, 2023

    @tacaswell
    tacaswell
    on May 2, 2023
    Contributor
    More actions

    There is a winding road to get here and I am not sure I have all of the details correct, but my rough understanding is:

    • IPython provides nicer names (without the agg) to select the backend
    • these names date back probably 15+ years and the current versions of Qt
    • in Matplotlib we had a pattern of doing a new backend for each GUI toolkit version (backend_qt4agg.py, backend_qt5agg.py, backend_gtk3agg.py, backend_gtk4agg.py) etc
    • when qt6 came out instead of making a backend_qt6agg.py we managed to push enough compatibility shims into backends/qt_compat.py that we could support all 4 Qt bindings (pyside / pyqt X Qt5, Qt6) and made one new backend called backend_qtagg.py. Support for PyQt6/PySide6. matplotlib/matplotlib#19255 . This is mpl3.5
      • as part of this we also dropped almost all of our machinery for picking the import you want...if you care import your preferred binding before us! See https://matplotlib.org/stable/api/backend_qt_api.html#qt-bindings
    • we kept backend_qt5agg.py around as a very thin shim (and a knob to force qt_compat.py to pick one of the Qt5 bindings) because there is no good reason to break any users who are importing directly
    • It looks like I was the last person to touch the forward mapping of 'qt' in 127b45b when I changed 'qt' to map to qt5agg!
    • There is a bug in the table at https://matplotlib.org/stable/users/explain/backends.html#the-builtin-backends which claims %matplotlib qt selects qtagg

    I think the course of action here should be:

    • version gate the meaning of qt to be qtagg

    I'll open this PR.

    This is closely related to #14038

  15. shaperilio commented on May 2, 2023

    @shaperilio
    shaperilio
    on May 2, 2023
    Contributor
    More actions

    Thanks @tacaswell; I'll need some time to process your comment.

    In the meantime, I've started a draft pull request. The messaging is improved (that's the easy part) but I left a comment there because importing matplotlib_inline.backend_inline triggers a GUI event loop hook that I don't think is needed, but I need more guidance on that.

  16. tacaswell commented on May 2, 2023

    @tacaswell
    tacaswell
    on May 2, 2023
    Contributor
    More actions

    but I left a comment there because importing matplotlib_inline.backend_inline triggers a GUI event loop hook that I don't think is needed, but I need more guidance on that.

    I'm 75% sure that is something that needs to be resolved in the inline backend.

  17. tacaswell commented on May 2, 2023

    @tacaswell
    tacaswell
    on May 2, 2023
    Contributor
    More actions

    The other thing to check is that the default backend in Matplotlib in now "auto", however if you ask Matplotlib what the current backend is or create a figure we will sort out what the best currently available backend is. If you have any of the Qt bindings installed, we will pick that (as interactive figures are better than dead figures).

    https://matplotlib.org/stable/users/explain/backends.html#selecting-a-backend

    Without a backend explicitly set, Matplotlib automatically detects a usable backend based on what is available on your system and on whether a GUI event loop is already running. The first usable backend in the following list is selected: MacOSX, QtAgg, GTK4Agg, Gtk3Agg, TkAgg, WxAgg, Agg. The last, Agg, is a non-interactive backend that can only write to files. It is used on Linux, if Matplotlib cannot connect to either an X display or a Wayland display.

    I do not see matplotlib_inline doing anything I expect to force the backend, but I may have missed it or am forgetting another condition that force us to resolve the backend.

  18. shaperilio commented on May 3, 2023

    @shaperilio
    shaperilio
    on May 3, 2023
    Contributor
    More actions

    The other thing to check is that the default backend in Matplotlib in now "auto"

    This is exactly what matplotlib_inline is triggering, by calling _enable_matplotlib_integration() in backend_inline.py. That calls matplotlib.get_backend(), which will trigger __getitem__ in RcParams and execute this:

    https://github.com/matplotlib/matplotlib/blob/5189609b9d2c0ea0b78ceba9d4003358db160b81/lib/matplotlib/__init__.py#L750-L754

    and that last line will go through the list mentioned in the docs.

    So yes, it seems that _enable_matplotlib_integration() should probably call matplotlib._get_backend_or_none().

  19. shaperilio commented on May 3, 2023

    @shaperilio
    shaperilio
    on May 3, 2023
    Contributor
    More actions

    OK, #14067 implements what I think we should do.

    I think it needs to wait to see what we hear from matplotlib_inline.

    Reacted by Carlos Cordoba and nodatapoints
  20. shaperilio commented on May 30, 2023

    @shaperilio
    shaperilio
    on May 30, 2023
    Contributor
    More actions

    I created a PR for this in matplotlib_inline: ipython/matplotlib-inline#26

    Now _enable_matplotlib_integration() won't trigger the auto-selection of a backend.

  21. shaperilio commented on May 30, 2023

    @shaperilio
    shaperilio
    on May 30, 2023
    Contributor
    More actions

    I just wrote up #14089; maybe we can take the choice away from users who don't really care? Especially with this Qt version stuff, I wonder if we support it just because the code is there and not because most people actually need it.

  22. Carreau
    added 3 commits that reference this issue on Sep 19, 2023

    ENH: Don't show message when enable the current eventloop.

    2f7ab00

    ENH: Don't show message when enable the current eventloop.

    cf63863

    ENH: Don't show message when enable the current eventloop. (#14168)

    3df4946
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions

      You are visitor 01402520 — GeezerVison does not store the pages you look up.
      Best viewed with Netscape Navigator 4.7 or Internet Explorer 6 at 800×600. No cookies required.