开发者

How to catch an exception in python and get a reference to the exception, WITHOUT knowing the type?

开发者 https://www.devze.com 2022-12-16 15:37 出处:网络
I\'m wondering how I can catch any raised object (i.e. a type that does not extend Exception), and still get a reference to it.

I'm wondering how I can catch any raised object (i.e. a type that does not extend Exception), and still get a reference to it.

I came across the desire to do this when using Jython. When calling a Java method, if that method raises an exception, it will not extend Python's Exception class, so a block like this will not catch it:

try:
    # some call to a java lib that raises an exception here
except Exception, e:
    # will never be entered

I can do this, but then I have no access to the exception object that was raised.

try:
    # some call to a java lib that raises an exception here
except:
    # will enter here, but there's no reference to the exception that was raised

I can solve this by importing the Java exception type and catching it explicitly, but this makes it difficult/impossible to write generic exception handling wrappers/decorators.

Is there a way to catch some arbitrary exception and still get a reference to it in the except block?

I should note that I'm hoping for the exception handling decorator I am making to be usable with Python projects, not just with Jython projects. I'd like to avoid importing java.lang.Exception because that just makes it Jython-only. For example, I figure I can do something like this (but I haven't tried it), but I'd like to avoid it if I can.

try:
    # some function that may be running jython and may raise a java exception
except (Exception, java.lang.Exception), e:
    # I imagine this would work, but i开发者_如何学Pythont makes the code jython-only


You can reference exceptions using the sys module. sys.exc_info is a tuple of the type, the instance and the traceback.

import sys

try:
    # some call to a java lib that raises an exception here
except:
    instance = sys.exc_info()[1]


FWIW, I have found that if you add this import to your Jython script:

from java.lang import Exception

and just use the conventional Python Exception handler:

except Exception, e:

it will catch both Python exceptions and Java exceptions


Just for anyone interested... I spent a bit of time testing stuff because I wanted to find out how to get a proper stack trace whether a Python Exception (BaseException in fact, which is the base class) or a java.lang.Throwable (java base class for Exception, Error, etc.) is thrown... this code illustrates how to catch all line number refs correctly.

import sys
import traceback
import java

print "hello world"

def custom_hook( type, exc, tb ):
  if isinstance( sys.exc_info()[ 1 ], java.lang.Throwable ):
    sys.stderr.write( "AS JAVA:\n" )
    sys.exc_info()[ 1 ].printStackTrace() # java part
  else:
    sys.stderr.write( "NO JAVA TRACE:\n" )
  sys.stderr.write( "AS PYTHON:\n" )
  traceback.print_exc()

# useful for custom exception handling!
sys.excepthook = custom_hook  

def handle_exc():
# generate either a java.lang.Throwable (uncomment the next line and comment out "a = 16 / 0"
#  java.lang.String( None )
# OR... a python-style BaseException:
  a = 16 / 0 

class Task( java.lang.Runnable ):
  def run( self ):
    # NB the problem with all this stuff is that the Java stack trace shows
    # a java.lang.Throwable occurring at the last line of this code block...
#    print "lots of stuff first"
#    print "lots 2"
#    handle_exc()
#    print "lots 3"
#    print "lots of stuff after"

    try:
      print "lots of stuff first"
      print "lots 2"
      handle_exc()
      print "lots 3"
      print "lots of stuff after"
    # NB do not catch both (Python) BaseException and java.lang.Throwable...   
#    except ( BaseException, java.lang.Throwable ), e:
    # the above means that the line no. in handle_exc is not shown when a BaseException  
    # is thrown...
    except java.lang.Throwable, t:
      tb = sys.exc_info()[ 2 ] 
      sys.stderr.write( "java.lang.Throwable thrown at: %s\n" % tb.tb_lineno )
      raise t

java.awt.EventQueue.invokeAndWait( Task() )

After this one might think of writing a decorator to precede def run( self ) and similar methods so that you don't have to write out this catch-the-Throwable try-except block each time... specifically:

def throw_trap( function ):
  def wrapper(*args, **kvargs):
    try:
      return function( *args, **kvargs )
    except  java.lang.Throwable, t:
      tb = sys.exc_info()[ 2 ]
      while( tb ): 
        sys.stderr.write( "thrown at: %s\n" % tb.tb_lineno )
        tb = tb.tb_next
      raise t
  return wrapper



def handle_exc():
  java.lang.String( None )
#  a = 16 / 0 


class Task( java.lang.Runnable ):
  @throw_trap
  def run( self ):
    print "lots of stuff first"
    print "lots 2"
    handle_exc()
    print "lots 3"
    print "lots of stuff after"

java.awt.EventQueue.invokeAndWait( Task() )
0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号