Re: [PyKDE] problem with exceptions within events

2005-02-25 Thread Phil Thompson
 Hello,

 it seems that Python exceptions generated within event handlers do not get
 propagated correctly. We use a sys.excepthook to abort gracefully with a
 messagebox from our application, and this seems to work in most cases but
 not within event handlers. For instance:

The old (ie. pre-SIP 4.2) behaviour was to call PyErr_Print() if an
exception was raised in a Python re-implementation of a C++ virtual
method. I never really liked this as it meant that the exception couldn't
be caught with try/except.

In SIP 4.2 I removed the calls to PyErr_Print() and added a check for a
Python exception after each called to a C++ method. The theory being that
a try/except around the corresponding Python method call would catch any
exception raised. There turned out to be two problems with this...

- The implementation was buggy. The SIP module was using exceptions in the
meantime - it should have been saving and restoring any existing
exception. With this fixed exceptions are caught properly.

- It only works if the C++ method returns to allow the test for the
exception to be made. The one place where this doesn't happen is
QApplication.exec_loop(). Therefore you still have to rely on providing
your own sys.excepthook. However, it turns out that the excepthook is only
called from within PyErr_Print().

So, rather than try and deal with the two conflicting requirements (being
able to catch as many exceptions as possible, and being able to detect
exceptions in exec_loop()) I plan to simply revert to the pre-SIP 4.2
behaviour - unless anybody has any other bright ideas.

I will do this in the next couple of days, leave it for a week for
feedback, and release SIP 4.2.1.

Phil

___
PyKDE mailing listPyKDE@mats.imk.fraunhofer.de
http://mats.imk.fraunhofer.de/mailman/listinfo/pykde


Re: [PyKDE] problem with exceptions within events

2005-02-25 Thread Giovanni Bajo
Phil Thompson [EMAIL PROTECTED] wrote:

 So, rather than try and deal with the two conflicting requirements (being
 able to catch as many exceptions as possible, and being able to detect
 exceptions in exec_loop()) I plan to simply revert to the pre-SIP 4.2
 behaviour - unless anybody has any other bright ideas.


Is it possible to translate Python exceptions to C++ exceptions? This way,
you can automatic roll out of any C++ method, even blocking ones. Then,
instead of explictly checking for python exception after each c++ method
call, you wrap C++ calls with try/catch, and you get the wrapped Python
exceptions there.

This probably requires Qt compilatoin with exception support (-exceptions).
I would find totally acceptable to have the pre-SIP 4.2 behaviour in case Qt
is compiled without exception support.
-- 
Giovanni Bajo

___
PyKDE mailing listPyKDE@mats.imk.fraunhofer.de
http://mats.imk.fraunhofer.de/mailman/listinfo/pykde


Re: [PyKDE] problem with exceptions within events

2005-02-25 Thread Phil Thompson
 Phil Thompson [EMAIL PROTECTED] wrote:

 So, rather than try and deal with the two conflicting requirements
 (being
 able to catch as many exceptions as possible, and being able to detect
 exceptions in exec_loop()) I plan to simply revert to the pre-SIP 4.2
 behaviour - unless anybody has any other bright ideas.


 Is it possible to translate Python exceptions to C++ exceptions? This way,
 you can automatic roll out of any C++ method, even blocking ones. Then,
 instead of explictly checking for python exception after each c++ method
 call, you wrap C++ calls with try/catch, and you get the wrapped Python
 exceptions there.

 This probably requires Qt compilatoin with exception support
 (-exceptions).
 I would find totally acceptable to have the pre-SIP 4.2 behaviour in case
 Qt
 is compiled without exception support.

Having the behaviour change depending on how the user (or their distro
provider) had built Qt is not a good idea.

Phil

___
PyKDE mailing listPyKDE@mats.imk.fraunhofer.de
http://mats.imk.fraunhofer.de/mailman/listinfo/pykde


Re: [PyKDE] problem with exceptions within events

2005-02-25 Thread Ulrich Berning
Phil Thompson schrieb:
Hello,
it seems that Python exceptions generated within event handlers do not get
propagated correctly. We use a sys.excepthook to abort gracefully with a
messagebox from our application, and this seems to work in most cases but
not within event handlers. For instance:
   

