Skip to content

Commit aad40cb

Browse files
committed
Document new kernel providers system
1 parent e92e5c1 commit aad40cb

File tree

3 files changed

+158
-7
lines changed

3 files changed

+158
-7
lines changed

docs/index.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ with Jupyter kernels.
2323

2424
kernels
2525
wrapperkernels
26+
kernel_providers
2627

2728
.. toctree::
2829
:maxdepth: 2

docs/kernel_providers.rst

Lines changed: 146 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,146 @@
1+
================
2+
Kernel providers
3+
================
4+
5+
.. note::
6+
This is a new interface under development. Not all Jupyter applications
7+
use this yet. See :ref:`kernelspecs` for the established way of discovering
8+
kernel types.
9+
10+
By writing a kernel provider, you can extend how Jupyter applications discover
11+
and start kernels. To do so, subclass
12+
:class:`jupyter_client.discovery.KernelProviderBase`, giving your provider an ID
13+
and overriding two methods.
14+
15+
.. class:: MyKernelProvider
16+
17+
.. attribute:: id
18+
19+
A short string identifying this provider. Cannot contain forward slash
20+
(``/``).
21+
22+
.. method:: find_kernels()
23+
24+
Get the available kernel types this provider knows about.
25+
Return an iterable of 2-tuples: (name, attributes).
26+
*name* is a short string identifying the kernel type.
27+
*attributes* is a dictionary with information to allow selecting a kernel.
28+
29+
.. method:: make_manager(name)
30+
31+
Prepare and return a :class:`~jupyter_client.KernelManager` instance
32+
ready to start a new kernel instance of the type identified by *name*.
33+
The input will be one of the names given by :meth:`find_kernels`.
34+
35+
For example, imagine we want to tell Jupyter about kernels for a new language
36+
called *oblong*::
37+
38+
# oblong_provider.py
39+
from jupyter_client.discover import KernelProviderBase
40+
from jupyter_client import KernelManager
41+
from shutil import which
42+
43+
class OblongKernelProvider(KernelProviderBase):
44+
id = 'oblong'
45+
46+
def find_kernels(self):
47+
if not which('oblong-kernel'):
48+
return # Check it's available
49+
50+
# Two variants - for a real kernel, these could be different
51+
# environments
52+
yield 'standard', {
53+
'display_name': 'Oblong (standard)',
54+
'language': {'name': 'oblong'},
55+
'argv': ['oblong-kernel'],
56+
}
57+
yield 'rounded', {
58+
'display_name': 'Oblong (rounded)',
59+
'language': {'name': 'oblong'},
60+
'argv': ['oblong-kernel'],
61+
}
62+
63+
def make_manager(self, name):
64+
if name == 'standard':
65+
return KernelManager(kernel_cmd=['oblong-kernel'],
66+
extra_env={'ROUNDED': '0'})
67+
elif name == 'rounded':
68+
return KernelManager(kernel_cmd=['oblong-kernel'],
69+
extra_env={'ROUNDED': '1'})
70+
else:
71+
raise ValueError("Unknown kernel %s" % name)
72+
73+
You would then register this with an *entry point*. In your ``setup.py``, put
74+
something like this::
75+
76+
setup(...
77+
entry_points = {
78+
'jupyter_client.kernel_providers' : [
79+
# The name before the '=' should match the id attribute
80+
'oblong = oblong_provider:OblongKernelProvider',
81+
]
82+
})
83+
84+
To find and start kernels in client code, use
85+
:class:`jupyter_client.discovery.KernelFinder`. This has a similar API to kernel
86+
providers, but it wraps a set of kernel providers. The kernel names it works
87+
with have the provider ID as a prefix, e.g. ``oblong/rounded`` (from the example
88+
above).
89+
90+
::
91+
92+
from jupyter_client.discovery import KernelFinder
93+
kf = KernelFinder.from_entrypoints()
94+
95+
## Find available kernel types
96+
for name, attributes in kf.find_kernels():
97+
print(name, ':', attributes['display_name'])
98+
# oblong/standard : Oblong (standard)
99+
# oblong/rounded : Oblong(rounded)
100+
# ...
101+
102+
## Start a kernel by name
103+
manager = kf.make_manager('oblong/standard')
104+
manager.start_kernel()
105+
106+
.. module:: jupyter_client.discovery
107+
108+
.. autoclass:: KernelFinder
109+
110+
.. automethod:: from_entrypoints
111+
112+
.. automethod:: find_kernels
113+
114+
.. automethod:: make_manager
115+
116+
Included kernel providers
117+
=========================
118+
119+
``jupyter_client`` includes two kernel providers:
120+
121+
.. autoclass:: KernelSpecProvider
122+
123+
.. seealso:: :ref:`kernelspecs`
124+
125+
.. autoclass:: IPykernelProvider
126+
127+
Glossary
128+
========
129+
130+
Kernel instance
131+
A running kernel, a process which can accept ZMQ connections from frontends.
132+
Its state includes a namespace and an execution counter.
133+
134+
Kernel type
135+
Allows starting multiple, initially similar kernel instances. The kernel type
136+
entails the combination of software to run the kernel, and the context in
137+
which it starts. For instance, one kernel type may be associated with one
138+
conda environment containing ``ipykernel``. The same kernel software in
139+
another environment would be a different kernel type. Another software package
140+
for a kernel, such as ``IRkernel``, would also be a different kernel type.
141+
142+
Kernel provider
143+
A Python class to discover kernel types and allow a client to start instances
144+
of those kernel types. For instance, one kernel provider might find conda
145+
environments containing ``ipykernel`` and allow starting kernel instances in
146+
these environments.

jupyter_client/discovery.py

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ def make_manager(self, name):
2525
pass
2626

2727
class KernelSpecProvider(KernelProviderBase):
28-
"""Find kernels from installed kernelspec directories.
28+
"""Offers kernel types from installed kernelspec directories.
2929
"""
3030
id = 'spec'
3131

@@ -48,7 +48,9 @@ def make_manager(self, name):
4848

4949

5050
class IPykernelProvider(KernelProviderBase):
51-
"""Find ipykernel on this Python version by trying to import it.
51+
"""Offers a kernel type using the Python interpreter it's running in.
52+
53+
This checks if ipykernel is importable first.
5254
"""
5355
id = 'pyimport'
5456

@@ -83,7 +85,9 @@ def make_manager(self, name):
8385

8486

8587
class KernelFinder(object):
86-
"""Manages a collection of kernel providers to find available kernels
88+
"""Manages a collection of kernel providers to find available kernel types
89+
90+
*providers* should be a list of kernel provider instances.
8791
"""
8892
def __init__(self, providers):
8993
self.providers = providers
@@ -109,17 +113,17 @@ def from_entrypoints(cls):
109113
return cls(providers)
110114

111115
def find_kernels(self):
112-
"""Iterate over available kernels.
116+
"""Iterate over available kernel types.
113117
114-
Yields 2-tuples of (id_str, attributes)
118+
Yields 2-tuples of (prefixed_name, attributes)
115119
"""
116120
for provider in self.providers:
117121
for kid, attributes in provider.find_kernels():
118122
id = provider.id + '/' + kid
119123
yield id, attributes
120124

121-
def make_manager(self, id):
122-
"""Make a KernelManager instance for a given kernel ID.
125+
def make_manager(self, name):
126+
"""Make a KernelManager instance for a given kernel type.
123127
"""
124128
provider_id, kernel_id = id.split('/', 1)
125129
for provider in self.providers:

0 commit comments

Comments
 (0)