Rebase range iterator __reduce__ to match CPython - #8424
Conversation
range_iterator.__reduce__ (and longrange_iterator) returned the original range plus the current index as pickle state; CPython returns the range rebased to the current position with a None state. Rebase start by index * step (clamped to the length) and emit None. __setstate__ is kept so pickles carrying an integer state still load. Assisted-by: Claude Code:claude-opus-4-8
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Path: .coderabbit.yml Review profile: CHILL Plan: Pro Plus Run ID: 📒 Files selected for processing (1)
📝 WalkthroughWalkthrough
ChangesRange iterator reduction
Estimated code review effort: 2 (Simple) | ~10 minutes Possibly related PRs
Suggested reviewers: 🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
youknowone
left a comment
There was a problem hiding this comment.
please add a test about this. copying the example code from original issue to extra_tests/snippets/builtin_range.py or stdlib_pickle.py will be good
Summary
range_iterator.__reduce__(andlongrange_iterator.__reduce__) returned the original range plus the current index as the pickle state, whereas CPython returns the remaining range rebased to the current position with aNonestate. The round-trip result was already correct on both (RustPython restored the index via__setstate__), so this is a representational / cross-compatibility divergence, not data loss.Cause
range_iter_reduceembedded the full original range and passedindexas the third tuple element. BothPyRangeIterator::__reduce__andPyLongRangeIterator::__reduce__go through it.Fix
Rebase the range start by
index * stepand emitNonefor the state. The index is clamped to the length first, because RustPython's iterator increments the index unconditionally, so it can run past the length after exhaustion (unlike CPython, which stops at the length).__setstate__is left intact, so pickles that carry an integer state still load.Test
Verified against CPython 3.14.6 —
__reduce__output now matches for mid-iteration, fresh,reversed, exhausted (range(2, 2)), step > 1, empty, single-element, negative-step,longrange, and__setstate__-advanced iterators.pickle.loads(pickle.dumps(it))round-trips correctly in all cases.test_range: SUCCESS (29 run, 2 skipped — the two skips are a separate, pre-existing__setstate__crash, unrelated to this change).cargo build/cargo clippy -p rustpython-vm/cargo fmt --check: clean.No
@expectedFailuremarker flips here: CPython's owntest_rangehas no test asserting the__reduce__shape, so this is a representational fix, covered for regressions by the existing pickle round-trip tests.Summary by CodeRabbit