Skip to content

Instantly share code, notes, and snippets.

@moritzmhmk
Forked from walkermatt/debounce.py
Last active August 29, 2015 14:16
Show Gist options
  • Save moritzmhmk/afb8d46a76648309d1f5 to your computer and use it in GitHub Desktop.
Save moritzmhmk/afb8d46a76648309d1f5 to your computer and use it in GitHub Desktop.
from threading import Timer
def debounce(wait, argument_dependent=False):
""" Decorator that will postpone a functions
execution until after wait seconds
have elapsed since the last time it was invoked. """
def decorator(fn):
def debounced(*args, **kwargs):
def call_it():
fn(*args, **kwargs)
if not hasattr(debounced, 't'):
debounced.t = {}
if argument_dependent:
_hash = str(hash(str(args)))+str(hash(str(kwargs)))
else:
_hash = "-"
try:
debounced.t[_hash].cancel()
except(KeyError):
pass
debounced.t[_hash] = Timer(wait, call_it)
debounced.t[_hash].start()
return debounced
return decorator
import unittest
import time
from debounce import debounce
class TestDebounce(unittest.TestCase):
@debounce(4)
def increment(self):
""" Simple function that
increments a counter when
called, used to test the
debounce function decorator """
self.count += 1
def setUp(self):
self.count = 0
def test_debounce(self):
"""
Test that the increment
function is being debounced.
The counter should only be incremented
once 10 seconds after the last call
to the function
"""
self.assertTrue(self.count == 0)
self.increment()
self.increment()
time.sleep(3)
self.assertTrue(self.count == 0)
self.increment()
self.increment()
self.increment()
self.increment()
self.assertTrue(self.count == 0)
time.sleep(5)
self.assertTrue(self.count == 1)
class TestDebounceArgumentDependent(unittest.TestCase):
@debounce(4, argument_dependent=True)
def increment(self, a, b, c, increment=1):
""" Simple function that
increments a counter when
called, used to test the
debounce function decorator """
self.count += increment
def setUp(self):
self.count = 0
def test_debounce(self):
""" Test that the increment
function is being debounced.
The counter should only be incremented
once 10 seconds after the last call
to the function """
self.assertTrue(self.count == 0)
self.increment(1, 2, 3)
self.increment(1, 2, 3)
time.sleep(3)
self.assertTrue(self.count == 0)
self.increment(1, 2, 3)
self.increment(1, 2, 3)
self.increment(1, 2, 3)
self.increment(1, 2, 3)
self.assertTrue(self.count == 0)
time.sleep(5)
self.assertTrue(self.count == 1)
def test_debounce_arguments(self):
""" Test that only calls with the same
argument values are debounced """
self.assertTrue(self.count == 0)
self.increment(1, 2, 3)
self.increment(1, 2, 4)
self.increment(1, 2, 3)
self.increment(1, 2, 3)
self.increment(1, 2, 4)
self.increment(1, 2, 3)
time.sleep(5)
self.assertTrue(self.count == 2)
def test_debounce_keyword_arguments(self):
""" Test that only calls with the same
keyword argument values are debounced """
self.assertTrue(self.count == 0)
self.increment(1, 2, 3, increment=40)
time.sleep(2)
self.increment(1, 2, 3, increment=2)
self.increment(1, 2, 3, increment=2)
self.increment(1, 2, 3, increment=2)
time.sleep(3)
self.assertTrue(self.count == 40)
time.sleep(2)
self.assertTrue(self.count == 42)
if __name__ == '__main__':
unittest.main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment