summaryrefslogtreecommitdiff
path: root/Lib/idlelib
diff options
context:
space:
mode:
authorKurt B. Kaiser <kbk@shore.net>2009-04-04 07:03:48 +0000
committerKurt B. Kaiser <kbk@shore.net>2009-04-04 07:03:48 +0000
commit027c1191496405748a80a2d6cd7ee1422d0c9d6c (patch)
tree5c72ffc6989303c03006e85511605155989698d0 /Lib/idlelib
parent82b6f1d3f471c545c35c90ec920cdd471e6f8a24 (diff)
downloadcpython-027c1191496405748a80a2d6cd7ee1422d0c9d6c.tar.gz
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.
Diffstat (limited to 'Lib/idlelib')
-rw-r--r--Lib/idlelib/NEWS.txt4
-rw-r--r--Lib/idlelib/PyShell.py47
-rw-r--r--Lib/idlelib/rpc.py2
3 files changed, 34 insertions, 19 deletions
diff --git a/Lib/idlelib/NEWS.txt b/Lib/idlelib/NEWS.txt
index b3095e6ad3..059ff1e452 100644
--- a/Lib/idlelib/NEWS.txt
+++ b/Lib/idlelib/NEWS.txt
@@ -3,6 +3,10 @@ What's New in IDLE 2.7a0?
*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
extract port from command line when warnings are present.
diff --git a/Lib/idlelib/PyShell.py b/Lib/idlelib/PyShell.py
index 7fec7e992f..a936c1777e 100644
--- a/Lib/idlelib/PyShell.py
+++ b/Lib/idlelib/PyShell.py
@@ -37,7 +37,8 @@ import Debugger
import RemoteDebugger
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:
from signal import SIGTERM
@@ -342,17 +343,21 @@ class ModifiedInterpreter(InteractiveInterpreter):
InteractiveInterpreter.__init__(self, locals=locals)
self.save_warnings_filters = None
self.restarting = False
- self.subprocess_arglist = self.build_subprocess_arglist()
+ self.subprocess_arglist = None
+ self.port = PORT
- port = 8833
rpcclt = None
rpcpid = None
def spawn_subprocess(self):
+ if self.subprocess_arglist == None:
+ self.subprocess_arglist = self.build_subprocess_arglist()
args = self.subprocess_arglist
self.rpcpid = os.spawnv(os.P_NOWAIT, sys.executable, args)
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')
@@ -373,11 +378,8 @@ class ModifiedInterpreter(InteractiveInterpreter):
return [decorated_exec] + w + ["-c", command, str(self.port)]
def start_subprocess(self):
- # spawning first avoids passing a listening socket to the subprocess
- self.spawn_subprocess()
- #time.sleep(20) # test to simulate GUI not accepting connection
- addr = (LOCALHOST, self.port)
- # Idle starts listening for connection on localhost
+ addr = (HOST, self.port)
+ # GUI makes several attempts to acquire socket, listens for connection
for i in range(3):
time.sleep(i)
try:
@@ -388,6 +390,18 @@ class ModifiedInterpreter(InteractiveInterpreter):
else:
self.display_port_binding_error()
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
self.rpcclt.listening_sock.settimeout(10)
try:
@@ -754,13 +768,12 @@ class ModifiedInterpreter(InteractiveInterpreter):
def display_port_binding_error(self):
tkMessageBox.showerror(
"Port Binding Error",
- "IDLE can't bind TCP/IP port 8833, which is necessary to "
- "communicate with its Python execution server. Either "
- "no networking is installed on this computer or another "
- "process (another IDLE?) is using the port. Run IDLE with the -n "
- "command line switch to start without a subprocess and refer to "
- "Help/IDLE Help 'Running without a subprocess' for further "
- "details.",
+ "IDLE can't bind to a TCP/IP port, which is necessary to "
+ "communicate with its Python execution server. This might be "
+ "because no networking is installed on this computer. "
+ "Run IDLE with the -n command line switch to start without a "
+ "subprocess and refer to Help/IDLE Help 'Running without a "
+ "subprocess' for further details.",
master=self.tkconsole.text)
def display_no_subprocess_error(self):
@@ -1300,7 +1313,7 @@ def main():
global flist, root, use_subprocess
use_subprocess = True
- enable_shell = False
+ enable_shell = True
enable_edit = False
debug = False
cmd = None
@@ -1321,6 +1334,7 @@ def main():
enable_shell = True
if o == '-e':
enable_edit = True
+ enable_shell = False
if o == '-h':
sys.stdout.write(usage_msg)
sys.exit()
@@ -1371,7 +1385,6 @@ def main():
edit_start = idleConf.GetOption('main', 'General',
'editor-on-startup', type='bool')
enable_edit = enable_edit or edit_start
- enable_shell = enable_shell or not edit_start
# start editor and/or shell windows:
root = Tk(className="Idle")
diff --git a/Lib/idlelib/rpc.py b/Lib/idlelib/rpc.py
index 3bac6a30b3..5adf32b384 100644
--- a/Lib/idlelib/rpc.py
+++ b/Lib/idlelib/rpc.py
@@ -518,8 +518,6 @@ class RPCClient(SocketIO):
def __init__(self, address, family=socket.AF_INET, type=socket.SOCK_STREAM):
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.listen(1)