##// END OF EJS Templates
fix a few remaining KernelApp/IPKernelApp changes
MinRK -
Show More
@@ -1,85 +1,85 b''
1 1 # encoding: utf-8
2 2 """
3 3 IPython: tools for interactive and parallel computing in Python.
4 4
5 5 http://ipython.org
6 6 """
7 7 #-----------------------------------------------------------------------------
8 8 # Copyright (c) 2008-2011, IPython Development Team.
9 9 # Copyright (c) 2001-2007, Fernando Perez <fernando.perez@colorado.edu>
10 10 # Copyright (c) 2001, Janko Hauser <jhauser@zscout.de>
11 11 # Copyright (c) 2001, Nathaniel Gray <n8gray@caltech.edu>
12 12 #
13 13 # Distributed under the terms of the Modified BSD License.
14 14 #
15 15 # The full license is in the file COPYING.txt, distributed with this software.
16 16 #-----------------------------------------------------------------------------
17 17
18 18 #-----------------------------------------------------------------------------
19 19 # Imports
20 20 #-----------------------------------------------------------------------------
21 21 from __future__ import absolute_import
22 22
23 23 import os
24 24 import sys
25 25
26 26 #-----------------------------------------------------------------------------
27 27 # Setup everything
28 28 #-----------------------------------------------------------------------------
29 29
30 30 # Don't forget to also update setup.py when this changes!
31 31 if sys.version[0:3] < '2.6':
32 32 raise ImportError('Python Version 2.6 or above is required for IPython.')
33 33
34 34 # Make it easy to import extensions - they are always directly on pythonpath.
35 35 # Therefore, non-IPython modules can be added to extensions directory.
36 36 # This should probably be in ipapp.py.
37 37 sys.path.append(os.path.join(os.path.dirname(__file__), "extensions"))
38 38
39 39 #-----------------------------------------------------------------------------
40 40 # Setup the top level names
41 41 #-----------------------------------------------------------------------------
42 42
43 43 from .config.loader import Config
44 44 from .core import release
45 45 from .core.application import Application
46 46 from .frontend.terminal.embed import embed
47 47
48 48 from .core.error import TryNext
49 49 from .core.interactiveshell import InteractiveShell
50 50 from .testing import test
51 51 from .utils.sysinfo import sys_info
52 52 from .utils.frame import extract_module_locals
53 53
54 54 # Release data
55 55 __author__ = '%s <%s>' % (release.author, release.author_email)
56 56 __license__ = release.license
57 57 __version__ = release.version
58 58 version_info = release.version_info
59 59
60 60 def embed_kernel(module=None, local_ns=None, **kwargs):
61 61 """Embed and start an IPython kernel in a given scope.
62 62
63 63 Parameters
64 64 ----------
65 65 module : ModuleType, optional
66 66 The module to load into IPython globals (default: caller)
67 67 local_ns : dict, optional
68 68 The namespace to load into IPython user namespace (default: caller)
69 69
70 70 kwargs : various, optional
71 Further keyword args are relayed to the KernelApp constructor,
71 Further keyword args are relayed to the IPKernelApp constructor,
72 72 allowing configuration of the Kernel. Will only have an effect
73 73 on the first embed_kernel call for a given process.
74 74
75 75 """
76 76
77 77 (caller_module, caller_locals) = extract_module_locals(1)
78 78 if module is None:
79 79 module = caller_module
80 80 if local_ns is None:
81 81 local_ns = caller_locals
82 82
83 83 # Only import .zmq when we really need it
84 84 from IPython.kernel.zmq.embed import embed_kernel as real_embed_kernel
85 85 real_embed_kernel(module=module, local_ns=local_ns, **kwargs)
@@ -1,362 +1,362 b''
1 1 """ A minimal application base mixin for all ZMQ based IPython frontends.
2 2
3 3 This is not a complete console app, as subprocess will not be able to receive
4 4 input, there is no real readline support, among other limitations. This is a
5 5 refactoring of what used to be the IPython/frontend/qt/console/qtconsoleapp.py
6 6
7 7 Authors:
8 8
9 9 * Evan Patterson
10 10 * Min RK
11 11 * Erik Tollerud
12 12 * Fernando Perez
13 13 * Bussonnier Matthias
14 14 * Thomas Kluyver
15 15 * Paul Ivanov
16 16
17 17 """
18 18
19 19 #-----------------------------------------------------------------------------
20 20 # Imports
21 21 #-----------------------------------------------------------------------------
22 22
23 23 # stdlib imports
24 24 import atexit
25 25 import json
26 26 import os
27 27 import shutil
28 28 import signal
29 29 import sys
30 30 import uuid
31 31
32 32
33 33 # Local imports
34 34 from IPython.config.application import boolean_flag
35 35 from IPython.config.configurable import Configurable
36 36 from IPython.core.profiledir import ProfileDir
37 37 from IPython.kernel.blockingkernelmanager import BlockingKernelManager
38 38 from IPython.kernel.kernelmanager import KernelManager
39 39 from IPython.kernel import tunnel_to_kernel, find_connection_file, swallow_argv
40 40 from IPython.utils.path import filefind
41 41 from IPython.utils.py3compat import str_to_bytes
42 42 from IPython.utils.traitlets import (
43 43 Dict, List, Unicode, CUnicode, Int, CBool, Any, CaselessStrEnum
44 44 )
45 45 from IPython.kernel.zmq.kernelapp import (
46 46 kernel_flags,
47 47 kernel_aliases,
48 48 IPKernelApp
49 49 )
50 50 from IPython.kernel.zmq.session import Session, default_secure
51 51 from IPython.kernel.zmq.zmqshell import ZMQInteractiveShell
52 52
53 53 #-----------------------------------------------------------------------------
54 54 # Network Constants
55 55 #-----------------------------------------------------------------------------
56 56
57 57 from IPython.utils.localinterfaces import LOCALHOST, LOCAL_IPS
58 58
59 59 #-----------------------------------------------------------------------------
60 60 # Globals
61 61 #-----------------------------------------------------------------------------
62 62
63 63
64 64 #-----------------------------------------------------------------------------
65 65 # Aliases and Flags
66 66 #-----------------------------------------------------------------------------
67 67
68 68 flags = dict(kernel_flags)
69 69
70 70 # the flags that are specific to the frontend
71 71 # these must be scrubbed before being passed to the kernel,
72 72 # or it will raise an error on unrecognized flags
73 73 app_flags = {
74 74 'existing' : ({'IPythonConsoleApp' : {'existing' : 'kernel*.json'}},
75 75 "Connect to an existing kernel. If no argument specified, guess most recent"),
76 76 }
77 77 app_flags.update(boolean_flag(
78 78 'confirm-exit', 'IPythonConsoleApp.confirm_exit',
79 79 """Set to display confirmation dialog on exit. You can always use 'exit' or 'quit',
80 80 to force a direct exit without any confirmation.
81 81 """,
82 82 """Don't prompt the user when exiting. This will terminate the kernel
83 83 if it is owned by the frontend, and leave it alive if it is external.
84 84 """
85 85 ))
86 86 flags.update(app_flags)
87 87
88 88 aliases = dict(kernel_aliases)
89 89
90 90 # also scrub aliases from the frontend
91 91 app_aliases = dict(
92 92 ip = 'KernelManager.ip',
93 93 transport = 'KernelManager.transport',
94 94 hb = 'IPythonConsoleApp.hb_port',
95 95 shell = 'IPythonConsoleApp.shell_port',
96 96 iopub = 'IPythonConsoleApp.iopub_port',
97 97 stdin = 'IPythonConsoleApp.stdin_port',
98 98 existing = 'IPythonConsoleApp.existing',
99 99 f = 'IPythonConsoleApp.connection_file',
100 100
101 101
102 102 ssh = 'IPythonConsoleApp.sshserver',
103 103 )
104 104 aliases.update(app_aliases)
105 105
106 106 #-----------------------------------------------------------------------------
107 107 # Classes
108 108 #-----------------------------------------------------------------------------
109 109
110 110 #-----------------------------------------------------------------------------
111 111 # IPythonConsole
112 112 #-----------------------------------------------------------------------------
113 113
114 114 classes = [IPKernelApp, ZMQInteractiveShell, KernelManager, ProfileDir, Session]
115 115
116 116 try:
117 117 from IPython.kernel.zmq.pylab.backend_inline import InlineBackend
118 118 except ImportError:
119 119 pass
120 120 else:
121 121 classes.append(InlineBackend)
122 122
123 123 class IPythonConsoleApp(Configurable):
124 124 name = 'ipython-console-mixin'
125 125 default_config_file_name='ipython_config.py'
126 126
127 127 description = """
128 128 The IPython Mixin Console.
129 129
130 130 This class contains the common portions of console client (QtConsole,
131 131 ZMQ-based terminal console, etc). It is not a full console, in that
132 132 launched terminal subprocesses will not be able to accept input.
133 133
134 134 The Console using this mixing supports various extra features beyond
135 135 the single-process Terminal IPython shell, such as connecting to
136 136 existing kernel, via:
137 137
138 138 ipython <appname> --existing
139 139
140 140 as well as tunnel via SSH
141 141
142 142 """
143 143
144 144 classes = classes
145 145 flags = Dict(flags)
146 146 aliases = Dict(aliases)
147 147 kernel_manager_class = BlockingKernelManager
148 148
149 149 kernel_argv = List(Unicode)
150 150 # frontend flags&aliases to be stripped when building kernel_argv
151 151 frontend_flags = Any(app_flags)
152 152 frontend_aliases = Any(app_aliases)
153 153
154 154 # create requested profiles by default, if they don't exist:
155 155 auto_create = CBool(True)
156 156 # connection info:
157 157
158 158 sshserver = Unicode('', config=True,
159 159 help="""The SSH server to use to connect to the kernel.""")
160 160 sshkey = Unicode('', config=True,
161 161 help="""Path to the ssh key to use for logging in to the ssh server.""")
162 162
163 163 hb_port = Int(0, config=True,
164 164 help="set the heartbeat port [default: random]")
165 165 shell_port = Int(0, config=True,
166 166 help="set the shell (ROUTER) port [default: random]")
167 167 iopub_port = Int(0, config=True,
168 168 help="set the iopub (PUB) port [default: random]")
169 169 stdin_port = Int(0, config=True,
170 170 help="set the stdin (DEALER) port [default: random]")
171 171 connection_file = Unicode('', config=True,
172 172 help="""JSON file in which to store connection info [default: kernel-<pid>.json]
173 173
174 174 This file will contain the IP, ports, and authentication key needed to connect
175 175 clients to this kernel. By default, this file will be created in the security-dir
176 176 of the current profile, but can be specified by absolute path.
177 177 """)
178 178 def _connection_file_default(self):
179 179 return 'kernel-%i.json' % os.getpid()
180 180
181 181 existing = CUnicode('', config=True,
182 182 help="""Connect to an already running kernel""")
183 183
184 184 confirm_exit = CBool(True, config=True,
185 185 help="""
186 186 Set to display confirmation dialog on exit. You can always use 'exit' or 'quit',
187 187 to force a direct exit without any confirmation.""",
188 188 )
189 189
190 190
191 191 def build_kernel_argv(self, argv=None):
192 192 """build argv to be passed to kernel subprocess"""
193 193 if argv is None:
194 194 argv = sys.argv[1:]
195 195 self.kernel_argv = swallow_argv(argv, self.frontend_aliases, self.frontend_flags)
196 196 # kernel should inherit default config file from frontend
197 self.kernel_argv.append("--KernelApp.parent_appname='%s'"%self.name)
197 self.kernel_argv.append("--IPKernelApp.parent_appname='%s'" % self.name)
198 198
199 199 def init_connection_file(self):
200 200 """find the connection file, and load the info if found.
201 201
202 202 The current working directory and the current profile's security
203 203 directory will be searched for the file if it is not given by
204 204 absolute path.
205 205
206 206 When attempting to connect to an existing kernel and the `--existing`
207 207 argument does not match an existing file, it will be interpreted as a
208 208 fileglob, and the matching file in the current profile's security dir
209 209 with the latest access time will be used.
210 210
211 211 After this method is called, self.connection_file contains the *full path*
212 212 to the connection file, never just its name.
213 213 """
214 214 if self.existing:
215 215 try:
216 216 cf = find_connection_file(self.existing)
217 217 except Exception:
218 218 self.log.critical("Could not find existing kernel connection file %s", self.existing)
219 219 self.exit(1)
220 220 self.log.info("Connecting to existing kernel: %s" % cf)
221 221 self.connection_file = cf
222 222 else:
223 223 # not existing, check if we are going to write the file
224 224 # and ensure that self.connection_file is a full path, not just the shortname
225 225 try:
226 226 cf = find_connection_file(self.connection_file)
227 227 except Exception:
228 228 # file might not exist
229 229 if self.connection_file == os.path.basename(self.connection_file):
230 230 # just shortname, put it in security dir
231 231 cf = os.path.join(self.profile_dir.security_dir, self.connection_file)
232 232 else:
233 233 cf = self.connection_file
234 234 self.connection_file = cf
235 235
236 236 # should load_connection_file only be used for existing?
237 237 # as it is now, this allows reusing ports if an existing
238 238 # file is requested
239 239 try:
240 240 self.load_connection_file()
241 241 except Exception:
242 242 self.log.error("Failed to load connection file: %r", self.connection_file, exc_info=True)
243 243 self.exit(1)
244 244
245 245 def load_connection_file(self):
246 246 """load ip/port/hmac config from JSON connection file"""
247 # this is identical to KernelApp.load_connection_file
247 # this is identical to IPKernelApp.load_connection_file
248 248 # perhaps it can be centralized somewhere?
249 249 try:
250 250 fname = filefind(self.connection_file, ['.', self.profile_dir.security_dir])
251 251 except IOError:
252 252 self.log.debug("Connection File not found: %s", self.connection_file)
253 253 return
254 254 self.log.debug(u"Loading connection file %s", fname)
255 255 with open(fname) as f:
256 256 cfg = json.load(f)
257 257
258 258 self.config.KernelManager.transport = cfg.get('transport', 'tcp')
259 259 self.config.KernelManager.ip = cfg.get('ip', LOCALHOST)
260 260
261 261 for channel in ('hb', 'shell', 'iopub', 'stdin'):
262 262 name = channel + '_port'
263 263 if getattr(self, name) == 0 and name in cfg:
264 264 # not overridden by config or cl_args
265 265 setattr(self, name, cfg[name])
266 266 if 'key' in cfg:
267 267 self.config.Session.key = str_to_bytes(cfg['key'])
268 268
269 269 def init_ssh(self):
270 270 """set up ssh tunnels, if needed."""
271 271 if not self.existing or (not self.sshserver and not self.sshkey):
272 272 return
273 273
274 274 self.load_connection_file()
275 275
276 276 transport = self.config.KernelManager.transport
277 277 ip = self.config.KernelManager.ip
278 278
279 279 if transport != 'tcp':
280 280 self.log.error("Can only use ssh tunnels with TCP sockets, not %s", transport)
281 281 sys.exit(-1)
282 282
283 283 if self.sshkey and not self.sshserver:
284 284 # specifying just the key implies that we are connecting directly
285 285 self.sshserver = ip
286 286 ip = LOCALHOST
287 287
288 288 # build connection dict for tunnels:
289 289 info = dict(ip=ip,
290 290 shell_port=self.shell_port,
291 291 iopub_port=self.iopub_port,
292 292 stdin_port=self.stdin_port,
293 293 hb_port=self.hb_port
294 294 )
295 295
296 296 self.log.info("Forwarding connections to %s via %s"%(ip, self.sshserver))
297 297
298 298 # tunnels return a new set of ports, which will be on localhost:
299 299 self.config.KernelManager.ip = LOCALHOST
300 300 try:
301 301 newports = tunnel_to_kernel(info, self.sshserver, self.sshkey)
302 302 except:
303 303 # even catch KeyboardInterrupt
304 304 self.log.error("Could not setup tunnels", exc_info=True)
305 305 self.exit(1)
306 306
307 307 self.shell_port, self.iopub_port, self.stdin_port, self.hb_port = newports
308 308
309 309 cf = self.connection_file
310 310 base,ext = os.path.splitext(cf)
311 311 base = os.path.basename(base)
312 312 self.connection_file = os.path.basename(base)+'-ssh'+ext
313 313 self.log.critical("To connect another client via this tunnel, use:")
314 314 self.log.critical("--existing %s" % self.connection_file)
315 315
316 316 def _new_connection_file(self):
317 317 cf = ''
318 318 while not cf:
319 319 # we don't need a 128b id to distinguish kernels, use more readable
320 320 # 48b node segment (12 hex chars). Users running more than 32k simultaneous
321 321 # kernels can subclass.
322 322 ident = str(uuid.uuid4()).split('-')[-1]
323 323 cf = os.path.join(self.profile_dir.security_dir, 'kernel-%s.json' % ident)
324 324 # only keep if it's actually new. Protect against unlikely collision
325 325 # in 48b random search space
326 326 cf = cf if not os.path.exists(cf) else ''
327 327 return cf
328 328
329 329 def init_kernel_manager(self):
330 330 # Don't let Qt or ZMQ swallow KeyboardInterupts.
331 331 signal.signal(signal.SIGINT, signal.SIG_DFL)
332 332
333 333 # Create a KernelManager and start a kernel.
334 334 self.kernel_manager = self.kernel_manager_class(
335 335 shell_port=self.shell_port,
336 336 iopub_port=self.iopub_port,
337 337 stdin_port=self.stdin_port,
338 338 hb_port=self.hb_port,
339 339 connection_file=self.connection_file,
340 340 config=self.config,
341 341 )
342 342 # start the kernel
343 343 if not self.existing:
344 344 self.kernel_manager.start_kernel(extra_arguments=self.kernel_argv)
345 345 atexit.register(self.kernel_manager.cleanup_ipc_files)
346 346 elif self.sshserver:
347 347 # ssh, write new connection file
348 348 self.kernel_manager.write_connection_file()
349 349 atexit.register(self.kernel_manager.cleanup_connection_file)
350 350 self.kernel_manager.start_channels()
351 351
352 352
353 353 def initialize(self, argv=None):
354 354 """
355 355 Classes which mix this class in should call:
356 356 IPythonConsoleApp.initialize(self,argv)
357 357 """
358 358 self.init_connection_file()
359 359 default_secure(self.config)
360 360 self.init_ssh()
361 361 self.init_kernel_manager()
362 362
@@ -1,347 +1,347 b''
1 1 """Utilities for connecting to kernels
2 2
3 3 Authors:
4 4
5 5 * Min Ragan-Kelley
6 6
7 7 """
8 8
9 9 #-----------------------------------------------------------------------------
10 10 # Copyright (C) 2013 The IPython Development Team
11 11 #
12 12 # Distributed under the terms of the BSD License. The full license is in
13 13 # the file COPYING, distributed as part of this software.
14 14 #-----------------------------------------------------------------------------
15 15
16 16 #-----------------------------------------------------------------------------
17 17 # Imports
18 18 #-----------------------------------------------------------------------------
19 19
20 20 import glob
21 21 import json
22 22 import os
23 23 import socket
24 24 import sys
25 25 from getpass import getpass
26 26 from subprocess import Popen, PIPE
27 27 import tempfile
28 28
29 29 # external imports
30 30 from IPython.external.ssh import tunnel
31 31
32 32 # IPython imports
33 33 from IPython.core.profiledir import ProfileDir
34 34 from IPython.utils.localinterfaces import LOCALHOST
35 35 from IPython.utils.path import filefind, get_ipython_dir
36 36 from IPython.utils.py3compat import str_to_bytes, bytes_to_str
37 37
38 38
39 39 #-----------------------------------------------------------------------------
40 40 # Working with Connection Files
41 41 #-----------------------------------------------------------------------------
42 42
43 43 def write_connection_file(fname=None, shell_port=0, iopub_port=0, stdin_port=0, hb_port=0,
44 44 ip=LOCALHOST, key=b'', transport='tcp'):
45 45 """Generates a JSON config file, including the selection of random ports.
46 46
47 47 Parameters
48 48 ----------
49 49
50 50 fname : unicode
51 51 The path to the file to write
52 52
53 53 shell_port : int, optional
54 54 The port to use for ROUTER channel.
55 55
56 56 iopub_port : int, optional
57 57 The port to use for the SUB channel.
58 58
59 59 stdin_port : int, optional
60 60 The port to use for the REQ (raw input) channel.
61 61
62 62 hb_port : int, optional
63 63 The port to use for the hearbeat REP channel.
64 64
65 65 ip : str, optional
66 66 The ip address the kernel will bind to.
67 67
68 68 key : str, optional
69 69 The Session key used for HMAC authentication.
70 70
71 71 """
72 72 # default to temporary connector file
73 73 if not fname:
74 74 fname = tempfile.mktemp('.json')
75 75
76 76 # Find open ports as necessary.
77 77
78 78 ports = []
79 79 ports_needed = int(shell_port <= 0) + int(iopub_port <= 0) + \
80 80 int(stdin_port <= 0) + int(hb_port <= 0)
81 81 if transport == 'tcp':
82 82 for i in range(ports_needed):
83 83 sock = socket.socket()
84 84 sock.bind(('', 0))
85 85 ports.append(sock)
86 86 for i, sock in enumerate(ports):
87 87 port = sock.getsockname()[1]
88 88 sock.close()
89 89 ports[i] = port
90 90 else:
91 91 N = 1
92 92 for i in range(ports_needed):
93 93 while os.path.exists("%s-%s" % (ip, str(N))):
94 94 N += 1
95 95 ports.append(N)
96 96 N += 1
97 97 if shell_port <= 0:
98 98 shell_port = ports.pop(0)
99 99 if iopub_port <= 0:
100 100 iopub_port = ports.pop(0)
101 101 if stdin_port <= 0:
102 102 stdin_port = ports.pop(0)
103 103 if hb_port <= 0:
104 104 hb_port = ports.pop(0)
105 105
106 106 cfg = dict( shell_port=shell_port,
107 107 iopub_port=iopub_port,
108 108 stdin_port=stdin_port,
109 109 hb_port=hb_port,
110 110 )
111 111 cfg['ip'] = ip
112 112 cfg['key'] = bytes_to_str(key)
113 113 cfg['transport'] = transport
114 114
115 115 with open(fname, 'w') as f:
116 116 f.write(json.dumps(cfg, indent=2))
117 117
118 118 return fname, cfg
119 119
120 120
121 121 def get_connection_file(app=None):
122 122 """Return the path to the connection file of an app
123 123
124 124 Parameters
125 125 ----------
126 app : KernelApp instance [optional]
126 app : IPKernelApp instance [optional]
127 127 If unspecified, the currently running app will be used
128 128 """
129 129 if app is None:
130 130 from IPython.kernel.zmq.kernelapp import IPKernelApp
131 131 if not IPKernelApp.initialized():
132 132 raise RuntimeError("app not specified, and not in a running Kernel")
133 133
134 134 app = IPKernelApp.instance()
135 135 return filefind(app.connection_file, ['.', app.profile_dir.security_dir])
136 136
137 137
138 138 def find_connection_file(filename, profile=None):
139 139 """find a connection file, and return its absolute path.
140 140
141 141 The current working directory and the profile's security
142 142 directory will be searched for the file if it is not given by
143 143 absolute path.
144 144
145 145 If profile is unspecified, then the current running application's
146 146 profile will be used, or 'default', if not run from IPython.
147 147
148 148 If the argument does not match an existing file, it will be interpreted as a
149 149 fileglob, and the matching file in the profile's security dir with
150 150 the latest access time will be used.
151 151
152 152 Parameters
153 153 ----------
154 154 filename : str
155 155 The connection file or fileglob to search for.
156 156 profile : str [optional]
157 157 The name of the profile to use when searching for the connection file,
158 158 if different from the current IPython session or 'default'.
159 159
160 160 Returns
161 161 -------
162 162 str : The absolute path of the connection file.
163 163 """
164 164 from IPython.core.application import BaseIPythonApplication as IPApp
165 165 try:
166 166 # quick check for absolute path, before going through logic
167 167 return filefind(filename)
168 168 except IOError:
169 169 pass
170 170
171 171 if profile is None:
172 172 # profile unspecified, check if running from an IPython app
173 173 if IPApp.initialized():
174 174 app = IPApp.instance()
175 175 profile_dir = app.profile_dir
176 176 else:
177 177 # not running in IPython, use default profile
178 178 profile_dir = ProfileDir.find_profile_dir_by_name(get_ipython_dir(), 'default')
179 179 else:
180 180 # find profiledir by profile name:
181 181 profile_dir = ProfileDir.find_profile_dir_by_name(get_ipython_dir(), profile)
182 182 security_dir = profile_dir.security_dir
183 183
184 184 try:
185 185 # first, try explicit name
186 186 return filefind(filename, ['.', security_dir])
187 187 except IOError:
188 188 pass
189 189
190 190 # not found by full name
191 191
192 192 if '*' in filename:
193 193 # given as a glob already
194 194 pat = filename
195 195 else:
196 196 # accept any substring match
197 197 pat = '*%s*' % filename
198 198 matches = glob.glob( os.path.join(security_dir, pat) )
199 199 if not matches:
200 200 raise IOError("Could not find %r in %r" % (filename, security_dir))
201 201 elif len(matches) == 1:
202 202 return matches[0]
203 203 else:
204 204 # get most recent match, by access time:
205 205 return sorted(matches, key=lambda f: os.stat(f).st_atime)[-1]
206 206
207 207
208 208 def get_connection_info(connection_file=None, unpack=False, profile=None):
209 209 """Return the connection information for the current Kernel.
210 210
211 211 Parameters
212 212 ----------
213 213 connection_file : str [optional]
214 214 The connection file to be used. Can be given by absolute path, or
215 215 IPython will search in the security directory of a given profile.
216 216 If run from IPython,
217 217
218 218 If unspecified, the connection file for the currently running
219 219 IPython Kernel will be used, which is only allowed from inside a kernel.
220 220 unpack : bool [default: False]
221 221 if True, return the unpacked dict, otherwise just the string contents
222 222 of the file.
223 223 profile : str [optional]
224 224 The name of the profile to use when searching for the connection file,
225 225 if different from the current IPython session or 'default'.
226 226
227 227
228 228 Returns
229 229 -------
230 230 The connection dictionary of the current kernel, as string or dict,
231 231 depending on `unpack`.
232 232 """
233 233 if connection_file is None:
234 234 # get connection file from current kernel
235 235 cf = get_connection_file()
236 236 else:
237 237 # connection file specified, allow shortnames:
238 238 cf = find_connection_file(connection_file, profile=profile)
239 239
240 240 with open(cf) as f:
241 241 info = f.read()
242 242
243 243 if unpack:
244 244 info = json.loads(info)
245 245 # ensure key is bytes:
246 246 info['key'] = str_to_bytes(info.get('key', ''))
247 247 return info
248 248
249 249
250 250 def connect_qtconsole(connection_file=None, argv=None, profile=None):
251 251 """Connect a qtconsole to the current kernel.
252 252
253 253 This is useful for connecting a second qtconsole to a kernel, or to a
254 254 local notebook.
255 255
256 256 Parameters
257 257 ----------
258 258 connection_file : str [optional]
259 259 The connection file to be used. Can be given by absolute path, or
260 260 IPython will search in the security directory of a given profile.
261 261 If run from IPython,
262 262
263 263 If unspecified, the connection file for the currently running
264 264 IPython Kernel will be used, which is only allowed from inside a kernel.
265 265 argv : list [optional]
266 266 Any extra args to be passed to the console.
267 267 profile : str [optional]
268 268 The name of the profile to use when searching for the connection file,
269 269 if different from the current IPython session or 'default'.
270 270
271 271
272 272 Returns
273 273 -------
274 274 subprocess.Popen instance running the qtconsole frontend
275 275 """
276 276 argv = [] if argv is None else argv
277 277
278 278 if connection_file is None:
279 279 # get connection file from current kernel
280 280 cf = get_connection_file()
281 281 else:
282 282 cf = find_connection_file(connection_file, profile=profile)
283 283
284 284 cmd = ';'.join([
285 285 "from IPython.frontend.qt.console import qtconsoleapp",
286 286 "qtconsoleapp.main()"
287 287 ])
288 288
289 289 return Popen([sys.executable, '-c', cmd, '--existing', cf] + argv, stdout=PIPE, stderr=PIPE)
290 290
291 291
292 292 def tunnel_to_kernel(connection_info, sshserver, sshkey=None):
293 293 """tunnel connections to a kernel via ssh
294 294
295 295 This will open four SSH tunnels from localhost on this machine to the
296 296 ports associated with the kernel. They can be either direct
297 297 localhost-localhost tunnels, or if an intermediate server is necessary,
298 298 the kernel must be listening on a public IP.
299 299
300 300 Parameters
301 301 ----------
302 302 connection_info : dict or str (path)
303 303 Either a connection dict, or the path to a JSON connection file
304 304 sshserver : str
305 305 The ssh sever to use to tunnel to the kernel. Can be a full
306 306 `user@server:port` string. ssh config aliases are respected.
307 307 sshkey : str [optional]
308 308 Path to file containing ssh key to use for authentication.
309 309 Only necessary if your ssh config does not already associate
310 310 a keyfile with the host.
311 311
312 312 Returns
313 313 -------
314 314
315 315 (shell, iopub, stdin, hb) : ints
316 316 The four ports on localhost that have been forwarded to the kernel.
317 317 """
318 318 if isinstance(connection_info, basestring):
319 319 # it's a path, unpack it
320 320 with open(connection_info) as f:
321 321 connection_info = json.loads(f.read())
322 322
323 323 cf = connection_info
324 324
325 325 lports = tunnel.select_random_ports(4)
326 326 rports = cf['shell_port'], cf['iopub_port'], cf['stdin_port'], cf['hb_port']
327 327
328 328 remote_ip = cf['ip']
329 329
330 330 if tunnel.try_passwordless_ssh(sshserver, sshkey):
331 331 password=False
332 332 else:
333 333 password = getpass("SSH Password for %s: "%sshserver)
334 334
335 335 for lp,rp in zip(lports, rports):
336 336 tunnel.ssh_tunnel(lp, rp, sshserver, remote_ip, sshkey, password)
337 337
338 338 return tuple(lports)
339 339
340 340 __all__ = [
341 341 'write_connection_file',
342 342 'get_connection_file',
343 343 'find_connection_file',
344 344 'get_connection_info',
345 345 'connect_qtconsole',
346 346 'tunnel_to_kernel',
347 347 ] No newline at end of file
@@ -1,57 +1,57 b''
1 1 """Simple function for embedding an IPython kernel
2 2 """
3 3 #-----------------------------------------------------------------------------
4 4 # Imports
5 5 #-----------------------------------------------------------------------------
6 6
7 7 import sys
8 8
9 9 from IPython.utils.frame import extract_module_locals
10 10
11 11 from kernelapp import IPKernelApp
12 12
13 13 #-----------------------------------------------------------------------------
14 14 # Code
15 15 #-----------------------------------------------------------------------------
16 16
17 17 def embed_kernel(module=None, local_ns=None, **kwargs):
18 18 """Embed and start an IPython kernel in a given scope.
19 19
20 20 Parameters
21 21 ----------
22 22 module : ModuleType, optional
23 23 The module to load into IPython globals (default: caller)
24 24 local_ns : dict, optional
25 25 The namespace to load into IPython user namespace (default: caller)
26 26
27 27 kwargs : various, optional
28 Further keyword args are relayed to the KernelApp constructor,
28 Further keyword args are relayed to the IPKernelApp constructor,
29 29 allowing configuration of the Kernel. Will only have an effect
30 30 on the first embed_kernel call for a given process.
31 31
32 32 """
33 33 # get the app if it exists, or set it up if it doesn't
34 34 if IPKernelApp.initialized():
35 35 app = IPKernelApp.instance()
36 36 else:
37 37 app = IPKernelApp.instance(**kwargs)
38 38 app.initialize([])
39 39 # Undo unnecessary sys module mangling from init_sys_modules.
40 40 # This would not be necessary if we could prevent it
41 41 # in the first place by using a different InteractiveShell
42 42 # subclass, as in the regular embed case.
43 43 main = app.kernel.shell._orig_sys_modules_main_mod
44 44 if main is not None:
45 45 sys.modules[app.kernel.shell._orig_sys_modules_main_name] = main
46 46
47 47 # load the calling scope if not given
48 48 (caller_module, caller_locals) = extract_module_locals(1)
49 49 if module is None:
50 50 module = caller_module
51 51 if local_ns is None:
52 52 local_ns = caller_locals
53 53
54 54 app.kernel.user_module = module
55 55 app.kernel.user_ns = local_ns
56 56 app.shell.set_completer_frame()
57 57 app.start()
@@ -1,432 +1,432 b''
1 1 """An Application for launching a kernel
2 2
3 3 Authors
4 4 -------
5 5 * MinRK
6 6 """
7 7 #-----------------------------------------------------------------------------
8 8 # Copyright (C) 2011 The IPython Development Team
9 9 #
10 10 # Distributed under the terms of the BSD License. The full license is in
11 11 # the file COPYING.txt, distributed as part of this software.
12 12 #-----------------------------------------------------------------------------
13 13
14 14 #-----------------------------------------------------------------------------
15 15 # Imports
16 16 #-----------------------------------------------------------------------------
17 17
18 18 from __future__ import print_function
19 19
20 20 # Standard library imports
21 21 import atexit
22 22 import json
23 23 import os
24 24 import sys
25 25 import signal
26 26
27 27 # System library imports
28 28 import zmq
29 29 from zmq.eventloop import ioloop
30 30 from zmq.eventloop.zmqstream import ZMQStream
31 31
32 32 # IPython imports
33 33 from IPython.core.ultratb import FormattedTB
34 34 from IPython.core.application import (
35 35 BaseIPythonApplication, base_flags, base_aliases, catch_config_error
36 36 )
37 37 from IPython.core.profiledir import ProfileDir
38 38 from IPython.core.shellapp import (
39 39 InteractiveShellApp, shell_flags, shell_aliases
40 40 )
41 41 from IPython.utils import io
42 42 from IPython.utils.localinterfaces import LOCALHOST
43 43 from IPython.utils.path import filefind
44 44 from IPython.utils.py3compat import str_to_bytes
45 45 from IPython.utils.traitlets import (
46 46 Any, Instance, Dict, Unicode, Integer, Bool, CaselessStrEnum,
47 47 DottedObjectName,
48 48 )
49 49 from IPython.utils.importstring import import_item
50 50 from IPython.kernel import write_connection_file
51 51
52 52 # local imports
53 53 from heartbeat import Heartbeat
54 54 from ipkernel import Kernel
55 55 from parentpoller import ParentPollerUnix, ParentPollerWindows
56 56 from session import (
57 57 Session, session_flags, session_aliases, default_secure,
58 58 )
59 59 from zmqshell import ZMQInteractiveShell
60 60
61 61 #-----------------------------------------------------------------------------
62 62 # Flags and Aliases
63 63 #-----------------------------------------------------------------------------
64 64
65 65 kernel_aliases = dict(base_aliases)
66 66 kernel_aliases.update({
67 67 'ip' : 'IPKernelApp.ip',
68 68 'hb' : 'IPKernelApp.hb_port',
69 69 'shell' : 'IPKernelApp.shell_port',
70 70 'iopub' : 'IPKernelApp.iopub_port',
71 71 'stdin' : 'IPKernelApp.stdin_port',
72 72 'f' : 'IPKernelApp.connection_file',
73 73 'parent': 'IPKernelApp.parent',
74 74 'transport': 'IPKernelApp.transport',
75 75 })
76 76 if sys.platform.startswith('win'):
77 kernel_aliases['interrupt'] = 'KernelApp.interrupt'
77 kernel_aliases['interrupt'] = 'IPKernelApp.interrupt'
78 78
79 79 kernel_flags = dict(base_flags)
80 80 kernel_flags.update({
81 81 'no-stdout' : (
82 82 {'IPKernelApp' : {'no_stdout' : True}},
83 83 "redirect stdout to the null device"),
84 84 'no-stderr' : (
85 85 {'IPKernelApp' : {'no_stderr' : True}},
86 86 "redirect stderr to the null device"),
87 87 'pylab' : (
88 88 {'IPKernelApp' : {'pylab' : 'auto'}},
89 89 """Pre-load matplotlib and numpy for interactive use with
90 90 the default matplotlib backend."""),
91 91 })
92 92
93 93 # inherit flags&aliases for any IPython shell apps
94 94 kernel_aliases.update(shell_aliases)
95 95 kernel_flags.update(shell_flags)
96 96
97 97 # inherit flags&aliases for Sessions
98 98 kernel_aliases.update(session_aliases)
99 99 kernel_flags.update(session_flags)
100 100
101 101 #-----------------------------------------------------------------------------
102 102 # Application class for starting an IPython Kernel
103 103 #-----------------------------------------------------------------------------
104 104
105 105 class IPKernelApp(BaseIPythonApplication, InteractiveShellApp):
106 106 name='ipkernel'
107 107 aliases = Dict(kernel_aliases)
108 108 flags = Dict(kernel_flags)
109 109 classes = [Kernel, ZMQInteractiveShell, ProfileDir, Session]
110 110 # the kernel class, as an importstring
111 111 kernel_class = DottedObjectName('IPython.kernel.zmq.ipkernel.Kernel')
112 112 kernel = Any()
113 113 poller = Any() # don't restrict this even though current pollers are all Threads
114 114 heartbeat = Instance(Heartbeat)
115 115 session = Instance('IPython.kernel.zmq.session.Session')
116 116 ports = Dict()
117 117
118 118 # inherit config file name from parent:
119 119 parent_appname = Unicode(config=True)
120 120 def _parent_appname_changed(self, name, old, new):
121 121 if self.config_file_specified:
122 122 # it was manually specified, ignore
123 123 return
124 124 self.config_file_name = new.replace('-','_') + u'_config.py'
125 125 # don't let this count as specifying the config file
126 126 self.config_file_specified = False
127 127
128 128 # connection info:
129 129 transport = CaselessStrEnum(['tcp', 'ipc'], default_value='tcp', config=True)
130 130 ip = Unicode(config=True,
131 131 help="Set the IP or interface on which the kernel will listen.")
132 132 def _ip_default(self):
133 133 if self.transport == 'ipc':
134 134 if self.connection_file:
135 135 return os.path.splitext(self.abs_connection_file)[0] + '-ipc'
136 136 else:
137 137 return 'kernel-ipc'
138 138 else:
139 139 return LOCALHOST
140 140 hb_port = Integer(0, config=True, help="set the heartbeat port [default: random]")
141 141 shell_port = Integer(0, config=True, help="set the shell (ROUTER) port [default: random]")
142 142 iopub_port = Integer(0, config=True, help="set the iopub (PUB) port [default: random]")
143 143 stdin_port = Integer(0, config=True, help="set the stdin (DEALER) port [default: random]")
144 144 connection_file = Unicode('', config=True,
145 145 help="""JSON file in which to store connection info [default: kernel-<pid>.json]
146 146
147 147 This file will contain the IP, ports, and authentication key needed to connect
148 148 clients to this kernel. By default, this file will be created in the security dir
149 149 of the current profile, but can be specified by absolute path.
150 150 """)
151 151 @property
152 152 def abs_connection_file(self):
153 153 if os.path.basename(self.connection_file) == self.connection_file:
154 154 return os.path.join(self.profile_dir.security_dir, self.connection_file)
155 155 else:
156 156 return self.connection_file
157 157
158 158
159 159 # streams, etc.
160 160 no_stdout = Bool(False, config=True, help="redirect stdout to the null device")
161 161 no_stderr = Bool(False, config=True, help="redirect stderr to the null device")
162 162 outstream_class = DottedObjectName('IPython.kernel.zmq.iostream.OutStream',
163 163 config=True, help="The importstring for the OutStream factory")
164 164 displayhook_class = DottedObjectName('IPython.kernel.zmq.displayhook.ZMQDisplayHook',
165 165 config=True, help="The importstring for the DisplayHook factory")
166 166
167 167 # polling
168 168 parent = Integer(0, config=True,
169 169 help="""kill this process if its parent dies. On Windows, the argument
170 170 specifies the HANDLE of the parent process, otherwise it is simply boolean.
171 171 """)
172 172 interrupt = Integer(0, config=True,
173 173 help="""ONLY USED ON WINDOWS
174 174 Interrupt this process when the parent is signaled.
175 175 """)
176 176
177 177 def init_crash_handler(self):
178 178 # Install minimal exception handling
179 179 sys.excepthook = FormattedTB(mode='Verbose', color_scheme='NoColor',
180 180 ostream=sys.__stdout__)
181 181
182 182 def init_poller(self):
183 183 if sys.platform == 'win32':
184 184 if self.interrupt or self.parent:
185 185 self.poller = ParentPollerWindows(self.interrupt, self.parent)
186 186 elif self.parent:
187 187 self.poller = ParentPollerUnix()
188 188
189 189 def _bind_socket(self, s, port):
190 190 iface = '%s://%s' % (self.transport, self.ip)
191 191 if self.transport == 'tcp':
192 192 if port <= 0:
193 193 port = s.bind_to_random_port(iface)
194 194 else:
195 195 s.bind("tcp://%s:%i" % (self.ip, port))
196 196 elif self.transport == 'ipc':
197 197 if port <= 0:
198 198 port = 1
199 199 path = "%s-%i" % (self.ip, port)
200 200 while os.path.exists(path):
201 201 port = port + 1
202 202 path = "%s-%i" % (self.ip, port)
203 203 else:
204 204 path = "%s-%i" % (self.ip, port)
205 205 s.bind("ipc://%s" % path)
206 206 return port
207 207
208 208 def load_connection_file(self):
209 209 """load ip/port/hmac config from JSON connection file"""
210 210 try:
211 211 fname = filefind(self.connection_file, ['.', self.profile_dir.security_dir])
212 212 except IOError:
213 213 self.log.debug("Connection file not found: %s", self.connection_file)
214 214 # This means I own it, so I will clean it up:
215 215 atexit.register(self.cleanup_connection_file)
216 216 return
217 217 self.log.debug(u"Loading connection file %s", fname)
218 218 with open(fname) as f:
219 219 s = f.read()
220 220 cfg = json.loads(s)
221 221 self.transport = cfg.get('transport', self.transport)
222 222 if self.ip == self._ip_default() and 'ip' in cfg:
223 223 # not overridden by config or cl_args
224 224 self.ip = cfg['ip']
225 225 for channel in ('hb', 'shell', 'iopub', 'stdin'):
226 226 name = channel + '_port'
227 227 if getattr(self, name) == 0 and name in cfg:
228 228 # not overridden by config or cl_args
229 229 setattr(self, name, cfg[name])
230 230 if 'key' in cfg:
231 231 self.config.Session.key = str_to_bytes(cfg['key'])
232 232
233 233 def write_connection_file(self):
234 234 """write connection info to JSON file"""
235 235 cf = self.abs_connection_file
236 236 self.log.debug("Writing connection file: %s", cf)
237 237 write_connection_file(cf, ip=self.ip, key=self.session.key, transport=self.transport,
238 238 shell_port=self.shell_port, stdin_port=self.stdin_port, hb_port=self.hb_port,
239 239 iopub_port=self.iopub_port)
240 240
241 241 def cleanup_connection_file(self):
242 242 cf = self.abs_connection_file
243 243 self.log.debug("Cleaning up connection file: %s", cf)
244 244 try:
245 245 os.remove(cf)
246 246 except (IOError, OSError):
247 247 pass
248 248
249 249 self.cleanup_ipc_files()
250 250
251 251 def cleanup_ipc_files(self):
252 252 """cleanup ipc files if we wrote them"""
253 253 if self.transport != 'ipc':
254 254 return
255 255 for port in (self.shell_port, self.iopub_port, self.stdin_port, self.hb_port):
256 256 ipcfile = "%s-%i" % (self.ip, port)
257 257 try:
258 258 os.remove(ipcfile)
259 259 except (IOError, OSError):
260 260 pass
261 261
262 262 def init_connection_file(self):
263 263 if not self.connection_file:
264 264 self.connection_file = "kernel-%s.json"%os.getpid()
265 265 try:
266 266 self.load_connection_file()
267 267 except Exception:
268 268 self.log.error("Failed to load connection file: %r", self.connection_file, exc_info=True)
269 269 self.exit(1)
270 270
271 271 def init_sockets(self):
272 272 # Create a context, a session, and the kernel sockets.
273 273 self.log.info("Starting the kernel at pid: %i", os.getpid())
274 274 context = zmq.Context.instance()
275 275 # Uncomment this to try closing the context.
276 276 # atexit.register(context.term)
277 277
278 278 self.shell_socket = context.socket(zmq.ROUTER)
279 279 self.shell_port = self._bind_socket(self.shell_socket, self.shell_port)
280 280 self.log.debug("shell ROUTER Channel on port: %i"%self.shell_port)
281 281
282 282 self.iopub_socket = context.socket(zmq.PUB)
283 283 self.iopub_port = self._bind_socket(self.iopub_socket, self.iopub_port)
284 284 self.log.debug("iopub PUB Channel on port: %i"%self.iopub_port)
285 285
286 286 self.stdin_socket = context.socket(zmq.ROUTER)
287 287 self.stdin_port = self._bind_socket(self.stdin_socket, self.stdin_port)
288 288 self.log.debug("stdin ROUTER Channel on port: %i"%self.stdin_port)
289 289
290 290 def init_heartbeat(self):
291 291 """start the heart beating"""
292 292 # heartbeat doesn't share context, because it mustn't be blocked
293 293 # by the GIL, which is accessed by libzmq when freeing zero-copy messages
294 294 hb_ctx = zmq.Context()
295 295 self.heartbeat = Heartbeat(hb_ctx, (self.transport, self.ip, self.hb_port))
296 296 self.hb_port = self.heartbeat.port
297 297 self.log.debug("Heartbeat REP Channel on port: %i"%self.hb_port)
298 298 self.heartbeat.start()
299 299
300 300 # Helper to make it easier to connect to an existing kernel.
301 301 # set log-level to critical, to make sure it is output
302 302 self.log.critical("To connect another client to this kernel, use:")
303 303
304 304 def log_connection_info(self):
305 305 """display connection info, and store ports"""
306 306 basename = os.path.basename(self.connection_file)
307 307 if basename == self.connection_file or \
308 308 os.path.dirname(self.connection_file) == self.profile_dir.security_dir:
309 309 # use shortname
310 310 tail = basename
311 311 if self.profile != 'default':
312 312 tail += " --profile %s" % self.profile
313 313 else:
314 314 tail = self.connection_file
315 315 self.log.critical("--existing %s", tail)
316 316
317 317
318 318 self.ports = dict(shell=self.shell_port, iopub=self.iopub_port,
319 319 stdin=self.stdin_port, hb=self.hb_port)
320 320
321 321 def init_session(self):
322 322 """create our session object"""
323 323 default_secure(self.config)
324 324 self.session = Session(config=self.config, username=u'kernel')
325 325
326 326 def init_blackhole(self):
327 327 """redirects stdout/stderr to devnull if necessary"""
328 328 if self.no_stdout or self.no_stderr:
329 329 blackhole = open(os.devnull, 'w')
330 330 if self.no_stdout:
331 331 sys.stdout = sys.__stdout__ = blackhole
332 332 if self.no_stderr:
333 333 sys.stderr = sys.__stderr__ = blackhole
334 334
335 335 def init_io(self):
336 336 """Redirect input streams and set a display hook."""
337 337 if self.outstream_class:
338 338 outstream_factory = import_item(str(self.outstream_class))
339 339 sys.stdout = outstream_factory(self.session, self.iopub_socket, u'stdout')
340 340 sys.stderr = outstream_factory(self.session, self.iopub_socket, u'stderr')
341 341 if self.displayhook_class:
342 342 displayhook_factory = import_item(str(self.displayhook_class))
343 343 sys.displayhook = displayhook_factory(self.session, self.iopub_socket)
344 344
345 345 def init_signal(self):
346 346 signal.signal(signal.SIGINT, signal.SIG_IGN)
347 347
348 348 def init_kernel(self):
349 349 """Create the Kernel object itself"""
350 350 shell_stream = ZMQStream(self.shell_socket)
351 351
352 352 kernel = Kernel(config=self.config, session=self.session,
353 353 shell_streams=[shell_stream],
354 354 iopub_socket=self.iopub_socket,
355 355 stdin_socket=self.stdin_socket,
356 356 log=self.log,
357 357 profile_dir=self.profile_dir,
358 358 )
359 359 kernel.record_ports(self.ports)
360 360 self.kernel = kernel
361 361
362 362 def init_gui_pylab(self):
363 363 """Enable GUI event loop integration, taking pylab into account."""
364 364
365 365 # Provide a wrapper for :meth:`InteractiveShellApp.init_gui_pylab`
366 366 # to ensure that any exception is printed straight to stderr.
367 367 # Normally _showtraceback associates the reply with an execution,
368 368 # which means frontends will never draw it, as this exception
369 369 # is not associated with any execute request.
370 370
371 371 shell = self.shell
372 372 _showtraceback = shell._showtraceback
373 373 try:
374 374 # replace pyerr-sending traceback with stderr
375 375 def print_tb(etype, evalue, stb):
376 376 print ("GUI event loop or pylab initialization failed",
377 377 file=io.stderr)
378 378 print (shell.InteractiveTB.stb2text(stb), file=io.stderr)
379 379 shell._showtraceback = print_tb
380 380 InteractiveShellApp.init_gui_pylab(self)
381 381 finally:
382 382 shell._showtraceback = _showtraceback
383 383
384 384 def init_shell(self):
385 385 self.shell = self.kernel.shell
386 386 self.shell.configurables.append(self)
387 387
388 388 @catch_config_error
389 389 def initialize(self, argv=None):
390 390 super(IPKernelApp, self).initialize(argv)
391 391 self.init_blackhole()
392 392 self.init_connection_file()
393 393 self.init_session()
394 394 self.init_poller()
395 395 self.init_sockets()
396 396 self.init_heartbeat()
397 397 # writing/displaying connection info must be *after* init_sockets/heartbeat
398 398 self.log_connection_info()
399 399 self.write_connection_file()
400 400 self.init_io()
401 401 self.init_signal()
402 402 self.init_kernel()
403 403 # shell init steps
404 404 self.init_path()
405 405 self.init_shell()
406 406 self.init_gui_pylab()
407 407 self.init_extensions()
408 408 self.init_code()
409 409 # flush stdout/stderr, so that anything written to these streams during
410 410 # initialization do not get associated with the first execution request
411 411 sys.stdout.flush()
412 412 sys.stderr.flush()
413 413
414 414 def start(self):
415 415 if self.poller is not None:
416 416 self.poller.start()
417 417 self.kernel.start()
418 418 try:
419 419 ioloop.IOLoop.instance().start()
420 420 except KeyboardInterrupt:
421 421 pass
422 422
423 423
424 424 def main():
425 425 """Run an IPKernel as an application"""
426 426 app = IPKernelApp.instance()
427 427 app.initialize()
428 428 app.start()
429 429
430 430
431 431 if __name__ == '__main__':
432 432 main()
General Comments 0
You need to be logged in to leave comments. Login now