##// END OF EJS Templates
fix kernel connection messsage with non-default profile...
MinRK -
Show More
@@ -1,292 +1,295 b''
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 # Standard library imports.
18 # Standard library imports.
19 import os
19 import os
20 import sys
20 import sys
21
21
22 # System library imports.
22 # System library imports.
23 import zmq
23 import zmq
24 from zmq.utils import jsonapi as json
24 from zmq.utils import jsonapi as json
25
25
26 # IPython imports.
26 # IPython imports.
27 from IPython.core.ultratb import FormattedTB
27 from IPython.core.ultratb import FormattedTB
28 from IPython.core.application import (
28 from IPython.core.application import (
29 BaseIPythonApplication, base_flags, base_aliases
29 BaseIPythonApplication, base_flags, base_aliases
30 )
30 )
31 from IPython.utils import io
31 from IPython.utils import io
32 from IPython.utils.localinterfaces import LOCALHOST
32 from IPython.utils.localinterfaces import LOCALHOST
33 from IPython.utils.path import filefind
33 from IPython.utils.path import filefind
34 from IPython.utils.py3compat import str_to_bytes
34 from IPython.utils.py3compat import str_to_bytes
35 from IPython.utils.traitlets import (Any, Instance, Dict, Unicode, Int, Bool,
35 from IPython.utils.traitlets import (Any, Instance, Dict, Unicode, Int, Bool,
36 DottedObjectName)
36 DottedObjectName)
37 from IPython.utils.importstring import import_item
37 from IPython.utils.importstring import import_item
38 # local imports
38 # local imports
39 from IPython.zmq.entry_point import write_connection_file
39 from IPython.zmq.entry_point import write_connection_file
40 from IPython.zmq.heartbeat import Heartbeat
40 from IPython.zmq.heartbeat import Heartbeat
41 from IPython.zmq.parentpoller import ParentPollerUnix, ParentPollerWindows
41 from IPython.zmq.parentpoller import ParentPollerUnix, ParentPollerWindows
42 from IPython.zmq.session import (
42 from IPython.zmq.session import (
43 Session, session_flags, session_aliases, default_secure,
43 Session, session_flags, session_aliases, default_secure,
44 )
44 )
45
45
46
46
47 #-----------------------------------------------------------------------------
47 #-----------------------------------------------------------------------------
48 # Flags and Aliases
48 # Flags and Aliases
49 #-----------------------------------------------------------------------------
49 #-----------------------------------------------------------------------------
50
50
51 kernel_aliases = dict(base_aliases)
51 kernel_aliases = dict(base_aliases)
52 kernel_aliases.update({
52 kernel_aliases.update({
53 'ip' : 'KernelApp.ip',
53 'ip' : 'KernelApp.ip',
54 'hb' : 'KernelApp.hb_port',
54 'hb' : 'KernelApp.hb_port',
55 'shell' : 'KernelApp.shell_port',
55 'shell' : 'KernelApp.shell_port',
56 'iopub' : 'KernelApp.iopub_port',
56 'iopub' : 'KernelApp.iopub_port',
57 'stdin' : 'KernelApp.stdin_port',
57 'stdin' : 'KernelApp.stdin_port',
58 'f' : 'KernelApp.connection_file',
58 'f' : 'KernelApp.connection_file',
59 'parent': 'KernelApp.parent',
59 'parent': 'KernelApp.parent',
60 })
60 })
61 if sys.platform.startswith('win'):
61 if sys.platform.startswith('win'):
62 kernel_aliases['interrupt'] = 'KernelApp.interrupt'
62 kernel_aliases['interrupt'] = 'KernelApp.interrupt'
63
63
64 kernel_flags = dict(base_flags)
64 kernel_flags = dict(base_flags)
65 kernel_flags.update({
65 kernel_flags.update({
66 'no-stdout' : (
66 'no-stdout' : (
67 {'KernelApp' : {'no_stdout' : True}},
67 {'KernelApp' : {'no_stdout' : True}},
68 "redirect stdout to the null device"),
68 "redirect stdout to the null device"),
69 'no-stderr' : (
69 'no-stderr' : (
70 {'KernelApp' : {'no_stderr' : True}},
70 {'KernelApp' : {'no_stderr' : True}},
71 "redirect stderr to the null device"),
71 "redirect stderr to the null device"),
72 })
72 })
73
73
74 # inherit flags&aliases for Sessions
74 # inherit flags&aliases for Sessions
75 kernel_aliases.update(session_aliases)
75 kernel_aliases.update(session_aliases)
76 kernel_flags.update(session_flags)
76 kernel_flags.update(session_flags)
77
77
78
78
79
79
80 #-----------------------------------------------------------------------------
80 #-----------------------------------------------------------------------------
81 # Application class for starting a Kernel
81 # Application class for starting a Kernel
82 #-----------------------------------------------------------------------------
82 #-----------------------------------------------------------------------------
83
83
84 class KernelApp(BaseIPythonApplication):
84 class KernelApp(BaseIPythonApplication):
85 name='pykernel'
85 name='pykernel'
86 aliases = Dict(kernel_aliases)
86 aliases = Dict(kernel_aliases)
87 flags = Dict(kernel_flags)
87 flags = Dict(kernel_flags)
88 classes = [Session]
88 classes = [Session]
89 # the kernel class, as an importstring
89 # the kernel class, as an importstring
90 kernel_class = DottedObjectName('IPython.zmq.pykernel.Kernel')
90 kernel_class = DottedObjectName('IPython.zmq.pykernel.Kernel')
91 kernel = Any()
91 kernel = Any()
92 poller = Any() # don't restrict this even though current pollers are all Threads
92 poller = Any() # don't restrict this even though current pollers are all Threads
93 heartbeat = Instance(Heartbeat)
93 heartbeat = Instance(Heartbeat)
94 session = Instance('IPython.zmq.session.Session')
94 session = Instance('IPython.zmq.session.Session')
95 ports = Dict()
95 ports = Dict()
96
96
97 # inherit config file name from parent:
97 # inherit config file name from parent:
98 parent_appname = Unicode(config=True)
98 parent_appname = Unicode(config=True)
99 def _parent_appname_changed(self, name, old, new):
99 def _parent_appname_changed(self, name, old, new):
100 if self.config_file_specified:
100 if self.config_file_specified:
101 # it was manually specified, ignore
101 # it was manually specified, ignore
102 return
102 return
103 self.config_file_name = new.replace('-','_') + u'_config.py'
103 self.config_file_name = new.replace('-','_') + u'_config.py'
104 # don't let this count as specifying the config file
104 # don't let this count as specifying the config file
105 self.config_file_specified = False
105 self.config_file_specified = False
106
106
107 # connection info:
107 # connection info:
108 ip = Unicode(LOCALHOST, config=True,
108 ip = Unicode(LOCALHOST, config=True,
109 help="Set the IP or interface on which the kernel will listen.")
109 help="Set the IP or interface on which the kernel will listen.")
110 hb_port = Int(0, config=True, help="set the heartbeat port [default: random]")
110 hb_port = Int(0, config=True, help="set the heartbeat port [default: random]")
111 shell_port = Int(0, config=True, help="set the shell (XREP) port [default: random]")
111 shell_port = Int(0, config=True, help="set the shell (XREP) port [default: random]")
112 iopub_port = Int(0, config=True, help="set the iopub (PUB) port [default: random]")
112 iopub_port = Int(0, config=True, help="set the iopub (PUB) port [default: random]")
113 stdin_port = Int(0, config=True, help="set the stdin (XREQ) port [default: random]")
113 stdin_port = Int(0, config=True, help="set the stdin (XREQ) port [default: random]")
114 connection_file = Unicode('', config=True,
114 connection_file = Unicode('', config=True,
115 help="""JSON file in which to store connection info [default: kernel-<pid>.json]
115 help="""JSON file in which to store connection info [default: kernel-<pid>.json]
116
116
117 This file will contain the IP, ports, and authentication key needed to connect
117 This file will contain the IP, ports, and authentication key needed to connect
118 clients to this kernel. By default, this file will be created in the security-dir
118 clients to this kernel. By default, this file will be created in the security-dir
119 of the current profile, but can be specified by absolute path.
119 of the current profile, but can be specified by absolute path.
120 """)
120 """)
121
121
122 # streams, etc.
122 # streams, etc.
123 no_stdout = Bool(False, config=True, help="redirect stdout to the null device")
123 no_stdout = Bool(False, config=True, help="redirect stdout to the null device")
124 no_stderr = Bool(False, config=True, help="redirect stderr to the null device")
124 no_stderr = Bool(False, config=True, help="redirect stderr to the null device")
125 outstream_class = DottedObjectName('IPython.zmq.iostream.OutStream',
125 outstream_class = DottedObjectName('IPython.zmq.iostream.OutStream',
126 config=True, help="The importstring for the OutStream factory")
126 config=True, help="The importstring for the OutStream factory")
127 displayhook_class = DottedObjectName('IPython.zmq.displayhook.ZMQDisplayHook',
127 displayhook_class = DottedObjectName('IPython.zmq.displayhook.ZMQDisplayHook',
128 config=True, help="The importstring for the DisplayHook factory")
128 config=True, help="The importstring for the DisplayHook factory")
129
129
130 # polling
130 # polling
131 parent = Int(0, config=True,
131 parent = Int(0, config=True,
132 help="""kill this process if its parent dies. On Windows, the argument
132 help="""kill this process if its parent dies. On Windows, the argument
133 specifies the HANDLE of the parent process, otherwise it is simply boolean.
133 specifies the HANDLE of the parent process, otherwise it is simply boolean.
134 """)
134 """)
135 interrupt = Int(0, config=True,
135 interrupt = Int(0, config=True,
136 help="""ONLY USED ON WINDOWS
136 help="""ONLY USED ON WINDOWS
137 Interrupt this process when the parent is signalled.
137 Interrupt this process when the parent is signalled.
138 """)
138 """)
139
139
140 def init_crash_handler(self):
140 def init_crash_handler(self):
141 # Install minimal exception handling
141 # Install minimal exception handling
142 sys.excepthook = FormattedTB(mode='Verbose', color_scheme='NoColor',
142 sys.excepthook = FormattedTB(mode='Verbose', color_scheme='NoColor',
143 ostream=sys.__stdout__)
143 ostream=sys.__stdout__)
144
144
145 def init_poller(self):
145 def init_poller(self):
146 if sys.platform == 'win32':
146 if sys.platform == 'win32':
147 if self.interrupt or self.parent:
147 if self.interrupt or self.parent:
148 self.poller = ParentPollerWindows(self.interrupt, self.parent)
148 self.poller = ParentPollerWindows(self.interrupt, self.parent)
149 elif self.parent:
149 elif self.parent:
150 self.poller = ParentPollerUnix()
150 self.poller = ParentPollerUnix()
151
151
152 def _bind_socket(self, s, port):
152 def _bind_socket(self, s, port):
153 iface = 'tcp://%s' % self.ip
153 iface = 'tcp://%s' % self.ip
154 if port <= 0:
154 if port <= 0:
155 port = s.bind_to_random_port(iface)
155 port = s.bind_to_random_port(iface)
156 else:
156 else:
157 s.bind(iface + ':%i'%port)
157 s.bind(iface + ':%i'%port)
158 return port
158 return port
159
159
160 def load_connection_file(self):
160 def load_connection_file(self):
161 """load ip/port/hmac config from JSON connection file"""
161 """load ip/port/hmac config from JSON connection file"""
162 try:
162 try:
163 fname = filefind(self.connection_file, ['.', self.profile_dir.security_dir])
163 fname = filefind(self.connection_file, ['.', self.profile_dir.security_dir])
164 except IOError:
164 except IOError:
165 self.log.debug("Connection file not found: %s", self.connection_file)
165 self.log.debug("Connection file not found: %s", self.connection_file)
166 return
166 return
167 self.log.debug(u"Loading connection file %s", fname)
167 self.log.debug(u"Loading connection file %s", fname)
168 with open(fname) as f:
168 with open(fname) as f:
169 s = f.read()
169 s = f.read()
170 cfg = json.loads(s)
170 cfg = json.loads(s)
171 if self.ip == LOCALHOST and 'ip' in cfg:
171 if self.ip == LOCALHOST and 'ip' in cfg:
172 # not overridden by config or cl_args
172 # not overridden by config or cl_args
173 self.ip = cfg['ip']
173 self.ip = cfg['ip']
174 for channel in ('hb', 'shell', 'iopub', 'stdin'):
174 for channel in ('hb', 'shell', 'iopub', 'stdin'):
175 name = channel + '_port'
175 name = channel + '_port'
176 if getattr(self, name) == 0 and name in cfg:
176 if getattr(self, name) == 0 and name in cfg:
177 # not overridden by config or cl_args
177 # not overridden by config or cl_args
178 setattr(self, name, cfg[name])
178 setattr(self, name, cfg[name])
179 if 'key' in cfg:
179 if 'key' in cfg:
180 self.config.Session.key = str_to_bytes(cfg['key'])
180 self.config.Session.key = str_to_bytes(cfg['key'])
181
181
182 def write_connection_file(self):
182 def write_connection_file(self):
183 """write connection info to JSON file"""
183 """write connection info to JSON file"""
184 if os.path.basename(self.connection_file) == self.connection_file:
184 if os.path.basename(self.connection_file) == self.connection_file:
185 cf = os.path.join(self.profile_dir.security_dir, self.connection_file)
185 cf = os.path.join(self.profile_dir.security_dir, self.connection_file)
186 else:
186 else:
187 cf = self.connection_file
187 cf = self.connection_file
188 write_connection_file(cf, ip=self.ip, key=self.session.key,
188 write_connection_file(cf, ip=self.ip, key=self.session.key,
189 shell_port=self.shell_port, stdin_port=self.stdin_port, hb_port=self.hb_port,
189 shell_port=self.shell_port, stdin_port=self.stdin_port, hb_port=self.hb_port,
190 iopub_port=self.iopub_port)
190 iopub_port=self.iopub_port)
191
191
192 def init_connection_file(self):
192 def init_connection_file(self):
193 if not self.connection_file:
193 if not self.connection_file:
194 self.connection_file = "kernel-%s.json"%os.getpid()
194 self.connection_file = "kernel-%s.json"%os.getpid()
195
195
196 self.load_connection_file()
196 self.load_connection_file()
197
197
198 def init_sockets(self):
198 def init_sockets(self):
199 # Create a context, a session, and the kernel sockets.
199 # Create a context, a session, and the kernel sockets.
200 self.log.info("Starting the kernel at pid: %i", os.getpid())
200 self.log.info("Starting the kernel at pid: %i", os.getpid())
201 context = zmq.Context.instance()
201 context = zmq.Context.instance()
202 # Uncomment this to try closing the context.
202 # Uncomment this to try closing the context.
203 # atexit.register(context.term)
203 # atexit.register(context.term)
204
204
205 self.shell_socket = context.socket(zmq.ROUTER)
205 self.shell_socket = context.socket(zmq.ROUTER)
206 self.shell_port = self._bind_socket(self.shell_socket, self.shell_port)
206 self.shell_port = self._bind_socket(self.shell_socket, self.shell_port)
207 self.log.debug("shell ROUTER Channel on port: %i"%self.shell_port)
207 self.log.debug("shell ROUTER Channel on port: %i"%self.shell_port)
208
208
209 self.iopub_socket = context.socket(zmq.PUB)
209 self.iopub_socket = context.socket(zmq.PUB)
210 self.iopub_port = self._bind_socket(self.iopub_socket, self.iopub_port)
210 self.iopub_port = self._bind_socket(self.iopub_socket, self.iopub_port)
211 self.log.debug("iopub PUB Channel on port: %i"%self.iopub_port)
211 self.log.debug("iopub PUB Channel on port: %i"%self.iopub_port)
212
212
213 self.stdin_socket = context.socket(zmq.ROUTER)
213 self.stdin_socket = context.socket(zmq.ROUTER)
214 self.stdin_port = self._bind_socket(self.stdin_socket, self.stdin_port)
214 self.stdin_port = self._bind_socket(self.stdin_socket, self.stdin_port)
215 self.log.debug("stdin ROUTER Channel on port: %i"%self.stdin_port)
215 self.log.debug("stdin ROUTER Channel on port: %i"%self.stdin_port)
216
216
217 self.heartbeat = Heartbeat(context, (self.ip, self.hb_port))
217 self.heartbeat = Heartbeat(context, (self.ip, self.hb_port))
218 self.hb_port = self.heartbeat.port
218 self.hb_port = self.heartbeat.port
219 self.log.debug("Heartbeat REP Channel on port: %i"%self.hb_port)
219 self.log.debug("Heartbeat REP Channel on port: %i"%self.hb_port)
220
220
221 # Helper to make it easier to connect to an existing kernel.
221 # Helper to make it easier to connect to an existing kernel.
222 # set log-level to critical, to make sure it is output
222 # set log-level to critical, to make sure it is output
223 self.log.critical("To connect another client to this kernel, use:")
223 self.log.critical("To connect another client to this kernel, use:")
224 if os.path.dirname(self.connection_file) == self.profile_dir.security_dir:
224
225 basename = os.path.basename(self.connection_file)
226 if basename == self.connection_file or \
227 os.path.dirname(self.connection_file) == self.profile_dir.security_dir:
225 # use shortname
228 # use shortname
226 tail = os.path.basename(self.connection_file)
229 tail = basename
227 if self.profile != 'default':
230 if self.profile != 'default':
228 tail += " --profile %s" % self.profile_name
231 tail += " --profile %s" % self.profile
229 else:
232 else:
230 tail = self.connection_file
233 tail = self.connection_file
231 self.log.critical("--existing %s", tail)
234 self.log.critical("--existing %s", tail)
232
235
233
236
234 self.ports = dict(shell=self.shell_port, iopub=self.iopub_port,
237 self.ports = dict(shell=self.shell_port, iopub=self.iopub_port,
235 stdin=self.stdin_port, hb=self.hb_port)
238 stdin=self.stdin_port, hb=self.hb_port)
236
239
237 def init_session(self):
240 def init_session(self):
238 """create our session object"""
241 """create our session object"""
239 default_secure(self.config)
242 default_secure(self.config)
240 self.session = Session(config=self.config, username=u'kernel')
243 self.session = Session(config=self.config, username=u'kernel')
241
244
242 def init_blackhole(self):
245 def init_blackhole(self):
243 """redirects stdout/stderr to devnull if necessary"""
246 """redirects stdout/stderr to devnull if necessary"""
244 if self.no_stdout or self.no_stderr:
247 if self.no_stdout or self.no_stderr:
245 blackhole = file(os.devnull, 'w')
248 blackhole = file(os.devnull, 'w')
246 if self.no_stdout:
249 if self.no_stdout:
247 sys.stdout = sys.__stdout__ = blackhole
250 sys.stdout = sys.__stdout__ = blackhole
248 if self.no_stderr:
251 if self.no_stderr:
249 sys.stderr = sys.__stderr__ = blackhole
252 sys.stderr = sys.__stderr__ = blackhole
250
253
251 def init_io(self):
254 def init_io(self):
252 """Redirect input streams and set a display hook."""
255 """Redirect input streams and set a display hook."""
253 if self.outstream_class:
256 if self.outstream_class:
254 outstream_factory = import_item(str(self.outstream_class))
257 outstream_factory = import_item(str(self.outstream_class))
255 sys.stdout = outstream_factory(self.session, self.iopub_socket, u'stdout')
258 sys.stdout = outstream_factory(self.session, self.iopub_socket, u'stdout')
256 sys.stderr = outstream_factory(self.session, self.iopub_socket, u'stderr')
259 sys.stderr = outstream_factory(self.session, self.iopub_socket, u'stderr')
257 if self.displayhook_class:
260 if self.displayhook_class:
258 displayhook_factory = import_item(str(self.displayhook_class))
261 displayhook_factory = import_item(str(self.displayhook_class))
259 sys.displayhook = displayhook_factory(self.session, self.iopub_socket)
262 sys.displayhook = displayhook_factory(self.session, self.iopub_socket)
260
263
261 def init_kernel(self):
264 def init_kernel(self):
262 """Create the Kernel object itself"""
265 """Create the Kernel object itself"""
263 kernel_factory = import_item(str(self.kernel_class))
266 kernel_factory = import_item(str(self.kernel_class))
264 self.kernel = kernel_factory(config=self.config, session=self.session,
267 self.kernel = kernel_factory(config=self.config, session=self.session,
265 shell_socket=self.shell_socket,
268 shell_socket=self.shell_socket,
266 iopub_socket=self.iopub_socket,
269 iopub_socket=self.iopub_socket,
267 stdin_socket=self.stdin_socket,
270 stdin_socket=self.stdin_socket,
268 log=self.log
271 log=self.log
269 )
272 )
270 self.kernel.record_ports(self.ports)
273 self.kernel.record_ports(self.ports)
271
274
272 def initialize(self, argv=None):
275 def initialize(self, argv=None):
273 super(KernelApp, self).initialize(argv)
276 super(KernelApp, self).initialize(argv)
274 self.init_blackhole()
277 self.init_blackhole()
275 self.init_connection_file()
278 self.init_connection_file()
276 self.init_session()
279 self.init_session()
277 self.init_poller()
280 self.init_poller()
278 self.init_sockets()
281 self.init_sockets()
279 # writing connection file must be *after* init_sockets
282 # writing connection file must be *after* init_sockets
280 self.write_connection_file()
283 self.write_connection_file()
281 self.init_io()
284 self.init_io()
282 self.init_kernel()
285 self.init_kernel()
283
286
284 def start(self):
287 def start(self):
285 self.heartbeat.start()
288 self.heartbeat.start()
286 if self.poller is not None:
289 if self.poller is not None:
287 self.poller.start()
290 self.poller.start()
288 try:
291 try:
289 self.kernel.start()
292 self.kernel.start()
290 except KeyboardInterrupt:
293 except KeyboardInterrupt:
291 pass
294 pass
292
295
General Comments 0
You need to be logged in to leave comments. Login now