Thread: RE: [PyOpenGL-Users] Have exceptions terminate glutMainLoop
Brought to you by:
mcfletch
|
From: Tarn W. B. <twb...@ma...> - 2001-10-05 23:32:32
|
| Would it be possible to have exceptions raised during | glutMainLoop processing | (ie. in the callbacks) actually terminate the loop? I find that | if there is a | problem, the exception ends up scrolling way off the screen when | the matrix | stack gets confused. I then have to quickly terminate my program | before the | initial exception disappears - which happens often when I'm working in | fullscreen mode. glutMainLoop never returns so it's not possible to pass an exception through the loop. Right now all exceptions are caught before reentering the loop. I did this mostly to make sys.exit work as this was broken in PyGLUT. Although after a bit more thought I think the right way to do this is to exit the script completely on an exception. But for right now if you want to halt the loop this is what you will have to do: ---------------- import traceback def on_display(): try: # draw except: traceback.print_exc() sys.exit(1) glutDisplayFunc(on_display) glutMainLoop() print "This print never gets executed" ---------------- Tarn |
|
From: Tarn W. B. <twb...@ph...> - 2001-10-06 14:02:56
|
Yes, but exiting on an uncaught exception is how Python behaves normally. Tarn |
|
From: Tarn W. B. <twb...@ph...> - 2001-10-06 15:01:42
|
I just realized that there is actually the same problem in GLU callbacks. Consider a tesselation callback which raises an exception. If GLU callbacks are following the Python exception model than tesselation would halt and the exception would pop out at gluEndPolygon. But since this isn't possible currently all callback exceptions are caught before reentering the tesselation routine. It wouldn't make any sense to exit on an uncaught exception here since gluEndPolygon is usually never at the top level of a script. This makes me think that the same should go for glutMainLoop. Of course it would be nice for callback exception handling to behave in a more Pythonic way, but the only way that I can see doing this is to use C++ exceptions, which would of course require users have a C++ compiler. And I'm not even sure this would work. Can one pass a C++ exception through a C function? Oh well, doesn't matter anyway since switching over C++ is probably a bad idea. Tarn |
|
From: Tarn W. B. <twb...@ph...> - 2001-10-07 14:39:22
|
Because of the mechanics of the callback execution model we can't pass exceptions through it. For consistency I think that any change in callback behavior should apply to all callbacks, not just GLUT callbacks embedded in glutMainLoop. In fact, the exception behavior really has nothing to do with glutMainLoop since the change actually occurs in the C callback which executes the user's Python callback. Because of the execution model of callbacks it's better to think of a callback as a separate thread of execution which the main thread waits on. In Python's threading model, an unhandled exception in a child thread would never cause the parent thread to terminate. Instead Python would print a traceback and terminate the child thread. In the current setup it's still possible to do what Richard wants to do by having the user supply their own try blocks. Which brings up the point, that user's should be providing a try block anyway. The current implementation is only the bare minimum needed to make sys.exit work. Tarn |
|
From: Richard J. <ric...@op...> - 2001-10-08 21:52:08
|
On Mon, 8 Oct 2001 00:36, Tarn Weisner Burton wrote:
> Because of the mechanics of the callback execution model we can't pass
> exceptions through it. For consistency I think that any change in callback
> behavior should apply to all callbacks, not just GLUT callbacks embedded in
> glutMainLoop. In fact, the exception behavior really has nothing to do
> with glutMainLoop since the change actually occurs in the C callback which
> executes the user's Python callback.
That's how I understand it.
> Because of the execution model of callbacks it's better to think of a
> callback as a separate thread of execution which the main thread waits on.
Yech. Sorry, but yech :)
Callbacks != threads in my mind.
> In Python's threading model, an unhandled exception in a child thread would
> never cause the parent thread to terminate. Instead Python would print a
> traceback and terminate the child thread.
>
> In the current setup it's still possible to do what Richard wants to do by
> having the user supply their own try blocks. Which brings up the point,
> that user's should be providing a try block anyway. The current
> implementation is only the bare minimum needed to make sys.exit work.
Sorry, but I believe this is completely around the wrong way. I'll be
perfectly happy to trap any exceptions that I expect, but the unexpected
ones, I want them to kill the program. That is, if my program doesn't know
how to deal with a certain situation, it should be terminated, rather than
just bumbling along, possibly causing damage along the way! I think it's the
height of ugliness to have to wrap all my callbacks in an extra try/except to
deal with this.
Richard
|
|
From: Frederic G. <fr...@sc...> - 2001-10-08 16:18:47
|
My two cents worth concerning the callback exception/error problem: Wouldn't a technically clean solution consist in storing the Python exception information in a global somewhere, and raise the opengl error indicator with a Python-specific value upon returning from the Python callback when PyErr_Occurred(), so that this 'Glenum PyOpenGLError' code be retrieved later with the glGetError() function by whomever wishes to catch the error ? Frederic Giacometti |
|
From: Mike C. F. <mcf...@ho...> - 2001-10-06 08:15:56
|
I'm not in agreement regarding the "right way" here. For instance, if you force an exit on an uncaught exception, then any callback raising an exception can cause data loss for the user (a spurious/unimportant exception is raised, rather than being able to use some other menu item (or whatever) to attempt to save their data, the user is booted right out of the program (likely not even seeing the error if they've launched the program directly instead of from a shell)). Fail on any exception is nice for scripting/testing environments, but kicking out of the whole application in larger projects seems too heavy to me. Would redirecting stderr to a log file work? I haven't tried it lately, but I think it should be able to catch the exception output. Anyway, it's late, I'm going to sleep. Enjoy yourselves, Mike -----Original Message----- From: pyo...@li... [mailto:pyo...@li...]On Behalf Of Tarn Weisner Burton Sent: October 5, 2001 19:29 To: PyOpenGL Mailing List Subject: RE: [PyOpenGL-Users] Have exceptions terminate glutMainLoop | Would it be possible to have exceptions raised during | glutMainLoop processing | (ie. in the callbacks) actually terminate the loop? I find that | if there is a | problem, the exception ends up scrolling way off the screen when | the matrix | stack gets confused. I then have to quickly terminate my program | before the | initial exception disappears - which happens often when I'm working in | fullscreen mode. glutMainLoop never returns so it's not possible to pass an exception through the loop. Right now all exceptions are caught before reentering the loop. I did this mostly to make sys.exit work as this was broken in PyGLUT. Although after a bit more thought I think the right way to do this is to exit the script completely on an exception. But for right now if you want to halt the loop this is what you will have to do: ---------------- import traceback def on_display(): try: # draw except: traceback.print_exc() sys.exit(1) glutDisplayFunc(on_display) glutMainLoop() print "This print never gets executed" ---------------- Tarn _______________________________________________ PyOpenGL Homepage http://pyopengl.sourceforge.net _______________________________________________ PyOpenGL-Users mailing list PyO...@li... https://lists.sourceforge.net/lists/listinfo/pyopengl-users |
|
From: Richard J. <ric...@op...> - 2001-10-06 23:05:28
|
On Sat, 6 Oct 2001 18:18, Mike C. Fletcher wrote:
> I'm not in agreement regarding the "right way" here.
>
> For instance, if you force an exit on an uncaught exception, then any
> callback raising an exception can cause data loss for the user (a
> spurious/unimportant exception is raised, rather than being able to use
Woah there. I'm of the firm belief that if an exception is not handled in
code, it's never going to be a "spurious/unimportant exception". It is, by
definition, an "exception" to the correct running of the code. It means that
something has happened that the programmer did not expect, and is likely to
cause lots of problems. The Python way of handling exceptions that are not
caught is to terminate the program to avoid complications. Consider that the
exception occurred during processing of the user's data. The
"spurious/unimportant exception" is ignored, and the user is given the option
to unknowingly save their corrupted data.
> Fail on any exception is nice for scripting/testing environments, but
> kicking out of the whole application in larger projects seems too heavy to
> me. Would redirecting stderr to a log file work? I haven't tried it
> lately, but I think it should be able to catch the exception output.
I suggest that the C callback handlers exit when they detect an exception
(the alternative is to quit the gluMainLoop, but we can't do that). As a
trade-off, have the exit behaviour dependant on some environment setting:
. gluMainLoop(suppress_exceptions=1)
. gluMainLoopSuppressExceptions
. os.environ['GLU_MAINLOOP_SUPPRESS_EXCEPTIONS'] = 1
Richard
|
|
From: Mike C. F. <mcf...@ho...> - 2001-10-07 06:58:50
|
So each handler needs to be something like:
def x( a,b ):
try:
try:
doWhatever
except (X,Y,MemoryError, IOError): # expected error conditions
pass
finally:
cleanup() # handle restoring state
vs
def x( a,b ):
try:
doWhatever
finally:
cleanup() # handle restoring state
It's possible to define "safe wrapper" functions that share that
exception-catching code, I suppose. Sigh. My reaction is based on my
experiences as a user where, for instance, 3DSMax dumps out because the
dongle got knocked loose, or Tiberean Sun decides to end the whole game
because 1 packet was received too late (timeout exception doesn't get
caught, so the entire program exits, dumping hours of play), or where setup
scripts bomb because a single callback wasn't received due to an unexpected
condition (too many mice on the system, or C drive isn't available, or
sockets can't be initialised). I suppose those (recent) experiences have
tainted my vision.
I will bow to general opinion on this one, as I can see lots of "rigor"
benefits, but from experience with OpenGLContext using PyGame (where an
exception in a handler actually kicks you out of the main loop), I've not
really found the functionality that pleasant to work with. I'm not really a
"rigor" programmer, suppose I'll have to learn.
If we are going to raise something, can we raise the last Python exception,
instead of SystemExit?
Dumb question: Can the glut main loop be restarted if I catch an exception
and decide it was unimportant (if I'm getting SystemExit instead of a real
exception, that's kinda hard to determine, of course)?
I don't really like the environmental variables approach. It makes code
harder to share, since code with one assumption won't readily fit into
another. Rather learn to write straight-jacket code than have a split in
coding styles like that.
Enjoy,
Mike
-----Original Message-----
From: pyo...@li...
[mailto:pyo...@li...]On Behalf Of Richard
Jones
Sent: October 6, 2001 19:05
To: 'PyOpenGL Mailing List'
Subject: Re: [PyOpenGL-Users] Have exceptions terminate glutMainLoop
On Sat, 6 Oct 2001 18:18, Mike C. Fletcher wrote:
> I'm not in agreement regarding the "right way" here.
>
> For instance, if you force an exit on an uncaught exception, then any
> callback raising an exception can cause data loss for the user (a
> spurious/unimportant exception is raised, rather than being able to use
Woah there. I'm of the firm belief that if an exception is not handled in
code, it's never going to be a "spurious/unimportant exception". It is, by
definition, an "exception" to the correct running of the code. It means that
something has happened that the programmer did not expect, and is likely to
cause lots of problems. The Python way of handling exceptions that are not
caught is to terminate the program to avoid complications. Consider that the
exception occurred during processing of the user's data. The
"spurious/unimportant exception" is ignored, and the user is given the
option
to unknowingly save their corrupted data.
> Fail on any exception is nice for scripting/testing environments, but
> kicking out of the whole application in larger projects seems too heavy to
> me. Would redirecting stderr to a log file work? I haven't tried it
> lately, but I think it should be able to catch the exception output.
I suggest that the C callback handlers exit when they detect an exception
(the alternative is to quit the gluMainLoop, but we can't do that). As a
trade-off, have the exit behaviour dependant on some environment setting:
. gluMainLoop(suppress_exceptions=1)
. gluMainLoopSuppressExceptions
. os.environ['GLU_MAINLOOP_SUPPRESS_EXCEPTIONS'] = 1
Richard
_______________________________________________
PyOpenGL Homepage
http://pyopengl.sourceforge.net
_______________________________________________
PyOpenGL-Users mailing list
PyO...@li...
https://lists.sourceforge.net/lists/listinfo/pyopengl-users
|
|
From: Richard J. <ric...@op...> - 2001-10-07 07:13:15
|
On Sun, 7 Oct 2001 17:01, Mike C. Fletcher wrote:
> So each handler needs to be something like:
This code should appear anywhere you are passing control from your code to
somewhere else that could raise an exception. Unless you're _absolutely_
certain it'll never raise that exception. Anything else is just ... I dunno,
"fuzzy" programming. I just can't imagine not handling ... a late packet, or
a loose dongle, or ...
You don't quit, you handle the exception and alert the user "hey, your
dongle's fallen out" or "hey, the network's getting a bit congested".
> def x( a,b ):
> try:
> try:
> doWhatever
> except (X,Y,MemoryError, IOError): # expected error conditions
> pass
> finally:
> cleanup() # handle restoring state
>
> vs
>
> def x( a,b ):
> try:
> doWhatever
> finally:
> cleanup() # handle restoring state
That's exactly what I believe are good programming practices. Mind you,
catching MemoryError and "pass"ing looks very, very dodgy to me :)
> It's possible to define "safe wrapper" functions that share that
> exception-catching code, I suppose. Sigh. My reaction is based on my
> experiences as a user where, for instance, 3DSMax dumps out because the
> dongle got knocked loose, or Tiberean Sun decides to end the whole game
> because 1 packet was received too late (timeout exception doesn't get
> caught, so the entire program exits, dumping hours of play), or where setup
> scripts bomb because a single callback wasn't received due to an unexpected
> condition (too many mice on the system, or C drive isn't available, or
> sockets can't be initialised). I suppose those (recent) experiences have
> tainted my vision.
There's a lot of baaad code out there that has a _lot_ to answer for in terms
of lowering user expectations. Python's exception model is a cinch to use,
and we should use it properly :)
> I will bow to general opinion on this one, as I can see lots of "rigor"
> benefits, but from experience with OpenGLContext using PyGame (where an
> exception in a handler actually kicks you out of the main loop), I've not
> really found the functionality that pleasant to work with. I'm not really
> a "rigor" programmer, suppose I'll have to learn.
>
> If we are going to raise something, can we raise the last Python exception,
> instead of SystemExit?
That'd be nice, but if the gluMainLoop can't be quit, then we're kinda stuck
there.
> I don't really like the environmental variables approach. It makes code
> harder to share, since code with one assumption won't readily fit into
> another. Rather learn to write straight-jacket code than have a split in
> coding styles like that.
I agree on those grounds - it'd be a bad approach.
Richard
|