first commit

This commit is contained in:
Ayxan
2022-05-23 00:16:32 +04:00
commit d660f2a4ca
24786 changed files with 4428337 additions and 0 deletions

View File

@@ -0,0 +1,4 @@
from .blocking import BlockingInProcessKernelClient # noqa
from .channels import InProcessChannel, InProcessHBChannel # noqa
from .client import InProcessKernelClient # noqa
from .manager import InProcessKernelManager # noqa

View File

@@ -0,0 +1,101 @@
""" Implements a fully blocking kernel client.
Useful for test suites and blocking terminal interfaces.
"""
import sys
# -----------------------------------------------------------------------------
# Copyright (C) 2012 The IPython Development Team
#
# Distributed under the terms of the BSD License. The full license is in
# the file COPYING.txt, distributed as part of this software.
# -----------------------------------------------------------------------------
from queue import Empty, Queue
# IPython imports
from traitlets import Type
# Local imports
from .channels import InProcessChannel
from .client import InProcessKernelClient
class BlockingInProcessChannel(InProcessChannel):
def __init__(self, *args, **kwds):
super().__init__(*args, **kwds)
self._in_queue: Queue[object] = Queue()
def call_handlers(self, msg):
self._in_queue.put(msg)
def get_msg(self, block=True, timeout=None):
"""Gets a message if there is one that is ready."""
if timeout is None:
# Queue.get(timeout=None) has stupid uninteruptible
# behavior, so wait for a week instead
timeout = 604800
return self._in_queue.get(block, timeout)
def get_msgs(self):
"""Get all messages that are currently ready."""
msgs = []
while True:
try:
msgs.append(self.get_msg(block=False))
except Empty:
break
return msgs
def msg_ready(self):
"""Is there a message that has been received?"""
return not self._in_queue.empty()
class BlockingInProcessStdInChannel(BlockingInProcessChannel):
def call_handlers(self, msg):
"""Overridden for the in-process channel.
This methods simply calls raw_input directly.
"""
msg_type = msg["header"]["msg_type"]
if msg_type == "input_request":
_raw_input = self.client.kernel._sys_raw_input
prompt = msg["content"]["prompt"]
print(prompt, end="", file=sys.__stdout__)
sys.__stdout__.flush()
self.client.input(_raw_input())
class BlockingInProcessKernelClient(InProcessKernelClient):
# The classes to use for the various channels.
shell_channel_class = Type(BlockingInProcessChannel)
iopub_channel_class = Type(BlockingInProcessChannel)
stdin_channel_class = Type(BlockingInProcessStdInChannel)
def wait_for_ready(self):
# Wait for kernel info reply on shell channel
while True:
self.kernel_info()
try:
msg = self.shell_channel.get_msg(block=True, timeout=1)
except Empty:
pass
else:
if msg["msg_type"] == "kernel_info_reply":
# Checking that IOPub is connected. If it is not connected, start over.
try:
self.iopub_channel.get_msg(block=True, timeout=0.2)
except Empty:
pass
else:
self._handle_kernel_info_reply(msg)
break
# Flush IOPub channel
while True:
try:
msg = self.iopub_channel.get_msg(block=True, timeout=0.2)
print(msg["msg_type"])
except Empty:
break

View File

