diff options
Diffstat (limited to 'Lib/idlelib/run.py')
-rw-r--r-- | Lib/idlelib/run.py | 62 |
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) |