The old (ie. pre-SIP 4.2) behaviour was to call PyErr_Print() if an
exception was raised in a Python re-implementation of a C++ virtual
method. I never really liked this as it meant that the exception couldn't
be caught with try/except.
In SIP 4.2 I removed the calls to PyErr_Print() and added a check for a
Python exception after each called to a C++ method. The theory being that
a try/except around the corresponding Python method call would catch any
exception raised. There turned out to be two problems with this...
- The implementation was buggy. The SIP module was using exceptions in the
meantime - it should have been saving and restoring any existing
exception. With this fixed exceptions are caught properly.
- It only works if the C++ method returns to allow the test for the
exception to be made. The one place where this doesn't happen is
QApplication.exec_loop(). Therefore you still have to rely on providing
your own sys.excepthook. However, it turns out that the excepthook is only
called from within PyErr_Print().
So, rather than try and deal with the two conflicting requirements (being
able to catch as many exceptions as possible, and being able to detect
exceptions in exec_loop()) I plan to simply revert to the pre-SIP 4.2
behaviour - unless anybody has any other bright ideas.
 

To recapitulate:
1.) If a Python method, called asynchronous by QApplication.exec_loop() 
raises an exception, the surrounding C++ method checks this and has to 
use PyErr_Print() to trigger the excepthook (either the default or your 
own excepthook).

2.) If a Python method, called synchronous, raises an exceptions, the 
surrounding C++ method checks this and let the calling Python code 
handle this exception.

Why not inspect the calling frames? A method called asynchronous by 
QApplication.exec_loop() must have exec_loop() in one of it's outer 
frames, a method called synchronous outside the exec_loop doesn't have 
exec_loop() in its outer frames. It's just an idea, don't know if it 
could work.

Ulli


___
PyKDE mailing listPyKDE@mats.imk.fraunhofer.de
http://mats.imk.fraunhofer.de/mailman/listinfo/pykde


Re: [PyKDE] problem with exceptions within events

2005-02-25 Thread Ulrich Berning
Phil Thompson schrieb:
PyQt or any other extension wrapped with SIP could install an optional
exception handler hook, that is called by SIP, indicating how to handle
the exception (propagate to caller or use PyErr_Print()).
   

It's PyErr_Print() that calls the hook, not the other way around. That
hook would have to be installed *after* any application installed hook.
Very messy.
 

Sorry, I wasn't clear enough. I do not mean 'sys.excepthook' or any 
replacement. I mean a function implemented in PyQt called by SIP.

SIP calls a method
SIP checks if an exception has occured
SIP checks, if the wrapped extension has installed a hook function (The 
module that provides exec_loop would do this)
If not, SIP calls PyErr_Print() == End
Otherwise SIP calls the hook funtion
SIP either propagates the exception or calls PyErr_Print() depending on 
the return value of the hook function == End

The hook function has to check, if one of the calling frames of the 
traceback frame contains the method exec_loop.
Maybe I'm totally wrong with my idea.

Ulli

___
PyKDE mailing listPyKDE@mats.imk.fraunhofer.de
http://mats.imk.fraunhofer.de/mailman/listinfo/pykde


Re: [PyKDE] problem with exceptions within events

2005-02-25 Thread Hans-Peter Jansen
Hi Ulli,

On Friday 25 February 2005 16:33, Ulrich Berning wrote:

 The hook function has to check, if one of the calling frames of the
 traceback frame contains the method exec_loop.

That's exactly Phils point: looking for specific methods in the call 
stacks are not only ugly as hell, it's prone to errors: 
- Who prevents users from creating exec_loop methods, functions, ...
- What other methods need this special handling?...

For that reason, Phil looked for a flag based solution, but couldn't 
escape this can o'worms theme..

 Maybe I'm totally wrong with my idea.

No, but it's just not ready for prime time ;-)

Pete

___
PyKDE mailing listPyKDE@mats.imk.fraunhofer.de
http://mats.imk.fraunhofer.de/mailman/listinfo/pykde


Re: [PyKDE] problem with exceptions within events