@@ -0,0 +1,97 @@
"""A kernel client for in-process kernels."""
# Copyright (c) IPython Development Team.
# Distributed under the terms of the Modified BSD License.
from typing import List
from jupyter_client.channelsabc import HBChannelABC
# -----------------------------------------------------------------------------
# Channel classes
# -----------------------------------------------------------------------------
class InProcessChannel:
"""Base class for in-process channels."""
proxy_methods: List[object] = []
def __init__(self, client=None):
super().__init__()
self.client = client
self._is_alive = False
def is_alive(self):
return self._is_alive
def start(self):
self._is_alive = True
def stop(self):
self._is_alive = False
def call_handlers(self, msg):
"""This method is called in the main thread when a message arrives.
Subclasses should override this method to handle incoming messages.
"""
raise NotImplementedError("call_handlers must be defined in a subclass.")
def flush(self, timeout=1.0):
pass
def call_handlers_later(self, *args, **kwds):
"""Call the message handlers later.
The default implementation just calls the handlers immediately, but this
method exists so that GUI toolkits can defer calling the handlers until
after the event loop has run, as expected by GUI frontends.
"""
self.call_handlers(*args, **kwds)
def process_events(self):
"""Process any pending GUI events.
This method will be never be called from a frontend without an event
loop (e.g., a terminal frontend).
"""
raise NotImplementedError
class InProcessHBChannel:
"""A dummy heartbeat channel interface for in-process kernels.
Normally we use the heartbeat to check that the kernel process is alive.
When the kernel is in-process, that doesn't make sense, but clients still
expect this interface.
"""
time_to_dead = 3.0
def __init__(self, client=None):
super().__init__()
self.client = client
self._is_alive = False
self._pause = True
def is_alive(self):
return self._is_alive
def start(self):
self._is_alive = True
def stop(self):
self._is_alive = False
def pause(self):
self._pause = True
def unpause(self):
self._pause = False
def is_beating(self):
return not self._pause
HBChannelABC.register(InProcessHBChannel)

View File

