Using a bare except:
statement is “almost never a good idea”
according to Python’s documentation:
Because
except:
catches all exceptions, including SystemExit, KeyboardInterrupt, and GeneratorExit (which is not an error and should not normally be caught by user code), using a bareexcept:
is almost never a good idea. In situations where you need to catch all “normal” errors, such as in a framework that runs callbacks, you can catch the base class for all normal exceptions, Exception.
I want to go into more depth to show exactly what can happen with a
bare except:
. I wrote this code in 2015 when working on the E-WORTH
project:
try:
GoalCheckInResponse.objects.create_or_update(
goal_setting_response=resp,
defaults=updated_values)
except:
GoalCheckInResponse.objects.filter(
goal_setting_response=resp,
).delete()
updated_values.update({'goal_setting_response': resp})
GoalCheckInResponse.objects.create(**updated_values)
I remember that my intention here was along the lines of, “try to create or update this response, but if anything goes wrong, it doesn’t matter what, just delete the response in question if it’s there, and make a new one.” Sounds reasonable, right? I thought I was programming cautiously and defensively here.
Sentry recently alerted us of an IntegrityError
triggered in the
except stanza of this code. I did some debugging, trying to come up
with a unit test that reproduced this error. That’s when I found that
the except part of this code was always being used, because the method
I wanted to call is update_or_create(),
and there is no create_or_update()
in Django. Back then I was more
used to Rails than Django, so that explains the mistake. And this
would have been quickly caught by my unit tests if it wasn’t inside a
try/except block that was hiding all exceptions.
Printed from: https://compiled.ctl.columbia.edu/articles/bare-except-statements/