summaryrefslogtreecommitdiffstats
path: root/Lib/idlelib/run.py
diff options
context:
space:
mode:
authorMiss Islington (bot) <31488909+miss-islington@users.noreply.github.com>2019-07-06 12:54:17 (GMT)
committerGitHub <noreply@github.com>2019-07-06 12:54:17 (GMT)
commitd4af55391f56286ab8d478591017174a5a0a5ce2 (patch)
treee2bbbb3535f87d3286a25beb90f2dc29f0d43d87 /Lib/idlelib/run.py
parentea9c8caa13977561787bf2de430f18c2031dde0d (diff)
downloadcpython-d4af55391f56286ab8d478591017174a5a0a5ce2.zip
cpython-d4af55391f56286ab8d478591017174a5a0a5ce2.tar.gz
cpython-d4af55391f56286ab8d478591017174a5a0a5ce2.tar.bz2
bpo-26806: add 30 to the recursion limit in IDLE's shell (GH-13944)
This is done to compensate for the extra stack frames added by IDLE itself, which cause problems when setting the recursion limit to low values. This wraps sys.setrecursionlimit() and sys.getrecursionlimit() as invisibly as possible. (cherry picked from commit fcf1d003bf4f0100c9d0921ff3d70e1127ca1b71) Co-authored-by: Tal Einat <taleinat+github@gmail.com>
Diffstat (limited to 'Lib/idlelib/run.py')
-rw-r--r--Lib/idlelib/run.py62
1 files changed, 62 insertions, 0 deletions
diff --git a/Lib/idlelib/run.py b/Lib/idlelib/run.py
index 6b3928b..c6ed76b 100644
--- a/Lib/idlelib/run.py
+++ b/Lib/idlelib/run.py
@@ -4,10 +4,12 @@ Simplified, pyshell.ModifiedInterpreter spawns a subprocess with
f'''{sys.executable} -c "__import__('idlelib.run').run.main()"'''
'.run' is needed because __import__ returns idlelib, not idlelib.run.
"""
+import functools
import io
import linecache
import queue
import sys
+import textwrap
import time
import traceback
import _thread as thread
@@ -305,6 +307,64 @@ def fix_scaling(root):
font['size'] = round(-0.75*size)
+RECURSIONLIMIT_DELTA = 30
+def install_recursionlimit_wrappers():
+ """Install wrappers to always add 30 to the recursion limit."""
+ # see: bpo-26806
+
+ @functools.wraps(sys.setrecursionlimit)
+ def setrecursionlimit(*args, **kwargs):
+ # mimic the original sys.setrecursionlimit()'s input handling
+ if kwargs:
+ raise TypeError(
+ "setrecursionlimit() takes no keyword arguments")
+ try:
+ limit, = args
+ except ValueError:
+ raise TypeError(f"setrecursionlimit() takes exactly one "
+ f"argument ({len(args)} given)")
+ if not limit > 0:
+ raise ValueError(
+ "recursion limit must be greater or equal than 1")
+
+ return setrecursionlimit.__wrapped__(limit + RECURSIONLIMIT_DELTA)
+
+ setrecursionlimit.__doc__ += "\n\n" + textwrap.fill(textwrap.dedent(f"""\
+ This IDLE wrapper adds {RECURSIONLIMIT_DELTA} to prevent possible
+ uninterruptible loops.
+ """).strip())
+
+ @functools.wraps(sys.getrecursionlimit)
+ def getrecursionlimit():
+ return getrecursionlimit.__wrapped__() - RECURSIONLIMIT_DELTA
+
+ getrecursionlimit.__doc__ += "\n\n" + textwrap.fill(textwrap.dedent(f"""\
+ This IDLE wrapper subtracts {RECURSIONLIMIT_DELTA} to compensate for
+ the {RECURSIONLIMIT_DELTA} IDLE adds when setting the limit.
+ """).strip())
+
+ # add the delta to the default recursion limit, to compensate
+ sys.setrecursionlimit(sys.getrecursionlimit() + RECURSIONLIMIT_DELTA)
+
+ sys.setrecursionlimit = setrecursionlimit
+ sys.getrecursionlimit = getrecursionlimit
+
+
+def uninstall_recursionlimit_wrappers():
+ """Uninstall the recursion limit wrappers from the sys module.
+
+ IDLE only uses this for tests. Users can import run and call
+ this to remove the wrapping.
+ """
+ if (
+ getattr(sys.setrecursionlimit, '__wrapped__', None) and
+ getattr(sys.getrecursionlimit, '__wrapped__', None)
+ ):
+ sys.setrecursionlimit = sys.setrecursionlimit.__wrapped__
+ sys.getrecursionlimit = sys.getrecursionlimit.__wrapped__
+ sys.setrecursionlimit(sys.getrecursionlimit() - RECURSIONLIMIT_DELTA)
+
+
class MyRPCServer(rpc.RPCServer):
def handle_error(self, request, client_address):
@@ -448,6 +508,8 @@ class MyHandler(rpc.RPCHandler):
# sys.stdin gets changed from within IDLE's shell. See issue17838.
self._keep_stdin = sys.stdin
+ install_recursionlimit_wrappers()
+
self.interp = self.get_remote_proxy("interp")
rpc.RPCHandler.getresponse(self, myseq=None, wait=0.05)