summaryrefslogtreecommitdiffstats
path: root/Lib/idlelib/run.py
diff options
context:
space:
mode:
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)