mirror of
https://github.com/aykhans/AzSuicideDataVisualization.git
synced 2025-07-01 14:07:48 +00:00
first commit
This commit is contained in:
47
.venv/Lib/site-packages/ipykernel/tests/__init__.py
Normal file
47
.venv/Lib/site-packages/ipykernel/tests/__init__.py
Normal file
@ -0,0 +1,47 @@
|
||||
# Copyright (c) IPython Development Team.
|
||||
# Distributed under the terms of the Modified BSD License.
|
||||
|
||||
import os
|
||||
import shutil
|
||||
import sys
|
||||
import tempfile
|
||||
from unittest.mock import patch
|
||||
|
||||
from ipykernel.kernelspec import install
|
||||
|
||||
pjoin = os.path.join
|
||||
|
||||
tmp = None
|
||||
patchers = []
|
||||
|
||||
|
||||
def setup():
|
||||
"""setup temporary env for tests"""
|
||||
global tmp
|
||||
tmp = tempfile.mkdtemp()
|
||||
patchers[:] = [
|
||||
patch.dict(
|
||||
os.environ,
|
||||
{
|
||||
"HOME": tmp,
|
||||
# Let tests work with --user install when HOME is changed:
|
||||
"PYTHONPATH": os.pathsep.join(sys.path),
|
||||
},
|
||||
),
|
||||
]
|
||||
for p in patchers:
|
||||
p.start()
|
||||
|
||||
# install IPython in the temp home:
|
||||
install(user=True)
|
||||
|
||||
|
||||
def teardown():
|
||||
for p in patchers:
|
||||
p.stop()
|
||||
|
||||
try:
|
||||
shutil.rmtree(tmp)
|
||||
except OSError:
|
||||
# no such file
|
||||
pass
|
17
.venv/Lib/site-packages/ipykernel/tests/_asyncio_utils.py
Normal file
17
.venv/Lib/site-packages/ipykernel/tests/_asyncio_utils.py
Normal file
@ -0,0 +1,17 @@
|
||||
"""test utilities that use async/await syntax
|
||||
|
||||
a separate file to avoid syntax errors on Python 2
|
||||
"""
|
||||
|
||||
import asyncio
|
||||
|
||||
|
||||
def async_func():
|
||||
"""Simple async function to schedule a task on the current eventloop"""
|
||||
loop = asyncio.get_event_loop()
|
||||
assert loop.is_running()
|
||||
|
||||
async def task():
|
||||
await asyncio.sleep(1)
|
||||
|
||||
loop.create_task(task())
|
28
.venv/Lib/site-packages/ipykernel/tests/conftest.py
Normal file
28
.venv/Lib/site-packages/ipykernel/tests/conftest.py
Normal file
@ -0,0 +1,28 @@
|
||||
import asyncio
|
||||
import os
|
||||
|
||||
try:
|
||||
import resource
|
||||
except ImportError:
|
||||
# Windows
|
||||
resource = None
|
||||
|
||||
|
||||
# Handle resource limit
|
||||
# Ensure a minimal soft limit of DEFAULT_SOFT if the current hard limit is at least that much.
|
||||
if resource is not None:
|
||||
soft, hard = resource.getrlimit(resource.RLIMIT_NOFILE)
|
||||
|
||||
DEFAULT_SOFT = 4096
|
||||
if hard >= DEFAULT_SOFT:
|
||||
soft = DEFAULT_SOFT
|
||||
|
||||
if hard < soft:
|
||||
hard = soft
|
||||
|
||||
resource.setrlimit(resource.RLIMIT_NOFILE, (soft, hard))
|
||||
|
||||
|
||||
# Enforce selector event loop on Windows.
|
||||
if os.name == "nt":
|
||||
asyncio.set_event_loop_policy(asyncio.WindowsSelectorEventLoopPolicy())
|
58
.venv/Lib/site-packages/ipykernel/tests/test_async.py
Normal file
58
.venv/Lib/site-packages/ipykernel/tests/test_async.py
Normal file
@ -0,0 +1,58 @@
|
||||
"""Test async/await integration"""
|
||||
|
||||
import pytest
|
||||
|
||||
from .test_message_spec import validate_message
|
||||
from .utils import TIMEOUT, execute, flush_channels, start_new_kernel
|
||||
|
||||
KC = KM = None
|
||||
|
||||
|
||||
def setup_function():
|
||||
"""start the global kernel (if it isn't running) and return its client"""
|
||||
global KM, KC
|
||||
KM, KC = start_new_kernel()
|
||||
flush_channels(KC)
|
||||
|
||||
|
||||
def teardown_function():
|
||||
KC.stop_channels()
|
||||
KM.shutdown_kernel(now=True)
|
||||
|
||||
|
||||
def test_async_await():
|
||||
flush_channels(KC)
|
||||
msg_id, content = execute("import asyncio; await asyncio.sleep(0.1)", KC)
|
||||
assert content["status"] == "ok", content
|
||||
|
||||
|
||||
@pytest.mark.parametrize("asynclib", ["asyncio", "trio", "curio"])
|
||||
def test_async_interrupt(asynclib, request):
|
||||
try:
|
||||
__import__(asynclib)
|
||||
except ImportError:
|
||||
pytest.skip("Requires %s" % asynclib)
|
||||
request.addfinalizer(lambda: execute("%autoawait asyncio", KC))
|
||||
|
||||
flush_channels(KC)
|
||||
msg_id, content = execute("%autoawait " + asynclib, KC)
|
||||
assert content["status"] == "ok", content
|
||||
|
||||
flush_channels(KC)
|
||||
msg_id = KC.execute(f"print('begin'); import {asynclib}; await {asynclib}.sleep(5)")
|
||||
busy = KC.get_iopub_msg(timeout=TIMEOUT)
|
||||
validate_message(busy, "status", msg_id)
|
||||
assert busy["content"]["execution_state"] == "busy"
|
||||
echo = KC.get_iopub_msg(timeout=TIMEOUT)
|
||||
validate_message(echo, "execute_input")
|
||||
stream = KC.get_iopub_msg(timeout=TIMEOUT)
|
||||
# wait for the stream output to be sure kernel is in the async block
|
||||
validate_message(stream, "stream")
|
||||
assert stream["content"]["text"] == "begin\n"
|
||||
|
||||
KM.interrupt_kernel()
|
||||
reply = KC.get_shell_msg()["content"]
|
||||
assert reply["status"] == "error", reply
|
||||
assert reply["ename"] in {"CancelledError", "KeyboardInterrupt"}
|
||||
|
||||
flush_channels(KC)
|
131
.venv/Lib/site-packages/ipykernel/tests/test_connect.py
Normal file
131
.venv/Lib/site-packages/ipykernel/tests/test_connect.py
Normal file
@ -0,0 +1,131 @@
|
||||
"""Tests for kernel connection utilities"""
|
||||
|
||||
# Copyright (c) IPython Development Team.
|
||||
# Distributed under the terms of the Modified BSD License.
|
||||
|
||||
import errno
|
||||
import json
|
||||
import os
|
||||
from tempfile import TemporaryDirectory
|
||||
from unittest.mock import patch
|
||||
|
||||
import pytest
|
||||
import zmq
|
||||
from traitlets.config import Config
|
||||
|
||||
from ipykernel import connect
|
||||
from ipykernel.kernelapp import IPKernelApp
|
||||
|
||||
from .utils import TemporaryWorkingDirectory
|
||||
|
||||
sample_info = {
|
||||
"ip": "1.2.3.4",
|
||||
"transport": "ipc",
|
||||
"shell_port": 1,
|
||||
"hb_port": 2,
|
||||
"iopub_port": 3,
|
||||
"stdin_port": 4,
|
||||
"control_port": 5,
|
||||
"key": b"abc123",
|
||||
"signature_scheme": "hmac-md5",
|
||||
}
|
||||
|
||||
|
||||
class DummyKernelApp(IPKernelApp):
|
||||
def _default_shell_port(self):
|
||||
return 0
|
||||
|
||||
def initialize(self, argv=None):
|
||||
self.init_profile_dir()
|
||||
self.init_connection_file()
|
||||
|
||||
|
||||
def test_get_connection_file():
|
||||
cfg = Config()
|
||||
with TemporaryWorkingDirectory() as d:
|
||||
cfg.ProfileDir.location = d
|
||||
cf = "kernel.json"
|
||||
app = DummyKernelApp(config=cfg, connection_file=cf)
|
||||
app.initialize()
|
||||
|
||||
profile_cf = os.path.join(app.connection_dir, cf)
|
||||
assert profile_cf == app.abs_connection_file
|
||||
with open(profile_cf, "w") as f:
|
||||
f.write("{}")
|
||||
assert os.path.exists(profile_cf)
|
||||
assert connect.get_connection_file(app) == profile_cf
|
||||
|
||||
app.connection_file = cf
|
||||
assert connect.get_connection_file(app) == profile_cf
|
||||
|
||||
|
||||
def test_get_connection_info():
|
||||
with TemporaryDirectory() as d:
|
||||
cf = os.path.join(d, "kernel.json")
|
||||
connect.write_connection_file(cf, **sample_info)
|
||||
json_info = connect.get_connection_info(cf)
|
||||
info = connect.get_connection_info(cf, unpack=True)
|
||||
assert isinstance(json_info, str)
|
||||
|
||||
sub_info = {k: v for k, v in info.items() if k in sample_info}
|
||||
assert sub_info == sample_info
|
||||
|
||||
info2 = json.loads(json_info)
|
||||
info2["key"] = info2["key"].encode("utf-8")
|
||||
sub_info2 = {k: v for k, v in info.items() if k in sample_info}
|
||||
assert sub_info2 == sample_info
|
||||
|
||||
|
||||
def test_port_bind_failure_raises(request):
|
||||
cfg = Config()
|
||||
with TemporaryWorkingDirectory() as d:
|
||||
cfg.ProfileDir.location = d
|
||||
cf = "kernel.json"
|
||||
app = DummyKernelApp(config=cfg, connection_file=cf)
|
||||
request.addfinalizer(app.close)
|
||||
app.initialize()
|
||||
with patch.object(app, "_try_bind_socket") as mock_try_bind:
|
||||
mock_try_bind.side_effect = zmq.ZMQError(-100, "fails for unknown error types")
|
||||
with pytest.raises(zmq.ZMQError):
|
||||
app.init_sockets()
|
||||
assert mock_try_bind.call_count == 1
|
||||
|
||||
|
||||
def test_port_bind_failure_recovery(request):
|
||||
try:
|
||||
errno.WSAEADDRINUSE
|
||||
except AttributeError:
|
||||
# Fake windows address in-use code
|
||||
p = patch.object(errno, "WSAEADDRINUSE", 12345, create=True)
|
||||
p.start()
|
||||
request.addfinalizer(p.stop)
|
||||
|
||||
cfg = Config()
|
||||
with TemporaryWorkingDirectory() as d:
|
||||
cfg.ProfileDir.location = d
|
||||
cf = "kernel.json"
|
||||
app = DummyKernelApp(config=cfg, connection_file=cf)
|
||||
request.addfinalizer(app.close)
|
||||
app.initialize()
|
||||
with patch.object(app, "_try_bind_socket") as mock_try_bind:
|
||||
mock_try_bind.side_effect = [
|
||||
zmq.ZMQError(errno.EADDRINUSE, "fails for non-bind unix"),
|
||||
zmq.ZMQError(errno.WSAEADDRINUSE, "fails for non-bind windows"),
|
||||
] + [0] * 100
|
||||
# Shouldn't raise anything as retries will kick in
|
||||
app.init_sockets()
|
||||
|
||||
|
||||
def test_port_bind_failure_gives_up_retries(request):
|
||||
cfg = Config()
|
||||
with TemporaryWorkingDirectory() as d:
|
||||
cfg.ProfileDir.location = d
|
||||
cf = "kernel.json"
|
||||
app = DummyKernelApp(config=cfg, connection_file=cf)
|
||||
request.addfinalizer(app.close)
|
||||
app.initialize()
|
||||
with patch.object(app, "_try_bind_socket") as mock_try_bind:
|
||||
mock_try_bind.side_effect = zmq.ZMQError(errno.EADDRINUSE, "fails for non-bind")
|
||||
with pytest.raises(zmq.ZMQError):
|
||||
app.init_sockets()
|
||||
assert mock_try_bind.call_count == 100
|
284
.venv/Lib/site-packages/ipykernel/tests/test_debugger.py
Normal file
284
.venv/Lib/site-packages/ipykernel/tests/test_debugger.py
Normal file
@ -0,0 +1,284 @@
|
||||
import sys
|
||||
|
||||
import pytest
|
||||
|
||||
from .utils import TIMEOUT, get_reply, new_kernel
|
||||
|
||||
seq = 0
|
||||
|
||||
# Skip if debugpy is not available
|
||||
pytest.importorskip("debugpy")
|
||||
|
||||
|
||||
def wait_for_debug_request(kernel, command, arguments=None, full_reply=False):
|
||||
"""Carry out a debug request and return the reply content.
|
||||
|
||||
It does not check if the request was successful.
|
||||
"""
|
||||
global seq
|
||||
seq += 1
|
||||
|
||||
msg = kernel.session.msg(
|
||||
"debug_request",
|
||||
{
|
||||
"type": "request",
|
||||
"seq": seq,
|
||||
"command": command,
|
||||
"arguments": arguments or {},
|
||||
},
|
||||
)
|
||||
kernel.control_channel.send(msg)
|
||||
reply = get_reply(kernel, msg["header"]["msg_id"], channel="control")
|
||||
return reply if full_reply else reply["content"]
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def kernel():
|
||||
with new_kernel() as kc:
|
||||
yield kc
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def kernel_with_debug(kernel):
|
||||
# Initialize
|
||||
wait_for_debug_request(
|
||||
kernel,
|
||||
"initialize",
|
||||
{
|
||||
"clientID": "test-client",
|
||||
"clientName": "testClient",
|
||||
"adapterID": "",
|
||||
"pathFormat": "path",
|
||||
"linesStartAt1": True,
|
||||
"columnsStartAt1": True,
|
||||
"supportsVariableType": True,
|
||||
"supportsVariablePaging": True,
|
||||
"supportsRunInTerminalRequest": True,
|
||||
"locale": "en",
|
||||
},
|
||||
)
|
||||
|
||||
# Attach
|
||||
wait_for_debug_request(kernel, "attach")
|
||||
|
||||
try:
|
||||
yield kernel
|
||||
finally:
|
||||
# Detach
|
||||
wait_for_debug_request(kernel, "disconnect", {"restart": False, "terminateDebuggee": True})
|
||||
|
||||
|
||||
def test_debug_initialize(kernel):
|
||||
reply = wait_for_debug_request(
|
||||
kernel,
|
||||
"initialize",
|
||||
{
|
||||
"clientID": "test-client",
|
||||
"clientName": "testClient",
|
||||
"adapterID": "",
|
||||
"pathFormat": "path",
|
||||
"linesStartAt1": True,
|
||||
"columnsStartAt1": True,
|
||||
"supportsVariableType": True,
|
||||
"supportsVariablePaging": True,
|
||||
"supportsRunInTerminalRequest": True,
|
||||
"locale": "en",
|
||||
},
|
||||
)
|
||||
assert reply["success"]
|
||||
|
||||
|
||||
def test_attach_debug(kernel_with_debug):
|
||||
reply = wait_for_debug_request(
|
||||
kernel_with_debug, "evaluate", {"expression": "'a' + 'b'", "context": "repl"}
|
||||
)
|
||||
assert reply["success"]
|
||||
assert reply["body"]["result"] == ""
|
||||
|
||||
|
||||
def test_set_breakpoints(kernel_with_debug):
|
||||
code = """def f(a, b):
|
||||
c = a + b
|
||||
return c
|
||||
|
||||
f(2, 3)"""
|
||||
|
||||
r = wait_for_debug_request(kernel_with_debug, "dumpCell", {"code": code})
|
||||
source = r["body"]["sourcePath"]
|
||||
|
||||
reply = wait_for_debug_request(
|
||||
kernel_with_debug,
|
||||
"setBreakpoints",
|
||||
{
|
||||
"breakpoints": [{"line": 2}],
|
||||
"source": {"path": source},
|
||||
"sourceModified": False,
|
||||
},
|
||||
)
|
||||
assert reply["success"]
|
||||
assert len(reply["body"]["breakpoints"]) == 1
|
||||
assert reply["body"]["breakpoints"][0]["verified"]
|
||||
assert reply["body"]["breakpoints"][0]["source"]["path"] == source
|
||||
|
||||
r = wait_for_debug_request(kernel_with_debug, "debugInfo")
|
||||
assert source in map(lambda b: b["source"], r["body"]["breakpoints"])
|
||||
|
||||
r = wait_for_debug_request(kernel_with_debug, "configurationDone")
|
||||
assert r["success"]
|
||||
|
||||
|
||||
def test_stop_on_breakpoint(kernel_with_debug):
|
||||
code = """def f(a, b):
|
||||
c = a + b
|
||||
return c
|
||||
|
||||
f(2, 3)"""
|
||||
|
||||
r = wait_for_debug_request(kernel_with_debug, "dumpCell", {"code": code})
|
||||
source = r["body"]["sourcePath"]
|
||||
|
||||
wait_for_debug_request(kernel_with_debug, "debugInfo")
|
||||
|
||||
wait_for_debug_request(
|
||||
kernel_with_debug,
|
||||
"setBreakpoints",
|
||||
{
|
||||
"breakpoints": [{"line": 2}],
|
||||
"source": {"path": source},
|
||||
"sourceModified": False,
|
||||
},
|
||||
)
|
||||
|
||||
wait_for_debug_request(kernel_with_debug, "configurationDone", full_reply=True)
|
||||
|
||||
kernel_with_debug.execute(code)
|
||||
|
||||
# Wait for stop on breakpoint
|
||||
msg = {"msg_type": "", "content": {}}
|
||||
while msg.get("msg_type") != "debug_event" or msg["content"].get("event") != "stopped":
|
||||
msg = kernel_with_debug.get_iopub_msg(timeout=TIMEOUT)
|
||||
|
||||
assert msg["content"]["body"]["reason"] == "breakpoint"
|
||||
|
||||
|
||||
@pytest.mark.skipif(sys.version_info >= (3, 10), reason="TODO Does not work on Python 3.10")
|
||||
def test_breakpoint_in_cell_with_leading_empty_lines(kernel_with_debug):
|
||||
code = """
|
||||
def f(a, b):
|
||||
c = a + b
|
||||
return c
|
||||
|
||||
f(2, 3)"""
|
||||
|
||||
r = wait_for_debug_request(kernel_with_debug, "dumpCell", {"code": code})
|
||||
source = r["body"]["sourcePath"]
|
||||
|
||||
wait_for_debug_request(kernel_with_debug, "debugInfo")
|
||||
|
||||
wait_for_debug_request(
|
||||
kernel_with_debug,
|
||||
"setBreakpoints",
|
||||
{
|
||||
"breakpoints": [{"line": 6}],
|
||||
"source": {"path": source},
|
||||
"sourceModified": False,
|
||||
},
|
||||
)
|
||||
|
||||
wait_for_debug_request(kernel_with_debug, "configurationDone", full_reply=True)
|
||||
|
||||
kernel_with_debug.execute(code)
|
||||
|
||||
# Wait for stop on breakpoint
|
||||
msg = {"msg_type": "", "content": {}}
|
||||
while msg.get("msg_type") != "debug_event" or msg["content"].get("event") != "stopped":
|
||||
msg = kernel_with_debug.get_iopub_msg(timeout=TIMEOUT)
|
||||
|
||||
assert msg["content"]["body"]["reason"] == "breakpoint"
|
||||
|
||||
|
||||
def test_rich_inspect_not_at_breakpoint(kernel_with_debug):
|
||||
var_name = "text"
|
||||
value = "Hello the world"
|
||||
code = f"""{var_name}='{value}'
|
||||
print({var_name})
|
||||
"""
|
||||
|
||||
msg_id = kernel_with_debug.execute(code)
|
||||
get_reply(kernel_with_debug, msg_id)
|
||||
|
||||
r = wait_for_debug_request(kernel_with_debug, "inspectVariables")
|
||||
assert var_name in list(map(lambda v: v["name"], r["body"]["variables"]))
|
||||
|
||||
reply = wait_for_debug_request(
|
||||
kernel_with_debug,
|
||||
"richInspectVariables",
|
||||
{"variableName": var_name},
|
||||
)
|
||||
|
||||
assert reply["body"]["data"] == {"text/plain": f"'{value}'"}
|
||||
|
||||
|
||||
def test_rich_inspect_at_breakpoint(kernel_with_debug):
|
||||
code = """def f(a, b):
|
||||
c = a + b
|
||||
return c
|
||||
|
||||
f(2, 3)"""
|
||||
|
||||
r = wait_for_debug_request(kernel_with_debug, "dumpCell", {"code": code})
|
||||
source = r["body"]["sourcePath"]
|
||||
|
||||
wait_for_debug_request(
|
||||
kernel_with_debug,
|
||||
"setBreakpoints",
|
||||
{
|
||||
"breakpoints": [{"line": 2}],
|
||||
"source": {"path": source},
|
||||
"sourceModified": False,
|
||||
},
|
||||
)
|
||||
|
||||
r = wait_for_debug_request(kernel_with_debug, "debugInfo")
|
||||
|
||||
r = wait_for_debug_request(kernel_with_debug, "configurationDone")
|
||||
|
||||
kernel_with_debug.execute(code)
|
||||
|
||||
# Wait for stop on breakpoint
|
||||
msg = {"msg_type": "", "content": {}}
|
||||
while msg.get("msg_type") != "debug_event" or msg["content"].get("event") != "stopped":
|
||||
msg = kernel_with_debug.get_iopub_msg(timeout=TIMEOUT)
|
||||
|
||||
stacks = wait_for_debug_request(kernel_with_debug, "stackTrace", {"threadId": 1})["body"][
|
||||
"stackFrames"
|
||||
]
|
||||
|
||||
scopes = wait_for_debug_request(kernel_with_debug, "scopes", {"frameId": stacks[0]["id"]})[
|
||||
"body"
|
||||
]["scopes"]
|
||||
|
||||
locals_ = wait_for_debug_request(
|
||||
kernel_with_debug,
|
||||
"variables",
|
||||
{
|
||||
"variablesReference": next(filter(lambda s: s["name"] == "Locals", scopes))[
|
||||
"variablesReference"
|
||||
]
|
||||
},
|
||||
)["body"]["variables"]
|
||||
|
||||
reply = wait_for_debug_request(
|
||||
kernel_with_debug,
|
||||
"richInspectVariables",
|
||||
{"variableName": locals_[0]["name"], "frameId": stacks[0]["id"]},
|
||||
)
|
||||
|
||||
assert reply["body"]["data"] == {"text/plain": locals_[0]["value"]}
|
||||
|
||||
|
||||
def test_convert_to_long_pathname():
|
||||
if sys.platform == "win32":
|
||||
from ipykernel.compiler import _convert_to_long_pathname
|
||||
|
||||
_convert_to_long_pathname(__file__)
|
190
.venv/Lib/site-packages/ipykernel/tests/test_embed_kernel.py
Normal file
190
.venv/Lib/site-packages/ipykernel/tests/test_embed_kernel.py
Normal file
@ -0,0 +1,190 @@
|
||||
"""test IPython.embed_kernel()"""
|
||||
|
||||
# Copyright (c) IPython Development Team.
|
||||
# Distributed under the terms of the Modified BSD License.
|
||||
|
||||
import json
|
||||
import os
|
||||
import sys
|
||||
import time
|
||||
from contextlib import contextmanager
|
||||
from subprocess import PIPE, Popen
|
||||
|
||||
from flaky import flaky
|
||||
from jupyter_client import BlockingKernelClient
|
||||
from jupyter_core import paths
|
||||
|
||||
SETUP_TIMEOUT = 60
|
||||
TIMEOUT = 15
|
||||
|
||||
|
||||
@contextmanager
|
||||
def setup_kernel(cmd):
|
||||
"""start an embedded kernel in a subprocess, and wait for it to be ready
|
||||
|
||||
Returns
|
||||
-------
|
||||
kernel_manager: connected KernelManager instance
|
||||
"""
|
||||
|
||||
def connection_file_ready(connection_file):
|
||||
"""Check if connection_file is a readable json file."""
|
||||
if not os.path.exists(connection_file):
|
||||
return False
|
||||
try:
|
||||
with open(connection_file) as f:
|
||||
json.load(f)
|
||||
return True
|
||||
except ValueError:
|
||||
return False
|
||||
|
||||
kernel = Popen([sys.executable, "-c", cmd], stdout=PIPE, stderr=PIPE, encoding="utf-8")
|
||||
try:
|
||||
connection_file = os.path.join(
|
||||
paths.jupyter_runtime_dir(),
|
||||
"kernel-%i.json" % kernel.pid,
|
||||
)
|
||||
# wait for connection file to exist, timeout after 5s
|
||||
tic = time.time()
|
||||
while (
|
||||
not connection_file_ready(connection_file)
|
||||
and kernel.poll() is None
|
||||
and time.time() < tic + SETUP_TIMEOUT
|
||||
):
|
||||
time.sleep(0.1)
|
||||
|
||||
# Wait 100ms for the writing to finish
|
||||
time.sleep(0.1)
|
||||
|
||||
if kernel.poll() is not None:
|
||||
o, e = kernel.communicate()
|
||||
raise OSError("Kernel failed to start:\n%s" % e)
|
||||
|
||||
if not os.path.exists(connection_file):
|
||||
if kernel.poll() is None:
|
||||
kernel.terminate()
|
||||
raise OSError("Connection file %r never arrived" % connection_file)
|
||||
|
||||
client = BlockingKernelClient(connection_file=connection_file)
|
||||
client.load_connection_file()
|
||||
client.start_channels()
|
||||
client.wait_for_ready()
|
||||
try:
|
||||
yield client
|
||||
finally:
|
||||
client.stop_channels()
|
||||
finally:
|
||||
kernel.terminate()
|
||||
kernel.wait()
|
||||
# Make sure all the fds get closed.
|
||||
for attr in ["stdout", "stderr", "stdin"]:
|
||||
fid = getattr(kernel, attr)
|
||||
if fid:
|
||||
fid.close()
|
||||
|
||||
|
||||
@flaky(max_runs=3)
|
||||
def test_embed_kernel_basic():
|
||||
"""IPython.embed_kernel() is basically functional"""
|
||||
cmd = "\n".join(
|
||||
[
|
||||
"from IPython import embed_kernel",
|
||||
"def go():",
|
||||
" a=5",
|
||||
' b="hi there"',
|
||||
" embed_kernel()",
|
||||
"go()",
|
||||
"",
|
||||
]
|
||||
)
|
||||
|
||||
with setup_kernel(cmd) as client:
|
||||
# oinfo a (int)
|
||||
client.inspect("a")
|
||||
msg = client.get_shell_msg(timeout=TIMEOUT)
|
||||
content = msg["content"]
|
||||
assert content["found"]
|
||||
|
||||
client.execute("c=a*2")
|
||||
msg = client.get_shell_msg(timeout=TIMEOUT)
|
||||
content = msg["content"]
|
||||
assert content["status"] == "ok"
|
||||
|
||||
# oinfo c (should be 10)
|
||||
client.inspect("c")
|
||||
msg = client.get_shell_msg(timeout=TIMEOUT)
|
||||
content = msg["content"]
|
||||
assert content["found"]
|
||||
text = content["data"]["text/plain"]
|
||||
assert "10" in text
|
||||
|
||||
|
||||
@flaky(max_runs=3)
|
||||
def test_embed_kernel_namespace():
|
||||
"""IPython.embed_kernel() inherits calling namespace"""
|
||||
cmd = "\n".join(
|
||||
[
|
||||
"from IPython import embed_kernel",
|
||||
"def go():",
|
||||
" a=5",
|
||||
' b="hi there"',
|
||||
" embed_kernel()",
|
||||
"go()",
|
||||
"",
|
||||
]
|
||||
)
|
||||
|
||||
with setup_kernel(cmd) as client:
|
||||
# oinfo a (int)
|
||||
client.inspect("a")
|
||||
msg = client.get_shell_msg(timeout=TIMEOUT)
|
||||
content = msg["content"]
|
||||
assert content["found"]
|
||||
text = content["data"]["text/plain"]
|
||||
assert "5" in text
|
||||
|
||||
# oinfo b (str)
|
||||
client.inspect("b")
|
||||
msg = client.get_shell_msg(timeout=TIMEOUT)
|
||||
content = msg["content"]
|
||||
assert content["found"]
|
||||
text = content["data"]["text/plain"]
|
||||
assert "hi there" in text
|
||||
|
||||
# oinfo c (undefined)
|
||||
client.inspect("c")
|
||||
msg = client.get_shell_msg(timeout=TIMEOUT)
|
||||
content = msg["content"]
|
||||
assert not content["found"]
|
||||
|
||||
|
||||
@flaky(max_runs=3)
|
||||
def test_embed_kernel_reentrant():
|
||||
"""IPython.embed_kernel() can be called multiple times"""
|
||||
cmd = "\n".join(
|
||||
[
|
||||
"from IPython import embed_kernel",
|
||||
"count = 0",
|
||||
"def go():",
|
||||
" global count",
|
||||
" embed_kernel()",
|
||||
" count = count + 1",
|
||||
"",
|
||||
"while True: go()",
|
||||
"",
|
||||
]
|
||||
)
|
||||
|
||||
with setup_kernel(cmd) as client:
|
||||
for i in range(5):
|
||||
client.inspect("count")
|
||||
msg = client.get_shell_msg(timeout=TIMEOUT)
|
||||
content = msg["content"]
|
||||
assert content["found"]
|
||||
text = content["data"]["text/plain"]
|
||||
assert str(i) in text
|
||||
|
||||
# exit from embed_kernel
|
||||
client.execute("get_ipython().exit_now = True")
|
||||
msg = client.get_shell_msg(timeout=TIMEOUT)
|
||||
time.sleep(0.2)
|
43
.venv/Lib/site-packages/ipykernel/tests/test_eventloop.py
Normal file
43
.venv/Lib/site-packages/ipykernel/tests/test_eventloop.py
Normal file
@ -0,0 +1,43 @@
|
||||
"""Test eventloop integration"""
|
||||
|
||||
import pytest
|
||||
import tornado
|
||||
|
||||
from .utils import execute, flush_channels, start_new_kernel
|
||||
|
||||
KC = KM = None
|
||||
|
||||
|
||||
def setup():
|
||||
"""start the global kernel (if it isn't running) and return its client"""
|
||||
global KM, KC
|
||||
KM, KC = start_new_kernel()
|
||||
flush_channels(KC)
|
||||
|
||||
|
||||
def teardown():
|
||||
KC.stop_channels()
|
||||
KM.shutdown_kernel(now=True)
|
||||
|
||||
|
||||
async_code = """
|
||||
from ipykernel.tests._asyncio_utils import async_func
|
||||
async_func()
|
||||
"""
|
||||
|
||||
|
||||
@pytest.mark.skipif(tornado.version_info < (5,), reason="only relevant on tornado 5")
|
||||
def test_asyncio_interrupt():
|
||||
flush_channels(KC)
|
||||
msg_id, content = execute("%gui asyncio", KC)
|
||||
assert content["status"] == "ok", content
|
||||
|
||||
flush_channels(KC)
|
||||
msg_id, content = execute(async_code, KC)
|
||||
assert content["status"] == "ok", content
|
||||
|
||||
KM.interrupt_kernel()
|
||||
|
||||
flush_channels(KC)
|
||||
msg_id, content = execute(async_code, KC)
|
||||
assert content["status"] == "ok"
|
59
.venv/Lib/site-packages/ipykernel/tests/test_heartbeat.py
Normal file
59
.venv/Lib/site-packages/ipykernel/tests/test_heartbeat.py
Normal file
@ -0,0 +1,59 @@
|
||||
"""Tests for heartbeat thread"""
|
||||
|
||||
# Copyright (c) IPython Development Team.
|
||||
# Distributed under the terms of the Modified BSD License.
|
||||
|
||||
import errno
|
||||
from unittest.mock import patch
|
||||
|
||||
import pytest
|
||||
import zmq
|
||||
|
||||
from ipykernel.heartbeat import Heartbeat
|
||||
|
||||
|
||||
def test_port_bind_failure_raises():
|
||||
heart = Heartbeat(None)
|
||||
with patch.object(heart, "_try_bind_socket") as mock_try_bind:
|
||||
mock_try_bind.side_effect = zmq.ZMQError(-100, "fails for unknown error types")
|
||||
with pytest.raises(zmq.ZMQError):
|
||||
heart._bind_socket()
|
||||
assert mock_try_bind.call_count == 1
|
||||
|
||||
|
||||
def test_port_bind_success():
|
||||
heart = Heartbeat(None)
|
||||
with patch.object(heart, "_try_bind_socket") as mock_try_bind:
|
||||
heart._bind_socket()
|
||||
assert mock_try_bind.call_count == 1
|
||||
|
||||
|
||||
def test_port_bind_failure_recovery():
|
||||
try:
|
||||
errno.WSAEADDRINUSE
|
||||
except AttributeError:
|
||||
# Fake windows address in-use code
|
||||
errno.WSAEADDRINUSE = 12345
|
||||
|
||||
try:
|
||||
heart = Heartbeat(None)
|
||||
with patch.object(heart, "_try_bind_socket") as mock_try_bind:
|
||||
mock_try_bind.side_effect = [
|
||||
zmq.ZMQError(errno.EADDRINUSE, "fails for non-bind unix"),
|
||||
zmq.ZMQError(errno.WSAEADDRINUSE, "fails for non-bind windows"),
|
||||
] + [0] * 100
|
||||
# Shouldn't raise anything as retries will kick in
|
||||
heart._bind_socket()
|
||||
finally:
|
||||
# Cleanup fake assignment
|
||||
if errno.WSAEADDRINUSE == 12345:
|
||||
del errno.WSAEADDRINUSE
|
||||
|
||||
|
||||
def test_port_bind_failure_gives_up_retries():
|
||||
heart = Heartbeat(None)
|
||||
with patch.object(heart, "_try_bind_socket") as mock_try_bind:
|
||||
mock_try_bind.side_effect = zmq.ZMQError(errno.EADDRINUSE, "fails for non-bind")
|
||||
with pytest.raises(zmq.ZMQError):
|
||||
heart._bind_socket()
|
||||
assert mock_try_bind.call_count == 100
|
53
.venv/Lib/site-packages/ipykernel/tests/test_io.py
Normal file
53
.venv/Lib/site-packages/ipykernel/tests/test_io.py
Normal file
@ -0,0 +1,53 @@
|
||||
"""Test IO capturing functionality"""
|
||||
|
||||
import io
|
||||
|
||||
import pytest
|
||||
import zmq
|
||||
from jupyter_client.session import Session
|
||||
|
||||
from ipykernel.iostream import IOPubThread, OutStream
|
||||
|
||||
|
||||
def test_io_api():
|
||||
"""Test that wrapped stdout has the same API as a normal TextIO object"""
|
||||
session = Session()
|
||||
ctx = zmq.Context()
|
||||
pub = ctx.socket(zmq.PUB)
|
||||
thread = IOPubThread(pub)
|
||||
thread.start()
|
||||
|
||||
stream = OutStream(session, thread, "stdout")
|
||||
|
||||
# cleanup unused zmq objects before we start testing
|
||||
thread.stop()
|
||||
thread.close()
|
||||
ctx.term()
|
||||
|
||||
assert stream.errors is None
|
||||
assert not stream.isatty()
|
||||
with pytest.raises(io.UnsupportedOperation):
|
||||
stream.detach()
|
||||
with pytest.raises(io.UnsupportedOperation):
|
||||
next(stream)
|
||||
with pytest.raises(io.UnsupportedOperation):
|
||||
stream.read()
|
||||
with pytest.raises(io.UnsupportedOperation):
|
||||
stream.readline()
|
||||
with pytest.raises(io.UnsupportedOperation):
|
||||
stream.seek(0)
|
||||
with pytest.raises(io.UnsupportedOperation):
|
||||
stream.tell()
|
||||
with pytest.raises(TypeError):
|
||||
stream.write(b"")
|
||||
|
||||
|
||||
def test_io_isatty():
|
||||
session = Session()
|
||||
ctx = zmq.Context()
|
||||
pub = ctx.socket(zmq.PUB)
|
||||
thread = IOPubThread(pub)
|
||||
thread.start()
|
||||
|
||||
stream = OutStream(session, thread, "stdout", isatty=True)
|
||||
assert stream.isatty()
|
119
.venv/Lib/site-packages/ipykernel/tests/test_jsonutil.py
Normal file
119
.venv/Lib/site-packages/ipykernel/tests/test_jsonutil.py
Normal file
@ -0,0 +1,119 @@
|
||||
"""Test suite for our JSON utilities."""
|
||||
|
||||
# Copyright (c) IPython Development Team.
|
||||
# Distributed under the terms of the Modified BSD License.
|
||||
|
||||
import json
|
||||
import numbers
|
||||
from binascii import a2b_base64
|
||||
from datetime import datetime
|
||||
|
||||
import pytest
|
||||
from jupyter_client._version import version_info as jupyter_client_version
|
||||
|
||||
from .. import jsonutil
|
||||
from ..jsonutil import encode_images, json_clean
|
||||
|
||||
JUPYTER_CLIENT_MAJOR_VERSION = jupyter_client_version[0]
|
||||
|
||||
|
||||
class MyInt:
|
||||
def __int__(self):
|
||||
return 389
|
||||
|
||||
|
||||
numbers.Integral.register(MyInt)
|
||||
|
||||
|
||||
class MyFloat:
|
||||
def __float__(self):
|
||||
return 3.14
|
||||
|
||||
|
||||
numbers.Real.register(MyFloat)
|
||||
|
||||
|
||||
@pytest.mark.skipif(JUPYTER_CLIENT_MAJOR_VERSION >= 7, reason="json_clean is a no-op")
|
||||
def test():
|
||||
# list of input/expected output. Use None for the expected output if it
|
||||
# can be the same as the input.
|
||||
pairs = [
|
||||
(1, None), # start with scalars
|
||||
(1.0, None),
|
||||
("a", None),
|
||||
(True, None),
|
||||
(False, None),
|
||||
(None, None),
|
||||
# Containers
|
||||
([1, 2], None),
|
||||
((1, 2), [1, 2]),
|
||||
({1, 2}, [1, 2]),
|
||||
(dict(x=1), None),
|
||||
({"x": 1, "y": [1, 2, 3], "1": "int"}, None),
|
||||
# More exotic objects
|
||||
((x for x in range(3)), [0, 1, 2]),
|
||||
(iter([1, 2]), [1, 2]),
|
||||
(datetime(1991, 7, 3, 12, 00), "1991-07-03T12:00:00.000000"),
|
||||
(MyFloat(), 3.14),
|
||||
(MyInt(), 389),
|
||||
]
|
||||
|
||||
for val, jval in pairs:
|
||||
if jval is None:
|
||||
jval = val
|
||||
out = json_clean(val)
|
||||
# validate our cleanup
|
||||
assert out == jval
|
||||
# and ensure that what we return, indeed encodes cleanly
|
||||
json.loads(json.dumps(out))
|
||||
|
||||
|
||||
@pytest.mark.skipif(JUPYTER_CLIENT_MAJOR_VERSION >= 7, reason="json_clean is a no-op")
|
||||
def test_encode_images():
|
||||
# invalid data, but the header and footer are from real files
|
||||
pngdata = b"\x89PNG\r\n\x1a\nblahblahnotactuallyvalidIEND\xaeB`\x82"
|
||||
jpegdata = b"\xff\xd8\xff\xe0\x00\x10JFIFblahblahjpeg(\xa0\x0f\xff\xd9"
|
||||
pdfdata = b"%PDF-1.\ntrailer<</Root<</Pages<</Kids[<</MediaBox[0 0 3 3]>>]>>>>>>"
|
||||
bindata = b"\xff\xff\xff\xff"
|
||||
|
||||
fmt = {
|
||||
"image/png": pngdata,
|
||||
"image/jpeg": jpegdata,
|
||||
"application/pdf": pdfdata,
|
||||
"application/unrecognized": bindata,
|
||||
}
|
||||
encoded = json_clean(encode_images(fmt))
|
||||
for key, value in fmt.items():
|
||||
# encoded has unicode, want bytes
|
||||
decoded = a2b_base64(encoded[key])
|
||||
assert decoded == value
|
||||
encoded2 = json_clean(encode_images(encoded))
|
||||
assert encoded == encoded2
|
||||
|
||||
for key, value in fmt.items():
|
||||
decoded = a2b_base64(encoded[key])
|
||||
assert decoded == value
|
||||
|
||||
|
||||
@pytest.mark.skipif(JUPYTER_CLIENT_MAJOR_VERSION >= 7, reason="json_clean is a no-op")
|
||||
def test_lambda():
|
||||
with pytest.raises(ValueError):
|
||||
json_clean(lambda: 1)
|
||||
|
||||
|
||||
@pytest.mark.skipif(JUPYTER_CLIENT_MAJOR_VERSION >= 7, reason="json_clean is a no-op")
|
||||
def test_exception():
|
||||
bad_dicts = [
|
||||
{1: "number", "1": "string"},
|
||||
{True: "bool", "True": "string"},
|
||||
]
|
||||
for d in bad_dicts:
|
||||
with pytest.raises(ValueError):
|
||||
json_clean(d)
|
||||
|
||||
|
||||
@pytest.mark.skipif(JUPYTER_CLIENT_MAJOR_VERSION >= 7, reason="json_clean is a no-op")
|
||||
def test_unicode_dict():
|
||||
data = {"üniço∂e": "üniço∂e"}
|
||||
clean = jsonutil.json_clean(data)
|
||||
assert data == clean
|
575
.venv/Lib/site-packages/ipykernel/tests/test_kernel.py
Normal file
575
.venv/Lib/site-packages/ipykernel/tests/test_kernel.py
Normal file
@ -0,0 +1,575 @@
|
||||
"""test the IPython Kernel"""
|
||||
|
||||
# Copyright (c) IPython Development Team.
|
||||
# Distributed under the terms of the Modified BSD License.
|
||||
|
||||
import ast
|
||||
import os.path
|
||||
import platform
|
||||
import signal
|
||||
import subprocess
|
||||
import sys
|
||||
import time
|
||||
from subprocess import Popen
|
||||
from tempfile import TemporaryDirectory
|
||||
|
||||
import IPython
|
||||
import psutil
|
||||
import pytest
|
||||
from flaky import flaky
|
||||
from IPython.paths import locate_profile
|
||||
|
||||
from .utils import (
|
||||
TIMEOUT,
|
||||
assemble_output,
|
||||
execute,
|
||||
flush_channels,
|
||||
get_reply,
|
||||
kernel,
|
||||
new_kernel,
|
||||
wait_for_idle,
|
||||
)
|
||||
|
||||
|
||||
def _check_master(kc, expected=True, stream="stdout"):
|
||||
execute(kc=kc, code="import sys")
|
||||
flush_channels(kc)
|
||||
msg_id, content = execute(kc=kc, code="print(sys.%s._is_master_process())" % stream)
|
||||
stdout, stderr = assemble_output(kc.get_iopub_msg)
|
||||
assert stdout.strip() == repr(expected)
|
||||
|
||||
|
||||
def _check_status(content):
|
||||
"""If status=error, show the traceback"""
|
||||
if content["status"] == "error":
|
||||
assert False, "".join(["\n"] + content["traceback"])
|
||||
|
||||
|
||||
# printing tests
|
||||
|
||||
|
||||
def test_simple_print():
|
||||
"""simple print statement in kernel"""
|
||||
with kernel() as kc:
|
||||
msg_id, content = execute(kc=kc, code="print('hi')")
|
||||
stdout, stderr = assemble_output(kc.get_iopub_msg)
|
||||
assert stdout == "hi\n"
|
||||
assert stderr == ""
|
||||
_check_master(kc, expected=True)
|
||||
|
||||
|
||||
@pytest.mark.skip(reason="Currently don't capture during test as pytest does its own capturing")
|
||||
def test_capture_fd():
|
||||
"""simple print statement in kernel"""
|
||||
with kernel() as kc:
|
||||
iopub = kc.iopub_channel
|
||||
msg_id, content = execute(kc=kc, code="import os; os.system('echo capsys')")
|
||||
stdout, stderr = assemble_output(iopub)
|
||||
assert stdout == "capsys\n"
|
||||
assert stderr == ""
|
||||
_check_master(kc, expected=True)
|
||||
|
||||
|
||||
@pytest.mark.skip(reason="Currently don't capture during test as pytest does its own capturing")
|
||||
def test_subprocess_peek_at_stream_fileno():
|
||||
""""""
|
||||
with kernel() as kc:
|
||||
iopub = kc.iopub_channel
|
||||
msg_id, content = execute(
|
||||
kc=kc,
|
||||
code="import subprocess, sys; subprocess.run(['python', '-c', 'import os; os.system(\"echo CAP1\"); print(\"CAP2\")'], stderr=sys.stderr)",
|
||||
)
|
||||
stdout, stderr = assemble_output(iopub)
|
||||
assert stdout == "CAP1\nCAP2\n"
|
||||
assert stderr == ""
|
||||
_check_master(kc, expected=True)
|
||||
|
||||
|
||||
def test_sys_path():
|
||||
"""test that sys.path doesn't get messed up by default"""
|
||||
with kernel() as kc:
|
||||
msg_id, content = execute(kc=kc, code="import sys; print(repr(sys.path))")
|
||||
stdout, stderr = assemble_output(kc.get_iopub_msg)
|
||||
# for error-output on failure
|
||||
sys.stderr.write(stderr)
|
||||
|
||||
sys_path = ast.literal_eval(stdout.strip())
|
||||
assert "" in sys_path
|
||||
|
||||
|
||||
def test_sys_path_profile_dir():
|
||||
"""test that sys.path doesn't get messed up when `--profile-dir` is specified"""
|
||||
|
||||
with new_kernel(["--profile-dir", locate_profile("default")]) as kc:
|
||||
msg_id, content = execute(kc=kc, code="import sys; print(repr(sys.path))")
|
||||
stdout, stderr = assemble_output(kc.get_iopub_msg)
|
||||
# for error-output on failure
|
||||
sys.stderr.write(stderr)
|
||||
|
||||
sys_path = ast.literal_eval(stdout.strip())
|
||||
assert "" in sys_path
|
||||
|
||||
|
||||
@flaky(max_runs=3)
|
||||
@pytest.mark.skipif(
|
||||
sys.platform == "win32" or (sys.platform == "darwin" and sys.version_info >= (3, 8)),
|
||||
reason="subprocess prints fail on Windows and MacOS Python 3.8+",
|
||||
)
|
||||
def test_subprocess_print():
|
||||
"""printing from forked mp.Process"""
|
||||
with new_kernel() as kc:
|
||||
|
||||
_check_master(kc, expected=True)
|
||||
flush_channels(kc)
|
||||
np = 5
|
||||
code = "\n".join(
|
||||
[
|
||||
"import time",
|
||||
"import multiprocessing as mp",
|
||||
"pool = [mp.Process(target=print, args=('hello', i,)) for i in range(%i)]" % np,
|
||||
"for p in pool: p.start()",
|
||||
"for p in pool: p.join()",
|
||||
"time.sleep(0.5),",
|
||||
]
|
||||
)
|
||||
|
||||
msg_id, content = execute(kc=kc, code=code)
|
||||
stdout, stderr = assemble_output(kc.get_iopub_msg)
|
||||
assert stdout.count("hello") == np, stdout
|
||||
for n in range(np):
|
||||
assert stdout.count(str(n)) == 1, stdout
|
||||
assert stderr == ""
|
||||
_check_master(kc, expected=True)
|
||||
_check_master(kc, expected=True, stream="stderr")
|
||||
|
||||
|
||||
@flaky(max_runs=3)
|
||||
def test_subprocess_noprint():
|
||||
"""mp.Process without print doesn't trigger iostream mp_mode"""
|
||||
with kernel() as kc:
|
||||
|
||||
np = 5
|
||||
code = "\n".join(
|
||||
[
|
||||
"import multiprocessing as mp",
|
||||
"pool = [mp.Process(target=range, args=(i,)) for i in range(%i)]" % np,
|
||||
"for p in pool: p.start()",
|
||||
"for p in pool: p.join()",
|
||||
]
|
||||
)
|
||||
|
||||
msg_id, content = execute(kc=kc, code=code)
|
||||
stdout, stderr = assemble_output(kc.get_iopub_msg)
|
||||
assert stdout == ""
|
||||
assert stderr == ""
|
||||
|
||||
_check_master(kc, expected=True)
|
||||
_check_master(kc, expected=True, stream="stderr")
|
||||
|
||||
|
||||
@flaky(max_runs=3)
|
||||
@pytest.mark.skipif(
|
||||
sys.platform == "win32" or (sys.platform == "darwin" and sys.version_info >= (3, 8)),
|
||||
reason="subprocess prints fail on Windows and MacOS Python 3.8+",
|
||||
)
|
||||
def test_subprocess_error():
|
||||
"""error in mp.Process doesn't crash"""
|
||||
with new_kernel() as kc:
|
||||
|
||||
code = "\n".join(
|
||||
[
|
||||
"import multiprocessing as mp",
|
||||
"p = mp.Process(target=int, args=('hi',))",
|
||||
"p.start()",
|
||||
"p.join()",
|
||||
]
|
||||
)
|
||||
|
||||
msg_id, content = execute(kc=kc, code=code)
|
||||
stdout, stderr = assemble_output(kc.get_iopub_msg)
|
||||
assert stdout == ""
|
||||
assert "ValueError" in stderr
|
||||
|
||||
_check_master(kc, expected=True)
|
||||
_check_master(kc, expected=True, stream="stderr")
|
||||
|
||||
|
||||
# raw_input tests
|
||||
|
||||
|
||||
def test_raw_input():
|
||||
"""test input"""
|
||||
with kernel() as kc:
|
||||
iopub = kc.iopub_channel
|
||||
|
||||
input_f = "input"
|
||||
theprompt = "prompt> "
|
||||
code = 'print({input_f}("{theprompt}"))'.format(**locals())
|
||||
msg_id = kc.execute(code, allow_stdin=True)
|
||||
msg = kc.get_stdin_msg(timeout=TIMEOUT)
|
||||
assert msg["header"]["msg_type"] == "input_request"
|
||||
content = msg["content"]
|
||||
assert content["prompt"] == theprompt
|
||||
text = "some text"
|
||||
kc.input(text)
|
||||
reply = kc.get_shell_msg(timeout=TIMEOUT)
|
||||
assert reply["content"]["status"] == "ok"
|
||||
stdout, stderr = assemble_output(kc.get_iopub_msg)
|
||||
assert stdout == text + "\n"
|
||||
|
||||
|
||||
def test_save_history():
|
||||
# Saving history from the kernel with %hist -f was failing because of
|
||||
# unicode problems on Python 2.
|
||||
with kernel() as kc, TemporaryDirectory() as td:
|
||||
file = os.path.join(td, "hist.out")
|
||||
execute("a=1", kc=kc)
|
||||
wait_for_idle(kc)
|
||||
execute('b="abcþ"', kc=kc)
|
||||
wait_for_idle(kc)
|
||||
_, reply = execute("%hist -f " + file, kc=kc)
|
||||
assert reply["status"] == "ok"
|
||||
with open(file, encoding="utf-8") as f:
|
||||
content = f.read()
|
||||
assert "a=1" in content
|
||||
assert 'b="abcþ"' in content
|
||||
|
||||
|
||||
def test_smoke_faulthandler():
|
||||
faulthadler = pytest.importorskip("faulthandler", reason="this test needs faulthandler")
|
||||
with kernel() as kc:
|
||||
# Note: faulthandler.register is not available on windows.
|
||||
code = "\n".join(
|
||||
[
|
||||
"import sys",
|
||||
"import faulthandler",
|
||||
"import signal",
|
||||
"faulthandler.enable()",
|
||||
'if not sys.platform.startswith("win32"):',
|
||||
" faulthandler.register(signal.SIGTERM)",
|
||||
]
|
||||
)
|
||||
_, reply = execute(code, kc=kc)
|
||||
assert reply["status"] == "ok", reply.get("traceback", "")
|
||||
|
||||
|
||||
def test_help_output():
|
||||
"""ipython kernel --help-all works"""
|
||||
cmd = [sys.executable, "-m", "IPython", "kernel", "--help-all"]
|
||||
proc = subprocess.run(cmd, timeout=30, capture_output=True)
|
||||
assert proc.returncode == 0, proc.stderr
|
||||
assert b"Traceback" not in proc.stderr
|
||||
assert b"Options" in proc.stdout
|
||||
assert b"Class" in proc.stdout
|
||||
|
||||
|
||||
def test_is_complete():
|
||||
with kernel() as kc:
|
||||
# There are more test cases for this in core - here we just check
|
||||
# that the kernel exposes the interface correctly.
|
||||
kc.is_complete("2+2")
|
||||
reply = kc.get_shell_msg(timeout=TIMEOUT)
|
||||
assert reply["content"]["status"] == "complete"
|
||||
|
||||
# SyntaxError
|
||||
kc.is_complete("raise = 2")
|
||||
reply = kc.get_shell_msg(timeout=TIMEOUT)
|
||||
assert reply["content"]["status"] == "invalid"
|
||||
|
||||
kc.is_complete("a = [1,\n2,")
|
||||
reply = kc.get_shell_msg(timeout=TIMEOUT)
|
||||
assert reply["content"]["status"] == "incomplete"
|
||||
assert reply["content"]["indent"] == ""
|
||||
|
||||
# Cell magic ends on two blank lines for console UIs
|
||||
kc.is_complete("%%timeit\na\n\n")
|
||||
reply = kc.get_shell_msg(timeout=TIMEOUT)
|
||||
assert reply["content"]["status"] == "complete"
|
||||
|
||||
|
||||
@pytest.mark.skipif(sys.platform != "win32", reason="only run on Windows")
|
||||
def test_complete():
|
||||
with kernel() as kc:
|
||||
execute("a = 1", kc=kc)
|
||||
wait_for_idle(kc)
|
||||
cell = "import IPython\nb = a."
|
||||
kc.complete(cell)
|
||||
reply = kc.get_shell_msg(timeout=TIMEOUT)
|
||||
|
||||
c = reply["content"]
|
||||
assert c["status"] == "ok"
|
||||
start = cell.find("a.")
|
||||
end = start + 2
|
||||
assert c["cursor_end"] == cell.find("a.") + 2
|
||||
assert c["cursor_start"] <= end
|
||||
|
||||
# there are many right answers for cursor_start,
|
||||
# so verify application of the completion
|
||||
# rather than the value of cursor_start
|
||||
|
||||
matches = c["matches"]
|
||||
assert matches
|
||||
for m in matches:
|
||||
completed = cell[: c["cursor_start"]] + m
|
||||
assert completed.startswith(cell)
|
||||
|
||||
|
||||
def test_matplotlib_inline_on_import():
|
||||
pytest.importorskip("matplotlib", reason="this test requires matplotlib")
|
||||
with kernel() as kc:
|
||||
cell = "\n".join(
|
||||
["import matplotlib, matplotlib.pyplot as plt", "backend = matplotlib.get_backend()"]
|
||||
)
|
||||
_, reply = execute(cell, user_expressions={"backend": "backend"}, kc=kc)
|
||||
_check_status(reply)
|
||||
backend_bundle = reply["user_expressions"]["backend"]
|
||||
_check_status(backend_bundle)
|
||||
assert "backend_inline" in backend_bundle["data"]["text/plain"]
|
||||
|
||||
|
||||
def test_message_order():
|
||||
N = 100 # number of messages to test
|
||||
with kernel() as kc:
|
||||
_, reply = execute("a = 1", kc=kc)
|
||||
_check_status(reply)
|
||||
offset = reply["execution_count"] + 1
|
||||
cell = "a += 1\na"
|
||||
msg_ids = []
|
||||
# submit N executions as fast as we can
|
||||
for _ in range(N):
|
||||
msg_ids.append(kc.execute(cell))
|
||||
# check message-handling order
|
||||
for i, msg_id in enumerate(msg_ids, offset):
|
||||
reply = kc.get_shell_msg(timeout=TIMEOUT)
|
||||
_check_status(reply["content"])
|
||||
assert reply["content"]["execution_count"] == i
|
||||
assert reply["parent_header"]["msg_id"] == msg_id
|
||||
|
||||
|
||||
@pytest.mark.skipif(
|
||||
sys.platform.startswith("linux") or sys.platform.startswith("darwin"),
|
||||
reason="test only on windows",
|
||||
)
|
||||
def test_unc_paths():
|
||||
with kernel() as kc, TemporaryDirectory() as td:
|
||||
drive_file_path = os.path.join(td, "unc.txt")
|
||||
with open(drive_file_path, "w+") as f:
|
||||
f.write("# UNC test")
|
||||
unc_root = "\\\\localhost\\C$"
|
||||
file_path = os.path.splitdrive(os.path.dirname(drive_file_path))[1]
|
||||
unc_file_path = os.path.join(unc_root, file_path[1:])
|
||||
|
||||
kc.execute(f"cd {unc_file_path:s}")
|
||||
reply = kc.get_shell_msg(timeout=TIMEOUT)
|
||||
assert reply["content"]["status"] == "ok"
|
||||
out, err = assemble_output(kc.get_iopub_msg)
|
||||
assert unc_file_path in out
|
||||
|
||||
flush_channels(kc)
|
||||
kc.execute(code="ls")
|
||||
reply = kc.get_shell_msg(timeout=TIMEOUT)
|
||||
assert reply["content"]["status"] == "ok"
|
||||
out, err = assemble_output(kc.get_iopub_msg)
|
||||
assert "unc.txt" in out
|
||||
|
||||
kc.execute(code="cd")
|
||||
reply = kc.get_shell_msg(timeout=TIMEOUT)
|
||||
assert reply["content"]["status"] == "ok"
|
||||
|
||||
|
||||
@pytest.mark.skipif(
|
||||
platform.python_implementation() == "PyPy",
|
||||
reason="does not work on PyPy",
|
||||
)
|
||||
def test_shutdown():
|
||||
"""Kernel exits after polite shutdown_request"""
|
||||
with new_kernel() as kc:
|
||||
km = kc.parent
|
||||
execute("a = 1", kc=kc)
|
||||
wait_for_idle(kc)
|
||||
kc.shutdown()
|
||||
for _ in range(300): # 30s timeout
|
||||
if km.is_alive():
|
||||
time.sleep(0.1)
|
||||
else:
|
||||
break
|
||||
assert not km.is_alive()
|
||||
|
||||
|
||||
def test_interrupt_during_input():
|
||||
"""
|
||||
The kernel exits after being interrupted while waiting in input().
|
||||
|
||||
input() appears to have issues other functions don't, and it needs to be
|
||||
interruptible in order for pdb to be interruptible.
|
||||
"""
|
||||
with new_kernel() as kc:
|
||||
km = kc.parent
|
||||
msg_id = kc.execute("input()")
|
||||
time.sleep(1) # Make sure it's actually waiting for input.
|
||||
km.interrupt_kernel()
|
||||
from .test_message_spec import validate_message
|
||||
|
||||
# If we failed to interrupt interrupt, this will timeout:
|
||||
reply = get_reply(kc, msg_id, TIMEOUT)
|
||||
validate_message(reply, "execute_reply", msg_id)
|
||||
|
||||
|
||||
@pytest.mark.skipif(os.name == "nt", reason="Message based interrupt not supported on Windows")
|
||||
def test_interrupt_with_message():
|
||||
""" """
|
||||
with new_kernel() as kc:
|
||||
km = kc.parent
|
||||
km.kernel_spec.interrupt_mode = "message"
|
||||
msg_id = kc.execute("input()")
|
||||
time.sleep(1) # Make sure it's actually waiting for input.
|
||||
km.interrupt_kernel()
|
||||
from .test_message_spec import validate_message
|
||||
|
||||
# If we failed to interrupt interrupt, this will timeout:
|
||||
reply = get_reply(kc, msg_id, TIMEOUT)
|
||||
validate_message(reply, "execute_reply", msg_id)
|
||||
|
||||
|
||||
@pytest.mark.skipif(
|
||||
"__pypy__" in sys.builtin_module_names,
|
||||
reason="fails on pypy",
|
||||
)
|
||||
def test_interrupt_during_pdb_set_trace():
|
||||
"""
|
||||
The kernel exits after being interrupted while waiting in pdb.set_trace().
|
||||
|
||||
Merely testing input() isn't enough, pdb has its own issues that need
|
||||
to be handled in addition.
|
||||
|
||||
This test will fail with versions of IPython < 7.14.0.
|
||||
"""
|
||||
with new_kernel() as kc:
|
||||
km = kc.parent
|
||||
msg_id = kc.execute("import pdb; pdb.set_trace()")
|
||||
msg_id2 = kc.execute("3 + 4")
|
||||
time.sleep(1) # Make sure it's actually waiting for input.
|
||||
km.interrupt_kernel()
|
||||
from .test_message_spec import validate_message
|
||||
|
||||
# If we failed to interrupt interrupt, this will timeout:
|
||||
reply = get_reply(kc, msg_id, TIMEOUT)
|
||||
validate_message(reply, "execute_reply", msg_id)
|
||||
# If we failed to interrupt interrupt, this will timeout:
|
||||
reply = get_reply(kc, msg_id2, TIMEOUT)
|
||||
validate_message(reply, "execute_reply", msg_id2)
|
||||
|
||||
|
||||
def test_control_thread_priority():
|
||||
|
||||
N = 5
|
||||
with new_kernel() as kc:
|
||||
msg_id = kc.execute("pass")
|
||||
get_reply(kc, msg_id)
|
||||
|
||||
sleep_msg_id = kc.execute("import asyncio; await asyncio.sleep(2)")
|
||||
|
||||
# submit N shell messages
|
||||
shell_msg_ids = []
|
||||
for i in range(N):
|
||||
shell_msg_ids.append(kc.execute(f"i = {i}"))
|
||||
|
||||
# ensure all shell messages have arrived at the kernel before any control messages
|
||||
time.sleep(0.5)
|
||||
# at this point, shell messages should be waiting in msg_queue,
|
||||
# rather than zmq while the kernel is still in the middle of processing
|
||||
# the first execution
|
||||
|
||||
# now send N control messages
|
||||
control_msg_ids = []
|
||||
for _ in range(N):
|
||||
msg = kc.session.msg("kernel_info_request", {})
|
||||
kc.control_channel.send(msg)
|
||||
control_msg_ids.append(msg["header"]["msg_id"])
|
||||
|
||||
# finally, collect the replies on both channels for comparison
|
||||
get_reply(kc, sleep_msg_id)
|
||||
shell_replies = []
|
||||
for msg_id in shell_msg_ids:
|
||||
shell_replies.append(get_reply(kc, msg_id))
|
||||
|
||||
control_replies = []
|
||||
for msg_id in control_msg_ids:
|
||||
control_replies.append(get_reply(kc, msg_id, channel="control"))
|
||||
|
||||
# verify that all control messages were handled before all shell messages
|
||||
shell_dates = [msg["header"]["date"] for msg in shell_replies]
|
||||
control_dates = [msg["header"]["date"] for msg in control_replies]
|
||||
# comparing first to last ought to be enough, since queues preserve order
|
||||
# use <= in case of very-fast handling and/or low resolution timers
|
||||
assert control_dates[-1] <= shell_dates[0]
|
||||
|
||||
|
||||
def _child():
|
||||
print("in child", os.getpid())
|
||||
|
||||
def _print_and_exit(sig, frame):
|
||||
print(f"Received signal {sig}")
|
||||
# take some time so retries are triggered
|
||||
time.sleep(0.5)
|
||||
sys.exit(-sig)
|
||||
|
||||
signal.signal(signal.SIGTERM, _print_and_exit)
|
||||
time.sleep(30)
|
||||
|
||||
|
||||
def _start_children():
|
||||
ip = IPython.get_ipython()
|
||||
ns = ip.user_ns
|
||||
|
||||
cmd = [sys.executable, "-c", f"from {__name__} import _child; _child()"]
|
||||
child_pg = Popen(cmd, start_new_session=False)
|
||||
child_newpg = Popen(cmd, start_new_session=True)
|
||||
ns["pid"] = os.getpid()
|
||||
ns["child_pg"] = child_pg.pid
|
||||
ns["child_newpg"] = child_newpg.pid
|
||||
# give them time to start up and register signal handlers
|
||||
time.sleep(1)
|
||||
|
||||
|
||||
@pytest.mark.skipif(
|
||||
platform.python_implementation() == "PyPy",
|
||||
reason="does not work on PyPy",
|
||||
)
|
||||
def test_shutdown_subprocesses():
|
||||
"""Kernel exits after polite shutdown_request"""
|
||||
with new_kernel() as kc:
|
||||
km = kc.parent
|
||||
msg_id, reply = execute(
|
||||
f"from {__name__} import _start_children\n_start_children()",
|
||||
kc=kc,
|
||||
user_expressions={
|
||||
"pid": "pid",
|
||||
"child_pg": "child_pg",
|
||||
"child_newpg": "child_newpg",
|
||||
},
|
||||
)
|
||||
print(reply)
|
||||
expressions = reply["user_expressions"]
|
||||
kernel_process = psutil.Process(int(expressions["pid"]["data"]["text/plain"]))
|
||||
child_pg = psutil.Process(int(expressions["child_pg"]["data"]["text/plain"]))
|
||||
child_newpg = psutil.Process(int(expressions["child_newpg"]["data"]["text/plain"]))
|
||||
wait_for_idle(kc)
|
||||
|
||||
kc.shutdown()
|
||||
for _ in range(300): # 30s timeout
|
||||
if km.is_alive():
|
||||
time.sleep(0.1)
|
||||
else:
|
||||
break
|
||||
assert not km.is_alive()
|
||||
assert not kernel_process.is_running()
|
||||
# child in the process group shut down
|
||||
assert not child_pg.is_running()
|
||||
# child outside the process group was not shut down (unix only)
|
||||
if os.name != "nt":
|
||||
assert child_newpg.is_running()
|
||||
try:
|
||||
child_newpg.terminate()
|
||||
except psutil.NoSuchProcess:
|
||||
pass
|
147
.venv/Lib/site-packages/ipykernel/tests/test_kernelspec.py
Normal file
147
.venv/Lib/site-packages/ipykernel/tests/test_kernelspec.py
Normal file
@ -0,0 +1,147 @@
|
||||
# Copyright (c) IPython Development Team.
|
||||
# Distributed under the terms of the Modified BSD License.
|
||||
|
||||
import json
|
||||
import os
|
||||
import shutil
|
||||
import sys
|
||||
import tempfile
|
||||
from unittest import mock
|
||||
|
||||
import pytest
|
||||
from jupyter_core.paths import jupyter_data_dir
|
||||
|
||||
from ipykernel.kernelspec import (
|
||||
KERNEL_NAME,
|
||||
RESOURCES,
|
||||
InstallIPythonKernelSpecApp,
|
||||
get_kernel_dict,
|
||||
install,
|
||||
make_ipkernel_cmd,
|
||||
write_kernel_spec,
|
||||
)
|
||||
|
||||
pjoin = os.path.join
|
||||
|
||||
|
||||
def test_make_ipkernel_cmd():
|
||||
cmd = make_ipkernel_cmd()
|
||||
assert cmd == [sys.executable, "-m", "ipykernel_launcher", "-f", "{connection_file}"]
|
||||
|
||||
|
||||
def assert_kernel_dict(d):
|
||||
assert d["argv"] == make_ipkernel_cmd()
|
||||
assert d["display_name"] == "Python %i (ipykernel)" % sys.version_info[0]
|
||||
assert d["language"] == "python"
|
||||
|
||||
|
||||
def test_get_kernel_dict():
|
||||
d = get_kernel_dict()
|
||||
assert_kernel_dict(d)
|
||||
|
||||
|
||||
def assert_kernel_dict_with_profile(d):
|
||||
assert d["argv"] == make_ipkernel_cmd(extra_arguments=["--profile", "test"])
|
||||
assert d["display_name"] == "Python %i (ipykernel)" % sys.version_info[0]
|
||||
assert d["language"] == "python"
|
||||
|
||||
|
||||
def test_get_kernel_dict_with_profile():
|
||||
d = get_kernel_dict(["--profile", "test"])
|
||||
assert_kernel_dict_with_profile(d)
|
||||
|
||||
|
||||
def assert_is_spec(path):
|
||||
for fname in os.listdir(RESOURCES):
|
||||
dst = pjoin(path, fname)
|
||||
assert os.path.exists(dst)
|
||||
kernel_json = pjoin(path, "kernel.json")
|
||||
assert os.path.exists(kernel_json)
|
||||
with open(kernel_json, encoding="utf8") as f:
|
||||
json.load(f)
|
||||
|
||||
|
||||
def test_write_kernel_spec():
|
||||
path = write_kernel_spec()
|
||||
assert_is_spec(path)
|
||||
shutil.rmtree(path)
|
||||
|
||||
|
||||
def test_write_kernel_spec_path():
|
||||
path = os.path.join(tempfile.mkdtemp(), KERNEL_NAME)
|
||||
path2 = write_kernel_spec(path)
|
||||
assert path == path2
|
||||
assert_is_spec(path)
|
||||
shutil.rmtree(path)
|
||||
|
||||
|
||||
def test_install_kernelspec():
|
||||
|
||||
path = tempfile.mkdtemp()
|
||||
try:
|
||||
InstallIPythonKernelSpecApp.launch_instance(argv=["--prefix", path])
|
||||
assert_is_spec(os.path.join(path, "share", "jupyter", "kernels", KERNEL_NAME))
|
||||
finally:
|
||||
shutil.rmtree(path)
|
||||
|
||||
|
||||
def test_install_user():
|
||||
tmp = tempfile.mkdtemp()
|
||||
|
||||
with mock.patch.dict(os.environ, {"HOME": tmp}):
|
||||
install(user=True)
|
||||
data_dir = jupyter_data_dir()
|
||||
|
||||
assert_is_spec(os.path.join(data_dir, "kernels", KERNEL_NAME))
|
||||
|
||||
|
||||
def test_install():
|
||||
system_jupyter_dir = tempfile.mkdtemp()
|
||||
|
||||
with mock.patch("jupyter_client.kernelspec.SYSTEM_JUPYTER_PATH", [system_jupyter_dir]):
|
||||
install()
|
||||
|
||||
assert_is_spec(os.path.join(system_jupyter_dir, "kernels", KERNEL_NAME))
|
||||
|
||||
|
||||
def test_install_profile():
|
||||
system_jupyter_dir = tempfile.mkdtemp()
|
||||
|
||||
with mock.patch("jupyter_client.kernelspec.SYSTEM_JUPYTER_PATH", [system_jupyter_dir]):
|
||||
install(profile="Test")
|
||||
|
||||
spec = os.path.join(system_jupyter_dir, "kernels", KERNEL_NAME, "kernel.json")
|
||||
with open(spec) as f:
|
||||
spec = json.load(f)
|
||||
assert spec["display_name"].endswith(" [profile=Test]")
|
||||
assert spec["argv"][-2:] == ["--profile", "Test"]
|
||||
|
||||
|
||||
def test_install_display_name_overrides_profile():
|
||||
system_jupyter_dir = tempfile.mkdtemp()
|
||||
|
||||
with mock.patch("jupyter_client.kernelspec.SYSTEM_JUPYTER_PATH", [system_jupyter_dir]):
|
||||
install(display_name="Display", profile="Test")
|
||||
|
||||
spec = os.path.join(system_jupyter_dir, "kernels", KERNEL_NAME, "kernel.json")
|
||||
with open(spec) as f:
|
||||
spec = json.load(f)
|
||||
assert spec["display_name"] == "Display"
|
||||
|
||||
|
||||
@pytest.mark.parametrize("env", [None, dict(spam="spam"), dict(spam="spam", foo="bar")])
|
||||
def test_install_env(tmp_path, env):
|
||||
# python 3.5 // tmp_path must be converted to str
|
||||
with mock.patch("jupyter_client.kernelspec.SYSTEM_JUPYTER_PATH", [str(tmp_path)]):
|
||||
install(env=env)
|
||||
|
||||
spec = tmp_path / "kernels" / KERNEL_NAME / "kernel.json"
|
||||
with spec.open() as f:
|
||||
spec = json.load(f)
|
||||
|
||||
if env:
|
||||
assert len(env) == len(spec["env"])
|
||||
for k, v in env.items():
|
||||
assert spec["env"][k] == v
|
||||
else:
|
||||
assert "env" not in spec
|
620
.venv/Lib/site-packages/ipykernel/tests/test_message_spec.py
Normal file
620
.venv/Lib/site-packages/ipykernel/tests/test_message_spec.py
Normal file
@ -0,0 +1,620 @@
|
||||
"""Test suite for our zeromq-based message specification."""
|
||||
|
||||
# Copyright (c) IPython Development Team.
|
||||
# Distributed under the terms of the Modified BSD License.
|
||||
|
||||
import re
|
||||
import sys
|
||||
from queue import Empty
|
||||
|
||||
import jupyter_client
|
||||
import pytest
|
||||
from packaging.version import Version as V
|
||||
from traitlets import (
|
||||
Bool,
|
||||
Dict,
|
||||
Enum,
|
||||
HasTraits,
|
||||
Integer,
|
||||
List,
|
||||
TraitError,
|
||||
Unicode,
|
||||
observe,
|
||||
)
|
||||
|
||||
from .utils import TIMEOUT, execute, flush_channels, get_reply, start_global_kernel
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# Globals
|
||||
# -----------------------------------------------------------------------------
|
||||
KC = None
|
||||
|
||||
|
||||
def setup():
|
||||
global KC
|
||||
KC = start_global_kernel()
|
||||
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# Message Spec References
|
||||
# -----------------------------------------------------------------------------
|
||||
|
||||
|
||||
class Reference(HasTraits):
|
||||
|
||||
"""
|
||||
Base class for message spec specification testing.
|
||||
|
||||
This class is the core of the message specification test. The
|
||||
idea is that child classes implement trait attributes for each
|
||||
message keys, so that message keys can be tested against these
|
||||
traits using :meth:`check` method.
|
||||
|
||||
"""
|
||||
|
||||
def check(self, d):
|
||||
"""validate a dict against our traits"""
|
||||
for key in self.trait_names():
|
||||
assert key in d
|
||||
# FIXME: always allow None, probably not a good idea
|
||||
if d[key] is None:
|
||||
continue
|
||||
try:
|
||||
setattr(self, key, d[key])
|
||||
except TraitError as e:
|
||||
assert False, str(e)
|
||||
|
||||
|
||||
class Version(Unicode):
|
||||
def __init__(self, *args, **kwargs):
|
||||
self.min = kwargs.pop("min", None)
|
||||
self.max = kwargs.pop("max", None)
|
||||
kwargs["default_value"] = self.min
|
||||
super().__init__(*args, **kwargs)
|
||||
|
||||
def validate(self, obj, value):
|
||||
if self.min and V(value) < V(self.min):
|
||||
raise TraitError("bad version: %s < %s" % (value, self.min))
|
||||
if self.max and (V(value) > V(self.max)):
|
||||
raise TraitError("bad version: %s > %s" % (value, self.max))
|
||||
|
||||
|
||||
class RMessage(Reference):
|
||||
msg_id = Unicode()
|
||||
msg_type = Unicode()
|
||||
header = Dict()
|
||||
parent_header = Dict()
|
||||
content = Dict()
|
||||
|
||||
def check(self, d):
|
||||
super().check(d)
|
||||
RHeader().check(self.header)
|
||||
if self.parent_header:
|
||||
RHeader().check(self.parent_header)
|
||||
|
||||
|
||||
class RHeader(Reference):
|
||||
msg_id = Unicode()
|
||||
msg_type = Unicode()
|
||||
session = Unicode()
|
||||
username = Unicode()
|
||||
version = Version(min="5.0")
|
||||
|
||||
|
||||
mime_pat = re.compile(r"^[\w\-\+\.]+/[\w\-\+\.]+$")
|
||||
|
||||
|
||||
class MimeBundle(Reference):
|
||||
metadata = Dict()
|
||||
data = Dict()
|
||||
|
||||
@observe("data")
|
||||
def _on_data_changed(self, change):
|
||||
for k, v in change["new"].items():
|
||||
assert mime_pat.match(k)
|
||||
assert isinstance(v, str)
|
||||
|
||||
|
||||
# shell replies
|
||||
class Reply(Reference):
|
||||
status = Enum(("ok", "error"), default_value="ok")
|
||||
|
||||
|
||||
class ExecuteReply(Reply):
|
||||
execution_count = Integer()
|
||||
|
||||
def check(self, d):
|
||||
Reference.check(self, d)
|
||||
if d["status"] == "ok":
|
||||
ExecuteReplyOkay().check(d)
|
||||
elif d["status"] == "error":
|
||||
ExecuteReplyError().check(d)
|
||||
elif d["status"] == "aborted":
|
||||
ExecuteReplyAborted().check(d)
|
||||
|
||||
|
||||
class ExecuteReplyOkay(Reply):
|
||||
status = Enum(("ok",))
|
||||
user_expressions = Dict()
|
||||
|
||||
|
||||
class ExecuteReplyError(Reply):
|
||||
status = Enum(("error",))
|
||||
ename = Unicode()
|
||||
evalue = Unicode()
|
||||
traceback = List(Unicode())
|
||||
|
||||
|
||||
class ExecuteReplyAborted(Reply):
|
||||
status = Enum(("aborted",))
|
||||
|
||||
|
||||
class InspectReply(Reply, MimeBundle):
|
||||
found = Bool()
|
||||
|
||||
|
||||
class ArgSpec(Reference):
|
||||
args = List(Unicode())
|
||||
varargs = Unicode()
|
||||
varkw = Unicode()
|
||||
defaults = List()
|
||||
|
||||
|
||||
class Status(Reference):
|
||||
execution_state = Enum(("busy", "idle", "starting"), default_value="busy")
|
||||
|
||||
|
||||
class CompleteReply(Reply):
|
||||
matches = List(Unicode())
|
||||
cursor_start = Integer()
|
||||
cursor_end = Integer()
|
||||
status = Unicode()
|
||||
|
||||
|
||||
class LanguageInfo(Reference):
|
||||
name = Unicode("python")
|
||||
version = Unicode(sys.version.split()[0])
|
||||
|
||||
|
||||
class KernelInfoReply(Reply):
|
||||
protocol_version = Version(min="5.0")
|
||||
implementation = Unicode("ipython")
|
||||
implementation_version = Version(min="2.1")
|
||||
language_info = Dict()
|
||||
banner = Unicode()
|
||||
|
||||
def check(self, d):
|
||||
Reference.check(self, d)
|
||||
LanguageInfo().check(d["language_info"])
|
||||
|
||||
|
||||
class ConnectReply(Reference):
|
||||
shell_port = Integer()
|
||||
control_port = Integer()
|
||||
stdin_port = Integer()
|
||||
iopub_port = Integer()
|
||||
hb_port = Integer()
|
||||
|
||||
|
||||
class CommInfoReply(Reply):
|
||||
comms = Dict()
|
||||
|
||||
|
||||
class IsCompleteReply(Reference):
|
||||
status = Enum(("complete", "incomplete", "invalid", "unknown"), default_value="complete")
|
||||
|
||||
def check(self, d):
|
||||
Reference.check(self, d)
|
||||
if d["status"] == "incomplete":
|
||||
IsCompleteReplyIncomplete().check(d)
|
||||
|
||||
|
||||
class IsCompleteReplyIncomplete(Reference):
|
||||
indent = Unicode()
|
||||
|
||||
|
||||
# IOPub messages
|
||||
|
||||
|
||||
class ExecuteInput(Reference):
|
||||
code = Unicode()
|
||||
execution_count = Integer()
|
||||
|
||||
|
||||
class Error(ExecuteReplyError):
|
||||
"""Errors are the same as ExecuteReply, but without status"""
|
||||
|
||||
status = None # no status field
|
||||
|
||||
|
||||
class Stream(Reference):
|
||||
name = Enum(("stdout", "stderr"), default_value="stdout")
|
||||
text = Unicode()
|
||||
|
||||
|
||||
class DisplayData(MimeBundle):
|
||||
pass
|
||||
|
||||
|
||||
class ExecuteResult(MimeBundle):
|
||||
execution_count = Integer()
|
||||
|
||||
|
||||
class HistoryReply(Reply):
|
||||
history = List(List())
|
||||
|
||||
|
||||
references = {
|
||||
"execute_reply": ExecuteReply(),
|
||||
"inspect_reply": InspectReply(),
|
||||
"status": Status(),
|
||||
"complete_reply": CompleteReply(),
|
||||
"kernel_info_reply": KernelInfoReply(),
|
||||
"connect_reply": ConnectReply(),
|
||||
"comm_info_reply": CommInfoReply(),
|
||||
"is_complete_reply": IsCompleteReply(),
|
||||
"execute_input": ExecuteInput(),
|
||||
"execute_result": ExecuteResult(),
|
||||
"history_reply": HistoryReply(),
|
||||
"error": Error(),
|
||||
"stream": Stream(),
|
||||
"display_data": DisplayData(),
|
||||
"header": RHeader(),
|
||||
}
|
||||
"""
|
||||
Specifications of `content` part of the reply messages.
|
||||
"""
|
||||
|
||||
|
||||
def validate_message(msg, msg_type=None, parent=None):
|
||||
"""validate a message
|
||||
|
||||
This is a generator, and must be iterated through to actually
|
||||
trigger each test.
|
||||
|
||||
If msg_type and/or parent are given, the msg_type and/or parent msg_id
|
||||
are compared with the given values.
|
||||
"""
|
||||
RMessage().check(msg)
|
||||
if msg_type:
|
||||
assert msg["msg_type"] == msg_type
|
||||
if parent:
|
||||
assert msg["parent_header"]["msg_id"] == parent
|
||||
content = msg["content"]
|
||||
ref = references[msg["msg_type"]]
|
||||
ref.check(content)
|
||||
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# Tests
|
||||
# -----------------------------------------------------------------------------
|
||||
|
||||
# Shell channel
|
||||
|
||||
|
||||
def test_execute():
|
||||
flush_channels()
|
||||
|
||||
msg_id = KC.execute(code="x=1")
|
||||
reply = get_reply(KC, msg_id, TIMEOUT)
|
||||
validate_message(reply, "execute_reply", msg_id)
|
||||
|
||||
|
||||
def test_execute_silent():
|
||||
flush_channels()
|
||||
msg_id, reply = execute(code="x=1", silent=True)
|
||||
|
||||
# flush status=idle
|
||||
status = KC.get_iopub_msg(timeout=TIMEOUT)
|
||||
validate_message(status, "status", msg_id)
|
||||
assert status["content"]["execution_state"] == "idle"
|
||||
|
||||
with pytest.raises(Empty):
|
||||
KC.get_iopub_msg(timeout=0.1)
|
||||
|
||||
count = reply["execution_count"]
|
||||
|
||||
msg_id, reply = execute(code="x=2", silent=True)
|
||||
|
||||
# flush status=idle
|
||||
status = KC.get_iopub_msg(timeout=TIMEOUT)
|
||||
validate_message(status, "status", msg_id)
|
||||
assert status["content"]["execution_state"] == "idle"
|
||||
|
||||
with pytest.raises(Empty):
|
||||
KC.get_iopub_msg(timeout=0.1)
|
||||
|
||||
count_2 = reply["execution_count"]
|
||||
assert count_2 == count
|
||||
|
||||
|
||||
def test_execute_error():
|
||||
flush_channels()
|
||||
|
||||
msg_id, reply = execute(code="1/0")
|
||||
assert reply["status"] == "error"
|
||||
assert reply["ename"] == "ZeroDivisionError"
|
||||
|
||||
error = KC.get_iopub_msg(timeout=TIMEOUT)
|
||||
validate_message(error, "error", msg_id)
|
||||
|
||||
|
||||
def test_execute_inc():
|
||||
"""execute request should increment execution_count"""
|
||||
flush_channels()
|
||||
|
||||
_, reply = execute(code="x=1")
|
||||
count = reply["execution_count"]
|
||||
|
||||
flush_channels()
|
||||
|
||||
_, reply = execute(code="x=2")
|
||||
count_2 = reply["execution_count"]
|
||||
assert count_2 == count + 1
|
||||
|
||||
|
||||
def test_execute_stop_on_error():
|
||||
"""execute request should not abort execution queue with stop_on_error False"""
|
||||
flush_channels()
|
||||
|
||||
fail = "\n".join(
|
||||
[
|
||||
# sleep to ensure subsequent message is waiting in the queue to be aborted
|
||||
# async sleep to ensure coroutines are processing while this happens
|
||||
"import asyncio",
|
||||
"await asyncio.sleep(1)",
|
||||
"raise ValueError()",
|
||||
]
|
||||
)
|
||||
KC.execute(code=fail)
|
||||
KC.execute(code='print("Hello")')
|
||||
KC.execute(code='print("world")')
|
||||
reply = KC.get_shell_msg(timeout=TIMEOUT)
|
||||
print(reply)
|
||||
reply = KC.get_shell_msg(timeout=TIMEOUT)
|
||||
assert reply["content"]["status"] == "aborted"
|
||||
# second message, too
|
||||
reply = KC.get_shell_msg(timeout=TIMEOUT)
|
||||
assert reply["content"]["status"] == "aborted"
|
||||
|
||||
flush_channels()
|
||||
|
||||
KC.execute(code=fail, stop_on_error=False)
|
||||
KC.execute(code='print("Hello")')
|
||||
KC.get_shell_msg(timeout=TIMEOUT)
|
||||
reply = KC.get_shell_msg(timeout=TIMEOUT)
|
||||
assert reply["content"]["status"] == "ok"
|
||||
|
||||
|
||||
def test_non_execute_stop_on_error():
|
||||
"""test that non-execute_request's are not aborted after an error"""
|
||||
flush_channels()
|
||||
|
||||
fail = "\n".join(
|
||||
[
|
||||
# sleep to ensure subsequent message is waiting in the queue to be aborted
|
||||
"import time",
|
||||
"time.sleep(0.5)",
|
||||
"raise ValueError",
|
||||
]
|
||||
)
|
||||
KC.execute(code=fail)
|
||||
KC.kernel_info()
|
||||
KC.comm_info()
|
||||
KC.inspect(code="print")
|
||||
reply = KC.get_shell_msg(timeout=TIMEOUT) # execute
|
||||
assert reply["content"]["status"] == "error"
|
||||
reply = KC.get_shell_msg(timeout=TIMEOUT) # kernel_info
|
||||
assert reply["content"]["status"] == "ok"
|
||||
reply = KC.get_shell_msg(timeout=TIMEOUT) # comm_info
|
||||
assert reply["content"]["status"] == "ok"
|
||||
reply = KC.get_shell_msg(timeout=TIMEOUT) # inspect
|
||||
assert reply["content"]["status"] == "ok"
|
||||
|
||||
|
||||
def test_user_expressions():
|
||||
flush_channels()
|
||||
|
||||
msg_id, reply = execute(code="x=1", user_expressions=dict(foo="x+1"))
|
||||
user_expressions = reply["user_expressions"]
|
||||
assert user_expressions == {
|
||||
"foo": {
|
||||
"status": "ok",
|
||||
"data": {"text/plain": "2"},
|
||||
"metadata": {},
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
def test_user_expressions_fail():
|
||||
flush_channels()
|
||||
|
||||
msg_id, reply = execute(code="x=0", user_expressions=dict(foo="nosuchname"))
|
||||
user_expressions = reply["user_expressions"]
|
||||
foo = user_expressions["foo"]
|
||||
assert foo["status"] == "error"
|
||||
assert foo["ename"] == "NameError"
|
||||
|
||||
|
||||
def test_oinfo():
|
||||
flush_channels()
|
||||
|
||||
msg_id = KC.inspect("a")
|
||||
reply = get_reply(KC, msg_id, TIMEOUT)
|
||||
validate_message(reply, "inspect_reply", msg_id)
|
||||
|
||||
|
||||
def test_oinfo_found():
|
||||
flush_channels()
|
||||
|
||||
msg_id, reply = execute(code="a=5")
|
||||
|
||||
msg_id = KC.inspect("a")
|
||||
reply = get_reply(KC, msg_id, TIMEOUT)
|
||||
validate_message(reply, "inspect_reply", msg_id)
|
||||
content = reply["content"]
|
||||
assert content["found"]
|
||||
text = content["data"]["text/plain"]
|
||||
assert "Type:" in text
|
||||
assert "Docstring:" in text
|
||||
|
||||
|
||||
def test_oinfo_detail():
|
||||
flush_channels()
|
||||
|
||||
msg_id, reply = execute(code="ip=get_ipython()")
|
||||
|
||||
msg_id = KC.inspect("ip.object_inspect", cursor_pos=10, detail_level=1)
|
||||
reply = get_reply(KC, msg_id, TIMEOUT)
|
||||
validate_message(reply, "inspect_reply", msg_id)
|
||||
content = reply["content"]
|
||||
assert content["found"]
|
||||
text = content["data"]["text/plain"]
|
||||
assert "Signature:" in text
|
||||
assert "Source:" in text
|
||||
|
||||
|
||||
def test_oinfo_not_found():
|
||||
flush_channels()
|
||||
|
||||
msg_id = KC.inspect("dne")
|
||||
reply = get_reply(KC, msg_id, TIMEOUT)
|
||||
validate_message(reply, "inspect_reply", msg_id)
|
||||
content = reply["content"]
|
||||
assert not content["found"]
|
||||
|
||||
|
||||
def test_complete():
|
||||
flush_channels()
|
||||
|
||||
msg_id, reply = execute(code="alpha = albert = 5")
|
||||
|
||||
msg_id = KC.complete("al", 2)
|
||||
reply = get_reply(KC, msg_id, TIMEOUT)
|
||||
validate_message(reply, "complete_reply", msg_id)
|
||||
matches = reply["content"]["matches"]
|
||||
for name in ("alpha", "albert"):
|
||||
assert name in matches
|
||||
|
||||
|
||||
def test_kernel_info_request():
|
||||
flush_channels()
|
||||
|
||||
msg_id = KC.kernel_info()
|
||||
reply = get_reply(KC, msg_id, TIMEOUT)
|
||||
validate_message(reply, "kernel_info_reply", msg_id)
|
||||
|
||||
|
||||
def test_connect_request():
|
||||
flush_channels()
|
||||
msg = KC.session.msg("connect_request")
|
||||
KC.shell_channel.send(msg)
|
||||
return msg["header"]["msg_id"]
|
||||
|
||||
msg_id = KC.kernel_info()
|
||||
reply = get_reply(KC, msg_id, TIMEOUT)
|
||||
validate_message(reply, "connect_reply", msg_id)
|
||||
|
||||
|
||||
@pytest.mark.skipif(
|
||||
jupyter_client.version_info < (5, 0),
|
||||
reason="earlier Jupyter Client don't have comm_info",
|
||||
)
|
||||
def test_comm_info_request():
|
||||
flush_channels()
|
||||
msg_id = KC.comm_info()
|
||||
reply = get_reply(KC, msg_id, TIMEOUT)
|
||||
validate_message(reply, "comm_info_reply", msg_id)
|
||||
|
||||
|
||||
def test_single_payload():
|
||||
"""
|
||||
We want to test the set_next_input is not triggered several time per cell.
|
||||
This is (was ?) mostly due to the fact that `?` in a loop would trigger
|
||||
several set_next_input.
|
||||
|
||||
I'm tempted to thing that we actually want to _allow_ multiple
|
||||
set_next_input (that's users' choice). But that `?` itself (and ?'s
|
||||
transform) should avoid setting multiple set_next_input).
|
||||
"""
|
||||
flush_channels()
|
||||
msg_id, reply = execute(
|
||||
code="ip = get_ipython()\nfor i in range(3):\n ip.set_next_input('Hello There')\n"
|
||||
)
|
||||
payload = reply["payload"]
|
||||
next_input_pls = [pl for pl in payload if pl["source"] == "set_next_input"]
|
||||
assert len(next_input_pls) == 1
|
||||
|
||||
|
||||
def test_is_complete():
|
||||
flush_channels()
|
||||
|
||||
msg_id = KC.is_complete("a = 1")
|
||||
reply = get_reply(KC, msg_id, TIMEOUT)
|
||||
validate_message(reply, "is_complete_reply", msg_id)
|
||||
|
||||
|
||||
def test_history_range():
|
||||
flush_channels()
|
||||
|
||||
KC.execute(code="x=1", store_history=True)
|
||||
KC.get_shell_msg(timeout=TIMEOUT)
|
||||
|
||||
msg_id = KC.history(hist_access_type="range", raw=True, output=True, start=1, stop=2, session=0)
|
||||
reply = get_reply(KC, msg_id, TIMEOUT)
|
||||
validate_message(reply, "history_reply", msg_id)
|
||||
content = reply["content"]
|
||||
assert len(content["history"]) == 1
|
||||
|
||||
|
||||
def test_history_tail():
|
||||
flush_channels()
|
||||
|
||||
KC.execute(code="x=1", store_history=True)
|
||||
KC.get_shell_msg(timeout=TIMEOUT)
|
||||
|
||||
msg_id = KC.history(hist_access_type="tail", raw=True, output=True, n=1, session=0)
|
||||
reply = get_reply(KC, msg_id, TIMEOUT)
|
||||
validate_message(reply, "history_reply", msg_id)
|
||||
content = reply["content"]
|
||||
assert len(content["history"]) == 1
|
||||
|
||||
|
||||
def test_history_search():
|
||||
flush_channels()
|
||||
|
||||
KC.execute(code="x=1", store_history=True)
|
||||
KC.get_shell_msg(timeout=TIMEOUT)
|
||||
|
||||
msg_id = KC.history(
|
||||
hist_access_type="search", raw=True, output=True, n=1, pattern="*", session=0
|
||||
)
|
||||
reply = get_reply(KC, msg_id, TIMEOUT)
|
||||
validate_message(reply, "history_reply", msg_id)
|
||||
content = reply["content"]
|
||||
assert len(content["history"]) == 1
|
||||
|
||||
|
||||
# IOPub channel
|
||||
|
||||
|
||||
def test_stream():
|
||||
flush_channels()
|
||||
|
||||
msg_id, reply = execute("print('hi')")
|
||||
|
||||
stdout = KC.get_iopub_msg(timeout=TIMEOUT)
|
||||
validate_message(stdout, "stream", msg_id)
|
||||
content = stdout["content"]
|
||||
assert content["text"] == "hi\n"
|
||||
|
||||
|
||||
def test_display_data():
|
||||
flush_channels()
|
||||
|
||||
msg_id, reply = execute("from IPython.display import display; display(1)")
|
||||
|
||||
display = KC.get_iopub_msg(timeout=TIMEOUT)
|
||||
validate_message(display, "display_data", parent=msg_id)
|
||||
data = display["content"]["data"]
|
||||
assert data["text/plain"] == "1"
|
78
.venv/Lib/site-packages/ipykernel/tests/test_pickleutil.py
Normal file
78
.venv/Lib/site-packages/ipykernel/tests/test_pickleutil.py
Normal file
@ -0,0 +1,78 @@
|
||||
import pickle
|
||||
import warnings
|
||||
|
||||
with warnings.catch_warnings():
|
||||
warnings.simplefilter("ignore")
|
||||
from ipykernel.pickleutil import can, uncan
|
||||
|
||||
|
||||
def interactive(f):
|
||||
f.__module__ = "__main__"
|
||||
return f
|
||||
|
||||
|
||||
def dumps(obj):
|
||||
return pickle.dumps(can(obj))
|
||||
|
||||
|
||||
def loads(obj):
|
||||
return uncan(pickle.loads(obj))
|
||||
|
||||
|
||||
def test_no_closure():
|
||||
@interactive
|
||||
def foo():
|
||||
a = 5
|
||||
return a
|
||||
|
||||
pfoo = dumps(foo)
|
||||
bar = loads(pfoo)
|
||||
assert foo() == bar()
|
||||
|
||||
|
||||
def test_generator_closure():
|
||||
# this only creates a closure on Python 3
|
||||
@interactive
|
||||
def foo():
|
||||
i = "i"
|
||||
r = [i for j in (1, 2)]
|
||||
return r
|
||||
|
||||
pfoo = dumps(foo)
|
||||
bar = loads(pfoo)
|
||||
assert foo() == bar()
|
||||
|
||||
|
||||
def test_nested_closure():
|
||||
@interactive
|
||||
def foo():
|
||||
i = "i"
|
||||
|
||||
def g():
|
||||
return i
|
||||
|
||||
return g()
|
||||
|
||||
pfoo = dumps(foo)
|
||||
bar = loads(pfoo)
|
||||
assert foo() == bar()
|
||||
|
||||
|
||||
def test_closure():
|
||||
i = "i"
|
||||
|
||||
@interactive
|
||||
def foo():
|
||||
return i
|
||||
|
||||
pfoo = dumps(foo)
|
||||
bar = loads(pfoo)
|
||||
assert foo() == bar()
|
||||
|
||||
|
||||
def test_uncan_bytes_buffer():
|
||||
data = b"data"
|
||||
canned = can(data)
|
||||
canned.buffers = [memoryview(buf) for buf in canned.buffers]
|
||||
out = uncan(canned)
|
||||
assert out == data
|
62
.venv/Lib/site-packages/ipykernel/tests/test_start_kernel.py
Normal file
62
.venv/Lib/site-packages/ipykernel/tests/test_start_kernel.py
Normal file
@ -0,0 +1,62 @@
|
||||
from textwrap import dedent
|
||||
|
||||
from flaky import flaky
|
||||
|
||||
from .test_embed_kernel import setup_kernel
|
||||
|
||||
TIMEOUT = 15
|
||||
|
||||
|
||||
@flaky(max_runs=3)
|
||||
def test_ipython_start_kernel_userns():
|
||||
cmd = dedent(
|
||||
"""
|
||||
from ipykernel.kernelapp import launch_new_instance
|
||||
ns = {"tre": 123}
|
||||
launch_new_instance(user_ns=ns)
|
||||
"""
|
||||
)
|
||||
|
||||
with setup_kernel(cmd) as client:
|
||||
client.inspect("tre")
|
||||
msg = client.get_shell_msg(timeout=TIMEOUT)
|
||||
content = msg["content"]
|
||||
assert content["found"]
|
||||
text = content["data"]["text/plain"]
|
||||
assert "123" in text
|
||||
|
||||
# user_module should be an instance of DummyMod
|
||||
client.execute("usermod = get_ipython().user_module")
|
||||
msg = client.get_shell_msg(timeout=TIMEOUT)
|
||||
content = msg["content"]
|
||||
assert content["status"] == "ok"
|
||||
client.inspect("usermod")
|
||||
msg = client.get_shell_msg(timeout=TIMEOUT)
|
||||
content = msg["content"]
|
||||
assert content["found"]
|
||||
text = content["data"]["text/plain"]
|
||||
assert "DummyMod" in text
|
||||
|
||||
|
||||
@flaky(max_runs=3)
|
||||
def test_ipython_start_kernel_no_userns():
|
||||
# Issue #4188 - user_ns should be passed to shell as None, not {}
|
||||
cmd = dedent(
|
||||
"""
|
||||
from ipykernel.kernelapp import launch_new_instance
|
||||
launch_new_instance()
|
||||
"""
|
||||
)
|
||||
|
||||
with setup_kernel(cmd) as client:
|
||||
# user_module should not be an instance of DummyMod
|
||||
client.execute("usermod = get_ipython().user_module")
|
||||
msg = client.get_shell_msg(timeout=TIMEOUT)
|
||||
content = msg["content"]
|
||||
assert content["status"] == "ok"
|
||||
client.inspect("usermod")
|
||||
msg = client.get_shell_msg(timeout=TIMEOUT)
|
||||
content = msg["content"]
|
||||
assert content["found"]
|
||||
text = content["data"]["text/plain"]
|
||||
assert "DummyMod" not in text
|
205
.venv/Lib/site-packages/ipykernel/tests/test_zmq_shell.py
Normal file
205
.venv/Lib/site-packages/ipykernel/tests/test_zmq_shell.py
Normal file
@ -0,0 +1,205 @@
|
||||
""" Tests for zmq shell / display publisher. """
|
||||
|
||||
# Copyright (c) IPython Development Team.
|
||||
# Distributed under the terms of the Modified BSD License.
|
||||
|
||||
import unittest
|
||||
from queue import Queue
|
||||
from threading import Thread
|
||||
|
||||
import zmq
|
||||
from jupyter_client.session import Session
|
||||
from traitlets import Int
|
||||
|
||||
from ipykernel.zmqshell import ZMQDisplayPublisher
|
||||
|
||||
|
||||
class NoReturnDisplayHook:
|
||||
"""
|
||||
A dummy DisplayHook which allows us to monitor
|
||||
the number of times an object is called, but which
|
||||
does *not* return a message when it is called.
|
||||
"""
|
||||
|
||||
call_count = 0
|
||||
|
||||
def __call__(self, obj):
|
||||
self.call_count += 1
|
||||
|
||||
|
||||
class ReturnDisplayHook(NoReturnDisplayHook):
|
||||
"""
|
||||
A dummy DisplayHook with the same counting ability
|
||||
as its base class, but which also returns the same
|
||||
message when it is called.
|
||||
"""
|
||||
|
||||
def __call__(self, obj):
|
||||
super().__call__(obj)
|
||||
return obj
|
||||
|
||||
|
||||
class CounterSession(Session):
|
||||
"""
|
||||
This is a simple subclass to allow us to count
|
||||
the calls made to the session object by the display
|
||||
publisher.
|
||||
"""
|
||||
|
||||
send_count = Int(0)
|
||||
|
||||
def send(self, *args, **kwargs):
|
||||
"""
|
||||
A trivial override to just augment the existing call
|
||||
with an increment to the send counter.
|
||||
"""
|
||||
self.send_count += 1
|
||||
super().send(*args, **kwargs)
|
||||
|
||||
|
||||
class ZMQDisplayPublisherTests(unittest.TestCase):
|
||||
"""
|
||||
Tests the ZMQDisplayPublisher in zmqshell.py
|
||||
"""
|
||||
|
||||
def setUp(self):
|
||||
self.context = zmq.Context()
|
||||
self.socket = self.context.socket(zmq.PUB)
|
||||
self.session = CounterSession()
|
||||
|
||||
self.disp_pub = ZMQDisplayPublisher(session=self.session, pub_socket=self.socket)
|
||||
|
||||
def tearDown(self):
|
||||
"""
|
||||
We need to close the socket in order to proceed with the
|
||||
tests.
|
||||
TODO - There is still an open file handler to '/dev/null',
|
||||
presumably created by zmq.
|
||||
"""
|
||||
self.disp_pub.clear_output()
|
||||
self.socket.close()
|
||||
self.context.term()
|
||||
|
||||
def test_display_publisher_creation(self):
|
||||
"""
|
||||
Since there's no explicit constructor, here we confirm
|
||||
that keyword args get assigned correctly, and override
|
||||
the defaults.
|
||||
"""
|
||||
assert self.disp_pub.session == self.session
|
||||
assert self.disp_pub.pub_socket == self.socket
|
||||
|
||||
def test_thread_local_hooks(self):
|
||||
"""
|
||||
Confirms that the thread_local attribute is correctly
|
||||
initialised with an empty list for the display hooks
|
||||
"""
|
||||
assert self.disp_pub._hooks == []
|
||||
|
||||
def hook(msg):
|
||||
return msg
|
||||
|
||||
self.disp_pub.register_hook(hook)
|
||||
assert self.disp_pub._hooks == [hook]
|
||||
|
||||
q = Queue()
|
||||
|
||||
def set_thread_hooks():
|
||||
q.put(self.disp_pub._hooks)
|
||||
|
||||
t = Thread(target=set_thread_hooks)
|
||||
t.start()
|
||||
thread_hooks = q.get(timeout=10)
|
||||
assert thread_hooks == []
|
||||
|
||||
def test_publish(self):
|
||||
"""
|
||||
Publish should prepare the message and eventually call
|
||||
`send` by default.
|
||||
"""
|
||||
data = dict(a=1)
|
||||
assert self.session.send_count == 0
|
||||
self.disp_pub.publish(data)
|
||||
assert self.session.send_count == 1
|
||||
|
||||
def test_display_hook_halts_send(self):
|
||||
"""
|
||||
If a hook is installed, and on calling the object
|
||||
it does *not* return a message, then we assume that
|
||||
the message has been consumed, and should not be
|
||||
processed (`sent`) in the normal manner.
|
||||
"""
|
||||
data = dict(a=1)
|
||||
hook = NoReturnDisplayHook()
|
||||
|
||||
self.disp_pub.register_hook(hook)
|
||||
assert hook.call_count == 0
|
||||
assert self.session.send_count == 0
|
||||
|
||||
self.disp_pub.publish(data)
|
||||
|
||||
assert hook.call_count == 1
|
||||
assert self.session.send_count == 0
|
||||
|
||||
def test_display_hook_return_calls_send(self):
|
||||
"""
|
||||
If a hook is installed and on calling the object
|
||||
it returns a new message, then we assume that this
|
||||
is just a message transformation, and the message
|
||||
should be sent in the usual manner.
|
||||
"""
|
||||
data = dict(a=1)
|
||||
hook = ReturnDisplayHook()
|
||||
|
||||
self.disp_pub.register_hook(hook)
|
||||
assert hook.call_count == 0
|
||||
assert self.session.send_count == 0
|
||||
|
||||
self.disp_pub.publish(data)
|
||||
|
||||
assert hook.call_count == 1
|
||||
assert self.session.send_count == 1
|
||||
|
||||
def test_unregister_hook(self):
|
||||
"""
|
||||
Once a hook is unregistered, it should not be called
|
||||
during `publish`.
|
||||
"""
|
||||
data = dict(a=1)
|
||||
hook = NoReturnDisplayHook()
|
||||
|
||||
self.disp_pub.register_hook(hook)
|
||||
assert hook.call_count == 0
|
||||
assert self.session.send_count == 0
|
||||
|
||||
self.disp_pub.publish(data)
|
||||
|
||||
assert hook.call_count == 1
|
||||
assert self.session.send_count == 0
|
||||
|
||||
#
|
||||
# After unregistering the `NoReturn` hook, any calls
|
||||
# to publish should *not* got through the DisplayHook,
|
||||
# but should instead hit the usual `session.send` call
|
||||
# at the end.
|
||||
#
|
||||
# As a result, the hook call count should *not* increase,
|
||||
# but the session send count *should* increase.
|
||||
#
|
||||
first = self.disp_pub.unregister_hook(hook)
|
||||
self.disp_pub.publish(data)
|
||||
|
||||
self.assertTrue(first)
|
||||
assert hook.call_count == 1
|
||||
assert self.session.send_count == 1
|
||||
|
||||
#
|
||||
# If a hook is not installed, `unregister_hook`
|
||||
# should return false.
|
||||
#
|
||||
second = self.disp_pub.unregister_hook(hook)
|
||||
self.assertFalse(second)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
213
.venv/Lib/site-packages/ipykernel/tests/utils.py
Normal file
213
.venv/Lib/site-packages/ipykernel/tests/utils.py
Normal file
@ -0,0 +1,213 @@
|
||||
"""utilities for testing IPython kernels"""
|
||||
|
||||
# Copyright (c) IPython Development Team.
|
||||
# Distributed under the terms of the Modified BSD License.
|
||||
|
||||
import atexit
|
||||
import os
|
||||
import sys
|
||||
from contextlib import contextmanager
|
||||
from queue import Empty
|
||||
from subprocess import STDOUT
|
||||
from tempfile import TemporaryDirectory
|
||||
from time import time
|
||||
|
||||
from jupyter_client import manager
|
||||
|
||||
STARTUP_TIMEOUT = 60
|
||||
TIMEOUT = 100
|
||||
|
||||
KM = None
|
||||
KC = None
|
||||
|
||||
|
||||
def start_new_kernel(**kwargs):
|
||||
"""start a new kernel, and return its Manager and Client
|
||||
|
||||
Integrates with our output capturing for tests.
|
||||
"""
|
||||
kwargs["stderr"] = STDOUT
|
||||
try:
|
||||
import nose
|
||||
|
||||
kwargs["stdout"] = nose.iptest_stdstreams_fileno()
|
||||
except (ImportError, AttributeError):
|
||||
pass
|
||||
return manager.start_new_kernel(startup_timeout=STARTUP_TIMEOUT, **kwargs)
|
||||
|
||||
|
||||
def flush_channels(kc=None):
|
||||
"""flush any messages waiting on the queue"""
|
||||
from .test_message_spec import validate_message
|
||||
|
||||
if kc is None:
|
||||
kc = KC
|
||||
for get_msg in (kc.get_shell_msg, kc.get_iopub_msg):
|
||||
while True:
|
||||
try:
|
||||
msg = get_msg(timeout=0.1)
|
||||
except Empty:
|
||||
break
|
||||
else:
|
||||
validate_message(msg)
|
||||
|
||||
|
||||
def get_reply(kc, msg_id, timeout=TIMEOUT, channel="shell"):
|
||||
t0 = time()
|
||||
while True:
|
||||
get_msg = getattr(kc, f"get_{channel}_msg")
|
||||
reply = get_msg(timeout=timeout)
|
||||
if reply["parent_header"]["msg_id"] == msg_id:
|
||||
break
|
||||
# Allow debugging ignored replies
|
||||
print(f"Ignoring reply not to {msg_id}: {reply}")
|
||||
t1 = time()
|
||||
timeout -= t1 - t0
|
||||
t0 = t1
|
||||
return reply
|
||||
|
||||
|
||||
def execute(code="", kc=None, **kwargs):
|
||||
"""wrapper for doing common steps for validating an execution request"""
|
||||
from .test_message_spec import validate_message
|
||||
|
||||
if kc is None:
|
||||
kc = KC
|
||||
msg_id = kc.execute(code=code, **kwargs)
|
||||
reply = get_reply(kc, msg_id, TIMEOUT)
|
||||
validate_message(reply, "execute_reply", msg_id)
|
||||
busy = kc.get_iopub_msg(timeout=TIMEOUT)
|
||||
validate_message(busy, "status", msg_id)
|
||||
assert busy["content"]["execution_state"] == "busy"
|
||||
|
||||
if not kwargs.get("silent"):
|
||||
execute_input = kc.get_iopub_msg(timeout=TIMEOUT)
|
||||
validate_message(execute_input, "execute_input", msg_id)
|
||||
assert execute_input["content"]["code"] == code
|
||||
|
||||
# show tracebacks if present for debugging
|
||||
if reply["content"].get("traceback"):
|
||||
print("\n".join(reply["content"]["traceback"]), file=sys.stderr)
|
||||
|
||||
return msg_id, reply["content"]
|
||||
|
||||
|
||||
def start_global_kernel():
|
||||
"""start the global kernel (if it isn't running) and return its client"""
|
||||
global KM, KC
|
||||
if KM is None:
|
||||
KM, KC = start_new_kernel()
|
||||
atexit.register(stop_global_kernel)
|
||||
else:
|
||||
flush_channels(KC)
|
||||
return KC
|
||||
|
||||
|
||||
@contextmanager
|
||||
def kernel():
|
||||
"""Context manager for the global kernel instance
|
||||
|
||||
Should be used for most kernel tests
|
||||
|
||||
Returns
|
||||
-------
|
||||
kernel_client: connected KernelClient instance
|
||||
"""
|
||||
yield start_global_kernel()
|
||||
|
||||
|
||||
def uses_kernel(test_f):
|
||||
"""Decorator for tests that use the global kernel"""
|
||||
|
||||
def wrapped_test():
|
||||
with kernel() as kc:
|
||||
test_f(kc)
|
||||
|
||||
wrapped_test.__doc__ = test_f.__doc__
|
||||
wrapped_test.__name__ = test_f.__name__
|
||||
return wrapped_test
|
||||
|
||||
|
||||
def stop_global_kernel():
|
||||
"""Stop the global shared kernel instance, if it exists"""
|
||||
global KM, KC
|
||||
KC.stop_channels()
|
||||
KC = None
|
||||
if KM is None:
|
||||
return
|
||||
KM.shutdown_kernel(now=True)
|
||||
KM = None
|
||||
|
||||
|
||||
def new_kernel(argv=None):
|
||||
"""Context manager for a new kernel in a subprocess
|
||||
|
||||
Should only be used for tests where the kernel must not be re-used.
|
||||
|
||||
Returns
|
||||
-------
|
||||
kernel_client: connected KernelClient instance
|
||||
"""
|
||||
kwargs = {"stderr": STDOUT}
|
||||
try:
|
||||
import nose
|
||||
|
||||
kwargs["stdout"] = nose.iptest_stdstreams_fileno()
|
||||
except (ImportError, AttributeError):
|
||||
pass
|
||||
if argv is not None:
|
||||
kwargs["extra_arguments"] = argv
|
||||
return manager.run_kernel(**kwargs)
|
||||
|
||||
|
||||
def assemble_output(get_msg):
|
||||
"""assemble stdout/err from an execution"""
|
||||
stdout = ""
|
||||
stderr = ""
|
||||
while True:
|
||||
msg = get_msg(timeout=1)
|
||||
msg_type = msg["msg_type"]
|
||||
content = msg["content"]
|
||||
if msg_type == "status" and content["execution_state"] == "idle":
|
||||
# idle message signals end of output
|
||||
break
|
||||
elif msg["msg_type"] == "stream":
|
||||
if content["name"] == "stdout":
|
||||
stdout += content["text"]
|
||||
elif content["name"] == "stderr":
|
||||
stderr += content["text"]
|
||||
else:
|
||||
raise KeyError("bad stream: %r" % content["name"])
|
||||
else:
|
||||
# other output, ignored
|
||||
pass
|
||||
return stdout, stderr
|
||||
|
||||
|
||||
def wait_for_idle(kc):
|
||||
while True:
|
||||
msg = kc.get_iopub_msg(timeout=1)
|
||||
msg_type = msg["msg_type"]
|
||||
content = msg["content"]
|
||||
if msg_type == "status" and content["execution_state"] == "idle":
|
||||
break
|
||||
|
||||
|
||||
class TemporaryWorkingDirectory(TemporaryDirectory):
|
||||
"""
|
||||
Creates a temporary directory and sets the cwd to that directory.
|
||||
Automatically reverts to previous cwd upon cleanup.
|
||||
Usage example:
|
||||
|
||||
with TemporaryWorkingDirectory() as tmpdir:
|
||||
...
|
||||
"""
|
||||
|
||||
def __enter__(self):
|
||||
self.old_wd = os.getcwd()
|
||||
os.chdir(self.name)
|
||||
return super().__enter__()
|
||||
|
||||
def __exit__(self, exc, value, tb):
|
||||
os.chdir(self.old_wd)
|
||||
return super().__exit__(exc, value, tb)
|
Reference in New Issue
Block a user