From 462eeada9302158961386ddfed111591f6c5416c Mon Sep 17 00:00:00 2001 From: Grzegorz Bokota Date: Fri, 18 Aug 2023 20:20:11 +0200 Subject: [PATCH] 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 --- src/superqt/utils/_throttler.py | 10 +++++++++- tests/test_throttler.py | 35 +++++++++++++++++++++++++++++++++ 2 files changed, 44 insertions(+), 1 deletion(-) diff --git a/src/superqt/utils/_throttler.py b/src/superqt/utils/_throttler.py index 925433c6..b628f1d6 100644 --- a/src/superqt/utils/_throttler.py +++ b/src/superqt/utils/_throttler.py @@ -259,7 +259,15 @@ def _get_throttler(self, instance, owner, parent, obj): throttler, ) except AttributeError: - self._obj_dkt[obj] = throttler + try: + self._obj_dkt[obj] = throttler + except TypeError as e: + raise TypeError( + "To use qthrottled or qdebounced as a method decorator, " + "objects must have `__dict__` or be weak referenceable. " + "Please either add `__weakref__` to `__slots__` or use" + "qthrottled/qdebounced as a function (not a decorator)." + ) from e return throttler def __get__(self, instance, owner): diff --git a/tests/test_throttler.py b/tests/test_throttler.py index 884d98e4..7d283060 100644 --- a/tests/test_throttler.py +++ b/tests/test_throttler.py @@ -87,6 +87,41 @@ def call2(): 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()