Skip to content

Commit 78d7e0b

Browse files
authored
Merge pull request #21410 from meeseeksmachine/auto-backport-of-pr-20591-on-v3.5.x
Backport PR #20591 on branch v3.5.x (Webagg backend: get rid of tornado)
2 parents 7e36e90 + 6f94783 commit 78d7e0b

File tree

4 files changed

+46
-6
lines changed

4 files changed

+46
-6
lines changed

doc/devel/dependencies.rst

+1-1
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ and the capabilities they provide.
4646
* wxPython_ (>= 4) [#]_: for the wx-based backends.
4747
* pycairo_ (>= 1.11.0) or cairocffi_ (>= 0.8): for the GTK and/or cairo-based
4848
backends.
49-
* Tornado_: for the WebAgg backend.
49+
* Tornado_ (>=5): for the WebAgg backend.
5050

5151
.. _Tk: https://docs.python.org/3/library/tk.html
5252
.. _PyQt5: https://pypi.org/project/PyQt5/

lib/matplotlib/backends/backend_nbagg.py

+2-1
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,8 @@
2222
from matplotlib.backend_bases import _Backend, NavigationToolbar2
2323
from matplotlib.backends.backend_webagg_core import (
2424
FigureCanvasWebAggCore, FigureManagerWebAgg, NavigationToolbar2WebAgg,
25-
TimerTornado)
25+
TimerTornado, TimerAsyncio
26+
)
2627

2728

2829
def connection_info():

lib/matplotlib/backends/backend_webagg.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@
3636
from matplotlib.backend_bases import _Backend
3737
from matplotlib._pylab_helpers import Gcf
3838
from . import backend_webagg_core as core
39-
from .backend_webagg_core import TimerTornado
39+
from .backend_webagg_core import TimerAsyncio, TimerTornado
4040

4141

4242
class ServerThread(threading.Thread):

lib/matplotlib/backends/backend_webagg_core.py

+42-3
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,9 @@
88
# way over a web socket.
99
#
1010
# - `backend_webagg.py` contains a concrete implementation of a basic
11-
# application, implemented with tornado.
11+
# application, implemented with asyncio.
1212

13+
import asyncio
1314
import datetime
1415
from io import BytesIO, StringIO
1516
import json
@@ -19,7 +20,6 @@
1920

2021
import numpy as np
2122
from PIL import Image
22-
import tornado
2323

2424
from matplotlib import _api, backend_bases, backend_tools
2525
from matplotlib.backends import backend_agg
@@ -85,6 +85,8 @@ def __init__(self, *args, **kwargs):
8585
super().__init__(*args, **kwargs)
8686

8787
def _timer_start(self):
88+
import tornado
89+
8890
self._timer_stop()
8991
if self._single:
9092
ioloop = tornado.ioloop.IOLoop.instance()
@@ -98,6 +100,8 @@ def _timer_start(self):
98100
self._timer.start()
99101

100102
def _timer_stop(self):
103+
import tornado
104+
101105
if self._timer is None:
102106
return
103107
elif self._single:
@@ -114,8 +118,43 @@ def _timer_set_interval(self):
114118
self._timer_start()
115119

116120

121+
class TimerAsyncio(backend_bases.TimerBase):
122+
def __init__(self, *args, **kwargs):
123+
self._task = None
124+
super().__init__(*args, **kwargs)
125+
126+
async def _timer_task(self, interval):
127+
while True:
128+
try:
129+
await asyncio.sleep(interval)
130+
self._on_timer()
131+
132+
if self._single:
133+
break
134+
except asyncio.CancelledError:
135+
break
136+
137+
def _timer_start(self):
138+
self._timer_stop()
139+
140+
self._task = asyncio.ensure_future(
141+
self._timer_task(max(self.interval / 1_000., 1e-6))
142+
)
143+
144+
def _timer_stop(self):
145+
if self._task is not None:
146+
self._task.cancel()
147+
self._task = None
148+
149+
def _timer_set_interval(self):
150+
# Only stop and restart it if the timer has already been started
151+
if self._task is not None:
152+
self._timer_stop()
153+
self._timer_start()
154+
155+
117156
class FigureCanvasWebAggCore(backend_agg.FigureCanvasAgg):
118-
_timer_cls = TimerTornado
157+
_timer_cls = TimerAsyncio
119158
# Webagg and friends having the right methods, but still
120159
# having bugs in practice. Do not advertise that it works until
121160
# we can debug this.

0 commit comments

Comments
 (0)