Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor!: New SignalGroup that does not subclass SignalInstance #269

Merged
merged 49 commits into from
Feb 16, 2024
Merged
Show file tree
Hide file tree
Changes from 35 commits
Commits
Show all changes
49 commits
Select commit Hold shift + click to select a range
92a1ab0
wip
tlambert03 Feb 10, 2024
05602e4
wip
tlambert03 Feb 11, 2024
4507073
tests passing
tlambert03 Feb 11, 2024
5500c22
more fixes
tlambert03 Feb 11, 2024
70dab51
add init error
tlambert03 Feb 11, 2024
8e4f9b8
add tests
tlambert03 Feb 11, 2024
ead7d37
fixes
tlambert03 Feb 12, 2024
4b966bf
catch warnings
tlambert03 Feb 12, 2024
315a3aa
style(pre-commit.ci): auto fixes [...]
pre-commit-ci[bot] Feb 12, 2024
03c006c
use annotation for public name
tlambert03 Feb 12, 2024
80d7393
Merge branch 'new-signal-group' of https://github.com/tlambert03/psyg…
tlambert03 Feb 12, 2024
2d8920a
don't use mutable mapping
tlambert03 Feb 12, 2024
a64ac84
Merge branch 'main' into new-signal-group
tlambert03 Feb 12, 2024
07afe29
fix: hacky fix tests
tlambert03 Feb 12, 2024
ed0b934
test: more tests
tlambert03 Feb 12, 2024
3697b52
Merge branch 'main' into new-signal-group
tlambert03 Feb 12, 2024
367e46b
replace old graoup
tlambert03 Feb 13, 2024
744b973
use psygnal_relay
tlambert03 Feb 13, 2024
a78d9d6
undo change
tlambert03 Feb 13, 2024
9f44dfc
more test fixes
tlambert03 Feb 13, 2024
6d2c795
try fix typing
tlambert03 Feb 13, 2024
a2e88ea
fix typing
tlambert03 Feb 13, 2024
18d3e25
more deprecations
tlambert03 Feb 13, 2024
f14646f
docs: more docs
tlambert03 Feb 13, 2024
1a7e6a1
fix: improve model setattr performance
tlambert03 Feb 13, 2024
25596c8
fix: coverage
tlambert03 Feb 13, 2024
189c018
perf: try improve bench
tlambert03 Feb 13, 2024
5e6a65e
perf: change benchmark
tlambert03 Feb 13, 2024
56fe620
perf: fix evented setattr performance
tlambert03 Feb 13, 2024
8b29145
test: fix warning in test_bench
tlambert03 Feb 13, 2024
77e11ec
fix: revert event_names change
tlambert03 Feb 13, 2024
e83edeb
Merge branch 'main' into new-signal-group
tlambert03 Feb 14, 2024
5875261
docs: more docs
tlambert03 Feb 14, 2024
144cf6d
Merge branch 'main' into new-signal-group
tlambert03 Feb 14, 2024
8eab8af
Merge branch 'main' into new-signal-group
tlambert03 Feb 14, 2024
8037e8a
refactor: use dict methods
tlambert03 Feb 15, 2024
d9b32b4
refactor: use getitem in descriptor
tlambert03 Feb 15, 2024
ff7cd83
test: add test
tlambert03 Feb 15, 2024
2509648
refactor: add explicit line to getattr and contains
tlambert03 Feb 15, 2024
47bf3ae
feat: use name all permanently
tlambert03 Feb 16, 2024
837b260
refactor: change attr error strategy
tlambert03 Feb 16, 2024
6d78c8f
test: add test
tlambert03 Feb 16, 2024
61b0ef8
fix: change setattr strategy
tlambert03 Feb 16, 2024
5b67dc0
refactor: pragma
tlambert03 Feb 16, 2024
60b73d0
feat: add conflicts warning
tlambert03 Feb 16, 2024
6d49dfc
test: more tests and warnings
tlambert03 Feb 16, 2024
ff0bae7
test: more tests and deprecations
tlambert03 Feb 16, 2024
6dd25bb
test: split test
tlambert03 Feb 16, 2024
dbbd2fa
test: add field
tlambert03 Feb 16, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions benchmarks/benchmarks.py
Original file line number Diff line number Diff line change
Expand Up @@ -141,20 +141,21 @@ class Model(EventedModel):
x: int = 1

self.model = Model
self.model_instance = Model()

def time_setattr_no_connections(self, n: int) -> None:
if self.model is None:
return

obj = self.model()
obj = self.model_instance
for i in range(n):
obj.x = i

def time_setattr_with_connections(self, n: int) -> None:
if self.model is None:
return

