comparison Lib/idlelib/PyShell.py @ 52849:a014dc47b552

Merged revisions 71126 via svnmerge from svn+ssh://pythondev@svn.python.org/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. ........
author Kurt B. Kaiser <kbk@shore.net>
date Sat, 04 Apr 2009 21:07:39 +0000
parents f138fbe2945e
children e63d4678fca7 e4a83e91521a
comparison
equal deleted inserted replaced
52848:5bc8cf3d90b3 52849:a014dc47b552
32 from idlelib import rpc 32 from idlelib import rpc
33 from idlelib import Debugger 33 from idlelib import Debugger
34 from idlelib import RemoteDebugger 34 from idlelib import RemoteDebugger
35 from idlelib import macosxSupport 35 from idlelib import macosxSupport
36 36
37 LOCALHOST = '127.0.0.1' 37 HOST = '127.0.0.1' # python execution server on localhost loopback
38 PORT = 0 # someday pass in host, port for remote debug capability
38 39
39 try: 40 try:
40 from signal import SIGTERM 41 from signal import SIGTERM
41 except ImportError: 42 except ImportError:
42 SIGTERM = 15 43 SIGTERM = 15
337 self.tkconsole = tkconsole 338 self.tkconsole = tkconsole
338 locals = sys.modules['__main__'].__dict__ 339 locals = sys.modules['__main__'].__dict__
339 InteractiveInterpreter.__init__(self, locals=locals) 340 InteractiveInterpreter.__init__(self, locals=locals)
340 self.save_warnings_filters = None 341 self.save_warnings_filters = None
341 self.restarting = False 342 self.restarting = False
342 self.subprocess_arglist = self.build_subprocess_arglist() 343 self.subprocess_arglist = None
343 344 self.port = PORT
344 port = 8833 345
345 rpcclt = None 346 rpcclt = None
346 rpcpid = None 347 rpcpid = None
347 348
348 def spawn_subprocess(self): 349 def spawn_subprocess(self):
350 if self.subprocess_arglist == None:
351 self.subprocess_arglist = self.build_subprocess_arglist()
349 args = self.subprocess_arglist 352 args = self.subprocess_arglist
350 self.rpcpid = os.spawnv(os.P_NOWAIT, sys.executable, args) 353 self.rpcpid = os.spawnv(os.P_NOWAIT, sys.executable, args)
351 354
352 def build_subprocess_arglist(self): 355 def build_subprocess_arglist(self):
356 assert (self.port!=0), (
357 "Socket should have been assigned a port number.")
353 w = ['-W' + s for s in sys.warnoptions] 358 w = ['-W' + s for s in sys.warnoptions]
354 # Maybe IDLE is installed and is being accessed via sys.path, 359 # Maybe IDLE is installed and is being accessed via sys.path,
355 # or maybe it's not installed and the idle.py script is being 360 # or maybe it's not installed and the idle.py script is being
356 # run from the IDLE source directory. 361 # run from the IDLE source directory.
357 del_exitf = idleConf.GetOption('main', 'General', 'delete-exitfunc', 362 del_exitf = idleConf.GetOption('main', 'General', 'delete-exitfunc',
366 else: 371 else:
367 decorated_exec = sys.executable 372 decorated_exec = sys.executable
368 return [decorated_exec] + w + ["-c", command, str(self.port)] 373 return [decorated_exec] + w + ["-c", command, str(self.port)]
369 374
370 def start_subprocess(self): 375 def start_subprocess(self):
371 # spawning first avoids passing a listening socket to the subprocess 376 addr = (HOST, self.port)
372 self.spawn_subprocess() 377 # GUI makes several attempts to acquire socket, listens for connection
373 #time.sleep(20) # test to simulate GUI not accepting connection
374 addr = (LOCALHOST, self.port)
375 # Idle starts listening for connection on localhost
376 for i in range(3): 378 for i in range(3):
377 time.sleep(i) 379 time.sleep(i)
378 try: 380 try:
379 self.rpcclt = MyRPCClient(addr) 381 self.rpcclt = MyRPCClient(addr)
380 break 382 break
381 except socket.error as err: 383 except socket.error as err:
382 pass 384 pass
383 else: 385 else:
384 self.display_port_binding_error() 386 self.display_port_binding_error()
385 return None 387 return None
388 # if PORT was 0, system will assign an 'ephemeral' port. Find it out:
389 self.port = self.rpcclt.listening_sock.getsockname()[1]
390 # if PORT was not 0, probably working with a remote execution server
391 if PORT != 0:
392 # To allow reconnection within the 2MSL wait (cf. Stevens TCP
393 # V1, 18.6), set SO_REUSEADDR. Note that this can be problematic
394 # on Windows since the implementation allows two active sockets on
395 # the same address!
396 self.rpcclt.listening_sock.setsockopt(socket.SOL_SOCKET,
397 socket.SO_REUSEADDR, 1)
398 self.spawn_subprocess()
399 #time.sleep(20) # test to simulate GUI not accepting connection
386 # Accept the connection from the Python execution server 400 # Accept the connection from the Python execution server
387 self.rpcclt.listening_sock.settimeout(10) 401 self.rpcclt.listening_sock.settimeout(10)
388 try: 402 try:
389 self.rpcclt.accept() 403 self.rpcclt.accept()
390 except socket.timeout as err: 404 except socket.timeout as err:
732 self.tkconsole.stderr.write(s) 746 self.tkconsole.stderr.write(s)
733 747
734 def display_port_binding_error(self): 748 def display_port_binding_error(self):
735 tkMessageBox.showerror( 749 tkMessageBox.showerror(
736 "Port Binding Error", 750 "Port Binding Error",
737 "IDLE can't bind TCP/IP port 8833, which is necessary to " 751 "IDLE can't bind to a TCP/IP port, which is necessary to "
738 "communicate with its Python execution server. Either " 752 "communicate with its Python execution server. This might be "
739 "no networking is installed on this computer or another " 753 "because no networking is installed on this computer. "
740 "process (another IDLE?) is using the port. Run IDLE with the -n " 754 "Run IDLE with the -n command line switch to start without a "
741 "command line switch to start without a subprocess and refer to " 755 "subprocess and refer to Help/IDLE Help 'Running without a "
742 "Help/IDLE Help 'Running without a subprocess' for further " 756 "subprocess' for further details.",
743 "details.",
744 master=self.tkconsole.text) 757 master=self.tkconsole.text)
745 758
746 def display_no_subprocess_error(self): 759 def display_no_subprocess_error(self):
747 tkMessageBox.showerror( 760 tkMessageBox.showerror(
748 "Subprocess Startup Error", 761 "Subprocess Startup Error",
1283 1296
1284 def main(): 1297 def main():
1285 global flist, root, use_subprocess 1298 global flist, root, use_subprocess
1286 1299
1287 use_subprocess = True 1300 use_subprocess = True
1288 enable_shell = False 1301 enable_shell = True
1289 enable_edit = False 1302 enable_edit = False
1290 debug = False 1303 debug = False
1291 cmd = None 1304 cmd = None
1292 script = None 1305 script = None
1293 startup = False 1306 startup = False
1304 if o == '-d': 1317 if o == '-d':
1305 debug = True 1318 debug = True
1306 enable_shell = True 1319 enable_shell = True
1307 if o == '-e': 1320 if o == '-e':
1308 enable_edit = True 1321 enable_edit = True
1322 enable_shell = False
1309 if o == '-h': 1323 if o == '-h':
1310 sys.stdout.write(usage_msg) 1324 sys.stdout.write(usage_msg)
1311 sys.exit() 1325 sys.exit()
1312 if o == '-i': 1326 if o == '-i':
1313 enable_shell = True 1327 enable_shell = True
1354 sys.path.insert(0, dir) 1368 sys.path.insert(0, dir)
1355 # check the IDLE settings configuration (but command line overrides) 1369 # check the IDLE settings configuration (but command line overrides)
1356 edit_start = idleConf.GetOption('main', 'General', 1370 edit_start = idleConf.GetOption('main', 'General',
1357 'editor-on-startup', type='bool') 1371 'editor-on-startup', type='bool')
1358 enable_edit = enable_edit or edit_start 1372 enable_edit = enable_edit or edit_start
1359 enable_shell = enable_shell or not edit_start
1360 # start editor and/or shell windows: 1373 # start editor and/or shell windows:
1361 root = Tk(className="Idle") 1374 root = Tk(className="Idle")
1362 1375
1363 fixwordbreaks(root) 1376 fixwordbreaks(root)
1364 root.withdraw() 1377 root.withdraw()