|
8 | 8 | # way over a web socket. |
9 | 9 | # |
10 | 10 | # - `backend_webagg.py` contains a concrete implementation of a basic |
11 | | -# application, implemented with tornado. |
| 11 | +# application, implemented with asyncio. |
12 | 12 |
|
13 | | -import datetime |
14 | 13 | from io import BytesIO, StringIO |
15 | 14 | import json |
16 | 15 | import logging |
|
19 | 18 |
|
20 | 19 | import numpy as np |
21 | 20 | from PIL import Image |
22 | | -import tornado |
| 21 | +import asyncio |
23 | 22 |
|
24 | 23 | from matplotlib import _api, backend_bases, backend_tools |
25 | 24 | from matplotlib.backends import backend_agg |
@@ -79,43 +78,43 @@ def _handle_key(key): |
79 | 78 | return key |
80 | 79 |
|
81 | 80 |
|
82 | | -class TimerTornado(backend_bases.TimerBase): |
| 81 | +class TimerAsyncio(backend_bases.TimerBase): |
83 | 82 | def __init__(self, *args, **kwargs): |
84 | | - self._timer = None |
| 83 | + self._task = None |
85 | 84 | super().__init__(*args, **kwargs) |
86 | 85 |
|
| 86 | + async def _timer_task(self, interval): |
| 87 | + while True: |
| 88 | + try: |
| 89 | + await asyncio.sleep(interval) |
| 90 | + self._on_timer() |
| 91 | + |
| 92 | + if self._single: |
| 93 | + break |
| 94 | + except asyncio.CancelledError: |
| 95 | + break |
| 96 | + |
87 | 97 | def _timer_start(self): |
88 | 98 | self._timer_stop() |
89 | | - if self._single: |
90 | | - ioloop = tornado.ioloop.IOLoop.instance() |
91 | | - self._timer = ioloop.add_timeout( |
92 | | - datetime.timedelta(milliseconds=self.interval), |
93 | | - self._on_timer) |
94 | | - else: |
95 | | - self._timer = tornado.ioloop.PeriodicCallback( |
96 | | - self._on_timer, |
97 | | - max(self.interval, 1e-6)) |
98 | | - self._timer.start() |
| 99 | + |
| 100 | + self._task = asyncio.ensure_future( |
| 101 | + self._timer_task(max(self.interval / 1_000., 1e-6)) |
| 102 | + ) |
99 | 103 |
|
100 | 104 | def _timer_stop(self): |
101 | | - if self._timer is None: |
102 | | - return |
103 | | - elif self._single: |
104 | | - ioloop = tornado.ioloop.IOLoop.instance() |
105 | | - ioloop.remove_timeout(self._timer) |
106 | | - else: |
107 | | - self._timer.stop() |
108 | | - self._timer = None |
| 105 | + if self._task is not None: |
| 106 | + self._task.cancel() |
| 107 | + self._task = None |
109 | 108 |
|
110 | 109 | def _timer_set_interval(self): |
111 | 110 | # Only stop and restart it if the timer has already been started |
112 | | - if self._timer is not None: |
| 111 | + if self._task is not None: |
113 | 112 | self._timer_stop() |
114 | 113 | self._timer_start() |
115 | 114 |
|
116 | 115 |
|
117 | 116 | class FigureCanvasWebAggCore(backend_agg.FigureCanvasAgg): |
118 | | - _timer_cls = TimerTornado |
| 117 | + _timer_cls = TimerAsyncio |
119 | 118 | # Webagg and friends having the right methods, but still |
120 | 119 | # having bugs in practice. Do not advertise that it works until |
121 | 120 | # we can debug this. |
|
0 commit comments