Files
superqt/tests/test_throttler.py
Grzegorz Bokota 462eeada93 fix: Add descriptive exception when fail to add instance to weakref dictionary (#189)
* add weakref information and test

* more information

* Update src/superqt/utils/_throttler.py

---------

Co-authored-by: Talley Lambert <talley.lambert@gmail.com>
2023-08-18 14:20:11 -04:00

169 lines
3.4 KiB
Python

from unittest.mock import Mock
import pytest
from qtpy.QtCore import QObject, Signal
from superqt.utils import qdebounced, qthrottled
from superqt.utils._throttler import ThrottledCallable
def test_debounced(qtbot):
mock1 = Mock()
mock2 = Mock()
@qdebounced(timeout=5)
def f1() -> str:
mock1()
def f2() -> str:
mock2()
for _ in range(10):
f1()
f2()
qtbot.wait(5)
mock1.assert_called_once()
assert mock2.call_count == 10
def test_debouncer_method(qtbot):
class A(QObject):
def __init__(self):
super().__init__()
self.count = 0
def callback(self):
self.count += 1
a = A()
assert all(not isinstance(x, ThrottledCallable) for x in a.children())
b = qdebounced(a.callback, timeout=4)
assert any(isinstance(x, ThrottledCallable) for x in a.children())
for _ in range(10):
b()
qtbot.wait(5)
assert a.count == 1
def test_debouncer_method_definition(qtbot):
mock1 = Mock()
mock2 = Mock()
class A(QObject):
def __init__(self):
super().__init__()
self.count = 0
@qdebounced(timeout=4)
def callback(self):
self.count += 1
@qdebounced(timeout=4)
@staticmethod
def call1():
mock1()
@staticmethod
@qdebounced(timeout=4)
def call2():
mock2()
a = A()
assert all(not isinstance(x, ThrottledCallable) for x in a.children())
for _ in range(10):
a.callback(1)
A.call1(34)
a.call1(22)
a.call2(22)
A.call2(32)
qtbot.wait(5)
assert a.count == 1
mock1.assert_called_once()
mock2.assert_called_once()
def test_class_with_slots(qtbot):
class A:
__slots__ = ("count", "__weakref__")
def __init__(self):
self.count = 0
@qdebounced(timeout=4)
def callback(self):
self.count += 1
a = A()
for _ in range(10):
a.callback()
qtbot.wait(5)
assert a.count == 1
@pytest.mark.usefixtures("qapp")
def test_class_with_slots_except():
class A:
__slots__ = ("count",)
def __init__(self):
self.count = 0
@qdebounced(timeout=4)
def callback(self):
self.count += 1
with pytest.raises(TypeError, match="To use qthrottled or qdebounced"):
A().callback()
def test_throttled(qtbot):
mock1 = Mock()
mock2 = Mock()
@qthrottled(timeout=5)
def f1() -> str:
mock1()
def f2() -> str:
mock2()
for _ in range(10):
f1()
f2()
qtbot.wait(5)
assert mock1.call_count == 2
assert mock2.call_count == 10
@pytest.mark.parametrize("deco", [qthrottled, qdebounced])
def test_ensure_throttled_sig_inspection(deco, qtbot):
mock = Mock()
class Emitter(QObject):
sig = Signal(int, int, int)
@deco
def func(a: int, b: int):
"""docstring"""
mock(a, b)
obj = Emitter()
obj.sig.connect(func)
# this is the crux of the test...
# we emit 3 args, but the function only takes 2
# this should normally work fine in Qt.
# testing here that the decorator doesn't break it.
with qtbot.waitSignal(func.triggered, timeout=1000):
obj.sig.emit(1, 2, 3)
mock.assert_called_once_with(1, 2)
assert func.__doc__ == "docstring"
assert func.__name__ == "func"