annotate CSP2/CSP2_env/env-d9b9114564458d9d-741b3de822f2aaca6c6caa4325c4afce/lib/python3.8/idlelib/run.py @ 68:5028fdace37b

planemo upload commit 2e9511a184a1ca667c7be0c6321a36dc4e3d116d
author jpayne
date Tue, 18 Mar 2025 16:23:26 -0400
parents
children
rev   line source
jpayne@68 1 """ idlelib.run
jpayne@68 2
jpayne@68 3 Simplified, pyshell.ModifiedInterpreter spawns a subprocess with
jpayne@68 4 f'''{sys.executable} -c "__import__('idlelib.run').run.main()"'''
jpayne@68 5 '.run' is needed because __import__ returns idlelib, not idlelib.run.
jpayne@68 6 """
jpayne@68 7 import functools
jpayne@68 8 import io
jpayne@68 9 import linecache
jpayne@68 10 import queue
jpayne@68 11 import sys
jpayne@68 12 import textwrap
jpayne@68 13 import time
jpayne@68 14 import traceback
jpayne@68 15 import _thread as thread
jpayne@68 16 import threading
jpayne@68 17 import warnings
jpayne@68 18
jpayne@68 19 from idlelib import autocomplete # AutoComplete, fetch_encodings
jpayne@68 20 from idlelib import calltip # Calltip
jpayne@68 21 from idlelib import debugger_r # start_debugger
jpayne@68 22 from idlelib import debugobj_r # remote_object_tree_item
jpayne@68 23 from idlelib import iomenu # encoding
jpayne@68 24 from idlelib import rpc # multiple objects
jpayne@68 25 from idlelib import stackviewer # StackTreeItem
jpayne@68 26 import __main__
jpayne@68 27
jpayne@68 28 import tkinter # Use tcl and, if startup fails, messagebox.
jpayne@68 29 if not hasattr(sys.modules['idlelib.run'], 'firstrun'):
jpayne@68 30 # Undo modifications of tkinter by idlelib imports; see bpo-25507.
jpayne@68 31 for mod in ('simpledialog', 'messagebox', 'font',
jpayne@68 32 'dialog', 'filedialog', 'commondialog',
jpayne@68 33 'ttk'):
jpayne@68 34 delattr(tkinter, mod)
jpayne@68 35 del sys.modules['tkinter.' + mod]
jpayne@68 36 # Avoid AttributeError if run again; see bpo-37038.
jpayne@68 37 sys.modules['idlelib.run'].firstrun = False
jpayne@68 38
jpayne@68 39 LOCALHOST = '127.0.0.1'
jpayne@68 40
jpayne@68 41
jpayne@68 42 def idle_formatwarning(message, category, filename, lineno, line=None):
jpayne@68 43 """Format warnings the IDLE way."""
jpayne@68 44
jpayne@68 45 s = "\nWarning (from warnings module):\n"
jpayne@68 46 s += ' File \"%s\", line %s\n' % (filename, lineno)
jpayne@68 47 if line is None:
jpayne@68 48 line = linecache.getline(filename, lineno)
jpayne@68 49 line = line.strip()
jpayne@68 50 if line:
jpayne@68 51 s += " %s\n" % line
jpayne@68 52 s += "%s: %s\n" % (category.__name__, message)
jpayne@68 53 return s
jpayne@68 54
jpayne@68 55 def idle_showwarning_subproc(
jpayne@68 56 message, category, filename, lineno, file=None, line=None):
jpayne@68 57 """Show Idle-format warning after replacing warnings.showwarning.
jpayne@68 58
jpayne@68 59 The only difference is the formatter called.
jpayne@68 60 """
jpayne@68 61 if file is None:
jpayne@68 62 file = sys.stderr
jpayne@68 63 try:
jpayne@68 64 file.write(idle_formatwarning(
jpayne@68 65 message, category, filename, lineno, line))
jpayne@68 66 except OSError:
jpayne@68 67 pass # the file (probably stderr) is invalid - this warning gets lost.
jpayne@68 68
jpayne@68 69 _warnings_showwarning = None
jpayne@68 70
jpayne@68 71 def capture_warnings(capture):
jpayne@68 72 "Replace warning.showwarning with idle_showwarning_subproc, or reverse."
jpayne@68 73
jpayne@68 74 global _warnings_showwarning
jpayne@68 75 if capture:
jpayne@68 76 if _warnings_showwarning is None:
jpayne@68 77 _warnings_showwarning = warnings.showwarning
jpayne@68 78 warnings.showwarning = idle_showwarning_subproc
jpayne@68 79 else:
jpayne@68 80 if _warnings_showwarning is not None:
jpayne@68 81 warnings.showwarning = _warnings_showwarning
jpayne@68 82 _warnings_showwarning = None
jpayne@68 83
jpayne@68 84 capture_warnings(True)
jpayne@68 85 tcl = tkinter.Tcl()
jpayne@68 86
jpayne@68 87 def handle_tk_events(tcl=tcl):
jpayne@68 88 """Process any tk events that are ready to be dispatched if tkinter
jpayne@68 89 has been imported, a tcl interpreter has been created and tk has been
jpayne@68 90 loaded."""
jpayne@68 91 tcl.eval("update")
jpayne@68 92
jpayne@68 93 # Thread shared globals: Establish a queue between a subthread (which handles
jpayne@68 94 # the socket) and the main thread (which runs user code), plus global
jpayne@68 95 # completion, exit and interruptable (the main thread) flags:
jpayne@68 96
jpayne@68 97 exit_now = False
jpayne@68 98 quitting = False
jpayne@68 99 interruptable = False
jpayne@68 100
jpayne@68 101 def main(del_exitfunc=False):
jpayne@68 102 """Start the Python execution server in a subprocess
jpayne@68 103
jpayne@68 104 In the Python subprocess, RPCServer is instantiated with handlerclass
jpayne@68 105 MyHandler, which inherits register/unregister methods from RPCHandler via
jpayne@68 106 the mix-in class SocketIO.
jpayne@68 107
jpayne@68 108 When the RPCServer 'server' is instantiated, the TCPServer initialization
jpayne@68 109 creates an instance of run.MyHandler and calls its handle() method.
jpayne@68 110 handle() instantiates a run.Executive object, passing it a reference to the
jpayne@68 111 MyHandler object. That reference is saved as attribute rpchandler of the
jpayne@68 112 Executive instance. The Executive methods have access to the reference and
jpayne@68 113 can pass it on to entities that they command
jpayne@68 114 (e.g. debugger_r.Debugger.start_debugger()). The latter, in turn, can
jpayne@68 115 call MyHandler(SocketIO) register/unregister methods via the reference to
jpayne@68 116 register and unregister themselves.
jpayne@68 117
jpayne@68 118 """
jpayne@68 119 global exit_now
jpayne@68 120 global quitting
jpayne@68 121 global no_exitfunc
jpayne@68 122 no_exitfunc = del_exitfunc
jpayne@68 123 #time.sleep(15) # test subprocess not responding
jpayne@68 124 try:
jpayne@68 125 assert(len(sys.argv) > 1)
jpayne@68 126 port = int(sys.argv[-1])
jpayne@68 127 except:
jpayne@68 128 print("IDLE Subprocess: no IP port passed in sys.argv.",
jpayne@68 129 file=sys.__stderr__)
jpayne@68 130 return
jpayne@68 131
jpayne@68 132 capture_warnings(True)
jpayne@68 133 sys.argv[:] = [""]
jpayne@68 134 sockthread = threading.Thread(target=manage_socket,
jpayne@68 135 name='SockThread',
jpayne@68 136 args=((LOCALHOST, port),))
jpayne@68 137 sockthread.daemon = True
jpayne@68 138 sockthread.start()
jpayne@68 139 while 1:
jpayne@68 140 try:
jpayne@68 141 if exit_now:
jpayne@68 142 try:
jpayne@68 143 exit()
jpayne@68 144 except KeyboardInterrupt:
jpayne@68 145 # exiting but got an extra KBI? Try again!
jpayne@68 146 continue
jpayne@68 147 try:
jpayne@68 148 request = rpc.request_queue.get(block=True, timeout=0.05)
jpayne@68 149 except queue.Empty:
jpayne@68 150 request = None
jpayne@68 151 # Issue 32207: calling handle_tk_events here adds spurious
jpayne@68 152 # queue.Empty traceback to event handling exceptions.
jpayne@68 153 if request:
jpayne@68 154 seq, (method, args, kwargs) = request
jpayne@68 155 ret = method(*args, **kwargs)
jpayne@68 156 rpc.response_queue.put((seq, ret))
jpayne@68 157 else:
jpayne@68 158 handle_tk_events()
jpayne@68 159 except KeyboardInterrupt:
jpayne@68 160 if quitting:
jpayne@68 161 exit_now = True
jpayne@68 162 continue
jpayne@68 163 except SystemExit:
jpayne@68 164 capture_warnings(False)
jpayne@68 165 raise
jpayne@68 166 except:
jpayne@68 167 type, value, tb = sys.exc_info()
jpayne@68 168 try:
jpayne@68 169 print_exception()
jpayne@68 170 rpc.response_queue.put((seq, None))
jpayne@68 171 except:
jpayne@68 172 # Link didn't work, print same exception to __stderr__
jpayne@68 173 traceback.print_exception(type, value, tb, file=sys.__stderr__)
jpayne@68 174 exit()
jpayne@68 175 else:
jpayne@68 176 continue
jpayne@68 177
jpayne@68 178 def manage_socket(address):
jpayne@68 179 for i in range(3):
jpayne@68 180 time.sleep(i)
jpayne@68 181 try:
jpayne@68 182 server = MyRPCServer(address, MyHandler)
jpayne@68 183 break
jpayne@68 184 except OSError as err:
jpayne@68 185 print("IDLE Subprocess: OSError: " + err.args[1] +
jpayne@68 186 ", retrying....", file=sys.__stderr__)
jpayne@68 187 socket_error = err
jpayne@68 188 else:
jpayne@68 189 print("IDLE Subprocess: Connection to "
jpayne@68 190 "IDLE GUI failed, exiting.", file=sys.__stderr__)
jpayne@68 191 show_socket_error(socket_error, address)
jpayne@68 192 global exit_now
jpayne@68 193 exit_now = True
jpayne@68 194 return
jpayne@68 195 server.handle_request() # A single request only
jpayne@68 196
jpayne@68 197 def show_socket_error(err, address):
jpayne@68 198 "Display socket error from manage_socket."
jpayne@68 199 import tkinter
jpayne@68 200 from tkinter.messagebox import showerror
jpayne@68 201 root = tkinter.Tk()
jpayne@68 202 fix_scaling(root)
jpayne@68 203 root.withdraw()
jpayne@68 204 showerror(
jpayne@68 205 "Subprocess Connection Error",
jpayne@68 206 f"IDLE's subprocess can't connect to {address[0]}:{address[1]}.\n"
jpayne@68 207 f"Fatal OSError #{err.errno}: {err.strerror}.\n"
jpayne@68 208 "See the 'Startup failure' section of the IDLE doc, online at\n"
jpayne@68 209 "https://docs.python.org/3/library/idle.html#startup-failure",
jpayne@68 210 parent=root)
jpayne@68 211 root.destroy()
jpayne@68 212
jpayne@68 213 def print_exception():
jpayne@68 214 import linecache
jpayne@68 215 linecache.checkcache()
jpayne@68 216 flush_stdout()
jpayne@68 217 efile = sys.stderr
jpayne@68 218 typ, val, tb = excinfo = sys.exc_info()
jpayne@68 219 sys.last_type, sys.last_value, sys.last_traceback = excinfo
jpayne@68 220 seen = set()
jpayne@68 221
jpayne@68 222 def print_exc(typ, exc, tb):
jpayne@68 223 seen.add(id(exc))
jpayne@68 224 context = exc.__context__
jpayne@68 225 cause = exc.__cause__
jpayne@68 226 if cause is not None and id(cause) not in seen:
jpayne@68 227 print_exc(type(cause), cause, cause.__traceback__)
jpayne@68 228 print("\nThe above exception was the direct cause "
jpayne@68 229 "of the following exception:\n", file=efile)
jpayne@68 230 elif (context is not None and
jpayne@68 231 not exc.__suppress_context__ and
jpayne@68 232 id(context) not in seen):
jpayne@68 233 print_exc(type(context), context, context.__traceback__)
jpayne@68 234 print("\nDuring handling of the above exception, "
jpayne@68 235 "another exception occurred:\n", file=efile)
jpayne@68 236 if tb:
jpayne@68 237 tbe = traceback.extract_tb(tb)
jpayne@68 238 print('Traceback (most recent call last):', file=efile)
jpayne@68 239 exclude = ("run.py", "rpc.py", "threading.py", "queue.py",
jpayne@68 240 "debugger_r.py", "bdb.py")
jpayne@68 241 cleanup_traceback(tbe, exclude)
jpayne@68 242 traceback.print_list(tbe, file=efile)
jpayne@68 243 lines = traceback.format_exception_only(typ, exc)
jpayne@68 244 for line in lines:
jpayne@68 245 print(line, end='', file=efile)
jpayne@68 246
jpayne@68 247 print_exc(typ, val, tb)
jpayne@68 248
jpayne@68 249 def cleanup_traceback(tb, exclude):
jpayne@68 250 "Remove excluded traces from beginning/end of tb; get cached lines"
jpayne@68 251 orig_tb = tb[:]
jpayne@68 252 while tb:
jpayne@68 253 for rpcfile in exclude:
jpayne@68 254 if tb[0][0].count(rpcfile):
jpayne@68 255 break # found an exclude, break for: and delete tb[0]
jpayne@68 256 else:
jpayne@68 257 break # no excludes, have left RPC code, break while:
jpayne@68 258 del tb[0]
jpayne@68 259 while tb:
jpayne@68 260 for rpcfile in exclude:
jpayne@68 261 if tb[-1][0].count(rpcfile):
jpayne@68 262 break
jpayne@68 263 else:
jpayne@68 264 break
jpayne@68 265 del tb[-1]
jpayne@68 266 if len(tb) == 0:
jpayne@68 267 # exception was in IDLE internals, don't prune!
jpayne@68 268 tb[:] = orig_tb[:]
jpayne@68 269 print("** IDLE Internal Exception: ", file=sys.stderr)
jpayne@68 270 rpchandler = rpc.objecttable['exec'].rpchandler
jpayne@68 271 for i in range(len(tb)):
jpayne@68 272 fn, ln, nm, line = tb[i]
jpayne@68 273 if nm == '?':
jpayne@68 274 nm = "-toplevel-"
jpayne@68 275 if not line and fn.startswith("<pyshell#"):
jpayne@68 276 line = rpchandler.remotecall('linecache', 'getline',
jpayne@68 277 (fn, ln), {})
jpayne@68 278 tb[i] = fn, ln, nm, line
jpayne@68 279
jpayne@68 280 def flush_stdout():
jpayne@68 281 """XXX How to do this now?"""
jpayne@68 282
jpayne@68 283 def exit():
jpayne@68 284 """Exit subprocess, possibly after first clearing exit functions.
jpayne@68 285
jpayne@68 286 If config-main.cfg/.def 'General' 'delete-exitfunc' is True, then any
jpayne@68 287 functions registered with atexit will be removed before exiting.
jpayne@68 288 (VPython support)
jpayne@68 289
jpayne@68 290 """
jpayne@68 291 if no_exitfunc:
jpayne@68 292 import atexit
jpayne@68 293 atexit._clear()
jpayne@68 294 capture_warnings(False)
jpayne@68 295 sys.exit(0)
jpayne@68 296
jpayne@68 297
jpayne@68 298 def fix_scaling(root):
jpayne@68 299 """Scale fonts on HiDPI displays."""
jpayne@68 300 import tkinter.font
jpayne@68 301 scaling = float(root.tk.call('tk', 'scaling'))
jpayne@68 302 if scaling > 1.4:
jpayne@68 303 for name in tkinter.font.names(root):
jpayne@68 304 font = tkinter.font.Font(root=root, name=name, exists=True)
jpayne@68 305 size = int(font['size'])
jpayne@68 306 if size < 0:
jpayne@68 307 font['size'] = round(-0.75*size)
jpayne@68 308
jpayne@68 309
jpayne@68 310 def fixdoc(fun, text):
jpayne@68 311 tem = (fun.__doc__ + '\n\n') if fun.__doc__ is not None else ''
jpayne@68 312 fun.__doc__ = tem + textwrap.fill(textwrap.dedent(text))
jpayne@68 313
jpayne@68 314 RECURSIONLIMIT_DELTA = 30
jpayne@68 315
jpayne@68 316 def install_recursionlimit_wrappers():
jpayne@68 317 """Install wrappers to always add 30 to the recursion limit."""
jpayne@68 318 # see: bpo-26806
jpayne@68 319
jpayne@68 320 @functools.wraps(sys.setrecursionlimit)
jpayne@68 321 def setrecursionlimit(*args, **kwargs):
jpayne@68 322 # mimic the original sys.setrecursionlimit()'s input handling
jpayne@68 323 if kwargs:
jpayne@68 324 raise TypeError(
jpayne@68 325 "setrecursionlimit() takes no keyword arguments")
jpayne@68 326 try:
jpayne@68 327 limit, = args
jpayne@68 328 except ValueError:
jpayne@68 329 raise TypeError(f"setrecursionlimit() takes exactly one "
jpayne@68 330 f"argument ({len(args)} given)")
jpayne@68 331 if not limit > 0:
jpayne@68 332 raise ValueError(
jpayne@68 333 "recursion limit must be greater or equal than 1")
jpayne@68 334
jpayne@68 335 return setrecursionlimit.__wrapped__(limit + RECURSIONLIMIT_DELTA)
jpayne@68 336
jpayne@68 337 fixdoc(setrecursionlimit, f"""\
jpayne@68 338 This IDLE wrapper adds {RECURSIONLIMIT_DELTA} to prevent possible
jpayne@68 339 uninterruptible loops.""")
jpayne@68 340
jpayne@68 341 @functools.wraps(sys.getrecursionlimit)
jpayne@68 342 def getrecursionlimit():
jpayne@68 343 return getrecursionlimit.__wrapped__() - RECURSIONLIMIT_DELTA
jpayne@68 344
jpayne@68 345 fixdoc(getrecursionlimit, f"""\
jpayne@68 346 This IDLE wrapper subtracts {RECURSIONLIMIT_DELTA} to compensate
jpayne@68 347 for the {RECURSIONLIMIT_DELTA} IDLE adds when setting the limit.""")
jpayne@68 348
jpayne@68 349 # add the delta to the default recursion limit, to compensate
jpayne@68 350 sys.setrecursionlimit(sys.getrecursionlimit() + RECURSIONLIMIT_DELTA)
jpayne@68 351
jpayne@68 352 sys.setrecursionlimit = setrecursionlimit
jpayne@68 353 sys.getrecursionlimit = getrecursionlimit
jpayne@68 354
jpayne@68 355
jpayne@68 356 def uninstall_recursionlimit_wrappers():
jpayne@68 357 """Uninstall the recursion limit wrappers from the sys module.
jpayne@68 358
jpayne@68 359 IDLE only uses this for tests. Users can import run and call
jpayne@68 360 this to remove the wrapping.
jpayne@68 361 """
jpayne@68 362 if (
jpayne@68 363 getattr(sys.setrecursionlimit, '__wrapped__', None) and
jpayne@68 364 getattr(sys.getrecursionlimit, '__wrapped__', None)
jpayne@68 365 ):
jpayne@68 366 sys.setrecursionlimit = sys.setrecursionlimit.__wrapped__
jpayne@68 367 sys.getrecursionlimit = sys.getrecursionlimit.__wrapped__
jpayne@68 368 sys.setrecursionlimit(sys.getrecursionlimit() - RECURSIONLIMIT_DELTA)
jpayne@68 369
jpayne@68 370
jpayne@68 371 class MyRPCServer(rpc.RPCServer):
jpayne@68 372
jpayne@68 373 def handle_error(self, request, client_address):
jpayne@68 374 """Override RPCServer method for IDLE
jpayne@68 375
jpayne@68 376 Interrupt the MainThread and exit server if link is dropped.
jpayne@68 377
jpayne@68 378 """
jpayne@68 379 global quitting
jpayne@68 380 try:
jpayne@68 381 raise
jpayne@68 382 except SystemExit:
jpayne@68 383 raise
jpayne@68 384 except EOFError:
jpayne@68 385 global exit_now
jpayne@68 386 exit_now = True
jpayne@68 387 thread.interrupt_main()
jpayne@68 388 except:
jpayne@68 389 erf = sys.__stderr__
jpayne@68 390 print('\n' + '-'*40, file=erf)
jpayne@68 391 print('Unhandled server exception!', file=erf)
jpayne@68 392 print('Thread: %s' % threading.current_thread().name, file=erf)
jpayne@68 393 print('Client Address: ', client_address, file=erf)
jpayne@68 394 print('Request: ', repr(request), file=erf)
jpayne@68 395 traceback.print_exc(file=erf)
jpayne@68 396 print('\n*** Unrecoverable, server exiting!', file=erf)
jpayne@68 397 print('-'*40, file=erf)
jpayne@68 398 quitting = True
jpayne@68 399 thread.interrupt_main()
jpayne@68 400
jpayne@68 401
jpayne@68 402 # Pseudofiles for shell-remote communication (also used in pyshell)
jpayne@68 403
jpayne@68 404 class StdioFile(io.TextIOBase):
jpayne@68 405
jpayne@68 406 def __init__(self, shell, tags, encoding='utf-8', errors='strict'):
jpayne@68 407 self.shell = shell
jpayne@68 408 self.tags = tags
jpayne@68 409 self._encoding = encoding
jpayne@68 410 self._errors = errors
jpayne@68 411
jpayne@68 412 @property
jpayne@68 413 def encoding(self):
jpayne@68 414 return self._encoding
jpayne@68 415
jpayne@68 416 @property
jpayne@68 417 def errors(self):
jpayne@68 418 return self._errors
jpayne@68 419
jpayne@68 420 @property
jpayne@68 421 def name(self):
jpayne@68 422 return '<%s>' % self.tags
jpayne@68 423
jpayne@68 424 def isatty(self):
jpayne@68 425 return True
jpayne@68 426
jpayne@68 427
jpayne@68 428 class StdOutputFile(StdioFile):
jpayne@68 429
jpayne@68 430 def writable(self):
jpayne@68 431 return True
jpayne@68 432
jpayne@68 433 def write(self, s):
jpayne@68 434 if self.closed:
jpayne@68 435 raise ValueError("write to closed file")
jpayne@68 436 s = str.encode(s, self.encoding, self.errors).decode(self.encoding, self.errors)
jpayne@68 437 return self.shell.write(s, self.tags)
jpayne@68 438
jpayne@68 439
jpayne@68 440 class StdInputFile(StdioFile):
jpayne@68 441 _line_buffer = ''
jpayne@68 442
jpayne@68 443 def readable(self):
jpayne@68 444 return True
jpayne@68 445
jpayne@68 446 def read(self, size=-1):
jpayne@68 447 if self.closed:
jpayne@68 448 raise ValueError("read from closed file")
jpayne@68 449 if size is None:
jpayne@68 450 size = -1
jpayne@68 451 elif not isinstance(size, int):
jpayne@68 452 raise TypeError('must be int, not ' + type(size).__name__)
jpayne@68 453 result = self._line_buffer
jpayne@68 454 self._line_buffer = ''
jpayne@68 455 if size < 0:
jpayne@68 456 while True:
jpayne@68 457 line = self.shell.readline()
jpayne@68 458 if not line: break
jpayne@68 459 result += line
jpayne@68 460 else:
jpayne@68 461 while len(result) < size:
jpayne@68 462 line = self.shell.readline()
jpayne@68 463 if not line: break
jpayne@68 464 result += line
jpayne@68 465 self._line_buffer = result[size:]
jpayne@68 466 result = result[:size]
jpayne@68 467 return result
jpayne@68 468
jpayne@68 469 def readline(self, size=-1):
jpayne@68 470 if self.closed:
jpayne@68 471 raise ValueError("read from closed file")
jpayne@68 472 if size is None:
jpayne@68 473 size = -1
jpayne@68 474 elif not isinstance(size, int):
jpayne@68 475 raise TypeError('must be int, not ' + type(size).__name__)
jpayne@68 476 line = self._line_buffer or self.shell.readline()
jpayne@68 477 if size < 0:
jpayne@68 478 size = len(line)
jpayne@68 479 eol = line.find('\n', 0, size)
jpayne@68 480 if eol >= 0:
jpayne@68 481 size = eol + 1
jpayne@68 482 self._line_buffer = line[size:]
jpayne@68 483 return line[:size]
jpayne@68 484
jpayne@68 485 def close(self):
jpayne@68 486 self.shell.close()
jpayne@68 487
jpayne@68 488
jpayne@68 489 class MyHandler(rpc.RPCHandler):
jpayne@68 490
jpayne@68 491 def handle(self):
jpayne@68 492 """Override base method"""
jpayne@68 493 executive = Executive(self)
jpayne@68 494 self.register("exec", executive)
jpayne@68 495 self.console = self.get_remote_proxy("console")
jpayne@68 496 sys.stdin = StdInputFile(self.console, "stdin",
jpayne@68 497 iomenu.encoding, iomenu.errors)
jpayne@68 498 sys.stdout = StdOutputFile(self.console, "stdout",
jpayne@68 499 iomenu.encoding, iomenu.errors)
jpayne@68 500 sys.stderr = StdOutputFile(self.console, "stderr",
jpayne@68 501 iomenu.encoding, "backslashreplace")
jpayne@68 502
jpayne@68 503 sys.displayhook = rpc.displayhook
jpayne@68 504 # page help() text to shell.
jpayne@68 505 import pydoc # import must be done here to capture i/o binding
jpayne@68 506 pydoc.pager = pydoc.plainpager
jpayne@68 507
jpayne@68 508 # Keep a reference to stdin so that it won't try to exit IDLE if
jpayne@68 509 # sys.stdin gets changed from within IDLE's shell. See issue17838.
jpayne@68 510 self._keep_stdin = sys.stdin
jpayne@68 511
jpayne@68 512 install_recursionlimit_wrappers()
jpayne@68 513
jpayne@68 514 self.interp = self.get_remote_proxy("interp")
jpayne@68 515 rpc.RPCHandler.getresponse(self, myseq=None, wait=0.05)
jpayne@68 516
jpayne@68 517 def exithook(self):
jpayne@68 518 "override SocketIO method - wait for MainThread to shut us down"
jpayne@68 519 time.sleep(10)
jpayne@68 520
jpayne@68 521 def EOFhook(self):
jpayne@68 522 "Override SocketIO method - terminate wait on callback and exit thread"
jpayne@68 523 global quitting
jpayne@68 524 quitting = True
jpayne@68 525 thread.interrupt_main()
jpayne@68 526
jpayne@68 527 def decode_interrupthook(self):
jpayne@68 528 "interrupt awakened thread"
jpayne@68 529 global quitting
jpayne@68 530 quitting = True
jpayne@68 531 thread.interrupt_main()
jpayne@68 532
jpayne@68 533
jpayne@68 534 class Executive(object):
jpayne@68 535
jpayne@68 536 def __init__(self, rpchandler):
jpayne@68 537 self.rpchandler = rpchandler
jpayne@68 538 self.locals = __main__.__dict__
jpayne@68 539 self.calltip = calltip.Calltip()
jpayne@68 540 self.autocomplete = autocomplete.AutoComplete()
jpayne@68 541
jpayne@68 542 def runcode(self, code):
jpayne@68 543 global interruptable
jpayne@68 544 try:
jpayne@68 545 self.usr_exc_info = None
jpayne@68 546 interruptable = True
jpayne@68 547 try:
jpayne@68 548 exec(code, self.locals)
jpayne@68 549 finally:
jpayne@68 550 interruptable = False
jpayne@68 551 except SystemExit as e:
jpayne@68 552 if e.args: # SystemExit called with an argument.
jpayne@68 553 ob = e.args[0]
jpayne@68 554 if not isinstance(ob, (type(None), int)):
jpayne@68 555 print('SystemExit: ' + str(ob), file=sys.stderr)
jpayne@68 556 # Return to the interactive prompt.
jpayne@68 557 except:
jpayne@68 558 self.usr_exc_info = sys.exc_info()
jpayne@68 559 if quitting:
jpayne@68 560 exit()
jpayne@68 561 print_exception()
jpayne@68 562 jit = self.rpchandler.console.getvar("<<toggle-jit-stack-viewer>>")
jpayne@68 563 if jit:
jpayne@68 564 self.rpchandler.interp.open_remote_stack_viewer()
jpayne@68 565 else:
jpayne@68 566 flush_stdout()
jpayne@68 567
jpayne@68 568 def interrupt_the_server(self):
jpayne@68 569 if interruptable:
jpayne@68 570 thread.interrupt_main()
jpayne@68 571
jpayne@68 572 def start_the_debugger(self, gui_adap_oid):
jpayne@68 573 return debugger_r.start_debugger(self.rpchandler, gui_adap_oid)
jpayne@68 574
jpayne@68 575 def stop_the_debugger(self, idb_adap_oid):
jpayne@68 576 "Unregister the Idb Adapter. Link objects and Idb then subject to GC"
jpayne@68 577 self.rpchandler.unregister(idb_adap_oid)
jpayne@68 578
jpayne@68 579 def get_the_calltip(self, name):
jpayne@68 580 return self.calltip.fetch_tip(name)
jpayne@68 581
jpayne@68 582 def get_the_completion_list(self, what, mode):
jpayne@68 583 return self.autocomplete.fetch_completions(what, mode)
jpayne@68 584
jpayne@68 585 def stackviewer(self, flist_oid=None):
jpayne@68 586 if self.usr_exc_info:
jpayne@68 587 typ, val, tb = self.usr_exc_info
jpayne@68 588 else:
jpayne@68 589 return None
jpayne@68 590 flist = None
jpayne@68 591 if flist_oid is not None:
jpayne@68 592 flist = self.rpchandler.get_remote_proxy(flist_oid)
jpayne@68 593 while tb and tb.tb_frame.f_globals["__name__"] in ["rpc", "run"]:
jpayne@68 594 tb = tb.tb_next
jpayne@68 595 sys.last_type = typ
jpayne@68 596 sys.last_value = val
jpayne@68 597 item = stackviewer.StackTreeItem(flist, tb)
jpayne@68 598 return debugobj_r.remote_object_tree_item(item)
jpayne@68 599
jpayne@68 600
jpayne@68 601 if __name__ == '__main__':
jpayne@68 602 from unittest import main
jpayne@68 603 main('idlelib.idle_test.test_run', verbosity=2)
jpayne@68 604
jpayne@68 605 capture_warnings(False) # Make sure turned off; see bpo-18081.