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:
- Switch
PyType_IsSubtype
toPyObject_IsSubclass
. - 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.
- Add tests. Note that
unittest
’sself.assertRaises
function usesissubclass
and does not alert to this bug. (Different symptom, same cause.)
-Mike