2005-02-25 Thread Phil Thompson
On Friday 25 February 2005 3:33 pm, Ulrich Berning wrote:
 Phil Thompson schrieb:
 PyQt or any other extension wrapped with SIP could install an optional
 exception handler hook, that is called by SIP, indicating how to handle
 the exception (propagate to caller or use PyErr_Print()).
 
 It's PyErr_Print() that calls the hook, not the other way around. That
 hook would have to be installed *after* any application installed hook.
 Very messy.

 Sorry, I wasn't clear enough. I do not mean 'sys.excepthook' or any
 replacement. I mean a function implemented in PyQt called by SIP.

 SIP calls a method
 SIP checks if an exception has occured
 SIP checks, if the wrapped extension has installed a hook function (The
 module that provides exec_loop would do this)
 If not, SIP calls PyErr_Print() == End
 Otherwise SIP calls the hook funtion
 SIP either propagates the exception or calls PyErr_Print() depending on
 the return value of the hook function == End

 The hook function has to check, if one of the calling frames of the
 traceback frame contains the method exec_loop.
 Maybe I'm totally wrong with my idea.

I can think of a way to make this work - but it's too much of a change for 
a .1 release. I'll restore the old behaviour for the next snapshot (you'll 
have to re-build PyQt) and add it to the list of things for SIP v4.3.

Phil

___
PyKDE mailing listPyKDE@mats.imk.fraunhofer.de
http://mats.imk.fraunhofer.de/mailman/listinfo/pykde


Re: [PyKDE] problem with exceptions within events

2005-02-24 Thread Toby Dickenson
On Thursday 24 February 2005 00:44, Giovanni Bajo wrote:

 I reckon you have slightly misunderstood my problem.

I had misunderstood it too. 

 The problem is: when the exception is raised from within the overriden
 method of an event handler (as opposed to an exception raised from within
 the constructor of a subclass, or from within a slot called by a signal),
 the exception is *totally* ignored. There is no acknowledgement
 whatsoever. Nothing. Nada. I have no way to know that my code did not
 work.

Ive attached a test script based on your original report. I cant reproduce the 
problem here with sip 4.0.1, PyQt 3.1.2, qt 3.3.3

 I would expect the
 exception raised by the event handler to call our custom excepthook just
 like other exceptions raised in different contexts, but it would be fine
 if it *just* printed something on the console. 

Agreed.

-- 
Toby Dickenson


error.py
Description: application/python
about to send event
in event handler
Traceback (most recent call last):
  File error.py, line 8, in customEvent
1/0 # gratuitous exception lets see how it gets handled
ZeroDivisionError: integer division or modulo by zero
you should see an exception logged above


about to post event, should see nothing yet
about to process that event
in event handler
Traceback (most recent call last):
  File error.py, line 8, in customEvent
1/0 # gratuitous exception lets see how it gets handled
ZeroDivisionError: integer division or modulo by zero
you *should* see the same exception logged again.
Giovanni Bajo [EMAIL PROTECTED] reports that it is omitted


___
PyKDE mailing listPyKDE@mats.imk.fraunhofer.de
http://mats.imk.fraunhofer.de/mailman/listinfo/pykde


Re: [PyKDE] problem with exceptions within events

2005-02-24 Thread Giovanni Bajo
Toby Dickenson [EMAIL PROTECTED] wrote:

 Ive attached a test script based on your original report. I cant reproduce
the
 problem here with sip 4.0.1, PyQt 3.1.2, qt 3.3.3


Thanks for doing this.

