tags:

views:

636

answers:

3

I'm currently learning Python using Zelle's Introductory text, and I'm trying to recreate one of the example programs which uses an accompanying file graphics.py. Because I'm using Python 3.1 and the text was written for 2.x though, I'm using the GraphicsPy3.py file found at http://mcsp.wartburg.edu/zelle/python and renaming it graphics.py on my computer.

The file named futval_graph.py is as follows:

from graphics import *

def main():
    print("This program plots the growth of a 10-year investment.")

    principal = eval(input("Enter the initial principal: "))
    apr = eval(input("Enter the annualized interest rate: "))

    win = GraphWin("Investment Grown Chart", 320, 420)
    win.setBackground("white")
    Text(Point(20, 230), ' 0.0K').draw(win)
    Text(Point(20, 180), ' 2.5K').draw(win)
    Text(Point(20, 130), ' 5.0K').draw(win)
    Text(Point(20, 80), ' 7.5K').draw(win)
    Text(Point(20, 30), '10.0K').draw(win)

    # Rest of code is here but I've commented it out to isolate the problem.

main()

When I run 'import futval_graph' on a fresh IDLE session the program simply runs and then hangs after inputing 'apr' without opening the new graphics window. When I run the program from the command line I get the following result:

C:\Python31>futval_graph.py
This program plots the growth of a 10-year investment.
Enter the initial principal: 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 -errorco de NONE -errorinfo {out of stack space (infinite loop?)
while execu..."

Especially frustrating is the fact that this series of commands works when entered into a fresh session of IDLE. And then when running 'import futval_graph' from IDLE after all of the commands have been run on their own, futval_graph works properly.

So my question is: how can I get futval_graph.py to run properly both from the command line and IDLE? Sorry if my explanation of the problem is a bit scattered. Let me know if any further info would help clarify.

+2  A: 

There appears to be a problem with the Python 3 version of graphics.py.

I downloaded the Python 3 version, renamed it to graphics.py, then ran the following.

PS C:\Users\jaraco\Desktop> python
Python 3.1.1 (r311:74483, Aug 17 2009, 17:02:12) [MSC v.1500 32 bit (Intel)] on
win32
Type "help", "copyright", "credits" or "license" for more information.
>>> from graphics import *
>>> dir()
['BAD_OPTION', 'Circle', 'DEAD_THREAD', 'DEFAULT_CONFIG', 'Entry', 'GraphWin', 'GraphicsError', 'GraphicsObject', 'Image', 'Line', 'OBJ_ALREADY_DRAWN', 'Oval',
'Pixmap', 'Point', 'Polygon', 'Queue', 'Rectangle', 'Text', 'Transform', 'UNSUPPORTED_METHOD', '\_\_builtins\_\_', '\_\_doc\_\_', '\_\_name\_\_', '\_\_package\_\_', 'atexit', 'color_rgb', 'copy', 'os', 'sys', 'test', 'time', 'tk']
>>> 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..."

As you can see, I get the same error, and I haven't even executed anything in the module. There appears to be a problem with the library itself, and not something you're doing in your code.

I would report this to the author, as he suggests.

I did find that I did not get the error if I simply imported the graphics module.

>>> import graphics
>>> dir(graphics)

I found that if I did this to your code, and then changed references GraphWin to graphics.GraphWin, Text to graphics.Text, and Point to graphics.Point, the problem seemed to go away, and I could run it from the command line.

import graphics

def main():
 print("This program plots the growth of a 10-year investment.")

 principal = eval(input("Enter the initial principal: "))
 apr = eval(input("Enter the annualized interest rate: "))

 win = graphics.GraphWin("Investment Grown Chart", 320, 420)
 win.setBackground("white")
 graphics.Text(graphics.Point(20, 230), ' 0.0K').draw(win)
 graphics.Text(graphics.Point(20, 180), ' 2.5K').draw(win)
 graphics.Text(graphics.Point(20, 130), ' 5.0K').draw(win)
 graphics.Text(graphics.Point(20, 80), ' 7.5K').draw(win)
 graphics.Text(graphics.Point(20, 30), '10.0K').draw(win)

 # Rest of code is here but I've commented it out to isolate the problem.

main()

Why should this be? It shouldn't. It appears the graphics.py module has some side-effect that's not behaving properly.

I suspect you would not be running into these errors under the Python 2.x version.

Jason R. Coombs
After additional contemplation, I suspect the reason it works under IDLE and not at the command line is because when you run from IDLE, IDLE has already initialized the windowing toolkit, but when you run from the command-line, the graphics.py module initializes the toolkit, but perhaps not entirely correctly.
Jason R. Coombs
Jason, thanks for the workaround. I believe I will indeed be passing this along to the author.
IanWhalen
Actually, I'm afraid the workaround didn't quite work around like I thought it would. Just to be sure, I upgraded from 3.1 to 3.1.1, but running 'from graphics import *' and then 'dir()' didn't give me any error message.similarly, subbing in 'graphics.' where necessary didn't solve the problem either.I'm probably going to DL python 2.6.2 now in order to see whether it at least works there, and if so continue working in that version.
IanWhalen
Actually, I ran into the very same thing under Python 2.5. ('Tis the season for the very first bits of introductory comp classes!)
Jenn D.
Indeed, the error seems to be sporadic. Perhaps the program needs to run from pythonw instead of python?
Jason R. Coombs
Upvoting this to reward the detail, effort, and time that went into it.
John Y
+1  A: 

your code has issues with buil-in input, when it's called with non-empty string as argument. I suspect it might have something to do with the thread setup that graphics does.

If you make Tkinter widgets to read these inputs, may be it'll solve your problem.

To be honest, when you download graphicsPy3.py it says:

Graphics library ported to Python 3.x. Still experimental, please report any issues.

so, I suppose, you better follow this recommendation.

SilentGhost
A: 

After some additional research, it does appear that the call to input() does have some impact on triggering the unwanted behavior.

I re-wrote the program to not import the graphics module until after the input() calls were complete. In this case, I was unable to reproduce the error, and the code seemed to behave normally even when run from the command-line. I was able to get the parameters from the user, then it would begin to draw a graph (although with the sample code, only very little was drawn before the app closed). Perhaps this technique is a suitable workaround for your problem.

The underlying problem seems to have something to do with the way the tkinter module is initialized in a separate thread, and some undesirable interactions between threads. My guess is that the input() method, when run from a command-line, either locks a resource or otherwise triggers behavior that causes the Tk thread to go into an infinite loop.

Doing some searches around the Internet, I see that other users have gotten the same error, but for other reasons. Some were getting it when tkinter was built without thread support, but I don't think that applies here.

Jason R. Coombs