obj = self.model()
obj = self.model_instance
obj.events.x.connect(callback)
for i in range(n):
obj.x = i
5 changes: 3 additions & 2 deletions src/psygnal/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,8 @@
"_compiled",
"debounced",
"EmissionInfo",
"EmitLoopError",
"emit_queued",
"EmitLoopError",
"evented",
"EventedModel",
"get_evented_namespace",
Expand All @@ -33,6 +33,7 @@
"SignalGroup",
"SignalGroupDescriptor",
"SignalInstance",
"SignalRelay",
"throttled",
]

Expand All @@ -50,7 +51,7 @@

from ._evented_decorator import evented
from ._exceptions import EmitLoopError
from ._group import EmissionInfo, SignalGroup
from ._group import EmissionInfo, SignalGroup, SignalRelay
from ._group_descriptor import (
SignalGroupDescriptor,
get_evented_namespace,
Expand Down
11 changes: 6 additions & 5 deletions src/psygnal/_evented_model_v1.py
Original file line number Diff line number Diff line change
Expand Up @@ -347,7 +347,7 @@
if (
name == "_events"
or not hasattr(self, "_events") # can happen on init
or name not in self._events.signals
or name not in self._events
):
# fallback to default behavior
return self._super_setattr_(name, value)
Expand All @@ -357,16 +357,17 @@
# dependent properties.
# note that ALL signals will have at least one listener simply by nature of
# being in the `self._events` SignalGroup.
signal_instance: SignalInstance = getattr(self._events, name)
group = self._events
signal_instance: SignalInstance = group[name]

Check warning on line 361 in src/psygnal/_evented_model_v1.py

View check run for this annotation

Codecov / codecov/patch

src/psygnal/_evented_model_v1.py#L360-L361

Added lines #L360 - L361 were not covered by tests
deps_with_callbacks = {
dep_name
for dep_name in self.__field_dependents__.get(name, ())
if len(getattr(self._events, dep_name)) > 1
if len(group[dep_name]) > 1
}
if (
len(signal_instance) < 2 # the signal itself has no listeners
and not deps_with_callbacks # no dependent properties with listeners
and not len(self._events) # no listeners on the SignalGroup
and not len(group._psygnal_relay) # no listeners on the SignalGroup
):
return self._super_setattr_(name, value)

Expand Down Expand Up @@ -433,7 +434,7 @@
if not isinstance(values, dict): # pragma: no cover
raise TypeError(f"values must be a dict or BaseModel. got {type(values)}")

with self.events.paused(): # TODO: reduce?
with self.events._psygnal_relay.paused(): # TODO: reduce?

Check warning on line 437 in src/psygnal/_evented_model_v1.py

View check run for this annotation

Codecov / codecov/patch

src/psygnal/_evented_model_v1.py#L437

Added line #L437 was not covered by tests
for key, value in values.items():
field = getattr(self, key)
if isinstance(field, EventedModel) and recurse:
Expand Down
15 changes: 8 additions & 7 deletions src/psygnal/_evented_model_v2.py
Original file line number Diff line number Diff line change
Expand Up @@ -332,9 +332,9 @@ def _super_setattr_(self, name: str, value: Any) -> None:
def __setattr__(self, name: str, value: Any) -> None:
if (
name == "_events"
or not hasattr(self, "_events")
or name not in self._events.signals
): # can happen on init
or not hasattr(self, "_events") # can happen on init
or name not in self._events
):
# fallback to default behavior
return self._super_setattr_(name, value)

Expand All @@ -343,16 +343,17 @@ def __setattr__(self, name: str, value: Any) -> None:
# dependent properties.
# note that ALL signals will have sat least one listener simply by nature of
# being in the `self._events` SignalGroup.
signal_instance: SignalInstance = getattr(self._events, name)
group = self._events
signal_instance: SignalInstance = group[name]
deps_with_callbacks = {
dep_name
for dep_name in self.__field_dependents__.get(name, ())
if len(getattr(self._events, dep_name)) > 1
if len(group[dep_name]) > 1
}
if (
len(signal_instance) < 2 # the signal itself has no listeners
and not deps_with_callbacks # no dependent properties with listeners
and not len(self._events) # no listeners on the SignalGroup
and not len(group._psygnal_relay) # no listeners on the SignalGroup
):
return self._super_setattr_(name, value)

Expand Down Expand Up @@ -419,7 +420,7 @@ def update(self, values: Union["EventedModel", dict], recurse: bool = True) -> N
if not isinstance(values, dict): # pragma: no cover
raise TypeError(f"values must be a dict or BaseModel. got {type(values)}")

with self.events.paused(): # TODO: reduce?
with self.events._psygnal_relay.paused(): # TODO: reduce?
for key, value in values.items():
field = getattr(self, key)
if isinstance(field, EventedModel) and recurse:
Expand Down
Loading
Loading