blob: 3836727691229e3e81ef4bc3db666ec76e2efb90 [file] [log] [blame]
Terry Jan Reedy81bb97d2019-05-24 21:59:53 -04001""" idlelib.run
2
3Simplified, pyshell.ModifiedInterpreter spawns a subprocess with
4f'''{sys.executable} -c "__import__('idlelib.run').run.main()"'''
5'.run' is needed because __import__ returns idlelib, not idlelib.run.
6"""
Miss Islington (bot)5a5237c2021-05-07 17:35:25 -07007import contextlib
Tal Einatfcf1d002019-07-06 15:35:24 +03008import functools
Terry Jan Reedy6cf0e132016-07-15 02:43:03 -04009import io
Kurt B. Kaiser49a5fe12004-07-04 01:25:56 +000010import linecache
Terry Jan Reedy6cf0e132016-07-15 02:43:03 -040011import queue
12import sys
Tal Einatfcf1d002019-07-06 15:35:24 +030013import textwrap
Terry Jan Reedy6cf0e132016-07-15 02:43:03 -040014import time
15import traceback
Terry Jan Reedybfbaa6b2016-08-31 00:50:55 -040016import _thread as thread
17import threading
18import warnings
Kurt B. Kaiser5afa1df2002-10-10 08:25:24 +000019
Ken7a343802021-01-27 07:55:52 +080020import idlelib # testing
Terry Jan Reedybfbaa6b2016-08-31 00:50:55 -040021from idlelib import autocomplete # AutoComplete, fetch_encodings
Terry Jan Reedy06e20292018-06-19 23:00:35 -040022from idlelib import calltip # Calltip
Terry Jan Reedybfbaa6b2016-08-31 00:50:55 -040023from idlelib import debugger_r # start_debugger
24from idlelib import debugobj_r # remote_object_tree_item
25from idlelib import iomenu # encoding
26from idlelib import rpc # multiple objects
27from idlelib import stackviewer # StackTreeItem
Kurt B. Kaiser5afa1df2002-10-10 08:25:24 +000028import __main__
29
Terry Jan Reedy81bb97d2019-05-24 21:59:53 -040030import tkinter # Use tcl and, if startup fails, messagebox.
31if not hasattr(sys.modules['idlelib.run'], 'firstrun'):
32 # Undo modifications of tkinter by idlelib imports; see bpo-25507.
33 for mod in ('simpledialog', 'messagebox', 'font',
34 'dialog', 'filedialog', 'commondialog',
35 'ttk'):
36 delattr(tkinter, mod)
37 del sys.modules['tkinter.' + mod]
38 # Avoid AttributeError if run again; see bpo-37038.
39 sys.modules['idlelib.run'].firstrun = False
Terry Jan Reedyff1d5ab2016-07-16 18:26:32 -040040
Kurt B. Kaiser24d7e0c2003-06-05 23:51:29 +000041LOCALHOST = '127.0.0.1'
42
Kurt B. Kaiser49a5fe12004-07-04 01:25:56 +000043
Terry Jan Reedy6cf0e132016-07-15 02:43:03 -040044def idle_formatwarning(message, category, filename, lineno, line=None):
45 """Format warnings the IDLE way."""
46
47 s = "\nWarning (from warnings module):\n"
48 s += ' File \"%s\", line %s\n' % (filename, lineno)
49 if line is None:
50 line = linecache.getline(filename, lineno)
51 line = line.strip()
52 if line:
53 s += " %s\n" % line
54 s += "%s: %s\n" % (category.__name__, message)
55 return s
56
Terry Jan Reedy95a3f112013-06-28 23:50:12 -040057def idle_showwarning_subproc(
58 message, category, filename, lineno, file=None, line=None):
59 """Show Idle-format warning after replacing warnings.showwarning.
Andrew Svetlova2251aa2012-03-13 18:36:13 -070060
Terry Jan Reedy95a3f112013-06-28 23:50:12 -040061 The only difference is the formatter called.
62 """
63 if file is None:
64 file = sys.stderr
65 try:
Terry Jan Reedy6cf0e132016-07-15 02:43:03 -040066 file.write(idle_formatwarning(
Terry Jan Reedy95a3f112013-06-28 23:50:12 -040067 message, category, filename, lineno, line))
Serhiy Storchaka55fe1ae2017-04-16 10:46:38 +030068 except OSError:
Terry Jan Reedy95a3f112013-06-28 23:50:12 -040069 pass # the file (probably stderr) is invalid - this warning gets lost.
70
71_warnings_showwarning = None
72
73def capture_warnings(capture):
74 "Replace warning.showwarning with idle_showwarning_subproc, or reverse."
75
76 global _warnings_showwarning
77 if capture:
78 if _warnings_showwarning is None:
79 _warnings_showwarning = warnings.showwarning
80 warnings.showwarning = idle_showwarning_subproc
81 else:
82 if _warnings_showwarning is not None:
83 warnings.showwarning = _warnings_showwarning
84 _warnings_showwarning = None
85
86capture_warnings(True)
Andrew Svetlov753445a2012-03-26 21:56:44 +030087tcl = tkinter.Tcl()
88
Andrew Svetlov753445a2012-03-26 21:56:44 +030089def handle_tk_events(tcl=tcl):
Andrew Svetlova2251aa2012-03-13 18:36:13 -070090 """Process any tk events that are ready to be dispatched if tkinter
91 has been imported, a tcl interpreter has been created and tk has been
92 loaded."""
Andrew Svetlov753445a2012-03-26 21:56:44 +030093 tcl.eval("update")
Andrew Svetlova2251aa2012-03-13 18:36:13 -070094
Kurt B. Kaiser11c53e22003-03-22 19:40:19 +000095# Thread shared globals: Establish a queue between a subthread (which handles
96# the socket) and the main thread (which runs user code), plus global
Guido van Rossum8ce8a782007-11-01 19:42:39 +000097# completion, exit and interruptable (the main thread) flags:
Kurt B. Kaiser11c53e22003-03-22 19:40:19 +000098
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +000099exit_now = False
100quitting = False
Guido van Rossum8ce8a782007-11-01 19:42:39 +0000101interruptable = False
Kurt B. Kaiser11c53e22003-03-22 19:40:19 +0000102
Kurt B. Kaiser62df0442003-05-28 01:47:46 +0000103def main(del_exitfunc=False):
Kurt B. Kaiserb4179362002-07-26 00:06:42 +0000104 """Start the Python execution server in a subprocess
105
Kurt B. Kaiser5afa1df2002-10-10 08:25:24 +0000106 In the Python subprocess, RPCServer is instantiated with handlerclass
107 MyHandler, which inherits register/unregister methods from RPCHandler via
108 the mix-in class SocketIO.
Kurt B. Kaiserb4179362002-07-26 00:06:42 +0000109
Kurt B. Kaiser11c53e22003-03-22 19:40:19 +0000110 When the RPCServer 'server' is instantiated, the TCPServer initialization
Kurt B. Kaiser5afa1df2002-10-10 08:25:24 +0000111 creates an instance of run.MyHandler and calls its handle() method.
112 handle() instantiates a run.Executive object, passing it a reference to the
113 MyHandler object. That reference is saved as attribute rpchandler of the
114 Executive instance. The Executive methods have access to the reference and
115 can pass it on to entities that they command
Terry Jan Reedy6fa5bdc2016-05-28 13:22:31 -0400116 (e.g. debugger_r.Debugger.start_debugger()). The latter, in turn, can
Kurt B. Kaiser5afa1df2002-10-10 08:25:24 +0000117 call MyHandler(SocketIO) register/unregister methods via the reference to
118 register and unregister themselves.
Kurt B. Kaiserb4179362002-07-26 00:06:42 +0000119
120 """
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +0000121 global exit_now
122 global quitting
Kurt B. Kaiser62df0442003-05-28 01:47:46 +0000123 global no_exitfunc
124 no_exitfunc = del_exitfunc
Kurt B. Kaiseraf3eb872004-01-21 18:54:30 +0000125 #time.sleep(15) # test subprocess not responding
Kurt B. Kaisere67842a2009-04-04 20:13:23 +0000126 try:
127 assert(len(sys.argv) > 1)
128 port = int(sys.argv[-1])
129 except:
Kurt B. Kaiser8fc98c32009-04-04 20:20:29 +0000130 print("IDLE Subprocess: no IP port passed in sys.argv.",
131 file=sys.__stderr__)
Kurt B. Kaisere67842a2009-04-04 20:13:23 +0000132 return
Terry Jan Reedy95a3f112013-06-28 23:50:12 -0400133
134 capture_warnings(True)
Chui Tey5d2af632002-05-26 13:36:41 +0000135 sys.argv[:] = [""]
Kurt B. Kaiser11c53e22003-03-22 19:40:19 +0000136 sockthread = threading.Thread(target=manage_socket,
137 name='SockThread',
Kurt B. Kaiser24d7e0c2003-06-05 23:51:29 +0000138 args=((LOCALHOST, port),))
Benjamin Peterson71088cc2008-09-19 21:49:37 +0000139 sockthread.daemon = True
Kurt B. Kaiser11c53e22003-03-22 19:40:19 +0000140 sockthread.start()
141 while 1:
142 try:
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +0000143 if exit_now:
144 try:
Kurt B. Kaiser62df0442003-05-28 01:47:46 +0000145 exit()
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +0000146 except KeyboardInterrupt:
147 # exiting but got an extra KBI? Try again!
148 continue
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000149 try:
Terry Jan Reedy1e2fcac2017-12-04 16:16:18 -0500150 request = rpc.request_queue.get(block=True, timeout=0.05)
Alexandre Vassalottif260e442008-05-11 19:59:59 +0000151 except queue.Empty:
Terry Jan Reedy1e2fcac2017-12-04 16:16:18 -0500152 request = None
153 # Issue 32207: calling handle_tk_events here adds spurious
154 # queue.Empty traceback to event handling exceptions.
155 if request:
156 seq, (method, args, kwargs) = request
157 ret = method(*args, **kwargs)
158 rpc.response_queue.put((seq, ret))
159 else:
Andrew Svetlova2251aa2012-03-13 18:36:13 -0700160 handle_tk_events()
Kurt B. Kaiseraa6b8562003-05-14 18:15:40 +0000161 except KeyboardInterrupt:
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +0000162 if quitting:
163 exit_now = True
Kurt B. Kaiseraa6b8562003-05-14 18:15:40 +0000164 continue
Kurt B. Kaisera2792be2003-05-17 21:04:10 +0000165 except SystemExit:
Terry Jan Reedy95a3f112013-06-28 23:50:12 -0400166 capture_warnings(False)
Kurt B. Kaisera2792be2003-05-17 21:04:10 +0000167 raise
Kurt B. Kaiser9ec454e2003-05-12 02:33:47 +0000168 except:
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +0000169 type, value, tb = sys.exc_info()
Kurt B. Kaisera2792be2003-05-17 21:04:10 +0000170 try:
171 print_exception()
172 rpc.response_queue.put((seq, None))
173 except:
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +0000174 # Link didn't work, print same exception to __stderr__
175 traceback.print_exception(type, value, tb, file=sys.__stderr__)
Kurt B. Kaiser62df0442003-05-28 01:47:46 +0000176 exit()
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +0000177 else:
178 continue
Kurt B. Kaiser11c53e22003-03-22 19:40:19 +0000179
180def manage_socket(address):
Kurt B. Kaiseraf3eb872004-01-21 18:54:30 +0000181 for i in range(3):
Kurt B. Kaiserb4179362002-07-26 00:06:42 +0000182 time.sleep(i)
183 try:
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000184 server = MyRPCServer(address, MyHandler)
Kurt B. Kaiserb4179362002-07-26 00:06:42 +0000185 break
Andrew Svetlov0832af62012-12-18 23:10:48 +0200186 except OSError as err:
187 print("IDLE Subprocess: OSError: " + err.args[1] +
Georg Brandl6464d472007-10-22 16:16:13 +0000188 ", retrying....", file=sys.__stderr__)
Amaury Forgeot d'Arcefae8c42008-11-21 23:08:09 +0000189 socket_error = err
Kurt B. Kaiserb4179362002-07-26 00:06:42 +0000190 else:
Amaury Forgeot d'Arcefae8c42008-11-21 23:08:09 +0000191 print("IDLE Subprocess: Connection to "
192 "IDLE GUI failed, exiting.", file=sys.__stderr__)
193 show_socket_error(socket_error, address)
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +0000194 global exit_now
195 exit_now = True
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000196 return
Kurt B. Kaiser11c53e22003-03-22 19:40:19 +0000197 server.handle_request() # A single request only
198
Kurt B. Kaiseraf3eb872004-01-21 18:54:30 +0000199def show_socket_error(err, address):
terryjreedy188aedf2017-06-13 21:32:16 -0400200 "Display socket error from manage_socket."
Georg Brandl14fc4272008-05-17 18:39:55 +0000201 import tkinter
terryjreedy188aedf2017-06-13 21:32:16 -0400202 from tkinter.messagebox import showerror
Georg Brandl14fc4272008-05-17 18:39:55 +0000203 root = tkinter.Tk()
Serhiy Storchakaa96c96f2017-09-21 11:20:06 +0300204 fix_scaling(root)
Kurt B. Kaiseraf3eb872004-01-21 18:54:30 +0000205 root.withdraw()
Terry Jan Reedy8fac1222019-06-17 17:23:28 -0400206 showerror(
207 "Subprocess Connection Error",
208 f"IDLE's subprocess can't connect to {address[0]}:{address[1]}.\n"
209 f"Fatal OSError #{err.errno}: {err.strerror}.\n"
210 "See the 'Startup failure' section of the IDLE doc, online at\n"
211 "https://docs.python.org/3/library/idle.html#startup-failure",
212 parent=root)
Kurt B. Kaiseraf3eb872004-01-21 18:54:30 +0000213 root.destroy()
214
Miss Islington (bot)5a5237c2021-05-07 17:35:25 -0700215
216def get_message_lines(typ, exc, tb):
217 "Return line composing the exception message."
218 if typ in (AttributeError, NameError):
219 # 3.10+ hints are not directly accessible from python (#44026).
220 err = io.StringIO()
221 with contextlib.redirect_stderr(err):
222 sys.__excepthook__(typ, exc, tb)
223 return [err.getvalue().split("\n")[-2] + "\n"]
224 else:
225 return traceback.format_exception_only(typ, exc)
226
227
Kurt B. Kaiser9ec454e2003-05-12 02:33:47 +0000228def print_exception():
Kurt B. Kaisere9802a32004-01-02 04:04:04 +0000229 import linecache
230 linecache.checkcache()
Kurt B. Kaiser9ec454e2003-05-12 02:33:47 +0000231 flush_stdout()
232 efile = sys.stderr
Kurt B. Kaiser924f6162003-11-19 04:52:32 +0000233 typ, val, tb = excinfo = sys.exc_info()
234 sys.last_type, sys.last_value, sys.last_traceback = excinfo
Serhiy Storchaka78470b42013-01-09 12:21:57 +0200235 seen = set()
236
237 def print_exc(typ, exc, tb):
Zane Bitterde860732017-10-17 17:29:39 -0400238 seen.add(id(exc))
Serhiy Storchaka78470b42013-01-09 12:21:57 +0200239 context = exc.__context__
240 cause = exc.__cause__
Zane Bitterde860732017-10-17 17:29:39 -0400241 if cause is not None and id(cause) not in seen:
Serhiy Storchaka78470b42013-01-09 12:21:57 +0200242 print_exc(type(cause), cause, cause.__traceback__)
243 print("\nThe above exception was the direct cause "
244 "of the following exception:\n", file=efile)
Serhiy Storchaka71317492013-01-09 12:24:48 +0200245 elif (context is not None and
246 not exc.__suppress_context__ and
Zane Bitterde860732017-10-17 17:29:39 -0400247 id(context) not in seen):
Serhiy Storchaka78470b42013-01-09 12:21:57 +0200248 print_exc(type(context), context, context.__traceback__)
249 print("\nDuring handling of the above exception, "
250 "another exception occurred:\n", file=efile)
251 if tb:
252 tbe = traceback.extract_tb(tb)
253 print('Traceback (most recent call last):', file=efile)
254 exclude = ("run.py", "rpc.py", "threading.py", "queue.py",
Terry Jan Reedy6fa5bdc2016-05-28 13:22:31 -0400255 "debugger_r.py", "bdb.py")
Serhiy Storchaka78470b42013-01-09 12:21:57 +0200256 cleanup_traceback(tbe, exclude)
257 traceback.print_list(tbe, file=efile)
Miss Islington (bot)5a5237c2021-05-07 17:35:25 -0700258 lines = get_message_lines(typ, exc, tb)
Serhiy Storchaka78470b42013-01-09 12:21:57 +0200259 for line in lines:
260 print(line, end='', file=efile)
261
262 print_exc(typ, val, tb)
Kurt B. Kaiser9ec454e2003-05-12 02:33:47 +0000263
264def cleanup_traceback(tb, exclude):
265 "Remove excluded traces from beginning/end of tb; get cached lines"
266 orig_tb = tb[:]
267 while tb:
268 for rpcfile in exclude:
269 if tb[0][0].count(rpcfile):
270 break # found an exclude, break for: and delete tb[0]
271 else:
272 break # no excludes, have left RPC code, break while:
273 del tb[0]
274 while tb:
275 for rpcfile in exclude:
276 if tb[-1][0].count(rpcfile):
277 break
278 else:
279 break
280 del tb[-1]
281 if len(tb) == 0:
282 # exception was in IDLE internals, don't prune!
283 tb[:] = orig_tb[:]
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000284 print("** IDLE Internal Exception: ", file=sys.stderr)
Kurt B. Kaiser9ec454e2003-05-12 02:33:47 +0000285 rpchandler = rpc.objecttable['exec'].rpchandler
286 for i in range(len(tb)):
287 fn, ln, nm, line = tb[i]
288 if nm == '?':
289 nm = "-toplevel-"
290 if not line and fn.startswith("<pyshell#"):
291 line = rpchandler.remotecall('linecache', 'getline',
292 (fn, ln), {})
293 tb[i] = fn, ln, nm, line
294
295def flush_stdout():
Guido van Rossum79139b22007-02-09 23:20:19 +0000296 """XXX How to do this now?"""
Kurt B. Kaiser9ec454e2003-05-12 02:33:47 +0000297
Kurt B. Kaiser62df0442003-05-28 01:47:46 +0000298def exit():
Guido van Rossumc76a2502007-08-09 14:26:58 +0000299 """Exit subprocess, possibly after first clearing exit functions.
Kurt B. Kaiser62df0442003-05-28 01:47:46 +0000300
301 If config-main.cfg/.def 'General' 'delete-exitfunc' is True, then any
Guido van Rossumc76a2502007-08-09 14:26:58 +0000302 functions registered with atexit will be removed before exiting.
303 (VPython support)
Kurt B. Kaiser62df0442003-05-28 01:47:46 +0000304
305 """
306 if no_exitfunc:
Guido van Rossumc76a2502007-08-09 14:26:58 +0000307 import atexit
308 atexit._clear()
Terry Jan Reedy95a3f112013-06-28 23:50:12 -0400309 capture_warnings(False)
Kurt B. Kaiser62df0442003-05-28 01:47:46 +0000310 sys.exit(0)
Chui Tey5d2af632002-05-26 13:36:41 +0000311
Terry Jan Reedybfbaa6b2016-08-31 00:50:55 -0400312
Serhiy Storchakaa96c96f2017-09-21 11:20:06 +0300313def fix_scaling(root):
314 """Scale fonts on HiDPI displays."""
315 import tkinter.font
316 scaling = float(root.tk.call('tk', 'scaling'))
317 if scaling > 1.4:
318 for name in tkinter.font.names(root):
319 font = tkinter.font.Font(root=root, name=name, exists=True)
320 size = int(font['size'])
321 if size < 0:
322 font['size'] = round(-0.75*size)
323
324
Terry Jan Reedy6aeb2fe2019-07-09 14:37:25 -0400325def fixdoc(fun, text):
326 tem = (fun.__doc__ + '\n\n') if fun.__doc__ is not None else ''
327 fun.__doc__ = tem + textwrap.fill(textwrap.dedent(text))
328
Tal Einatfcf1d002019-07-06 15:35:24 +0300329RECURSIONLIMIT_DELTA = 30
Terry Jan Reedy6aeb2fe2019-07-09 14:37:25 -0400330
Tal Einatfcf1d002019-07-06 15:35:24 +0300331def install_recursionlimit_wrappers():
332 """Install wrappers to always add 30 to the recursion limit."""
333 # see: bpo-26806
334
335 @functools.wraps(sys.setrecursionlimit)
336 def setrecursionlimit(*args, **kwargs):
337 # mimic the original sys.setrecursionlimit()'s input handling
338 if kwargs:
339 raise TypeError(
340 "setrecursionlimit() takes no keyword arguments")
341 try:
342 limit, = args
343 except ValueError:
344 raise TypeError(f"setrecursionlimit() takes exactly one "
345 f"argument ({len(args)} given)")
346 if not limit > 0:
347 raise ValueError(
348 "recursion limit must be greater or equal than 1")
349
350 return setrecursionlimit.__wrapped__(limit + RECURSIONLIMIT_DELTA)
351
Terry Jan Reedy6aeb2fe2019-07-09 14:37:25 -0400352 fixdoc(setrecursionlimit, f"""\
353 This IDLE wrapper adds {RECURSIONLIMIT_DELTA} to prevent possible
354 uninterruptible loops.""")
Tal Einatfcf1d002019-07-06 15:35:24 +0300355
356 @functools.wraps(sys.getrecursionlimit)
357 def getrecursionlimit():
358 return getrecursionlimit.__wrapped__() - RECURSIONLIMIT_DELTA
359
Terry Jan Reedy6aeb2fe2019-07-09 14:37:25 -0400360 fixdoc(getrecursionlimit, f"""\
361 This IDLE wrapper subtracts {RECURSIONLIMIT_DELTA} to compensate
362 for the {RECURSIONLIMIT_DELTA} IDLE adds when setting the limit.""")
Tal Einatfcf1d002019-07-06 15:35:24 +0300363
364 # add the delta to the default recursion limit, to compensate
365 sys.setrecursionlimit(sys.getrecursionlimit() + RECURSIONLIMIT_DELTA)
366
367 sys.setrecursionlimit = setrecursionlimit
368 sys.getrecursionlimit = getrecursionlimit
369
370
371def uninstall_recursionlimit_wrappers():
372 """Uninstall the recursion limit wrappers from the sys module.
373
374 IDLE only uses this for tests. Users can import run and call
375 this to remove the wrapping.
376 """
377 if (
378 getattr(sys.setrecursionlimit, '__wrapped__', None) and
379 getattr(sys.getrecursionlimit, '__wrapped__', None)
380 ):
381 sys.setrecursionlimit = sys.setrecursionlimit.__wrapped__
382 sys.getrecursionlimit = sys.getrecursionlimit.__wrapped__
383 sys.setrecursionlimit(sys.getrecursionlimit() - RECURSIONLIMIT_DELTA)
384
385
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000386class MyRPCServer(rpc.RPCServer):
387
388 def handle_error(self, request, client_address):
389 """Override RPCServer method for IDLE
390
391 Interrupt the MainThread and exit server if link is dropped.
392
393 """
Kurt B. Kaisere9535112004-11-19 15:46:49 +0000394 global quitting
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000395 try:
396 raise
397 except SystemExit:
398 raise
399 except EOFError:
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +0000400 global exit_now
401 exit_now = True
Kurt B. Kaiser93e8e542003-06-13 22:03:43 +0000402 thread.interrupt_main()
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000403 except:
404 erf = sys.__stderr__
Terry Jan Reedyf2e161c2020-08-09 16:08:30 -0400405 print(textwrap.dedent(f"""
406 {'-'*40}
407 Unhandled exception in user code execution server!'
408 Thread: {threading.current_thread().name}
409 IDLE Client Address: {client_address}
410 Request: {request!r}
411 """), file=erf)
412 traceback.print_exc(limit=-20, file=erf)
413 print(textwrap.dedent(f"""
414 *** Unrecoverable, server exiting!
415
416 Users should never see this message; it is likely transient.
417 If this recurs, report this with a copy of the message
418 and an explanation of how to make it repeat.
419 {'-'*40}"""), file=erf)
Kurt B. Kaisere9535112004-11-19 15:46:49 +0000420 quitting = True
421 thread.interrupt_main()
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000422
Terry Jan Reedy6cf0e132016-07-15 02:43:03 -0400423
424# Pseudofiles for shell-remote communication (also used in pyshell)
425
Serhiy Storchakab690a272019-10-08 14:32:25 +0300426class StdioFile(io.TextIOBase):
Terry Jan Reedy6cf0e132016-07-15 02:43:03 -0400427
Serhiy Storchakab690a272019-10-08 14:32:25 +0300428 def __init__(self, shell, tags, encoding='utf-8', errors='strict'):
Terry Jan Reedy6cf0e132016-07-15 02:43:03 -0400429 self.shell = shell
430 self.tags = tags
431 self._encoding = encoding
Serhiy Storchakab690a272019-10-08 14:32:25 +0300432 self._errors = errors
Terry Jan Reedy6cf0e132016-07-15 02:43:03 -0400433
434 @property
435 def encoding(self):
436 return self._encoding
437
438 @property
Serhiy Storchakab690a272019-10-08 14:32:25 +0300439 def errors(self):
440 return self._errors
441
442 @property
Terry Jan Reedy6cf0e132016-07-15 02:43:03 -0400443 def name(self):
444 return '<%s>' % self.tags
445
446 def isatty(self):
447 return True
448
449
Serhiy Storchakab690a272019-10-08 14:32:25 +0300450class StdOutputFile(StdioFile):
Terry Jan Reedy6cf0e132016-07-15 02:43:03 -0400451
452 def writable(self):
453 return True
454
455 def write(self, s):
456 if self.closed:
457 raise ValueError("write to closed file")
Serhiy Storchakab690a272019-10-08 14:32:25 +0300458 s = str.encode(s, self.encoding, self.errors).decode(self.encoding, self.errors)
Terry Jan Reedy6cf0e132016-07-15 02:43:03 -0400459 return self.shell.write(s, self.tags)
460
461
Serhiy Storchakab690a272019-10-08 14:32:25 +0300462class StdInputFile(StdioFile):
463 _line_buffer = ''
Terry Jan Reedy6cf0e132016-07-15 02:43:03 -0400464
465 def readable(self):
466 return True
467
468 def read(self, size=-1):
469 if self.closed:
470 raise ValueError("read from closed file")
471 if size is None:
472 size = -1
473 elif not isinstance(size, int):
474 raise TypeError('must be int, not ' + type(size).__name__)
475 result = self._line_buffer
476 self._line_buffer = ''
477 if size < 0:
478 while True:
479 line = self.shell.readline()
480 if not line: break
481 result += line
482 else:
483 while len(result) < size:
484 line = self.shell.readline()
485 if not line: break
486 result += line
487 self._line_buffer = result[size:]
488 result = result[:size]
489 return result
490
491 def readline(self, size=-1):
492 if self.closed:
493 raise ValueError("read from closed file")
494 if size is None:
495 size = -1
496 elif not isinstance(size, int):
497 raise TypeError('must be int, not ' + type(size).__name__)
498 line = self._line_buffer or self.shell.readline()
499 if size < 0:
500 size = len(line)
501 eol = line.find('\n', 0, size)
502 if eol >= 0:
503 size = eol + 1
504 self._line_buffer = line[size:]
505 return line[:size]
506
507 def close(self):
508 self.shell.close()
509
510
Chui Tey5d2af632002-05-26 13:36:41 +0000511class MyHandler(rpc.RPCHandler):
512
513 def handle(self):
Kurt B. Kaiser11c53e22003-03-22 19:40:19 +0000514 """Override base method"""
Chui Tey5d2af632002-05-26 13:36:41 +0000515 executive = Executive(self)
516 self.register("exec", executive)
Serhiy Storchaka39e70a42013-01-25 15:30:58 +0200517 self.console = self.get_remote_proxy("console")
Serhiy Storchakab690a272019-10-08 14:32:25 +0300518 sys.stdin = StdInputFile(self.console, "stdin",
519 iomenu.encoding, iomenu.errors)
520 sys.stdout = StdOutputFile(self.console, "stdout",
521 iomenu.encoding, iomenu.errors)
522 sys.stderr = StdOutputFile(self.console, "stderr",
523 iomenu.encoding, "backslashreplace")
Serhiy Storchaka39e70a42013-01-25 15:30:58 +0200524
Andrew Svetlovcd49d532012-03-25 11:43:02 +0300525 sys.displayhook = rpc.displayhook
Kurt B. Kaiserf609a342007-12-28 03:57:56 +0000526 # page help() text to shell.
527 import pydoc # import must be done here to capture i/o binding
528 pydoc.pager = pydoc.plainpager
Benjamin Peterson0d4931e2013-05-11 22:24:28 -0500529
530 # Keep a reference to stdin so that it won't try to exit IDLE if
531 # sys.stdin gets changed from within IDLE's shell. See issue17838.
532 self._keep_stdin = sys.stdin
533
Tal Einatfcf1d002019-07-06 15:35:24 +0300534 install_recursionlimit_wrappers()
535
Kurt B. Kaiser9f366092003-06-02 01:50:19 +0000536 self.interp = self.get_remote_proxy("interp")
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000537 rpc.RPCHandler.getresponse(self, myseq=None, wait=0.05)
538
539 def exithook(self):
540 "override SocketIO method - wait for MainThread to shut us down"
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +0000541 time.sleep(10)
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000542
543 def EOFhook(self):
544 "Override SocketIO method - terminate wait on callback and exit thread"
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +0000545 global quitting
546 quitting = True
Kurt B. Kaiser93e8e542003-06-13 22:03:43 +0000547 thread.interrupt_main()
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000548
549 def decode_interrupthook(self):
550 "interrupt awakened thread"
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +0000551 global quitting
552 quitting = True
Kurt B. Kaiser93e8e542003-06-13 22:03:43 +0000553 thread.interrupt_main()
Kurt B. Kaiser11c53e22003-03-22 19:40:19 +0000554
Chui Tey5d2af632002-05-26 13:36:41 +0000555
Terry Jan Reedy8dfe1562021-01-24 14:08:50 -0500556class Executive:
Chui Tey5d2af632002-05-26 13:36:41 +0000557
558 def __init__(self, rpchandler):
Kurt B. Kaiserffd3a422002-06-26 02:32:09 +0000559 self.rpchandler = rpchandler
Ken7a343802021-01-27 07:55:52 +0800560 if idlelib.testing is False:
561 self.locals = __main__.__dict__
562 self.calltip = calltip.Calltip()
563 self.autocomplete = autocomplete.AutoComplete()
564 else:
565 self.locals = {}
Chui Tey5d2af632002-05-26 13:36:41 +0000566
567 def runcode(self, code):
Guido van Rossum8ce8a782007-11-01 19:42:39 +0000568 global interruptable
Kurt B. Kaiser86bc4642003-02-27 23:04:17 +0000569 try:
Ken7a343802021-01-27 07:55:52 +0800570 self.user_exc_info = None
Guido van Rossum8ce8a782007-11-01 19:42:39 +0000571 interruptable = True
572 try:
573 exec(code, self.locals)
574 finally:
575 interruptable = False
Terry Jan Reedy6d965b32019-05-19 22:52:22 -0400576 except SystemExit as e:
577 if e.args: # SystemExit called with an argument.
578 ob = e.args[0]
579 if not isinstance(ob, (type(None), int)):
580 print('SystemExit: ' + str(ob), file=sys.stderr)
581 # Return to the interactive prompt.
Kurt B. Kaiser86bc4642003-02-27 23:04:17 +0000582 except:
Ken7a343802021-01-27 07:55:52 +0800583 self.user_exc_info = sys.exc_info() # For testing, hook, viewer.
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +0000584 if quitting:
Kurt B. Kaiser62df0442003-05-28 01:47:46 +0000585 exit()
Ken7a343802021-01-27 07:55:52 +0800586 if sys.excepthook is sys.__excepthook__:
587 print_exception()
588 else:
589 try:
590 sys.excepthook(*self.user_exc_info)
591 except:
592 self.user_exc_info = sys.exc_info() # For testing.
593 print_exception()
Kurt B. Kaiser9f366092003-06-02 01:50:19 +0000594 jit = self.rpchandler.console.getvar("<<toggle-jit-stack-viewer>>")
595 if jit:
596 self.rpchandler.interp.open_remote_stack_viewer()
Kurt B. Kaiser11c53e22003-03-22 19:40:19 +0000597 else:
Kurt B. Kaiser9ec454e2003-05-12 02:33:47 +0000598 flush_stdout()
Chui Tey5d2af632002-05-26 13:36:41 +0000599
Kurt B. Kaiser003091c2003-02-17 18:57:16 +0000600 def interrupt_the_server(self):
Guido van Rossum8ce8a782007-11-01 19:42:39 +0000601 if interruptable:
602 thread.interrupt_main()
Kurt B. Kaiser11c53e22003-03-22 19:40:19 +0000603
Kurt B. Kaiser0e3a5772002-06-16 03:32:24 +0000604 def start_the_debugger(self, gui_adap_oid):
Terry Jan Reedy6fa5bdc2016-05-28 13:22:31 -0400605 return debugger_r.start_debugger(self.rpchandler, gui_adap_oid)
Kurt B. Kaiserffd3a422002-06-26 02:32:09 +0000606
607 def stop_the_debugger(self, idb_adap_oid):
608 "Unregister the Idb Adapter. Link objects and Idb then subject to GC"
609 self.rpchandler.unregister(idb_adap_oid)
Chui Tey5d2af632002-05-26 13:36:41 +0000610
Kurt B. Kaiser5afa1df2002-10-10 08:25:24 +0000611 def get_the_calltip(self, name):
612 return self.calltip.fetch_tip(name)
613
Kurt B. Kaiserb1754452005-11-18 22:05:48 +0000614 def get_the_completion_list(self, what, mode):
615 return self.autocomplete.fetch_completions(what, mode)
616
Chui Tey5d2af632002-05-26 13:36:41 +0000617 def stackviewer(self, flist_oid=None):
Ken7a343802021-01-27 07:55:52 +0800618 if self.user_exc_info:
619 typ, val, tb = self.user_exc_info
Kurt B. Kaiser9f366092003-06-02 01:50:19 +0000620 else:
Chui Tey5d2af632002-05-26 13:36:41 +0000621 return None
622 flist = None
623 if flist_oid is not None:
Kurt B. Kaiserffd3a422002-06-26 02:32:09 +0000624 flist = self.rpchandler.get_remote_proxy(flist_oid)
Chui Tey5d2af632002-05-26 13:36:41 +0000625 while tb and tb.tb_frame.f_globals["__name__"] in ["rpc", "run"]:
626 tb = tb.tb_next
Kurt B. Kaiser9f366092003-06-02 01:50:19 +0000627 sys.last_type = typ
628 sys.last_value = val
Terry Jan Reedy6fa5bdc2016-05-28 13:22:31 -0400629 item = stackviewer.StackTreeItem(flist, tb)
630 return debugobj_r.remote_object_tree_item(item)
Terry Jan Reedy95a3f112013-06-28 23:50:12 -0400631
Terry Jan Reedy81bb97d2019-05-24 21:59:53 -0400632
633if __name__ == '__main__':
634 from unittest import main
635 main('idlelib.idle_test.test_run', verbosity=2)
636
637capture_warnings(False) # Make sure turned off; see bpo-18081.