summaryrefslogtreecommitdiffstats
path: root/Lib/idlelib/PyShell.py
diff options
context:
space:
mode:
Diffstat (limited to 'Lib/idlelib/PyShell.py')
-rw-r--r--Lib/idlelib/PyShell.py125
1 files changed, 67 insertions, 58 deletions
diff --git a/Lib/idlelib/PyShell.py b/Lib/idlelib/PyShell.py
index 0fa3d76..e7c71b7 100644
--- a/Lib/idlelib/PyShell.py
+++ b/Lib/idlelib/PyShell.py
@@ -1,13 +1,15 @@
-#! /usr/bin/env python
+#! /usr/bin/env python3
+import getopt
import os
import os.path
-import sys
-import getopt
import re
import socket
-import time
+import subprocess
+import sys
import threading
+import time
+import tokenize
import traceback
import types
@@ -37,11 +39,6 @@ from idlelib import macosxSupport
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
@@ -55,20 +52,21 @@ except ImportError:
else:
def idle_showwarning(message, category, filename, lineno,
file=None, line=None):
- file = warning_stream
+ if file is None:
+ file = warning_stream
try:
- file.write(warnings.formatwarning(message, category, filename,\
- lineno, file=file, line=line))
+ file.write(warnings.formatwarning(message, category, filename,
+ lineno, line=line))
except IOError:
pass ## file (probably __stderr__) is invalid, warning dropped.
warnings.showwarning = idle_showwarning
- def idle_formatwarning(message, category, filename, lineno,
- file=None, line=None):
+ def idle_formatwarning(message, category, filename, lineno, line=None):
"""Format warnings the IDLE way"""
s = "\nWarning (from warnings module):\n"
s += ' File \"%s\", line %s\n' % (filename, lineno)
- line = linecache.getline(filename, lineno).strip() \
- if line is None else line
+ if line is None:
+ line = linecache.getline(filename, lineno)
+ line = line.strip()
if line:
s += " %s\n" % line
s += "%s: %s\n>>> " % (category.__name__, message)
@@ -81,18 +79,17 @@ def extended_linecache_checkcache(filename=None,
Rather than repeating the linecache code, patch it to save the
<pyshell#...> entries, call the original linecache.checkcache()
- (which destroys them), and then restore the saved entries.
+ (skipping them), and then restore the saved entries.
orig_checkcache is bound at definition time to the original
method, allowing it to be patched.
-
"""
cache = linecache.cache
save = {}
- for filename in cache:
- if filename[:1] + filename[-1:] == '<>':
- save[filename] = cache[filename]
- orig_checkcache()
+ for key in list(cache):
+ if key[:1] + key[-1:] == '<>':
+ save[key] = cache.pop(key)
+ orig_checkcache(filename)
cache.update(save)
# Patch linecache.checkcache():
@@ -205,18 +202,26 @@ class PyShellEditorWindow(EditorWindow):
breaks = self.breakpoints
filename = self.io.filename
try:
- lines = open(self.breakpointPath,"r").readlines()
+ with open(self.breakpointPath, "r") as fp:
+ lines = fp.readlines()
except IOError:
lines = []
- new_file = open(self.breakpointPath,"w")
- for line in lines:
- if not line.startswith(filename + '='):
- new_file.write(line)
- self.update_breakpoints()
- breaks = self.breakpoints
- if breaks:
- new_file.write(filename + '=' + str(breaks) + '\n')
- new_file.close()
+ 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.breakpoints
+ if breaks:
+ new_file.write(filename + '=' + str(breaks) + '\n')
+ except IOError as err:
+ if not getattr(self.root, "breakpoint_error_displayed", False):
+ self.root.breakpoint_error_displayed = True
+ tkMessageBox.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 visible
@@ -224,7 +229,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:])
@@ -342,15 +348,15 @@ class ModifiedInterpreter(InteractiveInterpreter):
self.restarting = False
self.subprocess_arglist = None
self.port = PORT
+ 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), (
@@ -365,12 +371,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)
@@ -428,7 +429,7 @@ 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
@@ -455,6 +456,7 @@ class ModifiedInterpreter(InteractiveInterpreter):
gui = RemoteDebugger.restart_subprocess_debugger(self.rpcclt)
# reload remote debugger breakpoints for all PyShellEditWindows
debug.load_breakpoints()
+ self.compile.compiler.flags = self.original_compiler_flags
self.restarting = False
return self.rpcclt
@@ -469,23 +471,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):
self.runcommand("""if 1:
@@ -582,7 +583,8 @@ 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):
@@ -651,9 +653,9 @@ class ModifiedInterpreter(InteractiveInterpreter):
text = tkconsole.text
text.tag_remove("ERROR", "1.0", "end")
type, value, tb = sys.exc_info()
- msg = value.msg or "<no detail available>"
- lineno = value.lineno or 1
- offset = value.offset or 0
+ 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:
@@ -1417,6 +1419,13 @@ def main():
shell.interp.prepend_syspath(script)
shell.interp.execfile(script)
+ # Check for problematic OS X Tk versions and print a warning message
+ # in the IDLE shell window; this is less intrusive than always opening
+ # a separate window.
+ tkversionwarning = macosxSupport.tkVersionWarning(root)
+ if tkversionwarning:
+ shell.interp.runcommand(''.join(("print('", tkversionwarning, "')")))
+
root.mainloop()
root.destroy()