-
-
Notifications
You must be signed in to change notification settings - Fork 31.4k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
gh-112217: Add check to call result for do_raise()
where cause is a type.
#112216
Conversation
Most changes to Python require a NEWS entry. Add one using the blurb_it web app or the blurb command-line tool. If this change has little impact on Python users, wait for a maintainer to apply the |
do_raise()
where cause is a type.do_raise()
where cause is a type.
Thanks for contributing a fix. You'll need a unit test to demonstrate this problem. Also, please open an issue; all substantive changes to CPython need an accompanying issue. |
do_raise()
where cause is a type.do_raise()
where cause is a type.
Most changes to Python require a NEWS entry. Add one using the blurb_it web app or the blurb command-line tool. If this change has little impact on Python users, wait for a maintainer to apply the |
What is the new output then? class ConstructsNone(BaseException):
@classmethod
def __new__(*args, **kwargs): return None
raise Exception("Printing this exception raises an exception. Mwa-ha-nyaa~ >:3") from ConstructsNone |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
looks good
@sunmy2019 The new output would be: Traceback (most recent call last):
File "/home/apaz/e.py", line 5, in <module>
raise Exception("Printing this exception raises an exception. Mwa-ha-nyaa~~ >:3") from ConstructsNone
TypeError: calling <class '__main__.ConstructsNone'> should have returned an instance of BaseException, not <class 'NoneType'> |
Which Python version are you looking at? I don't see this on main:
This doesn't sound right. The |
If the exception constructor returns an int rather than None, we do get this:
I'm not sure how much we should care. I'm of the view that there is no use case for "raise from Type" and it should never have been a feature. |
But it would shadow the original exception message, right? |
@iritkatriel Yeah, it's minor. I just thought it was really strange that the result of the call was checked for constructing exceptions, but not for constructing causes. I also thought it was strange that printing the exception threw an exception when the cause was I tested on 3.11.2 (Debian), 3.10.13+, and I could have sworn that I tested it on main, but I just recompiled, and you're right, it doesn't do this anymore, at least when the cause is And yeah, I dislike this feature too. @sunmy2019 Yes, it shadows the original exception message. That is (presumably) intentional. Your exception cannot be raised if you passed invalid arguments to |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Seems fine to me.
Errors reported from mistakes in error raising always amuse me, like how raise 42
is invalid so it raises TypeError
.
Most changes to Python require a NEWS entry. Add one using the blurb_it web app or the blurb command-line tool. If this change has little impact on Python users, wait for a maintainer to apply the |
@apaz-cli This needs a news file. There is a form for adding it, which you can reach through the "Details" link next to the failing "bedevere/news" check. |
News file added @iritkatriel |
Consider the following:
In
Python/ceval.c
, indo_raise()
, when you raise an object, cpython checks if it's an exception type, and if it is, constructs it by calling it with no arguments. Then it checks to make sure that what was constructed is in fact an exception.Then it does the same thing for the exception's cause. If it's a type, it constructs the cause by calling it with no arguments. But, for the cause, it actually doesn't check to make sure that the result of the call is in fact an exception, it just stores the result without checking. This seems like a bug. Not a catastrophic one by any means, but probably unintentional considering that the very same condition is checked a few lines above.
That doesn't necessarily explain the result above though. We've created an exception object where the cause is
None
(or any other sort of object that we want). Then, when the interpreter (interactive mode) goes to print the exception, it expects the cause to be an exception. This leads to yet another exception being raised, telling you that the cause is the wrong type.The solution of course is just to add the check when the cause is called.
do_raise()
doesn't make sure the constructed cause is an exception. #112217