diff options
Diffstat (limited to 'Lib/idlelib/PyShell.py')
-rw-r--r-- | Lib/idlelib/PyShell.py | 229 |
1 files changed, 104 insertions, 125 deletions
diff --git a/Lib/idlelib/PyShell.py b/Lib/idlelib/PyShell.py index 15ca392ca24..fb47b994d1f 100644 --- a/Lib/idlelib/PyShell.py +++ b/Lib/idlelib/PyShell.py @@ -1,14 +1,15 @@ -#! /usr/bin/env python +#! /usr/bin/env python3 +import getopt import os import os.path -import sys -import string -import getopt import re import socket -import time +import subprocess +import sys import threading +import time +import tokenize import traceback import types import io @@ -17,12 +18,12 @@ import linecache from code import InteractiveInterpreter try: - from Tkinter import * + from tkinter import * except ImportError: - print>>sys.__stderr__, "** IDLE can't import Tkinter. " \ - "Your Python may not be configured for Tk. **" + print("** IDLE can't import Tkinter. " \ + "Your Python may not be configured for Tk. **", file=sys.__stderr__) sys.exit(1) -import tkMessageBox +import tkinter.messagebox as tkMessageBox from idlelib.EditorWindow import EditorWindow, fixwordbreaks from idlelib.FileList import FileList @@ -36,15 +37,9 @@ from idlelib import Debugger from idlelib import RemoteDebugger from idlelib import macosxSupport -IDENTCHARS = string.ascii_letters + string.digits + "_" HOST = '127.0.0.1' # python execution server on localhost loopback PORT = 0 # someday pass in host, port for remote debug capability -try: - from signal import SIGTERM -except ImportError: - SIGTERM = 15 - # 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 @@ -126,6 +121,7 @@ class PyShellEditorWindow(EditorWindow): ("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) ] @@ -213,12 +209,12 @@ class PyShellEditorWindow(EditorWindow): breaks = self.breakpoints filename = self.io.filename try: - with open(self.breakpointPath,"r") as old_file: - lines = old_file.readlines() + with open(self.breakpointPath, "r") as fp: + lines = fp.readlines() except IOError: lines = [] try: - with open(self.breakpointPath,"w") as new_file: + with open(self.breakpointPath, "w") as new_file: for line in lines: if not line.startswith(filename + '='): new_file.write(line) @@ -240,7 +236,8 @@ class PyShellEditorWindow(EditorWindow): if filename is None: return if os.path.isfile(self.breakpointPath): - lines = open(self.breakpointPath,"r").readlines() + 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:]) @@ -366,20 +363,17 @@ class ModifiedInterpreter(InteractiveInterpreter): self.original_compiler_flags = self.compile.compiler.flags rpcclt = None - rpcpid = None + rpcsubproc = None def spawn_subprocess(self): if self.subprocess_arglist is None: self.subprocess_arglist = self.build_subprocess_arglist() - args = self.subprocess_arglist - self.rpcpid = os.spawnv(os.P_NOWAIT, sys.executable, args) + 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] - if 1/2 > 0: # account for new division - w.append('-Qnew') # 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. @@ -389,12 +383,7 @@ class ModifiedInterpreter(InteractiveInterpreter): command = "__import__('idlelib.run').run.main(%r)" % (del_exitf,) else: command = "__import__('run').main(%r)" % (del_exitf,) - if sys.platform[:3] == 'win' and ' ' in sys.executable: - # handle embedded space in path by quoting the argument - decorated_exec = '"%s"' % sys.executable - else: - decorated_exec = sys.executable - return [decorated_exec] + w + ["-c", command, str(self.port)] + return [sys.executable] + w + ["-c", command, str(self.port)] def start_subprocess(self): addr = (HOST, self.port) @@ -404,7 +393,7 @@ class ModifiedInterpreter(InteractiveInterpreter): try: self.rpcclt = MyRPCClient(addr) break - except socket.error, err: + except socket.error as err: pass else: self.display_port_binding_error() @@ -425,7 +414,7 @@ class ModifiedInterpreter(InteractiveInterpreter): self.rpcclt.listening_sock.settimeout(10) try: self.rpcclt.accept() - except socket.timeout, err: + except socket.timeout as err: self.display_no_subprocess_error() return None # Can't regiter self.tkconsole.stdin, since run.py wants to @@ -455,14 +444,14 @@ class ModifiedInterpreter(InteractiveInterpreter): pass # Kill subprocess, spawn a new one, accept connection. self.rpcclt.close() - self.unix_terminate() + self.terminate_subprocess() console = self.tkconsole was_executing = console.executing console.executing = False self.spawn_subprocess() try: self.rpcclt.accept() - except socket.timeout, err: + except socket.timeout as err: self.display_no_subprocess_error() return None self.transfer_path(with_cwd=with_cwd) @@ -497,23 +486,22 @@ class ModifiedInterpreter(InteractiveInterpreter): self.rpcclt.close() except AttributeError: # no socket pass - self.unix_terminate() + self.terminate_subprocess() self.tkconsole.executing = False self.rpcclt = None - def unix_terminate(self): - "UNIX: make sure subprocess is terminated and collect status" - if hasattr(os, 'kill'): + def terminate_subprocess(self): + "Make sure subprocess is terminated" + try: + self.rpcsubproc.kill() + except OSError: + # process already terminated + return + else: try: - os.kill(self.rpcpid, SIGTERM) + self.rpcsubproc.wait() except OSError: - # process already terminated: return - else: - try: - os.waitpid(self.rpcpid, 0) - except OSError: - return def transfer_path(self, with_cwd=False): if with_cwd: # Issue 13506 @@ -550,14 +538,14 @@ class ModifiedInterpreter(InteractiveInterpreter): console = self.tkconsole.console if how == "OK": if what is not None: - print >>console, repr(what) + 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 >>sys.__stderr__, errmsg, what - print >>console, errmsg, what + 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() @@ -616,14 +604,15 @@ class ModifiedInterpreter(InteractiveInterpreter): def execfile(self, filename, source=None): "Execute an existing file" if source is None: - source = open(filename, "r").read() + with tokenize.open(filename) as fp: + source = fp.read() try: code = compile(source, filename, "exec") except (OverflowError, SyntaxError): self.tkconsole.resetoutput() tkerr = self.tkconsole.stderr - print>>tkerr, '*** Error in script or command!\n' - print>>tkerr, 'Traceback (most recent call last):' + print('*** Error in script or command!\n', file=tkerr) + print('Traceback (most recent call last):', file=tkerr) InteractiveInterpreter.showsyntaxerror(self, filename) self.tkconsole.showprompt() else: @@ -635,14 +624,16 @@ class ModifiedInterpreter(InteractiveInterpreter): self.more = 0 self.save_warnings_filters = warnings.filters[:] warnings.filterwarnings(action="error", category=SyntaxWarning) - if isinstance(source, types.UnicodeType): - from idlelib import IOBinding - try: - source = source.encode(IOBinding.encoding) - except UnicodeError: - self.tkconsole.resetoutput() - self.write("Unsupported characters in input\n") - return + # at the moment, InteractiveInterpreter expects str + assert isinstance(source, str) + #if isinstance(source, str): + # from idlelib import IOBinding + # try: + # source = source.encode(IOBinding.encoding) + # except UnicodeError: + # self.tkconsole.resetoutput() + # self.write("Unsupported characters in input\n") + # return try: # InteractiveInterpreter.runsource() calls its runcode() method, # which is overridden (see below) @@ -673,47 +664,30 @@ class ModifiedInterpreter(InteractiveInterpreter): \n""" % (filename,)) def showsyntaxerror(self, filename=None): - """Extend base class method: Add Colorizing + """Override Interactive Interpreter method: Use Colorizing Color the offending position instead of printing it and pointing at it with a caret. """ - text = self.tkconsole.text - stuff = self.unpackerror() - if stuff: - msg, lineno, offset, line = stuff - if lineno == 1: - pos = "iomark + %d chars" % (offset-1) - else: - pos = "iomark linestart + %d lines + %d chars" % \ - (lineno-1, offset-1) - text.tag_add("ERROR", pos) - text.see(pos) - char = text.get(pos) - if char and char in IDENTCHARS: - text.tag_add("ERROR", pos + " wordstart", pos) - self.tkconsole.resetoutput() - self.write("SyntaxError: %s\n" % str(msg)) - else: - self.tkconsole.resetoutput() - InteractiveInterpreter.showsyntaxerror(self, filename) - self.tkconsole.showprompt() - - def unpackerror(self): + tkconsole = self.tkconsole + text = tkconsole.text + text.tag_remove("ERROR", "1.0", "end") type, value, tb = sys.exc_info() - ok = type is SyntaxError - if ok: - try: - msg, (dummy_filename, lineno, offset, line) = value - if not offset: - offset = 0 - except: - ok = 0 - if ok: - return msg, lineno, offset, line + msg = getattr(value, 'msg', '') or value or "<no detail available>" + lineno = getattr(value, 'lineno', '') or 1 + offset = getattr(value, 'offset', '') or 0 + if offset == 0: + lineno += 1 #mark end of offending line + if lineno == 1: + pos = "iomark + %d chars" % (offset-1) else: - return None + 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" @@ -725,7 +699,7 @@ class ModifiedInterpreter(InteractiveInterpreter): def checklinecache(self): c = linecache.cache - for key in c.keys(): + for key in list(c.keys()): if key[:1] + key[-1:] != "<>": del c[key] @@ -738,7 +712,7 @@ class ModifiedInterpreter(InteractiveInterpreter): if self.rpcclt: self.rpcclt.remotequeue("exec", "runcode", (code,), {}) else: - exec code in self.locals + exec(code, self.locals) return 1 def runcode(self, code): @@ -758,7 +732,7 @@ class ModifiedInterpreter(InteractiveInterpreter): elif debugger: debugger.run(code, self.locals) else: - exec code in self.locals + exec(code, self.locals) except SystemExit: if not self.tkconsole.closing: if tkMessageBox.askyesno( @@ -773,14 +747,14 @@ class ModifiedInterpreter(InteractiveInterpreter): raise except: if use_subprocess: - print >>self.tkconsole.stderr, \ - "IDLE internal error in runcode()" + print("IDLE internal error in runcode()", + file=self.tkconsole.stderr) self.showtraceback() self.tkconsole.endexecuting() else: if self.tkconsole.canceled: self.tkconsole.canceled = False - print >>self.tkconsole.stderr, "KeyboardInterrupt" + print("KeyboardInterrupt", file=self.tkconsole.stderr) else: self.showtraceback() finally: @@ -792,7 +766,7 @@ class ModifiedInterpreter(InteractiveInterpreter): def write(self, s): "Override base class method" - self.tkconsole.stderr.write(s) + return self.tkconsole.stderr.write(s) def display_port_binding_error(self): tkMessageBox.showerror( @@ -876,6 +850,8 @@ class PyShell(OutputWindow): 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) + self.color = color = self.ColorDelegator() + self.per.insertfilter(color) if use_subprocess: text.bind("<<view-restart>>", self.view_restart_mark) text.bind("<<restart-shell>>", self.restart_shell) @@ -892,6 +868,14 @@ class PyShell(OutputWindow): sys.stdout = self.stdout sys.stderr = self.stderr sys.stdin = self.stdin + try: + # page help() text to shell. + import pydoc # import must be done here to capture i/o rebinding. + # XXX KBK 27Dec07 use a textView someday, but must work w/o subproc + pydoc.pager = pydoc.plainpager + except: + sys.stderr = sys.__stderr__ + raise # self.history = self.History(self.text) # @@ -1017,6 +1001,7 @@ class PyShell(OutputWindow): 'Type "copyright", "credits" or "license()" for more information.' def begin(self): + self.text.mark_set("iomark", "insert") self.resetoutput() if use_subprocess: nosub = '' @@ -1029,8 +1014,8 @@ class PyShell(OutputWindow): self.write("Python %s on %s\n%s\n%s" % (sys.version, sys.platform, self.COPYRIGHT, nosub)) self.showprompt() - import Tkinter - Tkinter._default_root = None # 03Jan04 KBK What's this? + import tkinter + tkinter._default_root = None # 03Jan04 KBK What's this? return True def readline(self): @@ -1043,12 +1028,6 @@ class PyShell(OutputWindow): line = self.text.get("iomark", "end-1c") if len(line) == 0: # may be EOF if we quit our mainloop with Ctrl-C line = "\n" - if isinstance(line, unicode): - from idlelib import IOBinding - try: - line = line.encode(IOBinding.encoding) - except UnicodeError: - pass self.resetoutput() if self.canceled: self.canceled = 0 @@ -1166,7 +1145,7 @@ class PyShell(OutputWindow): self.text.tag_add("stdin", "iomark", "end-1c") self.text.update_idletasks() if self.reading: - self.top.quit() # Break out of recursive mainloop() in raw_input() + self.top.quit() # Break out of recursive mainloop() else: self.runit() return "break" @@ -1252,19 +1231,20 @@ class PyShell(OutputWindow): self.text.insert("end-1c", "\n") self.text.mark_set("iomark", "end-1c") self.set_line_and_column() - sys.stdout.softspace = 0 def write(self, s, tags=()): try: self.text.mark_gravity("iomark", "right") - OutputWindow.write(self, s, tags, "iomark") + count = OutputWindow.write(self, s, tags, "iomark") self.text.mark_gravity("iomark", "left") except: - pass + raise ###pass # ### 11Aug07 KBK if we are expecting exceptions + # let's find out what they are and be specific. if self.canceled: self.canceled = 0 if not use_subprocess: raise KeyboardInterrupt + return count def rmenu_check_cut(self): try: @@ -1272,25 +1252,24 @@ class PyShell(OutputWindow): return 'disabled' except TclError: # no selection, so the index 'sel.first' doesn't exist return 'disabled' - return super(PyShell, self).rmenu_check_cut() + return super().rmenu_check_cut() def rmenu_check_paste(self): - if self.text.compare('insert', '<', 'iomark'): + if self.text.compare('insert','<','iomark'): return 'disabled' - return super(PyShell, self).rmenu_check_paste() + return super().rmenu_check_paste() class PseudoFile(object): def __init__(self, shell, tags, encoding=None): self.shell = shell self.tags = tags - self.softspace = 0 self.encoding = encoding def write(self, s): - if not isinstance(s, (basestring, bytearray)): - raise TypeError('must be string, not ' + type(s).__name__) - self.shell.write(s, self.tags) + if not isinstance(s, str): + raise TypeError('must be str, not ' + type(s).__name__) + return self.shell.write(s, self.tags) def writelines(self, lines): for line in lines: @@ -1351,7 +1330,7 @@ idle -est "Baz" foo.py Run $IDLESTARTUP or $PYTHONSTARTUP, edit foo.py, and open a shell window with the title "Baz". -idle -c "import sys; print sys.argv" "foo" +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]. @@ -1360,7 +1339,7 @@ idle -d -s -r foo.py "Hello World" run foo.py, passing "foo.py" in sys.argv[0] and "Hello World" in sys.argv[1]. -echo "import sys; print sys.argv" | idle - "foobar" +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]. """ @@ -1377,7 +1356,7 @@ def main(): startup = False try: opts, args = getopt.getopt(sys.argv[1:], "c:deihnr:st:") - except getopt.error, msg: + except getopt.error as msg: sys.stderr.write("Error: %s\n" % str(msg)) sys.stderr.write(usage_msg) sys.exit(2) @@ -1403,7 +1382,7 @@ def main(): if os.path.isfile(script): pass else: - print "No script file: ", script + print("No script file: ", script) sys.exit() enable_shell = True if o == '-s': @@ -1431,11 +1410,11 @@ def main(): pathx.append(os.path.dirname(filename)) for dir in pathx: dir = os.path.abspath(dir) - if dir not in sys.path: + if not dir in sys.path: sys.path.insert(0, dir) else: dir = os.getcwd() - if not dir in sys.path: + 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', |