From 34eefb9b463f6229dc21a8d4655665aaabca4aa7 2011-08-17 06:26:47
From: MinRK <benjaminrk@gmail.com>
Date: 2011-08-17 06:26:47
Subject: [PATCH] Remove IPython dependency in external.ssh

copy parallel.util.select_random_ports into external.ssh.tunnel

This lets external.ssh be moved to another project without IPython, only changing the pexpect import.

This also resolves a circular import in the qtconsole

---

diff --git a/IPython/external/ssh/tunnel.py b/IPython/external/ssh/tunnel.py
index 871b557..746a513 100644
--- a/IPython/external/ssh/tunnel.py
+++ b/IPython/external/ssh/tunnel.py
@@ -16,6 +16,7 @@
 from __future__ import print_function
 
 import os,sys, atexit
+import socket
 from multiprocessing import Process
 from getpass import getpass, getuser
 import warnings
@@ -34,12 +35,32 @@ try:
 except ImportError:
     pexpect = None
 
-from IPython.parallel.util import select_random_ports
-
 #-----------------------------------------------------------------------------
 # Code
 #-----------------------------------------------------------------------------
 
+# select_random_ports copied from IPython.parallel.util
+_random_ports = set()
+
+def select_random_ports(n):
+    """Selects and return n random ports that are available."""
+    ports = []
+    for i in xrange(n):
+        sock = socket.socket()
+        sock.bind(('', 0))
+        while sock.getsockname()[1] in _random_ports:
+            sock.close()
+            sock = socket.socket()
+            sock.bind(('', 0))
+        ports.append(sock)
+    for i, sock in enumerate(ports):
+        port = sock.getsockname()[1]
+        sock.close()
+        ports[i] = port
+        _random_ports.add(port)
+    return ports
+
+
 #-----------------------------------------------------------------------------
 # Check for passwordless login
 #-----------------------------------------------------------------------------
diff --git a/IPython/frontend/qt/console/qtconsoleapp.py b/IPython/frontend/qt/console/qtconsoleapp.py
index 3c9e098..156d3d3 100644
--- a/IPython/frontend/qt/console/qtconsoleapp.py
+++ b/IPython/frontend/qt/console/qtconsoleapp.py
@@ -26,7 +26,9 @@ from getpass import getpass
 from IPython.external.qt import QtGui
 from pygments.styles import get_all_styles
 
-# from IPython.external.ssh import tunnel
+# external imports
+from IPython.external.ssh import tunnel
+
 # Local imports
 from IPython.config.application import boolean_flag
 from IPython.core.application import BaseIPythonApplication
@@ -334,8 +336,7 @@ class IPythonQtConsoleApp(BaseIPythonApplication):
                     self.kernel_argv.remove(a)
     
     def init_ssh(self):
-        # import here, to prevent circular import
-        from IPython.external.ssh import tunnel
+        """set up ssh tunnels, if needed."""
         if not self.sshserver and not self.sshkey:
             return