Expose PyErr_GivenExceptionMatches in inspect

the try/except exception matching is now documented such that “except does not match virtual subclasses of the specified exception type”

see [doc] clarify that except does not match virtual subclasses of the specified exception type · Issue #56238 · python/cpython · GitHub

I’d like to be able to emulate this behaviour in a few places, such as implementing context managers with def __exit__( eg:

class ExampleContextManager:
    def __enter__(self):
        return self

    def __exit__(self, typ, value, traceback):
        if typ is None:
            return False

        if value is None:
            value = typ()

        if inspect.exceptionmatches(exc, SomeType):
            # handle SomeType case

So I’m proposing a python implementation of PyErr_GivenExceptionMatches be made available as inspect.exceptionmatches

Since PyErr_GivenExceptionMatches is part of the public c api, I don’t see any reason not to expose it in python.

2 Likes

Perhaps it should go in operator, since that’s where function versions of other fundamental operations are exposed. Though it’s obviously very inefficient, here’s a method for a pure-Python implementation:

def exception_matches(exc, expected):
    traceback = exc.__traceback__
    context = exc.__context__
    cause = exc.__cause__
    suppress = exc.__suppress_context__
    try:
        try:
            raise exc
        except expected:
            return True
        except:
            return False
    finally:
        exc.__traceback__ = traceback
        exc.__context__ = context
        exc.__cause__ = cause
        exc.__suppress_context__ = suppress

Wouldn’t a simpler Python implementation just duplicate the high-level exception matching logic?

def exception_matches(exc, expected):
    """Return whether or not "raise exc" will be caught by "except expected"."""
    if isinstance(exc, type):
        return isubclass(exc, expected)
    return isinstance(exc, excepted)

Have I missed any cases, or some other issue?

It would be nice to have an official way to do this. The operator module makes sense to me.

Unlike regular instance checks, exception handling skips all of the various hooks - the abc modules, __class__, __instancecheck__() and __subclasscheck__(), etc. Examining the implementation of PyErr_GivenExceptionMatches() though suggests perhaps a better function to expose PyType_IsSubtype(), since the PyErr_GivenExceptionMatches() just recursively handles tuples and verifies they are exceptions.

1 Like