Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit ad9f42c

Browse files
committed
finish kernel shims
1 parent c71dcbc commit ad9f42c

5 files changed

Lines changed: 247 additions & 56 deletions

File tree

IPython/consoleapp.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,8 @@
2525
Dict, List, Unicode, CUnicode, CBool, Any
2626
)
2727
from IPython.kernel.zmq.session import Session
28-
from IPython.kernel.connect import ConnectionFileMixin
28+
from IPython.kernel import connect
29+
ConnectionFileMixin = connect.ConnectionFileMixin
2930

3031
from IPython.utils.localinterfaces import localhost
3132

IPython/kernel/__init__.py

Lines changed: 15 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -1,67 +1,29 @@
1-
"""IPython kernels and associated utilities
2-
3-
For connecting to kernels, use jupyter_client
41
"""
5-
2+
Shim to maintain backwards compatibility with old IPython.kernel imports.
3+
"""
64
# Copyright (c) IPython Development Team.
75
# Distributed under the terms of the Modified BSD License.
86

9-
# Shim to maintain backwards compatibility with old IPython.kernel imports.
10-
117
import sys
128
from warnings import warn
139

1410
warn("The `IPython.kernel` package has been deprecated. "
1511
"You should import from ipython_kernel or jupyter_client instead.")
1612

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
2113

22-
for name in (
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)
14+
from IPython.utils.shimmodule import ShimModule
4915

50-
# some files moved out of the zmq prefix
51-
for name in (
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
16+
# session moved relative to top-level
17+
sys.modules['IPython.kernel.zmq.session'] = ShimModule('session', mirror='jupyter_client.session')
5818

59-
# just for friendlier zmq version check
60-
from . import zmq
19+
for pkg in ('comm', 'inprocess', 'resources', '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)
6123

62-
from jupyter_client.connect import *
63-
from jupyter_client.launcher import *
64-
from jupyter_client.client import KernelClient
65-
from jupyter_client.manager import KernelManager, run_kernel
66-
from jupyter_client.blocking import BlockingKernelClient
67-
from jupyter_client.multikernelmanager import MultiKernelManager
24+
# required for `from IPython.kernel import PKG`
25+
from ipython_kernel import comm, inprocess, resources, zmq
26+
from jupyter_client import ioloop, blocking
27+
# public API
28+
from ipython_kernel.connect import *
29+
from jupyter_client import *

IPython/testing/iptest.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -172,6 +172,8 @@ def will_run(self):
172172

173173
shims = {
174174
'parallel': 'ipython_parallel',
175+
'kernel': 'ipython_kernel',
176+
'kernel.inprocess': 'ipython_kernel.inprocess',
175177
}
176178

177179
# Name -> (include, exclude, dependencies_met)

ipython_kernel/launcher.py

Lines changed: 226 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,226 @@
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+
]

jupyter_client/launcher.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -78,12 +78,12 @@ def swallow_argv(argv, aliases=None, flags=None):
7878
return stripped
7979

8080

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):
8282
"""Build Popen command list for launching an IPython kernel.
8383
8484
Parameters
8585
----------
86-
mod : str, optional (default 'IPython.kernel')
86+
mod : str, optional (default 'ipython_kernel')
8787
A string of an IPython module whose __main__ starts an IPython kernel
8888
8989
executable : str, optional (default sys.executable)

0 commit comments

Comments
 (0)