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

Pablo Galindo webhook-mailer at python.org
Sun Jan 5 12:30:58 EST 2020


https://github.com/python/cpython/commit/4b66fa6ce9c37e70b55af220d0e07368319de803
commit: 4b66fa6ce9c37e70b55af220d0e07368319de803
branch: master
author: Pablo Galindo <Pablogsal at gmail.com>
committer: GitHub <noreply at github.com>
date: 2020-01-05T17:30:53Z
summary:

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

Co-authored-by: Serhiy Storchaka <storchaka at gmail.com>

files:
A Misc/NEWS.d/next/Core and Builtins/2020-01-03-14-50-14.bpo-39200.Ip2_iI.rst
M Lib/test/test_range.py
M Objects/rangeobject.c

diff --git a/Lib/test/test_range.py b/Lib/test/test_range.py
index 73cbcc4717d7d..30fa129b50ecb 100644
--- a/Lib/test/test_range.py
+++ b/Lib/test/test_range.py
@@ -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)
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 0000000000000..e5cb396643fe0
--- /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 239ace6f4235e..9311f8b1f174c 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))
+    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);



More information about the Python-checkins mailing list