3

Using custom exceptions in python (v2.7.3): don't get a stack trace when call getSub() whereas getSub(True) invokes one, the difference being that it is caused via an additional try...except which I want to avoid (+feels unnecessary) so why/how can it be avoided?

import sys, traceback

class customException(Exception):
    def __init__(self, *args):
        super(customException,self).__init__(*args)
        print "Stack trace within exception", traceback.extract_tb(sys.exc_info()[2])
        errTxt = [a for a in args]
        print "error text", errTxt

def getFn():
    try:
        getSub()
    except customException as e:
        print "customException was raised"
    try:
        getSub(True)
    except customException as e:
        print "customException2 was raised"

def getSub(flag=False):
    if flag:
        try:
            1/0
        except:
            raise customException('test')
    else:
        raise customException('test')

getFn()

output:

Stack trace within exception []
error text ['test']
customException was raised
Stack trace within exception [('./test3.py', 25, 'getSub', '1/0')]
error text ['test']
customException2 was raised

To put the above in context I have code (pseudo) along the below lines and it wasn’t until I boiled down the code to the above example that I realised why the traceback access was not always working. The purpose of the custom exception class is to collect an aggregate count of exceptions in order to classify downstream the result of each do_something, e.g. fatal, warning etc. The use of the traceback was to record from WHERE the exception was ‘raised’ and therefore the creation of an exception (1/0 = albeit seems out of place) enables that to work. Wondering about using the inspect module rather than thinking about this within the traceback stack?

__main__
With each item in set:
    Try:
        do_something(item)
    except customException()
        clean up = log info etc.
end With
end.__main__

do_something(item)
    try:
        check_something()
    except customException
        if exception=typeA.1 raise customException(Type1)
        if exception=typeB.2 and item = ‘x’
            raise customException(Type2)

check_something()
    a = getInfo()
    unless getInfo()
        raise customException(typeA.1)
    try:
        b = getOtherInfo()
    except customException
        raise customException(typeB.2)
    …
macib
  • 31
  • 4
  • Are you asking why your `extract_tb` stuff doesn't work in the first case? There is no exception to be found in the traceback at the time you create the `customException` instance. – BrenBarn Jan 28 '14 at 19:04

2 Answers2

3

If I understand you right, you're wondering why your print "Stack trace within exception" line prints an empty list for getSub(), but prints some traceback info for getSub(True).

You have code in your exception class's __init__ to look at the most recent exception via sys.exc_info. When you do raise customException('test'), customException('test') is evaluated first on its own, before it "knows" that it is going to be raised as an exception. So when you do that raise in getSub(), there is no most recent exception.

With getSub(True), there is a most recent exception, because the 1/0 raises an exception before you create your customException. Note that when you do 1/0, the most recent exception is the one from that 1/0; you can see that there's nothing about your customException in that traceback.

An exception object has to be created before the exception is raised. So you can't look at "the current exception" in your exception class's __init__ to get info about the stack trace that will be created when it is raised, because it hasn't been raised yet at that time.

If you want, you could use traceback.extract_stack to get the call stack at the time the exception object is created, but there's no guarantee that that has anything to do with when it will be raised. Just because an instance of your exception class is created doesn't even mean it will ever be raised at all. It's perfectly legal (although generally pointless) for someone to just create an exception object with stuff = customException('blah') but never actually raise the exception.

In any case, it's not clear from your question what you're trying to achieve here. It would help if you explained that.

BrenBarn
  • 242,874
  • 37
  • 412
  • 384
0

Because you're catching the exception, there will be no traceback unless you either explicitly re-raise

try:
    getSub(True)
except customException as e:
    print "customException2 was raised"
    raise    # add this to re-raise, with original traceback

or print it yourself:

try:
    getSub(True)
except customException as e:
    print "customException2 was raised"
    print traceback.format_exc()
mhlester
  • 22,781
  • 10
  • 52
  • 75
  • I don't think this is what he's asking. No traceback is actually printed for either case, but he says that the traceback *is* created for `getSub(True)`. So I think what he means by "printing the traceback" is his own printing of the traceback info within his class's `__init__`. – BrenBarn Jan 28 '14 at 19:13
  • Ah ok, you're probably right. Will delete my answer once OP weighs in (accepts yours or comments here) – mhlester Jan 28 '14 at 19:19