By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
440,626 Members | 1,146 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 440,626 IT Pros & Developers. It's quick & easy.

Detecting an active exception

P: n/a
Hello everybody - my first post! And it may be the most monumentally
stupid question ever asked, but I just can't see an answer after several
hours experimenting, searching and reading.

It's simply this - how can a function determine whether or not it's
being called in handling of an exception (ie. there is an "active"
exception, and somewhere upstream on the stack there is an except: block
statement)?

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.

cheers

- John

Jun 1 '07 #1
Share this Question
Share on Google+
5 Replies


P: n/a
"NeBlackCat (lists)" <li***@asd-group.comwrote:
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.
Jun 1 '07 #2

P: n/a
Thanks Duncan - that does clear things up for me on how sys.exc_info()
it actually works!

But it does seem that there is no way to test "am I currently running in
the scope of handling of an exception", which is what I need. If there
was, I could then rely on sys.exc_info() to examine the exception. I'm
implementing something which has to do one thing if called during
exception handling, and another otherwise (and there's no way to
explicitly pass a flag to indicate the situation).

I'm surprised by there apparently not being such a test, I wonder if I
should do a PEP to ask for this feature.

If anyone does know a way to do it in the current implementation, even
by stack examining, I'd love to hear it! :-)

Cheers
- John

Duncan Booth wrote:
"NeBlackCat (lists)" <li***@asd-group.comwrote:

>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.
Jun 2 '07 #3

P: n/a
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)" <li***@asd-group.comwrote:

>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.
Jun 2 '07 #4

P: n/a
Duncan Booth wrote:
"NeBlackCat (lists)" <li***@asd-group.comwrote:
>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.
Duncan, that's a great description that should go in the docs (I suspect
you aren't just quoting from them here). Kristján V. Jónsson has also
raised some great points about this issue in a multi-threaded
multi-processing application architecture both simplified and
complicated by the presence of Stackless, though I can't lay my hands on
any summary of his findings right now.

regards
Steve
--
Steve Holden +1 571 484 6266 +1 800 494 3119
Holden Web LLC/Ltd http://www.holdenweb.com
Skype: holdenweb http://del.icio.us/steve.holden
------------------ Asciimercial ---------------------
Get on the web: Blog, lens and tag your way to fame!!
holdenweb.blogspot.com squidoo.com/pythonology
tagged items: del.icio.us/steve.holden/python
All these services currently offer free registration!
-------------- Thank You for Reading ----------------

Jun 2 '07 #5

P: n/a
NeBlackCat <li***@asd-group.comwrote:
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!).
Why don't you tell us what you are actually trying to achieve and we
can see if we can come up with a more pythonic solution? The fact
that you are running into limits of the language like this as a new
python programmer probably means you aren't thinking in python yet.

--
Nick Craig-Wood <ni**@craig-wood.com-- http://www.craig-wood.com/nick
Jun 3 '07 #6

This discussion thread is closed

Replies have been disabled for this discussion.