##// END OF EJS Templates
demote connection info to log.info...
MinRK -
Show More
@@ -1,447 +1,455
1 """An Application for launching a kernel
1 """An Application for launching a kernel
2
2
3 Authors
3 Authors
4 -------
4 -------
5 * MinRK
5 * MinRK
6 """
6 """
7 #-----------------------------------------------------------------------------
7 #-----------------------------------------------------------------------------
8 # Copyright (C) 2011 The IPython Development Team
8 # Copyright (C) 2011 The IPython Development Team
9 #
9 #
10 # Distributed under the terms of the BSD License. The full license is in
10 # Distributed under the terms of the BSD License. The full license is in
11 # the file COPYING.txt, distributed as part of this software.
11 # the file COPYING.txt, distributed as part of this software.
12 #-----------------------------------------------------------------------------
12 #-----------------------------------------------------------------------------
13
13
14 #-----------------------------------------------------------------------------
14 #-----------------------------------------------------------------------------
15 # Imports
15 # Imports
16 #-----------------------------------------------------------------------------
16 #-----------------------------------------------------------------------------
17
17
18 from __future__ import print_function
18 from __future__ import print_function
19
19
20 # Standard library imports
20 # Standard library imports
21 import atexit
21 import atexit
22 import json
22 import json
23 import os
23 import os
24 import sys
24 import sys
25 import signal
25 import signal
26
26
27 # System library imports
27 # System library imports
28 import zmq
28 import zmq
29 from zmq.eventloop import ioloop
29 from zmq.eventloop import ioloop
30 from zmq.eventloop.zmqstream import ZMQStream
30 from zmq.eventloop.zmqstream import ZMQStream
31
31
32 # IPython imports
32 # IPython imports
33 from IPython.core.ultratb import FormattedTB
33 from IPython.core.ultratb import FormattedTB
34 from IPython.core.application import (
34 from IPython.core.application import (
35 BaseIPythonApplication, base_flags, base_aliases, catch_config_error
35 BaseIPythonApplication, base_flags, base_aliases, catch_config_error
36 )
36 )
37 from IPython.core.profiledir import ProfileDir
37 from IPython.core.profiledir import ProfileDir
38 from IPython.core.shellapp import (
38 from IPython.core.shellapp import (
39 InteractiveShellApp, shell_flags, shell_aliases
39 InteractiveShellApp, shell_flags, shell_aliases
40 )
40 )
41 from IPython.utils import io
41 from IPython.utils import io
42 from IPython.utils.localinterfaces import LOCALHOST
42 from IPython.utils.localinterfaces import LOCALHOST
43 from IPython.utils.path import filefind
43 from IPython.utils.path import filefind
44 from IPython.utils.py3compat import str_to_bytes
44 from IPython.utils.py3compat import str_to_bytes
45 from IPython.utils.traitlets import (
45 from IPython.utils.traitlets import (
46 Any, Instance, Dict, Unicode, Integer, Bool, CaselessStrEnum,
46 Any, Instance, Dict, Unicode, Integer, Bool, CaselessStrEnum,
47 DottedObjectName,
47 DottedObjectName,
48 )
48 )
49 from IPython.utils.importstring import import_item
49 from IPython.utils.importstring import import_item
50 from IPython.kernel import write_connection_file
50 from IPython.kernel import write_connection_file
51
51
52 # local imports
52 # local imports
53 from heartbeat import Heartbeat
53 from heartbeat import Heartbeat
54 from ipkernel import Kernel
54 from ipkernel import Kernel
55 from parentpoller import ParentPollerUnix, ParentPollerWindows
55 from parentpoller import ParentPollerUnix, ParentPollerWindows
56 from session import (
56 from session import (
57 Session, session_flags, session_aliases, default_secure,
57 Session, session_flags, session_aliases, default_secure,
58 )
58 )
59 from zmqshell import ZMQInteractiveShell
59 from zmqshell import ZMQInteractiveShell
60
60
61 #-----------------------------------------------------------------------------
61 #-----------------------------------------------------------------------------
62 # Flags and Aliases
62 # Flags and Aliases
63 #-----------------------------------------------------------------------------
63 #-----------------------------------------------------------------------------
64
64
65 kernel_aliases = dict(base_aliases)
65 kernel_aliases = dict(base_aliases)
66 kernel_aliases.update({
66 kernel_aliases.update({
67 'ip' : 'IPKernelApp.ip',
67 'ip' : 'IPKernelApp.ip',
68 'hb' : 'IPKernelApp.hb_port',
68 'hb' : 'IPKernelApp.hb_port',
69 'shell' : 'IPKernelApp.shell_port',
69 'shell' : 'IPKernelApp.shell_port',
70 'iopub' : 'IPKernelApp.iopub_port',
70 'iopub' : 'IPKernelApp.iopub_port',
71 'stdin' : 'IPKernelApp.stdin_port',
71 'stdin' : 'IPKernelApp.stdin_port',
72 'control' : 'IPKernelApp.control_port',
72 'control' : 'IPKernelApp.control_port',
73 'f' : 'IPKernelApp.connection_file',
73 'f' : 'IPKernelApp.connection_file',
74 'parent': 'IPKernelApp.parent',
74 'parent': 'IPKernelApp.parent',
75 'transport': 'IPKernelApp.transport',
75 'transport': 'IPKernelApp.transport',
76 })
76 })
77 if sys.platform.startswith('win'):
77 if sys.platform.startswith('win'):
78 kernel_aliases['interrupt'] = 'IPKernelApp.interrupt'
78 kernel_aliases['interrupt'] = 'IPKernelApp.interrupt'
79
79
80 kernel_flags = dict(base_flags)
80 kernel_flags = dict(base_flags)
81 kernel_flags.update({
81 kernel_flags.update({
82 'no-stdout' : (
82 'no-stdout' : (
83 {'IPKernelApp' : {'no_stdout' : True}},
83 {'IPKernelApp' : {'no_stdout' : True}},
84 "redirect stdout to the null device"),
84 "redirect stdout to the null device"),
85 'no-stderr' : (
85 'no-stderr' : (
86 {'IPKernelApp' : {'no_stderr' : True}},
86 {'IPKernelApp' : {'no_stderr' : True}},
87 "redirect stderr to the null device"),
87 "redirect stderr to the null device"),
88 'pylab' : (
88 'pylab' : (
89 {'IPKernelApp' : {'pylab' : 'auto'}},
89 {'IPKernelApp' : {'pylab' : 'auto'}},
90 """Pre-load matplotlib and numpy for interactive use with
90 """Pre-load matplotlib and numpy for interactive use with
91 the default matplotlib backend."""),
91 the default matplotlib backend."""),
92 })
92 })
93
93
94 # inherit flags&aliases for any IPython shell apps
94 # inherit flags&aliases for any IPython shell apps
95 kernel_aliases.update(shell_aliases)
95 kernel_aliases.update(shell_aliases)
96 kernel_flags.update(shell_flags)
96 kernel_flags.update(shell_flags)
97
97
98 # inherit flags&aliases for Sessions
98 # inherit flags&aliases for Sessions
99 kernel_aliases.update(session_aliases)
99 kernel_aliases.update(session_aliases)
100 kernel_flags.update(session_flags)
100 kernel_flags.update(session_flags)
101
101
102 #-----------------------------------------------------------------------------
102 #-----------------------------------------------------------------------------
103 # Application class for starting an IPython Kernel
103 # Application class for starting an IPython Kernel
104 #-----------------------------------------------------------------------------
104 #-----------------------------------------------------------------------------
105
105
106 class IPKernelApp(BaseIPythonApplication, InteractiveShellApp):
106 class IPKernelApp(BaseIPythonApplication, InteractiveShellApp):
107 name='ipkernel'
107 name='ipkernel'
108 aliases = Dict(kernel_aliases)
108 aliases = Dict(kernel_aliases)
109 flags = Dict(kernel_flags)
109 flags = Dict(kernel_flags)
110 classes = [Kernel, ZMQInteractiveShell, ProfileDir, Session]
110 classes = [Kernel, ZMQInteractiveShell, ProfileDir, Session]
111 # the kernel class, as an importstring
111 # the kernel class, as an importstring
112 kernel_class = DottedObjectName('IPython.kernel.zmq.ipkernel.Kernel', config=True,
112 kernel_class = DottedObjectName('IPython.kernel.zmq.ipkernel.Kernel', config=True,
113 help="""The Kernel subclass to be used.
113 help="""The Kernel subclass to be used.
114
114
115 This should allow easy re-use of the IPKernelApp entry point
115 This should allow easy re-use of the IPKernelApp entry point
116 to configure and launch kernels other than IPython's own.
116 to configure and launch kernels other than IPython's own.
117 """)
117 """)
118 kernel = Any()
118 kernel = Any()
119 poller = Any() # don't restrict this even though current pollers are all Threads
119 poller = Any() # don't restrict this even though current pollers are all Threads
120 heartbeat = Instance(Heartbeat)
120 heartbeat = Instance(Heartbeat)
121 session = Instance('IPython.kernel.zmq.session.Session')
121 session = Instance('IPython.kernel.zmq.session.Session')
122 ports = Dict()
122 ports = Dict()
123
123
124 # inherit config file name from parent:
124 # inherit config file name from parent:
125 parent_appname = Unicode(config=True)
125 parent_appname = Unicode(config=True)
126 def _parent_appname_changed(self, name, old, new):
126 def _parent_appname_changed(self, name, old, new):
127 if self.config_file_specified:
127 if self.config_file_specified:
128 # it was manually specified, ignore
128 # it was manually specified, ignore
129 return
129 return
130 self.config_file_name = new.replace('-','_') + u'_config.py'
130 self.config_file_name = new.replace('-','_') + u'_config.py'
131 # don't let this count as specifying the config file
131 # don't let this count as specifying the config file
132 self.config_file_specified = False
132 self.config_file_specified = False
133
133
134 # connection info:
134 # connection info:
135 transport = CaselessStrEnum(['tcp', 'ipc'], default_value='tcp', config=True)
135 transport = CaselessStrEnum(['tcp', 'ipc'], default_value='tcp', config=True)
136 ip = Unicode(config=True,
136 ip = Unicode(config=True,
137 help="Set the IP or interface on which the kernel will listen.")
137 help="Set the IP or interface on which the kernel will listen.")
138 def _ip_default(self):
138 def _ip_default(self):
139 if self.transport == 'ipc':
139 if self.transport == 'ipc':
140 if self.connection_file:
140 if self.connection_file:
141 return os.path.splitext(self.abs_connection_file)[0] + '-ipc'
141 return os.path.splitext(self.abs_connection_file)[0] + '-ipc'
142 else:
142 else:
143 return 'kernel-ipc'
143 return 'kernel-ipc'
144 else:
144 else:
145 return LOCALHOST
145 return LOCALHOST
146 hb_port = Integer(0, config=True, help="set the heartbeat port [default: random]")
146 hb_port = Integer(0, config=True, help="set the heartbeat port [default: random]")
147 shell_port = Integer(0, config=True, help="set the shell (ROUTER) port [default: random]")
147 shell_port = Integer(0, config=True, help="set the shell (ROUTER) port [default: random]")
148 iopub_port = Integer(0, config=True, help="set the iopub (PUB) port [default: random]")
148 iopub_port = Integer(0, config=True, help="set the iopub (PUB) port [default: random]")
149 stdin_port = Integer(0, config=True, help="set the stdin (ROUTER) port [default: random]")
149 stdin_port = Integer(0, config=True, help="set the stdin (ROUTER) port [default: random]")
150 control_port = Integer(0, config=True, help="set the control (ROUTER) port [default: random]")
150 control_port = Integer(0, config=True, help="set the control (ROUTER) port [default: random]")
151 connection_file = Unicode('', config=True,
151 connection_file = Unicode('', config=True,
152 help="""JSON file in which to store connection info [default: kernel-<pid>.json]
152 help="""JSON file in which to store connection info [default: kernel-<pid>.json]
153
153
154 This file will contain the IP, ports, and authentication key needed to connect
154 This file will contain the IP, ports, and authentication key needed to connect
155 clients to this kernel. By default, this file will be created in the security dir
155 clients to this kernel. By default, this file will be created in the security dir
156 of the current profile, but can be specified by absolute path.
156 of the current profile, but can be specified by absolute path.
157 """)
157 """)
158 @property
158 @property
159 def abs_connection_file(self):
159 def abs_connection_file(self):
160 if os.path.basename(self.connection_file) == self.connection_file:
160 if os.path.basename(self.connection_file) == self.connection_file:
161 return os.path.join(self.profile_dir.security_dir, self.connection_file)
161 return os.path.join(self.profile_dir.security_dir, self.connection_file)
162 else:
162 else:
163 return self.connection_file
163 return self.connection_file
164
164
165
165
166 # streams, etc.
166 # streams, etc.
167 no_stdout = Bool(False, config=True, help="redirect stdout to the null device")
167 no_stdout = Bool(False, config=True, help="redirect stdout to the null device")
168 no_stderr = Bool(False, config=True, help="redirect stderr to the null device")
168 no_stderr = Bool(False, config=True, help="redirect stderr to the null device")
169 outstream_class = DottedObjectName('IPython.kernel.zmq.iostream.OutStream',
169 outstream_class = DottedObjectName('IPython.kernel.zmq.iostream.OutStream',
170 config=True, help="The importstring for the OutStream factory")
170 config=True, help="The importstring for the OutStream factory")
171 displayhook_class = DottedObjectName('IPython.kernel.zmq.displayhook.ZMQDisplayHook',
171 displayhook_class = DottedObjectName('IPython.kernel.zmq.displayhook.ZMQDisplayHook',
172 config=True, help="The importstring for the DisplayHook factory")
172 config=True, help="The importstring for the DisplayHook factory")
173
173
174 # polling
174 # polling
175 parent = Integer(0, config=True,
175 parent = Integer(0, config=True,
176 help="""kill this process if its parent dies. On Windows, the argument
176 help="""kill this process if its parent dies. On Windows, the argument
177 specifies the HANDLE of the parent process, otherwise it is simply boolean.
177 specifies the HANDLE of the parent process, otherwise it is simply boolean.
178 """)
178 """)
179 interrupt = Integer(0, config=True,
179 interrupt = Integer(0, config=True,
180 help="""ONLY USED ON WINDOWS
180 help="""ONLY USED ON WINDOWS
181 Interrupt this process when the parent is signaled.
181 Interrupt this process when the parent is signaled.
182 """)
182 """)
183
183
184 def init_crash_handler(self):
184 def init_crash_handler(self):
185 # Install minimal exception handling
185 # Install minimal exception handling
186 sys.excepthook = FormattedTB(mode='Verbose', color_scheme='NoColor',
186 sys.excepthook = FormattedTB(mode='Verbose', color_scheme='NoColor',
187 ostream=sys.__stdout__)
187 ostream=sys.__stdout__)
188
188
189 def init_poller(self):
189 def init_poller(self):
190 if sys.platform == 'win32':
190 if sys.platform == 'win32':
191 if self.interrupt or self.parent:
191 if self.interrupt or self.parent:
192 self.poller = ParentPollerWindows(self.interrupt, self.parent)
192 self.poller = ParentPollerWindows(self.interrupt, self.parent)
193 elif self.parent:
193 elif self.parent:
194 self.poller = ParentPollerUnix()
194 self.poller = ParentPollerUnix()
195
195
196 def _bind_socket(self, s, port):
196 def _bind_socket(self, s, port):
197 iface = '%s://%s' % (self.transport, self.ip)
197 iface = '%s://%s' % (self.transport, self.ip)
198 if self.transport == 'tcp':
198 if self.transport == 'tcp':
199 if port <= 0:
199 if port <= 0:
200 port = s.bind_to_random_port(iface)
200 port = s.bind_to_random_port(iface)
201 else:
201 else:
202 s.bind("tcp://%s:%i" % (self.ip, port))
202 s.bind("tcp://%s:%i" % (self.ip, port))
203 elif self.transport == 'ipc':
203 elif self.transport == 'ipc':
204 if port <= 0:
204 if port <= 0:
205 port = 1
205 port = 1
206 path = "%s-%i" % (self.ip, port)
206 path = "%s-%i" % (self.ip, port)
207 while os.path.exists(path):
207 while os.path.exists(path):
208 port = port + 1
208 port = port + 1
209 path = "%s-%i" % (self.ip, port)
209 path = "%s-%i" % (self.ip, port)
210 else:
210 else:
211 path = "%s-%i" % (self.ip, port)
211 path = "%s-%i" % (self.ip, port)
212 s.bind("ipc://%s" % path)
212 s.bind("ipc://%s" % path)
213 return port
213 return port
214
214
215 def load_connection_file(self):
215 def load_connection_file(self):
216 """load ip/port/hmac config from JSON connection file"""
216 """load ip/port/hmac config from JSON connection file"""
217 try:
217 try:
218 fname = filefind(self.connection_file, ['.', self.profile_dir.security_dir])
218 fname = filefind(self.connection_file, ['.', self.profile_dir.security_dir])
219 except IOError:
219 except IOError:
220 self.log.debug("Connection file not found: %s", self.connection_file)
220 self.log.debug("Connection file not found: %s", self.connection_file)
221 # This means I own it, so I will clean it up:
221 # This means I own it, so I will clean it up:
222 atexit.register(self.cleanup_connection_file)
222 atexit.register(self.cleanup_connection_file)
223 return
223 return
224 self.log.debug(u"Loading connection file %s", fname)
224 self.log.debug(u"Loading connection file %s", fname)
225 with open(fname) as f:
225 with open(fname) as f:
226 s = f.read()
226 s = f.read()
227 cfg = json.loads(s)
227 cfg = json.loads(s)
228 self.transport = cfg.get('transport', self.transport)
228 self.transport = cfg.get('transport', self.transport)
229 if self.ip == self._ip_default() and 'ip' in cfg:
229 if self.ip == self._ip_default() and 'ip' in cfg:
230 # not overridden by config or cl_args
230 # not overridden by config or cl_args
231 self.ip = cfg['ip']
231 self.ip = cfg['ip']
232 for channel in ('hb', 'shell', 'iopub', 'stdin', 'control'):
232 for channel in ('hb', 'shell', 'iopub', 'stdin', 'control'):
233 name = channel + '_port'
233 name = channel + '_port'
234 if getattr(self, name) == 0 and name in cfg:
234 if getattr(self, name) == 0 and name in cfg:
235 # not overridden by config or cl_args
235 # not overridden by config or cl_args
236 setattr(self, name, cfg[name])
236 setattr(self, name, cfg[name])
237 if 'key' in cfg:
237 if 'key' in cfg:
238 self.config.Session.key = str_to_bytes(cfg['key'])
238 self.config.Session.key = str_to_bytes(cfg['key'])
239
239
240 def write_connection_file(self):
240 def write_connection_file(self):
241 """write connection info to JSON file"""
241 """write connection info to JSON file"""
242 cf = self.abs_connection_file
242 cf = self.abs_connection_file
243 self.log.debug("Writing connection file: %s", cf)
243 self.log.debug("Writing connection file: %s", cf)
244 write_connection_file(cf, ip=self.ip, key=self.session.key, transport=self.transport,
244 write_connection_file(cf, ip=self.ip, key=self.session.key, transport=self.transport,
245 shell_port=self.shell_port, stdin_port=self.stdin_port, hb_port=self.hb_port,
245 shell_port=self.shell_port, stdin_port=self.stdin_port, hb_port=self.hb_port,
246 iopub_port=self.iopub_port, control_port=self.control_port)
246 iopub_port=self.iopub_port, control_port=self.control_port)
247
247
248 def cleanup_connection_file(self):
248 def cleanup_connection_file(self):
249 cf = self.abs_connection_file
249 cf = self.abs_connection_file
250 self.log.debug("Cleaning up connection file: %s", cf)
250 self.log.debug("Cleaning up connection file: %s", cf)
251 try:
251 try:
252 os.remove(cf)
252 os.remove(cf)
253 except (IOError, OSError):
253 except (IOError, OSError):
254 pass
254 pass
255
255
256 self.cleanup_ipc_files()
256 self.cleanup_ipc_files()
257
257
258 def cleanup_ipc_files(self):
258 def cleanup_ipc_files(self):
259 """cleanup ipc files if we wrote them"""
259 """cleanup ipc files if we wrote them"""
260 if self.transport != 'ipc':
260 if self.transport != 'ipc':
261 return
261 return
262 for port in (self.shell_port, self.iopub_port, self.stdin_port, self.hb_port, self.control_port):
262 for port in (self.shell_port, self.iopub_port, self.stdin_port, self.hb_port, self.control_port):
263 ipcfile = "%s-%i" % (self.ip, port)
263 ipcfile = "%s-%i" % (self.ip, port)
264 try:
264 try:
265 os.remove(ipcfile)
265 os.remove(ipcfile)
266 except (IOError, OSError):
266 except (IOError, OSError):
267 pass
267 pass
268
268
269 def init_connection_file(self):
269 def init_connection_file(self):
270 if not self.connection_file:
270 if not self.connection_file:
271 self.connection_file = "kernel-%s.json"%os.getpid()
271 self.connection_file = "kernel-%s.json"%os.getpid()
272 try:
272 try:
273 self.load_connection_file()
273 self.load_connection_file()
274 except Exception:
274 except Exception:
275 self.log.error("Failed to load connection file: %r", self.connection_file, exc_info=True)
275 self.log.error("Failed to load connection file: %r", self.connection_file, exc_info=True)
276 self.exit(1)
276 self.exit(1)
277
277
278 def init_sockets(self):
278 def init_sockets(self):
279 # Create a context, a session, and the kernel sockets.
279 # Create a context, a session, and the kernel sockets.
280 self.log.info("Starting the kernel at pid: %i", os.getpid())
280 self.log.info("Starting the kernel at pid: %i", os.getpid())
281 context = zmq.Context.instance()
281 context = zmq.Context.instance()
282 # Uncomment this to try closing the context.
282 # Uncomment this to try closing the context.
283 # atexit.register(context.term)
283 # atexit.register(context.term)
284
284
285 self.shell_socket = context.socket(zmq.ROUTER)
285 self.shell_socket = context.socket(zmq.ROUTER)
286 self.shell_port = self._bind_socket(self.shell_socket, self.shell_port)
286 self.shell_port = self._bind_socket(self.shell_socket, self.shell_port)
287 self.log.debug("shell ROUTER Channel on port: %i" % self.shell_port)
287 self.log.debug("shell ROUTER Channel on port: %i" % self.shell_port)
288
288
289 self.iopub_socket = context.socket(zmq.PUB)
289 self.iopub_socket = context.socket(zmq.PUB)
290 self.iopub_port = self._bind_socket(self.iopub_socket, self.iopub_port)
290 self.iopub_port = self._bind_socket(self.iopub_socket, self.iopub_port)
291 self.log.debug("iopub PUB Channel on port: %i" % self.iopub_port)
291 self.log.debug("iopub PUB Channel on port: %i" % self.iopub_port)
292
292
293 self.stdin_socket = context.socket(zmq.ROUTER)
293 self.stdin_socket = context.socket(zmq.ROUTER)
294 self.stdin_port = self._bind_socket(self.stdin_socket, self.stdin_port)
294 self.stdin_port = self._bind_socket(self.stdin_socket, self.stdin_port)
295 self.log.debug("stdin ROUTER Channel on port: %i" % self.stdin_port)
295 self.log.debug("stdin ROUTER Channel on port: %i" % self.stdin_port)
296
296
297 self.control_socket = context.socket(zmq.ROUTER)
297 self.control_socket = context.socket(zmq.ROUTER)
298 self.control_port = self._bind_socket(self.control_socket, self.control_port)
298 self.control_port = self._bind_socket(self.control_socket, self.control_port)
299 self.log.debug("control ROUTER Channel on port: %i" % self.control_port)
299 self.log.debug("control ROUTER Channel on port: %i" % self.control_port)
300
300
301 def init_heartbeat(self):
301 def init_heartbeat(self):
302 """start the heart beating"""
302 """start the heart beating"""
303 # heartbeat doesn't share context, because it mustn't be blocked
303 # heartbeat doesn't share context, because it mustn't be blocked
304 # by the GIL, which is accessed by libzmq when freeing zero-copy messages
304 # by the GIL, which is accessed by libzmq when freeing zero-copy messages
305 hb_ctx = zmq.Context()
305 hb_ctx = zmq.Context()
306 self.heartbeat = Heartbeat(hb_ctx, (self.transport, self.ip, self.hb_port))
306 self.heartbeat = Heartbeat(hb_ctx, (self.transport, self.ip, self.hb_port))
307 self.hb_port = self.heartbeat.port
307 self.hb_port = self.heartbeat.port
308 self.log.debug("Heartbeat REP Channel on port: %i" % self.hb_port)
308 self.log.debug("Heartbeat REP Channel on port: %i" % self.hb_port)
309 self.heartbeat.start()
309 self.heartbeat.start()
310
310
311 # Helper to make it easier to connect to an existing kernel.
312 # set log-level to critical, to make sure it is output
313 self.log.critical("To connect another client to this kernel, use:")
314
315 def log_connection_info(self):
311 def log_connection_info(self):
316 """display connection info, and store ports"""
312 """display connection info, and store ports"""
317 basename = os.path.basename(self.connection_file)
313 basename = os.path.basename(self.connection_file)
318 if basename == self.connection_file or \
314 if basename == self.connection_file or \
319 os.path.dirname(self.connection_file) == self.profile_dir.security_dir:
315 os.path.dirname(self.connection_file) == self.profile_dir.security_dir:
320 # use shortname
316 # use shortname
321 tail = basename
317 tail = basename
322 if self.profile != 'default':
318 if self.profile != 'default':
323 tail += " --profile %s" % self.profile
319 tail += " --profile %s" % self.profile
324 else:
320 else:
325 tail = self.connection_file
321 tail = self.connection_file
326 self.log.critical("--existing %s", tail)
322 lines = [
327
323 "To connect another client to this kernel, use:",
324 " --existing %s" % tail,
325 ]
326 # log connection info
327 # info-level, so often not shown.
328 # frontends should use the %connect_info magic
329 # to see the connection info
330 for line in lines:
331 self.log.info(line)
332 # also raw print to the terminal if no parent (`ipython kernel`)
333 if not self.parent:
334 for line in lines:
335 io.rprint(line)
328
336
329 self.ports = dict(shell=self.shell_port, iopub=self.iopub_port,
337 self.ports = dict(shell=self.shell_port, iopub=self.iopub_port,
330 stdin=self.stdin_port, hb=self.hb_port,
338 stdin=self.stdin_port, hb=self.hb_port,
331 control=self.control_port)
339 control=self.control_port)
332
340
333 def init_session(self):
341 def init_session(self):
334 """create our session object"""
342 """create our session object"""
335 default_secure(self.config)
343 default_secure(self.config)
336 self.session = Session(config=self.config, username=u'kernel')
344 self.session = Session(config=self.config, username=u'kernel')
337
345
338 def init_blackhole(self):
346 def init_blackhole(self):
339 """redirects stdout/stderr to devnull if necessary"""
347 """redirects stdout/stderr to devnull if necessary"""
340 if self.no_stdout or self.no_stderr:
348 if self.no_stdout or self.no_stderr:
341 blackhole = open(os.devnull, 'w')
349 blackhole = open(os.devnull, 'w')
342 if self.no_stdout:
350 if self.no_stdout:
343 sys.stdout = sys.__stdout__ = blackhole
351 sys.stdout = sys.__stdout__ = blackhole
344 if self.no_stderr:
352 if self.no_stderr:
345 sys.stderr = sys.__stderr__ = blackhole
353 sys.stderr = sys.__stderr__ = blackhole
346
354
347 def init_io(self):
355 def init_io(self):
348 """Redirect input streams and set a display hook."""
356 """Redirect input streams and set a display hook."""
349 if self.outstream_class:
357 if self.outstream_class:
350 outstream_factory = import_item(str(self.outstream_class))
358 outstream_factory = import_item(str(self.outstream_class))
351 sys.stdout = outstream_factory(self.session, self.iopub_socket, u'stdout')
359 sys.stdout = outstream_factory(self.session, self.iopub_socket, u'stdout')
352 sys.stderr = outstream_factory(self.session, self.iopub_socket, u'stderr')
360 sys.stderr = outstream_factory(self.session, self.iopub_socket, u'stderr')
353 if self.displayhook_class:
361 if self.displayhook_class:
354 displayhook_factory = import_item(str(self.displayhook_class))
362 displayhook_factory = import_item(str(self.displayhook_class))
355 sys.displayhook = displayhook_factory(self.session, self.iopub_socket)
363 sys.displayhook = displayhook_factory(self.session, self.iopub_socket)
356
364
357 def init_signal(self):
365 def init_signal(self):
358 signal.signal(signal.SIGINT, signal.SIG_IGN)
366 signal.signal(signal.SIGINT, signal.SIG_IGN)
359
367
360 def init_kernel(self):
368 def init_kernel(self):
361 """Create the Kernel object itself"""
369 """Create the Kernel object itself"""
362 shell_stream = ZMQStream(self.shell_socket)
370 shell_stream = ZMQStream(self.shell_socket)
363 control_stream = ZMQStream(self.control_socket)
371 control_stream = ZMQStream(self.control_socket)
364
372
365 kernel_factory = import_item(str(self.kernel_class))
373 kernel_factory = import_item(str(self.kernel_class))
366
374
367 kernel = kernel_factory(config=self.config, session=self.session,
375 kernel = kernel_factory(config=self.config, session=self.session,
368 shell_streams=[shell_stream, control_stream],
376 shell_streams=[shell_stream, control_stream],
369 iopub_socket=self.iopub_socket,
377 iopub_socket=self.iopub_socket,
370 stdin_socket=self.stdin_socket,
378 stdin_socket=self.stdin_socket,
371 log=self.log,
379 log=self.log,
372 profile_dir=self.profile_dir,
380 profile_dir=self.profile_dir,
373 )
381 )
374 kernel.record_ports(self.ports)
382 kernel.record_ports(self.ports)
375 self.kernel = kernel
383 self.kernel = kernel
376
384
377 def init_gui_pylab(self):
385 def init_gui_pylab(self):
378 """Enable GUI event loop integration, taking pylab into account."""
386 """Enable GUI event loop integration, taking pylab into account."""
379
387
380 # Provide a wrapper for :meth:`InteractiveShellApp.init_gui_pylab`
388 # Provide a wrapper for :meth:`InteractiveShellApp.init_gui_pylab`
381 # to ensure that any exception is printed straight to stderr.
389 # to ensure that any exception is printed straight to stderr.
382 # Normally _showtraceback associates the reply with an execution,
390 # Normally _showtraceback associates the reply with an execution,
383 # which means frontends will never draw it, as this exception
391 # which means frontends will never draw it, as this exception
384 # is not associated with any execute request.
392 # is not associated with any execute request.
385
393
386 shell = self.shell
394 shell = self.shell
387 _showtraceback = shell._showtraceback
395 _showtraceback = shell._showtraceback
388 try:
396 try:
389 # replace pyerr-sending traceback with stderr
397 # replace pyerr-sending traceback with stderr
390 def print_tb(etype, evalue, stb):
398 def print_tb(etype, evalue, stb):
391 print ("GUI event loop or pylab initialization failed",
399 print ("GUI event loop or pylab initialization failed",
392 file=io.stderr)
400 file=io.stderr)
393 print (shell.InteractiveTB.stb2text(stb), file=io.stderr)
401 print (shell.InteractiveTB.stb2text(stb), file=io.stderr)
394 shell._showtraceback = print_tb
402 shell._showtraceback = print_tb
395 InteractiveShellApp.init_gui_pylab(self)
403 InteractiveShellApp.init_gui_pylab(self)
396 finally:
404 finally:
397 shell._showtraceback = _showtraceback
405 shell._showtraceback = _showtraceback
398
406
399 def init_shell(self):
407 def init_shell(self):
400 self.shell = self.kernel.shell
408 self.shell = self.kernel.shell
401 self.shell.configurables.append(self)
409 self.shell.configurables.append(self)
402
410
403 @catch_config_error
411 @catch_config_error
404 def initialize(self, argv=None):
412 def initialize(self, argv=None):
405 super(IPKernelApp, self).initialize(argv)
413 super(IPKernelApp, self).initialize(argv)
406 self.init_blackhole()
414 self.init_blackhole()
407 self.init_connection_file()
415 self.init_connection_file()
408 self.init_session()
416 self.init_session()
409 self.init_poller()
417 self.init_poller()
410 self.init_sockets()
418 self.init_sockets()
411 self.init_heartbeat()
419 self.init_heartbeat()
412 # writing/displaying connection info must be *after* init_sockets/heartbeat
420 # writing/displaying connection info must be *after* init_sockets/heartbeat
413 self.log_connection_info()
421 self.log_connection_info()
414 self.write_connection_file()
422 self.write_connection_file()
415 self.init_io()
423 self.init_io()
416 self.init_signal()
424 self.init_signal()
417 self.init_kernel()
425 self.init_kernel()
418 # shell init steps
426 # shell init steps
419 self.init_path()
427 self.init_path()
420 self.init_shell()
428 self.init_shell()
421 self.init_gui_pylab()
429 self.init_gui_pylab()
422 self.init_extensions()
430 self.init_extensions()
423 self.init_code()
431 self.init_code()
424 # flush stdout/stderr, so that anything written to these streams during
432 # flush stdout/stderr, so that anything written to these streams during
425 # initialization do not get associated with the first execution request
433 # initialization do not get associated with the first execution request
426 sys.stdout.flush()
434 sys.stdout.flush()
427 sys.stderr.flush()
435 sys.stderr.flush()
428
436
429 def start(self):
437 def start(self):
430 if self.poller is not None:
438 if self.poller is not None:
431 self.poller.start()
439 self.poller.start()
432 self.kernel.start()
440 self.kernel.start()
433 try:
441 try:
434 ioloop.IOLoop.instance().start()
442 ioloop.IOLoop.instance().start()
435 except KeyboardInterrupt:
443 except KeyboardInterrupt:
436 pass
444 pass
437
445
438
446
439 def main():
447 def main():
440 """Run an IPKernel as an application"""
448 """Run an IPKernel as an application"""
441 app = IPKernelApp.instance()
449 app = IPKernelApp.instance()
442 app.initialize()
450 app.initialize()
443 app.start()
451 app.start()
444
452
445
453
446 if __name__ == '__main__':
454 if __name__ == '__main__':
447 main()
455 main()
General Comments 0
You need to be logged in to leave comments. Login now