@@ -0,0 +1,204 @@
"""A client for in-process kernels."""
# -----------------------------------------------------------------------------
# Copyright (C) 2012 The IPython Development Team
#
# Distributed under the terms of the BSD License. The full license is in
# the file COPYING, distributed as part of this software.
# -----------------------------------------------------------------------------
# -----------------------------------------------------------------------------
# Imports
# -----------------------------------------------------------------------------
import asyncio
from jupyter_client.client import KernelClient
from jupyter_client.clientabc import KernelClientABC
# IPython imports
from traitlets import Instance, Type, default
# Local imports
from .channels import InProcessChannel, InProcessHBChannel
# -----------------------------------------------------------------------------
# Main kernel Client class
# -----------------------------------------------------------------------------
class InProcessKernelClient(KernelClient):
"""A client for an in-process kernel.
This class implements the interface of
`jupyter_client.clientabc.KernelClientABC` and allows
(asynchronous) frontends to be used seamlessly with an in-process kernel.
See `jupyter_client.client.KernelClient` for docstrings.
"""
# The classes to use for the various channels.
shell_channel_class = Type(InProcessChannel)
iopub_channel_class = Type(InProcessChannel)
stdin_channel_class = Type(InProcessChannel)
control_channel_class = Type(InProcessChannel)
hb_channel_class = Type(InProcessHBChannel)
kernel = Instance("ipykernel.inprocess.ipkernel.InProcessKernel", allow_none=True)
# --------------------------------------------------------------------------
# Channel management methods
# --------------------------------------------------------------------------
@default("blocking_class")
def _default_blocking_class(self):
from .blocking import BlockingInProcessKernelClient
return BlockingInProcessKernelClient
def get_connection_info(self):
d = super().get_connection_info()
d["kernel"] = self.kernel
return d
def start_channels(self, *args, **kwargs):
super().start_channels()
self.kernel.frontends.append(self)
@property
def shell_channel(self):
if self._shell_channel is None:
self._shell_channel = self.shell_channel_class(self)
return self._shell_channel
@property
def iopub_channel(self):
if self._iopub_channel is None:
self._iopub_channel = self.iopub_channel_class(self)
return self._iopub_channel
@property
def stdin_channel(self):
if self._stdin_channel is None:
self._stdin_channel = self.stdin_channel_class(self)
return self._stdin_channel
@property
def control_channel(self):
if self._control_channel is None:
self._control_channel = self.control_channel_class(self)
return self._control_channel
@property
def hb_channel(self):
if self._hb_channel is None:
self._hb_channel = self.hb_channel_class(self)
return self._hb_channel
# Methods for sending specific messages
# -------------------------------------
def execute(
self, code, silent=False, store_history=True, user_expressions=None, allow_stdin=None
):
if allow_stdin is None:
allow_stdin = self.allow_stdin
content = dict(
code=code,
silent=silent,
store_history=store_history,
user_expressions=user_expressions or {},
allow_stdin=allow_stdin,
)
msg = self.session.msg("execute_request", content)
self._dispatch_to_kernel(msg)
return msg["header"]["msg_id"]
def complete(self, code, cursor_pos=None):
if cursor_pos is None:
cursor_pos = len(code)
content = dict(code=code, cursor_pos=cursor_pos)
msg = self.session.msg("complete_request", content)
self._dispatch_to_kernel(msg)
return msg["header"]["msg_id"]
def inspect(self, code, cursor_pos=None, detail_level=0):
if cursor_pos is None:
cursor_pos = len(code)
content = dict(
code=code,
cursor_pos=cursor_pos,
detail_level=detail_level,
)
msg = self.session.msg("inspect_request", content)
self._dispatch_to_kernel(msg)
return msg["header"]["msg_id"]
def history(self, raw=True, output=False, hist_access_type="range", **kwds):
content = dict(raw=raw, output=output, hist_access_type=hist_access_type, **kwds)
msg = self.session.msg("history_request", content)
self._dispatch_to_kernel(msg)
return msg["header"]["msg_id"]
def shutdown(self, restart=False):
# FIXME: What to do here?
raise NotImplementedError("Cannot shutdown in-process kernel")
def kernel_info(self):
"""Request kernel info."""
msg = self.session.msg("kernel_info_request")
self._dispatch_to_kernel(msg)
return msg["header"]["msg_id"]
def comm_info(self, target_name=None):
"""Request a dictionary of valid comms and their targets."""
if target_name is None:
content = {}
else:
content = dict(target_name=target_name)
msg = self.session.msg("comm_info_request", content)
self._dispatch_to_kernel(msg)
return msg["header"]["msg_id"]
def input(self, string):
if self.kernel is None:
raise RuntimeError("Cannot send input reply. No kernel exists.")
self.kernel.raw_input_str = string
def is_complete(self, code):
msg = self.session.msg("is_complete_request", {"code": code})
self._dispatch_to_kernel(msg)
return msg["header"]["msg_id"]
def _dispatch_to_kernel(self, msg):
"""Send a message to the kernel and handle a reply."""
kernel = self.kernel
if kernel is None:
raise RuntimeError("Cannot send request. No kernel exists.")
stream = kernel.shell_stream
self.session.send(stream, msg)
msg_parts = stream.recv_multipart()
loop = asyncio.get_event_loop()
loop.run_until_complete(kernel.dispatch_shell(msg_parts))
idents, reply_msg = self.session.recv(stream, copy=False)
self.shell_channel.call_handlers_later(reply_msg)
def get_shell_msg(self, block=True, timeout=None):
return self.shell_channel.get_msg(block, timeout)
def get_iopub_msg(self, block=True, timeout=None):
return self.iopub_channel.get_msg(block, timeout)
def get_stdin_msg(self, block=True, timeout=None):
return self.stdin_channel.get_msg(block, timeout)
def get_control_msg(self, block=True, timeout=None):
return self.control_channel.get_msg(block, timeout)
# -----------------------------------------------------------------------------
# ABC Registration
# -----------------------------------------------------------------------------
KernelClientABC.register(InProcessKernelClient)

View File

@@ -0,0 +1,8 @@
"""Shared constants.
"""
# Because inprocess communication is not networked, we can use a common Session
# key everywhere. This is not just the empty bytestring to avoid tripping
# certain security checks in the rest of Jupyter that assumes that empty keys
# are insecure.
INPROCESS_KEY = b"inprocess"

View File

