On Sat, Feb 27, 2021 at 2:39 AM Paul Moore <p.f.moore@gmail.com> wrote:
On Fri, 26 Feb 2021 at 23:36, Jim J. Jewett <jimjjewett@gmail.com> wrote:
>
> Whenever I've used except Exception or stronger, it was a sanitary barrier around code that might well do unpredictable or even stupid things.  Adding a new kind of exception that I hadn't predicted -- including ExceptionGroup -- would certainly fit this description, and I want my driver loop to do what I told it.  (Probably log an unexpected exception, and continue with the next record.  I honestly don't even want a page, let alone a crash, because data from outside that barrier ... is often bad, and almost never in ways the on-call person can safely fix.  And if they don't have time to find it in the logs, then it isn't a priority that week.)

This is my biggest concern. Disclaimer: I've yet to read the PEP,
because async makes my head hurt, but I am aware of some of the
background with Trio. Please take this as the perspective of someone
thinking "I don't use async/await in my code, can I assume this
doesn't affect me?"

The PEP doesn't actually do anything with async -- it just uses asyncio as one of the motivating use cases. The spec itself does not use async or asyncio. At some point in the future we might consider adding new APIs to asyncio that can raise ExceptionGroup, but other uses of 'async def' will definitely not be affected.

Our goal for the PEP is that *unless* you're going to use APIs that are documented to raise ExceptionGroup, you won't have to use `except *` nor will you have to deal with ExceptionGroup otherwise.
 
For me, the biggest requirement I would have is that if I have code like:

def safe_fn():
    try:
        do_something_funky()
        return True
    except Exception:
        print("Well, that was a shame...")
        return False

then I am intending to guarantee that calling safe_fn() will never
raise an exception. Obviously, the example is a toy (in reality, I'd
log the error, skip a record, whatever) but that's not the point here
- the point is that I consider it reasonable to expect `except
Exception` to be a hard barrier that allows me to be sure I've covered
everything.

The modification I proposed where we have both BaseExceptionGroup and ExceptionGroup will satisfy this need. It basically means that *unless* you are explicitly using an API that is documented to raise [Base]ExceptionGroup (such as a future variant of asyncio.gather()), you don't have to care about it. The other exception is if you're writing a library for formatting exceptions (like the stdlib traceback.py module).
 
My worry is that if ExceptionGroup exceptions are *not* trapped by
`except Exception`, then code like this is no longer safe. And by
making ExceptionGroup a BaseException subclass, that's what will
happen.

Right, and that's why I am proposing to change the PEP so that your code will remain safe.

Note that the class headings are like this:
```
class BaseExceptionGroup(BaseException): ...
class ExceptionGroup(BaseExceptionGroup, Exception): ...
```
which produces the following MROs:
```
ExceptionGroup -> BaseExceptionGroup -> Exception -> BaseException -> object
                  BaseExceptionGroup ->              BaseException -> object
```


Ultimately, there's a genuine use case for code that says "whatever
happens in the code I call, this is my last line of defense and I want
to be as near to 100% sure as I can be that I regain control at this
point". At the moment, that is spelled `except Exception`. If you're
proposing to change that, even if it's just to require that it be
spelled differently, you're going to break quite a lot of code - and
worse, the code you're breaking will be code that has taken care to
ensure it's written safely, so you're penalising people who *tried to
get stuff right*, which IMO is the worst type of breakage.

I got you.
 
I will at some point read the PEP fully, to better understand the
async side of the story, but for now please consider this as the
perspective of someone who doesn't expect to care about async, and
therefore wants to feel safe in assuming this PEP won't affect them.

There really is no async side. And you will be safe.
 
Paul

PS If you're thinking "but if you were using async, you'd know about
it", consider that I could be using a PyPI library that, for example,
returned stock values. That library switches to using async, and has a
bug that lets an exception group escape. My `except Exception` code is
designed *precisely* to protect me against such bugs, without me
needing to know anything about how the library works...

And it will.

--
--Guido van Rossum (python.org/~guido)