Skip to content

fix(reassembly): Deferred(Generic[_KT]) still fails to pickle under protocol 0/1 on GraalPy #2433

Closed

Description

@JarryShaw

Deferred(Generic[_KT]) still fails to pickle under protocol 0/1 on GraalPy, after #2424 explicitly added __getstate__/__setstate__ to fix exactly this for CPython. Found via the experimental: main push runs Discussion thread (run 40909721813, commit 857bd522e), Python graalpy-25.4 (experimental) leg, non-blocking but a real defect:

tests/foundation/reassembly/test_deferred_pickle_2423_unit.py::DeferredPickleTests::test_protocol_0_round_trips
tests/foundation/reassembly/test_deferred_pickle_2423_unit.py::DeferredPickleTests::test_protocol_1_round_trips
tests/foundation/reassembly/test_deferred_pickle_2423_unit.py::DeferredPickleSlotSpellingTests::test_bare_string_slot_round_trips_under_every_protocol (protocol 0/1)
tests/foundation/reassembly/test_deferred_pickle_2423_unit.py::DeferredPickleSlotSpellingTests::test_mangled_slot_round_trips_under_every_protocol (protocol 0/1)

All fail with:

state = base(self)
TypeError: typing.Generic() takes no arguments
/opt/hostedtoolcache/GraalPy/25.4.4/x64/lib/python3.13/copyreg.py:71: TypeError

Root cause: for pickle protocol < 2, copyreg._reduce_ex walks cls.__mro__ before consulting __getstate__, looking for the first base that is not a heap type (or whose __new__ is bound to itself) to compute a base-object state via base(self). On CPython that walk passes through Generic and lands on object (so state = None). On GraalPy, Generic.__new__ apparently satisfies the walk's stopping condition, so base resolves to Generic itself, and Generic(self) raises — #2424's __getstate__/__setstate__ only supplies the dict half of the reduction, not this base-object half, so it doesn't help.

Likely fix: implement Deferred.__reduce_ex__ (or __reduce__) directly for protocol 0/1, bypassing copyreg._reduce_ex's MRO walk entirely, rather than relying on __getstate__ alone — or drop the Generic[_KT] base if it's not load-bearing at runtime (it was added by #2417/#2418 for static typing only, Deferred.__subclasses__/runtime behavior doesn't depend on it).

Non-blocking (experimental GraalPy leg), but real — #2423/#2424's own test file is what's catching it.

Activity

  1. added
    bugIssues reporting a defect (set by the bug report template; a default, not an assessment)
    pythonPull requests that update Python code
    on Oct 29, 2026
  2. added
    wipWork in flight - a covering PR is open or an agent is actively on it
    on Oct 29, 2026
  3. added this to the PyPCAPKit v1.5 milestone on Oct 29, 2026
  4. moved this to Pending in PyPCAPKiton Oct 29, 2026
  5. moved this from Pending to WIP in PyPCAPKiton Oct 29, 2026
  6. added a commit that references this issue on Oct 29, 2026
    1d529f0
  7. removed
    wipWork in flight - a covering PR is open or an agent is actively on it
    on Oct 29, 2026
  8. moved this from WIP to Pending in PyPCAPKiton Oct 29, 2026
  9. added
    wipWork in flight - a covering PR is open or an agent is actively on it
    on Oct 29, 2026
  10. moved this from Pending to WIP in PyPCAPKiton Oct 29, 2026
  11. added 2 commits that reference this issue on Oct 29, 2026
    641331f
    b8ac765
  12. added a commit that references this issue on Oct 29, 2026
    ab178aa
  13. removed
    wipWork in flight - a covering PR is open or an agent is actively on it
    on Oct 29, 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

    bugIssues reporting a defect (set by the bug report template; a default, not an assessment)pythonPull requests that update Python code

    Projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions