On Wed, Feb 24, 2021 at 1:38 AM Irit Katriel <iritkatr...@googlemail.com>
wrote:

>
>
> On Wed, Feb 24, 2021 at 4:39 AM Guido van Rossum <gu...@python.org> wrote:
>
>>
>> OTOH we might reconsider deriving ExceptionGroup from BaseException --
>> maybe it's better to inherit from Exception? I don't think the PEP
>> currently has a clear reason why it must derive from BaseException. I
>> believe it has to do with the possibility that ExceptionGroup might wrap a
>> BaseException instance (e.g. KeyboardInterrupt or SystemExit).
>>
>
>
> That was the reason, and we also said that an ExceptionGroup escaping
> something that isn't supposed to be raising ExceptionGroups is a bug, so if
> you call an API that raises ExceptionGroups it is your responsibility to
> handle them.
>
> We could make ExceptionGroup be an Exception, and refuse to wrap anything
> which is not an Exception. So asyncio either raises KeyboardInterrupt or an
> ExceptionGroup of user exceptions.
>
> Those are quite different directions.
>
>>
Indeed. I don't think we require that all wrapped exceptions derive from
Exception; an important special case in asyncio is CancelledError, which
doesn't derive from Exception. (Ditto for trio.Cancelled.)

It is really worth carefully reading the section I mentioned in Trio's
MultiError v2 issue. But its "plan" seems complex, as it would require
asyncio to define `class TaskGroupError(ExceptionGroup, Exception)` -- that
was fine when we considered this *only* for asyncio, but now that we've
found several other use cases it really doesn't feel right.

Here's a potentially alternative plan, which is also complex, but doesn't
require asyncio or other use cases to define special classes. Let's define
two exceptions, BaseExceptionGroup which wraps BaseException instances, and
ExceptionGroup which only wraps Exception instances. (Names to be
bikeshedded.) They could share a constructor (always invoked via
BaseExceptionGroup) which chooses the right class depending on whether
there are any non-Exception instances being wrapped -- this would do the
right thing for split() and subgroup() and re-raising unhandled exceptions.

Then 'except Exception:' would catch ExceptionGroup but not
BaseExceptionGroup, so if a group wraps e.g. KeyboardError it wouldn't be
caught (even if there's also e.g. a ValueError among the wrapped errors).

Pseudo-code:

class BaseExceptionGroup(BaseException):
    def __new__(cls, msg, errors):
        if cls is BaseExceptionGroup and all(isinstance(e, Exception) for e
in errors):
            cls = ExceptionGroup
        return BaseException.__new__(cls, msg, errors)

class ExceptionGroup(Exception, BaseExceptionGroup):
    pass

-- 
--Guido van Rossum (python.org/~guido)
*Pronouns: he/him **(why is my pronoun here?)*
<http://feministing.com/2015/02/03/how-using-they-as-a-singular-pronoun-can-change-the-world/>
_______________________________________________
Python-Dev mailing list -- python-dev@python.org
To unsubscribe send an email to python-dev-le...@python.org
https://mail.python.org/mailman3/lists/python-dev.python.org/
Message archived at 
https://mail.python.org/archives/list/python-dev@python.org/message/ZFXN3GCNWC6GMZMC3UD56NLGAHGZBLTY/
Code of Conduct: http://python.org/psf/codeofconduct/

Reply via email to