-
-
Notifications
You must be signed in to change notification settings - Fork 1.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
Enhance the protocol checker #3259
Enhance the protocol checker #3259
Conversation
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.
Thank you for the PR @craig-sh ! This is going in the right direction, but I left a comment with an improvement we can make to type detection.
pylint/checkers/classes.py
Outdated
if not inferred or inferred is astroid.Uninferable: | ||
return | ||
|
||
if not isinstance(inferred, astroid.Instance) or inferred.name != "bool": |
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.
You can use a Const
node to check if it returns bools or not:
if not isinstance(inferred, astroid.Instance) or inferred.name != "bool": | |
if not isinstance(inferred, astroid.Const) or not isinstance(inferred.value, bool): | |
.... |
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.
Thanks! I'll update my changes!
Hey @craig-sh Let me know if this is ready for review. 😄 You can also switch it from the draft mode. |
Or are you planning to write all the checks from the TODO? No worries if that's the case, was just wondering. |
Hey, yeah Im just finishing the rest of the checks in the TODO |
I've implemented all the protocol functions mentioned in #560 . Just a couple of notes I followed the behavior of the existing I was not sure how to go about checking the elements of a tuple returned by a function invoking For example this PR will raise an error for Is this behavior fine or could you help point me in the right direction to fix it? Thanks! |
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.
Hey @craig-sh This is awesome work, thank you! Left a bunch of comments, overall looks great. Once those are fixed, we can pull this in.
ChangeLog
Outdated
@@ -7,6 +7,11 @@ What's New in Pylint 2.5.0? | |||
|
|||
Release date: TBA | |||
|
|||
* Added errors for some protocol functions (`__hash__`, `__index__`, etc) when |
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.
Would be useful to list all the new errors that were added in the description part of this entry.
doc/whatsnew/2.5.rst
Outdated
@@ -53,3 +53,6 @@ separated list of regexes, that if a name matches will be always marked as a bla | |||
* Mutable ``collections.*`` are now flagged as dangerous defaults. | |||
|
|||
* Add new --fail-under flag for setting the threshold for the score to fail overall tests. If the score is over the fail-under threshold, pylint will complete SystemExit with value 0 to indicate no errors. | |||
|
|||
* Add errors for invalid return types from functions ``__index__``, ``__repr__``, ``__str__``, ``__bytes__``, |
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.
Let's list the new checks as well. Also it should go under the New Checkers
section.
pylint/checkers/classes.py
Outdated
inferred = _safe_infer_call_result(node, node) | ||
# Only want to check types that we are able to infer | ||
if inferred and inferred is not astroid.Uninferable: | ||
call_map = { |
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.
Let's move this dict construction at __init__
level since otherwise we'll create it over and over for every function we visit (which might be a lot for large projects)
pylint/checkers/classes.py
Outdated
|
||
inferred = _safe_infer_call_result(node, node) | ||
# Only want to check types that we are able to infer | ||
if inferred and inferred is not astroid.Uninferable: |
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.
The second part is superfluous, astroid.Uninferable
is falsey in nature.
pylint/checkers/classes.py
Outdated
if SpecialMethodsChecker._is_wrapped_type(node, "int"): | ||
return True | ||
|
||
if isinstance(node, astroid.Const) and isinstance(node.value, int): |
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.
Can simply these three lines to:
if isinstance(node, astroid.Const) and isinstance(node.value, int): | |
return isinstance(node, astroid.Const) and isinstance(node.value, int) |
pylint/checkers/classes.py
Outdated
"__bool__ does not return bool", | ||
"invalid-bool-returned", | ||
"Used when a __bool__ method returns something which is not a bool", | ||
{}, |
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.
The fourth dict
argument should not be needed, let's try removing it.
Hey @PCManticore , thanks for the review! I added the fixes you mentioned, please let me know if there is anything else I can change :) Thanks! |
pylint/checkers/classes.py
Outdated
if SpecialMethodsChecker._is_wrapped_type(node, "str"): | ||
return True | ||
|
||
if isinstance(node, astroid.Const) and isinstance(node.value, str): |
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.
These can all be changed to return isinstance(....)
Hey @craig-sh Thank you for sending this PR! 🎉 |
Steps
doc/whatsnew/<current release.rst>
.Description
Checks return values of protocol functions to see if they are valid types
TODO
__index__
returned non-int__repr__
must return string__str__
must return string__bytes__
must return bytes__getnewargs_ex__
should return a tuple of length 2__getnewargs_ex__
must be a tuple__getnewargs_ex__
must be a dict__getnewargs__
should return a tuple__bool__
should return bool__hash__
should return integer__lenght_hint__
must be an integer__length_hint__
should return >=0__format__
must return stringType of Changes
Related Issue
Closes #560