diff --git a/ipykernel/tests/test_embed_kernel.py b/ipykernel/tests/test_embed_kernel.py index 5e60245b0..8bc776b4c 100644 --- a/ipykernel/tests/test_embed_kernel.py +++ b/ipykernel/tests/test_embed_kernel.py @@ -6,9 +6,11 @@ import os import sys import time +import json from contextlib import contextmanager from subprocess import Popen, PIPE +from flaky import flaky from jupyter_client import BlockingKernelClient from jupyter_core import paths @@ -28,39 +30,57 @@ def setup_kernel(cmd): ------- kernel_manager: connected KernelManager instance """ - kernel = Popen([sys.executable, '-c', cmd], stdout=PIPE, stderr=PIPE) - 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 os.path.exists(connection_file) \ - and kernel.poll() is None \ - and time.time() < tic + SETUP_TIMEOUT: - time.sleep(0.1) - - if kernel.poll() is not None: - o,e = kernel.communicate() - e = py3compat.cast_unicode(e) - raise IOError("Kernel failed to start:\n%s" % e) - if not os.path.exists(connection_file): - if kernel.poll() is None: - kernel.terminate() - raise IOError("Connection file %r never arrived" % connection_file) - - client = BlockingKernelClient(connection_file=connection_file) - client.load_connection_file() - client.start_channels() - client.wait_for_ready() + 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) try: - yield client + 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() + e = py3compat.cast_unicode(e) + raise IOError("Kernel failed to start:\n%s" % e) + + if not os.path.exists(connection_file): + if kernel.poll() is None: + kernel.terminate() + raise IOError("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: - client.stop_channels() kernel.terminate() + +@flaky(max_runs=3) def test_embed_kernel_basic(): """IPython.embed_kernel() is basically functional""" cmd = '\n'.join([ @@ -93,6 +113,8 @@ def test_embed_kernel_basic(): 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([ @@ -128,6 +150,7 @@ def test_embed_kernel_namespace(): 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([ diff --git a/ipykernel/tests/test_kernel.py b/ipykernel/tests/test_kernel.py index fda8a1f4d..219ded2d3 100644 --- a/ipykernel/tests/test_kernel.py +++ b/ipykernel/tests/test_kernel.py @@ -11,6 +11,7 @@ import time import nose.tools as nt +from flaky import flaky from IPython.testing import decorators as dec, tools as tt from ipython_genutils import py3compat @@ -75,6 +76,7 @@ def test_sys_path_profile_dir(): assert '' in sys_path +@flaky(max_runs=3) @dec.skipif(sys.platform == 'win32', "subprocess prints fail on Windows") def test_subprocess_print(): """printing from forked mp.Process""" @@ -104,6 +106,7 @@ def test_subprocess_print(): _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: @@ -126,6 +129,7 @@ def test_subprocess_noprint(): _check_master(kc, expected=True, stream="stderr") +@flaky(max_runs=3) @dec.skipif(sys.platform == 'win32', "subprocess prints fail on Windows") def test_subprocess_error(): """error in mp.Process doesn't crash""" diff --git a/ipykernel/tests/test_start_kernel.py b/ipykernel/tests/test_start_kernel.py index 797ddf19c..b69785453 100644 --- a/ipykernel/tests/test_start_kernel.py +++ b/ipykernel/tests/test_start_kernel.py @@ -1,7 +1,10 @@ from .test_embed_kernel import setup_kernel +from flaky import flaky TIMEOUT = 15 + +@flaky(max_runs=3) def test_ipython_start_kernel_userns(): cmd = ('from IPython import start_kernel\n' 'ns = {"tre": 123}\n' @@ -27,6 +30,8 @@ def test_ipython_start_kernel_userns(): text = content['data']['text/plain'] assert u'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 = ('from IPython import start_kernel\n' diff --git a/setup.py b/setup.py index c52c322f8..340befb68 100644 --- a/setup.py +++ b/setup.py @@ -97,6 +97,7 @@ def run(self): 'test': [ 'pytest', 'pytest-cov', + 'flaky', 'nose', # nose because there are still a few nose.tools imports hanging around ], },