Skip to content
Closed
16 changes: 12 additions & 4 deletions src/attr/_make.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
import itertools
import linecache
import sys
import textwrap
import types
import unicodedata
import weakref
Expand Down Expand Up @@ -893,14 +894,14 @@ def _create_slots_class(self):

base_names = set(self._base_names)

names = self._attr_names
names = dict.fromkeys(self._attr_names)
if (
self._weakref_slot
and "__weakref__" not in getattr(self._cls, "__slots__", ())
and "__weakref__" not in names
and not weakref_inherited
):
names += ("__weakref__",)
names["__weakref__"] = ""

cached_properties = {
name: cached_prop.func
Expand All @@ -915,13 +916,16 @@ def _create_slots_class(self):
class_annotations = _get_annotations(self._cls)
for name, func in cached_properties.items():
# Add cached properties to names for slotting.
names += (name,)
# Clear out function from class to avoid clashing.
del cd[name]
additional_closure_functions_to_update.append(func)
annotation = inspect.signature(func).return_annotation
if annotation is not inspect.Parameter.empty:
class_annotations[name] = annotation
doclines = []
if func.__doc__ is not None:
doclines.extend(textwrap.dedent(func.__doc__).splitlines())
names[name] = "\n".join(doclines)

original_getattr = cd.get("__getattr__")
if original_getattr is not None:
Expand Down Expand Up @@ -949,7 +953,7 @@ def _create_slots_class(self):
if self._cache_hash:
slot_names.append(_HASH_CACHE_FIELD)

cd["__slots__"] = tuple(slot_names)
cd["__slots__"] = {slot: names.get(slot) for slot in slot_names}

cd["__qualname__"] = self._cls.__qualname__

Expand Down Expand Up @@ -987,6 +991,10 @@ def _create_slots_class(self):
else:
if match:
cell.cell_contents = cls
# Add the cached properties back to the __dict__ again --
# they won't be used, not being in the *instance* __dict__, but
# Sphinx checks __dict__ directly, and will therefore see these.
cd.update(cached_properties)
return cls

def add_repr(self, ns):
Expand Down
4 changes: 2 additions & 2 deletions tests/test_slots.py
Original file line number Diff line number Diff line change
Expand Up @@ -1034,7 +1034,7 @@ def f(self):
return self.x * 2

assert B(1).f == 2
assert B.__slots__ == ()
assert list(B.__slots__) == []


def test_slots_sub_class_with_actual_slot():
Expand All @@ -1055,7 +1055,7 @@ class B(A):
f: int = attr.ib()

assert B(1, 2).f == 2
assert B.__slots__ == ()
assert list(B.__slots__) == []


def test_slots_cached_property_is_not_called_at_construction():
Expand Down
Loading