|
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