Skip to content

[mypyc] Fix pickling and copying frozen dataclasses - #22127

Merged
p-sawicki merged 1 commit into
python:masterfrom
rheard:fix-mypyc-1213
Oct 7, 2026
Merged

p-sawicki merged 1 commit into
python:masterfrom
rheard:fix-mypyc-1213

Conversation

@rheard

@rheard rheard commented Oct 7, 2026

Copy link
Copy Markdown
Contributor

Fixes mypyc/mypyc#1213.

A compiled frozen dataclass can't be pickled or copied, so it can't be sent to a multiprocessing worker either:

import copy
import pickle
from dataclasses import dataclass

@dataclass(frozen=True)
class Config:
    py_version: str = "3"

pickle.loads(pickle.dumps(Config()))  # FrozenInstanceError (works when interpreted)
copy.copy(Config())                   # FrozenInstanceError

The __setstate__ that mypyc gives native classes restored each attribute with PyObject_SetAttr, which calls the class's __setattr__, and the one @dataclass(frozen=True) adds always raises.

CPython restores the state of an object by updating its __dict__ directly, without calling __setattr__, and for a frozen dataclass with slots=True, dataclasses adds a __setstate__ that uses object.__setattr__. Now __setstate__ sets the attributes with PyObject_GenericSetAttr, as object.__setattr__ does. The copies are still frozen.

This only changes anything for classes with their own __setattr__, since PyObject_GenericSetAttr is already the tp_setattro of the others. A native class that defines __setattr__ no longer has it called when an instance is unpickled or copied, which matches CPython for a class without __slots__.

@p-sawicki p-sawicki left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

thanks!

@p-sawicki
p-sawicki merged commit 52ec9fd into python:master Oct 7, 2026
18 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

dataclasses.FrozenInstanceError raised with a multiprocessing.Pool.map and a frozen dataclass as argument

2 participants