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
Add a new declare-non-slot
error code
#9564
base: main
Are you sure you want to change the base?
Add a new declare-non-slot
error code
#9564
Conversation
- Add test case which should report the error code. - Add test case where the error is suppressed due to __dict__ in __slots__. - Add test to detect annotation not in any base class' __slots__ - Add test against false-positive when base doesn't have __slots__ (since there is still then an instance __dict__ thanks to base) - Add test against false-positive when base has __slots__ with __dict__ entry Ignore declare-non-slots for regression_5479.py - This regression test is for "assigning-non-slot" so ignore "declare-non-slots" which also matches this example. Implement check for "declare-non-slot" and 2 new helper methods: - Add method `_check_declare_non_slot` to report "declare-non-slot" error. This method checks `node` and all bases for a valid `__slots__`, gathering the names in all `__slots__` found. If `node` has an annotation not in any `__slots__`, then "declare-non-slot" is reported. - Add helper method `_has_valid_slots` which returns True if a valid `__slots__` is found on a ClassDef (re-use logic from `_check_slots`). - Refactor `_check_redefined_slots` to split out logic for getting `__slots__` names into `_get_classdef_slots_names` helper.
for more information, see https://pre-commit.ci
Codecov ReportAttention: Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #9564 +/- ##
=======================================
Coverage 95.81% 95.82%
=======================================
Files 173 173
Lines 18825 18875 +50
=======================================
+ Hits 18038 18087 +49
- Misses 787 788 +1
|
This comment has been minimized.
This comment has been minimized.
Based on these messages, the error should probably exclude any annotation that looks like a descriptor. I'm assuming that's how such members are implemented but I'll need to look into it. EDIT: upon further reading, an empty |
declare-non-slot
error code
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 great already, thank you. I don't have the time to really review the change at the moment but regarding the CI fail: You can create an example in the doc (see for example bad-chained-comparison : https://github.com/pylint-dev/pylint/tree/main/doc/data/messages/b/bad-chained-comparison) and a changelog entry for towncrier (Some doc here, but you can copy paste an existing fragment of course: https://pylint.readthedocs.io/en/stable/development_guide/contributor_guide/contribute.html#creating-a-pull-request)
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.
Left some comments. Code looks really good, thanks for opening the PR. I intended to have a look at your fork, but this is much easier as I can make in-line comments. Nice job on your first PR!
Thanks very much for the feedback! I'll incorporate suggestions when I have a little more time, hopefully in the next week or so. |
Co-authored-by: Daniël van Noord <13665637+DanielNoord@users.noreply.github.com>
Co-authored-by: Pierre Sassoulas <pierre.sassoulas@gmail.com>
Avoid unnecessary inference if any ancestor has __dict__ in __slots__ Co-authored-by: Pierre Sassoulas <pierre.sassoulas@gmail.com>
Thanks so much for the review comments! I've reflected on my implementation and I think it needs a bit more work 🤔 - just to share a few thoughts:
|
This comment has been minimized.
This comment has been minimized.
- An empty __slots__ is required if a class takes part in multiple inheritance, so assume this is the case if the base class has an empty __slots__ and abort the check. - Abort early if __dict__ found in any __slots__. - No need to call self._has_valid_slots in self._get_classdef_slots_names since we already call it at the start of the check. - Move definition to below E0244 for consistency, remove "'" around %r as this adds extra quotes when formatted.
for more information, see https://pre-commit.ci
This comment has been minimized.
This comment has been minimized.
Re. reporting an error for an empty |
🤖 According to the primer, this change has no effect on the checked open source code. 🤖🎉 This comment was generated for commit 67b5d50 |
Just letting you know that I do want to review this but haven't found the time. I hope to get to this in the next 7 days. |
@@ -1485,6 +1536,24 @@ def _check_functools_or_not(self, decorator: nodes.Attribute) -> bool: | |||
|
|||
return "functools" in dict(import_node.names) | |||
|
|||
def _has_valid_slots(self, node: nodes.ClassDef) -> 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.
I'm on mobile but this seems very similar to _check_slots
. I'm a bit worried that we're duplicating checks and run the risk of code drift.
Have you considered refactoring the other method to serve both purposes?
Type of Changes
Description
Refs #9499
Implement
declare-non-slot
which reports an error when a class has a__slots__
member and a type hint on the class is not present in__slots__
.Details
Tests:
Add test case which should report the error code.
Add test case where the error is suppressed due to
__dict__
in__slots__
.Add test to detect annotation not in any base class's
__slots__
.Add test against false-positive when base doesn't have
__slots__
(since there is still then an instance__dict__
thanks to base)Add test against false-positive when base has
__slots__
with__dict__
entry.Ignore
declare-non-slots
forregression_5479.py
which is forassigning-non-slot
.Implementation:
Implement check for
declare-non-slot
inclass_checker.py
and 2 new helper methods:Add method
_check_declare_non_slot
to reportdeclare-non-slot
error. This method checksnode
and all bases for a valid__slots__
, gathering the names in all__slots__
found. Ifnode
has an annotation not in any__slots__
, thendeclare-non-slot
is reported.Add helper method
_has_valid_slots
which returnsTrue
if a valid__slots__
is found on aClassDef
(re-use logic from_check_slots
).Refactor
_check_redefined_slots
to split out logic for getting__slots__
names into_get_classdef_slots_names
helper, since the same logic can be used by both functions.Some thoughts:
declare-non-slot
overdefine-non-slot
as annotating a class feels more like a declaration that such a member exists, rather than a definition of that member._get_classdef_slots_names
as this seemed the cleanest way to re-use existing logic. I hope this is ok.python3 -m pytest -m primer_stdlib --primer-stdlib
.To Do:
missing-slot-annotation
from Check "__slots__" and "@dataclass" attributes #9499Add documentation (good/bad code examples)Add changelog/towncrier entry