RepeatedTimer now allows adaptive interval and dynamic loop condition

This commit is contained in:
Gina Häußge 2015-03-25 17:24:12 +01:00
parent 18dd1659da
commit 50862668b1

View file

@ -536,7 +536,7 @@ def address_for_client(host, port):
class RepeatedTimer(threading.Thread):
"""
This class represents an action that should be run repeatedly in a predefined interval. It is similar to python's
This class represents an action that should be run repeatedly in an interval. It is similar to python's
own :class:`threading.Timer` class, but instead of only running once the ``function`` will be run again and again,
sleeping the stated ``interval`` in between.
@ -554,48 +554,92 @@ class RepeatedTimer(threading.Thread):
t = RepeatedTimer(1.0, hello)
t.start() # prints "Hello World!" every second
Another example with dynamic interval and loop condition:
.. code-block:: python
count = 0
maximum = 5
factor = 1
def interval():
global count
global factor
return count * factor
def condition():
global count
global maximum
return count <= maximum
def hello():
print("Hello World!")
global count
count += 1
t = RepeatedTimer(interval, hello, run_first=True, condition=condition)
t.start() # prints "Hello World!" 5 times, printing the first one
# directly, then waiting 1, 2, 3, 4s in between (adaptive interval)
Arguments:
interval (float): The interval between each ``function`` call, in seconds.
interval (float or callable): The interval between each ``function`` call, in seconds. Can also be a callable
returning the interval to use, in case the interval is not static.
function (callable): The function to call.
args (list or tuple): The arguments for the ``function`` call.
kwargs (dict): The keyword arguments for the ``function`` call.
args (list or tuple): The arguments for the ``function`` call. Defaults to an empty list.
kwargs (dict): The keyword arguments for the ``function`` call. Defaults to an empty dict.
run_first (boolean): If set to True, the function will be run for the first time *before* the first wait period.
If set to False (the default), the function will be run for the first time *after* the first wait period.
condition (callable): Condition that needs to be True for loop to continue. Defaults to ``lambda: True``.
"""
def __init__(self, interval, function, args=None, kwargs=None, run_first=False):
def __init__(self, interval, function, args=None, kwargs=None, run_first=False, condition=None):
threading.Thread.__init__(self)
if args is None:
args = []
if kwargs is None:
kwargs = dict()
if condition is None:
condition = lambda: True
if not callable(interval):
self.interval = lambda: interval
else:
self.interval = interval
self.interval = interval
self.function = function
self.finished = threading.Event()
self.args = args
self.kwargs = kwargs
self.run_first = run_first
self.condition = condition
def cancel(self):
self.finished.set()
def run(self):
while True:
while self.condition():
if self.run_first:
# if we are to run the function BEFORE waiting for the first time
self.function(*self.args, **self.kwargs)
# make sure our condition is still met before running into the downtime
if not self.condition():
break
# wait, but break if we are cancelled
self.finished.wait(self.interval)
self.finished.wait(self.interval())
if self.finished.is_set():
return
break
if not self.run_first:
# if we are to run the function AFTER waiting for the first time
self.function(*self.args, **self.kwargs)
# make sure we set our finished event so we can detect that the loop was finished
self.finished.set()
class CountedEvent(object):