Skip to content

Commit 67c2f28

Browse files
Support MultiKernelManager (#51)
1 parent 0418c04 commit 67c2f28

File tree

3 files changed

+59
-4
lines changed

3 files changed

+59
-4
lines changed

nbclient/client.py

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -363,25 +363,41 @@ async def async_start_new_kernel_client(self, **kwargs):
363363
-------
364364
kc : KernelClient
365365
Kernel client as created by the kernel manager `km`.
366+
kernel_id : string-ized version 4 uuid
367+
The id of the started kernel.
366368
"""
367369
resource_path = self.resources.get('metadata', {}).get('path') or None
368370
if resource_path and 'cwd' not in kwargs:
369371
kwargs["cwd"] = resource_path
370372

371-
if self.km.ipykernel and self.ipython_hist_file:
373+
# if self.km is a MultiKernelManager, it doesn't have an ipykernel attribute
374+
# so no extra_arguments can be passed
375+
if hasattr(self.km, 'ipykernel') and self.km.ipykernel and self.ipython_hist_file:
372376
self.extra_arguments += ['--HistoryManager.hist_file={}'.format(self.ipython_hist_file)]
373377

374-
await ensure_async(self.km.start_kernel(extra_arguments=self.extra_arguments, **kwargs))
378+
kernel_id = await ensure_async(self.km.start_kernel(extra_arguments=self.extra_arguments,
379+
**kwargs))
375380

376-
self.kc = self.km.client()
381+
# if self.km is not a KernelManager, it's probably a MultiKernelManager
382+
try:
383+
self.km.client
384+
km = self.km
385+
except AttributeError:
386+
try:
387+
km = self.km.get_kernel(kernel_id)
388+
except AttributeError:
389+
raise AttributeError('self.km={} has no client() or get_kernel() method, '
390+
'what is this?'.format(self.km))
391+
392+
self.kc = km.client()
377393
await ensure_async(self.kc.start_channels())
378394
try:
379395
await ensure_async(self.kc.wait_for_ready(timeout=self.startup_timeout))
380396
except RuntimeError:
381397
await self._async_cleanup_kernel()
382398
raise
383399
self.kc.allow_stdin = False
384-
return self.kc
400+
return self.kc, kernel_id
385401

386402
start_new_kernel_client = run_sync(async_start_new_kernel_client)
387403

nbclient/tests/test_client.py

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
import IPython
2121
from traitlets import TraitError
2222
from nbformat import NotebookNode
23+
from jupyter_client import KernelManager, MultiKernelManager
2324
from jupyter_client.kernelspec import KernelSpecManager
2425
from nbconvert.filters import strip_ansi
2526
from testpath import modified_env
@@ -400,6 +401,43 @@ def test_synchronous_setup_kernel():
400401
assert executor.kc is None
401402

402403

404+
def test_startnewkernel_with_kernelmanager():
405+
nb = nbformat.v4.new_notebook()
406+
km = KernelManager()
407+
executor = NotebookClient(nb, km=km)
408+
kc, kernel_id = executor.start_new_kernel_client()
409+
# no kernel_id for a single kernel manager
410+
assert kernel_id is None
411+
# prove it initalized client
412+
assert kc is not None
413+
# since we are not using the setup_kernel context manager,
414+
# cleanup has to be done manually
415+
kc.shutdown()
416+
km.cleanup()
417+
kc.stop_channels()
418+
419+
420+
def test_startnewkernel_with_multikernelmanager():
421+
nb = nbformat.v4.new_notebook()
422+
km = MultiKernelManager()
423+
executor = NotebookClient(nb, km=km)
424+
kc, kernel_id = executor.start_new_kernel_client()
425+
# a multi kernel manager always gives back an id to the started kernel
426+
assert kernel_id is not None
427+
# prove it initalized client
428+
assert kc is not None
429+
# since we are not using the setup_kernel context manager,
430+
# cleanup has to be done manually
431+
kc.shutdown()
432+
km.cleanup(kernel_id)
433+
km.remove_kernel(kernel_id)
434+
# check that the kernel doesn't exist anymore
435+
with pytest.raises(KeyError) as e_info:
436+
km.get_kernel(kernel_id)
437+
assert str(e_info.value) == "'Kernel with id not found: {}'".format(kernel_id)
438+
kc.stop_channels()
439+
440+
403441
class TestExecute(NBClientTestsBase):
404442
"""Contains test functions for execute.py"""
405443

requirements-dev.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
codecov
22
coverage
33
ipython
4+
ipykernel
45
ipywidgets
56
pytest>=4.1
67
pytest-cov>=2.6.1

0 commit comments

Comments
 (0)