diff --git a/CHANGES.rst b/CHANGES.rst index 6f2b6e1..a5e7850 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -3,6 +3,8 @@ Version 1.8.1 Unreleased +- Restore identity handling for ``str`` and ``int`` senders. :pr:`148` + Version 1.8.0 ------------- diff --git a/src/blinker/_utilities.py b/src/blinker/_utilities.py index 784ba4e..c948b09 100644 --- a/src/blinker/_utilities.py +++ b/src/blinker/_utilities.py @@ -39,9 +39,20 @@ def __getnewargs__(self) -> tuple[t.Any]: def make_id(obj: object) -> t.Hashable: + """Get a stable identifier for a receiver or sender, to be used as a dict + key or in a set. + """ if inspect.ismethod(obj): + # The id of a bound method is not stable, but the id of the unbound + # function and instance are. return id(obj.__func__), id(obj.__self__) + if isinstance(obj, (str, int)): + # Instances with the same value always compare equal and have the same + # hash, even if the id may change. + return obj + + # Assume other types are not hashable but will always be the same instance. return id(obj) diff --git a/tests/test_signals.py b/tests/test_signals.py index 325ba80..5edb536 100644 --- a/tests/test_signals.py +++ b/tests/test_signals.py @@ -485,15 +485,15 @@ def values_are_empty_sets_(dictionary: dict[t.Any, t.Any]) -> None: def test_int_sender() -> None: - sentinel = [] + count = 0 def received(sender: t.Any) -> None: - sentinel.append(sender) + nonlocal count + count += 1 sig = blinker.Signal() - sig.connect(received, sender=123456789) - sig.send(123456789) - assert len(sentinel) == 1 - sig.send(123456789 + 0) # Forces a new id with CPython - assert len(sentinel) == 2 + sig.send(123456789) # Python compiler uses same instance for same literal value. + assert count == 1 + sig.send(int("123456789")) # Force different instance with same value. + assert count == 2