##// END OF EJS Templates
finish kernel shims
Min RK -
Show More
@@ -0,0 +1,226 b''
1 """Utilities for launching kernels
2 """
3
4 # Copyright (c) IPython Development Team.
5 # Distributed under the terms of the Modified BSD License.
6
7 import os
8 import sys
9 from subprocess import Popen, PIPE
10
11 from IPython.utils.encoding import getdefaultencoding
12 from IPython.utils.py3compat import cast_bytes_py2
13
14
15 def swallow_argv(argv, aliases=None, flags=None):
16 """strip frontend-specific aliases and flags from an argument list
17
18 For use primarily in frontend apps that want to pass a subset of command-line
19 arguments through to a subprocess, where frontend-specific flags and aliases
20 should be removed from the list.
21
22 Parameters
23 ----------
24
25 argv : list(str)
26 The starting argv, to be filtered
27 aliases : container of aliases (dict, list, set, etc.)
28 The frontend-specific aliases to be removed
29 flags : container of flags (dict, list, set, etc.)
30 The frontend-specific flags to be removed
31
32 Returns
33 -------
34
35 argv : list(str)
36 The argv list, excluding flags and aliases that have been stripped
37 """
38
39 if aliases is None:
40 aliases = set()
41 if flags is None:
42 flags = set()
43
44 stripped = list(argv) # copy
45
46 swallow_next = False
47 was_flag = False
48 for a in argv:
49 if a == '--':
50 break
51 if swallow_next:
52 swallow_next = False
53 # last arg was an alias, remove the next one
54 # *unless* the last alias has a no-arg flag version, in which
55 # case, don't swallow the next arg if it's also a flag:
56 if not (was_flag and a.startswith('-')):
57 stripped.remove(a)
58 continue
59 if a.startswith('-'):
60 split = a.lstrip('-').split('=')
61 name = split[0]
62 # we use startswith because argparse accepts any arg to be specified
63 # by any leading section, as long as it is unique,
64 # so `--no-br` means `--no-browser` in the notebook, etc.
65 if any(alias.startswith(name) for alias in aliases):
66 stripped.remove(a)
67 if len(split) == 1:
68 # alias passed with arg via space
69 swallow_next = True
70 # could have been a flag that matches an alias, e.g. `existing`
71 # in which case, we might not swallow the next arg
72 was_flag = name in flags
73 elif len(split) == 1 and any(flag.startswith(name) for flag in flags):
74 # strip flag, but don't swallow next, as flags don't take args
75 stripped.remove(a)
76
77 # return shortened list
78 return stripped
79
80
81 def make_ipkernel_cmd(mod='ipython_kernel', executable=None, extra_arguments=[], **kw):
82 """Build Popen command list for launching an IPython kernel.
83
84 Parameters
85 ----------
86 mod : str, optional (default 'ipython_kernel')
87 A string of an IPython module whose __main__ starts an IPython kernel
88
89 executable : str, optional (default sys.executable)
90 The Python executable to use for the kernel process.
91
92 extra_arguments : list, optional
93 A list of extra arguments to pass when executing the launch code.
94
95 Returns
96 -------
97
98 A Popen command list
99 """
100 if executable is None:
101 executable = sys.executable
102 arguments = [ executable, '-m', mod, '-f', '{connection_file}' ]
103 arguments.extend(extra_arguments)
104
105 return arguments
106
107
108 def launch_kernel(cmd, stdin=None, stdout=None, stderr=None, env=None,
109 independent=False,
110 cwd=None,
111 **kw
112 ):
113 """ Launches a localhost kernel, binding to the specified ports.
114
115 Parameters
116 ----------
117 cmd : Popen list,
118 A string of Python code that imports and executes a kernel entry point.
119
120 stdin, stdout, stderr : optional (default None)
121 Standards streams, as defined in subprocess.Popen.
122
123 independent : bool, optional (default False)
124 If set, the kernel process is guaranteed to survive if this process
125 dies. If not set, an effort is made to ensure that the kernel is killed
126 when this process dies. Note that in this case it is still good practice
127 to kill kernels manually before exiting.
128
129 cwd : path, optional
130 The working dir of the kernel process (default: cwd of this process).
131
132 Returns
133 -------
134
135 Popen instance for the kernel subprocess
136 """
137
138 # Popen will fail (sometimes with a deadlock) if stdin, stdout, and stderr
139 # are invalid. Unfortunately, there is in general no way to detect whether
140 # they are valid. The following two blocks redirect them to (temporary)
141 # pipes in certain important cases.
142
143 # If this process has been backgrounded, our stdin is invalid. Since there
144 # is no compelling reason for the kernel to inherit our stdin anyway, we'll
145 # place this one safe and always redirect.
146 redirect_in = True
147 _stdin = PIPE if stdin is None else stdin
148
149 # If this process in running on pythonw, we know that stdin, stdout, and
150 # stderr are all invalid.
151 redirect_out = sys.executable.endswith('pythonw.exe')
152 if redirect_out:
153 blackhole = open(os.devnull, 'w')
154 _stdout = blackhole if stdout is None else stdout
155 _stderr = blackhole if stderr is None else stderr
156 else:
157 _stdout, _stderr = stdout, stderr
158
159 env = env if (env is not None) else os.environ.copy()
160
161 encoding = getdefaultencoding(prefer_stream=False)
162 kwargs = dict(
163 stdin=_stdin,
164 stdout=_stdout,
165 stderr=_stderr,
166 cwd=cwd,
167 env=env,
168 )
169
170 # Spawn a kernel.
171 if sys.platform == 'win32':
172 # Popen on Python 2 on Windows cannot handle unicode args or cwd
173 cmd = [ cast_bytes_py2(c, encoding) for c in cmd ]
174 if cwd:
175 cwd = cast_bytes_py2(cwd, sys.getfilesystemencoding() or 'ascii')
176 kwargs['cwd'] = cwd
177
178 from jupyter_client.parentpoller import ParentPollerWindows
179 # Create a Win32 event for interrupting the kernel
180 # and store it in an environment variable.
181 interrupt_event = ParentPollerWindows.create_interrupt_event()
182 env["JPY_INTERRUPT_EVENT"] = str(interrupt_event)
183 # deprecated old env name:
184 env["IPY_INTERRUPT_EVENT"] = env["JPY_INTERRUPT_EVENT"]
185
186 try:
187 from _winapi import DuplicateHandle, GetCurrentProcess, \
188 DUPLICATE_SAME_ACCESS, CREATE_NEW_PROCESS_GROUP
189 except:
190 from _subprocess import DuplicateHandle, GetCurrentProcess, \
191 DUPLICATE_SAME_ACCESS, CREATE_NEW_PROCESS_GROUP
192 # Launch the kernel process
193 if independent:
194 kwargs['creationflags'] = CREATE_NEW_PROCESS_GROUP
195 else:
196 pid = GetCurrentProcess()
197 handle = DuplicateHandle(pid, pid, pid, 0,
198 True, # Inheritable by new processes.
199 DUPLICATE_SAME_ACCESS)
200 env['JPY_PARENT_PID'] = str(int(handle))
201
202 proc = Popen(cmd, **kwargs)
203
204 # Attach the interrupt event to the Popen objet so it can be used later.
205 proc.win32_interrupt_event = interrupt_event
206
207 else:
208 if independent:
209 kwargs['preexec_fn'] = lambda: os.setsid()
210 else:
211 env['JPY_PARENT_PID'] = str(os.getpid())
212
213 proc = Popen(cmd, **kwargs)
214
215 # Clean up pipes created to work around Popen bug.
216 if redirect_in:
217 if stdin is None:
218 proc.stdin.close()
219
220 return proc
221
222 __all__ = [
223 'swallow_argv',
224 'make_ipkernel_cmd',
225 'launch_kernel',
226 ]
@@ -25,7 +25,8 b' from IPython.utils.traitlets import ('
25 Dict, List, Unicode, CUnicode, CBool, Any
25 Dict, List, Unicode, CUnicode, CBool, Any
26 )
26 )
27 from IPython.kernel.zmq.session import Session
27 from IPython.kernel.zmq.session import Session
28 from IPython.kernel.connect import ConnectionFileMixin
28 from IPython.kernel import connect
29 ConnectionFileMixin = connect.ConnectionFileMixin
29
30
30 from IPython.utils.localinterfaces import localhost
31 from IPython.utils.localinterfaces import localhost
31
32
@@ -1,67 +1,29 b''
1 """IPython kernels and associated utilities
2
3 For connecting to kernels, use jupyter_client
4 """
1 """
5
2 Shim to maintain backwards compatibility with old IPython.kernel imports.
3 """
6 # Copyright (c) IPython Development Team.
4 # Copyright (c) IPython Development Team.
7 # Distributed under the terms of the Modified BSD License.
5 # Distributed under the terms of the Modified BSD License.
8
6
9 # Shim to maintain backwards compatibility with old IPython.kernel imports.
10
11 import sys
7 import sys
12 from warnings import warn
8 from warnings import warn
13
9
14 warn("The `IPython.kernel` package has been deprecated. "
10 warn("The `IPython.kernel` package has been deprecated. "
15 "You should import from ipython_kernel or jupyter_client instead.")
11 "You should import from ipython_kernel or jupyter_client instead.")
16
12
17 from IPython.utils.shimmodule import ShimModule
18
19 # Shims for jupyter_client
20 # Can't do a single shim, because the package didn't move all together
21
13
22 for name in (
14 from IPython.utils.shimmodule import ShimModule
23 'adapter',
24 'blocking',
25 'channels',
26 'channelsabc',
27 'client',
28 'clientabc',
29 'connect',
30 'ioloop',
31 'kernelspec',
32 'kernelspecapp',
33 'launcher',
34 'manager',
35 'managerabc',
36 'multikernelmanager',
37 'restarter',
38 'threaded',
39 'tests.test_adapter',
40 'tests.test_connect',
41 'tests.test_kernelmanager',
42 'tests.test_kernelspec',
43 'tests.test_launcher',
44 'tests.test_multikernelmanager',
45 'tests.test_public_api',
46 ):
47 sys.modules['IPython.kernel.%s' % name] = \
48 ShimModule(name, mirror='jupyter_client.%s' % name)
49
15
50 # some files moved out of the zmq prefix
16 # session moved relative to top-level
51 for name in (
17 sys.modules['IPython.kernel.zmq.session'] = ShimModule('session', mirror='jupyter_client.session')
52 'session',
53 'tests.test_session',
54 ):
55 sys.modules['IPython.kernel.zmq.%s' % name] = \
56 ShimModule(name, mirror='jupyter_client.%s' % name)
57 # preserve top-level API modules, all from jupyter_client
58
18
59 # just for friendlier zmq version check
19 for pkg in ('comm', 'inprocess', 'resources', 'zmq'):
60 from . import zmq
20 sys.modules['IPython.kernel.%s' % pkg] = ShimModule(pkg, mirror='ipython_kernel.%s' % pkg)
21 for pkg in ('ioloop', 'blocking'):
22 sys.modules['IPython.kernel.%s' % pkg] = ShimModule(pkg, mirror='jupyter_client.%s' % pkg)
61
23
62 from jupyter_client.connect import *
24 # required for `from IPython.kernel import PKG`
63 from jupyter_client.launcher import *
25 from ipython_kernel import comm, inprocess, resources, zmq
64 from jupyter_client.client import KernelClient
26 from jupyter_client import ioloop, blocking
65 from jupyter_client.manager import KernelManager, run_kernel
27 # public API
66 from jupyter_client.blocking import BlockingKernelClient
28 from ipython_kernel.connect import *
67 from jupyter_client.multikernelmanager import MultiKernelManager
29 from jupyter_client import *
@@ -172,6 +172,8 b' class TestSection(object):'
172
172
173 shims = {
173 shims = {
174 'parallel': 'ipython_parallel',
174 'parallel': 'ipython_parallel',
175 'kernel': 'ipython_kernel',
176 'kernel.inprocess': 'ipython_kernel.inprocess',
175 }
177 }
176
178
177 # Name -> (include, exclude, dependencies_met)
179 # Name -> (include, exclude, dependencies_met)
@@ -78,12 +78,12 b' def swallow_argv(argv, aliases=None, flags=None):'
78 return stripped
78 return stripped
79
79
80
80
81 def make_ipkernel_cmd(mod='IPython.kernel', executable=None, extra_arguments=[], **kw):
81 def make_ipkernel_cmd(mod='ipython_kernel', executable=None, extra_arguments=[], **kw):
82 """Build Popen command list for launching an IPython kernel.
82 """Build Popen command list for launching an IPython kernel.
83
83
84 Parameters
84 Parameters
85 ----------
85 ----------
86 mod : str, optional (default 'IPython.kernel')
86 mod : str, optional (default 'ipython_kernel')
87 A string of an IPython module whose __main__ starts an IPython kernel
87 A string of an IPython module whose __main__ starts an IPython kernel
88
88
89 executable : str, optional (default sys.executable)
89 executable : str, optional (default sys.executable)
General Comments 0
You need to be logged in to leave comments. Login now