@@ -0,0 +1,191 @@
"""An in-process kernel"""
# Copyright (c) IPython Development Team.
# Distributed under the terms of the Modified BSD License.
import logging
import sys
from contextlib import contextmanager
from IPython.core.interactiveshell import InteractiveShellABC
from traitlets import Any, Enum, Instance, List, Type, default
from ipykernel.ipkernel import IPythonKernel
from ipykernel.jsonutil import json_clean
from ipykernel.zmqshell import ZMQInteractiveShell
from ..iostream import BackgroundSocket, IOPubThread, OutStream
from .constants import INPROCESS_KEY
from .socket import DummySocket
# -----------------------------------------------------------------------------
# Main kernel class
# -----------------------------------------------------------------------------
class InProcessKernel(IPythonKernel):
# -------------------------------------------------------------------------
# InProcessKernel interface
# -------------------------------------------------------------------------
# The frontends connected to this kernel.
frontends = List(Instance("ipykernel.inprocess.client.InProcessKernelClient", allow_none=True))
# The GUI environment that the kernel is running under. This need not be
# specified for the normal operation for the kernel, but is required for
# IPython's GUI support (including pylab). The default is 'inline' because
# it is safe under all GUI toolkits.
gui = Enum(("tk", "gtk", "wx", "qt", "qt4", "inline"), default_value="inline")
raw_input_str = Any()
stdout = Any()
stderr = Any()
# -------------------------------------------------------------------------
# Kernel interface
# -------------------------------------------------------------------------
shell_class = Type(allow_none=True)
_underlying_iopub_socket = Instance(DummySocket, ())
iopub_thread = Instance(IOPubThread)
shell_stream = Instance(DummySocket, ())
@default("iopub_thread")
def _default_iopub_thread(self):
thread = IOPubThread(self._underlying_iopub_socket)
thread.start()
return thread
iopub_socket = Instance(BackgroundSocket)
@default("iopub_socket")
def _default_iopub_socket(self):
return self.iopub_thread.background_socket
stdin_socket = Instance(DummySocket, ())
def __init__(self, **traits):
super().__init__(**traits)
self._underlying_iopub_socket.observe(self._io_dispatch, names=["message_sent"])
self.shell.kernel = self
async def execute_request(self, stream, ident, parent):
"""Override for temporary IO redirection."""
with self._redirected_io():
await super().execute_request(stream, ident, parent)
def start(self):
"""Override registration of dispatchers for streams."""
self.shell.exit_now = False
async def _abort_queues(self):
"""The in-process kernel doesn't abort requests."""
pass
async def _flush_control_queue(self):
"""No need to flush control queues for in-process"""
pass
def _input_request(self, prompt, ident, parent, password=False):
# Flush output before making the request.
self.raw_input_str = None
sys.stderr.flush()
sys.stdout.flush()
# Send the input request.
content = json_clean(dict(prompt=prompt, password=password))
msg = self.session.msg("input_request", content, parent)
for frontend in self.frontends:
if frontend.session.session == parent["header"]["session"]:
frontend.stdin_channel.call_handlers(msg)
break
else:
logging.error("No frontend found for raw_input request")
return ""
# Await a response.
while self.raw_input_str is None:
frontend.stdin_channel.process_events()
return self.raw_input_str
# -------------------------------------------------------------------------
# Protected interface
# -------------------------------------------------------------------------
@contextmanager
def _redirected_io(self):
"""Temporarily redirect IO to the kernel."""
sys_stdout, sys_stderr = sys.stdout, sys.stderr
sys.stdout, sys.stderr = self.stdout, self.stderr
yield
sys.stdout, sys.stderr = sys_stdout, sys_stderr
# ------ Trait change handlers --------------------------------------------
def _io_dispatch(self, change):
"""Called when a message is sent to the IO socket."""
ident, msg = self.session.recv(self.iopub_socket.io_thread.socket, copy=False)
for frontend in self.frontends:
frontend.iopub_channel.call_handlers(msg)
# ------ Trait initializers -----------------------------------------------
@default("log")
def _default_log(self):
return logging.getLogger(__name__)
@default("session")
def _default_session(self):
from jupyter_client.session import Session
return Session(parent=self, key=INPROCESS_KEY)
@default("shell_class")
def _default_shell_class(self):
return InProcessInteractiveShell
@default("stdout")
def _default_stdout(self):
return OutStream(self.session, self.iopub_thread, "stdout", watchfd=False)
@default("stderr")
def _default_stderr(self):
return OutStream(self.session, self.iopub_thread, "stderr", watchfd=False)
# -----------------------------------------------------------------------------
# Interactive shell subclass
# -----------------------------------------------------------------------------
class InProcessInteractiveShell(ZMQInteractiveShell):
kernel = Instance("ipykernel.inprocess.ipkernel.InProcessKernel", allow_none=True)
# -------------------------------------------------------------------------
# InteractiveShell interface
# -------------------------------------------------------------------------
def enable_gui(self, gui=None):
"""Enable GUI integration for the kernel."""
if not gui:
gui = self.kernel.gui
self.active_eventloop = gui
def enable_matplotlib(self, gui=None):
"""Enable matplotlib integration for the kernel."""
if not gui:
gui = self.kernel.gui
return super().enable_matplotlib(gui)
def enable_pylab(self, gui=None, import_all=True, welcome_message=False):
"""Activate pylab support at runtime."""
if not gui:
gui = self.kernel.gui
return super().enable_pylab(gui, import_all, welcome_message)
InteractiveShellABC.register(InProcessInteractiveShell)

