diff options
author | Roman Guchevskij <rvtpro@gmail.com> | 2023-03-28 20:09:34 +0300 |
---|---|---|
committer | GitHub <noreply@github.com> | 2023-03-28 19:09:34 +0200 |
commit | 6d2393bbeed3757eea6cbb4b33a14cb9960e597d (patch) | |
tree | cd9811505572b3462158871cf6ba835ac52589bd | |
parent | b593cf7645b6b9b5377945313f04f0d6a293fbfb (diff) | |
download | urwid-6d2393bbeed3757eea6cbb4b33a14cb9960e597d.tar.gz |
Fix TypeError in signals module on weak object dispose (#503)
squash and merge
-rw-r--r-- | urwid/signals.py | 6 | ||||
-rw-r--r-- | urwid/tests/test_signals.py | 62 |
2 files changed, 63 insertions, 5 deletions
diff --git a/urwid/signals.py b/urwid/signals.py index 0269dfd..78f1eae 100644 --- a/urwid/signals.py +++ b/urwid/signals.py @@ -174,10 +174,7 @@ class Signals(object): def weakref_callback(weakref): o = obj_weak() if o: - try: - del getattr(o, self._signal_attr, {})[name][key] - except KeyError: - pass + self.disconnect_by_key(o, name, key) user_args = self._prepare_user_args(weak_args, user_args, weakref_callback) handlers.append((key, callback, user_arg, user_args)) @@ -300,4 +297,3 @@ register_signal = _signals.register connect_signal = _signals.connect disconnect_signal = _signals.disconnect disconnect_signal_by_key = _signals.disconnect_by_key - diff --git a/urwid/tests/test_signals.py b/urwid/tests/test_signals.py new file mode 100644 index 0000000..22db34e --- /dev/null +++ b/urwid/tests/test_signals.py @@ -0,0 +1,62 @@ +import unittest +try: + from unittest.mock import Mock +except ImportError: + # Python2, rely on PyPi + from mock import Mock + +from urwid import connect_signal, disconnect_signal, register_signal, emit_signal, Signals, Edit + +class SiglnalsTest(unittest.TestCase): + + @classmethod + def setUpClass(cls): + cls.EmClass = type("EmClass", (object, ), {}) + register_signal(cls.EmClass, ["change", "test"]) + + def test_connect(self): + obj = Mock() + handler = Mock() + edit = Edit('') + key = connect_signal(edit, 'change', handler, user_args=[obj]) + self.assertIsNotNone(key) + edit.set_edit_text('long test text') + handler.assert_called_once_with(obj, edit, 'long test text') + + handler.reset_mock() + disconnect_signal(edit, 'change', handler, user_args=[obj]) + edit.set_edit_text('another text') + handler.assert_not_called() + + def test_weak_del(self): + emitter = SiglnalsTest.EmClass() + w1 = Mock() + w2 = Mock() + w3 = Mock() + + handler1 = Mock() + handler2 = Mock() + + k1 = connect_signal(emitter, 'test', handler1, weak_args=[w1], user_args=[42, "abc"]) + k2 = connect_signal(emitter, 'test', handler2, weak_args=[w2, w3], user_args=[8]) + self.assertIsNotNone(k2) + + emit_signal(emitter, 'test', "Foo") + handler1.assert_called_once_with(w1, 42, "abc", "Foo") + handler2.assert_called_once_with(w2, w3, 8, "Foo") + + handler1.reset_mock() + handler2.reset_mock() + del w1 + self.assertEqual(len(getattr(emitter, Signals._signal_attr)['test']), 1) + emit_signal(emitter, 'test', "Bar") + handler1.assert_not_called() + handler2.assert_called_once_with(w2, w3, 8, "Bar") + + handler2.reset_mock() + del w3 + emit_signal(emitter, 'test', "Baz") + handler1.assert_not_called() + handler2.assert_not_called() + self.assertEqual(len(getattr(emitter, Signals._signal_attr)['test']), 0) + del w2 |