aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/Lib/idlelib/PyShell.py
diff options
context:
space:
mode:
Diffstat (limited to 'Lib/idlelib/PyShell.py')
-rw-r--r--Lib/idlelib/PyShell.py229
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',