View File

@@ -0,0 +1,82 @@
"""A kernel manager for in-process kernels."""
# Copyright (c) IPython Development Team.
# Distributed under the terms of the Modified BSD License.
from jupyter_client.manager import KernelManager
from jupyter_client.managerabc import KernelManagerABC
from jupyter_client.session import Session
from traitlets import DottedObjectName, Instance, default
from .constants import INPROCESS_KEY
class InProcessKernelManager(KernelManager):
"""A manager for an in-process kernel.
This class implements the interface of
`jupyter_client.kernelmanagerabc.KernelManagerABC` and allows
(asynchronous) frontends to be used seamlessly with an in-process kernel.
See `jupyter_client.kernelmanager.KernelManager` for docstrings.
"""
# The kernel process with which the KernelManager is communicating.
kernel = Instance("ipykernel.inprocess.ipkernel.InProcessKernel", allow_none=True)
# the client class for KM.client() shortcut
client_class = DottedObjectName("ipykernel.inprocess.BlockingInProcessKernelClient")
@default("blocking_class")
def _default_blocking_class(self):
from .blocking import BlockingInProcessKernelClient
return BlockingInProcessKernelClient
@default("session")
def _default_session(self):
# don't sign in-process messages
return Session(key=INPROCESS_KEY, parent=self)
# --------------------------------------------------------------------------
# Kernel management methods
# --------------------------------------------------------------------------
def start_kernel(self, **kwds):
from ipykernel.inprocess.ipkernel import InProcessKernel
self.kernel = InProcessKernel(parent=self, session=self.session)
def shutdown_kernel(self):
self.kernel.iopub_thread.stop()
self._kill_kernel()
def restart_kernel(self, now=False, **kwds):
self.shutdown_kernel()
self.start_kernel(**kwds)
@property
def has_kernel(self):
return self.kernel is not None
def _kill_kernel(self):
self.kernel = None
def interrupt_kernel(self):
raise NotImplementedError("Cannot interrupt in-process kernel.")
def signal_kernel(self, signum):
raise NotImplementedError("Cannot signal in-process kernel.")
def is_alive(self):
return self.kernel is not None
def client(self, **kwargs):
kwargs["kernel"] = self.kernel
return super().client(**kwargs)
# -----------------------------------------------------------------------------
# ABC Registration
# -----------------------------------------------------------------------------
KernelManagerABC.register(InProcessKernelManager)

View File

@@ -0,0 +1,40 @@
""" Defines a dummy socket implementing (part of) the zmq.Socket interface. """
# Copyright (c) IPython Development Team.
# Distributed under the terms of the Modified BSD License.
from queue import Queue
import zmq
from traitlets import HasTraits, Instance, Int
# -----------------------------------------------------------------------------
# Dummy socket class
# -----------------------------------------------------------------------------
class DummySocket(HasTraits):
"""A dummy socket implementing (part of) the zmq.Socket interface."""
queue = Instance(Queue, ())
message_sent = Int(0) # Should be an Event
context = Instance(zmq.Context)
def _context_default(self):
return zmq.Context()
# -------------------------------------------------------------------------
# Socket interface
# -------------------------------------------------------------------------
def recv_multipart(self, flags=0, copy=True, track=False):
return self.queue.get_nowait()
def send_multipart(self, msg_parts, flags=0, copy=True, track=False):
msg_parts = list(map(zmq.Message, msg_parts)) # type:ignore[arg-type]
self.queue.put_nowait(msg_parts)
self.message_sent += 1
def flush(self, timeout=1.0):
"""no-op to comply with stream API"""
pass

