[Python-bugs-list] [ python-Bugs-231207 ] Fatal Python Error during program shutdown

noreply@sourceforge.net noreply@sourceforge.net
Mon, 04 Nov 2002 10:12:31 -0800


Bugs item #231207, was opened at 2001-02-05 19:50
You can respond by visiting: 
https://sourceforge.net/tracker/?func=detail&atid=105470&aid=231207&group_id=5470

Category: Tkinter
Group: None
Status: Open
Resolution: None
Priority: 5
Submitted By: Doug Henderson (djhender)
Assigned to: Nobody/Anonymous (nobody)
Summary: Fatal Python Error during program shutdown

Initial Comment:
The windows builds of versions 2.0 and 2.1a2 contain an intermittent bug which often appears when a script using Tkinter stops by calling self.tk.quit() and sometimes (less often) appears following a <Destroy> event or call to a ?.destory() function.
Under Windows 98SE, this results in a GPF.
Under Windows 2000, a message to the console window shows "Fatal Python Error", "PyEval_RestoreThread NULL tstate".

The following script demonstrates the problem:
---------------------
# BugDemo.py

from Tkinter import *

class BugDemo(Frame):
    def __init__(self, parent):
        Frame.__init__(self, parent)
        Button(self, text='Hi', command=self.hi).pack()
        Button(self, text='Quit', command=self.tk.quit).pack()
    def hi(self):
        print "hi"

bd = BugDemo(Tk())
bd.pack()
bd.mainloop()
----------------------
Execute in console window: "c:> python BugDemo.py"
Test this by 1) clicking Quit button 2) clicking Hi button, then Quit button.
Test 1: The script runs successfully most of the time. I found I had to minimize and restore its window to make it fail regularly.
Test 2: I need to click Hi button before clicking the Quit button. Then it failed about half the time.

The problem appears to occur after the script has completed, during some kind of cleanup perhaps. The more useful error message on the Win2k machine may help to locate the problem.

Problem also manifests using the PythonWare 2.0 release on Win98.

----------------------------------------------------------------------

>Comment By: Doug Henderson (djhender)
Date: 2002-11-04 11:12

Message:
Logged In: YES 
user_id=148444

I modified my BugDemo program to change the last 3 lines to

root = Tk()
bd = BugDemo(root)
bd.pack()
bd.mainloop()
root.destory()

This did not resolve the problem under Win98SE Python 2.2.1.
Both Python 2.2.1 and 2.2.2 use Tk/tcl 8.3. I have seen
comments that indicate that this is a known problem in stock
8.3 which is fixed in 8.4.

I also tested using the other two scripts presented
elsewhere among the comments to this bug report. These tests
also hang, even with the added root.destroy() statement.

I no longer have access to a Win2k machine, so I cannot test
there.


----------------------------------------------------------------------

Comment By: Internet Discovery (idiscovery)
Date: 2002-11-02 23:52

Message:
Logged In: YES 
user_id=33229

I know I'm a Python newbie but I know Tcl well and I think I know 
at least part of what's going on. Looking specifically at nobody's
2002-04-22 14:21 code, I see that this uses mainloop and quit
in a way that many Python books and examples do, as if quit()
will "Quit the Tcl interpreter. All widgets will be destroyed."

But if you look at MainLoop and Quit in _tkinter.c you see that
Quit just sets a variable that causes MainLoop to end - it
doesn't destroy anything nor quit the interpreter. 

IMHO all Tkinter programs need a root.destroy() after root.mainloop()
If you change nobody's program to add a root.destroy() it runs fine under
PythonWin.

The "bug" is in the documentation of quit() in Tkinter.py

    def quit(self):
        """Quit the Tcl interpreter. All widgets will be destroyed."""
        self.tk.quit()

The comment should read
         """Quit the main event loop. It is up to you to call root.destroy() after."""

If I'm right the documentation for Tkinter in the library reference should be
changed too; there should be a root.destroy() at the end of
            http://www.python.org/doc/2.2.1/lib/node503.html

If I'm right then I'll stick my neck out a little further: Tkinter's mainloop and quit
should be dropped from _tkinter.c and replaced with the following idiom
and usage:

In Tkinter.py declare a class variable in Misc: _exit = -1 and change in Misc
TCL_ALL_EVENTS		= 0
    def quit(self):
        """Quit the Tcl interpreter. All widgets will be destroyed."""
        self._exit = 0
    def mainloop(self):
        """Loop until we call quit()"""
        while self._exit < 0:
            try:
                self.root.tk.dooneevent(TCL_ALL_EVENTS)
            except SystemExit:
                #print 'Exit'
                self.exit = 1
                break
            except 
               # do something intelligent with errors or interrupts

