Skip to content

Commit

Permalink
feat: emit the old value as second argument in Signals from SignalGro…
Browse files Browse the repository at this point in the history
…upDescriptor (evented dataclass) (#257)

* add emit_old_value

* style(pre-commit.ci): auto fixes [...]

* merge conflicts

* merge conflicts

* correct tests

* minimal changes

* correct signal signature

* test: fix bench

---------

Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
Co-authored-by: Talley Lambert <[email protected]>
  • Loading branch information
3 people authored Feb 1, 2024
1 parent 59472ca commit d3d558d
Show file tree
Hide file tree
Showing 4 changed files with 16 additions and 11 deletions.
4 changes: 2 additions & 2 deletions src/psygnal/_group_descriptor.py
Original file line number Diff line number Diff line change
Expand Up @@ -155,7 +155,7 @@ def _build_dataclass_signal_group(
else:
eq_map[name] = _pick_equality_operator(type_)
field_type = object if type_ is None else type_
signals[name] = sig = Signal(field_type)
signals[name] = sig = Signal(field_type, field_type)
# patch in our custom SignalInstance class with maxargs=1 on connect_setattr
sig._signal_instance_class = _DataclassFieldSignalInstance

Expand Down Expand Up @@ -204,7 +204,7 @@ def __enter__(self) -> None:
def __exit__(self, *args: Any) -> None:
new: Any = getattr(self.obj, self.field, _NULL)
if not _check_field_equality(type(self.obj), self.field, self._prev, new):
self.signal.emit(new)
self.signal.emit(new, self._prev)


SetAttr = Callable[[Any, str, Any], None]
Expand Down
10 changes: 7 additions & 3 deletions tests/test_bench.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
"print",
]


# fmt: off
class Emitter:
one_int = Signal(int)
Expand Down Expand Up @@ -221,6 +222,9 @@ def _doit() -> None:
foo.e = (2, "hello")

benchmark(_doit)
for newval, attr in zip([2, "hello", False, 2.0, (2, "hello")], "abcde"):
mock.assert_any_call(EmissionInfo(getattr(foo.events, attr), (newval,)))
assert getattr(foo, attr) == newval
for emitted, attr in zip(
[(2, 1), ("hello", "hi"), (False, True), (2.0, 1.0), ((2, "hello"), (1, "hi"))],
"abcde",
):
mock.assert_any_call(EmissionInfo(getattr(foo.events, attr), emitted))
assert getattr(foo, attr) == emitted[0]
2 changes: 1 addition & 1 deletion tests/test_evented_decorator.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ def _check_events(cls, events_ns="events"):
assert obj.bar == 1
obj.bar = 2
assert obj.bar == 2
mock.assert_called_once_with(2)
mock.assert_called_once_with(2, 1)

mock.reset_mock()
obj.baz = "3"
Expand Down
11 changes: 6 additions & 5 deletions tests/test_group_descriptor.py
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,7 @@ class Foo:
foo._events.a.connect(mock)
foo.a = 2
if patch_setattr:
mock.assert_called_once_with(2)
mock.assert_called_once_with(2, 1)
else:
mock.assert_not_called()

Expand All @@ -142,7 +142,8 @@ class Foo:

@_group_descriptor.evented_setattr("_events")
def __setattr__(self, __name: str, __value: Any) -> None:
mock1(__name, __value)
old = getattr(self, __name, None)
mock1(__name, __value, old)
super().__setattr__(__name, __value)

assert _group_descriptor.is_evented(Foo.__setattr__)
Expand All @@ -154,8 +155,8 @@ def __setattr__(self, __name: str, __value: Any) -> None:
mock = Mock()
foo._events.a.connect(mock)
foo.a = 2
mock.assert_called_once_with(2) # confirm no double event emission
mock1.assert_called_with("a", 2)
mock.assert_called_once_with(2, 1) # confirm no double event emission
mock1.assert_called_with("a", 2, 1)


def test_no_getattr_on_non_evented_fields() -> None:
Expand All @@ -180,7 +181,7 @@ def b(self, value: int) -> None:
foo = Foo(a=1)
foo.events.a.connect(a_mock)
foo.a = 2
a_mock.assert_called_once_with(2)
a_mock.assert_called_once_with(2, 1)

foo.b = 1
b_mock.assert_not_called() # getter shouldn't have been called
Expand Down

0 comments on commit d3d558d

Please sign in to comment.