Skip to content

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

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Jan 5, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions Lib/test/test_range.py
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,19 @@ def test_range(self):
r = range(-sys.maxsize, sys.maxsize, 2)
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):
x = range(10**20, 10**20+10, 3)
self.assertEqual(len(x), 4)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
Correct the error message when trying to construct :class:`range` objects
with no arguments. Patch by Pablo Galindo.
73 changes: 44 additions & 29 deletions Objects/rangeobject.c
Original file line number Diff line number Diff line change
Expand Up @@ -77,37 +77,52 @@ range_new(PyTypeObject *type, PyObject *args, PyObject *kw)
if (!_PyArg_NoKeywords("range", kw))
return NULL;

if (PyTuple_Size(args) <= 1) {
if (!PyArg_UnpackTuple(args, "range", 1, 1, &stop))
Py_ssize_t num_args = PyTuple_GET_SIZE(args);
switch (num_args) {
case 3:
step = PyTuple_GET_ITEM(args, 2);
/* fallthrough */
case 2:
start = PyTuple_GET_ITEM(args, 0);
start = PyNumber_Index(start);
if (!start) {
return NULL;
}

stop = PyTuple_GET_ITEM(args, 1);
stop = PyNumber_Index(stop);
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;
stop = PyNumber_Index(stop);
if (!stop)
default:
PyErr_Format(PyExc_TypeError,
"range expected at most 3 arguments, got %zd",
num_args);
return NULL;
Py_INCREF(_PyLong_Zero);
start = _PyLong_Zero;
Py_INCREF(_PyLong_One);
step = _PyLong_One;
}
else {
if (!PyArg_UnpackTuple(args, "range", 2, 3,
&start, &stop, &step))
return NULL;

/* Convert borrowed refs to owned refs */
start = PyNumber_Index(start);
if (!start)
return NULL;
stop = PyNumber_Index(stop);
if (!stop) {
Py_DECREF(start);
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);
Expand Down