Skip to content

Commit 3a33fe4

Browse files
aseembits93claude
andcommitted
fix: support Python 3.10-3.14 in comparator itertools tests
Handle itertools.cycle on Python 3.14 where __reduce__ was removed by falling back to element-by-element sampling. Add version guards for pairwise (3.10+) and batched (3.12+) tests. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent eeda6c2 commit 3a33fe4

2 files changed

Lines changed: 29 additions & 15 deletions

File tree

codeflash/verification/comparator.py

Lines changed: 22 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -544,20 +544,28 @@ def comparator(orig: Any, new: Any, superset_obj: bool = False) -> bool:
544544
# __reduce__ returns (cls, (remaining_iter,), (saved_items, first_pass_done)).
545545
# NOTE: consuming the remaining_iter is destructive to the cycle object, but this is
546546
# acceptable since the comparator is the final consumer of captured return values.
547-
# NOTE: __reduce__ on itertools is deprecated and will be removed in Python 3.14.
548-
with warnings.catch_warnings():
549-
warnings.simplefilter("ignore", DeprecationWarning)
550-
orig_reduce = orig.__reduce__()
551-
new_reduce = new.__reduce__()
552-
orig_remaining = list(orig_reduce[1][0])
553-
new_remaining = list(new_reduce[1][0])
554-
orig_saved, orig_started = orig_reduce[2]
555-
new_saved, new_started = new_reduce[2]
556-
if orig_started != new_started:
557-
return False
558-
return comparator(orig_remaining, new_remaining, superset_obj) and comparator(
559-
orig_saved, new_saved, superset_obj
560-
)
547+
# NOTE: __reduce__ on itertools.cycle was removed in Python 3.14.
548+
try:
549+
with warnings.catch_warnings():
550+
warnings.simplefilter("ignore", DeprecationWarning)
551+
orig_reduce = orig.__reduce__()
552+
new_reduce = new.__reduce__()
553+
orig_remaining = list(orig_reduce[1][0])
554+
new_remaining = list(new_reduce[1][0])
555+
orig_saved, orig_started = orig_reduce[2]
556+
new_saved, new_started = new_reduce[2]
557+
if orig_started != new_started:
558+
return False
559+
return comparator(orig_remaining, new_remaining, superset_obj) and comparator(
560+
orig_saved, new_saved, superset_obj
561+
)
562+
except TypeError:
563+
# Python 3.14+: __reduce__ removed. Fall back to consuming elements from both
564+
# cycles and comparing. Since the comparator is the final consumer, this is safe.
565+
sample_size = 200
566+
orig_sample = [next(orig) for _ in range(sample_size)]
567+
new_sample = [next(new) for _ in range(sample_size)]
568+
return comparator(orig_sample, new_sample, superset_obj)
561569

562570
# Handle remaining itertools types (chain, islice, starmap, product, permutations, etc.)
563571
# by materializing into lists. count/repeat/cycle are already handled above.

tests/test_comparator.py

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -690,12 +690,18 @@ def test_itertools_groupby() -> None:
690690
)
691691

692692

693-
def test_itertools_pairwise_batched() -> None:
693+
@pytest.mark.skipif(sys.version_info < (3, 10), reason="itertools.pairwise requires Python 3.10+")
694+
def test_itertools_pairwise() -> None:
694695
import itertools
695696

696697
assert comparator(itertools.pairwise([1, 2, 3, 4]), itertools.pairwise([1, 2, 3, 4]))
697698
assert not comparator(itertools.pairwise([1, 2, 3, 4]), itertools.pairwise([1, 2, 3, 5]))
698699

700+
701+
@pytest.mark.skipif(sys.version_info < (3, 12), reason="itertools.batched requires Python 3.12+")
702+
def test_itertools_batched() -> None:
703+
import itertools
704+
699705
assert comparator(itertools.batched("ABCDEFG", 3), itertools.batched("ABCDEFG", 3))
700706
assert not comparator(itertools.batched("ABCDEFG", 3), itertools.batched("ABCDEFG", 2))
701707

0 commit comments

Comments
 (0)