##// END OF EJS Templates
refactoring common code out of qtconsole
Paul Ivanov -
Show More
@@ -0,0 +1,366 b''
1 """ A minimal application base mixin for all ZMQ based IPython frontends.
2
3 This is not a complete console app, as subprocess will not be able to receive
4 input, there is no real readline support, among other limitations. This is a
5 refactoring of what used to be the IPython/frontend/qt/console/qtconsoleapp.py
6
7 Authors:
8
9 * Evan Patterson
10 * Min RK
11 * Erik Tollerud
12 * Fernando Perez
13 * Bussonnier Matthias
14 * Thomas Kluyver
15 * Paul Ivanov
16
17 """
18
19 #-----------------------------------------------------------------------------
20 # Imports
21 #-----------------------------------------------------------------------------
22
23 # stdlib imports
24 import json
25 import os
26 import signal
27 import sys
28 import uuid
29
30
31 # Local imports
32 from IPython.config.application import boolean_flag
33 from IPython.config.configurable import Configurable
34 from IPython.core.profiledir import ProfileDir
35 from IPython.lib.kernel import tunnel_to_kernel, find_connection_file
36 from IPython.zmq.blockingkernelmanager import BlockingKernelManager
37 from IPython.utils.path import filefind
38 from IPython.utils.py3compat import str_to_bytes
39 from IPython.utils.traitlets import (
40 Dict, List, Unicode, CUnicode, Int, CBool, Any
41 )
42 from IPython.zmq.ipkernel import (
43 flags as ipkernel_flags,
44 aliases as ipkernel_aliases,
45 IPKernelApp
46 )
47 from IPython.zmq.session import Session, default_secure
48 from IPython.zmq.zmqshell import ZMQInteractiveShell
49
50 #-----------------------------------------------------------------------------
51 # Network Constants
52 #-----------------------------------------------------------------------------
53
54 from IPython.utils.localinterfaces import LOCALHOST, LOCAL_IPS
55
56 #-----------------------------------------------------------------------------
57 # Globals
58 #-----------------------------------------------------------------------------
59
60
61 #-----------------------------------------------------------------------------
62 # Aliases and Flags
63 #-----------------------------------------------------------------------------
64
65 flags = dict(ipkernel_flags)
66 app_flags = {
67 'existing' : ({'IPythonMixinConsoleApp' : {'existing' : 'kernel*.json'}},
68 "Connect to an existing kernel. If no argument specified, guess most recent"),
69 'pure' : ({'IPythonMixinConsoleApp' : {'pure' : True}},
70 "Use a pure Python kernel instead of an IPython kernel."),
71 'plain' : ({'ConsoleWidget' : {'kind' : 'plain'}},
72 "Disable rich text support."),
73 }
74 app_flags.update(boolean_flag(
75 'confirm-exit', 'IPythonMixinConsoleApp.confirm_exit',
76 """Set to display confirmation dialog on exit. You can always use 'exit' or 'quit',
77 to force a direct exit without any confirmation.
78 """,
79 """Don't prompt the user when exiting. This will terminate the kernel
80 if it is owned by the frontend, and leave it alive if it is external.
81 """
82 ))
83 flags.update(app_flags)
84
85 aliases = dict(ipkernel_aliases)
86
87 app_aliases = dict(
88 hb = 'IPythonMixinConsoleApp.hb_port',
89 shell = 'IPythonMixinConsoleApp.shell_port',
90 iopub = 'IPythonMixinConsoleApp.iopub_port',
91 stdin = 'IPythonMixinConsoleApp.stdin_port',
92 ip = 'IPythonMixinConsoleApp.ip',
93 existing = 'IPythonMixinConsoleApp.existing',
94 f = 'IPythonMixinConsoleApp.connection_file',
95
96
97 ssh = 'IPythonMixinConsoleApp.sshserver',
98 )
99 aliases.update(app_aliases)
100
101 #-----------------------------------------------------------------------------
102 # Classes
103 #-----------------------------------------------------------------------------
104
105 #-----------------------------------------------------------------------------
106 # IPythonMixinConsole
107 #-----------------------------------------------------------------------------
108
109
110 class IPythonMixinConsoleApp(Configurable):
111 name = 'ipython-console-mixin'
112 default_config_file_name='ipython_config.py'
113
114 description = """
115 The IPython Mixin Console.
116
117 This class contains the common portions of console client (QtConsole,
118 ZMQ-based terminal console, etc). It is not a full console, in that
119 launched terminal subprocesses will not be able to accept input.
120
121 The Console using this mixing supports various extra features beyond
122 the single-process Terminal IPython shell, such as connecting to
123 existing kernel, via:
124
125 ipython <appname> --existing
126
127 as well as tunnel via SSH
128
129 """
130
131 classes = [IPKernelApp, ZMQInteractiveShell, ProfileDir, Session]
132 flags = Dict(flags)
133 aliases = Dict(aliases)
134 kernel_manager_class = BlockingKernelManager
135
136 kernel_argv = List(Unicode)
137
138 # create requested profiles by default, if they don't exist:
139 auto_create = CBool(True)
140 # connection info:
141 ip = Unicode(LOCALHOST, config=True,
142 help="""Set the kernel\'s IP address [default localhost].
143 If the IP address is something other than localhost, then
144 Consoles on other machines will be able to connect
145 to the Kernel, so be careful!"""
146 )
147
148 sshserver = Unicode('', config=True,
149 help="""The SSH server to use to connect to the kernel.""")
150 sshkey = Unicode('', config=True,
151 help="""Path to the ssh key to use for logging in to the ssh server.""")
152
153 hb_port = Int(0, config=True,
154 help="set the heartbeat port [default: random]")
155 shell_port = Int(0, config=True,
156 help="set the shell (XREP) port [default: random]")
157 iopub_port = Int(0, config=True,
158 help="set the iopub (PUB) port [default: random]")
159 stdin_port = Int(0, config=True,
160 help="set the stdin (XREQ) port [default: random]")
161 connection_file = Unicode('', config=True,
162 help="""JSON file in which to store connection info [default: kernel-<pid>.json]
163
164 This file will contain the IP, ports, and authentication key needed to connect
165 clients to this kernel. By default, this file will be created in the security-dir
166 of the current profile, but can be specified by absolute path.
167 """)
168 def _connection_file_default(self):
169 return 'kernel-%i.json' % os.getpid()
170
171 existing = CUnicode('', config=True,
172 help="""Connect to an already running kernel""")
173
174 confirm_exit = CBool(True, config=True,
175 help="""
176 Set to display confirmation dialog on exit. You can always use 'exit' or 'quit',
177 to force a direct exit without any confirmation.""",
178 )
179
180
181 def parse_command_line(self, argv=None):
182 super(PythonBaseConsoleApp, self).parse_command_line(argv)
183 # make this stuff after this a function, in case the super stuff goes
184 # away. Also, Min notes that this functionality should be moved to a
185 # generic library of kernel stuff
186 if argv is None:
187 argv = sys.argv[1:]
188 self.kernel_argv = list(argv) # copy
189 # kernel should inherit default config file from frontend
190 self.kernel_argv.append("--KernelApp.parent_appname='%s'"%self.name)
191 # Scrub frontend-specific flags
192 swallow_next = False
193 was_flag = False
194 # copy again, in case some aliases have the same name as a flag
195 # argv = list(self.kernel_argv)
196 for a in argv:
197 if swallow_next:
198 swallow_next = False
199 # last arg was an alias, remove the next one
200 # *unless* the last alias has a no-arg flag version, in which
201 # case, don't swallow the next arg if it's also a flag:
202 if not (was_flag and a.startswith('-')):
203 self.kernel_argv.remove(a)
204 continue
205 if a.startswith('-'):
206 split = a.lstrip('-').split('=')
207 alias = split[0]
208 if alias in qt_aliases:
209 self.kernel_argv.remove(a)
210 if len(split) == 1:
211 # alias passed with arg via space
212 swallow_next = True
213 # could have been a flag that matches an alias, e.g. `existing`
214 # in which case, we might not swallow the next arg
215 was_flag = alias in qt_flags
216 elif alias in qt_flags:
217 # strip flag, but don't swallow next, as flags don't take args
218 self.kernel_argv.remove(a)
219
220 def init_connection_file(self):
221 """find the connection file, and load the info if found.
222
223 The current working directory and the current profile's security
224 directory will be searched for the file if it is not given by
225 absolute path.
226
227 When attempting to connect to an existing kernel and the `--existing`
228 argument does not match an existing file, it will be interpreted as a
229 fileglob, and the matching file in the current profile's security dir
230 with the latest access time will be used.
231 """
232 if self.existing:
233 try:
234 cf = find_connection_file(self.existing)
235 except Exception:
236 self.log.critical("Could not find existing kernel connection file %s", self.existing)
237 self.exit(1)
238 self.log.info("Connecting to existing kernel: %s" % cf)
239 self.connection_file = cf
240 # should load_connection_file only be used for existing?
241 # as it is now, this allows reusing ports if an existing
242 # file is requested
243 try:
244 self.load_connection_file()
245 except Exception:
246 self.log.error("Failed to load connection file: %r", self.connection_file, exc_info=True)
247 self.exit(1)
248
249 def load_connection_file(self):
250 """load ip/port/hmac config from JSON connection file"""
251 # this is identical to KernelApp.load_connection_file
252 # perhaps it can be centralized somewhere?
253 try:
254 fname = filefind(self.connection_file, ['.', self.profile_dir.security_dir])
255 except IOError:
256 self.log.debug("Connection File not found: %s", self.connection_file)
257 return
258 self.log.debug(u"Loading connection file %s", fname)
259 with open(fname) as f:
260 s = f.read()
261 cfg = json.loads(s)
262 if self.ip == LOCALHOST and 'ip' in cfg:
263 # not overridden by config or cl_args
264 self.ip = cfg['ip']
265 for channel in ('hb', 'shell', 'iopub', 'stdin'):
266 name = channel + '_port'
267 if getattr(self, name) == 0 and name in cfg:
268 # not overridden by config or cl_args
269 setattr(self, name, cfg[name])
270 if 'key' in cfg:
271 self.config.Session.key = str_to_bytes(cfg['key'])
272
273 def init_ssh(self):
274 """set up ssh tunnels, if needed."""
275 if not self.sshserver and not self.sshkey:
276 return
277
278 if self.sshkey and not self.sshserver:
279 # specifying just the key implies that we are connecting directly
280 self.sshserver = self.ip
281 self.ip = LOCALHOST
282
283 # build connection dict for tunnels:
284 info = dict(ip=self.ip,
285 shell_port=self.shell_port,
286 iopub_port=self.iopub_port,
287 stdin_port=self.stdin_port,
288 hb_port=self.hb_port
289 )
290
291 self.log.info("Forwarding connections to %s via %s"%(self.ip, self.sshserver))
292
293 # tunnels return a new set of ports, which will be on localhost:
294 self.ip = LOCALHOST
295 try:
296 newports = tunnel_to_kernel(info, self.sshserver, self.sshkey)
297 except:
298 # even catch KeyboardInterrupt
299 self.log.error("Could not setup tunnels", exc_info=True)
300 self.exit(1)
301
302 self.shell_port, self.iopub_port, self.stdin_port, self.hb_port = newports
303
304 cf = self.connection_file
305 base,ext = os.path.splitext(cf)
306 base = os.path.basename(base)
307 self.connection_file = os.path.basename(base)+'-ssh'+ext
308 self.log.critical("To connect another client via this tunnel, use:")
309 self.log.critical("--existing %s" % self.connection_file)
310
311 def _new_connection_file(self):
312 return os.path.join(self.profile_dir.security_dir, 'kernel-%s.json' % uuid.uuid4())
313
314 def init_kernel_manager(self):
315 # Don't let Qt or ZMQ swallow KeyboardInterupts.
316 signal.signal(signal.SIGINT, signal.SIG_DFL)
317 sec = self.profile_dir.security_dir
318 try:
319 cf = filefind(self.connection_file, ['.', sec])
320 except IOError:
321 # file might not exist
322 if self.connection_file == os.path.basename(self.connection_file):
323 # just shortname, put it in security dir
324 cf = os.path.join(sec, self.connection_file)
325 else:
326 cf = self.connection_file
327
328 # Create a KernelManager and start a kernel.
329 self.kernel_manager = self.kernel_manager_class(
330 ip=self.ip,
331 shell_port=self.shell_port,
332 iopub_port=self.iopub_port,
333 stdin_port=self.stdin_port,
334 hb_port=self.hb_port,
335 connection_file=cf,
336 config=self.config,
337 )
338 # start the kernel
339 if not self.existing:
340 kwargs = dict(ipython=not self.pure)
341 kwargs['extra_arguments'] = self.kernel_argv
342 self.kernel_manager.start_kernel(**kwargs)
343 elif self.sshserver:
344 # ssh, write new connection file
345 self.kernel_manager.write_connection_file()
346 self.kernel_manager.start_channels()
347
348
349 def initialize(self, argv=None):
350 super(IPythonMixinConsoleApp, self).initialize(argv)
351 self.init_connection_file()
352 default_secure(self.config)
353 self.init_ssh()
354 self.init_kernel_manager()
355 self.init_colors()
356
357 #-----------------------------------------------------------------------------
358 # Main entry point
359 #-----------------------------------------------------------------------------
360
361 def main():
362 raise NotImplementedError
363
364
365 if __name__ == '__main__':
366 main()
@@ -11,6 +11,7 b' Authors:'
11 * Fernando Perez
11 * Fernando Perez
12 * Bussonnier Matthias
12 * Bussonnier Matthias
13 * Thomas Kluyver
13 * Thomas Kluyver
14 * Paul Ivanov
14
15
15 """
16 """
16
17
@@ -44,13 +45,12 b' from IPython.utils.py3compat import str_to_bytes'
44 from IPython.utils.traitlets import (
45 from IPython.utils.traitlets import (
45 Dict, List, Unicode, Integer, CaselessStrEnum, CBool, Any
46 Dict, List, Unicode, Integer, CaselessStrEnum, CBool, Any
46 )
47 )
47 from IPython.zmq.ipkernel import (
48 from IPython.zmq.ipkernel import IPKernelApp
48 flags as ipkernel_flags,
49 aliases as ipkernel_aliases,
50 IPKernelApp
51 )
52 from IPython.zmq.session import Session, default_secure
49 from IPython.zmq.session import Session, default_secure
53 from IPython.zmq.zmqshell import ZMQInteractiveShell
50 from IPython.zmq.zmqshell import ZMQInteractiveShell
51 from IPython.frontend.kernelmixinapp import (
52 IPythonMixinConsoleApp, app_aliases, app_flags
53 )
54
54
55 #-----------------------------------------------------------------------------
55 #-----------------------------------------------------------------------------
56 # Network Constants
56 # Network Constants
@@ -71,10 +71,10 b' ipython qtconsole --pylab=inline # start with pylab in inline plotting mode'
71 # Aliases and Flags
71 # Aliases and Flags
72 #-----------------------------------------------------------------------------
72 #-----------------------------------------------------------------------------
73
73
74 flags = dict(ipkernel_flags)
74 flags = dict(app_flags)
75 qt_flags = {
75 qt_flags = {
76 'existing' : ({'IPythonQtConsoleApp' : {'existing' : 'kernel*.json'}},
76 #'existing' : ({'IPythonQtConsoleApp' : {'existing' : 'kernel*.json'}},
77 "Connect to an existing kernel. If no argument specified, guess most recent"),
77 # "Connect to an existing kernel. If no argument specified, guess most recent"),
78 'pure' : ({'IPythonQtConsoleApp' : {'pure' : True}},
78 'pure' : ({'IPythonQtConsoleApp' : {'pure' : True}},
79 "Use a pure Python kernel instead of an IPython kernel."),
79 "Use a pure Python kernel instead of an IPython kernel."),
80 'plain' : ({'ConsoleWidget' : {'kind' : 'plain'}},
80 'plain' : ({'ConsoleWidget' : {'kind' : 'plain'}},
@@ -85,25 +85,11 b' qt_flags.update(boolean_flag('
85 "use a GUI widget for tab completion",
85 "use a GUI widget for tab completion",
86 "use plaintext output for completion"
86 "use plaintext output for completion"
87 ))
87 ))
88 qt_flags.update(boolean_flag(
89 'confirm-exit', 'IPythonQtConsoleApp.confirm_exit',
90 """Set to display confirmation dialog on exit. You can always use 'exit' or 'quit',
91 to force a direct exit without any confirmation.
92 """,
93 """Don't prompt the user when exiting. This will terminate the kernel
94 if it is owned by the frontend, and leave it alive if it is external.
95 """
96 ))
97 flags.update(qt_flags)
88 flags.update(qt_flags)
98
89
99 aliases = dict(ipkernel_aliases)
90 aliases = dict(app_aliases)
100
91
101 qt_aliases = dict(
92 qt_aliases = dict(
102 hb = 'IPythonQtConsoleApp.hb_port',
103 shell = 'IPythonQtConsoleApp.shell_port',
104 iopub = 'IPythonQtConsoleApp.iopub_port',
105 stdin = 'IPythonQtConsoleApp.stdin_port',
106 ip = 'IPythonQtConsoleApp.ip',
107 existing = 'IPythonQtConsoleApp.existing',
93 existing = 'IPythonQtConsoleApp.existing',
108 f = 'IPythonQtConsoleApp.connection_file',
94 f = 'IPythonQtConsoleApp.connection_file',
109
95
@@ -113,7 +99,6 b' qt_aliases = dict('
113
99
114 editor = 'IPythonWidget.editor',
100 editor = 'IPythonWidget.editor',
115 paging = 'ConsoleWidget.paging',
101 paging = 'ConsoleWidget.paging',
116 ssh = 'IPythonQtConsoleApp.sshserver',
117 )
102 )
118 aliases.update(qt_aliases)
103 aliases.update(qt_aliases)
119
104
@@ -126,7 +111,7 b' aliases.update(qt_aliases)'
126 #-----------------------------------------------------------------------------
111 #-----------------------------------------------------------------------------
127
112
128
113
129 class IPythonQtConsoleApp(BaseIPythonApplication):
114 class IPythonQtConsoleApp(BaseIPythonApplication, IPythonMixinConsoleApp):
130 name = 'ipython-qtconsole'
115 name = 'ipython-qtconsole'
131 default_config_file_name='ipython_config.py'
116 default_config_file_name='ipython_config.py'
132
117
@@ -150,44 +135,7 b' class IPythonQtConsoleApp(BaseIPythonApplication):'
150 classes = [IPKernelApp, IPythonWidget, ZMQInteractiveShell, ProfileDir, Session]
135 classes = [IPKernelApp, IPythonWidget, ZMQInteractiveShell, ProfileDir, Session]
151 flags = Dict(flags)
136 flags = Dict(flags)
152 aliases = Dict(aliases)
137 aliases = Dict(aliases)
153
138 kernel_manager_class = QtKernelManager
154 kernel_argv = List(Unicode)
155
156 # create requested profiles by default, if they don't exist:
157 auto_create = CBool(True)
158 # connection info:
159 ip = Unicode(LOCALHOST, config=True,
160 help="""Set the kernel\'s IP address [default localhost].
161 If the IP address is something other than localhost, then
162 Consoles on other machines will be able to connect
163 to the Kernel, so be careful!"""
164 )
165
166 sshserver = Unicode('', config=True,
167 help="""The SSH server to use to connect to the kernel.""")
168 sshkey = Unicode('', config=True,
169 help="""Path to the ssh key to use for logging in to the ssh server.""")
170
171 hb_port = Integer(0, config=True,
172 help="set the heartbeat port [default: random]")
173 shell_port = Integer(0, config=True,
174 help="set the shell (XREP) port [default: random]")
175 iopub_port = Integer(0, config=True,
176 help="set the iopub (PUB) port [default: random]")
177 stdin_port = Integer(0, config=True,
178 help="set the stdin (XREQ) port [default: random]")
179 connection_file = Unicode('', config=True,
180 help="""JSON file in which to store connection info [default: kernel-<pid>.json]
181
182 This file will contain the IP, ports, and authentication key needed to connect
183 clients to this kernel. By default, this file will be created in the security-dir
184 of the current profile, but can be specified by absolute path.
185 """)
186 def _connection_file_default(self):
187 return 'kernel-%i.json' % os.getpid()
188
189 existing = Unicode('', config=True,
190 help="""Connect to an already running kernel""")
191
139
192 stylesheet = Unicode('', config=True,
140 stylesheet = Unicode('', config=True,
193 help="path to a custom CSS stylesheet")
141 help="path to a custom CSS stylesheet")
@@ -254,133 +202,7 b' class IPythonQtConsoleApp(BaseIPythonApplication):'
254 # strip flag, but don't swallow next, as flags don't take args
202 # strip flag, but don't swallow next, as flags don't take args
255 self.kernel_argv.remove(a)
203 self.kernel_argv.remove(a)
256
204
257 def init_connection_file(self):
258 """find the connection file, and load the info if found.
259
260 The current working directory and the current profile's security
261 directory will be searched for the file if it is not given by
262 absolute path.
263
264 When attempting to connect to an existing kernel and the `--existing`
265 argument does not match an existing file, it will be interpreted as a
266 fileglob, and the matching file in the current profile's security dir
267 with the latest access time will be used.
268 """
269 if self.existing:
270 try:
271 cf = find_connection_file(self.existing)
272 except Exception:
273 self.log.critical("Could not find existing kernel connection file %s", self.existing)
274 self.exit(1)
275 self.log.info("Connecting to existing kernel: %s" % cf)
276 self.connection_file = cf
277 # should load_connection_file only be used for existing?
278 # as it is now, this allows reusing ports if an existing
279 # file is requested
280 try:
281 self.load_connection_file()
282 except Exception:
283 self.log.error("Failed to load connection file: %r", self.connection_file, exc_info=True)
284 self.exit(1)
285
286 def load_connection_file(self):
287 """load ip/port/hmac config from JSON connection file"""
288 # this is identical to KernelApp.load_connection_file
289 # perhaps it can be centralized somewhere?
290 try:
291 fname = filefind(self.connection_file, ['.', self.profile_dir.security_dir])
292 except IOError:
293 self.log.debug("Connection File not found: %s", self.connection_file)
294 return
295 self.log.debug(u"Loading connection file %s", fname)
296 with open(fname) as f:
297 s = f.read()
298 cfg = json.loads(s)
299 if self.ip == LOCALHOST and 'ip' in cfg:
300 # not overridden by config or cl_args
301 self.ip = cfg['ip']
302 for channel in ('hb', 'shell', 'iopub', 'stdin'):
303 name = channel + '_port'
304 if getattr(self, name) == 0 and name in cfg:
305 # not overridden by config or cl_args
306 setattr(self, name, cfg[name])
307 if 'key' in cfg:
308 self.config.Session.key = str_to_bytes(cfg['key'])
309
310 def init_ssh(self):
311 """set up ssh tunnels, if needed."""
312 if not self.sshserver and not self.sshkey:
313 return
314
315 if self.sshkey and not self.sshserver:
316 # specifying just the key implies that we are connecting directly
317 self.sshserver = self.ip
318 self.ip = LOCALHOST
319
320 # build connection dict for tunnels:
321 info = dict(ip=self.ip,
322 shell_port=self.shell_port,
323 iopub_port=self.iopub_port,
324 stdin_port=self.stdin_port,
325 hb_port=self.hb_port
326 )
327
328 self.log.info("Forwarding connections to %s via %s"%(self.ip, self.sshserver))
329
330 # tunnels return a new set of ports, which will be on localhost:
331 self.ip = LOCALHOST
332 try:
333 newports = tunnel_to_kernel(info, self.sshserver, self.sshkey)
334 except:
335 # even catch KeyboardInterrupt
336 self.log.error("Could not setup tunnels", exc_info=True)
337 self.exit(1)
338
339 self.shell_port, self.iopub_port, self.stdin_port, self.hb_port = newports
340
341 cf = self.connection_file
342 base,ext = os.path.splitext(cf)
343 base = os.path.basename(base)
344 self.connection_file = os.path.basename(base)+'-ssh'+ext
345 self.log.critical("To connect another client via this tunnel, use:")
346 self.log.critical("--existing %s" % self.connection_file)
347
348 def _new_connection_file(self):
349 return os.path.join(self.profile_dir.security_dir, 'kernel-%s.json' % uuid.uuid4())
350
205
351 def init_kernel_manager(self):
352 # Don't let Qt or ZMQ swallow KeyboardInterupts.
353 signal.signal(signal.SIGINT, signal.SIG_DFL)
354 sec = self.profile_dir.security_dir
355 try:
356 cf = filefind(self.connection_file, ['.', sec])
357 except IOError:
358 # file might not exist
359 if self.connection_file == os.path.basename(self.connection_file):
360 # just shortname, put it in security dir
361 cf = os.path.join(sec, self.connection_file)
362 else:
363 cf = self.connection_file
364
365 # Create a KernelManager and start a kernel.
366 self.kernel_manager = QtKernelManager(
367 ip=self.ip,
368 shell_port=self.shell_port,
369 iopub_port=self.iopub_port,
370 stdin_port=self.stdin_port,
371 hb_port=self.hb_port,
372 connection_file=cf,
373 config=self.config,
374 )
375 # start the kernel
376 if not self.existing:
377 kwargs = dict(ipython=not self.pure)
378 kwargs['extra_arguments'] = self.kernel_argv
379 self.kernel_manager.start_kernel(**kwargs)
380 elif self.sshserver:
381 # ssh, write new connection file
382 self.kernel_manager.write_connection_file()
383 self.kernel_manager.start_channels()
384
206
385 def new_frontend_master(self):
207 def new_frontend_master(self):
386 """ Create and return new frontend attached to new kernel, launched on localhost.
208 """ Create and return new frontend attached to new kernel, launched on localhost.
General Comments 0
You need to be logged in to leave comments. Login now