mirror of
https://github.com/python/cpython.git
synced 2025-09-02 06:57:58 +00:00
Allow multiple IDLE GUI/subprocess pairs to exist
simultaneously. Thanks to David Scherer for suggesting the use of an ephemeral port for the GUI. Patch 1529142 Weeble.
This commit is contained in:
parent
195374e836
commit
013d6cc0df
3 changed files with 34 additions and 19 deletions
|
@ -3,6 +3,10 @@ What's New in IDLE 2.7a0?
|
||||||
|
|
||||||
*Release date: XX-XXX-2009*
|
*Release date: XX-XXX-2009*
|
||||||
|
|
||||||
|
- Allow multiple IDLE GUI/subprocess pairs to exist simultaneously. Thanks to
|
||||||
|
David Scherer for suggesting the use of an ephemeral port for the GUI.
|
||||||
|
Patch 1529142 Weeble.
|
||||||
|
|
||||||
- Remove port spec from run.py and fix bug where subprocess fails to
|
- Remove port spec from run.py and fix bug where subprocess fails to
|
||||||
extract port from command line when warnings are present.
|
extract port from command line when warnings are present.
|
||||||
|
|
||||||
|
|
|
@ -37,7 +37,8 @@ import Debugger
|
||||||
import RemoteDebugger
|
import RemoteDebugger
|
||||||
|
|
||||||
IDENTCHARS = string.ascii_letters + string.digits + "_"
|
IDENTCHARS = string.ascii_letters + string.digits + "_"
|
||||||
LOCALHOST = '127.0.0.1'
|
HOST = '127.0.0.1' # python execution server on localhost loopback
|
||||||
|
PORT = 0 # someday pass in host, port for remote debug capability
|
||||||
|
|
||||||
try:
|
try:
|
||||||
from signal import SIGTERM
|
from signal import SIGTERM
|
||||||
|
@ -342,17 +343,21 @@ class ModifiedInterpreter(InteractiveInterpreter):
|
||||||
InteractiveInterpreter.__init__(self, locals=locals)
|
InteractiveInterpreter.__init__(self, locals=locals)
|
||||||
self.save_warnings_filters = None
|
self.save_warnings_filters = None
|
||||||
self.restarting = False
|
self.restarting = False
|
||||||
self.subprocess_arglist = self.build_subprocess_arglist()
|
self.subprocess_arglist = None
|
||||||
|
self.port = PORT
|
||||||
|
|
||||||
port = 8833
|
|
||||||
rpcclt = None
|
rpcclt = None
|
||||||
rpcpid = None
|
rpcpid = None
|
||||||
|
|
||||||
def spawn_subprocess(self):
|
def spawn_subprocess(self):
|
||||||
|
if self.subprocess_arglist == None:
|
||||||
|
self.subprocess_arglist = self.build_subprocess_arglist()
|
||||||
args = self.subprocess_arglist
|
args = self.subprocess_arglist
|
||||||
self.rpcpid = os.spawnv(os.P_NOWAIT, sys.executable, args)
|
self.rpcpid = os.spawnv(os.P_NOWAIT, sys.executable, args)
|
||||||
|
|
||||||
def build_subprocess_arglist(self):
|
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]
|
w = ['-W' + s for s in sys.warnoptions]
|
||||||
if 1/2 > 0: # account for new division
|
if 1/2 > 0: # account for new division
|
||||||
w.append('-Qnew')
|
w.append('-Qnew')
|
||||||
|
@ -373,11 +378,8 @@ class ModifiedInterpreter(InteractiveInterpreter):
|
||||||
return [decorated_exec] + w + ["-c", command, str(self.port)]
|
return [decorated_exec] + w + ["-c", command, str(self.port)]
|
||||||
|
|
||||||
def start_subprocess(self):
|
def start_subprocess(self):
|
||||||
# spawning first avoids passing a listening socket to the subprocess
|
addr = (HOST, self.port)
|
||||||
self.spawn_subprocess()
|
# GUI makes several attempts to acquire socket, listens for connection
|
||||||
#time.sleep(20) # test to simulate GUI not accepting connection
|
|
||||||
addr = (LOCALHOST, self.port)
|
|
||||||
# Idle starts listening for connection on localhost
|
|
||||||
for i in range(3):
|
for i in range(3):
|
||||||
time.sleep(i)
|
time.sleep(i)
|
||||||
try:
|
try:
|
||||||
|
@ -388,6 +390,18 @@ class ModifiedInterpreter(InteractiveInterpreter):
|
||||||
else:
|
else:
|
||||||
self.display_port_binding_error()
|
self.display_port_binding_error()
|
||||||
return None
|
return None
|
||||||
|
# if PORT was 0, system will assign an 'ephemeral' port. Find it out:
|
||||||
|
self.port = self.rpcclt.listening_sock.getsockname()[1]
|
||||||
|
# if PORT was not 0, probably working with a remote execution server
|
||||||
|
if PORT != 0:
|
||||||
|
# To allow reconnection within the 2MSL wait (cf. Stevens TCP
|
||||||
|
# V1, 18.6), set SO_REUSEADDR. Note that this can be problematic
|
||||||
|
# on Windows since the implementation allows two active sockets on
|
||||||
|
# the same address!
|
||||||
|
self.rpcclt.listening_sock.setsockopt(socket.SOL_SOCKET,
|
||||||
|
socket.SO_REUSEADDR, 1)
|
||||||
|
self.spawn_subprocess()
|
||||||
|
#time.sleep(20) # test to simulate GUI not accepting connection
|
||||||
# Accept the connection from the Python execution server
|
# Accept the connection from the Python execution server
|
||||||
self.rpcclt.listening_sock.settimeout(10)
|
self.rpcclt.listening_sock.settimeout(10)
|
||||||
try:
|
try:
|
||||||
|
@ -754,13 +768,12 @@ class ModifiedInterpreter(InteractiveInterpreter):
|
||||||
def display_port_binding_error(self):
|
def display_port_binding_error(self):
|
||||||
tkMessageBox.showerror(
|
tkMessageBox.showerror(
|
||||||
"Port Binding Error",
|
"Port Binding Error",
|
||||||
"IDLE can't bind TCP/IP port 8833, which is necessary to "
|
"IDLE can't bind to a TCP/IP port, which is necessary to "
|
||||||
"communicate with its Python execution server. Either "
|
"communicate with its Python execution server. This might be "
|
||||||
"no networking is installed on this computer or another "
|
"because no networking is installed on this computer. "
|
||||||
"process (another IDLE?) is using the port. Run IDLE with the -n "
|
"Run IDLE with the -n command line switch to start without a "
|
||||||
"command line switch to start without a subprocess and refer to "
|
"subprocess and refer to Help/IDLE Help 'Running without a "
|
||||||
"Help/IDLE Help 'Running without a subprocess' for further "
|
"subprocess' for further details.",
|
||||||
"details.",
|
|
||||||
master=self.tkconsole.text)
|
master=self.tkconsole.text)
|
||||||
|
|
||||||
def display_no_subprocess_error(self):
|
def display_no_subprocess_error(self):
|
||||||
|
@ -1300,7 +1313,7 @@ def main():
|
||||||
global flist, root, use_subprocess
|
global flist, root, use_subprocess
|
||||||
|
|
||||||
use_subprocess = True
|
use_subprocess = True
|
||||||
enable_shell = False
|
enable_shell = True
|
||||||
enable_edit = False
|
enable_edit = False
|
||||||
debug = False
|
debug = False
|
||||||
cmd = None
|
cmd = None
|
||||||
|
@ -1321,6 +1334,7 @@ def main():
|
||||||
enable_shell = True
|
enable_shell = True
|
||||||
if o == '-e':
|
if o == '-e':
|
||||||
enable_edit = True
|
enable_edit = True
|
||||||
|
enable_shell = False
|
||||||
if o == '-h':
|
if o == '-h':
|
||||||
sys.stdout.write(usage_msg)
|
sys.stdout.write(usage_msg)
|
||||||
sys.exit()
|
sys.exit()
|
||||||
|
@ -1371,7 +1385,6 @@ def main():
|
||||||
edit_start = idleConf.GetOption('main', 'General',
|
edit_start = idleConf.GetOption('main', 'General',
|
||||||
'editor-on-startup', type='bool')
|
'editor-on-startup', type='bool')
|
||||||
enable_edit = enable_edit or edit_start
|
enable_edit = enable_edit or edit_start
|
||||||
enable_shell = enable_shell or not edit_start
|
|
||||||
# start editor and/or shell windows:
|
# start editor and/or shell windows:
|
||||||
root = Tk(className="Idle")
|
root = Tk(className="Idle")
|
||||||
|
|
||||||
|
|
|
@ -518,8 +518,6 @@ class RPCClient(SocketIO):
|
||||||
|
|
||||||
def __init__(self, address, family=socket.AF_INET, type=socket.SOCK_STREAM):
|
def __init__(self, address, family=socket.AF_INET, type=socket.SOCK_STREAM):
|
||||||
self.listening_sock = socket.socket(family, type)
|
self.listening_sock = socket.socket(family, type)
|
||||||
self.listening_sock.setsockopt(socket.SOL_SOCKET,
|
|
||||||
socket.SO_REUSEADDR, 1)
|
|
||||||
self.listening_sock.bind(address)
|
self.listening_sock.bind(address)
|
||||||
self.listening_sock.listen(1)
|
self.listening_sock.listen(1)
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue