Skip to content

Commit

Permalink
Fixes __slots__ regression in 0.930 (#11824)
Browse files Browse the repository at this point in the history
Closes #11821
Closes #11827
  • Loading branch information
sobolevn authored and JukkaL committed Jan 5, 2022
1 parent 810f218 commit 3773d2d
Show file tree
Hide file tree
Showing 2 changed files with 72 additions and 3 deletions.
9 changes: 6 additions & 3 deletions mypy/plugins/dataclasses.py
Expand Up @@ -221,9 +221,12 @@ def add_slots(self,
self._ctx.reason,
)
return
if info.slots is not None or info.names.get('__slots__'):

generated_slots = {attr.name for attr in attributes}
if ((info.slots is not None and info.slots != generated_slots)
or info.names.get('__slots__')):
# This means we have a slots conflict.
# Class explicitly specifies `__slots__` field.
# Class explicitly specifies a different `__slots__` field.
# And `@dataclass(slots=True)` is used.
# In runtime this raises a type error.
self._ctx.api.fail(
Expand All @@ -234,7 +237,7 @@ def add_slots(self,
)
return

info.slots = {attr.name for attr in attributes}
info.slots = generated_slots

def reset_init_only_vars(self, info: TypeInfo, attributes: List[DataclassAttribute]) -> None:
"""Remove init-only vars from the class and reset init var declarations."""
Expand Down
66 changes: 66 additions & 0 deletions test-data/unit/check-dataclasses.test
Expand Up @@ -1456,3 +1456,69 @@ class Other:
__slots__ = ('x',)
x: int
[builtins fixtures/dataclasses.pyi]


[case testSlotsDefinitionWithTwoPasses1]
# flags: --python-version 3.10
# https://github.com/python/mypy/issues/11821
from typing import TypeVar, Protocol, Generic
from dataclasses import dataclass

C = TypeVar("C", bound="Comparable")

class Comparable(Protocol):
pass

V = TypeVar("V", bound=Comparable)

@dataclass(slots=True)
class Node(Generic[V]): # Error was here
data: V
[builtins fixtures/dataclasses.pyi]

[case testSlotsDefinitionWithTwoPasses2]
# flags: --python-version 3.10
from typing import TypeVar, Protocol, Generic
from dataclasses import dataclass

C = TypeVar("C", bound="Comparable")

class Comparable(Protocol):
pass

V = TypeVar("V", bound=Comparable)

@dataclass(slots=True) # Explicit slots are still not ok:
class Node(Generic[V]): # E: "Node" both defines "__slots__" and is used with "slots=True"
__slots__ = ('data',)
data: V
[builtins fixtures/dataclasses.pyi]

[case testSlotsDefinitionWithTwoPasses3]
# flags: --python-version 3.10
from typing import TypeVar, Protocol, Generic
from dataclasses import dataclass

C = TypeVar("C", bound="Comparable")

class Comparable(Protocol):
pass

V = TypeVar("V", bound=Comparable)

@dataclass(slots=True) # Explicit slots are still not ok, even empty ones:
class Node(Generic[V]): # E: "Node" both defines "__slots__" and is used with "slots=True"
__slots__ = ()
data: V
[builtins fixtures/dataclasses.pyi]

[case testSlotsDefinitionWithTwoPasses4]
# flags: --python-version 3.10
import dataclasses as dtc

PublishedMessagesVar = dict[int, 'PublishedMessages']

@dtc.dataclass(frozen=True, slots=True)
class PublishedMessages:
left: int
[builtins fixtures/dataclasses.pyi]

0 comments on commit 3773d2d

Please sign in to comment.