View File

@@ -0,0 +1,156 @@
# Copyright (c) IPython Development Team.
# Distributed under the terms of the Modified BSD License.
import asyncio
import sys
import unittest
from contextlib import contextmanager
from io import StringIO
import pytest
import tornado
from IPython.utils.io import capture_output
from jupyter_client.session import Session
from ipykernel.inprocess.blocking import BlockingInProcessKernelClient
from ipykernel.inprocess.ipkernel import InProcessKernel
from ipykernel.inprocess.manager import InProcessKernelManager
from ipykernel.tests.utils import assemble_output
orig_msg = Session.msg
def _init_asyncio_patch():
"""set default asyncio policy to be compatible with tornado
Tornado 6 (at least) is not compatible with the default
asyncio implementation on Windows
Pick the older SelectorEventLoopPolicy on Windows
if the known-incompatible default policy is in use.
do this as early as possible to make it a low priority and overrideable
ref: https://github.com/tornadoweb/tornado/issues/2608
FIXME: if/when tornado supports the defaults in asyncio,
remove and bump tornado requirement for py38
"""
if (
sys.platform.startswith("win")
and sys.version_info >= (3, 8)
and tornado.version_info < (6, 1)
):
import asyncio
try:
from asyncio import (
WindowsProactorEventLoopPolicy,
WindowsSelectorEventLoopPolicy,
)
except ImportError:
pass
# not affected
else:
if type(asyncio.get_event_loop_policy()) is WindowsProactorEventLoopPolicy:
# WindowsProactorEventLoopPolicy is not compatible with tornado 6
# fallback to the pre-3.8 default of Selector
asyncio.set_event_loop_policy(WindowsSelectorEventLoopPolicy())
def _inject_cell_id(_self, *args, **kwargs):
"""
This patch jupyter_client.session:Session.msg to add a cell_id to the return message metadata
"""
assert isinstance(_self, Session)
res = orig_msg(_self, *args, **kwargs)
assert "cellId" not in res["metadata"]
res["metadata"]["cellId"] = "test_cell_id"
return res
@contextmanager
def patch_cell_id():
try:
Session.msg = _inject_cell_id
yield
finally:
Session.msg = orig_msg
class InProcessKernelTestCase(unittest.TestCase):
def setUp(self):
_init_asyncio_patch()
self.km = InProcessKernelManager()
self.km.start_kernel()
self.kc = self.km.client()
self.kc.start_channels()
self.kc.wait_for_ready()
def test_with_cell_id(self):
with patch_cell_id():
self.kc.execute("1+1")
def test_pylab(self):
"""Does %pylab work in the in-process kernel?"""
_ = pytest.importorskip("matplotlib", reason="This test requires matplotlib")
kc = self.kc
kc.execute("%pylab")
out, err = assemble_output(kc.get_iopub_msg)
self.assertIn("matplotlib", out)
def test_raw_input(self):
"""Does the in-process kernel handle raw_input correctly?"""
io = StringIO("foobar\n")
sys_stdin = sys.stdin
sys.stdin = io
try:
self.kc.execute("x = input()")
finally:
sys.stdin = sys_stdin
assert self.km.kernel.shell.user_ns.get("x") == "foobar"
@pytest.mark.skipif("__pypy__" in sys.builtin_module_names, reason="fails on pypy")
def test_stdout(self):
"""Does the in-process kernel correctly capture IO?"""
kernel = InProcessKernel()
with capture_output() as io:
kernel.shell.run_cell('print("foo")')
assert io.stdout == "foo\n"
kc = BlockingInProcessKernelClient(kernel=kernel, session=kernel.session)
kernel.frontends.append(kc)
kc.execute('print("bar")')
out, err = assemble_output(kc.get_iopub_msg)
assert out == "bar\n"
@pytest.mark.skip(reason="Currently don't capture during test as pytest does its own capturing")
def test_capfd(self):
"""Does correctly capture fd"""
kernel = InProcessKernel()
with capture_output() as io:
kernel.shell.run_cell('print("foo")')
assert io.stdout == "foo\n"
kc = BlockingInProcessKernelClient(kernel=kernel, session=kernel.session)
kernel.frontends.append(kc)
kc.execute("import os")
kc.execute('os.system("echo capfd")')
out, err = assemble_output(kc.iopub_channel)
assert out == "capfd\n"
def test_getpass_stream(self):
"Tests that kernel getpass accept the stream parameter"
kernel = InProcessKernel()
kernel._allow_stdin = True
kernel._input_request = lambda *args, **kwargs: None
kernel.getpass(stream="non empty")
def test_do_execute(self):
kernel = InProcessKernel()
asyncio.run(kernel.do_execute("a=1", True))
assert kernel.shell.user_ns["a"] == 1

