summaryrefslogtreecommitdiffstats
path: root/Lib/idlelib/run.py
diff options
context:
space:
mode:
Diffstat (limited to 'Lib/idlelib/run.py')
-rw-r--r--Lib/idlelib/run.py408
1 files changed, 96 insertions, 312 deletions
diff --git a/Lib/idlelib/run.py b/Lib/idlelib/run.py
index 5bd84aa..518afab 100644
--- a/Lib/idlelib/run.py
+++ b/Lib/idlelib/run.py
@@ -1,56 +1,27 @@
-""" idlelib.run
-
-Simplified, pyshell.ModifiedInterpreter spawns a subprocess with
-f'''{sys.executable} -c "__import__('idlelib.run').run.main()"'''
-'.run' is needed because __import__ returns idlelib, not idlelib.run.
-"""
-import functools
-import io
-import linecache
-import queue
import sys
-import textwrap
+import linecache
import time
+import socket
import traceback
-import _thread as thread
+import thread
import threading
-import warnings
+import Queue
-from idlelib import autocomplete # AutoComplete, fetch_encodings
-from idlelib import calltip # Calltip
-from idlelib import debugger_r # start_debugger
-from idlelib import debugobj_r # remote_object_tree_item
-from idlelib import iomenu # encoding
-from idlelib import rpc # multiple objects
-from idlelib import stackviewer # StackTreeItem
-import __main__
+from idlelib import CallTips
+from idlelib import AutoComplete
-import tkinter # Use tcl and, if startup fails, messagebox.
-if not hasattr(sys.modules['idlelib.run'], 'firstrun'):
- # Undo modifications of tkinter by idlelib imports; see bpo-25507.
- for mod in ('simpledialog', 'messagebox', 'font',
- 'dialog', 'filedialog', 'commondialog',
- 'ttk'):
- delattr(tkinter, mod)
- del sys.modules['tkinter.' + mod]
- # Avoid AttributeError if run again; see bpo-37038.
- sys.modules['idlelib.run'].firstrun = False
-
-LOCALHOST = '127.0.0.1'
+from idlelib import RemoteDebugger
+from idlelib import RemoteObjectBrowser
+from idlelib import StackViewer
+from idlelib import rpc
+from idlelib import PyShell
+from idlelib import IOBinding
+import __main__
-def idle_formatwarning(message, category, filename, lineno, line=None):
- """Format warnings the IDLE way."""
+LOCALHOST = '127.0.0.1'
- s = "\nWarning (from warnings module):\n"
- s += ' File \"%s\", line %s\n' % (filename, lineno)
- 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)
- return s
+import warnings
def idle_showwarning_subproc(
message, category, filename, lineno, file=None, line=None):
@@ -61,9 +32,9 @@ def idle_showwarning_subproc(
if file is None:
file = sys.stderr
try:
- file.write(idle_formatwarning(
+ file.write(PyShell.idle_formatwarning(
message, category, filename, lineno, line))
- except OSError:
+ except IOError:
pass # the file (probably stderr) is invalid - this warning gets lost.
_warnings_showwarning = None
@@ -82,13 +53,6 @@ def capture_warnings(capture):
_warnings_showwarning = None
capture_warnings(True)
-tcl = tkinter.Tcl()
-
-def handle_tk_events(tcl=tcl):
- """Process any tk events that are ready to be dispatched if tkinter
- has been imported, a tcl interpreter has been created and tk has been
- loaded."""
- tcl.eval("update")
# Thread shared globals: Establish a queue between a subthread (which handles
# the socket) and the main thread (which runs user code), plus global
@@ -111,7 +75,7 @@ def main(del_exitfunc=False):
MyHandler object. That reference is saved as attribute rpchandler of the
Executive instance. The Executive methods have access to the reference and
can pass it on to entities that they command
- (e.g. debugger_r.Debugger.start_debugger()). The latter, in turn, can
+ (e.g. RemoteDebugger.Debugger.start_debugger()). The latter, in turn, can
call MyHandler(SocketIO) register/unregister methods via the reference to
register and unregister themselves.
@@ -125,8 +89,7 @@ def main(del_exitfunc=False):
assert(len(sys.argv) > 1)
port = int(sys.argv[-1])
except:
- print("IDLE Subprocess: no IP port passed in sys.argv.",
- file=sys.__stderr__)
+ print>>sys.stderr, "IDLE Subprocess: no IP port passed in sys.argv."
return
capture_warnings(True)
@@ -134,7 +97,7 @@ def main(del_exitfunc=False):
sockthread = threading.Thread(target=manage_socket,
name='SockThread',
args=((LOCALHOST, port),))
- sockthread.daemon = True
+ sockthread.setDaemon(True)
sockthread.start()
while 1:
try:
@@ -145,17 +108,12 @@ def main(del_exitfunc=False):
# exiting but got an extra KBI? Try again!
continue
try:
- request = rpc.request_queue.get(block=True, timeout=0.05)
- except queue.Empty:
- request = None
- # Issue 32207: calling handle_tk_events here adds spurious
- # queue.Empty traceback to event handling exceptions.
- if request:
- seq, (method, args, kwargs) = request
- ret = method(*args, **kwargs)
- rpc.response_queue.put((seq, ret))
- else:
- handle_tk_events()
+ seq, request = rpc.request_queue.get(block=True, timeout=0.05)
+ except Queue.Empty:
+ continue
+ method, args, kwargs = request
+ ret = method(*args, **kwargs)
+ rpc.response_queue.put((seq, ret))
except KeyboardInterrupt:
if quitting:
exit_now = True
@@ -181,33 +139,33 @@ def manage_socket(address):
try:
server = MyRPCServer(address, MyHandler)
break
- except OSError as err:
- print("IDLE Subprocess: OSError: " + err.args[1] +
- ", retrying....", file=sys.__stderr__)
- socket_error = err
+ except socket.error as err:
+ print>>sys.__stderr__,"IDLE Subprocess: socket error: "\
+ + err.args[1] + ", retrying...."
else:
- print("IDLE Subprocess: Connection to "
- "IDLE GUI failed, exiting.", file=sys.__stderr__)
- show_socket_error(socket_error, address)
+ print>>sys.__stderr__, "IDLE Subprocess: Connection to "\
+ "IDLE GUI failed, exiting."
+ show_socket_error(err, address)
global exit_now
exit_now = True
return
server.handle_request() # A single request only
def show_socket_error(err, address):
- "Display socket error from manage_socket."
- import tkinter
- from tkinter.messagebox import showerror
- root = tkinter.Tk()
+ import Tkinter
+ import tkMessageBox
+ root = Tkinter.Tk()
fix_scaling(root)
root.withdraw()
- showerror(
- "Subprocess Connection Error",
- f"IDLE's subprocess can't connect to {address[0]}:{address[1]}.\n"
- f"Fatal OSError #{err.errno}: {err.strerror}.\n"
- "See the 'Startup failure' section of the IDLE doc, online at\n"
- "https://docs.python.org/3/library/idle.html#startup-failure",
- parent=root)
+ if err.args[0] == 61: # connection refused
+ msg = "IDLE's subprocess can't connect to %s:%d. This may be due "\
+ "to your personal firewall configuration. It is safe to "\
+ "allow this internal connection because no data is visible on "\
+ "external ports." % address
+ tkMessageBox.showerror("IDLE Subprocess Error", msg, parent=root)
+ else:
+ tkMessageBox.showerror("IDLE Subprocess Error",
+ "Socket Error: %s" % err.args[1], parent=root)
root.destroy()
def print_exception():
@@ -217,34 +175,15 @@ def print_exception():
efile = sys.stderr
typ, val, tb = excinfo = sys.exc_info()
sys.last_type, sys.last_value, sys.last_traceback = excinfo
- seen = set()
-
- def print_exc(typ, exc, tb):
- seen.add(id(exc))
- context = exc.__context__
- cause = exc.__cause__
- if cause is not None and id(cause) not in seen:
- print_exc(type(cause), cause, cause.__traceback__)
- print("\nThe above exception was the direct cause "
- "of the following exception:\n", file=efile)
- elif (context is not None and
- not exc.__suppress_context__ and
- id(context) not in seen):
- print_exc(type(context), context, context.__traceback__)
- print("\nDuring handling of the above exception, "
- "another exception occurred:\n", file=efile)
- if tb:
- tbe = traceback.extract_tb(tb)
- print('Traceback (most recent call last):', file=efile)
- exclude = ("run.py", "rpc.py", "threading.py", "queue.py",
- "debugger_r.py", "bdb.py")
- cleanup_traceback(tbe, exclude)
- traceback.print_list(tbe, file=efile)
- lines = traceback.format_exception_only(typ, exc)
- for line in lines:
- print(line, end='', file=efile)
-
- print_exc(typ, val, tb)
+ tbe = traceback.extract_tb(tb)
+ print>>efile, '\nTraceback (most recent call last):'
+ exclude = ("run.py", "rpc.py", "threading.py", "Queue.py",
+ "RemoteDebugger.py", "bdb.py")
+ cleanup_traceback(tbe, exclude)
+ traceback.print_list(tbe, file=efile)
+ lines = traceback.format_exception_only(typ, val)
+ for line in lines:
+ print>>efile, line,
def cleanup_traceback(tb, exclude):
"Remove excluded traces from beginning/end of tb; get cached lines"
@@ -266,106 +205,53 @@ def cleanup_traceback(tb, exclude):
if len(tb) == 0:
# exception was in IDLE internals, don't prune!
tb[:] = orig_tb[:]
- print("** IDLE Internal Exception: ", file=sys.stderr)
+ print>>sys.stderr, "** IDLE Internal Exception: "
rpchandler = rpc.objecttable['exec'].rpchandler
for i in range(len(tb)):
fn, ln, nm, line = tb[i]
if nm == '?':
nm = "-toplevel-"
+ if fn.startswith("<pyshell#") and IOBinding.encoding != 'utf-8':
+ ln -= 1 # correction for coding cookie
if not line and fn.startswith("<pyshell#"):
line = rpchandler.remotecall('linecache', 'getline',
(fn, ln), {})
tb[i] = fn, ln, nm, line
def flush_stdout():
- """XXX How to do this now?"""
+ try:
+ if sys.stdout.softspace:
+ sys.stdout.softspace = 0
+ sys.stdout.write("\n")
+ except (AttributeError, EOFError):
+ pass
def exit():
- """Exit subprocess, possibly after first clearing exit functions.
+ """Exit subprocess, possibly after first deleting sys.exitfunc
If config-main.cfg/.def 'General' 'delete-exitfunc' is True, then any
- functions registered with atexit will be removed before exiting.
- (VPython support)
+ sys.exitfunc will be removed before exiting. (VPython support)
"""
if no_exitfunc:
- import atexit
- atexit._clear()
+ try:
+ del sys.exitfunc
+ except AttributeError:
+ pass
capture_warnings(False)
sys.exit(0)
def fix_scaling(root):
"""Scale fonts on HiDPI displays."""
- import tkinter.font
+ import tkFont
scaling = float(root.tk.call('tk', 'scaling'))
if scaling > 1.4:
- for name in tkinter.font.names(root):
- font = tkinter.font.Font(root=root, name=name, exists=True)
+ for name in tkFont.names(root):
+ font = tkFont.Font(root=root, name=name, exists=True)
size = int(font['size'])
if size < 0:
- font['size'] = round(-0.75*size)
-
-
-def fixdoc(fun, text):
- tem = (fun.__doc__ + '\n\n') if fun.__doc__ is not None else ''
- fun.__doc__ = tem + textwrap.fill(textwrap.dedent(text))
-
-RECURSIONLIMIT_DELTA = 30
-
-def install_recursionlimit_wrappers():
- """Install wrappers to always add 30 to the recursion limit."""
- # see: bpo-26806
-
- @functools.wraps(sys.setrecursionlimit)
- def setrecursionlimit(*args, **kwargs):
- # mimic the original sys.setrecursionlimit()'s input handling
- if kwargs:
- raise TypeError(
- "setrecursionlimit() takes no keyword arguments")
- try:
- limit, = args
- except ValueError:
- raise TypeError(f"setrecursionlimit() takes exactly one "
- f"argument ({len(args)} given)")
- if not limit > 0:
- raise ValueError(
- "recursion limit must be greater or equal than 1")
-
- return setrecursionlimit.__wrapped__(limit + RECURSIONLIMIT_DELTA)
-
- fixdoc(setrecursionlimit, f"""\
- This IDLE wrapper adds {RECURSIONLIMIT_DELTA} to prevent possible
- uninterruptible loops.""")
-
- @functools.wraps(sys.getrecursionlimit)
- def getrecursionlimit():
- return getrecursionlimit.__wrapped__() - RECURSIONLIMIT_DELTA
-
- fixdoc(getrecursionlimit, f"""\
- This IDLE wrapper subtracts {RECURSIONLIMIT_DELTA} to compensate
- for the {RECURSIONLIMIT_DELTA} IDLE adds when setting the limit.""")
-
- # add the delta to the default recursion limit, to compensate
- sys.setrecursionlimit(sys.getrecursionlimit() + RECURSIONLIMIT_DELTA)
-
- sys.setrecursionlimit = setrecursionlimit
- sys.getrecursionlimit = getrecursionlimit
-
-
-def uninstall_recursionlimit_wrappers():
- """Uninstall the recursion limit wrappers from the sys module.
-
- IDLE only uses this for tests. Users can import run and call
- this to remove the wrapping.
- """
- if (
- getattr(sys.setrecursionlimit, '__wrapped__', None) and
- getattr(sys.getrecursionlimit, '__wrapped__', None)
- ):
- sys.setrecursionlimit = sys.setrecursionlimit.__wrapped__
- sys.getrecursionlimit = sys.getrecursionlimit.__wrapped__
- sys.setrecursionlimit(sys.getrecursionlimit() - RECURSIONLIMIT_DELTA)
+ font['size'] = int(round(-0.75*size))
class MyRPCServer(rpc.RPCServer):
@@ -387,105 +273,17 @@ class MyRPCServer(rpc.RPCServer):
thread.interrupt_main()
except:
erf = sys.__stderr__
- print('\n' + '-'*40, file=erf)
- print('Unhandled server exception!', file=erf)
- print('Thread: %s' % threading.current_thread().name, file=erf)
- print('Client Address: ', client_address, file=erf)
- print('Request: ', repr(request), file=erf)
+ print>>erf, '\n' + '-'*40
+ print>>erf, 'Unhandled server exception!'
+ print>>erf, 'Thread: %s' % threading.currentThread().getName()
+ print>>erf, 'Client Address: ', client_address
+ print>>erf, 'Request: ', repr(request)
traceback.print_exc(file=erf)
- print('\n*** Unrecoverable, server exiting!', file=erf)
- print('-'*40, file=erf)
+ print>>erf, '\n*** Unrecoverable, server exiting!'
+ print>>erf, '-'*40
quitting = True
thread.interrupt_main()
-
-# Pseudofiles for shell-remote communication (also used in pyshell)
-
-class StdioFile(io.TextIOBase):
-
- def __init__(self, shell, tags, encoding='utf-8', errors='strict'):
- self.shell = shell
- self.tags = tags
- self._encoding = encoding
- self._errors = errors
-
- @property
- def encoding(self):
- return self._encoding
-
- @property
- def errors(self):
- return self._errors
-
- @property
- def name(self):
- return '<%s>' % self.tags
-
- def isatty(self):
- return True
-
-
-class StdOutputFile(StdioFile):
-
- def writable(self):
- return True
-
- def write(self, s):
- if self.closed:
- raise ValueError("write to closed file")
- s = str.encode(s, self.encoding, self.errors).decode(self.encoding, self.errors)
- return self.shell.write(s, self.tags)
-
-
-class StdInputFile(StdioFile):
- _line_buffer = ''
-
- def readable(self):
- return True
-
- def read(self, size=-1):
- if self.closed:
- raise ValueError("read from closed file")
- if size is None:
- size = -1
- elif not isinstance(size, int):
- raise TypeError('must be int, not ' + type(size).__name__)
- result = self._line_buffer
- self._line_buffer = ''
- if size < 0:
- while True:
- line = self.shell.readline()
- if not line: break
- result += line
- else:
- while len(result) < size:
- line = self.shell.readline()
- if not line: break
- result += line
- self._line_buffer = result[size:]
- result = result[:size]
- return result
-
- def readline(self, size=-1):
- if self.closed:
- raise ValueError("read from closed file")
- if size is None:
- size = -1
- elif not isinstance(size, int):
- raise TypeError('must be int, not ' + type(size).__name__)
- line = self._line_buffer or self.shell.readline()
- if size < 0:
- size = len(line)
- eol = line.find('\n', 0, size)
- if eol >= 0:
- size = eol + 1
- self._line_buffer = line[size:]
- return line[:size]
-
- def close(self):
- self.shell.close()
-
-
class MyHandler(rpc.RPCHandler):
def handle(self):
@@ -493,24 +291,17 @@ class MyHandler(rpc.RPCHandler):
executive = Executive(self)
self.register("exec", executive)
self.console = self.get_remote_proxy("console")
- sys.stdin = StdInputFile(self.console, "stdin",
- iomenu.encoding, iomenu.errors)
- sys.stdout = StdOutputFile(self.console, "stdout",
- iomenu.encoding, iomenu.errors)
- sys.stderr = StdOutputFile(self.console, "stderr",
- iomenu.encoding, "backslashreplace")
-
- sys.displayhook = rpc.displayhook
- # page help() text to shell.
- import pydoc # import must be done here to capture i/o binding
- pydoc.pager = pydoc.plainpager
+ sys.stdin = PyShell.PseudoInputFile(self.console, "stdin",
+ IOBinding.encoding)
+ sys.stdout = PyShell.PseudoOutputFile(self.console, "stdout",
+ IOBinding.encoding)
+ sys.stderr = PyShell.PseudoOutputFile(self.console, "stderr",
+ IOBinding.encoding)
# Keep a reference to stdin so that it won't try to exit IDLE if
# sys.stdin gets changed from within IDLE's shell. See issue17838.
self._keep_stdin = sys.stdin
- install_recursionlimit_wrappers()
-
self.interp = self.get_remote_proxy("interp")
rpc.RPCHandler.getresponse(self, myseq=None, wait=0.05)
@@ -536,8 +327,8 @@ class Executive(object):
def __init__(self, rpchandler):
self.rpchandler = rpchandler
self.locals = __main__.__dict__
- self.calltip = calltip.Calltip()
- self.autocomplete = autocomplete.AutoComplete()
+ self.calltip = CallTips.CallTips()
+ self.autocomplete = AutoComplete.AutoComplete()
def runcode(self, code):
global interruptable
@@ -545,15 +336,13 @@ class Executive(object):
self.usr_exc_info = None
interruptable = True
try:
- exec(code, self.locals)
+ exec code in self.locals
finally:
interruptable = False
- except SystemExit as e:
- if e.args: # SystemExit called with an argument.
- ob = e.args[0]
- if not isinstance(ob, (type(None), int)):
- print('SystemExit: ' + str(ob), file=sys.stderr)
- # Return to the interactive prompt.
+ except SystemExit:
+ # Scripts that raise SystemExit should just
+ # return to the interactive prompt
+ pass
except:
self.usr_exc_info = sys.exc_info()
if quitting:
@@ -570,7 +359,7 @@ class Executive(object):
thread.interrupt_main()
def start_the_debugger(self, gui_adap_oid):
- return debugger_r.start_debugger(self.rpchandler, gui_adap_oid)
+ return RemoteDebugger.start_debugger(self.rpchandler, gui_adap_oid)
def stop_the_debugger(self, idb_adap_oid):
"Unregister the Idb Adapter. Link objects and Idb then subject to GC"
@@ -594,12 +383,7 @@ class Executive(object):
tb = tb.tb_next
sys.last_type = typ
sys.last_value = val
- item = stackviewer.StackTreeItem(flist, tb)
- return debugobj_r.remote_object_tree_item(item)
-
-
-if __name__ == '__main__':
- from unittest import main
- main('idlelib.idle_test.test_run', verbosity=2)
+ item = StackViewer.StackTreeItem(flist, tb)
+ return RemoteObjectBrowser.remote_object_tree_item(item)
-capture_warnings(False) # Make sure turned off; see bpo-18081.
+capture_warnings(False) # Make sure turned off; see issue 18081