I believe this is more transparent and more open to creativity.
I have experimented (all my code is like this now) and feel 
that there is no performance penalty to looping in Python.

In addition it avoids the 20msec sleep in _tkinter.mainloop()
that is an abomination. 

It would also allow people to think more clearly about what happens
when you have 2 Tk() instances, in which case you have 2 Tcl
interpeters. It may make you move _exit to be an instance
variable of the Tk class. In any event you'll be able to see what's
going on.






----------------------------------------------------------------------

Comment By: Nobody/Anonymous (nobody)
Date: 2002-04-22 08:21

Message:
Logged In: NO 

I confirm the behaviour for:
WinNT 4.0 SP5
tested with Python 2.2Beta1 (ActiveState)
tested with Python 2.2.1.222 (ActiveState)

PythonWinIDE will hang when the following program 
is "quit"ted.

But will "quit" normally when run standalone (not within 
PythonWinIDE):

# 
# 

from Tkinter import *
from tkMessageBox import *

class App:
    def __init__(self, winRoot):
        frame = Frame(winRoot)
        frame.pack()

        self.btnQuit = Button(frame, text="QUIT", 
bg="blue", foreground="light blue", command=frame.quit)
        self.btnQuit.pack(side=LEFT)

        self.btnHiThere = Button(frame, text="Hi 
there!",command=self.sayHiThere)
        self.btnHiThere.pack(side=LEFT)

    def sayHiThere(self):
        showinfo("Greeting", "Hi There")
        
        

if __name__ == "__main__":
    root = Tk()
    test = App(root)
    root.mainloop()




----------------------------------------------------------------------

Comment By: Jeremy Hylton (jhylton)
Date: 2002-03-01 15:49

Message:
Logged In: YES 
user_id=31392

Unassign as it appears that effbot isn't going to look at 
it.


----------------------------------------------------------------------

Comment By: Nobody/Anonymous (nobody)
Date: 2001-07-18 05:13

Message:
Logged In: NO 

i won't to be a hacker

----------------------------------------------------------------------

Comment By: Nobody/Anonymous (nobody)
Date: 2001-05-29 01:30

Message:
Logged In: NO 

Note:
I am running Windows98
ActivePython 2.1
Even with console apps in python this same error appears
I tried using another Distribution of Python for win32, 
PythonWare20

So this leads me to believe that some lib is missing on 
win98. Because at work I use Win95, and Installed 
ActivePython 2.1, and it works fine and dandy


----------------------------------------------------------------------

Comment By: Joel Gould (joelgould)
Date: 2001-03-24 09:52

Message:
Logged In: YES 
user_id=20954

I also see a GPF on shutdown under Windows 98 using 
Tkinter.  I tested this using the PythonWare 2.0 release as 
well.

I have attached a very simple Tkinter program.  When I run 
this on my Windows 98 SE machine, a crash occurs when the 
program exits.  Without the MainDialog class it works OK.  
Without the Pmw initialization call it works OK.  But as 
written it will crash around 75% of the time.

(1) run the program
(2) press the Test Button
(3) click Cancel in the file open dialog (you do not need 
to select a file)
(4) click the close button in the upper right corner
-->  Boom

--------------------

import Tkinter
import tkFileDialog
import Pmw

def action():
    tkFileDialog.askopenfilename(filetypes=[('All','*')])

class MainDialog:
    def __init__(self,parent):
        Tkinter.Button(parent,text='Test 
Button',command=action).pack()

root = Pmw.initialise()
dialog = MainDialog(root)
root.mainloop()

----------------------------------------------------------------------

Comment By: Tim Peters (tim_one)
Date: 2001-02-09 16:34

Message:
Assigned to /F, under the theory he can confirm that "this kind of thing" is still a general problem with Tk we can't do anything about.

----------------------------------------------------------------------

Comment By: Doug Henderson (djhender)
Date: 2001-02-05 22:30

Message:
See also #116289 (and my comment to it) which describes what often happened to my 'real' programs which lead to developing the above BugDemo script. My 'real' programs were developed over the last two years or so, and worked in Jan 2000 with 1.5.2. I upgraded the Python version recently, and then started working on these programs again. It was "WTF is wrong with my code", until I found the same problem showing up in the small test cases.

----------------------------------------------------------------------

You can respond by visiting: 
https://sourceforge.net/tracker/?func=detail&atid=105470&aid=231207&group_id=5470