View File

@@ -0,0 +1,106 @@
# Copyright (c) IPython Development Team.
# Distributed under the terms of the Modified BSD License.
import unittest
from ipykernel.inprocess.manager import InProcessKernelManager
# -----------------------------------------------------------------------------
# Test case
# -----------------------------------------------------------------------------
class InProcessKernelManagerTestCase(unittest.TestCase):
def setUp(self):
self.km = InProcessKernelManager()
def tearDown(self):
if self.km.has_kernel:
self.km.shutdown_kernel()
def test_interface(self):
"""Does the in-process kernel manager implement the basic KM interface?"""
km = self.km
assert not km.has_kernel
km.start_kernel()
assert km.has_kernel
assert km.kernel is not None
kc = km.client()
assert not kc.channels_running
kc.start_channels()
assert kc.channels_running
old_kernel = km.kernel
km.restart_kernel()
self.assertIsNotNone(km.kernel)
assert km.kernel != old_kernel
km.shutdown_kernel()
assert not km.has_kernel
self.assertRaises(NotImplementedError, km.interrupt_kernel)
self.assertRaises(NotImplementedError, km.signal_kernel, 9)
kc.stop_channels()
assert not kc.channels_running
def test_execute(self):
"""Does executing code in an in-process kernel work?"""
km = self.km
km.start_kernel()
kc = km.client()
kc.start_channels()
kc.wait_for_ready()
kc.execute("foo = 1")
assert km.kernel.shell.user_ns["foo"] == 1
def test_complete(self):
"""Does requesting completion from an in-process kernel work?"""
km = self.km
km.start_kernel()
kc = km.client()
kc.start_channels()
kc.wait_for_ready()
km.kernel.shell.push({"my_bar": 0, "my_baz": 1})
kc.complete("my_ba", 5)
msg = kc.get_shell_msg()
assert msg["header"]["msg_type"] == "complete_reply"
self.assertEqual(sorted(msg["content"]["matches"]), ["my_bar", "my_baz"])
def test_inspect(self):
"""Does requesting object information from an in-process kernel work?"""
km = self.km
km.start_kernel()
kc = km.client()
kc.start_channels()
kc.wait_for_ready()
km.kernel.shell.user_ns["foo"] = 1
kc.inspect("foo")
msg = kc.get_shell_msg()
assert msg["header"]["msg_type"] == "inspect_reply"
content = msg["content"]
assert content["found"]
text = content["data"]["text/plain"]
self.assertIn("int", text)
def test_history(self):
"""Does requesting history from an in-process kernel work?"""
km = self.km
km.start_kernel()
kc = km.client()
kc.start_channels()
kc.wait_for_ready()
kc.execute("1")
kc.history(hist_access_type="tail", n=1)
msg = kc.shell_channel.get_msgs()[-1]
assert msg["header"]["msg_type"] == "history_reply"
history = msg["content"]["history"]
assert len(history) == 1
assert history[0][2] == "1"
if __name__ == "__main__":
unittest.main()