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