Skip to content

A class pickled by value before its annotations are read loses them. #608

Description

@lgray

A summary of the problem from a bot below:

On Python 3.14, a class pickled by value before its annotations have ever been read unpickles with annotations == {}. This happens on cloudpickle 3.1.2, on #603's head (0f652a6), and on master (4af5936).

import subprocess, sys
import cloudpickle

ns = {"__name__": "not_importable"}  # not importable, so the class is pickled by value
exec("class C:\n    x: int\n", ns)
unread = cloudpickle.dumps(ns["C"])
ns["C"].__annotations__  # first read fills __annotations_cache__
read = cloudpickle.dumps(ns["C"])

load = "import pickle, sys; print(pickle.loads(sys.stdin.buffer.read()).__annotations__)"
for tag, blob in [("unread", unread), ("read", read)]:
    out = subprocess.run([sys.executable, "-c", load], input=blob, capture_output=True, check=True)
    print(tag, out.stdout.decode().strip())

Cause: _class_getstate (https://github.com/cloudpipe/cloudpickle/blob/4af5936/cloudpickle/cloudpickle.py#L792-L797) does clsdict.pop("annotate_func", None), with the comment "Python will recreate it when annotations is accessed at unpickling time". Python does not recreate it. Before the first read, the class dict holds only annotate_func, so the pickled state has no annotations at all. After a read, annotations_cache exists and survives. The note in _class_setstate (L1213 (https://github.com/cloudpipe/cloudpickle/blob/4af5936/cloudpickle/cloudpickle.py#L1213-L1215)) makes the same assumption.

#603 (crash report in #585) snapshots annotations for by-value annotate functions. The class path needs the same snapshot: in _class_getstate, evaluate the annotations (for example annotationlib.get_annotations(obj)) into annotations_cache before popping annotate_func. Dataclasses are not affected, because the decorator reads the annotations at class creation. Plain classes whose annotations are first read after pickling (typing introspection, pydantic-style consumers on the worker) lose them silently.

Activity

  1. changed the title [-]Incorrect behavior of annotations when they're empty.[/-] [+]A class pickled by value before its annotations are read loses them.[/+] on Oct 8, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions