From b78f4b536325f77995550f69a260398b8e579734 Mon Sep 17 00:00:00 2001 From: Nikita Sobolev Date: Wed, 12 Jul 2023 22:59:53 +0300 Subject: [PATCH] Add runtime `__slots__` attribute to `attrs` (#15651) This is similar to https://github.com/python/mypy/pull/15649 but for `attrs` :) Refs https://github.com/python/mypy/issues/15647 --- mypy/plugins/attrs.py | 7 +++++++ test-data/unit/check-plugin-attrs.test | 27 ++++++++++++++++++++++++++ 2 files changed, 34 insertions(+) diff --git a/mypy/plugins/attrs.py b/mypy/plugins/attrs.py index 7f1196c168017..0f748cc140e8f 100644 --- a/mypy/plugins/attrs.py +++ b/mypy/plugins/attrs.py @@ -896,6 +896,13 @@ def _add_slots(ctx: mypy.plugin.ClassDefContext, attributes: list[Attribute]) -> # Unlike `@dataclasses.dataclass`, `__slots__` is rewritten here. ctx.cls.info.slots = {attr.name for attr in attributes} + # Also, inject `__slots__` attribute to class namespace: + slots_type = TupleType( + [ctx.api.named_type("builtins.str") for _ in attributes], + fallback=ctx.api.named_type("builtins.tuple"), + ) + add_attribute_to_class(api=ctx.api, cls=ctx.cls, name="__slots__", typ=slots_type) + def _add_match_args(ctx: mypy.plugin.ClassDefContext, attributes: list[Attribute]) -> None: if ( diff --git a/test-data/unit/check-plugin-attrs.test b/test-data/unit/check-plugin-attrs.test index 3d1e2d730af89..88a541c28ac2d 100644 --- a/test-data/unit/check-plugin-attrs.test +++ b/test-data/unit/check-plugin-attrs.test @@ -1676,6 +1676,33 @@ class C: self.c = 2 # E: Trying to assign name "c" that is not in "__slots__" of type "__main__.C" [builtins fixtures/plugin_attrs.pyi] +[case testRuntimeSlotsAttr] +from attr 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/plugin_attrs.pyi] + [case testAttrsWithMatchArgs] # flags: --python-version 3.10 import attr