Skip to content

Commit 3773d2d

Browse files
sobolevnJukkaL
authored andcommitted
Fixes __slots__ regression in 0.930 (#11824)
Closes #11821 Closes #11827
1 parent 810f218 commit 3773d2d

File tree

2 files changed

+72
-3
lines changed

2 files changed

+72
-3
lines changed

mypy/plugins/dataclasses.py

+6-3
Original file line numberDiff line numberDiff line change
@@ -221,9 +221,12 @@ def add_slots(self,
221221
self._ctx.reason,
222222
)
223223
return
224-
if info.slots is not None or info.names.get('__slots__'):
224+
225+
generated_slots = {attr.name for attr in attributes}
226+
if ((info.slots is not None and info.slots != generated_slots)
227+
or info.names.get('__slots__')):
225228
# This means we have a slots conflict.
226-
# Class explicitly specifies `__slots__` field.
229+
# Class explicitly specifies a different `__slots__` field.
227230
# And `@dataclass(slots=True)` is used.
228231
# In runtime this raises a type error.
229232
self._ctx.api.fail(
@@ -234,7 +237,7 @@ def add_slots(self,
234237
)
235238
return
236239

237-
info.slots = {attr.name for attr in attributes}
240+
info.slots = generated_slots
238241

239242
def reset_init_only_vars(self, info: TypeInfo, attributes: List[DataclassAttribute]) -> None:
240243
"""Remove init-only vars from the class and reset init var declarations."""

test-data/unit/check-dataclasses.test

+66
Original file line numberDiff line numberDiff line change
@@ -1456,3 +1456,69 @@ class Other:
14561456
__slots__ = ('x',)
14571457
x: int
14581458
[builtins fixtures/dataclasses.pyi]
1459+
1460+
1461+
[case testSlotsDefinitionWithTwoPasses1]
1462+
# flags: --python-version 3.10
1463+
# https://github.com/python/mypy/issues/11821
1464+
from typing import TypeVar, Protocol, Generic
1465+
from dataclasses import dataclass
1466+
1467+
C = TypeVar("C", bound="Comparable")
1468+
1469+
class Comparable(Protocol):
1470+
pass
1471+
1472+
V = TypeVar("V", bound=Comparable)
1473+
1474+
@dataclass(slots=True)
1475+
class Node(Generic[V]): # Error was here
1476+
data: V
1477+
[builtins fixtures/dataclasses.pyi]
1478+
1479+
[case testSlotsDefinitionWithTwoPasses2]
1480+
# flags: --python-version 3.10
1481+
from typing import TypeVar, Protocol, Generic
1482+
from dataclasses import dataclass
1483+
1484+
C = TypeVar("C", bound="Comparable")
1485+
1486+
class Comparable(Protocol):
1487+
pass
1488+
1489+
V = TypeVar("V", bound=Comparable)
1490+
1491+
@dataclass(slots=True) # Explicit slots are still not ok:
1492+
class Node(Generic[V]): # E: "Node" both defines "__slots__" and is used with "slots=True"
1493+
__slots__ = ('data',)
1494+
data: V
1495+
[builtins fixtures/dataclasses.pyi]
1496+
1497+
[case testSlotsDefinitionWithTwoPasses3]
1498+
# flags: --python-version 3.10
1499+
from typing import TypeVar, Protocol, Generic
1500+
from dataclasses import dataclass
1501+
1502+
C = TypeVar("C", bound="Comparable")
1503+
1504+
class Comparable(Protocol):
1505+
pass
1506+
1507+
V = TypeVar("V", bound=Comparable)
1508+
1509+
@dataclass(slots=True) # Explicit slots are still not ok, even empty ones:
1510+
class Node(Generic[V]): # E: "Node" both defines "__slots__" and is used with "slots=True"
1511+
__slots__ = ()
1512+
data: V
1513+
[builtins fixtures/dataclasses.pyi]
1514+
1515+
[case testSlotsDefinitionWithTwoPasses4]
1516+
# flags: --python-version 3.10
1517+
import dataclasses as dtc
1518+
1519+
PublishedMessagesVar = dict[int, 'PublishedMessages']
1520+
1521+
@dtc.dataclass(frozen=True, slots=True)
1522+
class PublishedMessages:
1523+
left: int
1524+
[builtins fixtures/dataclasses.pyi]

0 commit comments

Comments
 (0)