#! /usr/bin/env python3import sysif __name__ == "__main__":sys.modules['idlelib.pyshell'] = sys.modules['__main__']try:from tkinter import *except ImportError:print("** IDLE can't import Tkinter.\n""Your Python may not be configured for Tk. **", file=sys.__stderr__)raise SystemExit(1)# Valid arguments for the ...Awareness call below are defined in the following.# https://msdn.microsoft.com/en-us/library/windows/desktop/dn280512(v=vs.85).aspxif sys.platform == 'win32':try:import ctypesPROCESS_SYSTEM_DPI_AWARE = 1ctypes.OleDLL('shcore').SetProcessDpiAwareness(PROCESS_SYSTEM_DPI_AWARE)except (ImportError, AttributeError, OSError):passimport tkinter.messagebox as tkMessageBoxif TkVersion < 8.5:root = Tk() # otherwise create root in mainroot.withdraw()from idlelib.run import fix_scalingfix_scaling(root)tkMessageBox.showerror("Idle Cannot Start","Idle requires tcl/tk 8.5+, not %s." % TkVersion,parent=root)raise SystemExit(1)from code import InteractiveInterpreterimport linecacheimport osimport os.pathfrom platform import python_versionimport reimport socketimport subprocessfrom textwrap import TextWrapperimport threadingimport timeimport tokenizeimport warningsfrom idlelib.colorizer import ColorDelegatorfrom idlelib.config import idleConffrom idlelib import debuggerfrom idlelib import debugger_rfrom idlelib.editor import EditorWindow, fixwordbreaksfrom idlelib.filelist import FileListfrom idlelib.outwin import OutputWindowfrom idlelib import rpcfrom idlelib.run import idle_formatwarning, StdInputFile, StdOutputFilefrom idlelib.undo import UndoDelegatorHOST = '127.0.0.1' # python execution server on localhost loopbackPORT = 0 # someday pass in host, port for remote debug capability# Override warnings module to write to warning_stream. Initialize to send IDLE# internal warnings to the console. ScriptBinding.check_syntax() will# temporarily redirect the stream to the shell window to display warnings when# checking user's code.warning_stream = sys.__stderr__ # None, at least on Windows, if no console.def idle_showwarning(message, category, filename, lineno, file=None, line=None):"""Show Idle-format warning (after replacing warnings.showwarning).The differences are the formatter called, the file=None replacement,which can be None, the capture of the consequence AttributeError,and the output of a hard-coded prompt."""if file is None:file = warning_streamtry:file.write(idle_formatwarning(message, category, filename, lineno, line=line))file.write(">>> ")except (AttributeError, OSError):pass # if file (probably __stderr__) is invalid, skip warning._warnings_showwarning = Nonedef capture_warnings(capture):"Replace warning.showwarning with idle_showwarning, or reverse."global _warnings_showwarningif capture:if _warnings_showwarning is None:_warnings_showwarning = warnings.showwarningwarnings.showwarning = idle_showwarningelse:if _warnings_showwarning is not None:warnings.showwarning = _warnings_showwarning_warnings_showwarning = Nonecapture_warnings(True)def extended_linecache_checkcache(filename=None,orig_checkcache=linecache.checkcache):"""Extend linecache.checkcache to preserve the <pyshell#...> entriesRather than repeating the linecache code, patch it to save the<pyshell#...> entries, call the original linecache.checkcache()(skipping them), and then restore the saved entries.orig_checkcache is bound at definition time to the originalmethod, allowing it to be patched."""cache = linecache.cachesave = {}for key in list(cache):if key[:1] + key[-1:] == '<>':save[key] = cache.pop(key)orig_checkcache(filename)cache.update(save)# Patch linecache.checkcache():linecache.checkcache = extended_linecache_checkcacheclass PyShellEditorWindow(EditorWindow):"Regular text edit window in IDLE, supports breakpoints"def __init__(self, *args):self.breakpoints = []EditorWindow.__init__(self, *args)self.text.bind("<<set-breakpoint-here>>", self.set_breakpoint_here)self.text.bind("<<clear-breakpoint-here>>", self.clear_breakpoint_here)self.text.bind("<<open-python-shell>>", self.flist.open_shell)#TODO: don't read/write this from/to .idlerc when testingself.breakpointPath = os.path.join(idleConf.userdir, 'breakpoints.lst')# whenever a file is changed, restore breakpointsdef filename_changed_hook(old_hook=self.io.filename_change_hook,self=self):self.restore_file_breaks()old_hook()self.io.set_filename_change_hook(filename_changed_hook)if self.io.filename:self.restore_file_breaks()self.color_breakpoint_text()rmenu_specs = [("Cut", "<<cut>>", "rmenu_check_cut"),("Copy", "<<copy>>", "rmenu_check_copy"),("Paste", "<<paste>>", "rmenu_check_paste"),(None, None, None),("Set Breakpoint", "<<set-breakpoint-here>>", None),("Clear Breakpoint", "<<clear-breakpoint-here>>", None)]def color_breakpoint_text(self, color=True):"Turn colorizing of breakpoint text on or off"if self.io is None:# possible due to update in restore_file_breaksreturnif color:theme = idleConf.CurrentTheme()cfg = idleConf.GetHighlight(theme, "break")else:cfg = {'foreground': '', 'background': ''}self.text.tag_config('BREAK', cfg)def set_breakpoint(self, lineno):text = self.textfilename = self.io.filenametext.tag_add("BREAK", "%d.0" % lineno, "%d.0" % (lineno+1))try:self.breakpoints.index(lineno)except ValueError: # only add if missing, i.e. do onceself.breakpoints.append(lineno)try: # update the subprocess debuggerdebug = self.flist.pyshell.interp.debuggerdebug.set_breakpoint_here(filename, lineno)except: # but debugger may not be active right now....passdef set_breakpoint_here(self, event=None):text = self.textfilename = self.io.filenameif not filename:text.bell()returnlineno = int(float(text.index("insert")))self.set_breakpoint(lineno)def clear_breakpoint_here(self, event=None):text = self.textfilename = self.io.filenameif not filename:text.bell()returnlineno = int(float(text.index("insert")))try:self.breakpoints.remove(lineno)except:passtext.tag_remove("BREAK", "insert linestart",\"insert lineend +1char")try:debug = self.flist.pyshell.interp.debuggerdebug.clear_breakpoint_here(filename, lineno)except:passdef clear_file_breaks(self):if self.breakpoints:text = self.textfilename = self.io.filenameif not filename:text.bell()returnself.breakpoints = []text.tag_remove("BREAK", "1.0", END)try:debug = self.flist.pyshell.interp.debuggerdebug.clear_file_breaks(filename)except:passdef store_file_breaks(self):"Save breakpoints when file is saved"# XXX 13 Dec 2002 KBK Currently the file must be saved before it can# be run. The breaks are saved at that time. If we introduce# a temporary file save feature the save breaks functionality# needs to be re-verified, since the breaks at the time the# temp file is created may differ from the breaks at the last# permanent save of the file. Currently, a break introduced# after a save will be effective, but not persistent.# This is necessary to keep the saved breaks synched with the# saved file.## Breakpoints are set as tagged ranges in the text.# Since a modified file has to be saved before it is# run, and since self.breakpoints (from which the subprocess# debugger is loaded) is updated during the save, the visible# breaks stay synched with the subprocess even if one of these# unexpected breakpoint deletions occurs.breaks = self.breakpointsfilename = self.io.filenametry:with open(self.breakpointPath, "r") as fp:lines = fp.readlines()except OSError:lines = []try:with open(self.breakpointPath, "w") as new_file:for line in lines:if not line.startswith(filename + '='):new_file.write(line)self.update_breakpoints()breaks = self.breakpointsif breaks:new_file.write(filename + '=' + str(breaks) + '\n')except OSError as err:if not getattr(self.root, "breakpoint_error_displayed", False):self.root.breakpoint_error_displayed = TruetkMessageBox.showerror(title='IDLE Error',message='Unable to update breakpoint list:\n%s'% str(err),parent=self.text)def restore_file_breaks(self):self.text.update() # this enables setting "BREAK" tags to be visibleif self.io is None:# can happen if IDLE closes due to the .update() callreturnfilename = self.io.filenameif filename is None:returnif os.path.isfile(self.breakpointPath):with open(self.breakpointPath, "r") as fp:lines = fp.readlines()for line in lines:if line.startswith(filename + '='):breakpoint_linenumbers = eval(line[len(filename)+1:])for breakpoint_linenumber in breakpoint_linenumbers:self.set_breakpoint(breakpoint_linenumber)def update_breakpoints(self):"Retrieves all the breakpoints in the current window"text = self.textranges = text.tag_ranges("BREAK")linenumber_list = self.ranges_to_linenumbers(ranges)self.breakpoints = linenumber_listdef ranges_to_linenumbers(self, ranges):lines = []for index in range(0, len(ranges), 2):lineno = int(float(ranges[index].string))end = int(float(ranges[index+1].string))while lineno < end:lines.append(lineno)lineno += 1return lines# XXX 13 Dec 2002 KBK Not used currently# def saved_change_hook(self):# "Extend base method - clear breaks if module is modified"# if not self.get_saved():# self.clear_file_breaks()# EditorWindow.saved_change_hook(self)def _close(self):"Extend base method - clear breaks when module is closed"self.clear_file_breaks()EditorWindow._close(self)class PyShellFileList(FileList):"Extend base class: IDLE supports a shell and breakpoints"# override FileList's class variable, instances return PyShellEditorWindow# instead of EditorWindow when new edit windows are created.EditorWindow = PyShellEditorWindowpyshell = Nonedef open_shell(self, event=None):if self.pyshell:self.pyshell.top.wakeup()else:self.pyshell = PyShell(self)if self.pyshell:if not self.pyshell.begin():return Nonereturn self.pyshellclass ModifiedColorDelegator(ColorDelegator):"Extend base class: colorizer for the shell window itself"def __init__(self):ColorDelegator.__init__(self)self.LoadTagDefs()def recolorize_main(self):self.tag_remove("TODO", "1.0", "iomark")self.tag_add("SYNC", "1.0", "iomark")ColorDelegator.recolorize_main(self)def LoadTagDefs(self):ColorDelegator.LoadTagDefs(self)theme = idleConf.CurrentTheme()self.tagdefs.update({"stdin": {'background':None,'foreground':None},"stdout": idleConf.GetHighlight(theme, "stdout"),"stderr": idleConf.GetHighlight(theme, "stderr"),"console": idleConf.GetHighlight(theme, "console"),})def removecolors(self):# Don't remove shell color tags before "iomark"for tag in self.tagdefs:self.tag_remove(tag, "iomark", "end")class ModifiedUndoDelegator(UndoDelegator):"Extend base class: forbid insert/delete before the I/O mark"def insert(self, index, chars, tags=None):try:if self.delegate.compare(index, "<", "iomark"):self.delegate.bell()returnexcept TclError:passUndoDelegator.insert(self, index, chars, tags)def delete(self, index1, index2=None):try:if self.delegate.compare(index1, "<", "iomark"):self.delegate.bell()returnexcept TclError:passUndoDelegator.delete(self, index1, index2)class MyRPCClient(rpc.RPCClient):def handle_EOF(self):"Override the base class - just re-raise EOFError"raise EOFErrordef restart_line(width, filename): # See bpo-38141."""Return width long restart line formatted with filename.Fill line with balanced '='s, with any extras and at least one atthe beginning. Do not end with a trailing space."""tag = f"= RESTART: {filename or 'Shell'} ="if width >= len(tag):div, mod = divmod((width -len(tag)), 2)return f"{(div+mod)*'='}{tag}{div*'='}"else:return tag[:-2] # Remove ' ='.class ModifiedInterpreter(InteractiveInterpreter):def __init__(self, tkconsole):self.tkconsole = tkconsolelocals = sys.modules['__main__'].__dict__InteractiveInterpreter.__init__(self, locals=locals)self.restarting = Falseself.subprocess_arglist = Noneself.port = PORTself.original_compiler_flags = self.compile.compiler.flags_afterid = Nonerpcclt = Nonerpcsubproc = Nonedef spawn_subprocess(self):if self.subprocess_arglist is None:self.subprocess_arglist = self.build_subprocess_arglist()self.rpcsubproc = subprocess.Popen(self.subprocess_arglist)def build_subprocess_arglist(self):assert (self.port!=0), ("Socket should have been assigned a port number.")w = ['-W' + s for s in sys.warnoptions]# Maybe IDLE is installed and is being accessed via sys.path,# or maybe it's not installed and the idle.py script is being# run from the IDLE source directory.del_exitf = idleConf.GetOption('main', 'General', 'delete-exitfunc',default=False, type='bool')command = "__import__('idlelib.run').run.main(%r)" % (del_exitf,)return [sys.executable] + w + ["-c", command, str(self.port)]def start_subprocess(self):addr = (HOST, self.port)# GUI makes several attempts to acquire socket, listens for connectionfor i in range(3):time.sleep(i)try:self.rpcclt = MyRPCClient(addr)breakexcept OSError:passelse:self.display_port_binding_error()return None# if PORT was 0, system will assign an 'ephemeral' port. Find it out:self.port = self.rpcclt.listening_sock.getsockname()[1]# if PORT was not 0, probably working with a remote execution serverif PORT != 0:# To allow reconnection within the 2MSL wait (cf. Stevens TCP# V1, 18.6), set SO_REUSEADDR. Note that this can be problematic# on Windows since the implementation allows two active sockets on# the same address!self.rpcclt.listening_sock.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR, 1)self.spawn_subprocess()#time.sleep(20) # test to simulate GUI not accepting connection# Accept the connection from the Python execution serverself.rpcclt.listening_sock.settimeout(10)try:self.rpcclt.accept()except socket.timeout:self.display_no_subprocess_error()return Noneself.rpcclt.register("console", self.tkconsole)self.rpcclt.register("stdin", self.tkconsole.stdin)self.rpcclt.register("stdout", self.tkconsole.stdout)self.rpcclt.register("stderr", self.tkconsole.stderr)self.rpcclt.register("flist", self.tkconsole.flist)self.rpcclt.register("linecache", linecache)self.rpcclt.register("interp", self)self.transfer_path(with_cwd=True)self.poll_subprocess()return self.rpccltdef restart_subprocess(self, with_cwd=False, filename=''):if self.restarting:return self.rpccltself.restarting = True# close only the subprocess debuggerdebug = self.getdebugger()if debug:try:# Only close subprocess debugger, don't unregister gui_adap!debugger_r.close_subprocess_debugger(self.rpcclt)except:pass# Kill subprocess, spawn a new one, accept connection.self.rpcclt.close()self.terminate_subprocess()console = self.tkconsolewas_executing = console.executingconsole.executing = Falseself.spawn_subprocess()try:self.rpcclt.accept()except socket.timeout:self.display_no_subprocess_error()return Noneself.transfer_path(with_cwd=with_cwd)console.stop_readline()# annotate restart in shell window and mark itconsole.text.delete("iomark", "end-1c")console.write('\n')console.write(restart_line(console.width, filename))console.text.mark_set("restart", "end-1c")console.text.mark_gravity("restart", "left")if not filename:console.showprompt()# restart subprocess debuggerif debug:# Restarted debugger connects to current instance of debug GUIdebugger_r.restart_subprocess_debugger(self.rpcclt)# reload remote debugger breakpoints for all PyShellEditWindowsdebug.load_breakpoints()self.compile.compiler.flags = self.original_compiler_flagsself.restarting = Falsereturn self.rpccltdef __request_interrupt(self):self.rpcclt.remotecall("exec", "interrupt_the_server", (), {})def interrupt_subprocess(self):threading.Thread(target=self.__request_interrupt).start()def kill_subprocess(self):if self._afterid is not None:self.tkconsole.text.after_cancel(self._afterid)try:self.rpcclt.listening_sock.close()except AttributeError: # no socketpasstry:self.rpcclt.close()except AttributeError: # no socketpassself.terminate_subprocess()self.tkconsole.executing = Falseself.rpcclt = Nonedef terminate_subprocess(self):"Make sure subprocess is terminated"try:self.rpcsubproc.kill()except OSError:# process already terminatedreturnelse:try:self.rpcsubproc.wait()except OSError:returndef transfer_path(self, with_cwd=False):if with_cwd: # Issue 13506path = [''] # include Current Working Directorypath.extend(sys.path)else:path = sys.pathself.runcommand("""if 1:import sys as _sys_sys.path = %rdel _sys\n""" % (path,))active_seq = Nonedef poll_subprocess(self):clt = self.rpccltif clt is None:returntry:response = clt.pollresponse(self.active_seq, wait=0.05)except (EOFError, OSError, KeyboardInterrupt):# lost connection or subprocess terminated itself, restart# [the KBI is from rpc.SocketIO.handle_EOF()]if self.tkconsole.closing:returnresponse = Noneself.restart_subprocess()if response:self.tkconsole.resetoutput()self.active_seq = Nonehow, what = responseconsole = self.tkconsole.consoleif how == "OK":if what is not None:print(repr(what), file=console)elif how == "EXCEPTION":if self.tkconsole.getvar("<<toggle-jit-stack-viewer>>"):self.remote_stack_viewer()elif how == "ERROR":errmsg = "pyshell.ModifiedInterpreter: Subprocess ERROR:\n"print(errmsg, what, file=sys.__stderr__)print(errmsg, what, file=console)# we received a response to the currently active seq number:try:self.tkconsole.endexecuting()except AttributeError: # shell may have closedpass# Reschedule myselfif not self.tkconsole.closing:self._afterid = self.tkconsole.text.after(self.tkconsole.pollinterval, self.poll_subprocess)debugger = Nonedef setdebugger(self, debugger):self.debugger = debuggerdef getdebugger(self):return self.debuggerdef open_remote_stack_viewer(self):"""Initiate the remote stack viewer from a separate thread.This method is called from the subprocess, and by returning from thismethod we allow the subprocess to unblock. After a bit the shellrequests the subprocess to open the remote stack viewer which returns astatic object looking at the last exception. It is queried throughthe RPC mechanism."""self.tkconsole.text.after(300, self.remote_stack_viewer)returndef remote_stack_viewer(self):from idlelib import debugobj_roid = self.rpcclt.remotequeue("exec", "stackviewer", ("flist",), {})if oid is None:self.tkconsole.root.bell()returnitem = debugobj_r.StubObjectTreeItem(self.rpcclt, oid)from idlelib.tree import ScrolledCanvas, TreeNodetop = Toplevel(self.tkconsole.root)theme = idleConf.CurrentTheme()background = idleConf.GetHighlight(theme, 'normal')['background']sc = ScrolledCanvas(top, bg=background, highlightthickness=0)sc.frame.pack(expand=1, fill="both")node = TreeNode(sc.canvas, None, item)node.expand()# XXX Should GC the remote tree when closing the windowgid = 0def execsource(self, source):"Like runsource() but assumes complete exec source"filename = self.stuffsource(source)self.execfile(filename, source)def execfile(self, filename, source=None):"Execute an existing file"if source is None:with tokenize.open(filename) as fp:source = fp.read()if use_subprocess:source = (f"__file__ = r'''{os.path.abspath(filename)}'''\n"+ source + "\ndel __file__")try:code = compile(source, filename, "exec")except (OverflowError, SyntaxError):self.tkconsole.resetoutput()print('*** Error in script or command!\n''Traceback (most recent call last):',file=self.tkconsole.stderr)InteractiveInterpreter.showsyntaxerror(self, filename)self.tkconsole.showprompt()else:self.runcode(code)def runsource(self, source):"Extend base class method: Stuff the source in the line cache first"filename = self.stuffsource(source)self.more = 0# at the moment, InteractiveInterpreter expects strassert isinstance(source, str)# InteractiveInterpreter.runsource() calls its runcode() method,# which is overridden (see below)return InteractiveInterpreter.runsource(self, source, filename)def stuffsource(self, source):"Stuff source in the filename cache"filename = "<pyshell#%d>" % self.gidself.gid = self.gid + 1lines = source.split("\n")linecache.cache[filename] = len(source)+1, 0, lines, filenamereturn filenamedef prepend_syspath(self, filename):"Prepend sys.path with file's directory if not already included"self.runcommand("""if 1:_filename = %rimport sys as _sysfrom os.path import dirname as _dirname_dir = _dirname(_filename)if not _dir in _sys.path:_sys.path.insert(0, _dir)del _filename, _sys, _dirname, _dir\n""" % (filename,))def showsyntaxerror(self, filename=None):"""Override Interactive Interpreter method: Use ColorizingColor the offending position instead of printing it and pointing at itwith a caret."""tkconsole = self.tkconsoletext = tkconsole.texttext.tag_remove("ERROR", "1.0", "end")type, value, tb = sys.exc_info()msg = getattr(value, 'msg', '') or value or "<no detail available>"lineno = getattr(value, 'lineno', '') or 1offset = getattr(value, 'offset', '') or 0if offset == 0:lineno += 1 #mark end of offending lineif lineno == 1:pos = "iomark + %d chars" % (offset-1)else:pos = "iomark linestart + %d lines + %d chars" % \(lineno-1, offset-1)tkconsole.colorize_syntax_error(text, pos)tkconsole.resetoutput()self.write("SyntaxError: %s\n" % msg)tkconsole.showprompt()def showtraceback(self):"Extend base class method to reset output properly"self.tkconsole.resetoutput()self.checklinecache()InteractiveInterpreter.showtraceback(self)if self.tkconsole.getvar("<<toggle-jit-stack-viewer>>"):self.tkconsole.open_stack_viewer()def checklinecache(self):c = linecache.cachefor key in list(c.keys()):if key[:1] + key[-1:] != "<>":del c[key]def runcommand(self, code):"Run the code without invoking the debugger"# The code better not raise an exception!if self.tkconsole.executing:self.display_executing_dialog()return 0if self.rpcclt:self.rpcclt.remotequeue("exec", "runcode", (code,), {})else:exec(code, self.locals)return 1def runcode(self, code):"Override base class method"if self.tkconsole.executing:self.interp.restart_subprocess()self.checklinecache()debugger = self.debuggertry:self.tkconsole.beginexecuting()if not debugger and self.rpcclt is not None:self.active_seq = self.rpcclt.asyncqueue("exec", "runcode",(code,), {})elif debugger:debugger.run(code, self.locals)else:exec(code, self.locals)except SystemExit:if not self.tkconsole.closing:if tkMessageBox.askyesno("Exit?","Do you want to exit altogether?",default="yes",parent=self.tkconsole.text):raiseelse:self.showtraceback()else:raiseexcept:if use_subprocess:print("IDLE internal error in runcode()",file=self.tkconsole.stderr)self.showtraceback()self.tkconsole.endexecuting()else:if self.tkconsole.canceled:self.tkconsole.canceled = Falseprint("KeyboardInterrupt", file=self.tkconsole.stderr)else:self.showtraceback()finally:if not use_subprocess:try:self.tkconsole.endexecuting()except AttributeError: # shell may have closedpassdef write(self, s):"Override base class method"return self.tkconsole.stderr.write(s)def display_port_binding_error(self):tkMessageBox.showerror("Port Binding Error","IDLE can't bind to a TCP/IP port, which is necessary to ""communicate with its Python execution server. This might be ""because no networking is installed on this computer. ""Run IDLE with the -n command line switch to start without a ""subprocess and refer to Help/IDLE Help 'Running without a ""subprocess' for further details.",parent=self.tkconsole.text)def display_no_subprocess_error(self):tkMessageBox.showerror("Subprocess Connection Error","IDLE's subprocess didn't make connection.\n""See the 'Startup failure' section of the IDLE doc, online at\n""https://docs.python.org/3/library/idle.html#startup-failure",parent=self.tkconsole.text)def display_executing_dialog(self):tkMessageBox.showerror("Already executing","The Python Shell window is already executing a command; ""please wait until it is finished.",parent=self.tkconsole.text)class PyShell(OutputWindow):shell_title = "Python " + python_version() + " Shell"# Override classesColorDelegator = ModifiedColorDelegatorUndoDelegator = ModifiedUndoDelegator# Override menusmenu_specs = [("file", "_File"),("edit", "_Edit"),("debug", "_Debug"),("options", "_Options"),("window", "_Window"),("help", "_Help"),]# Extend right-click context menurmenu_specs = OutputWindow.rmenu_specs + [("Squeeze", "<<squeeze-current-text>>"),]allow_line_numbers = False# New classesfrom idlelib.history import Historydef __init__(self, flist=None):if use_subprocess:ms = self.menu_specsif ms[2][0] != "shell":ms.insert(2, ("shell", "She_ll"))self.interp = ModifiedInterpreter(self)if flist is None:root = Tk()fixwordbreaks(root)root.withdraw()flist = PyShellFileList(root)OutputWindow.__init__(self, flist, None, None)self.usetabs = True# indentwidth must be 8 when using tabs. See note in EditorWindow:self.indentwidth = 8self.sys_ps1 = sys.ps1 if hasattr(sys, 'ps1') else '>>> 'self.prompt_last_line = self.sys_ps1.split('\n')[-1]self.prompt = self.sys_ps1 # Changes when debug activetext = self.texttext.configure(wrap="char")text.bind("<<newline-and-indent>>", self.enter_callback)text.bind("<<plain-newline-and-indent>>", self.linefeed_callback)text.bind("<<interrupt-execution>>", self.cancel_callback)text.bind("<<end-of-file>>", self.eof_callback)text.bind("<<open-stack-viewer>>", self.open_stack_viewer)text.bind("<<toggle-debugger>>", self.toggle_debugger)text.bind("<<toggle-jit-stack-viewer>>", self.toggle_jit_stack_viewer)if use_subprocess:text.bind("<<view-restart>>", self.view_restart_mark)text.bind("<<restart-shell>>", self.restart_shell)squeezer = self.Squeezer(self)text.bind("<<squeeze-current-text>>",squeezer.squeeze_current_text_event)self.save_stdout = sys.stdoutself.save_stderr = sys.stderrself.save_stdin = sys.stdinfrom idlelib import iomenuself.stdin = StdInputFile(self, "stdin",iomenu.encoding, iomenu.errors)self.stdout = StdOutputFile(self, "stdout",iomenu.encoding, iomenu.errors)self.stderr = StdOutputFile(self, "stderr",iomenu.encoding, "backslashreplace")self.console = StdOutputFile(self, "console",iomenu.encoding, iomenu.errors)if not use_subprocess:sys.stdout = self.stdoutsys.stderr = self.stderrsys.stdin = self.stdintry:# page help() text to shell.import pydoc # import must be done here to capture i/o rebinding.# XXX KBK 27Dec07 use text viewer someday, but must work w/o subprocpydoc.pager = pydoc.plainpagerexcept:sys.stderr = sys.__stderr__raise#self.history = self.History(self.text)#self.pollinterval = 50 # millisecdef get_standard_extension_names(self):return idleConf.GetExtensions(shell_only=True)reading = Falseexecuting = Falsecanceled = Falseendoffile = Falseclosing = False_stop_readline_flag = Falsedef set_warning_stream(self, stream):global warning_streamwarning_stream = streamdef get_warning_stream(self):return warning_streamdef toggle_debugger(self, event=None):if self.executing:tkMessageBox.showerror("Don't debug now","You can only toggle the debugger when idle",parent=self.text)self.set_debugger_indicator()return "break"else:db = self.interp.getdebugger()if db:self.close_debugger()else:self.open_debugger()def set_debugger_indicator(self):db = self.interp.getdebugger()self.setvar("<<toggle-debugger>>", not not db)def toggle_jit_stack_viewer(self, event=None):pass # All we need is the variabledef close_debugger(self):db = self.interp.getdebugger()if db:self.interp.setdebugger(None)db.close()if self.interp.rpcclt:debugger_r.close_remote_debugger(self.interp.rpcclt)self.resetoutput()self.console.write("[DEBUG OFF]\n")self.prompt = self.sys_ps1self.showprompt()self.set_debugger_indicator()def open_debugger(self):if self.interp.rpcclt:dbg_gui = debugger_r.start_remote_debugger(self.interp.rpcclt,self)else:dbg_gui = debugger.Debugger(self)self.interp.setdebugger(dbg_gui)dbg_gui.load_breakpoints()self.prompt = "[DEBUG ON]\n" + self.sys_ps1self.showprompt()self.set_debugger_indicator()def beginexecuting(self):"Helper for ModifiedInterpreter"self.resetoutput()self.executing = 1def endexecuting(self):"Helper for ModifiedInterpreter"self.executing = 0self.canceled = 0self.showprompt()def close(self):"Extend EditorWindow.close()"if self.executing:response = tkMessageBox.askokcancel("Kill?","Your program is still running!\n Do you want to kill it?",default="ok",parent=self.text)if response is False:return "cancel"self.stop_readline()self.canceled = Trueself.closing = Truereturn EditorWindow.close(self)def _close(self):"Extend EditorWindow._close(), shut down debugger and execution server"self.close_debugger()if use_subprocess:self.interp.kill_subprocess()# Restore std streamssys.stdout = self.save_stdoutsys.stderr = self.save_stderrsys.stdin = self.save_stdin# Break cyclesself.interp = Noneself.console = Noneself.flist.pyshell = Noneself.history = NoneEditorWindow._close(self)def ispythonsource(self, filename):"Override EditorWindow method: never remove the colorizer"return Truedef short_title(self):return self.shell_titleCOPYRIGHT = \'Type "help", "copyright", "credits" or "license()" for more information.'def begin(self):self.text.mark_set("iomark", "insert")self.resetoutput()if use_subprocess:nosub = ''client = self.interp.start_subprocess()if not client:self.close()return Falseelse:nosub = ("==== No Subprocess ====\n\n" +"WARNING: Running IDLE without a Subprocess is deprecated\n" +"and will be removed in a later version. See Help/IDLE Help\n" +"for details.\n\n")sys.displayhook = rpc.displayhookself.write("Python %s on %s\n%s\n%s" %(sys.version, sys.platform, self.COPYRIGHT, nosub))self.text.focus_force()self.showprompt()import tkintertkinter._default_root = None # 03Jan04 KBK What's this?return Truedef stop_readline(self):if not self.reading: # no nested mainloop to exit.returnself._stop_readline_flag = Trueself.top.quit()def readline(self):save = self.readingtry:self.reading = 1self.top.mainloop() # nested mainloop()finally:self.reading = saveif self._stop_readline_flag:self._stop_readline_flag = Falsereturn ""line = self.text.get("iomark", "end-1c")if len(line) == 0: # may be EOF if we quit our mainloop with Ctrl-Cline = "\n"self.resetoutput()if self.canceled:self.canceled = 0if not use_subprocess:raise KeyboardInterruptif self.endoffile:self.endoffile = 0line = ""return linedef isatty(self):return Truedef cancel_callback(self, event=None):try:if self.text.compare("sel.first", "!=", "sel.last"):return # Active selection -- always use default bindingexcept:passif not (self.executing or self.reading):self.resetoutput()self.interp.write("KeyboardInterrupt\n")self.showprompt()return "break"self.endoffile = 0self.canceled = 1if (self.executing and self.interp.rpcclt):if self.interp.getdebugger():self.interp.restart_subprocess()else:self.interp.interrupt_subprocess()if self.reading:self.top.quit() # exit the nested mainloop() in readline()return "break"def eof_callback(self, event):if self.executing and not self.reading:return # Let the default binding (delete next char) take overif not (self.text.compare("iomark", "==", "insert") andself.text.compare("insert", "==", "end-1c")):return # Let the default binding (delete next char) take overif not self.executing:self.resetoutput()self.close()else:self.canceled = 0self.endoffile = 1self.top.quit()return "break"def linefeed_callback(self, event):# Insert a linefeed without entering anything (still autoindented)if self.reading:self.text.insert("insert", "\n")self.text.see("insert")else:self.newline_and_indent_event(event)return "break"def enter_callback(self, event):if self.executing and not self.reading:return # Let the default binding (insert '\n') take over# If some text is selected, recall the selection# (but only if this before the I/O mark)try:sel = self.text.get("sel.first", "sel.last")if sel:if self.text.compare("sel.last", "<=", "iomark"):self.recall(sel, event)return "break"except:pass# If we're strictly before the line containing iomark, recall# the current line, less a leading prompt, less leading or# trailing whitespaceif self.text.compare("insert", "<", "iomark linestart"):# Check if there's a relevant stdin range -- if so, use itprev = self.text.tag_prevrange("stdin", "insert")if prev and self.text.compare("insert", "<", prev[1]):self.recall(self.text.get(prev[0], prev[1]), event)return "break"next = self.text.tag_nextrange("stdin", "insert")if next and self.text.compare("insert lineend", ">=", next[0]):self.recall(self.text.get(next[0], next[1]), event)return "break"# No stdin mark -- just get the current line, less any promptindices = self.text.tag_nextrange("console", "insert linestart")if indices and \self.text.compare(indices[0], "<=", "insert linestart"):self.recall(self.text.get(indices[1], "insert lineend"), event)else:self.recall(self.text.get("insert linestart", "insert lineend"), event)return "break"# If we're between the beginning of the line and the iomark, i.e.# in the prompt area, move to the end of the promptif self.text.compare("insert", "<", "iomark"):self.text.mark_set("insert", "iomark")# If we're in the current input and there's only whitespace# beyond the cursor, erase that whitespace firsts = self.text.get("insert", "end-1c")if s and not s.strip():self.text.delete("insert", "end-1c")# If we're in the current input before its last line,# insert a newline right at the insert pointif self.text.compare("insert", "<", "end-1c linestart"):self.newline_and_indent_event(event)return "break"# We're in the last line; append a newline and submit itself.text.mark_set("insert", "end-1c")if self.reading:self.text.insert("insert", "\n")self.text.see("insert")else:self.newline_and_indent_event(event)self.text.tag_add("stdin", "iomark", "end-1c")self.text.update_idletasks()if self.reading:self.top.quit() # Break out of recursive mainloop()else:self.runit()return "break"def recall(self, s, event):# remove leading and trailing empty or whitespace liness = re.sub(r'^\s*\n', '' , s)s = re.sub(r'\n\s*$', '', s)lines = s.split('\n')self.text.undo_block_start()try:self.text.tag_remove("sel", "1.0", "end")self.text.mark_set("insert", "end-1c")prefix = self.text.get("insert linestart", "insert")if prefix.rstrip().endswith(':'):self.newline_and_indent_event(event)prefix = self.text.get("insert linestart", "insert")self.text.insert("insert", lines[0].strip())if len(lines) > 1:orig_base_indent = re.search(r'^([ \t]*)', lines[0]).group(0)new_base_indent = re.search(r'^([ \t]*)', prefix).group(0)for line in lines[1:]:if line.startswith(orig_base_indent):# replace orig base indentation with new indentationline = new_base_indent + line[len(orig_base_indent):]self.text.insert('insert', '\n'+line.rstrip())finally:self.text.see("insert")self.text.undo_block_stop()def runit(self):line = self.text.get("iomark", "end-1c")# Strip off last newline and surrounding whitespace.# (To allow you to hit return twice to end a statement.)i = len(line)while i > 0 and line[i-1] in " \t":i = i-1if i > 0 and line[i-1] == "\n":i = i-1while i > 0 and line[i-1] in " \t":i = i-1line = line[:i]self.interp.runsource(line)def open_stack_viewer(self, event=None):if self.interp.rpcclt:return self.interp.remote_stack_viewer()try:sys.last_tracebackexcept:tkMessageBox.showerror("No stack trace","There is no stack trace yet.\n""(sys.last_traceback is not defined)",parent=self.text)returnfrom idlelib.stackviewer import StackBrowserStackBrowser(self.root, self.flist)def view_restart_mark(self, event=None):self.text.see("iomark")self.text.see("restart")def restart_shell(self, event=None):"Callback for Run/Restart Shell Cntl-F6"self.interp.restart_subprocess(with_cwd=True)def showprompt(self):self.resetoutput()self.console.write(self.prompt)self.text.mark_set("insert", "end-1c")self.set_line_and_column()self.io.reset_undo()def show_warning(self, msg):width = self.interp.tkconsole.widthwrapper = TextWrapper(width=width, tabsize=8, expand_tabs=True)wrapped_msg = '\n'.join(wrapper.wrap(msg))if not wrapped_msg.endswith('\n'):wrapped_msg += '\n'self.per.bottom.insert("iomark linestart", wrapped_msg, "stderr")def resetoutput(self):source = self.text.get("iomark", "end-1c")if self.history:self.history.store(source)if self.text.get("end-2c") != "\n":self.text.insert("end-1c", "\n")self.text.mark_set("iomark", "end-1c")self.set_line_and_column()def write(self, s, tags=()):try:self.text.mark_gravity("iomark", "right")count = OutputWindow.write(self, s, tags, "iomark")self.text.mark_gravity("iomark", "left")except:raise ###pass # ### 11Aug07 KBK if we are expecting exceptions# let's find out what they are and be specific.if self.canceled:self.canceled = 0if not use_subprocess:raise KeyboardInterruptreturn countdef rmenu_check_cut(self):try:if self.text.compare('sel.first', '<', 'iomark'):return 'disabled'except TclError: # no selection, so the index 'sel.first' doesn't existreturn 'disabled'return super().rmenu_check_cut()def rmenu_check_paste(self):if self.text.compare('insert','<','iomark'):return 'disabled'return super().rmenu_check_paste()def fix_x11_paste(root):"Make paste replace selection on x11. See issue #5124."if root._windowingsystem == 'x11':for cls in 'Text', 'Entry', 'Spinbox':root.bind_class(cls,'<<Paste>>','catch {%W delete sel.first sel.last}\n' +root.bind_class(cls, '<<Paste>>'))usage_msg = """\USAGE: idle [-deins] [-t title] [file]*idle [-dns] [-t title] (-c cmd | -r file) [arg]*idle [-dns] [-t title] - [arg]*-h print this help message and exit-n run IDLE without a subprocess (DEPRECATED,see Help/IDLE Help for details)The following options will override the IDLE 'settings' configuration:-e open an edit window-i open a shell windowThe following options imply -i and will open a shell:-c cmd run the command in a shell, or-r file run script from file-d enable the debugger-s run $IDLESTARTUP or $PYTHONSTARTUP before anything else-t title set title of shell windowA default edit window will be bypassed when -c, -r, or - are used.[arg]* are passed to the command (-c) or script (-r) in sys.argv[1:].Examples:idleOpen an edit window or shell depending on IDLE's configuration.idle foo.py foobar.pyEdit the files, also open a shell if configured to start with shell.idle -est "Baz" foo.pyRun $IDLESTARTUP or $PYTHONSTARTUP, edit foo.py, and open a shellwindow with the title "Baz".idle -c "import sys; print(sys.argv)" "foo"Open a shell window and run the command, passing "-c" in sys.argv[0]and "foo" in sys.argv[1].idle -d -s -r foo.py "Hello World"Open a shell window, run a startup script, enable the debugger, andrun foo.py, passing "foo.py" in sys.argv[0] and "Hello World" insys.argv[1].echo "import sys; print(sys.argv)" | idle - "foobar"Open a shell window, run the script piped in, passing '' in sys.argv[0]and "foobar" in sys.argv[1]."""def main():import getoptfrom platform import systemfrom idlelib import testing # bool valuefrom idlelib import macosxglobal flist, root, use_subprocesscapture_warnings(True)use_subprocess = Trueenable_shell = Falseenable_edit = Falsedebug = Falsecmd = Nonescript = Nonestartup = Falsetry:opts, args = getopt.getopt(sys.argv[1:], "c:deihnr:st:")except getopt.error as msg:print("Error: %s\n%s" % (msg, usage_msg), file=sys.stderr)sys.exit(2)for o, a in opts:if o == '-c':cmd = aenable_shell = Trueif o == '-d':debug = Trueenable_shell = Trueif o == '-e':enable_edit = Trueif o == '-h':sys.stdout.write(usage_msg)sys.exit()if o == '-i':enable_shell = Trueif o == '-n':print(" Warning: running IDLE without a subprocess is deprecated.",file=sys.stderr)use_subprocess = Falseif o == '-r':script = aif os.path.isfile(script):passelse:print("No script file: ", script)sys.exit()enable_shell = Trueif o == '-s':startup = Trueenable_shell = Trueif o == '-t':PyShell.shell_title = aenable_shell = Trueif args and args[0] == '-':cmd = sys.stdin.read()enable_shell = True# process sys.argv and sys.path:for i in range(len(sys.path)):sys.path[i] = os.path.abspath(sys.path[i])if args and args[0] == '-':sys.argv = [''] + args[1:]elif cmd:sys.argv = ['-c'] + argselif script:sys.argv = [script] + argselif args:enable_edit = Truepathx = []for filename in args:pathx.append(os.path.dirname(filename))for dir in pathx:dir = os.path.abspath(dir)if not dir in sys.path:sys.path.insert(0, dir)else:dir = os.getcwd()if dir not in sys.path:sys.path.insert(0, dir)# check the IDLE settings configuration (but command line overrides)edit_start = idleConf.GetOption('main', 'General','editor-on-startup', type='bool')enable_edit = enable_edit or edit_startenable_shell = enable_shell or not enable_edit# Setup root. Don't break user code run in IDLE process.# Don't change environment when testing.if use_subprocess and not testing:NoDefaultRoot()root = Tk(className="Idle")root.withdraw()from idlelib.run import fix_scalingfix_scaling(root)# set application iconicondir = os.path.join(os.path.dirname(__file__), 'Icons')if system() == 'Windows':iconfile = os.path.join(icondir, 'idle.ico')root.wm_iconbitmap(default=iconfile)elif not macosx.isAquaTk():ext = '.png' if TkVersion >= 8.6 else '.gif'iconfiles = [os.path.join(icondir, 'idle_%d%s' % (size, ext))for size in (16, 32, 48)]icons = [PhotoImage(master=root, file=iconfile)for iconfile in iconfiles]root.wm_iconphoto(True, *icons)# start editor and/or shell windows:fixwordbreaks(root)fix_x11_paste(root)flist = PyShellFileList(root)macosx.setupApp(root, flist)if enable_edit:if not (cmd or script):for filename in args[:]:if flist.open(filename) is None:# filename is a directory actually, disconsider itargs.remove(filename)if not args:flist.new()if enable_shell:shell = flist.open_shell()if not shell:return # couldn't open shellif macosx.isAquaTk() and flist.dict:# On OSX: when the user has double-clicked on a file that causes# IDLE to be launched the shell window will open just in front of# the file she wants to see. Lower the interpreter window when# there are open files.shell.top.lower()else:shell = flist.pyshell# Handle remaining options. If any of these are set, enable_shell# was set also, so shell must be true to reach here.if debug:shell.open_debugger()if startup:filename = os.environ.get("IDLESTARTUP") or \os.environ.get("PYTHONSTARTUP")if filename and os.path.isfile(filename):shell.interp.execfile(filename)if cmd or script:shell.interp.runcommand("""if 1:import sys as _sys_sys.argv = %rdel _sys\n""" % (sys.argv,))if cmd:shell.interp.execsource(cmd)elif script:shell.interp.prepend_syspath(script)shell.interp.execfile(script)elif shell:# If there is a shell window and no cmd or script in progress,# check for problematic issues and print warning message(s) in# the IDLE shell window; this is less intrusive than always# opening a separate window.# Warn if using a problematic OS X Tk version.tkversionwarning = macosx.tkVersionWarning(root)if tkversionwarning:shell.show_warning(tkversionwarning)# Warn if the "Prefer tabs when opening documents" system# preference is set to "Always".prefer_tabs_preference_warning = macosx.preferTabsPreferenceWarning()if prefer_tabs_preference_warning:shell.show_warning(prefer_tabs_preference_warning)while flist.inversedict: # keep IDLE running while files are open.root.mainloop()root.destroy()capture_warnings(False)if __name__ == "__main__":main()capture_warnings(False) # Make sure turned off; see issue 18081
此处可能存在不合适展示的内容,页面不予展示。您可通过相关编辑功能自查并修改。
如您确认内容无涉及 不当用语 / 纯广告导流 / 暴力 / 低俗色情 / 侵权 / 盗版 / 虚假 / 无价值内容或违法国家有关法律法规的内容,可点击提交进行申诉,我们将尽快为您处理。