You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
I think this behaviour is very surprising as the general behaviour of exceptions based on BaseException is that they propagate over error handling. Currently, we'd need to do something hacky like inherit from SystemExit instead, basically relegating BaseException to something internal.
This issue was mentioned in the PR, and supposed to be adjusted for Python 3.9:
I'm not entirely sure what behavior you expected. Can you describe the bug in terms of what you expected vs. what actually happened? And can you tell us in which Python version this changed? Is it new in 3.11? Finally, the issue you link to has several PRs associated with it. Which of those PRs do you think is the cause of the change in behavior?
Sorry about that. Let's see if I can make things more clear.
I'm not entirely sure what behavior you expected.
For the loop to stop. I.e. ShowStopper should propagate past loop.run_forever().
The de facto¹ standard has been that you derive from Exception for errors, and from BaseException if you want to force an unwind of the stack for other reasons. We've historically used this much like CancelledError in the referenced issue. In our case, it was to abort a deeply nested process on timeout by throwing a class TimeoutException(BaseException).
¹ I would appreciate it if Python could document this stronger. I.e. that try:/except: is an anti-pattern and you should be doing try:/except Exception:.
And can you tell us in which Python version this changed? Is it new in 3.11?
It started in Python 3.8.
To be clear, we have not yet encountered a real problem with this in asyncio. But it takes a long time for Python changes to propagate out to all distributions, so we want to be proactive when we see something that looks like it can cause issues for us down the line.
Finally, the issue you link to has several PRs associated with it. Which of those PRs do you think is the cause of the change in behavior?
My apologies. I followed things back from the commit and didn't notice that the issue had multiple PR. It's PR #13528.
The change is considered a feature. Previously, raising a base exception could violate internal invariants of the event loop machinery, because the event loop would only catch plain Exception. The changed policy handles all exceptions like, exceptKeyboardInterrupt and SystemExit -- those are now special, because it would break too much code to handle them the same way.
If you want to stop the event loop, use asyncio.get_running_loop().stop().
Activity
gvanrossum commentedon Aug 31, 2023
I'm not entirely sure what behavior you expected. Can you describe the bug in terms of what you expected vs. what actually happened? And can you tell us in which Python version this changed? Is it new in 3.11? Finally, the issue you link to has several PRs associated with it. Which of those PRs do you think is the cause of the change in behavior?
CendioOssman commentedon Sep 1, 2023
Sorry about that. Let's see if I can make things more clear.
For the loop to stop. I.e.
ShowStoppershould propagate pastloop.run_forever().The de facto¹ standard has been that you derive from
Exceptionfor errors, and fromBaseExceptionif you want to force an unwind of the stack for other reasons. We've historically used this much likeCancelledErrorin the referenced issue. In our case, it was to abort a deeply nested process on timeout by throwing aclass TimeoutException(BaseException).¹ I would appreciate it if Python could document this stronger. I.e. that
try:/except:is an anti-pattern and you should be doingtry:/except Exception:.It started in Python 3.8.
To be clear, we have not yet encountered a real problem with this in asyncio. But it takes a long time for Python changes to propagate out to all distributions, so we want to be proactive when we see something that looks like it can cause issues for us down the line.
My apologies. I followed things back from the commit and didn't notice that the issue had multiple PR. It's PR #13528.
I.e. changing this:
to
This gives
SystemExitandKeyboardInterruptsome special privilege over other things subclassed fromBaseException.The PR even mentions an approach that looks more appropriate to me:
gvanrossum commentedon Sep 1, 2023
The change is considered a feature. Previously, raising a base exception could violate internal invariants of the event loop machinery, because the event loop would only catch plain
Exception. The changed policy handles all exceptions like, exceptKeyboardInterruptandSystemExit-- those are now special, because it would break too much code to handle them the same way.If you want to stop the event loop, use
asyncio.get_running_loop().stop().