Handling all but one exception

17,553

Solution 1

The answer is to simply do a bare raise:

try:
    ...
except NoChildException:
    # optionally, do some stuff here and then ...
    raise
except Exception:
    # handling

This will re-raise the last thrown exception, with original stack trace intact (even if it's been handled!).

Solution 2

New to Python ... but is not this a viable answer? I use it and apparently works.... and is linear.

try:
    something
except NoChildException:
    assert True
except Exception:
    # handling

E.g., I use this to get rid of (in certain situation useless) return exception FileExistsError from os.mkdir.

That is my code is:

try:
  os.mkdir(dbFileDir, mode=0o700)
except FileExistsError:
  assert True

and I simply accept as an abort to execution the fact that the dir is not somehow accessible.

Solution 3

I'd offer this as an improvement on the accepted answer.

try:
    dosomestuff()
except MySpecialException:
    ttype, value, traceback = sys.exc_info()
    raise ttype, value, traceback
except Exception as e:
    mse = convert_to_myspecialexception_with_local_context(e, context)
    raise mse

This approach improves on the accepted answer by maintaining the original stacktrace when MySpecialException is caught, so when your top-level exception handler logs the exception you'll get a traceback that points to where the original exception was thrown.

Share:
17,553

Related videos on Youtube

Ivan Vulović
Author by

Ivan Vulović

Updated on June 06, 2022

Comments

  • Ivan Vulović
    Ivan Vulović almost 2 years

    How to handle all but one exception?

    try:
        something
    except <any Exception except for a NoChildException>:
        # handling
    

    Something like this, except without destroying the original traceback:

    try:
        something
    except NoChildException:
        raise NoChildException
    except Exception:
        # handling
    
    • Gareth Latty
      Gareth Latty about 11 years
      Simple answer: Don't. It's really bad practice to catch all exceptions, as you will tend to catch ones you didn't mean to, obscuring errors. There are only a tiny number of legitimate cases for doing such a thing.
    • matth
      matth about 11 years
      You seem to have answered your own question. Tell us why you are unsatisfied with what you have.
    • Gareth Latty
      Gareth Latty about 11 years
      @Robᵩ Not quite, his example will make a new exception, not re-raise the old one.
    • Tom Ferguson
      Tom Ferguson over 9 years
      @Lattyware There is no problem with catching all exceptions - e.g. to add extra context then reraising. However, swallowing all exceptions (as this example does), is bad practice.
  • Ivan Vulović
    Ivan Vulović about 11 years
    i agree. but i get this: Fail: Your Patient.update method caught an exception of type ZeroDivisionError when it shouldn't have. You should never use bare except clauses in your code. Only catch raised NoChildExceptions. instead of this: Successfully ignored raised exception of type: ZeroDivisionError Successfully ignored raised exception of type: NameError Successfully ignored raised exception of type: AttributeError Successfully ignored raised exception of type: TypeError Successfully ignored raised exception of type: ValueError Successfully caught raised NoChildException Test Completed
  • Gareth Latty
    Gareth Latty about 11 years
    @IvanVulović So what you want is to only catch NoChildExceptions (which is the exact opposite of what you have asked), so just do try: ... except NoChildException: ..., no need for anything fancy.
  • Reinderien
    Reinderien over 9 years
    Also: never except e/raise e. That swallows the stack trace.
  • wim
    wim about 6 years
    Hmm, nah. If you don't expect any exception in the test, don't catch any. If you do expect it, use with self.assertRaises or with pytest.raises and assert outside the context manager.
  • wim
    wim about 6 years
    This worked in older versions of Python, but now it's a SyntaxError.
  • coyot
    coyot about 6 years
    You are assuming pytest as the framework. Bad assumption.
  • wim
    wim about 6 years
    No, I'm not. self.assertRaises is unittest (stdlib). And nosetests is now deprecated, pytest is probably the most common test framework.
  • coyot
    coyot about 6 years
    I think the folks at nose2.readthedocs.io/en/latest would be very surprised to hear of your claim of deprecation. Especially since Python doesn't deprecate third party libraries, which asks the question, "Deprecated by whom?" . Also, having not done a survey of Python developers, I would be very hesitant to claim which is the most popular, especially in mature products. And to go back to the original point of the test which you missed and which assertRaises doesn't solve, is to test whether handle_it() handles the exception correctly.
  • wim
    wim about 6 years
    1. I guess nose2 is a fork, because nose is really deprecated according to the nose authors. Latest commit was over 2 years ago. 2. For your original point, it just doesn't make sense - if my_module.my_method() doesn't handle IOError, then it will blow up the stack until it gets caught by the test runner - which will fail the test - so there is no need to catch it and assert False inside the test. The test runner already does that job for you. So, that's useless to write into the test manually. Get it?
  • wim
    wim about 6 years
    FWIW, my point stands even for nose runner - there is nose.tools.assert_raises in the original and nose2.tools.such.helper.assertRaises in the newer project you've mentioned.