diff --git a/IPython/html/base/zmqhandlers.py b/IPython/html/base/zmqhandlers.py
index 7eec55bc3..6f5b302af 100644
--- a/IPython/html/base/zmqhandlers.py
+++ b/IPython/html/base/zmqhandlers.py
@@ -229,9 +229,12 @@ class AuthenticatedZMQStreamHandler(ZMQStreamHandler, IPythonHandler):
# start the pinging
if self.ping_interval > 0:
- self.last_ping = ioloop.IOLoop.instance().time() # Remember time of last ping
+ loop = ioloop.IOLoop.current()
+ self.last_ping = loop.time() # Remember time of last ping
self.last_pong = self.last_ping
- self.ping_callback = ioloop.PeriodicCallback(self.send_ping, self.ping_interval)
+ self.ping_callback = ioloop.PeriodicCallback(
+ self.send_ping, self.ping_interval, io_loop=loop,
+ )
self.ping_callback.start()
def send_ping(self):
@@ -242,7 +245,7 @@ class AuthenticatedZMQStreamHandler(ZMQStreamHandler, IPythonHandler):
# check for timeout on pong. Make sure that we really have sent a recent ping in
# case the machine with both server and client has been suspended since the last ping.
- now = ioloop.IOLoop.instance().time()
+ now = ioloop.IOLoop.current().time()
since_last_pong = 1e3 * (now - self.last_pong)
since_last_ping = 1e3 * (now - self.last_ping)
if since_last_ping < 2*self.ping_interval and since_last_pong > self.ping_timeout:
@@ -254,4 +257,4 @@ class AuthenticatedZMQStreamHandler(ZMQStreamHandler, IPythonHandler):
self.last_ping = now
def on_pong(self, data):
- self.last_pong = ioloop.IOLoop.instance().time()
+ self.last_pong = ioloop.IOLoop.current().time()
diff --git a/IPython/html/notebookapp.py b/IPython/html/notebookapp.py
index 6b798c821..291094ce2 100644
--- a/IPython/html/notebookapp.py
+++ b/IPython/html/notebookapp.py
@@ -888,7 +888,7 @@ class NotebookApp(BaseIPythonApplication):
line = sys.stdin.readline()
if line.lower().startswith('y') and 'n' not in line.lower():
self.log.critical("Shutdown confirmed")
- ioloop.IOLoop.instance().stop()
+ ioloop.IOLoop.current().stop()
return
else:
print("No answer for 5s:", end=' ')
@@ -897,11 +897,11 @@ class NotebookApp(BaseIPythonApplication):
# set it back to original SIGINT handler
# use IOLoop.add_callback because signal.signal must be called
# from main thread
- ioloop.IOLoop.instance().add_callback(self._restore_sigint_handler)
+ ioloop.IOLoop.current().add_callback(self._restore_sigint_handler)
def _signal_stop(self, sig, frame):
self.log.critical("received signal %s, stopping", sig)
- ioloop.IOLoop.instance().stop()
+ ioloop.IOLoop.current().stop()
def _signal_info(self, sig, frame):
print(self.notebook_info())
@@ -1004,13 +1004,21 @@ class NotebookApp(BaseIPythonApplication):
b = lambda : browser.open(url_path_join(self.connection_url, uri),
new=2)
threading.Thread(target=b).start()
+
+ self.io_loop = ioloop.IOLoop.current()
try:
- ioloop.IOLoop.instance().start()
+ self.io_loop.start()
except KeyboardInterrupt:
info("Interrupted...")
finally:
self.cleanup_kernels()
self.remove_server_info_file()
+
+ def stop(self):
+ def _stop():
+ self.http_server.stop()
+ self.io_loop.stop()
+ self.io_loop.add_callback(_stop)
def list_running_servers(profile='default'):
diff --git a/IPython/html/services/contents/tests/test_manager.py b/IPython/html/services/contents/tests/test_manager.py
index 647578c70..e2a1bc186 100644
--- a/IPython/html/services/contents/tests/test_manager.py
+++ b/IPython/html/services/contents/tests/test_manager.py
@@ -78,7 +78,6 @@ class TestContentsManager(TestCase):
self.td = self._temp_dir.name
self.contents_manager = FileContentsManager(
root_dir=self.td,
- log=logging.getLogger()
)
def tearDown(self):
diff --git a/IPython/html/tests/launchnotebook.py b/IPython/html/tests/launchnotebook.py
index 7775e2895..c78bef4e2 100644
--- a/IPython/html/tests/launchnotebook.py
+++ b/IPython/html/tests/launchnotebook.py
@@ -6,11 +6,12 @@ import sys
import time
import requests
from contextlib import contextmanager
-from subprocess import Popen, STDOUT
+from threading import Thread, Event
from unittest import TestCase
-import nose
+from tornado.ioloop import IOLoop
+from ..notebookapp import NotebookApp
from IPython.utils.tempdir import TemporaryDirectory
MAX_WAITTIME = 30 # seconds to wait for notebook server to start
@@ -50,35 +51,46 @@ class NotebookTestBase(TestCase):
@classmethod
def wait_until_dead(cls):
"""Wait for the server process to terminate after shutdown"""
- for _ in range(int(MAX_WAITTIME/POLL_INTERVAL)):
- if cls.notebook.poll() is not None:
- return
- time.sleep(POLL_INTERVAL)
-
- raise TimeoutError("Undead notebook server")
+ cls.notebook_thread.join(timeout=MAX_WAITTIME)
+ if cls.notebook_thread.is_alive():
+ raise TimeoutError("Undead notebook server")
@classmethod
def setup_class(cls):
cls.ipython_dir = TemporaryDirectory()
cls.notebook_dir = TemporaryDirectory()
- notebook_args = [
- sys.executable, '-c',
- 'from IPython.html.notebookapp import launch_new_instance; launch_new_instance()',
- '--port=%d' % cls.port,
- '--port-retries=0', # Don't try any other ports
- '--no-browser',
- '--ipython-dir=%s' % cls.ipython_dir.name,
- '--notebook-dir=%s' % cls.notebook_dir.name,
- ]
- cls.notebook = Popen(notebook_args,
- stdout=nose.iptest_stdstreams_fileno(),
- stderr=STDOUT,
+ app = cls.notebook = NotebookApp(
+ port=cls.port,
+ port_retries=0,
+ open_browser=False,
+ ipython_dir=cls.ipython_dir.name,
+ notebook_dir=cls.notebook_dir.name,
)
+
+ # clear log handlers and propagate to root for nose to capture it
+ # needs to be redone after initialize, which reconfigures logging
+ app.log.propagate = True
+ app.log.handlers = []
+ app.initialize(argv=[])
+ app.log.propagate = True
+ app.log.handlers = []
+ started = Event()
+ def start_thread():
+ loop = IOLoop.current()
+ loop.add_callback(started.set)
+ try:
+ app.start()
+ finally:
+ # set the event, so failure to start doesn't cause a hang
+ started.set()
+ cls.notebook_thread = Thread(target=start_thread)
+ cls.notebook_thread.start()
+ started.wait()
cls.wait_until_alive()
@classmethod
def teardown_class(cls):
- cls.notebook.terminate()
+ cls.notebook.stop()
cls.wait_until_dead()
cls.ipython_dir.cleanup()
cls.notebook_dir.cleanup()