Repository navigation
Fix pickling of cached_property descriptors before Python 3.12 - #617
Open
arindamsikder wants to merge 1 commit into
Open
arindamsikder wants to merge 1 commit into
arindamsikder wants to merge 1 commit into
Conversation
Recreate pre-3.12 descriptor locks while preserving descriptor state and instance caches. Regression coverage includes default and protocol 2 roundtrips. Based on the reducer approach in charan-rathore's closed PR cloudpipe#605 and pierreglaser's guidance in cloudpipe#438. AI-assisted implementation and independent automated review; no human pre-review claimed.
|
Thanks for picking this up, and for the generous acknowledgment. The minimal-reducer shape from #605 held up well in my testing, so it's good to see it carried forward here with the self-referential descriptor state and fresh-interpreter evaluation covered. Happy to dig out any context from the closed attempt if it would help the review. Prepared with AI assistance (Instinct assisted). |
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Support serializing classes, instances and standalone
functools.cached_propertydescriptors on Python versions before 3.12.Problem
On Python 3.8–3.11,
cached_propertycontains an internalRLock. Serializing a dynamically defined class or instance with that descriptor fails withTypeError: cannot pickle '_thread.RLock' object. Python 3.12+ removed the internal lock and does not have this failure.Solution
Add an exact-type reducer that reconstructs the descriptor from its getter, lets the constructor create a new internal lock where needed, and restores the descriptor's remaining state. Preserve the assigned attribute name, documentation, custom attributes, repeated references and cycles through descriptor state. On Python 3.12+, preserve a user-defined attribute named
lock.The descriptor does not store cached results; those remain in the instance dictionary and retain the normal instance-serialization behavior. No general lock serializer or arbitrary descriptor-subclass support is added.
Prior work: this follows pierreglaser's minimal-reducer suggestion in #438 and the reducer approach in @charan-rathore's author-closed #605. That PR was not merged; its contribution is acknowledged rather than presented as a new design. The tests here additionally exercise self-referential descriptor state and evaluate reconstructed classes in a fresh interpreter.
Testing
Executed in credential-free, offline Bubblewrap sandboxes on Linux. Private host paths and inherited credentials were absent, outbound networking was unavailable, and imports resolved to the tested checkout. Each interpreter used its own dependency layer.
Interpreter commands inside those sandboxes:
Pinned quality gates from
.pre-commit-config.yaml(Black 25.9.0, Ruff 0.14.3, pre-commit-hooks 6.0.0) ran offline using public hook checkouts and a wheel cache:--files *invocation passes on baseline and final, but skips Black/Ruff because it supplies only root entries. The explicit affected-file invocation runs Black/Ruff and passes on both.--all-filesinvocation is not clean: Black reformats the unchangedtests/cloudpickle_ipykernel_test.pyidentically on baseline and final. Other hooks pass. That unrelated formatting is excluded from this PR; the affected files require no changes.git diff --checkpassed.Other Python versions, PyPy, native Windows/macOS and optional downstream integration jobs were not run locally. No separate type-check or documentation-build gate is configured for these changed files. This remains same-version serialization, not cross-version or long-term pickle compatibility.
Related Issue
Fixes #438.
Related prior implementation: #605.
Automation disclosure: implemented, tested and independently reviewed by AI agents (Hermes DEV / GPT-6-Astra) on behalf of the account owner. No human pre-review is claimed.