blob: 41e0ded44029375eebd70e8f7c9d850d173b4980 [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"""
Tal Einatfcf1d002019-07-06 15:35:24 +03007import functools
Terry Jan Reedy6cf0e132016-07-15 02:43:03 -04008import io
Kurt B. Kaiser49a5fe12004-07-04 01:25:56 +00009import linecache
Terry Jan Reedy6cf0e132016-07-15 02:43:03 -040010import queue
11import sys
Tal Einatfcf1d002019-07-06 15:35:24 +030012import textwrap
Terry Jan Reedy6cf0e132016-07-15 02:43:03 -040013import time
14import traceback
Terry Jan Reedybfbaa6b2016-08-31 00:50:55 -040015import _thread as thread
16import threading
17import warnings
Kurt B. Kaiser5afa1df2002-10-10 08:25:24 +000018
Terry Jan Reedybfbaa6b2016-08-31 00:50:55 -040019from idlelib import autocomplete # AutoComplete, fetch_encodings
Terry Jan Reedy06e20292018-06-19 23:00:35 -040020from idlelib import calltip # Calltip
Terry Jan Reedybfbaa6b2016-08-31 00:50:55 -040021from idlelib import debugger_r # start_debugger
22from idlelib import debugobj_r # remote_object_tree_item
23from idlelib import iomenu # encoding
24from idlelib import rpc # multiple objects
25from idlelib import stackviewer # StackTreeItem
Kurt B. Kaiser5afa1df2002-10-10 08:25:24 +000026import __main__
27
Terry Jan Reedy81bb97d2019-05-24 21:59:53 -040028import tkinter # Use tcl and, if startup fails, messagebox.
29if not hasattr(sys.modules['idlelib.run'], 'firstrun'):
30 # Undo modifications of tkinter by idlelib imports; see bpo-25507.
31 for mod in ('simpledialog', 'messagebox', 'font',
32 'dialog', 'filedialog', 'commondialog',
33 'ttk'):
34 delattr(tkinter, mod)
35 del sys.modules['tkinter.' + mod]
36 # Avoid AttributeError if run again; see bpo-37038.
37 sys.modules['idlelib.run'].firstrun = False
Terry Jan Reedyff1d5ab2016-07-16 18:26:32 -040038
Kurt B. Kaiser24d7e0c2003-06-05 23:51:29 +000039LOCALHOST = '127.0.0.1'
40
Kurt B. Kaiser49a5fe12004-07-04 01:25:56 +000041
Terry Jan Reedy6cf0e132016-07-15 02:43:03 -040042def idle_formatwarning(message, category, filename, lineno, line=None):
43 """Format warnings the IDLE way."""
44
45 s = "\nWarning (from warnings module):\n"
46 s += ' File \"%s\", line %s\n' % (filename, lineno)
47 if line is None:
48 line = linecache.getline(filename, lineno)
49 line = line.strip()
50 if line:
51 s += " %s\n" % line
52 s += "%s: %s\n" % (category.__name__, message)
53 return s
54
Terry Jan Reedy95a3f112013-06-28 23:50:12 -040055def idle_showwarning_subproc(
56 message, category, filename, lineno, file=None, line=None):
57 """Show Idle-format warning after replacing warnings.showwarning.
Andrew Svetlova2251aa2012-03-13 18:36:13 -070058
Terry Jan Reedy95a3f112013-06-28 23:50:12 -040059 The only difference is the formatter called.
60 """
61 if file is None:
62 file = sys.stderr
63 try:
Terry Jan Reedy6cf0e132016-07-15 02:43:03 -040064 file.write(idle_formatwarning(
Terry Jan Reedy95a3f112013-06-28 23:50:12 -040065 message, category, filename, lineno, line))
Serhiy Storchaka55fe1ae2017-04-16 10:46:38 +030066 except OSError:
Terry Jan Reedy95a3f112013-06-28 23:50:12 -040067 pass # the file (probably stderr) is invalid - this warning gets lost.
68
69_warnings_showwarning = None
70
71def capture_warnings(capture):
72 "Replace warning.showwarning with idle_showwarning_subproc, or reverse."
73
74 global _warnings_showwarning
75 if capture:
76 if _warnings_showwarning is None:
77 _warnings_showwarning = warnings.showwarning
78 warnings.showwarning = idle_showwarning_subproc
79 else:
80 if _warnings_showwarning is not None:
81 warnings.showwarning = _warnings_showwarning
82 _warnings_showwarning = None
83
84capture_warnings(True)
Andrew Svetlov753445a2012-03-26 21:56:44 +030085tcl = tkinter.Tcl()
86
Andrew Svetlov753445a2012-03-26 21:56:44 +030087def handle_tk_events(tcl=tcl):
Andrew Svetlova2251aa2012-03-13 18:36:13 -070088 """Process any tk events that are ready to be dispatched if tkinter
89 has been imported, a tcl interpreter has been created and tk has been
90 loaded."""
Andrew Svetlov753445a2012-03-26 21:56:44 +030091 tcl.eval("update")
Andrew Svetlova2251aa2012-03-13 18:36:13 -070092
Kurt B. Kaiser11c53e22003-03-22 19:40:19 +000093# Thread shared globals: Establish a queue between a subthread (which handles
94# the socket) and the main thread (which runs user code), plus global
Guido van Rossum8ce8a782007-11-01 19:42:39 +000095# completion, exit and interruptable (the main thread) flags:
Kurt B. Kaiser11c53e22003-03-22 19:40:19 +000096
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +000097exit_now = False
98quitting = False
Guido van Rossum8ce8a782007-11-01 19:42:39 +000099interruptable = False
Kurt B. Kaiser11c53e22003-03-22 19:40:19 +0000100
Kurt B. Kaiser62df0442003-05-28 01:47:46 +0000101def main(del_exitfunc=False):
Kurt B. Kaiserb4179362002-07-26 00:06:42 +0000102 """Start the Python execution server in a subprocess
103
Kurt B. Kaiser5afa1df2002-10-10 08:25:24 +0000104 In the Python subprocess, RPCServer is instantiated with handlerclass
105 MyHandler, which inherits register/unregister methods from RPCHandler via
106 the mix-in class SocketIO.
Kurt B. Kaiserb4179362002-07-26 00:06:42 +0000107
Kurt B. Kaiser11c53e22003-03-22 19:40:19 +0000108 When the RPCServer 'server' is instantiated, the TCPServer initialization
Kurt B. Kaiser5afa1df2002-10-10 08:25:24 +0000109 creates an instance of run.MyHandler and calls its handle() method.
110 handle() instantiates a run.Executive object, passing it a reference to the
111 MyHandler object. That reference is saved as attribute rpchandler of the
112 Executive instance. The Executive methods have access to the reference and
113 can pass it on to entities that they command
Terry Jan Reedy6fa5bdc2016-05-28 13:22:31 -0400114 (e.g. debugger_r.Debugger.start_debugger()). The latter, in turn, can
Kurt B. Kaiser5afa1df2002-10-10 08:25:24 +0000115 call MyHandler(SocketIO) register/unregister methods via the reference to
116 register and unregister themselves.
Kurt B. Kaiserb4179362002-07-26 00:06:42 +0000117
118 """
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +0000119 global exit_now
120 global quitting
Kurt B. Kaiser62df0442003-05-28 01:47:46 +0000121 global no_exitfunc
122 no_exitfunc = del_exitfunc
Kurt B. Kaiseraf3eb872004-01-21 18:54:30 +0000123 #time.sleep(15) # test subprocess not responding
Kurt B. Kaisere67842a2009-04-04 20:13:23 +0000124 try:
125 assert(len(sys.argv) > 1)
126 port = int(sys.argv[-1])
127 except:
Kurt B. Kaiser8fc98c32009-04-04 20:20:29 +0000128 print("IDLE Subprocess: no IP port passed in sys.argv.",
129 file=sys.__stderr__)
Kurt B. Kaisere67842a2009-04-04 20:13:23 +0000130 return
Terry Jan Reedy95a3f112013-06-28 23:50:12 -0400131
132 capture_warnings(True)
Chui Tey5d2af632002-05-26 13:36:41 +0000133 sys.argv[:] = [""]
Kurt B. Kaiser11c53e22003-03-22 19:40:19 +0000134 sockthread = threading.Thread(target=manage_socket,
135 name='SockThread',
Kurt B. Kaiser24d7e0c2003-06-05 23:51:29 +0000136 args=((LOCALHOST, port),))
Benjamin Peterson71088cc2008-09-19 21:49:37 +0000137 sockthread.daemon = True
Kurt B. Kaiser11c53e22003-03-22 19:40:19 +0000138 sockthread.start()
139 while 1:
140 try:
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +0000141 if exit_now:
142 try:
Kurt B. Kaiser62df0442003-05-28 01:47:46 +0000143 exit()
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +0000144 except KeyboardInterrupt:
145 # exiting but got an extra KBI? Try again!
146 continue
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000147 try:
Terry Jan Reedy1e2fcac2017-12-04 16:16:18 -0500148 request = rpc.request_queue.get(block=True, timeout=0.05)
Alexandre Vassalottif260e442008-05-11 19:59:59 +0000149 except queue.Empty:
Terry Jan Reedy1e2fcac2017-12-04 16:16:18 -0500150 request = None
151 # Issue 32207: calling handle_tk_events here adds spurious
152 # queue.Empty traceback to event handling exceptions.
153 if request:
154 seq, (method, args, kwargs) = request
155 ret = method(*args, **kwargs)
156 rpc.response_queue.put((seq, ret))
157 else:
Andrew Svetlova2251aa2012-03-13 18:36:13 -0700158 handle_tk_events()
Kurt B. Kaiseraa6b8562003-05-14 18:15:40 +0000159 except KeyboardInterrupt:
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +0000160 if quitting:
161 exit_now = True
Kurt B. Kaiseraa6b8562003-05-14 18:15:40 +0000162 continue
Kurt B. Kaisera2792be2003-05-17 21:04:10 +0000163 except SystemExit:
Terry Jan Reedy95a3f112013-06-28 23:50:12 -0400164 capture_warnings(False)
Kurt B. Kaisera2792be2003-05-17 21:04:10 +0000165 raise
Kurt B. Kaiser9ec454e2003-05-12 02:33:47 +0000166 except:
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +0000167 type, value, tb = sys.exc_info()
Kurt B. Kaisera2792be2003-05-17 21:04:10 +0000168 try:
169 print_exception()
170 rpc.response_queue.put((seq, None))
171 except:
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +0000172 # Link didn't work, print same exception to __stderr__
173 traceback.print_exception(type, value, tb, file=sys.__stderr__)
Kurt B. Kaiser62df0442003-05-28 01:47:46 +0000174 exit()
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +0000175 else:
176 continue
Kurt B. Kaiser11c53e22003-03-22 19:40:19 +0000177
178def manage_socket(address):
Kurt B. Kaiseraf3eb872004-01-21 18:54:30 +0000179 for i in range(3):
Kurt B. Kaiserb4179362002-07-26 00:06:42 +0000180 time.sleep(i)
181 try:
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000182 server = MyRPCServer(address, MyHandler)
Kurt B. Kaiserb4179362002-07-26 00:06:42 +0000183 break
Andrew Svetlov0832af62012-12-18 23:10:48 +0200184 except OSError as err:
185 print("IDLE Subprocess: OSError: " + err.args[1] +
Georg Brandl6464d472007-10-22 16:16:13 +0000186 ", retrying....", file=sys.__stderr__)
Amaury Forgeot d'Arcefae8c42008-11-21 23:08:09 +0000187 socket_error = err
Kurt B. Kaiserb4179362002-07-26 00:06:42 +0000188 else:
Amaury Forgeot d'Arcefae8c42008-11-21 23:08:09 +0000189 print("IDLE Subprocess: Connection to "
190 "IDLE GUI failed, exiting.", file=sys.__stderr__)
191 show_socket_error(socket_error, address)
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +0000192 global exit_now
193 exit_now = True
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000194 return
Kurt B. Kaiser11c53e22003-03-22 19:40:19 +0000195 server.handle_request() # A single request only
196
Kurt B. Kaiseraf3eb872004-01-21 18:54:30 +0000197def show_socket_error(err, address):
terryjreedy188aedf2017-06-13 21:32:16 -0400198 "Display socket error from manage_socket."
Georg Brandl14fc4272008-05-17 18:39:55 +0000199 import tkinter
terryjreedy188aedf2017-06-13 21:32:16 -0400200 from tkinter.messagebox import showerror
Georg Brandl14fc4272008-05-17 18:39:55 +0000201 root = tkinter.Tk()
Serhiy Storchakaa96c96f2017-09-21 11:20:06 +0300202 fix_scaling(root)
Kurt B. Kaiseraf3eb872004-01-21 18:54:30 +0000203 root.withdraw()
Terry Jan Reedy8fac1222019-06-17 17:23:28 -0400204 showerror(
205 "Subprocess Connection Error",
206 f"IDLE's subprocess can't connect to {address[0]}:{address[1]}.\n"
207 f"Fatal OSError #{err.errno}: {err.strerror}.\n"
208 "See the 'Startup failure' section of the IDLE doc, online at\n"
209 "https://docs.python.org/3/library/idle.html#startup-failure",
210 parent=root)
Kurt B. Kaiseraf3eb872004-01-21 18:54:30 +0000211 root.destroy()
212
Kurt B. Kaiser9ec454e2003-05-12 02:33:47 +0000213def print_exception():
Kurt B. Kaisere9802a32004-01-02 04:04:04 +0000214 import linecache
215 linecache.checkcache()
Kurt B. Kaiser9ec454e2003-05-12 02:33:47 +0000216 flush_stdout()
217 efile = sys.stderr
Kurt B. Kaiser924f6162003-11-19 04:52:32 +0000218 typ, val, tb = excinfo = sys.exc_info()
219 sys.last_type, sys.last_value, sys.last_traceback = excinfo
Serhiy Storchaka78470b42013-01-09 12:21:57 +0200220 seen = set()
221
222 def print_exc(typ, exc, tb):
Zane Bitterde860732017-10-17 17:29:39 -0400223 seen.add(id(exc))
Serhiy Storchaka78470b42013-01-09 12:21:57 +0200224 context = exc.__context__
225 cause = exc.__cause__
Zane Bitterde860732017-10-17 17:29:39 -0400226 if cause is not None and id(cause) not in seen:
Serhiy Storchaka78470b42013-01-09 12:21:57 +0200227 print_exc(type(cause), cause, cause.__traceback__)
228 print("\nThe above exception was the direct cause "
229 "of the following exception:\n", file=efile)
Serhiy Storchaka71317492013-01-09 12:24:48 +0200230 elif (context is not None and
231 not exc.__suppress_context__ and
Zane Bitterde860732017-10-17 17:29:39 -0400232 id(context) not in seen):
Serhiy Storchaka78470b42013-01-09 12:21:57 +0200233 print_exc(type(context), context, context.__traceback__)
234 print("\nDuring handling of the above exception, "
235 "another exception occurred:\n", file=efile)
236 if tb:
237 tbe = traceback.extract_tb(tb)
238 print('Traceback (most recent call last):', file=efile)
239 exclude = ("run.py", "rpc.py", "threading.py", "queue.py",
Terry Jan Reedy6fa5bdc2016-05-28 13:22:31 -0400240 "debugger_r.py", "bdb.py")
Serhiy Storchaka78470b42013-01-09 12:21:57 +0200241 cleanup_traceback(tbe, exclude)
242 traceback.print_list(tbe, file=efile)
243 lines = traceback.format_exception_only(typ, exc)
244 for line in lines:
245 print(line, end='', file=efile)
246
247 print_exc(typ, val, tb)
Kurt B. Kaiser9ec454e2003-05-12 02:33:47 +0000248
249def cleanup_traceback(tb, exclude):
250 "Remove excluded traces from beginning/end of tb; get cached lines"
251 orig_tb = tb[:]
252 while tb:
253 for rpcfile in exclude:
254 if tb[0][0].count(rpcfile):
255 break # found an exclude, break for: and delete tb[0]
256 else:
257 break # no excludes, have left RPC code, break while:
258 del tb[0]
259 while tb:
260 for rpcfile in exclude:
261 if tb[-1][0].count(rpcfile):
262 break
263 else:
264 break
265 del tb[-1]
266 if len(tb) == 0:
267 # exception was in IDLE internals, don't prune!
268 tb[:] = orig_tb[:]
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000269 print("** IDLE Internal Exception: ", file=sys.stderr)
Kurt B. Kaiser9ec454e2003-05-12 02:33:47 +0000270 rpchandler = rpc.objecttable['exec'].rpchandler
271 for i in range(len(tb)):
272 fn, ln, nm, line = tb[i]
273 if nm == '?':
274 nm = "-toplevel-"
275 if not line and fn.startswith("<pyshell#"):
276 line = rpchandler.remotecall('linecache', 'getline',
277 (fn, ln), {})
278 tb[i] = fn, ln, nm, line
279
280def flush_stdout():
Guido van Rossum79139b22007-02-09 23:20:19 +0000281 """XXX How to do this now?"""
Kurt B. Kaiser9ec454e2003-05-12 02:33:47 +0000282
Kurt B. Kaiser62df0442003-05-28 01:47:46 +0000283def exit():
Guido van Rossumc76a2502007-08-09 14:26:58 +0000284 """Exit subprocess, possibly after first clearing exit functions.
Kurt B. Kaiser62df0442003-05-28 01:47:46 +0000285
286 If config-main.cfg/.def 'General' 'delete-exitfunc' is True, then any
Guido van Rossumc76a2502007-08-09 14:26:58 +0000287 functions registered with atexit will be removed before exiting.
288 (VPython support)
Kurt B. Kaiser62df0442003-05-28 01:47:46 +0000289
290 """
291 if no_exitfunc:
Guido van Rossumc76a2502007-08-09 14:26:58 +0000292 import atexit
293 atexit._clear()
Terry Jan Reedy95a3f112013-06-28 23:50:12 -0400294 capture_warnings(False)
Kurt B. Kaiser62df0442003-05-28 01:47:46 +0000295 sys.exit(0)
Chui Tey5d2af632002-05-26 13:36:41 +0000296
Terry Jan Reedybfbaa6b2016-08-31 00:50:55 -0400297
Serhiy Storchakaa96c96f2017-09-21 11:20:06 +0300298def fix_scaling(root):
299 """Scale fonts on HiDPI displays."""
300 import tkinter.font
301 scaling = float(root.tk.call('tk', 'scaling'))
302 if scaling > 1.4:
303 for name in tkinter.font.names(root):
304 font = tkinter.font.Font(root=root, name=name, exists=True)
305 size = int(font['size'])
306 if size < 0:
307 font['size'] = round(-0.75*size)
308
309
Terry Jan Reedy6aeb2fe2019-07-09 14:37:25 -0400310def fixdoc(fun, text):
311 tem = (fun.__doc__ + '\n\n') if fun.__doc__ is not None else ''
312 fun.__doc__ = tem + textwrap.fill(textwrap.dedent(text))
313
Tal Einatfcf1d002019-07-06 15:35:24 +0300314RECURSIONLIMIT_DELTA = 30
Terry Jan Reedy6aeb2fe2019-07-09 14:37:25 -0400315
Tal Einatfcf1d002019-07-06 15:35:24 +0300316def install_recursionlimit_wrappers():
317 """Install wrappers to always add 30 to the recursion limit."""
318 # see: bpo-26806
319
320 @functools.wraps(sys.setrecursionlimit)
321 def setrecursionlimit(*args, **kwargs):
322 # mimic the original sys.setrecursionlimit()'s input handling
323 if kwargs:
324 raise TypeError(
325 "setrecursionlimit() takes no keyword arguments")
326 try:
327 limit, = args
328 except ValueError:
329 raise TypeError(f"setrecursionlimit() takes exactly one "
330 f"argument ({len(args)} given)")
331 if not limit > 0:
332 raise ValueError(
333 "recursion limit must be greater or equal than 1")
334
335 return setrecursionlimit.__wrapped__(limit + RECURSIONLIMIT_DELTA)
336
Terry Jan Reedy6aeb2fe2019-07-09 14:37:25 -0400337 fixdoc(setrecursionlimit, f"""\
338 This IDLE wrapper adds {RECURSIONLIMIT_DELTA} to prevent possible
339 uninterruptible loops.""")
Tal Einatfcf1d002019-07-06 15:35:24 +0300340
341 @functools.wraps(sys.getrecursionlimit)
342 def getrecursionlimit():
343 return getrecursionlimit.__wrapped__() - RECURSIONLIMIT_DELTA
344
Terry Jan Reedy6aeb2fe2019-07-09 14:37:25 -0400345 fixdoc(getrecursionlimit, f"""\
346 This IDLE wrapper subtracts {RECURSIONLIMIT_DELTA} to compensate
347 for the {RECURSIONLIMIT_DELTA} IDLE adds when setting the limit.""")
Tal Einatfcf1d002019-07-06 15:35:24 +0300348
349 # add the delta to the default recursion limit, to compensate
350 sys.setrecursionlimit(sys.getrecursionlimit() + RECURSIONLIMIT_DELTA)
351
352 sys.setrecursionlimit = setrecursionlimit
353 sys.getrecursionlimit = getrecursionlimit
354
355
356def uninstall_recursionlimit_wrappers():
357 """Uninstall the recursion limit wrappers from the sys module.
358
359 IDLE only uses this for tests. Users can import run and call
360 this to remove the wrapping.
361 """
362 if (
363 getattr(sys.setrecursionlimit, '__wrapped__', None) and
364 getattr(sys.getrecursionlimit, '__wrapped__', None)
365 ):
366 sys.setrecursionlimit = sys.setrecursionlimit.__wrapped__
367 sys.getrecursionlimit = sys.getrecursionlimit.__wrapped__
368 sys.setrecursionlimit(sys.getrecursionlimit() - RECURSIONLIMIT_DELTA)
369
370
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000371class MyRPCServer(rpc.RPCServer):
372
373 def handle_error(self, request, client_address):
374 """Override RPCServer method for IDLE
375
376 Interrupt the MainThread and exit server if link is dropped.
377
378 """
Kurt B. Kaisere9535112004-11-19 15:46:49 +0000379 global quitting
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000380 try:
381 raise
382 except SystemExit:
383 raise
384 except EOFError:
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +0000385 global exit_now
386 exit_now = True
Kurt B. Kaiser93e8e542003-06-13 22:03:43 +0000387 thread.interrupt_main()
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000388 except:
389 erf = sys.__stderr__
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000390 print('\n' + '-'*40, file=erf)
391 print('Unhandled server exception!', file=erf)
Amaury Forgeot d'Arcbed17102008-11-29 01:48:47 +0000392 print('Thread: %s' % threading.current_thread().name, file=erf)
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000393 print('Client Address: ', client_address, file=erf)
394 print('Request: ', repr(request), file=erf)
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000395 traceback.print_exc(file=erf)
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000396 print('\n*** Unrecoverable, server exiting!', file=erf)
397 print('-'*40, file=erf)
Kurt B. Kaisere9535112004-11-19 15:46:49 +0000398 quitting = True
399 thread.interrupt_main()
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000400
Terry Jan Reedy6cf0e132016-07-15 02:43:03 -0400401
402# Pseudofiles for shell-remote communication (also used in pyshell)
403
404class PseudoFile(io.TextIOBase):
405
406 def __init__(self, shell, tags, encoding=None):
407 self.shell = shell
408 self.tags = tags
409 self._encoding = encoding
410
411 @property
412 def encoding(self):
413 return self._encoding
414
415 @property
416 def name(self):
417 return '<%s>' % self.tags
418
419 def isatty(self):
420 return True
421
422
423class PseudoOutputFile(PseudoFile):
424
425 def writable(self):
426 return True
427
428 def write(self, s):
429 if self.closed:
430 raise ValueError("write to closed file")
431 if type(s) is not str:
432 if not isinstance(s, str):
433 raise TypeError('must be str, not ' + type(s).__name__)
434 # See issue #19481
435 s = str.__str__(s)
436 return self.shell.write(s, self.tags)
437
438
439class PseudoInputFile(PseudoFile):
440
441 def __init__(self, shell, tags, encoding=None):
442 PseudoFile.__init__(self, shell, tags, encoding)
443 self._line_buffer = ''
444
445 def readable(self):
446 return True
447
448 def read(self, size=-1):
449 if self.closed:
450 raise ValueError("read from closed file")
451 if size is None:
452 size = -1
453 elif not isinstance(size, int):
454 raise TypeError('must be int, not ' + type(size).__name__)
455 result = self._line_buffer
456 self._line_buffer = ''
457 if size < 0:
458 while True:
459 line = self.shell.readline()
460 if not line: break
461 result += line
462 else:
463 while len(result) < size:
464 line = self.shell.readline()
465 if not line: break
466 result += line
467 self._line_buffer = result[size:]
468 result = result[:size]
469 return result
470
471 def readline(self, size=-1):
472 if self.closed:
473 raise ValueError("read from closed file")
474 if size is None:
475 size = -1
476 elif not isinstance(size, int):
477 raise TypeError('must be int, not ' + type(size).__name__)
478 line = self._line_buffer or self.shell.readline()
479 if size < 0:
480 size = len(line)
481 eol = line.find('\n', 0, size)
482 if eol >= 0:
483 size = eol + 1
484 self._line_buffer = line[size:]
485 return line[:size]
486
487 def close(self):
488 self.shell.close()
489
490
Chui Tey5d2af632002-05-26 13:36:41 +0000491class MyHandler(rpc.RPCHandler):
492
493 def handle(self):
Kurt B. Kaiser11c53e22003-03-22 19:40:19 +0000494 """Override base method"""
Chui Tey5d2af632002-05-26 13:36:41 +0000495 executive = Executive(self)
496 self.register("exec", executive)
Serhiy Storchaka39e70a42013-01-25 15:30:58 +0200497 self.console = self.get_remote_proxy("console")
Terry Jan Reedy6cf0e132016-07-15 02:43:03 -0400498 sys.stdin = PseudoInputFile(self.console, "stdin",
Terry Jan Reedy6fa5bdc2016-05-28 13:22:31 -0400499 iomenu.encoding)
Terry Jan Reedy6cf0e132016-07-15 02:43:03 -0400500 sys.stdout = PseudoOutputFile(self.console, "stdout",
Terry Jan Reedy6fa5bdc2016-05-28 13:22:31 -0400501 iomenu.encoding)
Terry Jan Reedy6cf0e132016-07-15 02:43:03 -0400502 sys.stderr = PseudoOutputFile(self.console, "stderr",
Terry Jan Reedy6fa5bdc2016-05-28 13:22:31 -0400503 iomenu.encoding)
Serhiy Storchaka39e70a42013-01-25 15:30:58 +0200504
Andrew Svetlovcd49d532012-03-25 11:43:02 +0300505 sys.displayhook = rpc.displayhook
Kurt B. Kaiserf609a342007-12-28 03:57:56 +0000506 # page help() text to shell.
507 import pydoc # import must be done here to capture i/o binding
508 pydoc.pager = pydoc.plainpager
Benjamin Peterson0d4931e2013-05-11 22:24:28 -0500509
510 # Keep a reference to stdin so that it won't try to exit IDLE if
511 # sys.stdin gets changed from within IDLE's shell. See issue17838.
512 self._keep_stdin = sys.stdin
513
Tal Einatfcf1d002019-07-06 15:35:24 +0300514 install_recursionlimit_wrappers()
515
Kurt B. Kaiser9f366092003-06-02 01:50:19 +0000516 self.interp = self.get_remote_proxy("interp")
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000517 rpc.RPCHandler.getresponse(self, myseq=None, wait=0.05)
518
519 def exithook(self):
520 "override SocketIO method - wait for MainThread to shut us down"
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +0000521 time.sleep(10)
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000522
523 def EOFhook(self):
524 "Override SocketIO method - terminate wait on callback and exit thread"
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +0000525 global quitting
526 quitting = True
Kurt B. Kaiser93e8e542003-06-13 22:03:43 +0000527 thread.interrupt_main()
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000528
529 def decode_interrupthook(self):
530 "interrupt awakened thread"
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +0000531 global quitting
532 quitting = True
Kurt B. Kaiser93e8e542003-06-13 22:03:43 +0000533 thread.interrupt_main()
Kurt B. Kaiser11c53e22003-03-22 19:40:19 +0000534
Chui Tey5d2af632002-05-26 13:36:41 +0000535
Kurt B. Kaiserdcba6622004-12-21 22:10:32 +0000536class Executive(object):
Chui Tey5d2af632002-05-26 13:36:41 +0000537
538 def __init__(self, rpchandler):
Kurt B. Kaiserffd3a422002-06-26 02:32:09 +0000539 self.rpchandler = rpchandler
Kurt B. Kaiseradc63842002-08-25 14:08:07 +0000540 self.locals = __main__.__dict__
Terry Jan Reedy06e20292018-06-19 23:00:35 -0400541 self.calltip = calltip.Calltip()
Terry Jan Reedy6fa5bdc2016-05-28 13:22:31 -0400542 self.autocomplete = autocomplete.AutoComplete()
Chui Tey5d2af632002-05-26 13:36:41 +0000543
544 def runcode(self, code):
Guido van Rossum8ce8a782007-11-01 19:42:39 +0000545 global interruptable
Kurt B. Kaiser86bc4642003-02-27 23:04:17 +0000546 try:
Kurt B. Kaiser9f366092003-06-02 01:50:19 +0000547 self.usr_exc_info = None
Guido van Rossum8ce8a782007-11-01 19:42:39 +0000548 interruptable = True
549 try:
550 exec(code, self.locals)
551 finally:
552 interruptable = False
Terry Jan Reedy6d965b32019-05-19 22:52:22 -0400553 except SystemExit as e:
554 if e.args: # SystemExit called with an argument.
555 ob = e.args[0]
556 if not isinstance(ob, (type(None), int)):
557 print('SystemExit: ' + str(ob), file=sys.stderr)
558 # Return to the interactive prompt.
Kurt B. Kaiser86bc4642003-02-27 23:04:17 +0000559 except:
Kurt B. Kaiser9f366092003-06-02 01:50:19 +0000560 self.usr_exc_info = sys.exc_info()
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +0000561 if quitting:
Kurt B. Kaiser62df0442003-05-28 01:47:46 +0000562 exit()
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +0000563 print_exception()
Kurt B. Kaiser9f366092003-06-02 01:50:19 +0000564 jit = self.rpchandler.console.getvar("<<toggle-jit-stack-viewer>>")
565 if jit:
566 self.rpchandler.interp.open_remote_stack_viewer()
Kurt B. Kaiser11c53e22003-03-22 19:40:19 +0000567 else:
Kurt B. Kaiser9ec454e2003-05-12 02:33:47 +0000568 flush_stdout()
Chui Tey5d2af632002-05-26 13:36:41 +0000569
Kurt B. Kaiser003091c2003-02-17 18:57:16 +0000570 def interrupt_the_server(self):
Guido van Rossum8ce8a782007-11-01 19:42:39 +0000571 if interruptable:
572 thread.interrupt_main()
Kurt B. Kaiser11c53e22003-03-22 19:40:19 +0000573
Kurt B. Kaiser0e3a5772002-06-16 03:32:24 +0000574 def start_the_debugger(self, gui_adap_oid):
Terry Jan Reedy6fa5bdc2016-05-28 13:22:31 -0400575 return debugger_r.start_debugger(self.rpchandler, gui_adap_oid)
Kurt B. Kaiserffd3a422002-06-26 02:32:09 +0000576
577 def stop_the_debugger(self, idb_adap_oid):
578 "Unregister the Idb Adapter. Link objects and Idb then subject to GC"
579 self.rpchandler.unregister(idb_adap_oid)
Chui Tey5d2af632002-05-26 13:36:41 +0000580
Kurt B. Kaiser5afa1df2002-10-10 08:25:24 +0000581 def get_the_calltip(self, name):
582 return self.calltip.fetch_tip(name)
583
Kurt B. Kaiserb1754452005-11-18 22:05:48 +0000584 def get_the_completion_list(self, what, mode):
585 return self.autocomplete.fetch_completions(what, mode)
586
Chui Tey5d2af632002-05-26 13:36:41 +0000587 def stackviewer(self, flist_oid=None):
Kurt B. Kaiser9f366092003-06-02 01:50:19 +0000588 if self.usr_exc_info:
589 typ, val, tb = self.usr_exc_info
590 else:
Chui Tey5d2af632002-05-26 13:36:41 +0000591 return None
592 flist = None
593 if flist_oid is not None:
Kurt B. Kaiserffd3a422002-06-26 02:32:09 +0000594 flist = self.rpchandler.get_remote_proxy(flist_oid)
Chui Tey5d2af632002-05-26 13:36:41 +0000595 while tb and tb.tb_frame.f_globals["__name__"] in ["rpc", "run"]:
596 tb = tb.tb_next
Kurt B. Kaiser9f366092003-06-02 01:50:19 +0000597 sys.last_type = typ
598 sys.last_value = val
Terry Jan Reedy6fa5bdc2016-05-28 13:22:31 -0400599 item = stackviewer.StackTreeItem(flist, tb)
600 return debugobj_r.remote_object_tree_item(item)
Terry Jan Reedy95a3f112013-06-28 23:50:12 -0400601
Terry Jan Reedy81bb97d2019-05-24 21:59:53 -0400602
603if __name__ == '__main__':
604 from unittest import main
605 main('idlelib.idle_test.test_run', verbosity=2)
606
607capture_warnings(False) # Make sure turned off; see bpo-18081.