This issue tracker has been migrated to GitHub, and is currently read-only.
For more information, see the GitHub FAQs in the Python's Developer Guide.

classification
Title: Pickle fails on frozen dataclass that has slots
Type: behavior Stage: patch review
Components: Versions: Python 3.9, Python 3.8, Python 3.7
process
Status: open Resolution:
Dependencies: Superseder:
Assigned To: eric.smith Nosy List: BTaskaya, ZackerySpytz, acucci, andrei.avk, drhagen, eric.smith, jagaudin, josh.r
Priority: normal Keywords: patch

Created on 2019-03-25 15:18 by drhagen, last changed 2022-04-11 14:59 by admin.

Pull Requests
URL Status Linked Edit
PR 17254 closed python-dev, 2019-11-19 09:27
PR 22459 open ZackerySpytz, 2020-09-30 01:25
Messages (4)
msg338803 - (view) Author: David Hagen (drhagen) Date: 2019-03-25 15:18
If a dataclass is `frozen` and has `__slots__`, then unpickling an instance of it fails because the default behavior is to use `setattr` which `frozen` does not allow.

```
import pickle
from dataclasses import dataclass

@dataclass(frozen=True)
class A:
  __slots__ = ('a',)
  a: int

b = pickle.dumps(A(5))
pickle.loads(b)
```

```
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<string>", line 3, in __setattr__
dataclasses.FrozenInstanceError: cannot assign to field 'a'
```

This has a straightforward workaround, namely to use `object.setattr`.

```
import pickle
from dataclasses import dataclass

@dataclass(frozen=True)
class A:
    __slots__ = ('a',)
    a: int

    def __getstate__(self):
        return dict(
            (slot, getattr(self, slot))
            for slot in self.__slots__
            if hasattr(self, slot)
        )

    def __setstate__(self, state):
        for slot, value in state.items():
            object.__setattr__(self, slot, value)


b = pickle.dumps(A(5))
pickle.loads(b)
```

It would be nice if this was fixed for all frozen, slotted dataclasses.

Originally report on SO: https://stackoverflow.com/questions/55307017/pickle-a-frozen-dataclass-that-has-slots
msg399007 - (view) Author: Andrei Kulakov (andrei.avk) * (Python triager) Date: 2021-08-05 14:08
This was fixed in https://github.com/python/cpython/pull/25786 , and so can be closed.
msg401489 - (view) Author: Andrei Kulakov (andrei.avk) * (Python triager) Date: 2021-09-09 14:57
This actually can't be closed yet as the fix was not backported to 3.9
msg403833 - (view) Author: David Hagen (drhagen) Date: 2021-10-13 13:39
Because the implementation in GH-25786 relies on the new `dataclass(slots=True)` feature (i.e. it does not work if the slots are specified with `__slots__`), I don't think this can be trivially backported to versions before 3.10.
History
Date User Action Args
2022-04-11 14:59:13adminsetgithub: 80605
2021-10-13 13:39:16drhagensetmessages: + msg403833
2021-09-09 14:57:08andrei.avksetmessages: + msg401489
2021-08-05 14:08:28andrei.avksetnosy: + andrei.avk
messages: + msg399007
2020-09-30 01:25:52ZackerySpytzsetnosy: + ZackerySpytz
pull_requests: + pull_request21485
2019-11-19 09:39:13BTaskayasetnosy: + BTaskaya

versions: + Python 3.8, Python 3.9
2019-11-19 09:27:15python-devsetkeywords: + patch
stage: patch review
pull_requests: + pull_request16750
2019-04-25 23:54:18acuccisetnosy: + acucci
2019-04-25 16:53:33josh.rsetnosy: + josh.r
2019-03-25 19:25:19eric.smithsetassignee: eric.smith
2019-03-25 18:05:33jagaudinsetnosy: + jagaudin
2019-03-25 15:50:55xtreaksetnosy: + eric.smith
2019-03-25 15:18:08drhagencreate