[Python-checkins] cpython (merge 3.5 -> default): Merge 3.5 (Issue #19235)

yury.selivanov python-checkins at python.org
Fri Jul 3 07:12:42 CEST 2015


https://hg.python.org/cpython/rev/749d74e5dfa7
changeset:   96773:749d74e5dfa7
parent:      96771:5e9f794fd776
parent:      96772:a795cf73ce6f
user:        Yury Selivanov <yselivanov at sprymix.com>
date:        Fri Jul 03 01:10:11 2015 -0400
summary:
  Merge 3.5 (Issue #19235)

files:
  Doc/c-api/exceptions.rst             |  12 ++++++--
  Doc/library/exceptions.rst           |  10 ++++++
  Doc/library/pickle.rst               |   2 +-
  Doc/whatsnew/3.5.rst                 |   2 +
  Include/ceval.h                      |   6 ++--
  Include/pyerrors.h                   |   1 +
  Lib/ctypes/test/test_as_parameter.py |   2 +-
  Lib/test/exception_hierarchy.txt     |   1 +
  Lib/test/list_tests.py               |   2 +-
  Lib/test/test_class.py               |   4 +-
  Lib/test/test_compile.py             |   2 +-
  Lib/test/test_copy.py                |   6 ++--
  Lib/test/test_descr.py               |   6 ++--
  Lib/test/test_dictviews.py           |   2 +-
  Lib/test/test_exceptions.py          |  13 ++++----
  Lib/test/test_isinstance.py          |  10 +++---
  Lib/test/test_json/test_recursion.py |  12 ++++----
  Lib/test/test_pickle.py              |   3 +-
  Lib/test/test_richcmp.py             |  24 ++++++++--------
  Lib/test/test_runpy.py               |   2 +-
  Lib/test/test_sys.py                 |   6 ++--
  Lib/test/test_threading.py           |   2 +-
  Misc/NEWS                            |   2 +
  Modules/_pickle.c                    |   2 +-
  Modules/_sre.c                       |   3 +-
  Objects/exceptions.c                 |  19 ++++++++----
  Objects/typeobject.c                 |   2 +-
  Python/ceval.c                       |   2 +-
  Python/errors.c                      |   2 +-
  Python/symtable.c                    |   4 +-
  Tools/scripts/find_recursionlimit.py |   4 +-
  31 files changed, 101 insertions(+), 69 deletions(-)


diff --git a/Doc/c-api/exceptions.rst b/Doc/c-api/exceptions.rst
--- a/Doc/c-api/exceptions.rst
+++ b/Doc/c-api/exceptions.rst
@@ -683,12 +683,12 @@
    sets a :exc:`MemoryError` and returns a nonzero value.
 
    The function then checks if the recursion limit is reached.  If this is the
-   case, a :exc:`RuntimeError` is set and a nonzero value is returned.
+   case, a :exc:`RecursionError` is set and a nonzero value is returned.
    Otherwise, zero is returned.
 
    *where* should be a string such as ``" in instance check"`` to be
-   concatenated to the :exc:`RuntimeError` message caused by the recursion depth
-   limit.
+   concatenated to the :exc:`RecursionError` message caused by the recursion
+   depth limit.
 
 .. c:function:: void Py_LeaveRecursiveCall()
 
@@ -800,6 +800,8 @@
 +-----------------------------------------+---------------------------------+----------+
 | :c:data:`PyExc_ProcessLookupError`      | :exc:`ProcessLookupError`       |          |
 +-----------------------------------------+---------------------------------+----------+
+| :c:data:`PyExc_RecursionError`          | :exc:`RecursionError`           |          |
++-----------------------------------------+---------------------------------+----------+
 | :c:data:`PyExc_ReferenceError`          | :exc:`ReferenceError`           | \(2)     |
 +-----------------------------------------+---------------------------------+----------+
 | :c:data:`PyExc_RuntimeError`            | :exc:`RuntimeError`             |          |
@@ -829,6 +831,9 @@
    :c:data:`PyExc_PermissionError`, :c:data:`PyExc_ProcessLookupError`
    and :c:data:`PyExc_TimeoutError` were introduced following :pep:`3151`.
 
+.. versionadded:: 3.5
+   :c:data:`PyExc_RecursionError`.
+
 
 These are compatibility aliases to :c:data:`PyExc_OSError`:
 
@@ -877,6 +882,7 @@
    single: PyExc_OverflowError
    single: PyExc_PermissionError
    single: PyExc_ProcessLookupError
+   single: PyExc_RecursionError
    single: PyExc_ReferenceError
    single: PyExc_RuntimeError
    single: PyExc_SyntaxError
diff --git a/Doc/library/exceptions.rst b/Doc/library/exceptions.rst
--- a/Doc/library/exceptions.rst
+++ b/Doc/library/exceptions.rst
@@ -282,6 +282,16 @@
    handling in C, most floating point operations are not checked.
 
 
+.. exception:: RecursionError
+
+   This exception is derived from :exc:`RuntimeError`.  It is raised when the
+   interpreter detects that the maximum recursion depth (see
+   :func:`sys.getrecursionlimit`) is exceeded.
+
+   .. versionadded:: 3.5
+      Previously, a plain :exc:`RuntimeError` was raised.
+
+
 .. exception:: ReferenceError
 
    This exception is raised when a weak reference proxy, created by the
diff --git a/Doc/library/pickle.rst b/Doc/library/pickle.rst
--- a/Doc/library/pickle.rst
+++ b/Doc/library/pickle.rst
@@ -425,7 +425,7 @@
 Attempts to pickle unpicklable objects will raise the :exc:`PicklingError`
 exception; when this happens, an unspecified number of bytes may have already
 been written to the underlying file.  Trying to pickle a highly recursive data
-structure may exceed the maximum recursion depth, a :exc:`RuntimeError` will be
+structure may exceed the maximum recursion depth, a :exc:`RecursionError` will be
 raised in this case.  You can carefully raise this limit with
 :func:`sys.setrecursionlimit`.
 
diff --git a/Doc/whatsnew/3.5.rst b/Doc/whatsnew/3.5.rst
--- a/Doc/whatsnew/3.5.rst
+++ b/Doc/whatsnew/3.5.rst
@@ -87,6 +87,8 @@
 * Generators have new ``gi_yieldfrom`` attribute, which returns the
   object being iterated by ``yield from`` expressions. (Contributed
   by Benno Leslie and Yury Selivanov in :issue:`24450`.)
+* New :exc:`RecursionError` exception. (Contributed by Georg Brandl
+  in :issue:`19235`.)
 
 Implementation improvements:
 
diff --git a/Include/ceval.h b/Include/ceval.h
--- a/Include/ceval.h
+++ b/Include/ceval.h
@@ -48,16 +48,16 @@
 
    In Python 3.0, this protection has two levels:
    * normal anti-recursion protection is triggered when the recursion level
-     exceeds the current recursion limit. It raises a RuntimeError, and sets
+     exceeds the current recursion limit. It raises a RecursionError, and sets
      the "overflowed" flag in the thread state structure. This flag
      temporarily *disables* the normal protection; this allows cleanup code
      to potentially outgrow the recursion limit while processing the
-     RuntimeError.
+     RecursionError.
    * "last chance" anti-recursion protection is triggered when the recursion
      level exceeds "current recursion limit + 50". By construction, this
      protection can only be triggered when the "overflowed" flag is set. It
      means the cleanup code has itself gone into an infinite loop, or the
-     RuntimeError has been mistakingly ignored. When this protection is
+     RecursionError has been mistakingly ignored. When this protection is
      triggered, the interpreter aborts with a Fatal Error.
 
    In addition, the "overflowed" flag is automatically reset when the
diff --git a/Include/pyerrors.h b/Include/pyerrors.h
--- a/Include/pyerrors.h
+++ b/Include/pyerrors.h
@@ -167,6 +167,7 @@
 PyAPI_DATA(PyObject *) PyExc_NameError;
 PyAPI_DATA(PyObject *) PyExc_OverflowError;
 PyAPI_DATA(PyObject *) PyExc_RuntimeError;
+PyAPI_DATA(PyObject *) PyExc_RecursionError;
 PyAPI_DATA(PyObject *) PyExc_NotImplementedError;
 PyAPI_DATA(PyObject *) PyExc_SyntaxError;
 PyAPI_DATA(PyObject *) PyExc_IndentationError;
diff --git a/Lib/ctypes/test/test_as_parameter.py b/Lib/ctypes/test/test_as_parameter.py
--- a/Lib/ctypes/test/test_as_parameter.py
+++ b/Lib/ctypes/test/test_as_parameter.py
@@ -194,7 +194,7 @@
 
         a = A()
         a._as_parameter_ = a
-        with self.assertRaises(RuntimeError):
+        with self.assertRaises(RecursionError):
             c_int.from_param(a)
 
 
diff --git a/Lib/test/exception_hierarchy.txt b/Lib/test/exception_hierarchy.txt
--- a/Lib/test/exception_hierarchy.txt
+++ b/Lib/test/exception_hierarchy.txt
@@ -39,6 +39,7 @@
       +-- ReferenceError
       +-- RuntimeError
       |    +-- NotImplementedError
+      |    +-- RecursionError
       +-- SyntaxError
       |    +-- IndentationError
       |         +-- TabError
diff --git a/Lib/test/list_tests.py b/Lib/test/list_tests.py
--- a/Lib/test/list_tests.py
+++ b/Lib/test/list_tests.py
@@ -56,7 +56,7 @@
         l0 = []
         for i in range(sys.getrecursionlimit() + 100):
             l0 = [l0]
-        self.assertRaises(RuntimeError, repr, l0)
+        self.assertRaises(RecursionError, repr, l0)
 
     def test_print(self):
         d = self.type2test(range(200))
diff --git a/Lib/test/test_class.py b/Lib/test/test_class.py
--- a/Lib/test/test_class.py
+++ b/Lib/test/test_class.py
@@ -500,10 +500,10 @@
 
         try:
             a() # This should not segfault
-        except RuntimeError:
+        except RecursionError:
             pass
         else:
-            self.fail("Failed to raise RuntimeError")
+            self.fail("Failed to raise RecursionError")
 
     def testForExceptionsRaisedInInstanceGetattr2(self):
         # Tests for exceptions raised in instance_getattr2().
diff --git a/Lib/test/test_compile.py b/Lib/test/test_compile.py
--- a/Lib/test/test_compile.py
+++ b/Lib/test/test_compile.py
@@ -534,7 +534,7 @@
             broken = prefix + repeated * fail_depth
             details = "Compiling ({!r} + {!r} * {})".format(
                          prefix, repeated, fail_depth)
-            with self.assertRaises(RuntimeError, msg=details):
+            with self.assertRaises(RecursionError, msg=details):
                 self.compile_single(broken)
 
         check_limit("a", "()")
diff --git a/Lib/test/test_copy.py b/Lib/test/test_copy.py
--- a/Lib/test/test_copy.py
+++ b/Lib/test/test_copy.py
@@ -327,7 +327,7 @@
         x.append(x)
         y = copy.deepcopy(x)
         for op in comparisons:
-            self.assertRaises(RuntimeError, op, y, x)
+            self.assertRaises(RecursionError, op, y, x)
         self.assertIsNot(y, x)
         self.assertIs(y[0], y)
         self.assertEqual(len(y), 1)
@@ -354,7 +354,7 @@
         x[0].append(x)
         y = copy.deepcopy(x)
         for op in comparisons:
-            self.assertRaises(RuntimeError, op, y, x)
+            self.assertRaises(RecursionError, op, y, x)
         self.assertIsNot(y, x)
         self.assertIsNot(y[0], x[0])
         self.assertIs(y[0][0], y)
@@ -373,7 +373,7 @@
         for op in order_comparisons:
             self.assertRaises(TypeError, op, y, x)
         for op in equality_comparisons:
-            self.assertRaises(RuntimeError, op, y, x)
+            self.assertRaises(RecursionError, op, y, x)
         self.assertIsNot(y, x)
         self.assertIs(y['foo'], y)
         self.assertEqual(len(y), 1)
diff --git a/Lib/test/test_descr.py b/Lib/test/test_descr.py
--- a/Lib/test/test_descr.py
+++ b/Lib/test/test_descr.py
@@ -3342,7 +3342,7 @@
         A.__call__ = A()
         try:
             A()()
-        except RuntimeError:
+        except RecursionError:
             pass
         else:
             self.fail("Recursion limit should have been reached for __call__()")
@@ -4317,8 +4317,8 @@
             pass
         Foo.__repr__ = Foo.__str__
         foo = Foo()
-        self.assertRaises(RuntimeError, str, foo)
-        self.assertRaises(RuntimeError, repr, foo)
+        self.assertRaises(RecursionError, str, foo)
+        self.assertRaises(RecursionError, repr, foo)
 
     def test_mixing_slot_wrappers(self):
         class X(dict):
diff --git a/Lib/test/test_dictviews.py b/Lib/test/test_dictviews.py
--- a/Lib/test/test_dictviews.py
+++ b/Lib/test/test_dictviews.py
@@ -196,7 +196,7 @@
     def test_recursive_repr(self):
         d = {}
         d[42] = d.values()
-        self.assertRaises(RuntimeError, repr, d)
+        self.assertRaises(RecursionError, repr, d)
 
     def test_abc_registry(self):
         d = dict(a=1)
diff --git a/Lib/test/test_exceptions.py b/Lib/test/test_exceptions.py
--- a/Lib/test/test_exceptions.py
+++ b/Lib/test/test_exceptions.py
@@ -84,6 +84,7 @@
             x += x  # this simply shouldn't blow up
 
         self.raise_catch(RuntimeError, "RuntimeError")
+        self.raise_catch(RecursionError, "RecursionError")
 
         self.raise_catch(SyntaxError, "SyntaxError")
         try: exec('/\n')
@@ -474,14 +475,14 @@
     def testInfiniteRecursion(self):
         def f():
             return f()
-        self.assertRaises(RuntimeError, f)
+        self.assertRaises(RecursionError, f)
 
         def g():
             try:
                 return g()
             except ValueError:
                 return -1
-        self.assertRaises(RuntimeError, g)
+        self.assertRaises(RecursionError, g)
 
     def test_str(self):
         # Make sure both instances and classes have a str representation.
@@ -887,10 +888,10 @@
         def g():
             try:
                 return g()
-            except RuntimeError:
+            except RecursionError:
                 return sys.exc_info()
         e, v, tb = g()
-        self.assertTrue(isinstance(v, RuntimeError), type(v))
+        self.assertTrue(isinstance(v, RecursionError), type(v))
         self.assertIn("maximum recursion depth exceeded", str(v))
 
 
@@ -989,10 +990,10 @@
         # We cannot use assertRaises since it manually deletes the traceback
         try:
             inner()
-        except RuntimeError as e:
+        except RecursionError as e:
             self.assertNotEqual(wr(), None)
         else:
-            self.fail("RuntimeError not raised")
+            self.fail("RecursionError not raised")
         self.assertEqual(wr(), None)
 
     def test_errno_ENOTDIR(self):
diff --git a/Lib/test/test_isinstance.py b/Lib/test/test_isinstance.py
--- a/Lib/test/test_isinstance.py
+++ b/Lib/test/test_isinstance.py
@@ -258,18 +258,18 @@
         self.assertEqual(True, issubclass(str, (str, (Child, NewChild, str))))
 
     def test_subclass_recursion_limit(self):
-        # make sure that issubclass raises RuntimeError before the C stack is
+        # make sure that issubclass raises RecursionError before the C stack is
         # blown
-        self.assertRaises(RuntimeError, blowstack, issubclass, str, str)
+        self.assertRaises(RecursionError, blowstack, issubclass, str, str)
 
     def test_isinstance_recursion_limit(self):
-        # make sure that issubclass raises RuntimeError before the C stack is
+        # make sure that issubclass raises RecursionError before the C stack is
         # blown
-        self.assertRaises(RuntimeError, blowstack, isinstance, '', str)
+        self.assertRaises(RecursionError, blowstack, isinstance, '', str)
 
 def blowstack(fxn, arg, compare_to):
     # Make sure that calling isinstance with a deeply nested tuple for its
-    # argument will raise RuntimeError eventually.
+    # argument will raise RecursionError eventually.
     tuple_arg = (compare_to,)
     for cnt in range(sys.getrecursionlimit()+5):
         tuple_arg = (tuple_arg,)
diff --git a/Lib/test/test_json/test_recursion.py b/Lib/test/test_json/test_recursion.py
--- a/Lib/test/test_json/test_recursion.py
+++ b/Lib/test/test_json/test_recursion.py
@@ -68,11 +68,11 @@
     def test_highly_nested_objects_decoding(self):
         # test that loading highly-nested objects doesn't segfault when C
         # accelerations are used. See #12017
-        with self.assertRaises(RuntimeError):
+        with self.assertRaises(RecursionError):
             self.loads('{"a":' * 100000 + '1' + '}' * 100000)
-        with self.assertRaises(RuntimeError):
+        with self.assertRaises(RecursionError):
             self.loads('{"a":' * 100000 + '[1]' + '}' * 100000)
-        with self.assertRaises(RuntimeError):
+        with self.assertRaises(RecursionError):
             self.loads('[' * 100000 + '1' + ']' * 100000)
 
     def test_highly_nested_objects_encoding(self):
@@ -80,9 +80,9 @@
         l, d = [], {}
         for x in range(100000):
             l, d = [l], {'k':d}
-        with self.assertRaises(RuntimeError):
+        with self.assertRaises(RecursionError):
             self.dumps(l)
-        with self.assertRaises(RuntimeError):
+        with self.assertRaises(RecursionError):
             self.dumps(d)
 
     def test_endless_recursion(self):
@@ -92,7 +92,7 @@
                 """If check_circular is False, this will keep adding another list."""
                 return [o]
 
-        with self.assertRaises(RuntimeError):
+        with self.assertRaises(RecursionError):
             EndlessJSONEncoder(check_circular=False).encode(5j)
 
 
diff --git a/Lib/test/test_pickle.py b/Lib/test/test_pickle.py
--- a/Lib/test/test_pickle.py
+++ b/Lib/test/test_pickle.py
@@ -353,7 +353,8 @@
             with self.subTest(name):
                 if exc in (BlockingIOError,
                            ResourceWarning,
-                           StopAsyncIteration):
+                           StopAsyncIteration,
+                           RecursionError):
                     continue
                 if exc is not OSError and issubclass(exc, OSError):
                     self.assertEqual(reverse_mapping('builtins', name),
diff --git a/Lib/test/test_richcmp.py b/Lib/test/test_richcmp.py
--- a/Lib/test/test_richcmp.py
+++ b/Lib/test/test_richcmp.py
@@ -228,25 +228,25 @@
         b = UserList()
         a.append(b)
         b.append(a)
-        self.assertRaises(RuntimeError, operator.eq, a, b)
-        self.assertRaises(RuntimeError, operator.ne, a, b)
-        self.assertRaises(RuntimeError, operator.lt, a, b)
-        self.assertRaises(RuntimeError, operator.le, a, b)
-        self.assertRaises(RuntimeError, operator.gt, a, b)
-        self.assertRaises(RuntimeError, operator.ge, a, b)
+        self.assertRaises(RecursionError, operator.eq, a, b)
+        self.assertRaises(RecursionError, operator.ne, a, b)
+        self.assertRaises(RecursionError, operator.lt, a, b)
+        self.assertRaises(RecursionError, operator.le, a, b)
+        self.assertRaises(RecursionError, operator.gt, a, b)
+        self.assertRaises(RecursionError, operator.ge, a, b)
 
         b.append(17)
         # Even recursive lists of different lengths are different,
         # but they cannot be ordered
         self.assertTrue(not (a == b))
         self.assertTrue(a != b)
-        self.assertRaises(RuntimeError, operator.lt, a, b)
-        self.assertRaises(RuntimeError, operator.le, a, b)
-        self.assertRaises(RuntimeError, operator.gt, a, b)
-        self.assertRaises(RuntimeError, operator.ge, a, b)
+        self.assertRaises(RecursionError, operator.lt, a, b)
+        self.assertRaises(RecursionError, operator.le, a, b)
+        self.assertRaises(RecursionError, operator.gt, a, b)
+        self.assertRaises(RecursionError, operator.ge, a, b)
         a.append(17)
-        self.assertRaises(RuntimeError, operator.eq, a, b)
-        self.assertRaises(RuntimeError, operator.ne, a, b)
+        self.assertRaises(RecursionError, operator.eq, a, b)
+        self.assertRaises(RecursionError, operator.ne, a, b)
         a.insert(0, 11)
         b.insert(0, 12)
         self.assertTrue(not (a == b))
diff --git a/Lib/test/test_runpy.py b/Lib/test/test_runpy.py
--- a/Lib/test/test_runpy.py
+++ b/Lib/test/test_runpy.py
@@ -673,7 +673,7 @@
             script_name = self._make_test_script(script_dir, mod_name, source)
             zip_name, fname = make_zip_script(script_dir, 'test_zip', script_name)
             msg = "recursion depth exceeded"
-            self.assertRaisesRegex(RuntimeError, msg, run_path, zip_name)
+            self.assertRaisesRegex(RecursionError, msg, run_path, zip_name)
 
     def test_encoding(self):
         with temp_dir() as script_dir:
diff --git a/Lib/test/test_sys.py b/Lib/test/test_sys.py
--- a/Lib/test/test_sys.py
+++ b/Lib/test/test_sys.py
@@ -211,8 +211,8 @@
             for i in (50, 1000):
                 # Issue #5392: stack overflow after hitting recursion limit twice
                 sys.setrecursionlimit(i)
-                self.assertRaises(RuntimeError, f)
-                self.assertRaises(RuntimeError, f)
+                self.assertRaises(RecursionError, f)
+                self.assertRaises(RecursionError, f)
         finally:
             sys.setrecursionlimit(oldlimit)
 
@@ -225,7 +225,7 @@
             def f():
                 try:
                     f()
-                except RuntimeError:
+                except RecursionError:
                     f()
 
             sys.setrecursionlimit(%d)
diff --git a/Lib/test/test_threading.py b/Lib/test/test_threading.py
--- a/Lib/test/test_threading.py
+++ b/Lib/test/test_threading.py
@@ -945,7 +945,7 @@
             def outer():
                 try:
                     recurse()
-                except RuntimeError:
+                except RecursionError:
                     pass
 
             w = threading.Thread(target=outer)
diff --git a/Misc/NEWS b/Misc/NEWS
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -52,6 +52,8 @@
 - Issue #24450: Add gi_yieldfrom to generators and cr_await to coroutines.
   Contributed by Benno Leslie and Yury Selivanov.
 
+- Issue #19235: Add new RecursionError exception. Patch by Georg Brandl.
+
 Library
 -------
 
diff --git a/Modules/_pickle.c b/Modules/_pickle.c
--- a/Modules/_pickle.c
+++ b/Modules/_pickle.c
@@ -3622,7 +3622,7 @@
              >>> pickle.dumps(1+2j)
              Traceback (most recent call last):
                ...
-             RuntimeError: maximum recursion depth exceeded
+             RecursionError: maximum recursion depth exceeded
 
            Removing the complex class from copyreg.dispatch_table made the
            __reduce_ex__() method emit another complex object:
diff --git a/Modules/_sre.c b/Modules/_sre.c
--- a/Modules/_sre.c
+++ b/Modules/_sre.c
@@ -497,8 +497,9 @@
 {
     switch (status) {
     case SRE_ERROR_RECURSION_LIMIT:
+        /* This error code seems to be unused. */
         PyErr_SetString(
-            PyExc_RuntimeError,
+            PyExc_RecursionError,
             "maximum recursion limit exceeded"
             );
         break;
diff --git a/Objects/exceptions.c b/Objects/exceptions.c
--- a/Objects/exceptions.c
+++ b/Objects/exceptions.c
@@ -1231,6 +1231,11 @@
 SimpleExtendsException(PyExc_Exception, RuntimeError,
                        "Unspecified run-time error.");
 
+/*
+ *    RecursionError extends RuntimeError
+ */
+SimpleExtendsException(PyExc_RuntimeError, RecursionError,
+                       "Recursion limit exceeded.");
 
 /*
  *    NotImplementedError extends RuntimeError
@@ -2380,7 +2385,7 @@
 
 
 
-/* Pre-computed RuntimeError instance for when recursion depth is reached.
+/* Pre-computed RecursionError instance for when recursion depth is reached.
    Meant to be used when normalizing the exception for exceeding the recursion
    depth will cause its own infinite recursion.
 */
@@ -2484,6 +2489,7 @@
     PRE_INIT(OSError)
     PRE_INIT(EOFError)
     PRE_INIT(RuntimeError)
+    PRE_INIT(RecursionError)
     PRE_INIT(NotImplementedError)
     PRE_INIT(NameError)
     PRE_INIT(UnboundLocalError)
@@ -2560,6 +2566,7 @@
 #endif
     POST_INIT(EOFError)
     POST_INIT(RuntimeError)
+    POST_INIT(RecursionError)
     POST_INIT(NotImplementedError)
     POST_INIT(NameError)
     POST_INIT(UnboundLocalError)
@@ -2643,9 +2650,9 @@
     preallocate_memerrors();
 
     if (!PyExc_RecursionErrorInst) {
-        PyExc_RecursionErrorInst = BaseException_new(&_PyExc_RuntimeError, NULL, NULL);
+        PyExc_RecursionErrorInst = BaseException_new(&_PyExc_RecursionError, NULL, NULL);
         if (!PyExc_RecursionErrorInst)
-            Py_FatalError("Cannot pre-allocate RuntimeError instance for "
+            Py_FatalError("Cannot pre-allocate RecursionError instance for "
                             "recursion errors");
         else {
             PyBaseExceptionObject *err_inst =
@@ -2654,15 +2661,15 @@
             PyObject *exc_message;
             exc_message = PyUnicode_FromString("maximum recursion depth exceeded");
             if (!exc_message)
-                Py_FatalError("cannot allocate argument for RuntimeError "
+                Py_FatalError("cannot allocate argument for RecursionError "
                                 "pre-allocation");
             args_tuple = PyTuple_Pack(1, exc_message);
             if (!args_tuple)
-                Py_FatalError("cannot allocate tuple for RuntimeError "
+                Py_FatalError("cannot allocate tuple for RecursionError "
                                 "pre-allocation");
             Py_DECREF(exc_message);
             if (BaseException_init(err_inst, args_tuple, NULL))
-                Py_FatalError("init of pre-allocated RuntimeError failed");
+                Py_FatalError("init of pre-allocated RecursionError failed");
             Py_DECREF(args_tuple);
         }
     }
diff --git a/Objects/typeobject.c b/Objects/typeobject.c
--- a/Objects/typeobject.c
+++ b/Objects/typeobject.c
@@ -4142,7 +4142,7 @@
  * were implemented in the same function:
  *  - trying to pickle an object with a custom __reduce__ method that
  *    fell back to object.__reduce__ in certain circumstances led to
- *    infinite recursion at Python level and eventual RuntimeError.
+ *    infinite recursion at Python level and eventual RecursionError.
  *  - Pickling objects that lied about their type by overwriting the
  *    __class__ descriptor could lead to infinite recursion at C level
  *    and eventual segfault.
diff --git a/Python/ceval.c b/Python/ceval.c
--- a/Python/ceval.c
+++ b/Python/ceval.c
@@ -737,7 +737,7 @@
     if (tstate->recursion_depth > recursion_limit) {
         --tstate->recursion_depth;
         tstate->overflowed = 1;
-        PyErr_Format(PyExc_RuntimeError,
+        PyErr_Format(PyExc_RecursionError,
                      "maximum recursion depth exceeded%s",
                      where);
         return -1;
diff --git a/Python/errors.c b/Python/errors.c
--- a/Python/errors.c
+++ b/Python/errors.c
@@ -319,7 +319,7 @@
         Py_DECREF(*exc);
         Py_DECREF(*val);
         /* ... and use the recursion error instead */
-        *exc = PyExc_RuntimeError;
+        *exc = PyExc_RecursionError;
         *val = PyExc_RecursionErrorInst;
         Py_INCREF(*exc);
         Py_INCREF(*val);
diff --git a/Python/symtable.c b/Python/symtable.c
--- a/Python/symtable.c
+++ b/Python/symtable.c
@@ -1135,7 +1135,7 @@
 symtable_visit_stmt(struct symtable *st, stmt_ty s)
 {
     if (++st->recursion_depth > st->recursion_limit) {
-        PyErr_SetString(PyExc_RuntimeError,
+        PyErr_SetString(PyExc_RecursionError,
                         "maximum recursion depth exceeded during compilation");
         VISIT_QUIT(st, 0);
     }
@@ -1357,7 +1357,7 @@
 symtable_visit_expr(struct symtable *st, expr_ty e)
 {
     if (++st->recursion_depth > st->recursion_limit) {
-        PyErr_SetString(PyExc_RuntimeError,
+        PyErr_SetString(PyExc_RecursionError,
                         "maximum recursion depth exceeded during compilation");
         VISIT_QUIT(st, 0);
     }
diff --git a/Tools/scripts/find_recursionlimit.py b/Tools/scripts/find_recursionlimit.py
--- a/Tools/scripts/find_recursionlimit.py
+++ b/Tools/scripts/find_recursionlimit.py
@@ -92,7 +92,7 @@
 def test_compiler_recursion():
     # The compiler uses a scaling factor to support additional levels
     # of recursion. This is a sanity check of that scaling to ensure
-    # it still raises RuntimeError even at higher recursion limits
+    # it still raises RecursionError even at higher recursion limits
     compile("()" * (10 * sys.getrecursionlimit()), "<single>", "single")
 
 def check_limit(n, test_func_name):
@@ -107,7 +107,7 @@
     # AttributeError can be raised because of the way e.g. PyDict_GetItem()
     # silences all exceptions and returns NULL, which is usually interpreted
     # as "missing attribute".
-    except (RuntimeError, AttributeError):
+    except (RecursionError, AttributeError):
         pass
     else:
         print("Yikes!")

-- 
Repository URL: https://hg.python.org/cpython


More information about the Python-checkins mailing list