Change __getstate__ and __setstate__ to use a dict (#1004) (#1009)

Co-authored-by: Nikola Dipanov <ndipanov@hudson-trading.com>
This commit is contained in:
Nikola Dipanov 2022-08-18 07:59:50 +01:00 committed by GitHub
parent 5ecc39749a
commit 89a890a326
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 61 additions and 3 deletions

View File

@ -922,7 +922,7 @@ class _ClassBuilder:
"""
Automatically created by attrs.
"""
return tuple(getattr(self, name) for name in state_attr_names)
return {name: getattr(self, name) for name in state_attr_names}
hash_caching_enabled = self._cache_hash
@ -931,8 +931,9 @@ class _ClassBuilder:
Automatically created by attrs.
"""
__bound_setattr = _obj_setattr.__get__(self)
for name, value in zip(state_attr_names, state):
__bound_setattr(name, value)
for name in state_attr_names:
if name in state:
__bound_setattr(name, state[name])
# The hash code cache is not included when the object is
# serialized, but it still needs to be initialized to None to

View File

@ -9,6 +9,8 @@ import sys
import types
import weakref
from unittest import mock
import pytest
import attr
@ -743,3 +745,58 @@ def test_slots_super_property_get_shortcut():
assert B(11).f == 121
assert B(17).f == 289
@attr.s(slots=True)
class A:
x = attr.ib()
b = attr.ib()
c = attr.ib()
@pytest.mark.parametrize("cls", [A])
def test_slots_unpickle_after_attr_removed(cls):
"""
We don't assign attributes we don't have anymore if the class has
removed it.
"""
a = cls(1, 2, 3)
a_pickled = pickle.dumps(a)
a_unpickled = pickle.loads(a_pickled)
assert a_unpickled == a
@attr.s(slots=True)
class NEW_A:
x = attr.ib()
c = attr.ib()
with mock.patch(f"{__name__}.A", NEW_A):
new_a = pickle.loads(a_pickled)
assert new_a.x == 1
assert new_a.c == 3
assert not hasattr(new_a, "b")
@pytest.mark.parametrize("cls", [A])
def test_slots_unpickle_after_attr_added(cls):
"""
We don't assign attribute we haven't had before if the class has one added.
"""
a = cls(1, 2, 3)
a_pickled = pickle.dumps(a)
a_unpickled = pickle.loads(a_pickled)
assert a_unpickled == a
@attr.s(slots=True)
class NEW_A:
x = attr.ib()
b = attr.ib()
d = attr.ib()
c = attr.ib()
with mock.patch(f"{__name__}.A", NEW_A):
new_a = pickle.loads(a_pickled)
assert new_a.x == 1
assert new_a.b == 2
assert new_a.c == 3
assert not hasattr(new_a, "d")