Commit 8f9cafad authored by Serhiy Storchaka's avatar Serhiy Storchaka

Issue #28019: itertools.count() no longer rounds non-integer step in range

between 1.0 and 2.0 to 1.
parents 2d7250b3 8ddcf3ab
...@@ -510,12 +510,18 @@ class TestBasicOps(unittest.TestCase): ...@@ -510,12 +510,18 @@ class TestBasicOps(unittest.TestCase):
self.assertEqual(take(2, zip('abc',count(-3))), [('a', -3), ('b', -2)]) self.assertEqual(take(2, zip('abc',count(-3))), [('a', -3), ('b', -2)])
self.assertRaises(TypeError, count, 2, 3, 4) self.assertRaises(TypeError, count, 2, 3, 4)
self.assertRaises(TypeError, count, 'a') self.assertRaises(TypeError, count, 'a')
self.assertEqual(list(islice(count(maxsize-5), 10)), self.assertEqual(take(10, count(maxsize-5)),
list(range(maxsize-5, maxsize+5))) list(range(maxsize-5, maxsize+5)))
self.assertEqual(list(islice(count(-maxsize-5), 10)), self.assertEqual(take(10, count(-maxsize-5)),
list(range(-maxsize-5, -maxsize+5))) list(range(-maxsize-5, -maxsize+5)))
self.assertEqual(list(islice(count(10, maxsize+5), 3)), self.assertEqual(take(3, count(3.25)), [3.25, 4.25, 5.25])
list(range(10, 10+3*(maxsize+5), maxsize+5))) self.assertEqual(take(3, count(3.25-4j)), [3.25-4j, 4.25-4j, 5.25-4j])
self.assertEqual(take(3, count(Decimal('1.1'))),
[Decimal('1.1'), Decimal('2.1'), Decimal('3.1')])
self.assertEqual(take(3, count(Fraction(2, 3))),
[Fraction(2, 3), Fraction(5, 3), Fraction(8, 3)])
BIGINT = 1<<1000
self.assertEqual(take(3, count(BIGINT)), [BIGINT, BIGINT+1, BIGINT+2])
c = count(3) c = count(3)
self.assertEqual(repr(c), 'count(3)') self.assertEqual(repr(c), 'count(3)')
next(c) next(c)
...@@ -523,8 +529,10 @@ class TestBasicOps(unittest.TestCase): ...@@ -523,8 +529,10 @@ class TestBasicOps(unittest.TestCase):
c = count(-9) c = count(-9)
self.assertEqual(repr(c), 'count(-9)') self.assertEqual(repr(c), 'count(-9)')
next(c) next(c)
self.assertEqual(repr(count(10.25)), 'count(10.25)')
self.assertEqual(next(c), -8) self.assertEqual(next(c), -8)
self.assertEqual(repr(count(10.25)), 'count(10.25)')
self.assertEqual(repr(count(10.0)), 'count(10.0)')
self.assertEqual(type(next(count(10.0))), float)
for i in (-sys.maxsize-5, -sys.maxsize+5 ,-10, -1, 0, 10, sys.maxsize-5, sys.maxsize+5): for i in (-sys.maxsize-5, -sys.maxsize+5 ,-10, -1, 0, 10, sys.maxsize-5, sys.maxsize+5):
# Test repr # Test repr
r1 = repr(count(i)) r1 = repr(count(i))
...@@ -548,16 +556,22 @@ class TestBasicOps(unittest.TestCase): ...@@ -548,16 +556,22 @@ class TestBasicOps(unittest.TestCase):
[('a', 2), ('b', 5), ('c', 8)]) [('a', 2), ('b', 5), ('c', 8)])
self.assertEqual(lzip('abc',count(step=-1)), self.assertEqual(lzip('abc',count(step=-1)),
[('a', 0), ('b', -1), ('c', -2)]) [('a', 0), ('b', -1), ('c', -2)])
self.assertRaises(TypeError, count, 'a', 'b')
self.assertEqual(lzip('abc',count(2,0)), [('a', 2), ('b', 2), ('c', 2)]) self.assertEqual(lzip('abc',count(2,0)), [('a', 2), ('b', 2), ('c', 2)])
self.assertEqual(lzip('abc',count(2,1)), [('a', 2), ('b', 3), ('c', 4)]) self.assertEqual(lzip('abc',count(2,1)), [('a', 2), ('b', 3), ('c', 4)])
self.assertEqual(lzip('abc',count(2,3)), [('a', 2), ('b', 5), ('c', 8)]) self.assertEqual(lzip('abc',count(2,3)), [('a', 2), ('b', 5), ('c', 8)])
self.assertEqual(take(20, count(maxsize-15, 3)), take(20, range(maxsize-15, maxsize+100, 3))) self.assertEqual(take(20, count(maxsize-15, 3)), take(20, range(maxsize-15, maxsize+100, 3)))
self.assertEqual(take(20, count(-maxsize-15, 3)), take(20, range(-maxsize-15,-maxsize+100, 3))) self.assertEqual(take(20, count(-maxsize-15, 3)), take(20, range(-maxsize-15,-maxsize+100, 3)))
self.assertEqual(take(3, count(10, maxsize+5)),
list(range(10, 10+3*(maxsize+5), maxsize+5)))
self.assertEqual(take(3, count(2, 1.25)), [2, 3.25, 4.5])
self.assertEqual(take(3, count(2, 3.25-4j)), [2, 5.25-4j, 8.5-8j]) self.assertEqual(take(3, count(2, 3.25-4j)), [2, 5.25-4j, 8.5-8j])
self.assertEqual(take(3, count(Decimal('1.1'), Decimal('.1'))), self.assertEqual(take(3, count(Decimal('1.1'), Decimal('.1'))),
[Decimal('1.1'), Decimal('1.2'), Decimal('1.3')]) [Decimal('1.1'), Decimal('1.2'), Decimal('1.3')])
self.assertEqual(take(3, count(Fraction(2,3), Fraction(1,7))), self.assertEqual(take(3, count(Fraction(2,3), Fraction(1,7))),
[Fraction(2,3), Fraction(17,21), Fraction(20,21)]) [Fraction(2,3), Fraction(17,21), Fraction(20,21)])
BIGINT = 1<<1000
self.assertEqual(take(3, count(step=BIGINT)), [0, BIGINT, 2*BIGINT])
self.assertEqual(repr(take(3, count(10, 2.5))), repr([10, 12.5, 15.0])) self.assertEqual(repr(take(3, count(10, 2.5))), repr([10, 12.5, 15.0]))
c = count(3, 5) c = count(3, 5)
self.assertEqual(repr(c), 'count(3, 5)') self.assertEqual(repr(c), 'count(3, 5)')
...@@ -575,6 +589,10 @@ class TestBasicOps(unittest.TestCase): ...@@ -575,6 +589,10 @@ class TestBasicOps(unittest.TestCase):
self.assertEqual(repr(count(10.5, 1.25)), 'count(10.5, 1.25)') self.assertEqual(repr(count(10.5, 1.25)), 'count(10.5, 1.25)')
self.assertEqual(repr(count(10.5, 1)), 'count(10.5)') # suppress step=1 when it's an int self.assertEqual(repr(count(10.5, 1)), 'count(10.5)') # suppress step=1 when it's an int
self.assertEqual(repr(count(10.5, 1.00)), 'count(10.5, 1.0)') # do show float values lilke 1.0 self.assertEqual(repr(count(10.5, 1.00)), 'count(10.5, 1.0)') # do show float values lilke 1.0
self.assertEqual(repr(count(10, 1.00)), 'count(10, 1.0)')
c = count(10, 1.0)
self.assertEqual(type(next(c)), int)
self.assertEqual(type(next(c)), float)
for i in (-sys.maxsize-5, -sys.maxsize+5 ,-10, -1, 0, 10, sys.maxsize-5, sys.maxsize+5): for i in (-sys.maxsize-5, -sys.maxsize+5 ,-10, -1, 0, 10, sys.maxsize-5, sys.maxsize+5):
for j in (-sys.maxsize-5, -sys.maxsize+5 ,-10, -1, 0, 1, 10, sys.maxsize-5, sys.maxsize+5): for j in (-sys.maxsize-5, -sys.maxsize+5 ,-10, -1, 0, 1, 10, sys.maxsize-5, sys.maxsize+5):
# Test repr # Test repr
......
...@@ -135,6 +135,9 @@ Core and Builtins ...@@ -135,6 +135,9 @@ Core and Builtins
Library Library
------- -------
- Issue #28019: itertools.count() no longer rounds non-integer step in range
between 1.0 and 2.0 to 1.
- Issue #18401: Pdb now supports the 'readrc' keyword argument to control - Issue #18401: Pdb now supports the 'readrc' keyword argument to control
whether .pdbrc files should be read. Patch by Martin Matusiak and whether .pdbrc files should be read. Patch by Martin Matusiak and
Sam Kimbrel. Sam Kimbrel.
......
...@@ -3907,7 +3907,7 @@ static PyObject * ...@@ -3907,7 +3907,7 @@ static PyObject *
count_new(PyTypeObject *type, PyObject *args, PyObject *kwds) count_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
{ {
countobject *lz; countobject *lz;
int slow_mode = 0; int fast_mode;
Py_ssize_t cnt = 0; Py_ssize_t cnt = 0;
PyObject *long_cnt = NULL; PyObject *long_cnt = NULL;
PyObject *long_step = NULL; PyObject *long_step = NULL;
...@@ -3924,16 +3924,26 @@ count_new(PyTypeObject *type, PyObject *args, PyObject *kwds) ...@@ -3924,16 +3924,26 @@ count_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
return NULL; return NULL;
} }
fast_mode = (long_cnt == NULL || PyLong_Check(long_cnt)) &&
(long_step == NULL || PyLong_Check(long_step));
/* If not specified, start defaults to 0 */
if (long_cnt != NULL) { if (long_cnt != NULL) {
cnt = PyLong_AsSsize_t(long_cnt); if (fast_mode) {
if ((cnt == -1 && PyErr_Occurred()) || !PyLong_Check(long_cnt)) { assert(PyLong_Check(long_cnt));
PyErr_Clear(); cnt = PyLong_AsSsize_t(long_cnt);
slow_mode = 1; if (cnt == -1 && PyErr_Occurred()) {
PyErr_Clear();
fast_mode = 0;
}
} }
Py_INCREF(long_cnt); Py_INCREF(long_cnt);
} else { } else {
cnt = 0; cnt = 0;
long_cnt = PyLong_FromLong(0); long_cnt = PyLong_FromLong(0);
if (long_cnt == NULL) {
return NULL;
}
} }
/* If not specified, step defaults to 1 */ /* If not specified, step defaults to 1 */
...@@ -3949,21 +3959,24 @@ count_new(PyTypeObject *type, PyObject *args, PyObject *kwds) ...@@ -3949,21 +3959,24 @@ count_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
assert(long_cnt != NULL && long_step != NULL); assert(long_cnt != NULL && long_step != NULL);
/* Fast mode only works when the step is 1 */ /* Fast mode only works when the step is 1 */
step = PyLong_AsLong(long_step); if (fast_mode) {
if (step != 1) { assert(PyLong_Check(long_step));
slow_mode = 1; step = PyLong_AsLong(long_step);
if (step == -1 && PyErr_Occurred()) if (step != 1) {
PyErr_Clear(); fast_mode = 0;
if (step == -1 && PyErr_Occurred())
PyErr_Clear();
}
} }
if (slow_mode) if (fast_mode)
cnt = PY_SSIZE_T_MAX;
else
Py_CLEAR(long_cnt); Py_CLEAR(long_cnt);
else
cnt = PY_SSIZE_T_MAX;
assert((cnt != PY_SSIZE_T_MAX && long_cnt == NULL && !slow_mode) || assert((cnt != PY_SSIZE_T_MAX && long_cnt == NULL && fast_mode) ||
(cnt == PY_SSIZE_T_MAX && long_cnt != NULL && slow_mode)); (cnt == PY_SSIZE_T_MAX && long_cnt != NULL && !fast_mode));
assert(slow_mode || assert(!fast_mode ||
(PyLong_Check(long_step) && PyLong_AS_LONG(long_step) == 1)); (PyLong_Check(long_step) && PyLong_AS_LONG(long_step) == 1));
/* create countobject structure */ /* create countobject structure */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment