-
-
Notifications
You must be signed in to change notification settings - Fork 30.1k
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
Fix ClassVar as string fails when getting type hints #6824
Conversation
Hello, and thanks for your contribution! I'm a bot set up to make sure that the project can legally accept your contribution by verifying you have signed the PSF contributor agreement (CLA). Unfortunately our records indicate you have not signed the CLA. For legal reasons we need you to sign this before we can look at your contribution. Please follow the steps outlined in the CPython devguide to rectify this issue. When your account is ready, please add a comment in this pull request Thanks again to your contribution and we look forward to looking at it! |
Lib/typing.py
Outdated
self.__forward_value__ = _type_check( | ||
eval(self.__forward_code__, globalns, localns), | ||
"Forward references must evaluate to types.") | ||
self.__forward_value__ = eval(self.__forward_code__, globalns, localns) |
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.
I am not sure just removing the check is the right thing to do. Instead I would rather fix _type_check
.
We can of course abandon any runtime validation, but this should be a conscious decision and goes beyond the scope of this patch.
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.
Well, get_type_hints()
is not running _type_check on non-forward references so I feel it's a bit weird that we do it for forward references only. Why do we need the additional check for that case? It did successfully evaluate after all, just as if you didn't use a ForwardRef.
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.
This is indeed inconsistent, but the proposed solution creates a bigger inconsistency IMO. This code is also called from other places like List['C']
, with this change arbitrary string will be valid. The actual problem is that currently _type_check
is used for two different purposes:
- Check whether something is valid as a type
- Check whether something is valid as a type argument
The proper solution is to disentangle these two. Namely, at this particular position we only need to check if it is a valid type, so we can use a less restrictive check. I think the proper solution would be to add an optional argument to _type_check
to skip the two corresponding checks.
Could you please also add a short |
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.
Review declined.
7861376
to
b8f0472
Compare
The PR has been updated based on comments by @ilevkivskyi and @ambv, added a |
Thanks! ✨ 🍰 ✨ |
(cherry picked from commit 2d2d3b1) Co-authored-by: Nina Zakharenko <[email protected]>
GH-6912 is a backport of this pull request to the 3.7 branch. |
(cherry picked from commit 2d2d3b1) Co-authored-by: Nina Zakharenko <[email protected]>
@@ -998,7 +1005,7 @@ def get_type_hints(obj, globalns=None, localns=None): | |||
if value is None: | |||
value = type(None) | |||
if isinstance(value, str): | |||
value = ForwardRef(value) | |||
value = ForwardRef(value, is_argument=True) |
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.
Sorry for not having time to review this earlier, this all looks good except for the meaning is exactly the opposite to what I expected :-) There are two options:
- Rename
is_argument
tois_not_argument
everywhere (arguably ugly) - Carefully replace
True
withFalse
and vice versa, and update the corresponding checks
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.
@ilevkivskyi cc/ @ambv Yes, I'll have time tomorrow evening on my flight home.
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.
Ivan, I don't think the meaning is reversed? As I understand it:
- "argument" is what's directly an annotation on a function argument and so on; so it includes non-types
- otherwise, it has to be a type (like inside generics)
If you still want to make a change to this, I would prefer renaming to is_annotation
which signifies that we're talking about an entire annotations.
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.
Renaming to is_annotation
is a possible option, but IMO is still less clear than is_argument
with reversed value, since the latter makes simple distinction between these two cases:
List['int']
, here'int'
appears as a type argument in another type'int'
here'int'
appears just as a type
In the first case the rules are stricter, e.g. ClassVar
can't appear as a type argument.
In view of this, the ideal option would be to both rename it to is_type_argument
and reverse False
to True
, but I don't want to ask for too much :-) I will be happy with either option if there will be a short comment explaining what is_argument
/is_annotation
/is_type_argument
means.
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.
Is the term "type argument" used anywhere in typing? I only heard of them being called "generics".
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.
OK, cool, in this case you're right, let's just reverse True with False and vice versa.
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.
@ambv @ilevkivskyi Should I open a new PR for these changes? What's the needed course of action for the backport? #6912
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.
Yes, please make a PR against master branch. Also it makes sense to do this ASAP, since 3.7rc1 is out in one day.
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.
@ilevkivskyi 👍I can work on this tonight. Will you be available to review?
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.
@ilevkivskyi Done! The updated PR is #7039. Please let me know how it looks.
Yes, I will be available until midnight PST |
The CLA label should have been verified before merging this. |
This was during PyCon sprints. I knew the CLA is signed, bugs.python.org was behind. The confirmation there is manual. |
Ah. Instantly recorded signings would be great for sprints. |
Closes python/typing#505