The problem can be reproduced if you convert your app.processEvents() call
to app.exec_loop(). In that case, I cannot see the traceback anymore.
(Again, I'm using Qt 3.3.4, PyQt 3.14, SIP 4.2).

There is also another difference: on my computer, the script aborts whenever
it hits the first exception. For instance, it aborts on the app.sendEvent()
call, and I never see the following string you should see an exception
above on the screen. Thus, to reproduce the problem with exec_loop(), I
have commented out the first sendEvent() call.

I don't know if it is related, but my Qt is compiled with -no-exceptions. I
know that Python and C++ exceptions are not related, but I don't know if SIP
converts exceptions on bindings boundaries (I know other similar wrapping
tools do that). Could Phil enlighten us on this?


To sum it up. With this script:

=
import sys

def foo(*args):
print except hook
sys.excepthook = foo

from qt import *
app=QApplication([])
class W(QWidget):
def customEvent(self, e):
print  sys.stderr,'in event handler'
1/0 # gratuitous exception lets see how it gets handled
w = W()

#print  sys.stderr,'about to send event'
#app.sendEvent(w, QCustomEvent(QEvent.User))
#print  sys.stderr,'you should see an exception logged above\n\n'

print  sys.stderr, 'about to post event, should see nothing yet'
app.postEvent(w, QCustomEvent(QEvent.User))
print  sys.stderr, 'about to process that event'
app.exec_loop()
print  sys.stderr,'you *should* see the same exception logged again.'
print  sys.stderr,'Giovanni Bajo [EMAIL PROTECTED] reports that it is
omitted\n\n'

print 'done'
=

I get this output:

=
about to post event, should see nothing yet
about to process that event
in event handler
=

-- 
Giovanni Bajo

___
PyKDE mailing listPyKDE@mats.imk.fraunhofer.de
http://mats.imk.fraunhofer.de/mailman/listinfo/pykde


Re: [PyKDE] problem with exceptions within events

2005-02-24 Thread Ulrich Berning
Toby Dickenson schrieb:
On Thursday 24 February 2005 00:44, Giovanni Bajo wrote:
 

I reckon you have slightly misunderstood my problem.
   

I had misunderstood it too. 

 

The problem is: when the exception is raised from within the overriden
method of an event handler (as opposed to an exception raised from within
the constructor of a subclass, or from within a slot called by a signal),
the exception is *totally* ignored. There is no acknowledgement
whatsoever. Nothing. Nada. I have no way to know that my code did not
work.
   

Ive attached a test script based on your original report. I cant reproduce the 
problem here with sip 4.0.1, PyQt 3.1.2, qt 3.3.3

 

I would expect the
exception raised by the event handler to call our custom excepthook just
like other exceptions raised in different contexts, but it would be fine
if it *just* printed something on the console. 
   

Agreed.
 

I have attached a more practical example, that shows the problem in more 
detail. If you use sendEvent(), everything is fine (at least for me) and 
the exepthook function is called. This is because the event is 
immediately processed. With postEvent(), the event processing is 
deferred until control returns to the main loop and the excepthook 
function is not called. I think, this has to do with the fact, that the 
ownership of the event is taken by the post event queue and the event is 
deleted once it has been posted.

In your example you first called sendEvent(), then postEvent() and then 
processEvents(). By calling postEvent() followed by processEvents(), you 
simulate the behavior of sendEvent(). Uncomment the processEvents() call 
in my script and you will get the same result as with sendEvent().

Ulli
#!/usr/bin/env python
##
# Imports#
##
import sys, string, traceback, qt

##
# Excepthook catching unhandled exceptions   #
##
def my_excepthook(exc_type, exc_value, exc_traceback):
sys.stderr.write(in my_excepthook()\n)
trb = string.join(traceback.format_exception(exc_type,
 exc_value,
 exc_traceback))
id =qt.QMessageBox.critical(None,
Unhandled Exception caught,
trb,
qt.QMessageBox.Ignore,
qt.QMessageBox.Abort)
if id == qt.QMessageBox.Abort:
sys.stderr.write(Aborting application...\n)
qt.qApp.exit()
else:
sys.stderr.write(Continuing application... (may give you unexpected 
behavior)\n)

##
# Main widget#
##
class MainWidget(qt.QWidget):
def __init__(self, parent=None, name=None, fl=0):
qt.QWidget.__init__(self, parent, name, fl)

# Create custom event type
self.myEventType = qt.QEvent.Type(qt.QEvent.User)

# Create the widget layout
self.vbox = qt.QVBoxLayout(self, 11, 6)

# A radio button group to select the event method
self.groupMethod = qt.QButtonGroup(1, qt.QGroupBox.Horizontal, Event 
Delivery Method, self)
self.groupMethod.setExclusive(True)
self.vbox.addWidget(self.groupMethod)
self.methodSend = qt.QRadioButton(sendEvent(), self.groupMethod)
self.methodSend.setChecked(True)
self.methodPost = qt.QRadioButton(postEvent(), self.groupMethod)

# A buuton group with a push button
self.groupEvent = qt.QButtonGroup(1, qt.QGroupBox.Horizontal, Generate 
Custom Event, self)
self.vbox.addWidget(self.groupEvent)
self.button = qt.QPushButton(Raises ZeroDivisonError, 
self.groupEvent)
self.connect(self.button, qt.SIGNAL(clicked()), self.slotButton)

# Push button slot
def slotButton(self):
if self.methodPost.isChecked():
qt.qApp.postEvent(self, qt.QCustomEvent(self.myEventType))
#qt.qApp.processEvents()
else:
qt.qApp.sendEvent(self, qt.QCustomEvent(self.myEventType))

# Custom event handler
def customEvent(self, e):
sys.stderr.write(in customEvent()\n)
if e.type() == self.myEventType:
x = 1 / 0

##
# Main programm  #

Re: [PyKDE] problem with exceptions within events

2005-02-24 Thread Giovanni Bajo
Ulrich Berning [EMAIL PROTECTED] wrote:

 I have attached a more practical example, that shows the problem in more
 detail.

Thanks. I would call this a very serious bug.

BTW, let me notice that this does *not only* happen with an explicit
postEvent() call. Even though I am unable to reproduce it in a short snippet
at the moment, it happens also for other events (e.g. paintEvent) in my
application. Just a few minutes ago I had to use the debugger and trace step
by step to find a typo error (raising an exception) within a paintGL()
method, because it was *not* reported at all.

There is something weird going on.
-- 
Giovanni Bajo

___
PyKDE mailing listPyKDE@mats.imk.fraunhofer.de
http://mats.imk.fraunhofer.de/mailman/listinfo/pykde


Re: [PyKDE] problem with exceptions within events

2005-02-24 Thread Giovanni Bajo
Giovanni Bajo [EMAIL PROTECTED] wrote:

 I have attached a more practical example, that shows the problem in more
 detail.

 Thanks. I would call this a very serious bug.

 BTW, let me notice that this does *not only* happen with an explicit
 postEvent() call. Even though I am unable to reproduce it in a short
snippet
 at the moment, it happens also for other events (e.g. paintEvent) in my
 application. Just a few minutes ago I had to use the debugger and trace
step
 by step to find a typo error (raising an exception) within a paintGL()
 method, because it was *not* reported at all.

 There is something weird going on.

Some more information: I tried downgrading to my previous configuration (SIP
4.1.1, PyQt 3.13, Qt 3.3.2) and the problem does not occur anymore. I
verified that it does not occur in either my application or Ulrich's
testcase error_ui.py (after having tweaked for execution with old PyQt which
does not have enum types), so I will assume that error_ui is a faithful
reduction of my problem.

This confirms that this bug is a regression introduced between PyQt 3.13 and
3.14 (or SIP 4.1.1 and 4.2).
-- 
Giovanni Bajo

___
PyKDE mailing listPyKDE@mats.imk.fraunhofer.de
http://mats.imk.fraunhofer.de/mailman/listinfo/pykde


Re: [PyKDE] problem with exceptions within events

2005-02-24 Thread Phil Thompson
 Giovanni Bajo [EMAIL PROTECTED] wrote:

 I have attached a more practical example, that shows the problem in
 more
 detail.

 Thanks. I would call this a very serious bug.

 BTW, let me notice that this does *not only* happen with an explicit
 postEvent() call. Even though I am unable to reproduce it in a short
 snippet
 at the moment, it happens also for other events (e.g. paintEvent) in my
 application. Just a few minutes ago I had to use the debugger and trace
 step
 by step to find a typo error (raising an exception) within a paintGL()
 method, because it was *not* reported at all.

 There is something weird going on.

 Some more information: I tried downgrading to my previous configuration
 (SIP
 4.1.1, PyQt 3.13, Qt 3.3.2) and the problem does not occur anymore. I
 verified that it does not occur in either my application or Ulrich's
 testcase error_ui.py (after having tweaked for execution with old PyQt
 which
 does not have enum types), so I will assume that error_ui is a faithful
 reduction of my problem.

 This confirms that this bug is a regression introduced between PyQt 3.13
 and
 3.14 (or SIP 4.1.1 and 4.2).

That's the information I was waiting for - thanks.

There was a change that was intended to make sure that exceptions raised
in Python re-implementations would ripple through without having to do
anything with exception hooks. I need to check, but I suspect that the
exception is being cleared too soon.

Phil

___
PyKDE mailing listPyKDE@mats.imk.fraunhofer.de
http://mats.imk.fraunhofer.de/mailman/listinfo/pykde