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