RLS
RLS

Reputation: 41

Python Program is Terminating on Handled Exception

I am editing the question for clarity.

I created a class in a module that imports MySQLdb. I have found that MySQLdb will raise an Exception if the table the user passes to my class does not exist. I am catching that exception, and passing a new one to the client. But even if the client catches my exception, the program still terminates. I have also tried passing to the client the same Exception MySQLdb is giving my class.

Since the client will be calling my method in a loop, passing in various table names, I don't want the program to choke if the table name is bad. I'd like the client's iterations to continue to the next valid table name. Here is a snippet (tableName is an arg pass in to the method):

In my class/module:

    self.tableName = tableName
    try:       
        self.cursor.execute("select * from " + self.tableName + ";") #Will raise Exception if the table does not exist.
    except:
        raise MyException("\n*** " + self.tableName + " does not exist. ***")

In the client:

    tables = ["BadTableName", "GoodTableNameA", "GoodTableNameB","GoodTableNameC"]

    try:
        for table in tables:
            my_method(table) #Exception message gets passed in with BadTableName, but the program ends. Subsequest iterations of this loop never happen
    except Exception, e:
        print e

I would like the client to continue even after calling my_method(BadTableName).

By the way, my_method() is part of a class defined in its own module which the client is importing.

Thank you.

Upvotes: 0

Views: 2759

Answers (5)

abarnert
abarnert

Reputation: 365697

After reading your edited question, I'm not sure which of two problems you're having.


If your problem is just that you just want an exception to only terminate one loop iteration instead of the whole loop, it's just a matter of re-nesting the statements in the obvious way. Instead of this:

try:
    for table in tables:
        my_method(table) #Exception message gets passed in with BadTableName, but the program ends. Subsequest iterations of this loop never happen
except Exception, e:
    print e

Do this:

for table in tables:
    try:
        my_method(table) #Exception message gets passed in with BadTableName, but the program ends. Subsequest iterations of this loop never happen
    except Exception, e:
        print e

On the other hand, if the problem is that the client isn't catching the exception, the problem is most likely that your MyException isn't a subclass of Exception. There are at least three ways this could happen.

Since you're using old-style except syntax (except Exception, e:) instead of new-style (except Exception as e:), you may be using an older Python version that lets you raise classes that don't inherit from BaseException. For example:

class MyException(object):
    def __init__(self, msg):
        pass

try:
    raise MyException("dsfsdf")
except Exception:
    pass

Depending on your Python version, this may fail to raise the MyException and instead raise a TypeError(' Out[11]: TypeError('exceptions must be old-style classes or derived from BaseException, not MyException') (which will get caught), or print a warning, or just silently "work" as you asked it to (meaning you don't catch anything, and your program quits with a traceback).


Meanwhile, even in 2.7, you can still raise old-style classes, which also won't get caught:

class MyException:
    def __init__(self, msg):
        pass

try:
    raise MyException("dsfsdf")
except Exception:
    pass

This will always fail to catch the exception, and your app will quit with a traceback.


Finally, if you inherited from BaseException instead of Exception, then obviously Exception won't catch it.

class MyException(BaseException):
    def __init__(self, msg):
        pass

try:
    raise MyException("dsfsdf")
except Exception:
    pass

Once again, this will always fail to catch what you raised, and you'll quit with a traceback.

Upvotes: 0

Cairnarvon
Cairnarvon

Reputation: 27762

Adding to the other answers: uncaught exceptions will terminate a program, but only after executing the applicable finally block (if any) and any atexit handlers. So in principle, it is possible to continue execution indefinitely after an uncaught exception.

There is no class of exceptions that will just print an error message and continue execution by their nature, though. If you want that, use warnings.

Upvotes: 1

Steven Kane
Steven Kane

Reputation: 11

An uncaught exception will terminate a program. A caught exception will not

If the exception is caught, the stack trace can be output using the traceback module:

http://docs.python.org/2/library/traceback.html#traceback-examples

Upvotes: 0

dm03514
dm03514

Reputation: 55952

Exceptions do not always cause the program to end. From the docs:

Errors detected during execution are called exceptions and are not unconditionally fatal:

If an exception is raised in a try: except block and the except clause is specifying the exception or a super class of the exception it will be handled.

When handling an exception you can inspect it and find out all information related to it. I have never used the traceback module before but it looks like it contains everything you need.

I guess your second question depends on what you want your user to see. Should the exception be shown? (you have access to the traceback). Should just the message be shown? SHould you log the traceback?

Upvotes: 1

tom
tom

Reputation: 19153

1) No, raising an exception doesn't always cause the program to terminate. Uncaught exceptions cause a program to terminate. You can surround code with a try/except block, as follows, to stop the exception from propagating up the stack.

try:
    file = open("foo.txt")
except IOError:
    file = None

2) The code that actually catches the exception has access to the originating stack frame of the exception, and can decide what to do with it.

Re-raise error with original traceback:

try:
    some_function()
except IOError as e:
    raise

Re-raise error with new traceback (almost never as useful as the first case):

try:
    some_function()
except IOError as e:
    raise e

Don't re-raise, and print the exception and traceback:

try:
    some_function()
except IOError as e:
    import traceback
    traceback.print_exc()

Upvotes: 0

Related Questions