##// END OF EJS Templates
move IPython.zmq.entry_point to IPython.utils.kernel
MinRK -
Show More
@@ -1,4 +1,4 b''
1 """Utilities for connecting to kernels
1 """Utilities for working with kernels and their connection files
2 2
3 3 Authors:
4 4
@@ -7,7 +7,7 b' Authors:'
7 7 """
8 8
9 9 #-----------------------------------------------------------------------------
10 # Copyright (C) 2011 The IPython Development Team
10 # Copyright (C) 2013 The IPython Development Team
11 11 #
12 12 # Distributed under the terms of the BSD License. The full license is in
13 13 # the file COPYING, distributed as part of this software.
@@ -20,23 +20,104 b' Authors:'
20 20 import glob
21 21 import json
22 22 import os
23 import socket
23 24 import sys
24 25 from getpass import getpass
25 26 from subprocess import Popen, PIPE
27 import tempfile
26 28
27 29 # external imports
28 30 from IPython.external.ssh import tunnel
29 31
30 32 # IPython imports
31 33 from IPython.core.profiledir import ProfileDir
34 from IPython.utils.localinterfaces import LOCALHOST
32 35 from IPython.utils.path import filefind, get_ipython_dir
33 from IPython.utils.py3compat import str_to_bytes
36 from IPython.utils.py3compat import str_to_bytes, bytes_to_str
34 37
35 38
36 39 #-----------------------------------------------------------------------------
37 # Functions
40 # Working with Connection Files
38 41 #-----------------------------------------------------------------------------
39 42
43 def write_connection_file(fname=None, shell_port=0, iopub_port=0, stdin_port=0, hb_port=0,
44 ip=LOCALHOST, key=b'', transport='tcp'):
45 """Generates a JSON config file, including the selection of random ports.
46
47 Parameters
48 ----------
49
50 fname : unicode
51 The path to the file to write
52
53 shell_port : int, optional
54 The port to use for ROUTER channel.
55
56 iopub_port : int, optional
57 The port to use for the SUB channel.
58
59 stdin_port : int, optional
60 The port to use for the REQ (raw input) channel.
61
62 hb_port : int, optional
63 The port to use for the hearbeat REP channel.
64
65 ip : str, optional
66 The ip address the kernel will bind to.
67
68 key : str, optional
69 The Session key used for HMAC authentication.
70
71 """
72 # default to temporary connector file
73 if not fname:
74 fname = tempfile.mktemp('.json')
75
76 # Find open ports as necessary.
77
78 ports = []
79 ports_needed = int(shell_port <= 0) + int(iopub_port <= 0) + \
80 int(stdin_port <= 0) + int(hb_port <= 0)
81 if transport == 'tcp':
82 for i in range(ports_needed):
83 sock = socket.socket()
84 sock.bind(('', 0))
85 ports.append(sock)
86 for i, sock in enumerate(ports):
87 port = sock.getsockname()[1]
88 sock.close()
89 ports[i] = port
90 else:
91 N = 1
92 for i in range(ports_needed):
93 while os.path.exists("%s-%s" % (ip, str(N))):
94 N += 1
95 ports.append(N)
96 N += 1
97 if shell_port <= 0:
98 shell_port = ports.pop(0)
99 if iopub_port <= 0:
100 iopub_port = ports.pop(0)
101 if stdin_port <= 0:
102 stdin_port = ports.pop(0)
103 if hb_port <= 0:
104 hb_port = ports.pop(0)
105
106 cfg = dict( shell_port=shell_port,
107 iopub_port=iopub_port,
108 stdin_port=stdin_port,
109 hb_port=hb_port,
110 )
111 cfg['ip'] = ip
112 cfg['key'] = bytes_to_str(key)
113 cfg['transport'] = transport
114
115 with open(fname, 'w') as f:
116 f.write(json.dumps(cfg, indent=2))
117
118 return fname, cfg
119
120
40 121 def get_connection_file(app=None):
41 122 """Return the path to the connection file of an app
42 123
@@ -53,6 +134,7 b' def get_connection_file(app=None):'
53 134 app = IPKernelApp.instance()
54 135 return filefind(app.connection_file, ['.', app.profile_dir.security_dir])
55 136
137
56 138 def find_connection_file(filename, profile=None):
57 139 """find a connection file, and return its absolute path.
58 140
@@ -122,6 +204,7 b' def find_connection_file(filename, profile=None):'
122 204 # get most recent match, by access time:
123 205 return sorted(matches, key=lambda f: os.stat(f).st_atime)[-1]
124 206
207
125 208 def get_connection_info(connection_file=None, unpack=False, profile=None):
126 209 """Return the connection information for the current Kernel.
127 210
@@ -163,6 +246,7 b' def get_connection_info(connection_file=None, unpack=False, profile=None):'
163 246 info['key'] = str_to_bytes(info.get('key', ''))
164 247 return info
165 248
249
166 250 def connect_qtconsole(connection_file=None, argv=None, profile=None):
167 251 """Connect a qtconsole to the current kernel.
168 252
@@ -204,6 +288,7 b' def connect_qtconsole(connection_file=None, argv=None, profile=None):'
204 288
205 289 return Popen([sys.executable, '-c', cmd, '--existing', cf] + argv, stdout=PIPE, stderr=PIPE)
206 290
291
207 292 def tunnel_to_kernel(connection_info, sshserver, sshkey=None):
208 293 """tunnel connections to a kernel via ssh
209 294
@@ -251,7 +336,11 b' def tunnel_to_kernel(connection_info, sshserver, sshkey=None):'
251 336 tunnel.ssh_tunnel(lp, rp, sshserver, remote_ip, sshkey, password)
252 337
253 338 return tuple(lports)
254
339
340
341 #-----------------------------------------------------------------------------
342 # Launching Kernels
343 #-----------------------------------------------------------------------------
255 344
256 345 def swallow_argv(argv, aliases=None, flags=None):
257 346 """strip frontend-specific aliases and flags from an argument list
@@ -313,3 +402,168 b' def swallow_argv(argv, aliases=None, flags=None):'
313 402 # return shortened list
314 403 return stripped
315 404
405
406 def make_ipkernel_cmd(code, executable=None, extra_arguments=[], **kw):
407 """Build Popen command list for launching an IPython kernel.
408
409 Parameters
410 ----------
411 code : str,
412 A string of Python code that imports and executes a kernel entry point.
413
414 executable : str, optional (default sys.executable)
415 The Python executable to use for the kernel process.
416
417 extra_arguments : list, optional
418 A list of extra arguments to pass when executing the launch code.
419
420 Returns
421 -------
422
423 A Popen command list
424 """
425
426 # Build the kernel launch command.
427 if executable is None:
428 executable = sys.executable
429 arguments = [ executable, '-c', code, '-f', '{connection_file}' ]
430 arguments.extend(extra_arguments)
431
432 # Spawn a kernel.
433 if sys.platform == 'win32':
434
435 # If the kernel is running on pythonw and stdout/stderr are not been
436 # re-directed, it will crash when more than 4KB of data is written to
437 # stdout or stderr. This is a bug that has been with Python for a very
438 # long time; see http://bugs.python.org/issue706263.
439 # A cleaner solution to this problem would be to pass os.devnull to
440 # Popen directly. Unfortunately, that does not work.
441 if executable.endswith('pythonw.exe'):
442 arguments.append('--no-stdout')
443 arguments.append('--no-stderr')
444
445 return arguments
446
447
448 def launch_kernel(cmd, stdin=None, stdout=None, stderr=None,
449 independent=False,
450 cwd=None, ipython_kernel=True,
451 **kw
452 ):
453 """ Launches a localhost kernel, binding to the specified ports.
454
455 Parameters
456 ----------
457 cmd : Popen list,
458 A string of Python code that imports and executes a kernel entry point.
459
460 stdin, stdout, stderr : optional (default None)
461 Standards streams, as defined in subprocess.Popen.
462
463 independent : bool, optional (default False)
464 If set, the kernel process is guaranteed to survive if this process
465 dies. If not set, an effort is made to ensure that the kernel is killed
466 when this process dies. Note that in this case it is still good practice
467 to kill kernels manually before exiting.
468
469 cwd : path, optional
470 The working dir of the kernel process (default: cwd of this process).
471
472 ipython_kernel : bool, optional
473 Whether the kernel is an official IPython one,
474 and should get a bit of special treatment.
475
476 Returns
477 -------
478
479 Popen instance for the kernel subprocess
480 """
481
482 # Popen will fail (sometimes with a deadlock) if stdin, stdout, and stderr
483 # are invalid. Unfortunately, there is in general no way to detect whether
484 # they are valid. The following two blocks redirect them to (temporary)
485 # pipes in certain important cases.
486
487 # If this process has been backgrounded, our stdin is invalid. Since there
488 # is no compelling reason for the kernel to inherit our stdin anyway, we'll
489 # place this one safe and always redirect.
490 redirect_in = True
491 _stdin = PIPE if stdin is None else stdin
492
493 # If this process in running on pythonw, we know that stdin, stdout, and
494 # stderr are all invalid.
495 redirect_out = sys.executable.endswith('pythonw.exe')
496 if redirect_out:
497 _stdout = PIPE if stdout is None else stdout
498 _stderr = PIPE if stderr is None else stderr
499 else:
500 _stdout, _stderr = stdout, stderr
501
502 # Spawn a kernel.
503 if sys.platform == 'win32':
504 from IPython.zmq.parentpoller import ParentPollerWindows
505 # Create a Win32 event for interrupting the kernel.
506 interrupt_event = ParentPollerWindows.create_interrupt_event()
507 if ipython_kernel:
508 cmd += [ '--interrupt=%i' % interrupt_event ]
509
510 # If the kernel is running on pythonw and stdout/stderr are not been
511 # re-directed, it will crash when more than 4KB of data is written to
512 # stdout or stderr. This is a bug that has been with Python for a very
513 # long time; see http://bugs.python.org/issue706263.
514 # A cleaner solution to this problem would be to pass os.devnull to
515 # Popen directly. Unfortunately, that does not work.
516 if cmd[0].endswith('pythonw.exe'):
517 if stdout is None:
518 cmd.append('--no-stdout')
519 if stderr is None:
520 cmd.append('--no-stderr')
521
522 # Launch the kernel process.
523 if independent:
524 proc = Popen(cmd,
525 creationflags=512, # CREATE_NEW_PROCESS_GROUP
526 stdin=_stdin, stdout=_stdout, stderr=_stderr)
527 else:
528 if ipython_kernel:
529 try:
530 from _winapi import DuplicateHandle, GetCurrentProcess, \
531 DUPLICATE_SAME_ACCESS
532 except:
533 from _subprocess import DuplicateHandle, GetCurrentProcess, \
534 DUPLICATE_SAME_ACCESS
535 pid = GetCurrentProcess()
536 handle = DuplicateHandle(pid, pid, pid, 0,
537 True, # Inheritable by new processes.
538 DUPLICATE_SAME_ACCESS)
539 cmd +=[ '--parent=%i' % handle ]
540
541
542 proc = Popen(cmd,
543 stdin=_stdin, stdout=_stdout, stderr=_stderr, cwd=cwd)
544
545 # Attach the interrupt event to the Popen objet so it can be used later.
546 proc.win32_interrupt_event = interrupt_event
547
548 else:
549 if independent:
550 proc = Popen(cmd, preexec_fn=lambda: os.setsid(),
551 stdin=_stdin, stdout=_stdout, stderr=_stderr, cwd=cwd)
552 else:
553 if ipython_kernel:
554 cmd += ['--parent=1']
555 proc = Popen(cmd,
556 stdin=_stdin, stdout=_stdout, stderr=_stderr, cwd=cwd)
557
558 # Clean up pipes created to work around Popen bug.
559 if redirect_in:
560 if stdin is None:
561 proc.stdin.close()
562 if redirect_out:
563 if stdout is None:
564 proc.stdout.close()
565 if stderr is None:
566 proc.stderr.close()
567
568 return proc
569
@@ -40,8 +40,8 b' from IPython.utils.traitlets import ('
40 40 DottedObjectName,
41 41 )
42 42 from IPython.utils.importstring import import_item
43 from IPython.utils.kernel import write_connection_file
43 44 # local imports
44 from IPython.zmq.entry_point import write_connection_file
45 45 from IPython.zmq.heartbeat import Heartbeat
46 46 from IPython.zmq.parentpoller import ParentPollerUnix, ParentPollerWindows
47 47 from IPython.zmq.session import (
@@ -40,7 +40,7 b' from IPython.utils.traitlets import ('
40 40 Any, Instance, Type, Unicode, List, Integer, Bool, CaselessStrEnum
41 41 )
42 42 from IPython.utils.py3compat import str_to_bytes
43 from IPython.zmq.entry_point import (
43 from IPython.utils.kernel import (
44 44 write_connection_file,
45 45 make_ipkernel_cmd,
46 46 launch_kernel,
@@ -925,14 +925,9 b' class KernelManager(Configurable):'
925 925
926 926 Parameters:
927 927 -----------
928 launcher : callable, optional (default None)
929 A custom function for launching the kernel process (generally a
930 wrapper around ``entry_point.base_launch_kernel``). In most cases,
931 it should not be necessary to use this parameter.
932
933 928 **kw : optional
934 keyword arguments that are passed down into the launcher
935 callable.
929 keyword arguments that are passed down to build the kernel_cmd
930 and launching the kernel (e.g. Popen kwargs).
936 931 """
937 932 if self.transport == 'tcp' and self.ip not in LOCAL_IPS:
938 933 raise RuntimeError("Can only launch a kernel on a local interface. "
1 NO CONTENT: file was removed
General Comments 0
You need to be logged in to leave comments. Login now