bpo-39200: Correct the error message for range() empty constructor (GH-17813)

Co-authored-by: Serhiy Storchaka <storchaka@gmail.com>
This commit is contained in:
Pablo Galindo 2020-01-05 17:30:53 +00:00 committed by GitHub
parent b121a4a45f
commit 4b66fa6ce9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 58 additions and 28 deletions

View File

@ -91,6 +91,19 @@ class RangeTest(unittest.TestCase):
r = range(-sys.maxsize, sys.maxsize, 2) r = range(-sys.maxsize, sys.maxsize, 2)
self.assertEqual(len(r), sys.maxsize) self.assertEqual(len(r), sys.maxsize)
def test_range_constructor_error_messages(self):
with self.assertRaisesRegex(
TypeError,
"range expected at least 1 argument, got 0"
):
range()
with self.assertRaisesRegex(
TypeError,
"range expected at most 3 arguments, got 6"
):
range(1, 2, 3, 4, 5, 6)
def test_large_operands(self): def test_large_operands(self):
x = range(10**20, 10**20+10, 3) x = range(10**20, 10**20+10, 3)
self.assertEqual(len(x), 4) self.assertEqual(len(x), 4)

View File

@ -0,0 +1,2 @@
Correct the error message when trying to construct :class:`range` objects
with no arguments. Patch by Pablo Galindo.

View File

@ -77,37 +77,52 @@ range_new(PyTypeObject *type, PyObject *args, PyObject *kw)
if (!_PyArg_NoKeywords("range", kw)) if (!_PyArg_NoKeywords("range", kw))
return NULL; return NULL;
if (PyTuple_Size(args) <= 1) { Py_ssize_t num_args = PyTuple_GET_SIZE(args);
if (!PyArg_UnpackTuple(args, "range", 1, 1, &stop)) switch (num_args) {
return NULL; case 3:
stop = PyNumber_Index(stop); step = PyTuple_GET_ITEM(args, 2);
if (!stop) /* fallthrough */
return NULL; case 2:
Py_INCREF(_PyLong_Zero); start = PyTuple_GET_ITEM(args, 0);
start = _PyLong_Zero; start = PyNumber_Index(start);
Py_INCREF(_PyLong_One); if (!start) {
step = _PyLong_One; return NULL;
} }
else {
if (!PyArg_UnpackTuple(args, "range", 2, 3,
&start, &stop, &step))
return NULL;
/* Convert borrowed refs to owned refs */ stop = PyTuple_GET_ITEM(args, 1);
start = PyNumber_Index(start); stop = PyNumber_Index(stop);
if (!start) if (!stop) {
Py_DECREF(start);
return NULL;
}
step = validate_step(step);
if (!step) {
Py_DECREF(start);
Py_DECREF(stop);
return NULL;
}
break;
case 1:
stop = PyTuple_GET_ITEM(args, 0);
stop = PyNumber_Index(stop);
if (!stop) {
return NULL;
}
Py_INCREF(_PyLong_Zero);
start = _PyLong_Zero;
Py_INCREF(_PyLong_One);
step = _PyLong_One;
break;
case 0:
PyErr_SetString(PyExc_TypeError,
"range expected at least 1 argument, got 0");
return NULL; return NULL;
stop = PyNumber_Index(stop); default:
if (!stop) { PyErr_Format(PyExc_TypeError,
Py_DECREF(start); "range expected at most 3 arguments, got %zd",
num_args);
return NULL; return NULL;
}
step = validate_step(step); /* Caution, this can clear exceptions */
if (!step) {
Py_DECREF(start);
Py_DECREF(stop);
return NULL;
}
} }
obj = make_range_object(type, start, stop, step); obj = make_range_object(type, start, stop, step);