annotate CSP2/CSP2_env/env-d9b9114564458d9d-741b3de822f2aaca6c6caa4325c4afce/lib/python3.8/idlelib/run.py @ 69:33d812a61356

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