pylint
pylint copied to clipboard
Check "__slots__" and "@dataclass" attributes
Current problem
The following is valid code but implicates some problems.
from dataclasses import dataclass
@dataclass
class MyClass:
__slots__ = ('foo', 'bar', )
foo: str
def __init__(self):
self.foo = 'one'
self.bar = 'two'
There are two slot variables (foo & bar) but only foo is handled by the @dataclass. For example str(MyClass()) will result in MyClass(foo="one"). The variable bar is missing in that output no matter that it exists.
Desired solution
PyLint should warn about that.
The list of variables in __slot__ do not fit to the list specificied for @dataclass.
Python 3.10 or higher to offer @dataclass(slots=True) to prevent situations like this. So this could be one possible solution PyLint could suggest. But there are also older Python versions still relevant.
Additional context
No response
Thank you for opening the issue, how would you name this new message ?
There is already some slot related messages in the classe checker (https://github.com/pylint-dev/pylint/blob/main/pylint/checkers/classes/class_checker.py#L665), but it seems it could go in the data classes checker (https://github.com/pylint-dev/pylint/blob/main/pylint/checkers/dataclass_checker.py)
Thanks for asking.
how would you name this new message ?
I wonder that there still is an assigning-non-slot. Regarding that existing name I would suggest using declare-non-slot (or define-non-slot). I can't diffrenciate between declare and define.
For the docs and based on assigning-non-slot:
Problematic code
class Student:
__slots__ = ("name",)
name: str
surname: str # [define-non-slot]
Correct code:
class Student:
__slots__ = ("name", "surname")
name: str
surname: str
Hi there! I'm looking for a way to contribute and I'd like to try implementing this feature.
As well as the [define-non-slot] case I can see another case that you might want to warn on:
Problematic code:
class Student:
__slots__ = ("name", "age") # [missing-slot-annotation]
name: str
Correct code:
class Student:
__slots__ = ("name", "age")
name: str
age: int
I'd consider this merely a warning rather than an error as this code will still run with the dataclass decorator, whereas it won't in the [define-non-slot] case.
These checks shouldn't be evaluated if __slots__ contains __dict__.
Sounds like a useful warning to me!
I have an implementation for declare-non-slot at https://github.com/adamtuft/pylint/tree/9499-slots-and-class-annotations, would be very grateful for comments & discussion! I will also implement missing-slot-annotation when I have a little more time.
A few points:
- I thought this check belonged in the class checker instead of the dataclass checker since the problematic code is problematic even without the dataclass decorator. There may be other cases where the class annotations and
__slots__items should match, and making this check dataclass-specific would miss those cases. - I went with
declare-non-slotoverdefine-non-slotas annotating a class feels more like a declaration that such a member exists, rather than a definition of that member. - I made some changes to existing code to factor out some logic into a helper function
_get_classdef_slots_namesas this seemed the cleanest way to re-use existing logic. I hope this is ok. - I've checked that the existing tests still pass and have run the primer tests with
python3 -m pytest -m primer_stdlib --primer-stdlib.
Hey @adamtuft, thanks a lot for working on this ! Do you mind opening a pull request directly from your branch ? (Use "Refs #9499" in the description :) )
@adamtuft do you think this can be closed following the merge of the new checker ?
@adamtuft do you think this can be closed following the merge of the new checker ?
The new checker covers the original issue, but there was also some discussion above of a missing-slot-annotation warning. Would you still want this? It could be implemented later, referencing this (closed) issue.
Let's keep open for discussion about missing-slot-annotation then. I'm +1 myself.