# HG changeset patch # User Georg Brandl # Date 1381681874 -7200 # Sun Oct 13 18:31:14 2013 +0200 # Node ID 2e60eaf8b3340bfe21d409b0ea6386f27059d4a7 # Parent eeed65cb68b0ab8f3457e1a01f3f9e1168fc6edd Closes #19235: Add a dedicated RecursionError subclass of RuntimeError. diff -r eeed65cb68b0 -r 2e60eaf8b334 Doc/c-api/exceptions.rst --- a/Doc/c-api/exceptions.rst Sun Oct 13 18:12:22 2013 +0300 +++ b/Doc/c-api/exceptions.rst Sun Oct 13 18:31:14 2013 +0200 @@ -609,12 +609,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() @@ -726,6 +726,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` | | @@ -755,6 +757,9 @@ :c:data:`PyExc_PermissionError`, :c:data:`PyExc_ProcessLookupError` and :c:data:`PyExc_TimeoutError` were introduced following :pep:`3151`. +.. versionadded:: 3.4 + :c:data:`PyExc_RecursionError`. + These are compatibility aliases to :c:data:`PyExc_OSError`: @@ -803,6 +808,7 @@ single: PyExc_OverflowError single: PyExc_PermissionError single: PyExc_ProcessLookupError + single: PyExc_RecursionError single: PyExc_ReferenceError single: PyExc_RuntimeError single: PyExc_SyntaxError diff -r eeed65cb68b0 -r 2e60eaf8b334 Doc/library/exceptions.rst --- a/Doc/library/exceptions.rst Sun Oct 13 18:12:22 2013 +0300 +++ b/Doc/library/exceptions.rst Sun Oct 13 18:31:14 2013 +0200 @@ -276,6 +276,16 @@ aren't 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.4 + Previously, a plain :exc:`RuntimeError` was raised. + + .. exception:: ReferenceError This exception is raised when a weak reference proxy, created by the diff -r eeed65cb68b0 -r 2e60eaf8b334 Doc/library/pickle.rst --- a/Doc/library/pickle.rst Sun Oct 13 18:12:22 2013 +0300 +++ b/Doc/library/pickle.rst Sun Oct 13 18:31:14 2013 +0200 @@ -397,7 +397,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 -r eeed65cb68b0 -r 2e60eaf8b334 Include/ceval.h --- a/Include/ceval.h Sun Oct 13 18:12:22 2013 +0300 +++ b/Include/ceval.h Sun Oct 13 18:31:14 2013 +0200 @@ -46,16 +46,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 -r eeed65cb68b0 -r 2e60eaf8b334 Include/pyerrors.h --- a/Include/pyerrors.h Sun Oct 13 18:12:22 2013 +0300 +++ b/Include/pyerrors.h Sun Oct 13 18:31:14 2013 +0200 @@ -160,6 +160,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 -r eeed65cb68b0 -r 2e60eaf8b334 Lib/ctypes/test/test_as_parameter.py --- a/Lib/ctypes/test/test_as_parameter.py Sun Oct 13 18:12:22 2013 +0300 +++ b/Lib/ctypes/test/test_as_parameter.py Sun Oct 13 18:31:14 2013 +0200 @@ -196,7 +196,7 @@ a = A() a._as_parameter_ = a - with self.assertRaises(RuntimeError): + with self.assertRaises(RecursionError): c_int.from_param(a) diff -r eeed65cb68b0 -r 2e60eaf8b334 Lib/test/exception_hierarchy.txt --- a/Lib/test/exception_hierarchy.txt Sun Oct 13 18:12:22 2013 +0300 +++ b/Lib/test/exception_hierarchy.txt Sun Oct 13 18:31:14 2013 +0200 @@ -38,6 +38,7 @@ +-- ReferenceError +-- RuntimeError | +-- NotImplementedError + | +-- RecursionError +-- SyntaxError | +-- IndentationError | +-- TabError diff -r eeed65cb68b0 -r 2e60eaf8b334 Lib/test/list_tests.py --- a/Lib/test/list_tests.py Sun Oct 13 18:12:22 2013 +0300 +++ b/Lib/test/list_tests.py Sun Oct 13 18:31:14 2013 +0200 @@ -50,7 +50,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 -r eeed65cb68b0 -r 2e60eaf8b334 Lib/test/pickletester.py --- a/Lib/test/pickletester.py Sun Oct 13 18:12:22 2013 +0300 +++ b/Lib/test/pickletester.py Sun Oct 13 18:31:14 2013 +0200 @@ -1060,8 +1060,8 @@ def test_bad_getattr(self): x = BadGetattr() for proto in 0, 1: - self.assertRaises(RuntimeError, self.dumps, x, proto) - # protocol 2 don't raise a RuntimeError. + self.assertRaises(RecursionError, self.dumps, x, proto) + # protocol 2 don't raise a RecursionError. d = self.dumps(x, 2) def test_reduce_bad_iterator(self): diff -r eeed65cb68b0 -r 2e60eaf8b334 Lib/test/test_class.py --- a/Lib/test/test_class.py Sun Oct 13 18:12:22 2013 +0300 +++ b/Lib/test/test_class.py Sun Oct 13 18:31:14 2013 +0200 @@ -477,10 +477,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 -r eeed65cb68b0 -r 2e60eaf8b334 Lib/test/test_compile.py --- a/Lib/test/test_compile.py Sun Oct 13 18:12:22 2013 +0300 +++ b/Lib/test/test_compile.py Sun Oct 13 18:31:14 2013 +0200 @@ -492,7 +492,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 -r eeed65cb68b0 -r 2e60eaf8b334 Lib/test/test_copy.py --- a/Lib/test/test_copy.py Sun Oct 13 18:12:22 2013 +0300 +++ b/Lib/test/test_copy.py Sun Oct 13 18:31:14 2013 +0200 @@ -290,7 +290,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) @@ -317,7 +317,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) @@ -336,7 +336,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 -r eeed65cb68b0 -r 2e60eaf8b334 Lib/test/test_descr.py --- a/Lib/test/test_descr.py Sun Oct 13 18:12:22 2013 +0300 +++ b/Lib/test/test_descr.py Sun Oct 13 18:31:14 2013 +0200 @@ -3486,7 +3486,7 @@ A.__call__ = A() try: A()() - except RuntimeError: + except RecursionError: pass else: self.fail("Recursion limit should have been reached for __call__()") @@ -4461,8 +4461,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 -r eeed65cb68b0 -r 2e60eaf8b334 Lib/test/test_dictviews.py --- a/Lib/test/test_dictviews.py Sun Oct 13 18:12:22 2013 +0300 +++ b/Lib/test/test_dictviews.py Sun Oct 13 18:31:14 2013 +0200 @@ -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_main(): diff -r eeed65cb68b0 -r 2e60eaf8b334 Lib/test/test_exceptions.py --- a/Lib/test/test_exceptions.py Sun Oct 13 18:12:22 2013 +0300 +++ b/Lib/test/test_exceptions.py Sun Oct 13 18:31:14 2013 +0200 @@ -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') @@ -451,14 +452,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. @@ -812,10 +813,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)) @@ -912,7 +913,7 @@ # 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") diff -r eeed65cb68b0 -r 2e60eaf8b334 Lib/test/test_isinstance.py --- a/Lib/test/test_isinstance.py Sun Oct 13 18:12:22 2013 +0300 +++ b/Lib/test/test_isinstance.py Sun Oct 13 18:31:14 2013 +0200 @@ -259,18 +259,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 -r eeed65cb68b0 -r 2e60eaf8b334 Lib/test/test_json/test_recursion.py --- a/Lib/test/test_json/test_recursion.py Sun Oct 13 18:12:22 2013 +0300 +++ b/Lib/test/test_json/test_recursion.py Sun Oct 13 18:31:14 2013 +0200 @@ -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 -r eeed65cb68b0 -r 2e60eaf8b334 Lib/test/test_richcmp.py --- a/Lib/test/test_richcmp.py Sun Oct 13 18:12:22 2013 +0300 +++ b/Lib/test/test_richcmp.py Sun Oct 13 18:31:14 2013 +0200 @@ -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 -r eeed65cb68b0 -r 2e60eaf8b334 Lib/test/test_runpy.py --- a/Lib/test/test_runpy.py Sun Oct 13 18:12:22 2013 +0300 +++ b/Lib/test/test_runpy.py Sun Oct 13 18:31:14 2013 +0200 @@ -561,7 +561,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 -r eeed65cb68b0 -r 2e60eaf8b334 Lib/test/test_sys.py --- a/Lib/test/test_sys.py Sun Oct 13 18:12:22 2013 +0300 +++ b/Lib/test/test_sys.py Sun Oct 13 18:31:14 2013 +0200 @@ -231,8 +231,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) @@ -245,7 +245,7 @@ def f(): try: f() - except RuntimeError: + except RecursionError: f() sys.setrecursionlimit(%d) diff -r eeed65cb68b0 -r 2e60eaf8b334 Lib/test/test_threading.py --- a/Lib/test/test_threading.py Sun Oct 13 18:12:22 2013 +0300 +++ b/Lib/test/test_threading.py Sun Oct 13 18:31:14 2013 +0200 @@ -905,7 +905,7 @@ def outer(): try: recurse() - except RuntimeError: + except RecursionError: pass w = threading.Thread(target=outer) diff -r eeed65cb68b0 -r 2e60eaf8b334 Modules/_pickle.c --- a/Modules/_pickle.c Sun Oct 13 18:12:22 2013 +0300 +++ b/Modules/_pickle.c Sun Oct 13 18:31:14 2013 +0200 @@ -3076,7 +3076,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 -r eeed65cb68b0 -r 2e60eaf8b334 Modules/_sre.c --- a/Modules/_sre.c Sun Oct 13 18:12:22 2013 +0300 +++ b/Modules/_sre.c Sun Oct 13 18:31:14 2013 +0200 @@ -1839,8 +1839,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 -r eeed65cb68b0 -r 2e60eaf8b334 Objects/exceptions.c --- a/Objects/exceptions.c Sun Oct 13 18:12:22 2013 +0300 +++ b/Objects/exceptions.c Sun Oct 13 18:31:14 2013 +0200 @@ -1172,6 +1172,11 @@ SimpleExtendsException(PyExc_Exception, RuntimeError, "Unspecified run-time error."); +/* + * RecursionError extends RuntimeError + */ +SimpleExtendsException(PyExc_RuntimeError, RecursionError, + "Recursion limit exceeded."); /* * NotImplementedError extends RuntimeError @@ -2295,7 +2300,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. */ @@ -2398,6 +2403,7 @@ PRE_INIT(OSError) PRE_INIT(EOFError) PRE_INIT(RuntimeError) + PRE_INIT(RecursionError) PRE_INIT(NotImplementedError) PRE_INIT(NameError) PRE_INIT(UnboundLocalError) @@ -2476,6 +2482,7 @@ #endif POST_INIT(EOFError) POST_INIT(RuntimeError) + POST_INIT(RecursionError) POST_INIT(NotImplementedError) POST_INIT(NameError) POST_INIT(UnboundLocalError) @@ -2559,9 +2566,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 = @@ -2570,15 +2577,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 -r eeed65cb68b0 -r 2e60eaf8b334 Objects/typeobject.c --- a/Objects/typeobject.c Sun Oct 13 18:12:22 2013 +0300 +++ b/Objects/typeobject.c Sun Oct 13 18:31:14 2013 +0200 @@ -3577,7 +3577,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 -r eeed65cb68b0 -r 2e60eaf8b334 Python/ceval.c --- a/Python/ceval.c Sun Oct 13 18:12:22 2013 +0300 +++ b/Python/ceval.c Sun Oct 13 18:31:14 2013 +0200 @@ -730,7 +730,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 -r eeed65cb68b0 -r 2e60eaf8b334 Python/errors.c --- a/Python/errors.c Sun Oct 13 18:12:22 2013 +0300 +++ b/Python/errors.c Sun Oct 13 18:31:14 2013 +0200 @@ -316,7 +316,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 -r eeed65cb68b0 -r 2e60eaf8b334 Python/symtable.c --- a/Python/symtable.c Sun Oct 13 18:12:22 2013 +0300 +++ b/Python/symtable.c Sun Oct 13 18:31:14 2013 +0200 @@ -1169,7 +1169,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); } @@ -1374,7 +1374,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 -r eeed65cb68b0 -r 2e60eaf8b334 Tools/scripts/find_recursionlimit.py --- a/Tools/scripts/find_recursionlimit.py Sun Oct 13 18:12:22 2013 +0300 +++ b/Tools/scripts/find_recursionlimit.py Sun Oct 13 18:31:14 2013 +0200 @@ -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") 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!")