From 96690e11d24faa5fee999f38aaee885feef2087f Mon Sep 17 00:00:00 2001 From: Antony Lee Date: Thu, 16 Apr 2020 23:29:24 +0200 Subject: [PATCH] Correctly go through property setter when init'ing Timer interval. The setter casts the interval to an int, which is required at least by the tk backend. This caught a bug in the wx timer, where just setting the interval would start the timer. Fixed that. --- doc/api/api_changes_3.3/behaviour.rst | 5 +++++ lib/matplotlib/backend_bases.py | 7 +++---- lib/matplotlib/backends/_backend_tk.py | 3 +-- lib/matplotlib/backends/backend_gtk3.py | 4 ++++ lib/matplotlib/backends/backend_qt5.py | 3 +-- lib/matplotlib/backends/backend_webagg_core.py | 5 ++++- lib/matplotlib/backends/backend_wx.py | 5 +++-- lib/matplotlib/tests/test_backends_interactive.py | 2 +- 8 files changed, 22 insertions(+), 12 deletions(-) diff --git a/doc/api/api_changes_3.3/behaviour.rst b/doc/api/api_changes_3.3/behaviour.rst index a85f2974debc..042cecca9e66 100644 --- a/doc/api/api_changes_3.3/behaviour.rst +++ b/doc/api/api_changes_3.3/behaviour.rst @@ -176,3 +176,8 @@ explicitly pass a "%1.2f" as the *valfmt* parameter to `.Slider`. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ All the functionality of ``CustomCell`` has been moved to its base class `~.table.Cell`. + +wx Timer interval +~~~~~~~~~~~~~~~~~ +Setting the timer interval on a not-yet-started ``TimerWx`` won't start it +anymore. diff --git a/lib/matplotlib/backend_bases.py b/lib/matplotlib/backend_bases.py index 9338908cda3f..cf9453959853 100644 --- a/lib/matplotlib/backend_bases.py +++ b/lib/matplotlib/backend_bases.py @@ -1059,10 +1059,9 @@ def __init__(self, interval=None, callbacks=None): `remove_callback` can be used. """ self.callbacks = [] if callbacks is None else callbacks.copy() - self._interval = 1000 if interval is None else interval - self._single = False - # Default attribute for holding the GUI-specific timer object - self._timer = None + # Set .interval and not ._interval to go through the property setter. + self.interval = 1000 if interval is None else interval + self.single_shot = False def __del__(self): """Need to stop timer and possibly disconnect timer.""" diff --git a/lib/matplotlib/backends/_backend_tk.py b/lib/matplotlib/backends/_backend_tk.py index bbe94cd48195..d0ec5e848a86 100644 --- a/lib/matplotlib/backends/_backend_tk.py +++ b/lib/matplotlib/backends/_backend_tk.py @@ -82,9 +82,9 @@ class TimerTk(TimerBase): """Subclass of `backend_bases.TimerBase` using Tk timer events.""" def __init__(self, parent, *args, **kwargs): + self._timer = None TimerBase.__init__(self, *args, **kwargs) self.parent = parent - self._timer = None def _timer_start(self): self._timer_stop() @@ -97,7 +97,6 @@ def _timer_stop(self): def _on_timer(self): TimerBase._on_timer(self) - # Tk after() is only a single shot, so we need to add code here to # reset the timer if we're not operating in single shot mode. However, # if _timer is None, this means that _timer_stop has been called; so diff --git a/lib/matplotlib/backends/backend_gtk3.py b/lib/matplotlib/backends/backend_gtk3.py index 7fdc6070b9d4..237df2355c18 100644 --- a/lib/matplotlib/backends/backend_gtk3.py +++ b/lib/matplotlib/backends/backend_gtk3.py @@ -52,6 +52,10 @@ class TimerGTK3(TimerBase): """Subclass of `.TimerBase` using GTK3 timer events.""" + def __init__(self, *args, **kwargs): + self._timer = None + TimerBase.__init__(self, *args, **kwargs) + def _timer_start(self): # Need to stop it, otherwise we potentially leak a timer id that will # never be stopped. diff --git a/lib/matplotlib/backends/backend_qt5.py b/lib/matplotlib/backends/backend_qt5.py index 1bb4f55e5397..897da61be67a 100644 --- a/lib/matplotlib/backends/backend_qt5.py +++ b/lib/matplotlib/backends/backend_qt5.py @@ -180,12 +180,11 @@ class TimerQT(TimerBase): """Subclass of `.TimerBase` using QTimer events.""" def __init__(self, *args, **kwargs): - TimerBase.__init__(self, *args, **kwargs) # Create a new timer and connect the timeout() signal to the # _on_timer method. self._timer = QtCore.QTimer() self._timer.timeout.connect(self._on_timer) - self._timer_set_interval() + TimerBase.__init__(self, *args, **kwargs) def __del__(self): # The check for deletedness is needed to avoid an error at animation diff --git a/lib/matplotlib/backends/backend_webagg_core.py b/lib/matplotlib/backends/backend_webagg_core.py index 3fb06648a9ac..73cca1f2b1d2 100644 --- a/lib/matplotlib/backends/backend_webagg_core.py +++ b/lib/matplotlib/backends/backend_webagg_core.py @@ -489,6 +489,10 @@ def _send_event(self, event_type, **kwargs): class TimerTornado(backend_bases.TimerBase): + def __init__(self, *args, **kwargs): + self._timer = None + super().__init__(*args, **kwargs) + def _timer_start(self): self._timer_stop() if self._single: @@ -510,7 +514,6 @@ def _timer_stop(self): ioloop.remove_timeout(self._timer) else: self._timer.stop() - self._timer = None def _timer_set_interval(self): diff --git a/lib/matplotlib/backends/backend_wx.py b/lib/matplotlib/backends/backend_wx.py index 0f84f23ca372..5105dbfe4e78 100644 --- a/lib/matplotlib/backends/backend_wx.py +++ b/lib/matplotlib/backends/backend_wx.py @@ -70,9 +70,9 @@ class TimerWx(TimerBase): """Subclass of `.TimerBase` using wx.Timer events.""" def __init__(self, *args, **kwargs): - TimerBase.__init__(self, *args, **kwargs) self._timer = wx.Timer() self._timer.Notify = self._on_timer + TimerBase.__init__(self, *args, **kwargs) def _timer_start(self): self._timer.Start(self._interval, self._single) @@ -81,7 +81,8 @@ def _timer_stop(self): self._timer.Stop() def _timer_set_interval(self): - self._timer_start() + if self._timer.IsRunning(): + self._timer_start() # Restart with new interval. def _timer_set_single_shot(self): self._timer.Start() diff --git a/lib/matplotlib/tests/test_backends_interactive.py b/lib/matplotlib/tests/test_backends_interactive.py index e5a6946e2211..4fc6c966dd85 100644 --- a/lib/matplotlib/tests/test_backends_interactive.py +++ b/lib/matplotlib/tests/test_backends_interactive.py @@ -114,7 +114,7 @@ def check_alt_backend(alt_backend): ax.plot([0, 1], [2, 3]) -timer = fig.canvas.new_timer(1) +timer = fig.canvas.new_timer(1.) # Test that floats are cast to int as needed. timer.add_callback(FigureCanvasBase.key_press_event, fig.canvas, "q") # Trigger quitting upon draw. fig.canvas.mpl_connect("draw_event", lambda event: timer.start())