[Tkinter-discuss] Debugging non-zero exit code

Reinis Danne rei4dan at gmail.com
Sat Feb 6 11:43:07 EST 2016

On Fri, Feb 05, 2016 at 09:09:39PM +0100, Michael Lange wrote:
> Hi,
> On Fri, 5 Feb 2016 21:44:04 +0200
> Reinis Danne <rei4dan at gmail.com> wrote:
> > Hi!
> > 
> > I'm trying to debug why BKChem prints '0' and exits with exit
> > code 1. As far as I can tell that is not directly in the app.
> > I tried to debug it with gdb, but it tried (and failed) to start
> > the app again after I have pressed the close button, so I didn't
> > get any useful info out of it. How could I debug this issue?
> just a guess from a quick glance in bkchem.py:
> in the if __name__ == '__main__' part of your code you have something
> like this:
>   myapp.geometry(geometry)
>   myapp.update_idletasks()
>   myapp.deiconify()
>   myapp.mainloop()
>   myapp.destroy()
> In the following minimal example:
> from Tkinter import *
> root = Tk()
> root.mainloop()
> root.destroy()
> when you click the "X" button in the window corner to close the window,
> you will get an exit code 1 along with an error message like this:
> Traceback (most recent call last):
>   File "test.py", line 6, in <module>
>     root.destroy()
>   File "/usr/lib/python2.7/lib-tk/Tkinter.py", line 1858, in destroy
>     self.tk.call('destroy', self._w)
> _tkinter.TclError: can't invoke "destroy" command: application has been
> destroyed
> Maybe something like this is happening?
> If yes, the solution is to add a handler for the responsible window
> manager protocol, as in:
> from Tkinter import *
> root = Tk()
> root.wm_protocol('WM_DELETE_WINDOW', root.quit)
> root.mainloop()
> root.destroy()
> Best regards
> Michael

Thanks for the help!

Adding root.wm_protocol('WM_DELETE_WINDOW', root.quit) worked
indeed, but only for the close button. It didn't work if I closed
the window with Alt+F4 or File->Exit. On further inspection it
already used WM_DELETE_WINDOW protocol in
main.py::BKChem.initialize() like this:

self.protocol("WM_DELETE_WINDOW", self._quit)

And then called self.quit() and sys.exit():

def _quit(self):
    # Do some clean-up
    if os.name != "nt":

The issue seems to be with the sys.exit() call, removing that
fixes the issue. It was introduced in commit
ca8deafe48de3f358c09e9a7b9532fa56caff6b4 and was supposed to deal
with exiting when editPool widget has been active. Without it the
window is not closed if editPool widget has been active (press
the button with simbol "N" and click on the paper to activate
editPool widget and Enter to deactivate it).

Another issue is the self.quit() call. According to the
documentation [1] the WM_DELETE_WINDOW protocol handler should
call self.destroy(). If I move the bkchem.py::myapp.destroy() to
main.py::BKChem._quit() in place of self.quit() call everything
still works. So what is the difference between destroy() and
quit() and which is better here?

>From documentation [2]:
"The mainloop call enters the Tk event loop, in which the
application will stay until the quit method is called (just click
the QUIT button), or the window is closed.

The destroy call is only required if you run this example under
certain development environments; it explicitly destroys the main
window when the event loop is terminated. Some development
environments won’t terminate the Python process unless this is

So is either way (with or without the quit() call) ok?

It turns out that using destroy() in place of quit() allows to
close the app properly even in the case when editPool has been
active so there is no need for sys.exit() call.

The remaining question is if I'm supposed to do some extra
clean-up when deactivating editPool (beyond calling
edit_pool.py::editPool._cancel() on it if it is still active;
that calls editPool.quit() among other things)? How?

Calling destroy() at exit time feels like dealing with the issue
with brute force instead of properly cleaning up when
deactivating the widget.


[2] http://effbot.org/tkinterbook/tkinter-hello-again.htm

More information about the Tkinter-discuss mailing list