##// END OF EJS Templates
use connection files instead of ports to connect to kernels...
MinRK -
Show More
@@ -17,6 +17,7 b' Authors:'
17 #-----------------------------------------------------------------------------
17 #-----------------------------------------------------------------------------
18
18
19 # stdlib imports
19 # stdlib imports
20 import glob
20 import os
21 import os
21 import signal
22 import signal
22 import sys
23 import sys
@@ -25,6 +26,7 b' from getpass import getpass'
25 # System library imports
26 # System library imports
26 from IPython.external.qt import QtGui
27 from IPython.external.qt import QtGui
27 from pygments.styles import get_all_styles
28 from pygments.styles import get_all_styles
29 from zmq.utils import jsonapi as json
28
30
29 # external imports
31 # external imports
30 from IPython.external.ssh import tunnel
32 from IPython.external.ssh import tunnel
@@ -39,6 +41,7 b' from IPython.frontend.qt.console.rich_ipython_widget import RichIPythonWidget'
39 from IPython.frontend.qt.console import styles
41 from IPython.frontend.qt.console import styles
40 from IPython.frontend.qt.kernelmanager import QtKernelManager
42 from IPython.frontend.qt.kernelmanager import QtKernelManager
41 from IPython.parallel.util import select_random_ports
43 from IPython.parallel.util import select_random_ports
44 from IPython.utils.path import filefind
42 from IPython.utils.traitlets import (
45 from IPython.utils.traitlets import (
43 Dict, List, Unicode, Int, CaselessStrEnum, CBool, Any
46 Dict, List, Unicode, Int, CaselessStrEnum, CBool, Any
44 )
47 )
@@ -182,8 +185,8 b' class MainWindow(QtGui.QMainWindow):'
182
185
183 flags = dict(ipkernel_flags)
186 flags = dict(ipkernel_flags)
184 qt_flags = {
187 qt_flags = {
185 'existing' : ({'IPythonQtConsoleApp' : {'existing' : True}},
188 'existing' : ({'IPythonQtConsoleApp' : {'existing' : 'kernel*.json'}},
186 "Connect to an existing kernel."),
189 "Connect to an existing kernel. If no argument specified, guess most recent"),
187 'pure' : ({'IPythonQtConsoleApp' : {'pure' : True}},
190 'pure' : ({'IPythonQtConsoleApp' : {'pure' : True}},
188 "Use a pure Python kernel instead of an IPython kernel."),
191 "Use a pure Python kernel instead of an IPython kernel."),
189 'plain' : ({'ConsoleWidget' : {'kind' : 'plain'}},
192 'plain' : ({'ConsoleWidget' : {'kind' : 'plain'}},
@@ -213,6 +216,8 b' qt_aliases = dict('
213 iopub = 'IPythonQtConsoleApp.iopub_port',
216 iopub = 'IPythonQtConsoleApp.iopub_port',
214 stdin = 'IPythonQtConsoleApp.stdin_port',
217 stdin = 'IPythonQtConsoleApp.stdin_port',
215 ip = 'IPythonQtConsoleApp.ip',
218 ip = 'IPythonQtConsoleApp.ip',
219 existing = 'IPythonQtConsoleApp.existing',
220 f = 'IPythonQtConsoleApp.connection_file',
216
221
217 style = 'IPythonWidget.syntax_style',
222 style = 'IPythonWidget.syntax_style',
218 stylesheet = 'IPythonQtConsoleApp.stylesheet',
223 stylesheet = 'IPythonQtConsoleApp.stylesheet',
@@ -280,9 +285,18 b' class IPythonQtConsoleApp(BaseIPythonApplication):'
280 help="set the iopub (PUB) port [default: random]")
285 help="set the iopub (PUB) port [default: random]")
281 stdin_port = Int(0, config=True,
286 stdin_port = Int(0, config=True,
282 help="set the stdin (XREQ) port [default: random]")
287 help="set the stdin (XREQ) port [default: random]")
288 connection_file = Unicode('', config=True,
289 help="""JSON file in which to store connection info [default: kernel-<pid>.json]
283
290
284 existing = CBool(False, config=True,
291 This file will contain the IP, ports, and authentication key needed to connect
285 help="Whether to connect to an already running Kernel.")
292 clients to this kernel. By default, this file will be created in the security-dir
293 of the current profile, but can be specified by absolute path.
294 """)
295 def _connection_file_default(self):
296 return 'kernel-%i.json' % os.getpid()
297
298 existing = Unicode('', config=True,
299 help="""Connect to an already running kernel""")
286
300
287 stylesheet = Unicode('', config=True,
301 stylesheet = Unicode('', config=True,
288 help="path to a custom CSS stylesheet")
302 help="path to a custom CSS stylesheet")
@@ -340,6 +354,58 b' class IPythonQtConsoleApp(BaseIPythonApplication):'
340 # alias passed with arg via space
354 # alias passed with arg via space
341 swallow_next = True
355 swallow_next = True
342
356
357 def init_connection_file(self):
358 sec = self.profile_dir.security_dir
359 if self.existing:
360 try:
361 # first, try explicit name
362 cf = filefind(self.existing, ['.', sec])
363 except IOError:
364 # not found by full name
365 if '*' in self.existing:
366 # given as a glob already
367 pat = self.existing
368 else:
369 # accept any substring match
370 pat = '*%s*'
371 matches = glob.glob( os.path.join(sec, pat) )
372 if not matches:
373 self.log.critical("Could not find existing kernel connection file %s", self.existing)
374 self.exit(1)
375 else:
376 # get most recent match:
377 cf = sorted(matches, key=lambda f: os.stat(f).st_atime)[-1]
378 self.log.info("Connecting to existing kernel: %s" % cf)
379 self.connection_file = cf
380 # should load_connection_file only be used for existing?
381 # as it is now, this allows reusing ports if an existing
382 # file is requested
383 self.load_connection_file()
384
385 def load_connection_file(self):
386 """load ip/port/hmac config from JSON connection file"""
387 # this is identical to KernelApp.load_connection_file
388 # perhaps it can be centralized somewhere?
389 try:
390 fname = filefind(self.connection_file, ['.', self.profile_dir.security_dir])
391 except IOError:
392 self.log.debug("Connection File not found: %s", self.connection_file)
393 return
394 self.log.debug(u"Loading connection file %s", fname)
395 with open(fname) as f:
396 s = f.read()
397 cfg = json.loads(s)
398 if self.ip == LOCALHOST and 'ip' in cfg:
399 # not overridden by config or cl_args
400 self.ip = cfg['ip']
401 for channel in ('hb', 'shell', 'iopub', 'stdin'):
402 name = channel + '_port'
403 if getattr(self, name) == 0 and name in cfg:
404 # not overridden by config or cl_args
405 setattr(self, name, cfg[name])
406 if 'key' in cfg:
407 self.config.Session.key = cfg['key']
408
343 def init_ssh(self):
409 def init_ssh(self):
344 """set up ssh tunnels, if needed."""
410 """set up ssh tunnels, if needed."""
345 if not self.sshserver and not self.sshkey:
411 if not self.sshserver and not self.sshkey:
@@ -374,18 +440,30 b' class IPythonQtConsoleApp(BaseIPythonApplication):'
374 def init_kernel_manager(self):
440 def init_kernel_manager(self):
375 # Don't let Qt or ZMQ swallow KeyboardInterupts.
441 # Don't let Qt or ZMQ swallow KeyboardInterupts.
376 signal.signal(signal.SIGINT, signal.SIG_DFL)
442 signal.signal(signal.SIGINT, signal.SIG_DFL)
443 sec = self.profile_dir.security_dir
444 try:
445 cf = filefind(self.connection_file, ['.', sec])
446 except IOError:
447 # file might not exist, use
448 if self.connection_file == os.path.basename(self.connection_file):
449 # just shortname, put it in security dir
450 cf = os.path.join(sec, self.connection_file)
451 else:
452 cf = self.connection_file
377
453
378 # Create a KernelManager and start a kernel.
454 # Create a KernelManager and start a kernel.
379 self.kernel_manager = QtKernelManager(ip=self.ip,
455 self.kernel_manager = QtKernelManager(
456 ip=self.ip,
380 shell_port=self.shell_port,
457 shell_port=self.shell_port,
381 sub_port=self.iopub_port,
458 sub_port=self.iopub_port,
382 stdin_port=self.stdin_port,
459 stdin_port=self.stdin_port,
383 hb_port=self.hb_port,
460 hb_port=self.hb_port,
461 connection_file=cf,
384 config=self.config,
462 config=self.config,
385 )
463 )
386 # start the kernel
464 # start the kernel
387 if not self.existing:
465 if not self.existing:
388 kwargs = dict(ip=self.ip, ipython=not self.pure)
466 kwargs = dict(ipython=not self.pure)
389 kwargs['extra_arguments'] = self.kernel_argv
467 kwargs['extra_arguments'] = self.kernel_argv
390 self.kernel_manager.start_kernel(**kwargs)
468 self.kernel_manager.start_kernel(**kwargs)
391 self.kernel_manager.start_channels()
469 self.kernel_manager.start_channels()
@@ -469,6 +547,7 b' class IPythonQtConsoleApp(BaseIPythonApplication):'
469 def initialize(self, argv=None):
547 def initialize(self, argv=None):
470 super(IPythonQtConsoleApp, self).initialize(argv)
548 super(IPythonQtConsoleApp, self).initialize(argv)
471 self.init_ssh()
549 self.init_ssh()
550 self.init_connection_file()
472 self.init_kernel_manager()
551 self.init_kernel_manager()
473 self.init_qt_elements()
552 self.init_qt_elements()
474 self.init_colors()
553 self.init_colors()
@@ -8,20 +8,26 b' import os'
8 import socket
8 import socket
9 from subprocess import Popen, PIPE
9 from subprocess import Popen, PIPE
10 import sys
10 import sys
11 import tempfile
11
12
12 # Local imports.
13 # System library imports
13 from parentpoller import ParentPollerWindows
14 from zmq.utils import jsonapi as json
14
15
16 # IPython imports
17 from IPython.utils.localinterfaces import LOCALHOST
15
18
16 def base_launch_kernel(code, shell_port=0, iopub_port=0, stdin_port=0, hb_port=0,
19 # Local imports.
17 ip=None, stdin=None, stdout=None, stderr=None,
20 from parentpoller import ParentPollerWindows
18 executable=None, independent=False, extra_arguments=[]):
19 """ Launches a localhost kernel, binding to the specified ports.
20
21
22 def write_connection_file(fname=None, shell_port=0, iopub_port=0, stdin_port=0, hb_port=0,
23 ip=LOCALHOST, key=''):
24 """Generates a JSON config file, including the selection of random ports.
25
21 Parameters
26 Parameters
22 ----------
27 ----------
23 code : str,
28
24 A string of Python code that imports and executes a kernel entry point.
29 fname : unicode
30 The path to the file to write
25
31
26 shell_port : int, optional
32 shell_port : int, optional
27 The port to use for XREP channel.
33 The port to use for XREP channel.
@@ -38,27 +44,14 b' def base_launch_kernel(code, shell_port=0, iopub_port=0, stdin_port=0, hb_port=0'
38 ip : str, optional
44 ip : str, optional
39 The ip address the kernel will bind to.
45 The ip address the kernel will bind to.
40
46
41 stdin, stdout, stderr : optional (default None)
47 key : str, optional
42 Standards streams, as defined in subprocess.Popen.
48 The Session key used for HMAC authentication.
43
49
44 executable : str, optional (default sys.executable)
45 The Python executable to use for the kernel process.
46
47 independent : bool, optional (default False)
48 If set, the kernel process is guaranteed to survive if this process
49 dies. If not set, an effort is made to ensure that the kernel is killed
50 when this process dies. Note that in this case it is still good practice
51 to kill kernels manually before exiting.
52
53 extra_arguments = list, optional
54 A list of extra arguments to pass when executing the launch code.
55
56 Returns
57 -------
58 A tuple of form:
59 (kernel_process, shell_port, iopub_port, stdin_port, hb_port)
60 where kernel_process is a Popen object and the ports are integers.
61 """
50 """
51 # default to temporary connector file
52 if not fname:
53 fname = tempfile.mktemp('.json')
54
62 # Find open ports as necessary.
55 # Find open ports as necessary.
63 ports = []
56 ports = []
64 ports_needed = int(shell_port <= 0) + int(iopub_port <= 0) + \
57 ports_needed = int(shell_port <= 0) + int(iopub_port <= 0) + \
@@ -79,15 +72,62 b' def base_launch_kernel(code, shell_port=0, iopub_port=0, stdin_port=0, hb_port=0'
79 stdin_port = ports.pop(0)
72 stdin_port = ports.pop(0)
80 if hb_port <= 0:
73 if hb_port <= 0:
81 hb_port = ports.pop(0)
74 hb_port = ports.pop(0)
75
76 cfg = dict( shell_port=shell_port,
77 iopub_port=iopub_port,
78 stdin_port=stdin_port,
79 hb_port=hb_port,
80 )
81 cfg['ip'] = ip
82 cfg['key'] = key
83
84 with open(fname, 'wb') as f:
85 f.write(json.dumps(cfg, indent=2))
86
87 return fname, cfg
88
89
90 def base_launch_kernel(code, fname, stdin=None, stdout=None, stderr=None,
91 executable=None, independent=False, extra_arguments=[]):
92 """ Launches a localhost kernel, binding to the specified ports.
93
94 Parameters
95 ----------
96 code : str,
97 A string of Python code that imports and executes a kernel entry point.
82
98
99 stdin, stdout, stderr : optional (default None)
100 Standards streams, as defined in subprocess.Popen.
101
102 fname : unicode, optional
103 The JSON connector file, containing ip/port/hmac key information.
104
105 key : str, optional
106 The Session key used for HMAC authentication.
107
108 executable : str, optional (default sys.executable)
109 The Python executable to use for the kernel process.
110
111 independent : bool, optional (default False)
112 If set, the kernel process is guaranteed to survive if this process
113 dies. If not set, an effort is made to ensure that the kernel is killed
114 when this process dies. Note that in this case it is still good practice
115 to kill kernels manually before exiting.
116
117 extra_arguments = list, optional
118 A list of extra arguments to pass when executing the launch code.
119
120 Returns
121 -------
122 A tuple of form:
123 (kernel_process, shell_port, iopub_port, stdin_port, hb_port)
124 where kernel_process is a Popen object and the ports are integers.
125 """
126
83 # Build the kernel launch command.
127 # Build the kernel launch command.
84 if executable is None:
128 if executable is None:
85 executable = sys.executable
129 executable = sys.executable
86 arguments = [ executable, '-c', code, '--shell=%i'%shell_port,
130 arguments = [ executable, '-c', code, '-f', fname ]
87 '--iopub=%i'%iopub_port, '--stdin=%i'%stdin_port,
88 '--hb=%i'%hb_port ]
89 if ip is not None:
90 arguments.append('--ip=%s'%ip)
91 arguments.extend(extra_arguments)
131 arguments.extend(extra_arguments)
92
132
93 # Popen will fail (sometimes with a deadlock) if stdin, stdout, and stderr
133 # Popen will fail (sometimes with a deadlock) if stdin, stdout, and stderr
@@ -164,4 +204,4 b' def base_launch_kernel(code, shell_port=0, iopub_port=0, stdin_port=0, hb_port=0'
164 if stderr is None:
204 if stderr is None:
165 proc.stderr.close()
205 proc.stderr.close()
166
206
167 return proc, shell_port, iopub_port, stdin_port, hb_port
207 return proc
@@ -21,6 +21,7 b' 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
25
25 # IPython imports.
26 # IPython imports.
26 from IPython.core.ultratb import FormattedTB
27 from IPython.core.ultratb import FormattedTB
@@ -29,10 +30,12 b' from IPython.core.application import ('
29 )
30 )
30 from IPython.utils import io
31 from IPython.utils import io
31 from IPython.utils.localinterfaces import LOCALHOST
32 from IPython.utils.localinterfaces import LOCALHOST
33 from IPython.utils.path import filefind
32 from IPython.utils.traitlets import (Any, Instance, Dict, Unicode, Int, Bool,
34 from IPython.utils.traitlets import (Any, Instance, Dict, Unicode, Int, Bool,
33 DottedObjectName)
35 DottedObjectName)
34 from IPython.utils.importstring import import_item
36 from IPython.utils.importstring import import_item
35 # local imports
37 # local imports
38 from IPython.zmq.entry_point import write_connection_file
36 from IPython.zmq.heartbeat import Heartbeat
39 from IPython.zmq.heartbeat import Heartbeat
37 from IPython.zmq.parentpoller import ParentPollerUnix, ParentPollerWindows
40 from IPython.zmq.parentpoller import ParentPollerUnix, ParentPollerWindows
38 from IPython.zmq.session import Session
41 from IPython.zmq.session import Session
@@ -49,6 +52,7 b' kernel_aliases.update({'
49 'shell' : 'KernelApp.shell_port',
52 'shell' : 'KernelApp.shell_port',
50 'iopub' : 'KernelApp.iopub_port',
53 'iopub' : 'KernelApp.iopub_port',
51 'stdin' : 'KernelApp.stdin_port',
54 'stdin' : 'KernelApp.stdin_port',
55 'f' : 'KernelApp.connection_file',
52 'parent': 'KernelApp.parent',
56 'parent': 'KernelApp.parent',
53 })
57 })
54 if sys.platform.startswith('win'):
58 if sys.platform.startswith('win'):
@@ -99,6 +103,13 b' class KernelApp(BaseIPythonApplication):'
99 shell_port = Int(0, config=True, help="set the shell (XREP) port [default: random]")
103 shell_port = Int(0, config=True, help="set the shell (XREP) port [default: random]")
100 iopub_port = Int(0, config=True, help="set the iopub (PUB) port [default: random]")
104 iopub_port = Int(0, config=True, help="set the iopub (PUB) port [default: random]")
101 stdin_port = Int(0, config=True, help="set the stdin (XREQ) port [default: random]")
105 stdin_port = Int(0, config=True, help="set the stdin (XREQ) port [default: random]")
106 connection_file = Unicode('', config=True,
107 help="""JSON file in which to store connection info [default: kernel-<pid>.json]
108
109 This file will contain the IP, ports, and authentication key needed to connect
110 clients to this kernel. By default, this file will be created in the security-dir
111 of the current profile, but can be specified by absolute path.
112 """)
102
113
103 # streams, etc.
114 # streams, etc.
104 no_stdout = Bool(False, config=True, help="redirect stdout to the null device")
115 no_stdout = Bool(False, config=True, help="redirect stdout to the null device")
@@ -138,6 +149,44 b' class KernelApp(BaseIPythonApplication):'
138 s.bind(iface + ':%i'%port)
149 s.bind(iface + ':%i'%port)
139 return port
150 return port
140
151
152 def load_connection_file(self):
153 """load ip/port/hmac config from JSON connection file"""
154 try:
155 fname = filefind(self.connection_file, ['.', self.profile_dir.security_dir])
156 except IOError:
157 self.log.debug("Connection file not found: %s", self.connection_file)
158 return
159 self.log.debug(u"Loading connection file %s", fname)
160 with open(fname) as f:
161 s = f.read()
162 cfg = json.loads(s)
163 if self.ip == LOCALHOST and 'ip' in cfg:
164 # not overridden by config or cl_args
165 self.ip = cfg['ip']
166 for channel in ('hb', 'shell', 'iopub', 'stdin'):
167 name = channel + '_port'
168 if getattr(self, name) == 0 and name in cfg:
169 # not overridden by config or cl_args
170 setattr(self, name, cfg[name])
171 if 'key' in cfg:
172 self.config.Session.key = cfg['key']
173
174 def write_connection_file(self):
175 """write connection info to JSON file"""
176 if os.path.basename(self.connection_file) == self.connection_file:
177 cf = os.path.join(self.profile_dir.security_dir, self.connection_file)
178 else:
179 cf = self.connection_file
180 write_connection_file(cf, ip=self.ip, key=self.session.key,
181 shell_port=self.shell_port, stdin_port=self.stdin_port, hb_port=self.hb_port,
182 iopub_port=self.iopub_port)
183
184 def init_connection_file(self):
185 if not self.connection_file:
186 self.connection_file = "kernel-%s.json"%os.getpid()
187
188 self.load_connection_file()
189
141 def init_sockets(self):
190 def init_sockets(self):
142 # Create a context, a session, and the kernel sockets.
191 # Create a context, a session, and the kernel sockets.
143 self.log.info("Starting the kernel at pid: %i", os.getpid())
192 self.log.info("Starting the kernel at pid: %i", os.getpid())
@@ -161,12 +210,17 b' class KernelApp(BaseIPythonApplication):'
161 self.hb_port = self.heartbeat.port
210 self.hb_port = self.heartbeat.port
162 self.log.debug("Heartbeat REP Channel on port: %i"%self.hb_port)
211 self.log.debug("Heartbeat REP Channel on port: %i"%self.hb_port)
163
212
164 # Helper to make it easier to connect to an existing kernel, until we have
213 # Helper to make it easier to connect to an existing kernel.
165 # single-port connection negotiation fully implemented.
166 # set log-level to critical, to make sure it is output
214 # set log-level to critical, to make sure it is output
167 self.log.critical("To connect another client to this kernel, use:")
215 self.log.critical("To connect another client to this kernel, use:")
168 self.log.critical("--existing --shell={0} --iopub={1} --stdin={2} --hb={3}".format(
216 if os.path.dirname(self.connection_file) == self.profile_dir.security_dir:
169 self.shell_port, self.iopub_port, self.stdin_port, self.hb_port))
217 # use shortname
218 tail = os.path.basename(self.connection_file)
219 if self.profile != 'default':
220 tail += " --profile %s" % self.profile_name
221 else:
222 tail = self.connection_file
223 self.log.critical("--existing %s", tail)
170
224
171
225
172 self.ports = dict(shell=self.shell_port, iopub=self.iopub_port,
226 self.ports = dict(shell=self.shell_port, iopub=self.iopub_port,
@@ -209,9 +263,12 b' class KernelApp(BaseIPythonApplication):'
209 def initialize(self, argv=None):
263 def initialize(self, argv=None):
210 super(KernelApp, self).initialize(argv)
264 super(KernelApp, self).initialize(argv)
211 self.init_blackhole()
265 self.init_blackhole()
266 self.init_connection_file()
212 self.init_session()
267 self.init_session()
213 self.init_poller()
268 self.init_poller()
214 self.init_sockets()
269 self.init_sockets()
270 # writing connection file must be *after* init_sockets
271 self.write_connection_file()
215 self.init_io()
272 self.init_io()
216 self.init_kernel()
273 self.init_kernel()
217
274
@@ -19,6 +19,7 b' TODO'
19 import errno
19 import errno
20 from Queue import Queue, Empty
20 from Queue import Queue, Empty
21 from subprocess import Popen
21 from subprocess import Popen
22 import os
22 import signal
23 import signal
23 import sys
24 import sys
24 from threading import Thread
25 from threading import Thread
@@ -32,7 +33,10 b' from zmq.eventloop import ioloop'
32 # Local imports.
33 # Local imports.
33 from IPython.config.loader import Config
34 from IPython.config.loader import Config
34 from IPython.utils.localinterfaces import LOCALHOST, LOCAL_IPS
35 from IPython.utils.localinterfaces import LOCALHOST, LOCAL_IPS
35 from IPython.utils.traitlets import HasTraits, Any, Instance, Type, Unicode, Int
36 from IPython.utils.traitlets import (
37 HasTraits, Any, Instance, Type, Unicode, Int, Bool
38 )
39 from IPython.zmq.entry_point import write_connection_file
36 from session import Session
40 from session import Session
37
41
38 #-----------------------------------------------------------------------------
42 #-----------------------------------------------------------------------------
@@ -702,6 +706,7 b' class KernelManager(HasTraits):'
702 kernel = Instance(Popen)
706 kernel = Instance(Popen)
703
707
704 # The addresses for the communication channels.
708 # The addresses for the communication channels.
709 connection_file = Unicode('')
705 ip = Unicode(LOCALHOST)
710 ip = Unicode(LOCALHOST)
706 shell_port = Int(0)
711 shell_port = Int(0)
707 sub_port = Int(0)
712 sub_port = Int(0)
@@ -720,13 +725,22 b' class KernelManager(HasTraits):'
720 _sub_channel = Any
725 _sub_channel = Any
721 _stdin_channel = Any
726 _stdin_channel = Any
722 _hb_channel = Any
727 _hb_channel = Any
728 _connection_file_written=Bool(False)
723
729
724 def __init__(self, **kwargs):
730 def __init__(self, **kwargs):
725 super(KernelManager, self).__init__(**kwargs)
731 super(KernelManager, self).__init__(**kwargs)
726 if self.session is None:
732 if self.session is None:
727 self.session = Session(config=self.config)
733 self.session = Session(config=self.config)
728 # Uncomment this to try closing the context.
734
729 # atexit.register(self.context.term)
735 def __del__(self):
736 if self._connection_file_written:
737 # cleanup connection files on full shutdown of kernel we started
738 self._connection_file_written = False
739 try:
740 os.remove(self.connection_file)
741 except IOError:
742 pass
743
730
744
731 #--------------------------------------------------------------------------
745 #--------------------------------------------------------------------------
732 # Channel management methods:
746 # Channel management methods:
@@ -773,7 +787,22 b' class KernelManager(HasTraits):'
773 #--------------------------------------------------------------------------
787 #--------------------------------------------------------------------------
774 # Kernel process management methods:
788 # Kernel process management methods:
775 #--------------------------------------------------------------------------
789 #--------------------------------------------------------------------------
776
790
791 def write_connection_file(self):
792 if self._connection_file_written:
793 return
794 self.connection_file,cfg = write_connection_file(self.connection_file,
795 ip=self.ip, key=self.session.key,
796 stdin_port=self.stdin_port, iopub_port=self.sub_port,
797 shell_port=self.shell_port, hb_port=self.hb_port)
798 # write_connection_file also sets default ports:
799 self.shell_port = cfg['shell_port']
800 self.stdin_port = cfg['stdin_port']
801 self.sub_port = cfg['iopub_port']
802 self.hb_port = cfg['hb_port']
803
804 self._connection_file_written = True
805
777 def start_kernel(self, **kw):
806 def start_kernel(self, **kw):
778 """Starts a kernel process and configures the manager to use it.
807 """Starts a kernel process and configures the manager to use it.
779
808
@@ -799,6 +828,9 b' class KernelManager(HasTraits):'
799 "configured properly. "
828 "configured properly. "
800 "Currently valid addresses are: %s"%LOCAL_IPS
829 "Currently valid addresses are: %s"%LOCAL_IPS
801 )
830 )
831
832 # write connection file / get default ports
833 self.write_connection_file()
802
834
803 self._launch_args = kw.copy()
835 self._launch_args = kw.copy()
804 launch_kernel = kw.pop('launcher', None)
836 launch_kernel = kw.pop('launcher', None)
@@ -807,13 +839,7 b' class KernelManager(HasTraits):'
807 from ipkernel import launch_kernel
839 from ipkernel import launch_kernel
808 else:
840 else:
809 from pykernel import launch_kernel
841 from pykernel import launch_kernel
810 self.kernel, shell, sub, stdin, hb = launch_kernel(
842 self.kernel = launch_kernel(fname=self.connection_file, **kw)
811 shell_port=self.shell_port, iopub_port=self.sub_port,
812 stdin_port=self.stdin_port, hb_port=self.hb_port, **kw)
813 self.shell_port = shell
814 self.sub_port = sub
815 self.stdin_port = stdin
816 self.hb_port = hb
817
843
818 def shutdown_kernel(self, restart=False):
844 def shutdown_kernel(self, restart=False):
819 """ Attempts to the stop the kernel process cleanly. If the kernel
845 """ Attempts to the stop the kernel process cleanly. If the kernel
@@ -842,6 +868,14 b' class KernelManager(HasTraits):'
842 if self.has_kernel:
868 if self.has_kernel:
843 self.kill_kernel()
869 self.kill_kernel()
844
870
871 if not restart and self._connection_file_written:
872 # cleanup connection files on full shutdown of kernel we started
873 self._connection_file_written = False
874 try:
875 os.remove(self.connection_file)
876 except IOError:
877 pass
878
845 def restart_kernel(self, now=False, **kw):
879 def restart_kernel(self, now=False, **kw):
846 """Restarts a kernel with the arguments that were used to launch it.
880 """Restarts a kernel with the arguments that were used to launch it.
847
881
General Comments 0
You need to be logged in to leave comments. Login now