Issue1256374

classification
Title: sys.excepthook patch for Swing exceptions
Type: Severity: normal
Components: Core Versions:
process
Status: closed Resolution: out of date
Dependencies: Superseder:
Assigned To: alex.gronholm Nosy List: alex.gronholm, fwierzbicki, paulfernhout
Priority: low Keywords: patch

Created on 2005-08-11.03:33:48 by paulfernhout, last changed 2013-02-07.22:59:53 by fwierzbicki.

Messages
msg2460 (view) Author: Paul Fernhout (paulfernhout) Date: 2005-08-11.03:33:48
The sys.excepthook functionality does not appear to
catch Swing generated exceptions, only exceptions
generated from straight Jython. This is perhaps because
Swing events happen in a different thread.

As discussed on the Jython users list on 2003-12-01:
"Re: sys.excepthook doesn't affect Swing exception
handling  "
by (Randolph Brown)
http://sourceforge.net/mailarchive/message.php?msg_id=6710944
in order to catch Swing exceptions, there needs to be
some special handling code written in Java. Apparently
there is a hack of:
   System.setProperty("sun.awt.exception.handler",
         "full.name.of.your.Class");
to do so.

For reference, that hack is "temporary", according to:
  http://www.jguru.com/faq/view.jsp?EID=427279
"Note: This method is a temporary hack to work around
the absence of a real API that provides the ability to
replace the event-dispatch thread. The magic
"sun.awt.exception.handler" property will be removed in
a future release."

Clearly this approach has worked for several versions
of Java, but it would be something that might need
future maintenance if Java changesthe API for doing
such hooks.

Still, based on that idea, I put together the following
change to the Jython code in case it is of use to anyone.

First, here is a test case that shows the latest Jython not
handling sys.excepthook in response to code activated
from a menu event. (All three of 2.1, 2.2a, and the
latest CVS seem to have this issue).

==== jython_swing_excepthook_test.py  ===

import sys
from javax.swing import JFrame, JMenuBar, JMenu, JMenuItem

class TestFrame(JFrame):
    def __init__(self):
        JFrame.__init__(self, "Jython excepthook Test")
        self.setBounds(200, 200, 400, 300)

        menuBar = JMenuBar()
        self.setJMenuBar(menuBar)

        fileMenu = JMenu("File")
        menuBar.add(fileMenu)

        menuItem = JMenuItem("Test",
                    actionPerformed=self.test)
        fileMenu.add(menuItem)

    def test(self, event=None):
        print "test exception -- divide by zero attempt
follows"
        x = 1 / 0
        print "divide by zero done"

def MyExceptHook(type, value, traceback):
    print "my exception handler:", type, value, traceback

sys.excepthook = MyExceptHook
frame = TestFrame()
frame.setVisible(1)

# now try the menu item
# and you will get default exception handler, 
# not my exception handler
# unless you apply patch

======================

Here is a patch that makes the exception handler be
called for the latest Jython from CVS. The patch consists
of a new class file (AwtExceptionHandler.java), and a
one line addition to an existing class file (jython.java).

==== AwtExceptionHandler.java ====
package org.python.util;

import org.python.core.Py;

public class AwtExceptionHandler {
      public void handle(Throwable t) {
        // This indirectly calls the excepthook if it
exists
        Py.printException(t, null, null);
      }
}

=========================

One line added to jython.java below to hook up the class...

==== jython.java changes =====

public class jython

