diff --git a/changelog.d/311.change.rst b/changelog.d/311.change.rst new file mode 100644 index 000000000..85efbe60c --- /dev/null +++ b/changelog.d/311.change.rst @@ -0,0 +1 @@ +In slots classes, ``__getstate__`` and ``__setstate__`` now ignore the ``__weakref__`` attribute. diff --git a/changelog.d/324.change.rst b/changelog.d/324.change.rst new file mode 100644 index 000000000..85efbe60c --- /dev/null +++ b/changelog.d/324.change.rst @@ -0,0 +1 @@ +In slots classes, ``__getstate__`` and ``__setstate__`` now ignore the ``__weakref__`` attribute. diff --git a/src/attr/_make.py b/src/attr/_make.py index 7868a718b..5b95a7ef8 100644 --- a/src/attr/_make.py +++ b/src/attr/_make.py @@ -443,20 +443,26 @@ def _create_slots_class(self): if qualname is not None: cd["__qualname__"] = qualname - attr_names = tuple(self._attr_names) + # __weakref__ is not writable. + state_attr_names = tuple( + an for an in self._attr_names if an != "__weakref__" + ) def slots_getstate(self): """ Automatically created by attrs. """ - return tuple(getattr(self, name) for name in attr_names) + return tuple( + getattr(self, name) + for name in state_attr_names + ) def slots_setstate(self, state): """ Automatically created by attrs. """ __bound_setattr = _obj_setattr.__get__(self, Attribute) - for name, value in zip(attr_names, state): + for name, value in zip(state_attr_names, state): __bound_setattr(name, value) # slots and frozen require __getstate__/__setstate__ to work diff --git a/tests/test_make.py b/tests/test_make.py index 4107bb977..e6a5e23a4 100644 --- a/tests/test_make.py +++ b/tests/test_make.py @@ -4,6 +4,7 @@ from __future__ import absolute_import, division, print_function +import copy import inspect import itertools import sys @@ -1054,3 +1055,16 @@ def fake_meth(self): assert "42" == rv.__module__ == fake_meth.__module__ assert "23" == rv.__qualname__ == fake_meth.__qualname__ + + def test_weakref_setstate(self): + """ + __weakref__ is not set on in setstate because it's not writable in + slots classes. + """ + @attr.s(slots=True) + class C(object): + __weakref__ = attr.ib( + init=False, hash=False, repr=False, cmp=False + ) + + assert C() == copy.deepcopy(C())