Uh oh!
There was an error while loading.Please reload this page.
- Notifications
You must be signed in to change notification settings - Fork7.9k
Tk backend improvements#17789
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 ourterms of service andprivacy statement. We’ll occasionally send you account related emails.
Already on GitHub?Sign in to your account
Tk backend improvements#17789
Uh oh!
There was an error while loading.Please reload this page.
Conversation
One of the |
To check my understanding, in the |
On linux the code from#9856 %matplotlibtkimportsysimportmatplotlibimportmatplotlibasmplimportpylabaspltprint('OS: %s'%sys.platform)print('matplotlib version: %s'%mpl.__version__)print('Backend: %s'%matplotlib.get_backend())foriinrange(3):plt.figure()plt.close()plt.figure()plt.plot([0,1],[0,1])plt.show() does not crash, but gives me
when run from inside of IPython, but no warnings when run as a script which makes me think that the problem is actually coming from the prompt toolkit inputhook (seehttps://github.com/ipython/ipython/blob/master/IPython/terminal/pt_inputhooks/tk.py to send you down all of the tk related rabbit holes...)? Are we sure that this will not bring back that crash on the mac? On v3.2.2 I get no warnings, but see the closed windows flicker in and out of existence. |
That is correct, to my understanding. for consistency "mainloop" should be everywhere and always the _tkinter.tkapp.mainloop method eventually.
Unfortunately, I don't have a mac to test on. Can we get a test going on CI? I get no messages like that on windows from python repl or ipython. I do see the blinky root windows on ipython though! |
I have access to a mac that I can test on, but down a rabbit hole of figuring out why |
Fortunately, the bug I thought I found is fixed on both 3.3.x and master as of#17764 ! |
I can run the code and verify that it does not crash but am having issues getting VNC to work so ~95% sure this is OK. If you are feeling motivated, I think another subprocess test would work here, if not I'll try to take care of it. |
@tacaswell, is this still OK? |
These should be exercised with |
Uh oh!
There was an error while loading.Please reload this page.
I don't really understand the |
FYI |
No need to draw if event loop is responsive
message will be destroyed via tk object tree (master=self) and GCd by Python (only referred to by other self attributes)
tkinter has a perfectly good event loop written in C
timeout is given in float seconds according to FigureCanvasBase, but tk needs int milliseconds
start_event_loop semantics are equivalent to update with timeout < 0.001
c1cffde
to880c6c5
Compare@QuLogic I believe I have addressed your comment with this last commit, my rebase on master might have made that unclear! |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
Small test improvements, but LGTM.
Uh oh!
There was an error while loading.Please reload this page.
Uh oh!
There was an error while loading.Please reload this page.
Uh oh!
There was an error while loading.Please reload this page.
PR Summary
This PR makes changes to the Tk backend to prevent unnecessary recursion into the Tcl event loop, REPL hangs on figure close, and unnecessary draws on resize plus some extras.
Background
I have a project to explorestructured concurrency as applied to GUI design. Specifically, I have written a tkinter "app" that hoststrio inguest mode, and then uses callbacks exclusively to launch async functions, which themselves are eventually scheduled to run using
Tk.after_idle
.Changes
Without going in to detail, it is easy to wind up in a situation where
FigureCanvasTkAgg.draw
is called from an async function in such a way that it deadlocks the event loop. Fortunately, there are absolutely no legitimate reasons to invokeTk.update
ortk.update_idletasks
while an event loop is running, so this PR removes them entirely.Other changes are less directly related to my primary motivation but became apparent as I was diagnosing the deadlock issue.
Resize events call
FigureCanvasTkAgg.draw
inFigureCanvasTkAgg.resize
unnecessarily, asFigureCanvasBase.resize_event
callsFigureCanvasTk.draw_idle
. This PR removes that line, so resizes will be drawn eventually, without hogging the event loop.NavigationToolbar2Tk
has a special destroy method to delete it'stkinter.StringVar
attribute namedmessage
. It will be destroyed via Tk object tree (master=self) and GCd by Python (only referred to by other self attributes) without this, so this PR removes it outright.FigureManagerTk
has a destroy method that is completely ineffective and also fails to stop the Tk mainloop. This PR rewrites the method entirely usingprotocol("WM_DELETE_WINDOW",...)
rather thanbind("<Destroy>",...)
. (Cherry picked and merged to master in#17802)FigureCanvasTk
is missing methodsstart_event_loop
andstop_event_loop
and so relies onFigureCanvasBase
pure Python event loop implementations. This PR reimplements them following the example of the Qt and wx backends. However, I can't find any test code or Matplotlib API functions that actually exercise these methods.Summary
These changes have minor or no user facing effect unless somewhere
Tk.after_idle
schedules a callback that containsTk.update_idletasks
. Writing this summary, it seems the fix toFigureManagerTk
may actually the most user-noticeable (except most users are probably using Qt.) Not knowing whyTk.update_idletasks
was sprinkled about in the first place, it is hard to say if this is backward-incompatable; it should be fine. A test to assert thatupdate
orupdate_idletasks
is never called when using the Tk backend would be appropriate, as well as a test of theFigureCanvasTk
event loop methods, but I can't fathom how the backend tests are constructed, so some help would be appreciated.PR Checklist