Skip to content

Commit

Permalink
Merged revisions 71126 via svnmerge from
Browse files Browse the repository at this point in the history
svn+ssh://[email protected]/python/trunk

........
  r71126 | kurt.kaiser | 2009-04-04 03:03:48 -0400 (Sat, 04 Apr 2009) | 5 lines

  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.
........
  • Loading branch information
kbkaiser committed Apr 4, 2009
1 parent 88f1435 commit e866c81
Show file tree
Hide file tree
Showing 3 changed files with 34 additions and 19 deletions.
4 changes: 4 additions & 0 deletions Lib/idlelib/NEWS.txt
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,10 @@ What's New in IDLE 3.1a1?

*Release date: XX-XXX-XXXX*

- 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.

Expand Down
47 changes: 30 additions & 17 deletions Lib/idlelib/PyShell.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,8 @@
from idlelib import RemoteDebugger
from idlelib import macosxSupport

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
Expand Down Expand Up @@ -339,17 +340,21 @@ def __init__(self, tkconsole):
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]
# Maybe IDLE is installed and is being accessed via sys.path,
# or maybe it's not installed and the idle.py script is being
Expand All @@ -368,11 +373,8 @@ def build_subprocess_arglist(self):
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:
Expand All @@ -383,6 +385,18 @@ def start_subprocess(self):
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:
Expand Down Expand Up @@ -734,13 +748,12 @@ def write(self, s):
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):
Expand Down Expand Up @@ -1285,7 +1298,7 @@ def main():
global flist, root, use_subprocess

use_subprocess = True
enable_shell = False
enable_shell = True
enable_edit = False
debug = False
cmd = None
Expand All @@ -1306,6 +1319,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()
Expand Down Expand Up @@ -1356,7 +1370,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")

Expand Down
2 changes: 0 additions & 2 deletions Lib/idlelib/rpc.py
Original file line number Diff line number Diff line change
Expand Up @@ -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)

Expand Down

0 comments on commit e866c81

Please sign in to comment.