Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Catching exceptions that don't inherit from Exception

I have a database access module that I call with a query or a command. It figures out what to do with the database, and tries to do it. But, for instance if the query or command string is pathological, the call to the underlying PGDB module can throw an exception.

Some incredibly useful information is returned by PGDB (from PostgreSQL under that), specifically calling out what errors were found in the query or command. This kind of usage of PGDB's various functions retrieves that information:

try:
    pgdb.dothing(mod.withx)
except Exception, e:
    mod.error = 'pgdb.dothing('+str(type(mod.withx))+str(mod.withx)+') failed with: '+str(e)

Then when the class returns, having failed, the object contains the message in .error and viola, I can fix my stupidity in the query or command.

And this all seems to work just fine -- (in Python 2.2.2, which might change to 2.higher someday... but not now -- and never, ever to 3.whatever)

But... I have found this bit of opacity: "exception doesn't have to be inherited from Exception. Thus plain 'except:' catches all exceptions, not only system. String exceptions are one example of an exception that doesn't inherit from Exception"

So here's the question: Why do I care? If an exception is thrown, I want to know why. I don't care where it came from, really, I just want the error message, and I sure don't want Python to come to a crashing halt. That would include if the error came from the string thing or whatever. So except catching everything is good. Or it should be.

Is it that the parameter of Exception means, I won't catch an error if it comes from, for instance, the String innards? And that then, the code will halt with an uncaught exception? And that then I'd need a series of catches for every type that "doesn't inherit from exception" in order to get the behavior I want? Something like this:

try:
    pgdb.dothing(mod.withx)
except Exception, e:
    mod.error = 'pgdb.dothing('+str(type(mod.withx))+str(mod.withx)+') failed with: '+str(e)
except:
    mod.error = 'pgdb.dothing('+str(type(mod.withx))+str(mod.withx)+') failed with: WTF???'

...because that really... kinda sucks.

And, if that's the case, is there some other way I can catch all exceptions of all types and grab the error message for them? It seems like this would be something that is highly, highly desirable (and it also seems like a one-liner should solve it, and it should look somewhat like the former example, rather than the latter.)

Please, before you answer: Yes, I know Python 2.2.2 is old. No, it's not going to be upgraded soon. This is a production system with several million lines of code; it's stable and we want it to remain that way, based upon, "not broken, not fixing."

I just need a solid understanding of this part of the exception process beaten into me. All the explanations seem to be making assumptions about what I know that are... optimistic. :)

Thanks for any insight.

like image 397
fyngyrz Avatar asked Dec 03 '14 21:12

fyngyrz


People also ask

What happens if an exception does not have a matching except clause?

If an exception occurs which does not match the exception named in the except clause, it is passed on to outer try statements; if no handler is found, it is an unhandled exception and execution stops with a message as shown above.

Why you should not catch exception?

Also when you catch all exceptions, you may get an exception that cannot deal with and prevent code that is upper in the stack to handle it properly. The general principal is to catch the most specific type you can. catch(Exception) is a bad practice because it catches all RuntimeException (unchecked exception) too.

Does Baseexception catch all exceptions?

Since Exception is the base class of all exceptions, it will catch any exception.

How do you catch an unknown exception in Python?

Try and except statements are used to catch and handle exceptions in Python. Statements that can raise exceptions are kept inside the try clause and the statements that handle the exception are written inside except clause.


2 Answers

Try this, although this is a bad practice. You should be as explicit as possible when overriding errors.

try:
    ...
except:
    e = sys.exc_info()
    print e

I also suggest taking a look at https://wiki.python.org/moin/HandlingExceptions

like image 86
MeetTitan Avatar answered Sep 28 '22 08:09

MeetTitan


Wow. It's going to take a bit of time to unpack some of the wrong assumptions in this question.

Catching everything is not at all desirable. How can it be? If an exception is raised, that's because something has gone wrong. You can't possibly write code that deals with every error that could ever happen, simply because no code is perfect. So exceptions are raised when unforeseen errors happen, and you write handling code for the ones you know you can handle.

But that still leaves things you can't handle: why would you want to catch those? What would you do, having caught them? There's no point saying "I'll just log them, and carry on", because now your system is in an undefined state. Does that piece of data exist? Don't know. Has it been written to the db? Can't tell. Have you just lost millions in revenue? Search me, guv.

As regards the Python version, if the fact that you are running a production system on an unsupported platform on which a large number of serious vulnerabilities have not only been discovered but actually exploited does not count as "broken", then I don't know what does.

like image 21
Daniel Roseman Avatar answered Sep 28 '22 08:09

Daniel Roseman