Login | Register For Free | Help
Search for: (Advanced)

Mailing List Archive: Python: Python

Problems with using queue in Tkinter application

 

 

Python python RSS feed   Index | Next | Previous | View Threaded


asm198 at gmail

Jul 3, 2009, 6:14 PM

Post #1 of 6 (218 views)
Permalink
Problems with using queue in Tkinter application

I'm working on a serial protocol analyzer in python. We have an
application written by someone else in MFC but we need something that
is cross platform. I intended to implement the GUI portion in Tkinter
but am having trouble.

The idea is that I will read messages from the serial port and output
them to a Tkinter Text object initially. Eventually it will have
other functionality but that's it for the short term. I've written
this little test app to experiment with putting things on the GUI via
a Queue which is polled by the Tkinter loop.

On some machines this code works fine and I get whatever I type in
displayed in the Text widget. On others I get errors like this as
soon as I start it running.

error in background error handler:
out of stack space (infinite loop?)
while executing
"::tcl::Bgerror {out of stack space (infinite loop?)} {-code 1 -level
0 -errorcode NONE -errorinfo {out of stack space (infinite loop?)
while execu..."


I don't understand why on some machines it works exactly as expected
and on others it acts the same way Tkinter does when I call functions
directly from outside the Tkinter thread. Does anyone have any
suggestions? The full code as appended below. Thanks in advance.

[code]

import Queue

class functionQueue:

def __init__(self, root = None, timeout = 250):

self.functionQueue = Queue.Queue()
self.root = root
self.timeout = timeout

if(self.root):
self.pop_function(root)


def pop_function(self, root = None):

try:
funcArgList = self.functionQueue.get(block = False)
except Queue.Empty:
pass
else:
try:
funcArgList[0](*funcArgList[1])
except:
try:
print "Failed to call function", funcArgList[0]
except:
print "Failed to call function"

if(root):
root.after(self.timeout, lambda: self.pop_function
(self.root))

def add_function(self, function, argList):

try:
self.functionQueue.put([function, argList])
except:
pass


if( __name__ == '__main__'):

import Tkinter
import thread

text = Tkinter.Text()
text.pack()

myQueue = functionQueue(text, 50)

def gui_loop():
try:
text.mainloop()
except:
import os
os._exit(1)

thread.start_new_thread(text.mainloop, ())

while(True):
usrInput = raw_input()

if(usrInput == "-1"):
import os
os._exit(0)

myQueue.add_function(text.insert, ['end', usrInput + "\n"])
myQueue.add_function(text.see, ['end'])

[/code]

--
http://mail.python.org/mailman/listinfo/python-list


__peter__ at web

Jul 4, 2009, 1:21 AM

Post #2 of 6 (195 views)
Permalink
Re: Problems with using queue in Tkinter application [In reply to]

Icarus wrote:

> I'm working on a serial protocol analyzer in python. We have an
> application written by someone else in MFC but we need something that
> is cross platform. I intended to implement the GUI portion in Tkinter
> but am having trouble.
>
> The idea is that I will read messages from the serial port and output
> them to a Tkinter Text object initially. Eventually it will have
> other functionality but that's it for the short term. I've written
> this little test app to experiment with putting things on the GUI via
> a Queue which is polled by the Tkinter loop.
>
> On some machines this code works fine and I get whatever I type in
> displayed in the Text widget. On others I get errors like this as
> soon as I start it running.
>
> error in background error handler:
> out of stack space (infinite loop?)
> while executing
> "::tcl::Bgerror {out of stack space (infinite loop?)} {-code 1 -level
> 0 -errorcode NONE -errorinfo {out of stack space (infinite loop?)
> while execu..."
>
>
> I don't understand why on some machines it works exactly as expected
> and on others it acts the same way Tkinter does when I call functions
> directly from outside the Tkinter thread. Does anyone have any
> suggestions? The full code as appended below. Thanks in advance.
>
> [code]
>
> import Queue
>
> class functionQueue:
>
> def __init__(self, root = None, timeout = 250):
>
> self.functionQueue = Queue.Queue()
> self.root = root
> self.timeout = timeout
>
> if(self.root):
> self.pop_function(root)
>
>
> def pop_function(self, root = None):
>
> try:
> funcArgList = self.functionQueue.get(block = False)
> except Queue.Empty:
> pass
> else:
> try:
> funcArgList[0](*funcArgList[1])
> except:
> try:
> print "Failed to call function", funcArgList[0]
> except:
> print "Failed to call function"
>
> if(root):
> root.after(self.timeout, lambda: self.pop_function
> (self.root))
>
> def add_function(self, function, argList):
>
> try:
> self.functionQueue.put([function, argList])
> except:
> pass
>
>
> if( __name__ == '__main__'):
>
> import Tkinter
> import thread
>
> text = Tkinter.Text()
> text.pack()
>
> myQueue = functionQueue(text, 50)
>
> def gui_loop():
> try:
> text.mainloop()
> except:
> import os
> os._exit(1)
>
> thread.start_new_thread(text.mainloop, ())
>
> while(True):
> usrInput = raw_input()
>
> if(usrInput == "-1"):
> import os
> os._exit(0)
>
> myQueue.add_function(text.insert, ['end', usrInput + "\n"])
> myQueue.add_function(text.see, ['end'])
>
> [/code]

I can make it work over here by putting the UI into the main thread, as
suggested by http://effbot.org/zone/tkinter-threads.htm:

import Queue
import Tkinter
import threading

class FunctionQueue:
# unchanged

def input_loop():
while True:
try:
usrInput = raw_input()
except EOFError:
break
myQueue.add_function(text.insert, ['end', usrInput + "\n"])
myQueue.add_function(text.see, ['end'])
myQueue.add_function(text.quit, [])

if __name__ == '__main__':
text = Tkinter.Text()
text.pack()

myQueue = FunctionQueue(text, 50)
threading.Thread(target=input_loop).start()
text.mainloop()

Peter


--
http://mail.python.org/mailman/listinfo/python-list


asm198 at gmail

Jul 4, 2009, 8:23 AM

Post #3 of 6 (190 views)
Permalink
Re: Problems with using queue in Tkinter application [In reply to]

On Jul 4, 3:21 am, Peter Otten <__pete...@web.de> wrote:
> Icarus wrote:
> > I'm working on a serial protocol analyzer in python.  We have an
> > application written by someone else in MFC but we need something that
> > is cross platform.  I intended to implement the GUI portion in Tkinter
> > but am having trouble.
>
> > The idea is that I will read messages from the serial port and output
> > them to a Tkinter Text object initially.  Eventually it will have
> > other functionality but that's it for the short term.  I've written
> > this little test app to experiment with putting things on the GUI via
> > a Queue which is polled by the Tkinter loop.
>
> > On some machines this code works fine and I get whatever I type in
> > displayed in the Text widget.  On others I get errors like this as
> > soon as I start it running.
>
> > error in background error handler:
> > out of stack space (infinite loop?)
> >     while executing
> > "::tcl::Bgerror {out of stack space (infinite loop?)} {-code 1 -level
> > 0 -errorcode NONE -errorinfo {out of stack space (infinite loop?)
> >     while execu..."
>
> > I don't understand why on some machines it works exactly as expected
> > and on others it acts the same way Tkinter does when I call functions
> > directly from outside the Tkinter thread.  Does anyone have any
> > suggestions?  The full code as appended below.  Thanks in advance.
>
> > [code]
>
> > import Queue
>
> > class functionQueue:
>
> >     def __init__(self, root = None, timeout = 250):
>
> >         self.functionQueue = Queue.Queue()
> >         self.root = root
> >         self.timeout = timeout
>
> >         if(self.root):
> >             self.pop_function(root)
>
> >     def pop_function(self, root = None):
>
> >         try:
> >             funcArgList = self.functionQueue.get(block = False)
> >         except Queue.Empty:
> >             pass
> >         else:
> >             try:
> >                 funcArgList[0](*funcArgList[1])
> >             except:
> >                 try:
> >                     print "Failed to call function", funcArgList[0]
> >                 except:
> >                     print "Failed to call function"
>
> >         if(root):
> >             root.after(self.timeout, lambda: self.pop_function
> > (self.root))
>
> >     def add_function(self, function, argList):
>
> >         try:
> >             self.functionQueue.put([function, argList])
> >         except:
> >             pass
>
> > if( __name__ == '__main__'):
>
> >     import Tkinter
> >     import thread
>
> >     text = Tkinter.Text()
> >     text.pack()
>
> >     myQueue = functionQueue(text, 50)
>
> >     def gui_loop():
> >         try:
> >             text.mainloop()
> >         except:
> >             import os
> >             os._exit(1)
>
> >     thread.start_new_thread(text.mainloop, ())
>
> >     while(True):
> >         usrInput = raw_input()
>
> >         if(usrInput == "-1"):
> >             import os
> >             os._exit(0)
>
> >         myQueue.add_function(text.insert, ['end', usrInput + "\n"])
> >         myQueue.add_function(text.see, ['end'])
>
> > [/code]
>
> I can make it work over here by putting the UI into the main thread, as
> suggested byhttp://effbot.org/zone/tkinter-threads.htm:
>
> import Queue
> import Tkinter
> import threading
>
> class FunctionQueue:
>     # unchanged
>
> def input_loop():
>     while True:
>         try:
>             usrInput = raw_input()
>         except EOFError:
>             break
>         myQueue.add_function(text.insert, ['end', usrInput + "\n"])
>         myQueue.add_function(text.see, ['end'])
>     myQueue.add_function(text.quit, [])
>
> if __name__ == '__main__':
>     text = Tkinter.Text()
>     text.pack()
>
>     myQueue = FunctionQueue(text, 50)
>     threading.Thread(target=input_loop).start()
>     text.mainloop()
>
> Peter

Peter, thanks for the suggestion. I tried your code exactly on my box
and I still get the same results. As soon as I run the script and
every time I click on the Text box I get tcl::Bgerror ... just like I
mentioned above. I'm fairly certain that I'm not calling Tkinter
functions from any other thread but it's acting as though I am as soon
as I create the input thread.
If I comment out the input loop thread everything is fine but of
course that's not terribly useful as a logging box.
--
http://mail.python.org/mailman/listinfo/python-list


__peter__ at web

Jul 4, 2009, 9:24 AM

Post #4 of 6 (189 views)
Permalink
Re: Problems with using queue in Tkinter application [In reply to]

Icarus wrote:

> On Jul 4, 3:21 am, Peter Otten <__pete...@web.de> wrote:
>> Icarus wrote:
>> > I'm working on a serial protocol analyzer in python. We have an
>> > application written by someone else in MFC but we need something that
>> > is cross platform. I intended to implement the GUI portion in Tkinter
>> > but am having trouble.
>>
>> > The idea is that I will read messages from the serial port and output
>> > them to a Tkinter Text object initially. Eventually it will have
>> > other functionality but that's it for the short term. I've written
>> > this little test app to experiment with putting things on the GUI via
>> > a Queue which is polled by the Tkinter loop.
>>
>> > On some machines this code works fine and I get whatever I type in
>> > displayed in the Text widget. On others I get errors like this as
>> > soon as I start it running.
>>
>> > error in background error handler:
>> > out of stack space (infinite loop?)
>> > while executing
>> > "::tcl::Bgerror {out of stack space (infinite loop?)} {-code 1 -level
>> > 0 -errorcode NONE -errorinfo {out of stack space (infinite loop?)
>> > while execu..."
>>
>> > I don't understand why on some machines it works exactly as expected
>> > and on others it acts the same way Tkinter does when I call functions
>> > directly from outside the Tkinter thread. Does anyone have any
>> > suggestions? The full code as appended below. Thanks in advance.
>>
>> > [code]
>>
>> > import Queue
>>
>> > class functionQueue:
>>
>> > def __init__(self, root = None, timeout = 250):
>>
>> > self.functionQueue = Queue.Queue()
>> > self.root = root
>> > self.timeout = timeout
>>
>> > if(self.root):
>> > self.pop_function(root)
>>
>> > def pop_function(self, root = None):
>>
>> > try:
>> > funcArgList = self.functionQueue.get(block = False)
>> > except Queue.Empty:
>> > pass
>> > else:
>> > try:
>> > funcArgList[0](*funcArgList[1])
>> > except:
>> > try:
>> > print "Failed to call function", funcArgList[0]
>> > except:
>> > print "Failed to call function"
>>
>> > if(root):
>> > root.after(self.timeout, lambda: self.pop_function
>> > (self.root))
>>
>> > def add_function(self, function, argList):
>>
>> > try:
>> > self.functionQueue.put([function, argList])
>> > except:
>> > pass
>>
>> > if( __name__ == '__main__'):
>>
>> > import Tkinter
>> > import thread
>>
>> > text = Tkinter.Text()
>> > text.pack()
>>
>> > myQueue = functionQueue(text, 50)
>>
>> > def gui_loop():
>> > try:
>> > text.mainloop()
>> > except:
>> > import os
>> > os._exit(1)
>>
>> > thread.start_new_thread(text.mainloop, ())
>>
>> > while(True):
>> > usrInput = raw_input()
>>
>> > if(usrInput == "-1"):
>> > import os
>> > os._exit(0)
>>
>> > myQueue.add_function(text.insert, ['end', usrInput + "\n"])
>> > myQueue.add_function(text.see, ['end'])
>>
>> > [/code]
>>
>> I can make it work over here by putting the UI into the main thread, as
>> suggested byhttp://effbot.org/zone/tkinter-threads.htm:
>>
>> import Queue
>> import Tkinter
>> import threading
>>
>> class FunctionQueue:
>> # unchanged
>>
>> def input_loop():
>> while True:
>> try:
>> usrInput = raw_input()
>> except EOFError:
>> break
>> myQueue.add_function(text.insert, ['end', usrInput + "\n"])
>> myQueue.add_function(text.see, ['end'])
>> myQueue.add_function(text.quit, [])
>>
>> if __name__ == '__main__':
>> text = Tkinter.Text()
>> text.pack()
>>
>> myQueue = FunctionQueue(text, 50)
>> threading.Thread(target=input_loop).start()
>> text.mainloop()
>>
>> Peter
>
> Peter, thanks for the suggestion. I tried your code exactly on my box
> and I still get the same results. As soon as I run the script and
> every time I click on the Text box I get tcl::Bgerror ... just like I
> mentioned above. I'm fairly certain that I'm not calling Tkinter
> functions from any other thread but it's acting as though I am as soon
> as I create the input thread.
> If I comment out the input loop thread everything is fine but of
> course that's not terribly useful as a logging box.

http://bugs.python.org/issue3835

Could tcl have been built without thread support on the failing machines?

Peter

--
http://mail.python.org/mailman/listinfo/python-list


python at mrabarnett

Jul 4, 2009, 9:40 AM

Post #5 of 6 (190 views)
Permalink
Re: Problems with using queue in Tkinter application [In reply to]

Icarus wrote:
> I'm working on a serial protocol analyzer in python. We have an
> application written by someone else in MFC but we need something that
> is cross platform. I intended to implement the GUI portion in Tkinter
> but am having trouble.
>
> The idea is that I will read messages from the serial port and output
> them to a Tkinter Text object initially. Eventually it will have
> other functionality but that's it for the short term. I've written
> this little test app to experiment with putting things on the GUI via
> a Queue which is polled by the Tkinter loop.
>
> On some machines this code works fine and I get whatever I type in
> displayed in the Text widget. On others I get errors like this as
> soon as I start it running.
>
> error in background error handler:
> out of stack space (infinite loop?)
> while executing
> "::tcl::Bgerror {out of stack space (infinite loop?)} {-code 1 -level
> 0 -errorcode NONE -errorinfo {out of stack space (infinite loop?)
> while execu..."
>
>
> I don't understand why on some machines it works exactly as expected
> and on others it acts the same way Tkinter does when I call functions
> directly from outside the Tkinter thread. Does anyone have any
> suggestions? The full code as appended below. Thanks in advance.
>
> [code]
>
> import Queue
>
> class functionQueue:
>
> def __init__(self, root = None, timeout = 250):
>
> self.functionQueue = Queue.Queue()
> self.root = root
> self.timeout = timeout
>
> if(self.root):
> self.pop_function(root)
>
>
> def pop_function(self, root = None):
>
> try:
> funcArgList = self.functionQueue.get(block = False)
> except Queue.Empty:
> pass
> else:
> try:
> funcArgList[0](*funcArgList[1])
> except:
> try:
> print "Failed to call function", funcArgList[0]
> except:
> print "Failed to call function"
>
> if(root):
> root.after(self.timeout, lambda: self.pop_function
> (self.root))
>
> def add_function(self, function, argList):
>
> try:
> self.functionQueue.put([function, argList])
> except:
> pass
>
>
> if( __name__ == '__main__'):
>
> import Tkinter
> import thread
>
> text = Tkinter.Text()
> text.pack()
>
> myQueue = functionQueue(text, 50)
>
> def gui_loop():
> try:
> text.mainloop()
> except:
> import os
> os._exit(1)
>
> thread.start_new_thread(text.mainloop, ())
>
> while(True):
> usrInput = raw_input()
>
> if(usrInput == "-1"):
> import os
> os._exit(0)
>
> myQueue.add_function(text.insert, ['end', usrInput + "\n"])
> myQueue.add_function(text.see, ['end'])
>
> [/code]
>
Only an idea, but:

myQueue = functionQueue(text, 50)

runs in the main thread, so the pop_function method is calling Tkinter
methods in the main thread every 50ms.

But:

thread.start_new_thread(text.mainloop, ())

is running the Tkinter main loop in another thread.

You might be experiencing a race condition, so different timings on
different machines might cause a problem to appear sooner on one than
another.
--
http://mail.python.org/mailman/listinfo/python-list


asm198 at gmail

Jul 5, 2009, 7:56 AM

Post #6 of 6 (173 views)
Permalink
Re: Problems with using queue in Tkinter application [In reply to]

On Jul 4, 11:24 am, Peter Otten <__pete...@web.de> wrote:
> Icarus wrote:
> > On Jul 4, 3:21 am, Peter Otten <__pete...@web.de> wrote:
> >> Icarus wrote:
> >> > I'm working on a serial protocol analyzer in python.  We have an
> >> > application written by someone else in MFC but we need something that
> >> > is cross platform.  I intended to implement the GUI portion in Tkinter
> >> > but am having trouble.
>
> >> > The idea is that I will read messages from the serial port and output
> >> > them to a Tkinter Text object initially.  Eventually it will have
> >> > other functionality but that's it for the short term.  I've written
> >> > this little test app to experiment with putting things on the GUI via
> >> > a Queue which is polled by the Tkinter loop.
>
> >> > On some machines this code works fine and I get whatever I type in
> >> > displayed in the Text widget.  On others I get errors like this as
> >> > soon as I start it running.
>
> >> > error in background error handler:
> >> > out of stack space (infinite loop?)
> >> > while executing
> >> > "::tcl::Bgerror {out of stack space (infinite loop?)} {-code 1 -level
> >> > 0 -errorcode NONE -errorinfo {out of stack space (infinite loop?)
> >> > while execu..."
>
> >> > I don't understand why on some machines it works exactly as expected
> >> > and on others it acts the same way Tkinter does when I call functions
> >> > directly from outside the Tkinter thread.  Does anyone have any
> >> > suggestions?  The full code as appended below.  Thanks in advance.
>
> >> > [code]
>
> >> > import Queue
>
> >> > class functionQueue:
>
> >> > def __init__(self, root = None, timeout = 250):
>
> >> > self.functionQueue = Queue.Queue()
> >> > self.root = root
> >> > self.timeout = timeout
>
> >> > if(self.root):
> >> > self.pop_function(root)
>
> >> > def pop_function(self, root = None):
>
> >> > try:
> >> > funcArgList = self.functionQueue.get(block = False)
> >> > except Queue.Empty:
> >> > pass
> >> > else:
> >> > try:
> >> > funcArgList[0](*funcArgList[1])
> >> > except:
> >> > try:
> >> > print "Failed to call function", funcArgList[0]
> >> > except:
> >> > print "Failed to call function"
>
> >> > if(root):
> >> > root.after(self.timeout, lambda: self.pop_function
> >> > (self.root))
>
> >> > def add_function(self, function, argList):
>
> >> > try:
> >> > self.functionQueue.put([function, argList])
> >> > except:
> >> > pass
>
> >> > if( __name__ == '__main__'):
>
> >> > import Tkinter
> >> > import thread
>
> >> > text = Tkinter.Text()
> >> > text.pack()
>
> >> > myQueue = functionQueue(text, 50)
>
> >> > def gui_loop():
> >> > try:
> >> > text.mainloop()
> >> > except:
> >> > import os
> >> > os._exit(1)
>
> >> > thread.start_new_thread(text.mainloop, ())
>
> >> > while(True):
> >> > usrInput = raw_input()
>
> >> > if(usrInput == "-1"):
> >> > import os
> >> > os._exit(0)
>
> >> > myQueue.add_function(text.insert, ['end', usrInput + "\n"])
> >> > myQueue.add_function(text.see, ['end'])
>
> >> > [/code]
>
> >> I can make it work over here by putting the UI into the main thread, as
> >> suggested byhttp://effbot.org/zone/tkinter-threads.htm:
>
> >> import Queue
> >> import Tkinter
> >> import threading
>
> >> class FunctionQueue:
> >> # unchanged
>
> >> def input_loop():
> >> while True:
> >> try:
> >> usrInput = raw_input()
> >> except EOFError:
> >> break
> >> myQueue.add_function(text.insert, ['end', usrInput + "\n"])
> >> myQueue.add_function(text.see, ['end'])
> >> myQueue.add_function(text.quit, [])
>
> >> if __name__ == '__main__':
> >> text = Tkinter.Text()
> >> text.pack()
>
> >> myQueue = FunctionQueue(text, 50)
> >> threading.Thread(target=input_loop).start()
> >> text.mainloop()
>
> >> Peter
>
> > Peter, thanks for the suggestion.  I tried your code exactly on my box
> > and I still get the same results.  As soon as I run the script and
> > every time I click on the Text box I get tcl::Bgerror ... just like I
> > mentioned above.  I'm fairly certain that I'm not calling Tkinter
> > functions from any other thread but it's acting as though I am as soon
> > as I create the input thread.
> > If I comment out the input loop thread everything is fine but of
> > course that's not terribly useful as a logging box.
>
> http://bugs.python.org/issue3835
>
> Could tcl have been built without thread support on the failing machines?
>
> Peter

You had it Peter. I tried the "import pydoc pydoc.gui()" in the bug
report you referenced and the same thing described there occurred.
After recompiling tcl/tk with --threads-enabled and replacing the
slackware default packages with those everything is working as I
expected. Thanks for the help.
--
http://mail.python.org/mailman/listinfo/python-list

Python python RSS feed   Index | Next | Previous | View Threaded
 
 


Interested in having your list archived? Contact lists@gossamer-threads.com
 
  Web Applications & Managed Hosting Powered by Gossamer Threads Inc.