On Wed, Mar 3, 2021 at 6:57 PM Paul Moore firstname.lastname@example.org wrote:
Sorry, I keep thinking I've finished and you keep making interesting points :-)
On Wed, 3 Mar 2021 at 17:01, Irit Katriel email@example.com wrote:
Raising an ExceptionGroup is an API change. If you call APIs that say
they will raise ExceptionGroups you need to update your code accordingly. If a library doesn't document that it raises ExceptionGroups and then one of those escapes, then that library has a bug. Just like with any other exception type.
In my experience, libraries don't document what exceptions they raise very well. You can call that a bug, but it's a fact of life, I'm afraid. The problem here isn't so much that the library code now raises an exception that it used not to raise, but rather that *the user hitting Ctrl-C* can now result in a different exception surfacing in my code than it used to. Libraries don't re-wrap KeyboardInterrupt, as you pointed out in a previous response, so I can currently write code that traps KeyboardInterrupt, safe in the knowledge that by doing so I'll handle that user action properly. But with PEP 654, libraries might well (indeed, some libraries almost certainly will) start wrapping KeyboardInterrupt in an exception group. That's a backward incompatible change from the perspective of my code's interaction with the user, and I need to re-code my application to deal with it (and worse still, writing that new code in a way that is portable between versions is not particularly straightforward).
This is also true for MemoryError, and many other errors. What makes KeyboardInterrupt special?
For older Pythons you would have to do something like
except KeyboardInterrupt: ... except BaseExceptionGroup: # some stub type in old versions # inspect the contents # if there's a KeyboardInterrupt do what you need to do # reraise the rest
I'd be inclined to suggest that a complete version of this should be included in the "Backward compatibility" part of the PEP, as I honestly don't really know how I'd write that without doing more research. But such an example would make the KeyboardInterrupt case seem more important than it is. Maybe if it's framed as "how to write calling code that's compatible with older versions of Python but still able to handle called code potentially raising exceptions that you need to trap as part of a group", that would be a useful general example.
Or maybe it's not actually something that will be needed that often. I'm not sure - I'm trying to think in terms of pip, where we can't use new features in our own code until we drop support for older versions, but we might potentially rely on a library that uses exception grouping internally on versions where it's available (and that code lets those exception groups escape). It feels like a stretch to claim this is particularly likely, but conversely it's something I can easily imagine *could* happen...
If a library starts raising ExceptionGroups from version 3.X it should probably do that from a new API so people won't have to worry about it just because they are bumping Python version. So I think the cross-version issue is in the case of "I'm calling a user function and I don't know what it is or what it raises", or the "I just want to write all exceptions to the log and ignore them". So this is the "except Exception" case, which will work.