...
    public static void main(String[] args) {

+       System.setProperty("sun.awt.exception.handler",
"org.python.util.AwtExceptionHandler");

...

=====================

Now this patch has not been heavily tested; I just got
it working as a proof of concept. Also the
"System.setProperty" line may not be in the best place
to link it in; I suspect there is a more general place
to put it and perhaps it may not be called when Jython
is used in other ways? I just downloaded the Jython
source recently, and this internal exception stuff is
bound to be tricky, and I don't know the Jython
codebase, so think of this as just a pointer in one
possible direction for a bug fix to be mulled over,
rather than the final answer. There may perhaps be
other Java exceptions still not caught. Also, I was
working in Java 1.4.2 (GNU/Linux Blackdown-1.4.2-02),
perhaps Java 1.5 has other options? For example, a
newly added feature in 1.5 (though I'm currently using
1.4.2, so it is unavailable to me) is this function:
 http://java.sun.com/j2se/1.5.0/docs/api/java/lang/Thread.html
"java.lang
Class Thread
static void
setDefaultUncaughtExceptionHandler(Thread.UncaughtExceptionHandler
eh)
          Set the default handler invoked when a thread
abruptly
terminates due to an uncaught exception, and no other
handler has been defined for that thread."

Also, I was not too sure about passing those two nulls to
"Py.printException(t, null, null);". Maybe they could
be something else?

Anyway, there was discussion in that thread above from
2003-12-01 of making a flag somewhere to set this
behavior and questioning what the default expectation
should be. Personally I think an excepthook in Python
should always fire on any exception, but I could see
not changing default behavior if people rely on it
already, especially if they call
Jython from Java and expect Java to be in control of
things. 
msg7363 (view) Author: Frank Wierzbicki (fwierzbicki) Date: 2012-08-10.17:53:34
Paul are you still around and interested in pushing this forward? If so uploading a patch and perhaps some tests would be much easier to evaluate than embedded code. Sorry that this has lingered for so long without a reply :(
msg7389 (view) Author: Paul Fernhout (paulfernhout) Date: 2012-08-11.17:54:59
Frank, 

First, thanks for all the great work you've done with Jython, and thanks for getting around to snipping off all these loose ends. I really enjoyed my time using Jython, but I've been doing mostly straight Java work myself lately, so I don't have time or interest to push this issue forward much myself at this point, sorry. This issue was with the Jython version from about seven years ago and running on Java 1.4 (the issue being posted in 2005), so I am not sure how reproducible this issue is at this point or whether the suggestion for resolving it is the best one anymore. However, here are a few comments on the general issue that might be useful to any Jython user encountering this issue or trying to resolve it in some way. These comments suggest you can just mark the issue closed (at least with a likely workaround) at this point.

Later versions of Java have new ways of dealing with uncaught exceptions, like in Java 5, which introduced setDefaultUncaughtExceptionHandler for Thread:
http://docs.oracle.com/javase/1.5.0/docs/api/java/lang/Thread.html#setDefaultUncaughtExceptionHandler%28java.lang.Thread.UncaughtExceptionHandler%29

Still, since the Swing thread has its own exception handler that prints to the console, something else might still need to be done for a Java-based application to intercept such Swing exceptions. Apparently, according to this StackOverflow question, you still need to set the "sun.awt.exception.hander" property in some situations, even in Java 6:
http://stackoverflow.com/questions/5794472/why-bother-with-setting-the-sun-awt-exception-handler-property

So, I don't think using the above by itself would fix this issue. Still, clearly you can handle Swing Event Dispatch Thread exceptions from plain Java, like discussed in these Stack Overflow questions: 
http://stackoverflow.com/questions/4448523/how-can-i-catch-event-dispatch-thread-edt-exceptions
http://stackoverflow.com/questions/95767/how-can-i-catch-awt-thread-exceptions-in-java

It is suggested in an answer at the last link that Java7 may have fixed this, so that the uncaught exception handler will cover everything. 

I'm also not quite sure what happens if you try to get hold of the EDT instance directly and call setUncaughtExceptionHandler directly (perhaps by reflection if needed)? However, it seems like Java6 will not allow that, according to this JDK bug report / feature request?
http://bugs.sun.com/view_bug.do?bug_id=6791501

In any case, seven years later, I can hope this could be done entirely from Jython at this point for Java 5 or Java 6? Certainly I would expect it would work from Java 7. 

The big issue back then was that I could not figure out how to get a valid class name string to send into that call to System.setProperty which referenced a Jython-defined exception handler class. Otherwise, a Jython application could then just call System.setProperty directly of course (and that part of the patch probably did not have to be in Java even then). However, I have not tried the latest versions of Jython to know if you could define a class in such a way that the JVM would notice it later. If so, you could set the Event Dispatch Thread hook in the regular way for "sun.awt.exception.handler". But if Jython could do that now (or if perhaps it could do it then and I did not understand how to do that then), then there would be no need for the change I outlined back then.

In that sense, maybe this was (or still is?) more a "bug" about the way Jython defined Java-accessible class names then? Or at least a "bug" in my understanding of how to to pass a string to Java with the full name of a Jython-defined class? You might be the best person to be able to answer off-hand whether a Jython-defined class could looked up by name in the current version of Jython. If there was a way to do that, and it worked when setting this System property, then this patch would be unneeded.

Also, if a new Java-defined exception handling class was for some reason was needed in the end (I'm not sure how Java looks for named classes that are defined later), then it might be possible that a developer could include such a class in a Jar file in the classpath when starting Jython rather than by modifying the Jython codebase itself? I have not tried that though, but I would expect it might work. So, if using a jar file was combined with calling System.setProperty from Jython, I would think there is at the very least a workaround (although I have not tested that). I can wonder if there is also possible that this is an issue of timing -- that once the EDT is started in those earlier versions of Java, maybe it was too late to set that property?

So, probably there are a few plausible workarounds for this issue (including just waiting for Java 7 to become mainstream). In that sense, it's fine by me if you just mark this issue closed. 

--Paul Fernhout
http://www.pdfernhout.net/
====
The biggest challenge of the 21st century is the irony of technologies of abundance in the hands of those thinking in terms of scarcity.
msg7393 (view) Author: Frank Wierzbicki (fwierzbicki) Date: 2012-08-13.18:18:13
Paul: thanks for the extra details!

Alex: I assigned this one to you - but really just to get your opinion since you know so much about Jython/Swing interaction. Hopefully you have some comments or suggestions on what we should do here (if anything). Perhaps it isn't even a bug anymore?
msg7452 (view) Author: Alex Grönholm (alex.gronholm) Date: 2012-09-01.16:38:20
I've been wondering if it's okay for Jython to hijack all the Swing exceptions. In a 100% Jython-Swing app that's fine I suppose, but what of apps that only embed Jython?
msg7490 (view) Author: Alex Grönholm (alex.gronholm) Date: 2012-10-27.22:53:53
The reason this has taken so long is probably as follows:

Jython can be used either by directly launching it or from embedding it into an existing application. If Jython is launched directly, then sure, by all means we should handle all AWT exceptions through the exception hook if it exists. However, if Jython is embedded into the application, it may not be desirable in all situations to mess with the default exception handler. But I would still expect exceptions in Jython code to be handled by the exception hook, even when they're run in the Event Dispatch Thread! However, Java AWT code not called from Jython that throws an exception should not be redirected to the Jython exception hook. Is this even possible to accomplish? I'm such a noob in Jython development that I don't know where to even begin to work on such a solution.

Bottom line: IMHO this patch is too naïve -- a more sophisticated solution is needed.
msg7643 (view) Author: Frank Wierzbicki (fwierzbicki) Date: 2013-02-07.22:59:53
Alex: Since you are our resident Swing expert I'd say we close this.
History
Date User Action Args
2013-02-07 22:59:53fwierzbickisetstatus: open -> closed
resolution: out of date
messages: + msg7643
2012-10-27 22:53:54alex.gronholmsetmessages: + msg7490
2012-09-01 16:38:21alex.gronholmsetmessages: + msg7452
2012-08-13 18:18:13fwierzbickisetassignee: alex.gronholm
messages: + msg7393
nosy: + alex.gronholm
2012-08-11 17:55:01paulfernhoutsetmessages: + msg7389
2012-08-10 17:53:35fwierzbickisetnosy: + fwierzbicki
messages: + msg7363
2008-12-14 17:46:34fwierzbickisetcomponents: + Core, - None
2005-08-11 03:33:48paulfernhoutcreate