Detecting an active exception

NeBlackCat lists at asd-group.com
Sat Jun 2 00:47:46 EDT 2007


I've now also looked at this from a traceback and stack frame walking 
perspective as well and it seems impossible, ie. it see,s impossible to 
create a function AmIHandlingAnException() which would behave as follows:

  try:
      a=a+1
  except:
      pass

  try:
      AmIHandlingAnException()        # returns FALSE
      b = b + 1
  except:
      AmIHandlingAnException()        # returns TRUE
      try:
          AmIHandlingAnException()    # returns TRUE
      except:
          pass
          
  AmIHandlingAnException()            # returns FALSE
      
The only way I can see to do it is to use something like the 'inspect' 
module to walk up the stack and, for each frame, walk lines of code 
backwards to determine whether or not you're in an except: block. Of 
course that would be horribly inefficient.

I'm rather stunned by this (this was the 'easy' bit that I left to 
last!). I can't see a solution unless a) a traceback object is provided 
for the exception handling path as well as (per sys.exc_info()) the 
exception creating path, or b) exception handlers are internally treated 
as new frames (ie. internally, entering an except: clause creates a 
pseudo-function call to the first handling line).

- John



Duncan Booth wrote:
> "NeBlackCat (lists)" <lists at asd-group.com> wrote:
>
>   
>> Depending on what you read, sys.exc_info() is supposed to return 
>> (None,None,None) when there is no active exception, but it seems that
>> it returns info about the last exception when there isn't one
>> currently active.
>>
>> For example:
>>
>> try:
>>     a = a + 1
>> except:
>>     pass
>>
>> print sys.exc_info()
>>
>> produces:
>> <class exceptions.NameError at 0x009648D0>, <exceptions.NameError 
>> instance at 0x00B5E508>, <traceback object at 0x00B5E4E0>
>>
>> Where the traceback object identifies the offending a=a+1 line (of
>> course). 
>>
>> Is there another way of doing this? Note that I can't rely on using 
>> sys.exc_clear() in any solution, unfortunately.
>>     
>
> I think you have misunderstood the definition of when an exception is 
> 'currently active'. When an exception is caught, it remains currently 
> active so long as you are in the same function, or in a function which it 
> calls (i.e. so long as the current scope is still active). When you return 
> from that function the exception is no longer active and the previous 
> exception becomes active (or None if there has not been one or you have 
> used sys.exc_clear()).
>
> Try this:
> --------- t.py -------------
> import sys
>
> def f():
>     try:
>         a = a + 1
>     except:
>         pass
>
>     g()
>     print "f", sys.exc_info()
>
> def g():
>     print "g", sys.exc_info()
>
> def h():
>     f()
>     print "h", sys.exc_info()
>
> h()
> ----------------------------
> The output is:
>
> g (<type 'exceptions.UnboundLocalError'>, UnboundLocalError("local variable 
> 'a' referenced before assignment",), <traceback object at 0x00A8B300>)
> f (<type 'exceptions.UnboundLocalError'>, UnboundLocalError("local variable 
> 'a' referenced before assignment",), <traceback object at 0x00A8B300>)
> h (None, None, None)
>
> As you can see the exception remains 'currently active' only until the 
> function in which it was caught returns.
>   




More information about the Python-list mailing list