mirror of
https://github.com/python/cpython.git
synced 2025-07-19 09:15:34 +00:00
Initial revision
This commit is contained in:
parent
33a6da9971
commit
7aced17437
73 changed files with 12383 additions and 0 deletions
198
Lib/idlelib/ExecBinding.py
Normal file
198
Lib/idlelib/ExecBinding.py
Normal file
|
@ -0,0 +1,198 @@
|
|||
"""Extension to execute a script in a separate process
|
||||
|
||||
David Scherer <dscherer@cmu.edu>
|
||||
|
||||
The ExecBinding module, a replacement for ScriptBinding, executes
|
||||
programs in a separate process. Unlike previous versions, this version
|
||||
communicates with the user process via an RPC protocol (see the 'protocol'
|
||||
module). The user program is loaded by the 'loader' and 'Remote'
|
||||
modules. Its standard output and input are directed back to the
|
||||
ExecBinding class through the RPC mechanism and implemented here.
|
||||
|
||||
A "stop program" command is provided and bound to control-break. Closing
|
||||
the output window also stops the running program.
|
||||
"""
|
||||
|
||||
import sys
|
||||
import os
|
||||
import imp
|
||||
import OutputWindow
|
||||
import protocol
|
||||
import spawn
|
||||
import traceback
|
||||
import tempfile
|
||||
|
||||
# Find Python and the loader. This should be done as early in execution
|
||||
# as possible, because if the current directory or sys.path is changed
|
||||
# it may no longer be possible to get correct paths for these things.
|
||||
|
||||
pyth_exe = spawn.hardpath( sys.executable )
|
||||
load_py = spawn.hardpath( imp.find_module("loader")[1] )
|
||||
|
||||
# The following mechanism matches loaders up with ExecBindings that are
|
||||
# trying to load something.
|
||||
|
||||
waiting_for_loader = []
|
||||
|
||||
def loader_connect(client, addr):
|
||||
if waiting_for_loader:
|
||||
a = waiting_for_loader.pop(0)
|
||||
try:
|
||||
return a.connect(client, addr)
|
||||
except:
|
||||
return loader_connect(client,addr)
|
||||
|
||||
protocol.publish('ExecBinding', loader_connect)
|
||||
|
||||
class ExecBinding:
|
||||
keydefs = {
|
||||
'<<run-complete-script>>': ['<F5>'],
|
||||
'<<stop-execution>>': ['<Cancel>'], #'<Control-c>'
|
||||
}
|
||||
|
||||
menudefs = [
|
||||
('run', [None,
|
||||
('Run program', '<<run-complete-script>>'),
|
||||
('Stop program', '<<stop-execution>>'),
|
||||
]
|
||||
),
|
||||
]
|
||||
|
||||
delegate = 1
|
||||
|
||||
def __init__(self, editwin):
|
||||
self.editwin = editwin
|
||||
self.client = None
|
||||
self.temp = []
|
||||
|
||||
if not hasattr(editwin, 'source_window'):
|
||||
self.delegate = 0
|
||||
self.output = OutputWindow.OnDemandOutputWindow(editwin.flist)
|
||||
self.output.close_hook = self.stopProgram
|
||||
self.output.source_window = editwin
|
||||
else:
|
||||
if (self.editwin.source_window and
|
||||
self.editwin.source_window.extensions.has_key('ExecBinding') and
|
||||
not self.editwin.source_window.extensions['ExecBinding'].delegate):
|
||||
delegate = self.editwin.source_window.extensions['ExecBinding']
|
||||
self.run_complete_script_event = delegate.run_complete_script_event
|
||||
self.stop_execution_event = delegate.stop_execution_event
|
||||
|
||||
def __del__(self):
|
||||
self.stopProgram()
|
||||
|
||||
def stop_execution_event(self, event):
|
||||
if self.client:
|
||||
self.stopProgram()
|
||||
self.write('\nProgram stopped.\n','stderr')
|
||||
|
||||
def run_complete_script_event(self, event):
|
||||
filename = self.getfilename()
|
||||
if not filename: return
|
||||
filename = os.path.abspath(filename)
|
||||
|
||||
self.stopProgram()
|
||||
|
||||
self.commands = [ ('run', filename) ]
|
||||
waiting_for_loader.append(self)
|
||||
spawn.spawn( pyth_exe, load_py )
|
||||
|
||||
def connect(self, client, addr):
|
||||
# Called by loader_connect() above. It is remotely possible that
|
||||
# we get connected to two loaders if the user is running the
|
||||
# program repeatedly in a short span of time. In this case, we
|
||||
# simply return None, refusing to connect and letting the redundant
|
||||
# loader die.
|
||||
if self.client: return None
|
||||
|
||||
self.client = client
|
||||
client.set_close_hook( self.connect_lost )
|
||||
|
||||
title = self.editwin.short_title()
|
||||
if title:
|
||||
self.output.set_title(title + " Output")
|
||||
else:
|
||||
self.output.set_title("Output")
|
||||
self.output.write('\n',"stderr")
|
||||
self.output.scroll_clear()
|
||||
|
||||
return self
|
||||
|
||||
def connect_lost(self):
|
||||
# Called by the client's close hook when the loader closes its
|
||||
# socket.
|
||||
|
||||
# We print a disconnect message only if the output window is already
|
||||
# open.
|
||||
if self.output.owin and self.output.owin.text:
|
||||
self.output.owin.interrupt()
|
||||
self.output.write("\nProgram disconnected.\n","stderr")
|
||||
|
||||
for t in self.temp:
|
||||
try:
|
||||
os.remove(t)
|
||||
except:
|
||||
pass
|
||||
self.temp = []
|
||||
self.client = None
|
||||
|
||||
def get_command(self):
|
||||
# Called by Remote to find out what it should be executing.
|
||||
# Later this will be used to implement debugging, interactivity, etc.
|
||||
if self.commands:
|
||||
return self.commands.pop(0)
|
||||
return ('finish',)
|
||||
|
||||
def program_exception(self, type, value, tb, first, last):
|
||||
if type == SystemExit: return 0
|
||||
|
||||
for i in range(len(tb)):
|
||||
filename, lineno, name, line = tb[i]
|
||||
if filename in self.temp:
|
||||
filename = 'Untitled'
|
||||
tb[i] = filename, lineno, name, line
|
||||
|
||||
list = traceback.format_list(tb[first:last])
|
||||
exc = traceback.format_exception_only( type, value )
|
||||
|
||||
self.write('Traceback (innermost last)\n', 'stderr')
|
||||
for i in (list+exc):
|
||||
self.write(i, 'stderr')
|
||||
|
||||
self.commands = []
|
||||
return 1
|
||||
|
||||
def write(self, text, tag):
|
||||
self.output.write(text,tag)
|
||||
|
||||
def readline(self):
|
||||
return self.output.readline()
|
||||
|
||||
def stopProgram(self):
|
||||
if self.client:
|
||||
self.client.close()
|
||||
self.client = None
|
||||
|
||||
def getfilename(self):
|
||||
# Save all files which have been named, because they might be modules
|
||||
for edit in self.editwin.flist.inversedict.keys():
|
||||
if edit.io and edit.io.filename and not edit.get_saved():
|
||||
edit.io.save(None)
|
||||
|
||||
# Experimental: execute unnamed buffer
|
||||
if not self.editwin.io.filename:
|
||||
filename = os.path.normcase(os.path.abspath(tempfile.mktemp()))
|
||||
self.temp.append(filename)
|
||||
if self.editwin.io.writefile(filename):
|
||||
return filename
|
||||
|
||||
# If the file isn't save, we save it. If it doesn't have a filename,
|
||||
# the user will be prompted.
|
||||
if self.editwin.io and not self.editwin.get_saved():
|
||||
self.editwin.io.save(None)
|
||||
|
||||
# If the file *still* isn't saved, we give up.
|
||||
if not self.editwin.get_saved():
|
||||
return
|
||||
|
||||
return self.editwin.io.filename
|
Loading…
Add table
Add a link
Reference in a new issue