Skip to content

Deprecate considering *args, **kwargs in Timer.remove_callback. #12170

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Mar 18, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 22 additions & 0 deletions doc/api/next_api_changes/2018-09-19-AL.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
Timer.remove_callback won't consider ``*args, **kwargs`` in a future version
````````````````````````````````````````````````````````````````````````````

Currently, ``Timer.remove_callback(func, *args, **kwargs)`` removes a callback
previously added by ``Timer.add_callback(func, *args, **kwargs)``, but if
``*args, **kwargs`` is not passed in (``Timer.remove_callback(func)``), then
the first callback with a matching ``func`` is removed, regardless of whether
it was added with or without ``*args, **kwargs``.

In a future version, ``Timer.remove_callback`` will always use the latter
behavior (not consider ``*args, **kwargs``); to specifically consider them, add
the callback as a `functools.partial` object ::

cb = timer.add_callback(functools.partial(func, *args, **kwargs))
# ...
# later
timer.remove_callback(cb)

``Timer.add_callback`` was modified to return *func* to simplify the above
usage (previously it returned None); this also allows using it as a decorator.

The new API is modelled after `atexit.register` / `atexit.unregister`.
56 changes: 36 additions & 20 deletions lib/matplotlib/backend_bases.py
Original file line number Diff line number Diff line change
Expand Up @@ -1094,7 +1094,7 @@ def set_sketch_params(self, scale=None, length=None, randomness=None):


class TimerBase(object):
'''
"""
A base class for providing timer events, useful for things animations.
Backends need to implement a few specific methods in order to use their
own timing mechanisms so that the timer events are integrated into their
Expand Down Expand Up @@ -1137,8 +1137,7 @@ class TimerBase(object):
Stores list of (func, args, kwargs) tuples that will be called upon
timer events. This list can be manipulated directly, or the
functions `add_callback` and `remove_callback` can be used.

'''
"""
def __init__(self, interval=None, callbacks=None):
#Initialize empty callbacks list and setup default settings if necssary
if callbacks is None:
Expand All @@ -1157,22 +1156,25 @@ def __init__(self, interval=None, callbacks=None):
self._timer = None

def __del__(self):
'Need to stop timer and possibly disconnect timer.'
"""Need to stop timer and possibly disconnect timer."""
self._timer_stop()

def start(self, interval=None):
'''
Start the timer object. `interval` is optional and will be used
to reset the timer interval first if provided.
'''
"""
Start the timer object.

Parameters
----------
interval : int, optional
Timer interval in milliseconds; overrides a previously set interval
if provided.
"""
if interval is not None:
self._set_interval(interval)
self._timer_start()

def stop(self):
'''
Stop the timer.
'''
"""Stop the timer."""
self._timer_stop()

def _timer_start(self):
Expand Down Expand Up @@ -1203,19 +1205,33 @@ def single_shot(self, ss):
self._timer_set_single_shot()

def add_callback(self, func, *args, **kwargs):
'''
"""
Register *func* to be called by timer when the event fires. Any
additional arguments provided will be passed to *func*.
'''

This function returns *func*, which makes it possible to use it as a
decorator.
"""
self.callbacks.append((func, args, kwargs))
return func

def remove_callback(self, func, *args, **kwargs):
'''
Remove *func* from list of callbacks. *args* and *kwargs* are optional
and used to distinguish between copies of the same function registered
to be called with different arguments.
'''
"""
Remove *func* from list of callbacks.

*args* and *kwargs* are optional and used to distinguish between copies
of the same function registered to be called with different arguments.
This behavior is deprecated. In the future, `*args, **kwargs` won't be
considered anymore; to keep a specific callback removable by itself,
pass it to `add_callback` as a `functools.partial` object.
"""
if args or kwargs:
cbook.warn_deprecated(
"3.1", "In a future version, Timer.remove_callback will not "
"take *args, **kwargs anymore, but remove all callbacks where "
"the callable matches; to keep a specific callback removable "
"by itself, pass it to add_callback as a functools.partial "
"object.")
self.callbacks.remove((func, args, kwargs))
else:
funcs = [c[0] for c in self.callbacks]
Expand All @@ -1229,11 +1245,11 @@ def _timer_set_single_shot(self):
"""Used to set single shot on underlying timer object."""

def _on_timer(self):
'''
"""
Runs all function that have been registered as callbacks. Functions
can return False (or 0) if they should not be called any more. If there
are no callbacks, the timer is automatically stopped.
'''
"""
for func, args, kwargs in self.callbacks:
ret = func(*args, **kwargs)
# docstring above explains why we use `if ret == 0` here,
Expand Down