Skip to content

Commit 8f9cafa

Browse files
Issue python#28019: itertools.count() no longer rounds non-integer step in range
between 1.0 and 2.0 to 1.
2 parents 2d7250b + 8ddcf3a commit 8f9cafa

3 files changed

Lines changed: 55 additions & 21 deletions

File tree

Lib/test/test_itertools.py

Lines changed: 23 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -510,21 +510,29 @@ def test_count(self):
510510
self.assertEqual(take(2, zip('abc',count(-3))), [('a', -3), ('b', -2)])
511511
self.assertRaises(TypeError, count, 2, 3, 4)
512512
self.assertRaises(TypeError, count, 'a')
513-
self.assertEqual(list(islice(count(maxsize-5), 10)),
513+
self.assertEqual(take(10, count(maxsize-5)),
514514
list(range(maxsize-5, maxsize+5)))
515-
self.assertEqual(list(islice(count(-maxsize-5), 10)),
515+
self.assertEqual(take(10, count(-maxsize-5)),
516516
list(range(-maxsize-5, -maxsize+5)))
517-
self.assertEqual(list(islice(count(10, maxsize+5), 3)),
518-
list(range(10, 10+3*(maxsize+5), maxsize+5)))
517+
self.assertEqual(take(3, count(3.25)), [3.25, 4.25, 5.25])
518+
self.assertEqual(take(3, count(3.25-4j)), [3.25-4j, 4.25-4j, 5.25-4j])
519+
self.assertEqual(take(3, count(Decimal('1.1'))),
520+
[Decimal('1.1'), Decimal('2.1'), Decimal('3.1')])
521+
self.assertEqual(take(3, count(Fraction(2, 3))),
522+
[Fraction(2, 3), Fraction(5, 3), Fraction(8, 3)])
523+
BIGINT = 1<<1000
524+
self.assertEqual(take(3, count(BIGINT)), [BIGINT, BIGINT+1, BIGINT+2])
519525
c = count(3)
520526
self.assertEqual(repr(c), 'count(3)')
521527
next(c)
522528
self.assertEqual(repr(c), 'count(4)')
523529
c = count(-9)
524530
self.assertEqual(repr(c), 'count(-9)')
525531
next(c)
526-
self.assertEqual(repr(count(10.25)), 'count(10.25)')
527532
self.assertEqual(next(c), -8)
533+
self.assertEqual(repr(count(10.25)), 'count(10.25)')
534+
self.assertEqual(repr(count(10.0)), 'count(10.0)')
535+
self.assertEqual(type(next(count(10.0))), float)
528536
for i in (-sys.maxsize-5, -sys.maxsize+5 ,-10, -1, 0, 10, sys.maxsize-5, sys.maxsize+5):
529537
# Test repr
530538
r1 = repr(count(i))
@@ -548,16 +556,22 @@ def test_count_with_stride(self):
548556
[('a', 2), ('b', 5), ('c', 8)])
549557
self.assertEqual(lzip('abc',count(step=-1)),
550558
[('a', 0), ('b', -1), ('c', -2)])
559+
self.assertRaises(TypeError, count, 'a', 'b')
551560
self.assertEqual(lzip('abc',count(2,0)), [('a', 2), ('b', 2), ('c', 2)])
552561
self.assertEqual(lzip('abc',count(2,1)), [('a', 2), ('b', 3), ('c', 4)])
553562
self.assertEqual(lzip('abc',count(2,3)), [('a', 2), ('b', 5), ('c', 8)])
554563
self.assertEqual(take(20, count(maxsize-15, 3)), take(20, range(maxsize-15, maxsize+100, 3)))
555564
self.assertEqual(take(20, count(-maxsize-15, 3)), take(20, range(-maxsize-15,-maxsize+100, 3)))
565+
self.assertEqual(take(3, count(10, maxsize+5)),
566+
list(range(10, 10+3*(maxsize+5), maxsize+5)))
567+
self.assertEqual(take(3, count(2, 1.25)), [2, 3.25, 4.5])
556568
self.assertEqual(take(3, count(2, 3.25-4j)), [2, 5.25-4j, 8.5-8j])
557569
self.assertEqual(take(3, count(Decimal('1.1'), Decimal('.1'))),
558570
[Decimal('1.1'), Decimal('1.2'), Decimal('1.3')])
559571
self.assertEqual(take(3, count(Fraction(2,3), Fraction(1,7))),
560572
[Fraction(2,3), Fraction(17,21), Fraction(20,21)])
573+
BIGINT = 1<<1000
574+
self.assertEqual(take(3, count(step=BIGINT)), [0, BIGINT, 2*BIGINT])
561575
self.assertEqual(repr(take(3, count(10, 2.5))), repr([10, 12.5, 15.0]))
562576
c = count(3, 5)
563577
self.assertEqual(repr(c), 'count(3, 5)')
@@ -575,6 +589,10 @@ def test_count_with_stride(self):
575589
self.assertEqual(repr(count(10.5, 1.25)), 'count(10.5, 1.25)')
576590
self.assertEqual(repr(count(10.5, 1)), 'count(10.5)') # suppress step=1 when it's an int
577591
self.assertEqual(repr(count(10.5, 1.00)), 'count(10.5, 1.0)') # do show float values lilke 1.0
592+
self.assertEqual(repr(count(10, 1.00)), 'count(10, 1.0)')
593+
c = count(10, 1.0)
594+
self.assertEqual(type(next(c)), int)
595+
self.assertEqual(type(next(c)), float)
578596
for i in (-sys.maxsize-5, -sys.maxsize+5 ,-10, -1, 0, 10, sys.maxsize-5, sys.maxsize+5):
579597
for j in (-sys.maxsize-5, -sys.maxsize+5 ,-10, -1, 0, 1, 10, sys.maxsize-5, sys.maxsize+5):
580598
# Test repr

Misc/NEWS

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,9 @@ Core and Builtins
135135
Library
136136
-------
137137

138+
- Issue #28019: itertools.count() no longer rounds non-integer step in range
139+
between 1.0 and 2.0 to 1.
140+
138141
- Issue #18401: Pdb now supports the 'readrc' keyword argument to control
139142
whether .pdbrc files should be read. Patch by Martin Matusiak and
140143
Sam Kimbrel.

Modules/itertoolsmodule.c

Lines changed: 29 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -3907,7 +3907,7 @@ static PyObject *
39073907
count_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
39083908
{
39093909
countobject *lz;
3910-
int slow_mode = 0;
3910+
int fast_mode;
39113911
Py_ssize_t cnt = 0;
39123912
PyObject *long_cnt = NULL;
39133913
PyObject *long_step = NULL;
@@ -3924,16 +3924,26 @@ count_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
39243924
return NULL;
39253925
}
39263926

3927+
fast_mode = (long_cnt == NULL || PyLong_Check(long_cnt)) &&
3928+
(long_step == NULL || PyLong_Check(long_step));
3929+
3930+
/* If not specified, start defaults to 0 */
39273931
if (long_cnt != NULL) {
3928-
cnt = PyLong_AsSsize_t(long_cnt);
3929-
if ((cnt == -1 && PyErr_Occurred()) || !PyLong_Check(long_cnt)) {
3930-
PyErr_Clear();
3931-
slow_mode = 1;
3932+
if (fast_mode) {
3933+
assert(PyLong_Check(long_cnt));
3934+
cnt = PyLong_AsSsize_t(long_cnt);
3935+
if (cnt == -1 && PyErr_Occurred()) {
3936+
PyErr_Clear();
3937+
fast_mode = 0;
3938+
}
39323939
}
39333940
Py_INCREF(long_cnt);
39343941
} else {
39353942
cnt = 0;
39363943
long_cnt = PyLong_FromLong(0);
3944+
if (long_cnt == NULL) {
3945+
return NULL;
3946+
}
39373947
}
39383948

39393949
/* If not specified, step defaults to 1 */
@@ -3949,21 +3959,24 @@ count_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
39493959
assert(long_cnt != NULL && long_step != NULL);
39503960

39513961
/* Fast mode only works when the step is 1 */
3952-
step = PyLong_AsLong(long_step);
3953-
if (step != 1) {
3954-
slow_mode = 1;
3955-
if (step == -1 && PyErr_Occurred())
3956-
PyErr_Clear();
3962+
if (fast_mode) {
3963+
assert(PyLong_Check(long_step));
3964+
step = PyLong_AsLong(long_step);
3965+
if (step != 1) {
3966+
fast_mode = 0;
3967+
if (step == -1 && PyErr_Occurred())
3968+
PyErr_Clear();
3969+
}
39573970
}
39583971

3959-
if (slow_mode)
3960-
cnt = PY_SSIZE_T_MAX;
3961-
else
3972+
if (fast_mode)
39623973
Py_CLEAR(long_cnt);
3974+
else
3975+
cnt = PY_SSIZE_T_MAX;
39633976

3964-
assert((cnt != PY_SSIZE_T_MAX && long_cnt == NULL && !slow_mode) ||
3965-
(cnt == PY_SSIZE_T_MAX && long_cnt != NULL && slow_mode));
3966-
assert(slow_mode ||
3977+
assert((cnt != PY_SSIZE_T_MAX && long_cnt == NULL && fast_mode) ||
3978+
(cnt == PY_SSIZE_T_MAX && long_cnt != NULL && !fast_mode));
3979+
assert(!fast_mode ||
39673980
(PyLong_Check(long_step) && PyLong_AS_LONG(long_step) == 1));
39683981

39693982
/* create countobject structure */

0 commit comments

Comments
 (0)