jpayne@69: """ idlelib.run jpayne@69: jpayne@69: Simplified, pyshell.ModifiedInterpreter spawns a subprocess with jpayne@69: f'''{sys.executable} -c "__import__('idlelib.run').run.main()"''' jpayne@69: '.run' is needed because __import__ returns idlelib, not idlelib.run. jpayne@69: """ jpayne@69: import functools jpayne@69: import io jpayne@69: import linecache jpayne@69: import queue jpayne@69: import sys jpayne@69: import textwrap jpayne@69: import time jpayne@69: import traceback jpayne@69: import _thread as thread jpayne@69: import threading jpayne@69: import warnings jpayne@69: jpayne@69: from idlelib import autocomplete # AutoComplete, fetch_encodings jpayne@69: from idlelib import calltip # Calltip jpayne@69: from idlelib import debugger_r # start_debugger jpayne@69: from idlelib import debugobj_r # remote_object_tree_item jpayne@69: from idlelib import iomenu # encoding jpayne@69: from idlelib import rpc # multiple objects jpayne@69: from idlelib import stackviewer # StackTreeItem jpayne@69: import __main__ jpayne@69: jpayne@69: import tkinter # Use tcl and, if startup fails, messagebox. jpayne@69: if not hasattr(sys.modules['idlelib.run'], 'firstrun'): jpayne@69: # Undo modifications of tkinter by idlelib imports; see bpo-25507. jpayne@69: for mod in ('simpledialog', 'messagebox', 'font', jpayne@69: 'dialog', 'filedialog', 'commondialog', jpayne@69: 'ttk'): jpayne@69: delattr(tkinter, mod) jpayne@69: del sys.modules['tkinter.' + mod] jpayne@69: # Avoid AttributeError if run again; see bpo-37038. jpayne@69: sys.modules['idlelib.run'].firstrun = False jpayne@69: jpayne@69: LOCALHOST = '127.0.0.1' jpayne@69: jpayne@69: jpayne@69: def idle_formatwarning(message, category, filename, lineno, line=None): jpayne@69: """Format warnings the IDLE way.""" jpayne@69: jpayne@69: s = "\nWarning (from warnings module):\n" jpayne@69: s += ' File \"%s\", line %s\n' % (filename, lineno) jpayne@69: if line is None: jpayne@69: line = linecache.getline(filename, lineno) jpayne@69: line = line.strip() jpayne@69: if line: jpayne@69: s += " %s\n" % line jpayne@69: s += "%s: %s\n" % (category.__name__, message) jpayne@69: return s jpayne@69: jpayne@69: def idle_showwarning_subproc( jpayne@69: message, category, filename, lineno, file=None, line=None): jpayne@69: """Show Idle-format warning after replacing warnings.showwarning. jpayne@69: jpayne@69: The only difference is the formatter called. jpayne@69: """ jpayne@69: if file is None: jpayne@69: file = sys.stderr jpayne@69: try: jpayne@69: file.write(idle_formatwarning( jpayne@69: message, category, filename, lineno, line)) jpayne@69: except OSError: jpayne@69: pass # the file (probably stderr) is invalid - this warning gets lost. jpayne@69: jpayne@69: _warnings_showwarning = None jpayne@69: jpayne@69: def capture_warnings(capture): jpayne@69: "Replace warning.showwarning with idle_showwarning_subproc, or reverse." jpayne@69: jpayne@69: global _warnings_showwarning jpayne@69: if capture: jpayne@69: if _warnings_showwarning is None: jpayne@69: _warnings_showwarning = warnings.showwarning jpayne@69: warnings.showwarning = idle_showwarning_subproc jpayne@69: else: jpayne@69: if _warnings_showwarning is not None: jpayne@69: warnings.showwarning = _warnings_showwarning jpayne@69: _warnings_showwarning = None jpayne@69: jpayne@69: capture_warnings(True) jpayne@69: tcl = tkinter.Tcl() jpayne@69: jpayne@69: def handle_tk_events(tcl=tcl): jpayne@69: """Process any tk events that are ready to be dispatched if tkinter jpayne@69: has been imported, a tcl interpreter has been created and tk has been jpayne@69: loaded.""" jpayne@69: tcl.eval("update") jpayne@69: jpayne@69: # Thread shared globals: Establish a queue between a subthread (which handles jpayne@69: # the socket) and the main thread (which runs user code), plus global jpayne@69: # completion, exit and interruptable (the main thread) flags: jpayne@69: jpayne@69: exit_now = False jpayne@69: quitting = False jpayne@69: interruptable = False jpayne@69: jpayne@69: def main(del_exitfunc=False): jpayne@69: """Start the Python execution server in a subprocess jpayne@69: jpayne@69: In the Python subprocess, RPCServer is instantiated with handlerclass jpayne@69: MyHandler, which inherits register/unregister methods from RPCHandler via jpayne@69: the mix-in class SocketIO. jpayne@69: jpayne@69: When the RPCServer 'server' is instantiated, the TCPServer initialization jpayne@69: creates an instance of run.MyHandler and calls its handle() method. jpayne@69: handle() instantiates a run.Executive object, passing it a reference to the jpayne@69: MyHandler object. That reference is saved as attribute rpchandler of the jpayne@69: Executive instance. The Executive methods have access to the reference and jpayne@69: can pass it on to entities that they command jpayne@69: (e.g. debugger_r.Debugger.start_debugger()). The latter, in turn, can jpayne@69: call MyHandler(SocketIO) register/unregister methods via the reference to jpayne@69: register and unregister themselves. jpayne@69: jpayne@69: """ jpayne@69: global exit_now jpayne@69: global quitting jpayne@69: global no_exitfunc jpayne@69: no_exitfunc = del_exitfunc jpayne@69: #time.sleep(15) # test subprocess not responding jpayne@69: try: jpayne@69: assert(len(sys.argv) > 1) jpayne@69: port = int(sys.argv[-1]) jpayne@69: except: jpayne@69: print("IDLE Subprocess: no IP port passed in sys.argv.", jpayne@69: file=sys.__stderr__) jpayne@69: return jpayne@69: jpayne@69: capture_warnings(True) jpayne@69: sys.argv[:] = [""] jpayne@69: sockthread = threading.Thread(target=manage_socket, jpayne@69: name='SockThread', jpayne@69: args=((LOCALHOST, port),)) jpayne@69: sockthread.daemon = True jpayne@69: sockthread.start() jpayne@69: while 1: jpayne@69: try: jpayne@69: if exit_now: jpayne@69: try: jpayne@69: exit() jpayne@69: except KeyboardInterrupt: jpayne@69: # exiting but got an extra KBI? Try again! jpayne@69: continue jpayne@69: try: jpayne@69: request = rpc.request_queue.get(block=True, timeout=0.05) jpayne@69: except queue.Empty: jpayne@69: request = None jpayne@69: # Issue 32207: calling handle_tk_events here adds spurious jpayne@69: # queue.Empty traceback to event handling exceptions. jpayne@69: if request: jpayne@69: seq, (method, args, kwargs) = request jpayne@69: ret = method(*args, **kwargs) jpayne@69: rpc.response_queue.put((seq, ret)) jpayne@69: else: jpayne@69: handle_tk_events() jpayne@69: except KeyboardInterrupt: jpayne@69: if quitting: jpayne@69: exit_now = True jpayne@69: continue jpayne@69: except SystemExit: jpayne@69: capture_warnings(False) jpayne@69: raise jpayne@69: except: jpayne@69: type, value, tb = sys.exc_info() jpayne@69: try: jpayne@69: print_exception() jpayne@69: rpc.response_queue.put((seq, None)) jpayne@69: except: jpayne@69: # Link didn't work, print same exception to __stderr__ jpayne@69: traceback.print_exception(type, value, tb, file=sys.__stderr__) jpayne@69: exit() jpayne@69: else: jpayne@69: continue jpayne@69: jpayne@69: def manage_socket(address): jpayne@69: for i in range(3): jpayne@69: time.sleep(i) jpayne@69: try: jpayne@69: server = MyRPCServer(address, MyHandler) jpayne@69: break jpayne@69: except OSError as err: jpayne@69: print("IDLE Subprocess: OSError: " + err.args[1] + jpayne@69: ", retrying....", file=sys.__stderr__) jpayne@69: socket_error = err jpayne@69: else: jpayne@69: print("IDLE Subprocess: Connection to " jpayne@69: "IDLE GUI failed, exiting.", file=sys.__stderr__) jpayne@69: show_socket_error(socket_error, address) jpayne@69: global exit_now jpayne@69: exit_now = True jpayne@69: return jpayne@69: server.handle_request() # A single request only jpayne@69: jpayne@69: def show_socket_error(err, address): jpayne@69: "Display socket error from manage_socket." jpayne@69: import tkinter jpayne@69: from tkinter.messagebox import showerror jpayne@69: root = tkinter.Tk() jpayne@69: fix_scaling(root) jpayne@69: root.withdraw() jpayne@69: showerror( jpayne@69: "Subprocess Connection Error", jpayne@69: f"IDLE's subprocess can't connect to {address[0]}:{address[1]}.\n" jpayne@69: f"Fatal OSError #{err.errno}: {err.strerror}.\n" jpayne@69: "See the 'Startup failure' section of the IDLE doc, online at\n" jpayne@69: "https://docs.python.org/3/library/idle.html#startup-failure", jpayne@69: parent=root) jpayne@69: root.destroy() jpayne@69: jpayne@69: def print_exception(): jpayne@69: import linecache jpayne@69: linecache.checkcache() jpayne@69: flush_stdout() jpayne@69: efile = sys.stderr jpayne@69: typ, val, tb = excinfo = sys.exc_info() jpayne@69: sys.last_type, sys.last_value, sys.last_traceback = excinfo jpayne@69: seen = set() jpayne@69: jpayne@69: def print_exc(typ, exc, tb): jpayne@69: seen.add(id(exc)) jpayne@69: context = exc.__context__ jpayne@69: cause = exc.__cause__ jpayne@69: if cause is not None and id(cause) not in seen: jpayne@69: print_exc(type(cause), cause, cause.__traceback__) jpayne@69: print("\nThe above exception was the direct cause " jpayne@69: "of the following exception:\n", file=efile) jpayne@69: elif (context is not None and jpayne@69: not exc.__suppress_context__ and jpayne@69: id(context) not in seen): jpayne@69: print_exc(type(context), context, context.__traceback__) jpayne@69: print("\nDuring handling of the above exception, " jpayne@69: "another exception occurred:\n", file=efile) jpayne@69: if tb: jpayne@69: tbe = traceback.extract_tb(tb) jpayne@69: print('Traceback (most recent call last):', file=efile) jpayne@69: exclude = ("run.py", "rpc.py", "threading.py", "queue.py", jpayne@69: "debugger_r.py", "bdb.py") jpayne@69: cleanup_traceback(tbe, exclude) jpayne@69: traceback.print_list(tbe, file=efile) jpayne@69: lines = traceback.format_exception_only(typ, exc) jpayne@69: for line in lines: jpayne@69: print(line, end='', file=efile) jpayne@69: jpayne@69: print_exc(typ, val, tb) jpayne@69: jpayne@69: def cleanup_traceback(tb, exclude): jpayne@69: "Remove excluded traces from beginning/end of tb; get cached lines" jpayne@69: orig_tb = tb[:] jpayne@69: while tb: jpayne@69: for rpcfile in exclude: jpayne@69: if tb[0][0].count(rpcfile): jpayne@69: break # found an exclude, break for: and delete tb[0] jpayne@69: else: jpayne@69: break # no excludes, have left RPC code, break while: jpayne@69: del tb[0] jpayne@69: while tb: jpayne@69: for rpcfile in exclude: jpayne@69: if tb[-1][0].count(rpcfile): jpayne@69: break jpayne@69: else: jpayne@69: break jpayne@69: del tb[-1] jpayne@69: if len(tb) == 0: jpayne@69: # exception was in IDLE internals, don't prune! jpayne@69: tb[:] = orig_tb[:] jpayne@69: print("** IDLE Internal Exception: ", file=sys.stderr) jpayne@69: rpchandler = rpc.objecttable['exec'].rpchandler jpayne@69: for i in range(len(tb)): jpayne@69: fn, ln, nm, line = tb[i] jpayne@69: if nm == '?': jpayne@69: nm = "-toplevel-" jpayne@69: if not line and fn.startswith(" 1.4: jpayne@69: for name in tkinter.font.names(root): jpayne@69: font = tkinter.font.Font(root=root, name=name, exists=True) jpayne@69: size = int(font['size']) jpayne@69: if size < 0: jpayne@69: font['size'] = round(-0.75*size) jpayne@69: jpayne@69: jpayne@69: def fixdoc(fun, text): jpayne@69: tem = (fun.__doc__ + '\n\n') if fun.__doc__ is not None else '' jpayne@69: fun.__doc__ = tem + textwrap.fill(textwrap.dedent(text)) jpayne@69: jpayne@69: RECURSIONLIMIT_DELTA = 30 jpayne@69: jpayne@69: def install_recursionlimit_wrappers(): jpayne@69: """Install wrappers to always add 30 to the recursion limit.""" jpayne@69: # see: bpo-26806 jpayne@69: jpayne@69: @functools.wraps(sys.setrecursionlimit) jpayne@69: def setrecursionlimit(*args, **kwargs): jpayne@69: # mimic the original sys.setrecursionlimit()'s input handling jpayne@69: if kwargs: jpayne@69: raise TypeError( jpayne@69: "setrecursionlimit() takes no keyword arguments") jpayne@69: try: jpayne@69: limit, = args jpayne@69: except ValueError: jpayne@69: raise TypeError(f"setrecursionlimit() takes exactly one " jpayne@69: f"argument ({len(args)} given)") jpayne@69: if not limit > 0: jpayne@69: raise ValueError( jpayne@69: "recursion limit must be greater or equal than 1") jpayne@69: jpayne@69: return setrecursionlimit.__wrapped__(limit + RECURSIONLIMIT_DELTA) jpayne@69: jpayne@69: fixdoc(setrecursionlimit, f"""\ jpayne@69: This IDLE wrapper adds {RECURSIONLIMIT_DELTA} to prevent possible jpayne@69: uninterruptible loops.""") jpayne@69: jpayne@69: @functools.wraps(sys.getrecursionlimit) jpayne@69: def getrecursionlimit(): jpayne@69: return getrecursionlimit.__wrapped__() - RECURSIONLIMIT_DELTA jpayne@69: jpayne@69: fixdoc(getrecursionlimit, f"""\ jpayne@69: This IDLE wrapper subtracts {RECURSIONLIMIT_DELTA} to compensate jpayne@69: for the {RECURSIONLIMIT_DELTA} IDLE adds when setting the limit.""") jpayne@69: jpayne@69: # add the delta to the default recursion limit, to compensate jpayne@69: sys.setrecursionlimit(sys.getrecursionlimit() + RECURSIONLIMIT_DELTA) jpayne@69: jpayne@69: sys.setrecursionlimit = setrecursionlimit jpayne@69: sys.getrecursionlimit = getrecursionlimit jpayne@69: jpayne@69: jpayne@69: def uninstall_recursionlimit_wrappers(): jpayne@69: """Uninstall the recursion limit wrappers from the sys module. jpayne@69: jpayne@69: IDLE only uses this for tests. Users can import run and call jpayne@69: this to remove the wrapping. jpayne@69: """ jpayne@69: if ( jpayne@69: getattr(sys.setrecursionlimit, '__wrapped__', None) and jpayne@69: getattr(sys.getrecursionlimit, '__wrapped__', None) jpayne@69: ): jpayne@69: sys.setrecursionlimit = sys.setrecursionlimit.__wrapped__ jpayne@69: sys.getrecursionlimit = sys.getrecursionlimit.__wrapped__ jpayne@69: sys.setrecursionlimit(sys.getrecursionlimit() - RECURSIONLIMIT_DELTA) jpayne@69: jpayne@69: jpayne@69: class MyRPCServer(rpc.RPCServer): jpayne@69: jpayne@69: def handle_error(self, request, client_address): jpayne@69: """Override RPCServer method for IDLE jpayne@69: jpayne@69: Interrupt the MainThread and exit server if link is dropped. jpayne@69: jpayne@69: """ jpayne@69: global quitting jpayne@69: try: jpayne@69: raise jpayne@69: except SystemExit: jpayne@69: raise jpayne@69: except EOFError: jpayne@69: global exit_now jpayne@69: exit_now = True jpayne@69: thread.interrupt_main() jpayne@69: except: jpayne@69: erf = sys.__stderr__ jpayne@69: print('\n' + '-'*40, file=erf) jpayne@69: print('Unhandled server exception!', file=erf) jpayne@69: print('Thread: %s' % threading.current_thread().name, file=erf) jpayne@69: print('Client Address: ', client_address, file=erf) jpayne@69: print('Request: ', repr(request), file=erf) jpayne@69: traceback.print_exc(file=erf) jpayne@69: print('\n*** Unrecoverable, server exiting!', file=erf) jpayne@69: print('-'*40, file=erf) jpayne@69: quitting = True jpayne@69: thread.interrupt_main() jpayne@69: jpayne@69: jpayne@69: # Pseudofiles for shell-remote communication (also used in pyshell) jpayne@69: jpayne@69: class StdioFile(io.TextIOBase): jpayne@69: jpayne@69: def __init__(self, shell, tags, encoding='utf-8', errors='strict'): jpayne@69: self.shell = shell jpayne@69: self.tags = tags jpayne@69: self._encoding = encoding jpayne@69: self._errors = errors jpayne@69: jpayne@69: @property jpayne@69: def encoding(self): jpayne@69: return self._encoding jpayne@69: jpayne@69: @property jpayne@69: def errors(self): jpayne@69: return self._errors jpayne@69: jpayne@69: @property jpayne@69: def name(self): jpayne@69: return '<%s>' % self.tags jpayne@69: jpayne@69: def isatty(self): jpayne@69: return True jpayne@69: jpayne@69: jpayne@69: class StdOutputFile(StdioFile): jpayne@69: jpayne@69: def writable(self): jpayne@69: return True jpayne@69: jpayne@69: def write(self, s): jpayne@69: if self.closed: jpayne@69: raise ValueError("write to closed file") jpayne@69: s = str.encode(s, self.encoding, self.errors).decode(self.encoding, self.errors) jpayne@69: return self.shell.write(s, self.tags) jpayne@69: jpayne@69: jpayne@69: class StdInputFile(StdioFile): jpayne@69: _line_buffer = '' jpayne@69: jpayne@69: def readable(self): jpayne@69: return True jpayne@69: jpayne@69: def read(self, size=-1): jpayne@69: if self.closed: jpayne@69: raise ValueError("read from closed file") jpayne@69: if size is None: jpayne@69: size = -1 jpayne@69: elif not isinstance(size, int): jpayne@69: raise TypeError('must be int, not ' + type(size).__name__) jpayne@69: result = self._line_buffer jpayne@69: self._line_buffer = '' jpayne@69: if size < 0: jpayne@69: while True: jpayne@69: line = self.shell.readline() jpayne@69: if not line: break jpayne@69: result += line jpayne@69: else: jpayne@69: while len(result) < size: jpayne@69: line = self.shell.readline() jpayne@69: if not line: break jpayne@69: result += line jpayne@69: self._line_buffer = result[size:] jpayne@69: result = result[:size] jpayne@69: return result jpayne@69: jpayne@69: def readline(self, size=-1): jpayne@69: if self.closed: jpayne@69: raise ValueError("read from closed file") jpayne@69: if size is None: jpayne@69: size = -1 jpayne@69: elif not isinstance(size, int): jpayne@69: raise TypeError('must be int, not ' + type(size).__name__) jpayne@69: line = self._line_buffer or self.shell.readline() jpayne@69: if size < 0: jpayne@69: size = len(line) jpayne@69: eol = line.find('\n', 0, size) jpayne@69: if eol >= 0: jpayne@69: size = eol + 1 jpayne@69: self._line_buffer = line[size:] jpayne@69: return line[:size] jpayne@69: jpayne@69: def close(self): jpayne@69: self.shell.close() jpayne@69: jpayne@69: jpayne@69: class MyHandler(rpc.RPCHandler): jpayne@69: jpayne@69: def handle(self): jpayne@69: """Override base method""" jpayne@69: executive = Executive(self) jpayne@69: self.register("exec", executive) jpayne@69: self.console = self.get_remote_proxy("console") jpayne@69: sys.stdin = StdInputFile(self.console, "stdin", jpayne@69: iomenu.encoding, iomenu.errors) jpayne@69: sys.stdout = StdOutputFile(self.console, "stdout", jpayne@69: iomenu.encoding, iomenu.errors) jpayne@69: sys.stderr = StdOutputFile(self.console, "stderr", jpayne@69: iomenu.encoding, "backslashreplace") jpayne@69: jpayne@69: sys.displayhook = rpc.displayhook jpayne@69: # page help() text to shell. jpayne@69: import pydoc # import must be done here to capture i/o binding jpayne@69: pydoc.pager = pydoc.plainpager jpayne@69: jpayne@69: # Keep a reference to stdin so that it won't try to exit IDLE if jpayne@69: # sys.stdin gets changed from within IDLE's shell. See issue17838. jpayne@69: self._keep_stdin = sys.stdin jpayne@69: jpayne@69: install_recursionlimit_wrappers() jpayne@69: jpayne@69: self.interp = self.get_remote_proxy("interp") jpayne@69: rpc.RPCHandler.getresponse(self, myseq=None, wait=0.05) jpayne@69: jpayne@69: def exithook(self): jpayne@69: "override SocketIO method - wait for MainThread to shut us down" jpayne@69: time.sleep(10) jpayne@69: jpayne@69: def EOFhook(self): jpayne@69: "Override SocketIO method - terminate wait on callback and exit thread" jpayne@69: global quitting jpayne@69: quitting = True jpayne@69: thread.interrupt_main() jpayne@69: jpayne@69: def decode_interrupthook(self): jpayne@69: "interrupt awakened thread" jpayne@69: global quitting jpayne@69: quitting = True jpayne@69: thread.interrupt_main() jpayne@69: jpayne@69: jpayne@69: class Executive(object): jpayne@69: jpayne@69: def __init__(self, rpchandler): jpayne@69: self.rpchandler = rpchandler jpayne@69: self.locals = __main__.__dict__ jpayne@69: self.calltip = calltip.Calltip() jpayne@69: self.autocomplete = autocomplete.AutoComplete() jpayne@69: jpayne@69: def runcode(self, code): jpayne@69: global interruptable jpayne@69: try: jpayne@69: self.usr_exc_info = None jpayne@69: interruptable = True jpayne@69: try: jpayne@69: exec(code, self.locals) jpayne@69: finally: jpayne@69: interruptable = False jpayne@69: except SystemExit as e: jpayne@69: if e.args: # SystemExit called with an argument. jpayne@69: ob = e.args[0] jpayne@69: if not isinstance(ob, (type(None), int)): jpayne@69: print('SystemExit: ' + str(ob), file=sys.stderr) jpayne@69: # Return to the interactive prompt. jpayne@69: except: jpayne@69: self.usr_exc_info = sys.exc_info() jpayne@69: if quitting: jpayne@69: exit() jpayne@69: print_exception() jpayne@69: jit = self.rpchandler.console.getvar("<>") jpayne@69: if jit: jpayne@69: self.rpchandler.interp.open_remote_stack_viewer() jpayne@69: else: jpayne@69: flush_stdout() jpayne@69: jpayne@69: def interrupt_the_server(self): jpayne@69: if interruptable: jpayne@69: thread.interrupt_main() jpayne@69: jpayne@69: def start_the_debugger(self, gui_adap_oid): jpayne@69: return debugger_r.start_debugger(self.rpchandler, gui_adap_oid) jpayne@69: jpayne@69: def stop_the_debugger(self, idb_adap_oid): jpayne@69: "Unregister the Idb Adapter. Link objects and Idb then subject to GC" jpayne@69: self.rpchandler.unregister(idb_adap_oid) jpayne@69: jpayne@69: def get_the_calltip(self, name): jpayne@69: return self.calltip.fetch_tip(name) jpayne@69: jpayne@69: def get_the_completion_list(self, what, mode): jpayne@69: return self.autocomplete.fetch_completions(what, mode) jpayne@69: jpayne@69: def stackviewer(self, flist_oid=None): jpayne@69: if self.usr_exc_info: jpayne@69: typ, val, tb = self.usr_exc_info jpayne@69: else: jpayne@69: return None jpayne@69: flist = None jpayne@69: if flist_oid is not None: jpayne@69: flist = self.rpchandler.get_remote_proxy(flist_oid) jpayne@69: while tb and tb.tb_frame.f_globals["__name__"] in ["rpc", "run"]: jpayne@69: tb = tb.tb_next jpayne@69: sys.last_type = typ jpayne@69: sys.last_value = val jpayne@69: item = stackviewer.StackTreeItem(flist, tb) jpayne@69: return debugobj_r.remote_object_tree_item(item) jpayne@69: jpayne@69: jpayne@69: if __name__ == '__main__': jpayne@69: from unittest import main jpayne@69: main('idlelib.idle_test.test_run', verbosity=2) jpayne@69: jpayne@69: capture_warnings(False) # Make sure turned off; see bpo-18081.