Add runtime `__slots__` attribute to dataclasses (#15649)
Closes https://github.com/python/mypy/issues/15647
diff --git a/mypy/plugins/dataclasses.py b/mypy/plugins/dataclasses.py
index c78a1b3..b1dc016 100644
--- a/mypy/plugins/dataclasses.py
+++ b/mypy/plugins/dataclasses.py
@@ -469,9 +469,15 @@
self._cls,
)
return
-
info.slots = generated_slots
+ # Now, insert `.__slots__` attribute to class namespace:
+ slots_type = TupleType(
+ [self._api.named_type("builtins.str") for _ in generated_slots],
+ self._api.named_type("builtins.tuple"),
+ )
+ add_attribute_to_class(self._api, self._cls, "__slots__", slots_type)
+
def reset_init_only_vars(self, info: TypeInfo, attributes: list[DataclassAttribute]) -> None:
"""Remove init-only vars from the class and reset init var declarations."""
for attr in attributes:
diff --git a/test-data/unit/check-dataclasses.test b/test-data/unit/check-dataclasses.test
index 4a6e737..131521a 100644
--- a/test-data/unit/check-dataclasses.test
+++ b/test-data/unit/check-dataclasses.test
@@ -1547,6 +1547,35 @@
[builtins fixtures/dataclasses.pyi]
+[case testDataclassWithSlotsRuntimeAttr]
+# flags: --python-version 3.10
+from dataclasses import dataclass
+
+@dataclass(slots=True)
+class Some:
+ x: int
+ y: str
+ z: bool
+
+reveal_type(Some.__slots__) # N: Revealed type is "Tuple[builtins.str, builtins.str, builtins.str]"
+
+@dataclass(slots=True)
+class Other:
+ x: int
+ y: str
+
+reveal_type(Other.__slots__) # N: Revealed type is "Tuple[builtins.str, builtins.str]"
+
+
+@dataclass
+class NoSlots:
+ x: int
+ y: str
+
+NoSlots.__slots__ # E: "Type[NoSlots]" has no attribute "__slots__"
+[builtins fixtures/dataclasses.pyi]
+
+
[case testSlotsDefinitionWithTwoPasses1]
# flags: --python-version 3.10
# https://github.com/python/mypy/issues/11821