pylint icon indicating copy to clipboard operation
pylint copied to clipboard

Check "__slots__" and "@dataclass" attributes

Open buhtz opened this issue 1 year ago • 9 comments

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

buhtz avatar Mar 13 '24 09:03 buhtz

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)

Pierre-Sassoulas avatar Mar 18 '24 12:03 Pierre-Sassoulas

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

buhtz avatar Mar 18 '24 12:03 buhtz

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__.

adamtuft avatar Apr 19 '24 21:04 adamtuft

Sounds like a useful warning to me!

DanielNoord avatar Apr 20 '24 16:04 DanielNoord

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-slot over define-non-slot as 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_names as 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.

adamtuft avatar Apr 20 '24 19:04 adamtuft

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 :) )

Pierre-Sassoulas avatar Apr 22 '24 11:04 Pierre-Sassoulas

@adamtuft do you think this can be closed following the merge of the new checker ?

Pierre-Sassoulas avatar Jun 06 '24 09:06 Pierre-Sassoulas

@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.

adamtuft avatar Jun 06 '24 09:06 adamtuft

Let's keep open for discussion about missing-slot-annotation then. I'm +1 myself.

Pierre-Sassoulas avatar Jun 06 '24 09:06 Pierre-Sassoulas