From 4b66fa6ce9c37e70b55af220d0e07368319de803 Mon Sep 17 00:00:00 2001 From: Pablo Galindo Date: Sun, 5 Jan 2020 17:30:53 +0000 Subject: [PATCH] bpo-39200: Correct the error message for range() empty constructor (GH-17813) Co-authored-by: Serhiy Storchaka --- Lib/test/test_range.py | 13 ++++ .../2020-01-03-14-50-14.bpo-39200.Ip2_iI.rst | 2 + Objects/rangeobject.c | 71 +++++++++++-------- 3 files changed, 58 insertions(+), 28 deletions(-) create mode 100644 Misc/NEWS.d/next/Core and Builtins/2020-01-03-14-50-14.bpo-39200.Ip2_iI.rst diff --git a/Lib/test/test_range.py b/Lib/test/test_range.py index 73cbcc4717d..30fa129b50e 100644 --- a/Lib/test/test_range.py +++ b/Lib/test/test_range.py @@ -91,6 +91,19 @@ class RangeTest(unittest.TestCase): 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) diff --git a/Misc/NEWS.d/next/Core and Builtins/2020-01-03-14-50-14.bpo-39200.Ip2_iI.rst b/Misc/NEWS.d/next/Core and Builtins/2020-01-03-14-50-14.bpo-39200.Ip2_iI.rst new file mode 100644 index 00000000000..e5cb396643f --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2020-01-03-14-50-14.bpo-39200.Ip2_iI.rst @@ -0,0 +1,2 @@ +Correct the error message when trying to construct :class:`range` objects +with no arguments. Patch by Pablo Galindo. diff --git a/Objects/rangeobject.c b/Objects/rangeobject.c index 239ace6f423..9311f8b1f17 100644 --- a/Objects/rangeobject.c +++ b/Objects/rangeobject.c @@ -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)) - return NULL; - stop = PyNumber_Index(stop); - if (!stop) - 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; + 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; + } - /* Convert borrowed refs to owned refs */ - start = PyNumber_Index(start); - if (!start) + 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) { - Py_DECREF(start); + default: + PyErr_Format(PyExc_TypeError, + "range expected at most 3 arguments, got %zd", + num_args); 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);