test_kernel.py
204 lines
| 6.1 KiB
| text/x-python
|
PythonLexer
MinRK
|
r9438 | """test the IPython Kernel""" | ||
#------------------------------------------------------------------------------- | ||||
# Copyright (C) 2013 The IPython Development Team | ||||
# | ||||
# Distributed under the terms of the BSD License. The full license is in | ||||
# the file COPYING, distributed as part of this software. | ||||
#------------------------------------------------------------------------------- | ||||
#------------------------------------------------------------------------------- | ||||
# Imports | ||||
#------------------------------------------------------------------------------- | ||||
import os | ||||
import shutil | ||||
MinRK
|
r9449 | import sys | ||
MinRK
|
r9438 | import tempfile | ||
from contextlib import contextmanager | ||||
from subprocess import PIPE | ||||
import nose.tools as nt | ||||
MinRK
|
r12318 | from IPython.kernel import KernelManager | ||
from IPython.kernel.tests.test_message_spec import execute, flush_channels | ||||
MinRK
|
r9438 | from IPython.testing import decorators as dec | ||
MinRK
|
r12318 | from IPython.utils import path | ||
MinRK
|
r9438 | |||
#------------------------------------------------------------------------------- | ||||
# Tests | ||||
#------------------------------------------------------------------------------- | ||||
MinRK
|
r12318 | IPYTHONDIR = None | ||
save_env = None | ||||
save_get_ipython_dir = None | ||||
MinRK
|
r9438 | |||
def setup(): | ||||
"""setup temporary IPYTHONDIR for tests""" | ||||
global IPYTHONDIR | ||||
global save_env | ||||
global save_get_ipython_dir | ||||
IPYTHONDIR = tempfile.mkdtemp() | ||||
save_env = os.environ.copy() | ||||
os.environ["IPYTHONDIR"] = IPYTHONDIR | ||||
save_get_ipython_dir = path.get_ipython_dir | ||||
path.get_ipython_dir = lambda : IPYTHONDIR | ||||
def teardown(): | ||||
path.get_ipython_dir = save_get_ipython_dir | ||||
os.environ = save_env | ||||
try: | ||||
shutil.rmtree(IPYTHONDIR) | ||||
except (OSError, IOError): | ||||
# no such file | ||||
pass | ||||
@contextmanager | ||||
def new_kernel(): | ||||
"""start a kernel in a subprocess, and wait for it to be ready | ||||
Returns | ||||
------- | ||||
kernel_manager: connected KernelManager instance | ||||
""" | ||||
MinRK
|
r12318 | KM = KernelManager() | ||
MinRK
|
r9438 | |||
KM.start_kernel(stdout=PIPE, stderr=PIPE) | ||||
MinRK
|
r12318 | KC = KM.client() | ||
KC.start_channels() | ||||
MinRK
|
r9438 | |||
# wait for kernel to be ready | ||||
MinRK
|
r12318 | KC.shell_channel.execute("import sys") | ||
KC.shell_channel.get_msg(block=True, timeout=5) | ||||
flush_channels(KC) | ||||
MinRK
|
r9438 | try: | ||
MinRK
|
r12318 | yield KC | ||
MinRK
|
r9438 | finally: | ||
MinRK
|
r12318 | KC.stop_channels() | ||
MinRK
|
r9438 | KM.shutdown_kernel() | ||
def assemble_output(iopub): | ||||
"""assemble stdout/err from an execution""" | ||||
stdout = '' | ||||
stderr = '' | ||||
while True: | ||||
msg = iopub.get_msg(block=True, 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 = stdout + content['data'] | ||||
elif content['name'] == 'stderr': | ||||
stderr = stderr + content['data'] | ||||
else: | ||||
raise KeyError("bad stream: %r" % content['name']) | ||||
else: | ||||
# other output, ignored | ||||
pass | ||||
return stdout, stderr | ||||
MinRK
|
r12318 | def _check_mp_mode(kc, expected=False, stream="stdout"): | ||
execute(kc=kc, code="import sys") | ||||
flush_channels(kc) | ||||
msg_id, content = execute(kc=kc, code="print (sys.%s._check_mp_mode())" % stream) | ||||
stdout, stderr = assemble_output(kc.iopub_channel) | ||||
MinRK
|
r9438 | nt.assert_equal(eval(stdout.strip()), expected) | ||
def test_simple_print(): | ||||
"""simple print statement in kernel""" | ||||
MinRK
|
r12318 | with new_kernel() as kc: | ||
iopub = kc.iopub_channel | ||||
msg_id, content = execute(kc=kc, code="print ('hi')") | ||||
MinRK
|
r9438 | stdout, stderr = assemble_output(iopub) | ||
MinRK
|
r9442 | nt.assert_equal(stdout, 'hi\n') | ||
nt.assert_equal(stderr, '') | ||||
MinRK
|
r12318 | _check_mp_mode(kc, expected=False) | ||
MinRK
|
r9442 | print ('hello') | ||
MinRK
|
r9438 | |||
MinRK
|
r9449 | @dec.knownfailureif(sys.platform == 'win32', "subprocess prints fail on Windows") | ||
MinRK
|
r9438 | def test_subprocess_print(): | ||
"""printing from forked mp.Process""" | ||||
MinRK
|
r12318 | with new_kernel() as kc: | ||
iopub = kc.iopub_channel | ||||
MinRK
|
r9438 | |||
MinRK
|
r12318 | _check_mp_mode(kc, expected=False) | ||
flush_channels(kc) | ||||
MinRK
|
r9438 | np = 5 | ||
code = '\n'.join([ | ||||
MinRK
|
r9446 | "from __future__ import print_function", | ||
MinRK
|
r9438 | "import multiprocessing as mp", | ||
MinRK
|
r9446 | "pool = [mp.Process(target=print, args=('hello', i,)) for i in range(%i)]" % np, | ||
MinRK
|
r9438 | "for p in pool: p.start()", | ||
"for p in pool: p.join()" | ||||
]) | ||||
expected = '\n'.join([ | ||||
"hello %s" % i for i in range(np) | ||||
]) + '\n' | ||||
MinRK
|
r12318 | msg_id, content = execute(kc=kc, code=code) | ||
MinRK
|
r9438 | stdout, stderr = assemble_output(iopub) | ||
MinRK
|
r9442 | nt.assert_equal(stdout.count("hello"), np, stdout) | ||
MinRK
|
r9438 | for n in range(np): | ||
MinRK
|
r9442 | nt.assert_equal(stdout.count(str(n)), 1, stdout) | ||
nt.assert_equal(stderr, '') | ||||
MinRK
|
r12318 | _check_mp_mode(kc, expected=False) | ||
_check_mp_mode(kc, expected=False, stream="stderr") | ||||
MinRK
|
r9438 | |||
def test_subprocess_noprint(): | ||||
"""mp.Process without print doesn't trigger iostream mp_mode""" | ||||
MinRK
|
r12318 | with new_kernel() as kc: | ||
iopub = kc.iopub_channel | ||||
MinRK
|
r9438 | |||
np = 5 | ||||
code = '\n'.join([ | ||||
"import multiprocessing as mp", | ||||
MinRK
|
r9449 | "pool = [mp.Process(target=range, args=(i,)) for i in range(%i)]" % np, | ||
MinRK
|
r9438 | "for p in pool: p.start()", | ||
"for p in pool: p.join()" | ||||
]) | ||||
MinRK
|
r12318 | msg_id, content = execute(kc=kc, code=code) | ||
MinRK
|
r9438 | stdout, stderr = assemble_output(iopub) | ||
MinRK
|
r9442 | nt.assert_equal(stdout, '') | ||
nt.assert_equal(stderr, '') | ||||
MinRK
|
r12318 | _check_mp_mode(kc, expected=False) | ||
_check_mp_mode(kc, expected=False, stream="stderr") | ||||
MinRK
|
r9438 | |||
MinRK
|
r9449 | @dec.knownfailureif(sys.platform == 'win32', "subprocess prints fail on Windows") | ||
MinRK
|
r9441 | def test_subprocess_error(): | ||
"""error in mp.Process doesn't crash""" | ||||
MinRK
|
r12318 | with new_kernel() as kc: | ||
iopub = kc.iopub_channel | ||||
MinRK
|
r9441 | |||
code = '\n'.join([ | ||||
"import multiprocessing as mp", | ||||
MinRK
|
r9446 | "p = mp.Process(target=int, args=('hi',))", | ||
MinRK
|
r9441 | "p.start()", | ||
"p.join()", | ||||
]) | ||||
MinRK
|
r12318 | msg_id, content = execute(kc=kc, code=code) | ||
MinRK
|
r9441 | stdout, stderr = assemble_output(iopub) | ||
MinRK
|
r9442 | nt.assert_equal(stdout, '') | ||
MinRK
|
r9446 | nt.assert_true("ValueError" in stderr, stderr) | ||
MinRK
|
r9441 | |||
MinRK
|
r12318 | _check_mp_mode(kc, expected=False) | ||
_check_mp_mode(kc, expected=False, stream="stderr") | ||||
MinRK
|
r9441 | |||