4

We are working on a medium-sized commercial Python project and have one reccuring problem when using functions from the standard library.

The documentation of the standard library often does not list all (or even any) exceptions that a function can throw, so we try all the error cases that we can come up with, have a look through the source of the library and then catch whatever is plausible. But quite often we miss that one random error that can still happen, but that we didn't come up with. For example, we missed, that json.loads() can raise a ValueError, if any of the built-in constants are spelled the wrong way (e.g. True instead of true).

In other cases, we tried to just catch Exception, because that part of the code is so critical, that it should never break on an Exception, but should rather try again. The problem here is, that it even caught the KeyboardInterrupt.

So, is there any way to find all exceptions that a function can raise, even if the documentation does not say anything about that? Are there any tools that can determine what exceptions can be raised?

Dakkaron
  • 5,930
  • 2
  • 36
  • 51
  • You could catch `StandardError` if you don't want to catch keyboard interrupts, but there's no tool AFAIK that can statically tell you what errors a function might raise at runtime. – jonrsharpe Jun 29 '16 at 15:17
  • FWIW, `KeyboardInterrupt` doesn't inherit from `Exception` so `except Exception` shouldn't catch `KeyboardInterrupts`... – mgilson Jun 29 '16 at 15:26

1 Answers1

1

There is no real way to do this other than reading all of the possible code paths that can be taken in that function and looking to see what exceptions can be raised there. I suppose some sort of automated tool could be written to do this, but even that is pretty tricky because due to python's dynamic nature, just about any exception could be raised from anywhere (If I really wanted to, I can always patch a dependency function with a different function that raises something else entirely).

Monkey Patching aside, To actually get it right, you'd need a really good type inferencer (maybe astroid could help?) to infer various TypeError or AttributeError that could be raised from accessing non-existent members or calling functions with the wrong arguments, etc. ValueError is particularly tricky because it can still get raised when you pass something of the correct type.

In other cases, we tried to just catch Exception, because that part of the code is so critical, that it should never break on an Exception, but should rather try again. The problem here is, that it even caught the KeyboardInterrupt.

This feels like a bad idea to me. For one, retrying code should only be done for exceptions that might give you a different result if you retry it (weird connectivity issues, etc.). For your ValueError case, you'll just raise the ValueError again. The best case scenario here is that the ValueError is allowed to propagate out of the exception handler on the second call -- The worst case is that you end up in an infinite loop (or RecursionError) that you don't really get much information to help debug.

Catching Exception should be a last resort (and it shouldn't catch KeyboardInterrupt or SystemExit since those don't inherit from Exception) and should probably only format some sort of error message that somebody can use to track down the issue and fix it.

mgilson
  • 300,191
  • 65
  • 633
  • 696
  • Thanks for the answer! The part of the code that I mean was used to send a heartbeat signal over a REST API to signal that a state is still correct. Loosing a few of these signals is completely fine, since only after 10 lost signals the opposite site reacts. But if the Handler crashes completely, because we forgot to catch some obscure exception (in this case it was a timeout-exception) that would be terrible. Generally I really dislike `catch Exception`, but I can't have code in production that might fail randomly because I forgot to catch an exception. – Dakkaron Jun 30 '16 at 09:49
  • At the same time, this makes debugging real errors really hard. I wish, Python had checked exceptions like Java... That would make things so much easier. – Dakkaron Jun 30 '16 at 09:50