bpo-12029: Exception handling should match subclasses by mbmccoy · Pull Request #6461 · python/cpython (original) (raw)

Exception handling should match subclasses, not subtypes

Example

from abc import ABC

class MyException(Exception, ABC):
    pass

class OtherException(Exception):
    pass

MyException.register(OtherException)

try:
    raise OtherException
except MyException:
    print("Correct: Caught MyException")
except Exception:
    print("Wrong: Caught something else")
    
# "Wrong: Caught something else"

Background and evidence of bug-ness

Issue 2534 [1] (10 years ago!) introduced the behavior, but only in the Python 3 patch [2]. During code review, the correct function call was used [3], but the function's name got switched in the final python3 patch without any comment.

The current Python 2 code uses PyObject_IsSubclass, and produces the correct behavior in the example above (using __metaclass__ = ABCMeta, of course). This leads me to strongly suspect that this is a bug, not a feature. The note below regarding unittest for further evidence that this code has eight legs.

Given the ancient nature of this bug, it affects all versions of python3.

[1] https://bugs.python.org/issue2534
[2] https://bugs.python.org/file11257/isinstance3k-2.patch
[3] https://codereview.appspot.com/483/diff/1/21#newcode114
[4] https://github.com/python/cpython/blob/2.7/Python/errors.c#L119

Solution

Coming very soon in a PR on Github, but in short, we do the following:

  1. Switch PyType_IsSubtype to PyObject_IsSubclass.
  2. Revert the changes made to remove “dead code” in https://bugs.python.org/issue31091. The code was dead because the wrong function was used—the PR left only the bug.
  3. Add tests. Note that unittest’s self.assertRaises function uses issubclass and does not alert to this bug. (Different symptom, same cause.)

-Mike

https://bugs.python.org/issue33271

https://bugs.python.org/issue12029