From 500e6fdfbfe1217e62dd38ce041a8978f76dbd7a Mon Sep 17 00:00:00 2001 From: CJ Carey Date: Mon, 25 Apr 2016 15:06:17 -0400 Subject: [PATCH] ENH: webagg: Handle ioloop shutdown correctly This change correctly cleans up after the ioloop is interrupted, allowing the user to call plt.show(), then resume control with a SIGINT, then call plt.show() again. --- lib/matplotlib/backends/backend_webagg.py | 34 ++++++++++++++++++++++--------- 1 file changed, 24 insertions(+), 10 deletions(-) diff --git a/lib/matplotlib/backends/backend_webagg.py b/lib/matplotlib/backends/backend_webagg.py index c5576777843..603e07a5f5a 100644 --- a/lib/matplotlib/backends/backend_webagg.py +++ b/lib/matplotlib/backends/backend_webagg.py @@ -15,14 +15,15 @@ from matplotlib.externals import six -import datetime import errno import json import os import random import sys +import signal import socket import threading +from contextlib import contextmanager try: import tornado @@ -323,9 +324,6 @@ def start(cls): if cls.started: return - # Set the flag to True *before* blocking on IOLoop.instance().start() - cls.started = True - """ IOLoop.running() was removed as of Tornado 2.4; see for example https://groups.google.com/forum/#!topic/python-tornado/QLMzkpQBGOY @@ -333,16 +331,32 @@ def start(cls): launched. We may end up with two concurrently running loops in that unlucky case with all the expected consequences. """ - print("Press Ctrl+C to stop WebAgg server") - sys.stdout.flush() - try: - tornado.ioloop.IOLoop.instance().start() - except KeyboardInterrupt: + ioloop = tornado.ioloop.IOLoop.instance() + + def shutdown(): + ioloop.stop() print("Server is stopped") sys.stdout.flush() - finally: cls.started = False + @contextmanager + def catch_sigint(): + old_handler = signal.signal( + signal.SIGINT, + lambda sig, frame: ioloop.add_callback_from_signal(shutdown)) + try: + yield + finally: + signal.signal(signal.SIGINT, old_handler) + + # Set the flag to True *before* blocking on ioloop.start() + cls.started = True + + print("Press Ctrl+C to stop WebAgg server") + sys.stdout.flush() + with catch_sigint(): + ioloop.start() + def ipython_inline_display(figure): import tornado.template