-
Notifications
You must be signed in to change notification settings - Fork 85
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
Feature: 'anytrait' for observe #1496
Conversation
Inplementation note: there's a substantial difference from the way that In particular, this means that |
Good to see this - it's a needed feature. High-level comments before I look more closely:
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actual implementation looks fine: does what it says, and cleanly.
One thought on this:
It seems like that might be an issue that is more general than "anytrait": should we have code that when traits are added (and perhaps more importantly, removed) runs through the observers and check for matches. There are events we can hook into for this, IIRC. |
Final thought: do we want to have |
Yep. This got discussed when we originally implemented
Kinda sorta. We have |
I'd rather not - we currently don't have any trait name "keywords" - names that would prevent the use of those names as traits. ("items" comes close, but it's okay because it can never be used on an instance trait - only on a list, set or dict). |
Yes. I've gone back and forth on this, but I think this is the right compromise. In particular, recent work on the I also dislike the use of |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM with one minor comment.
I'm having some trouble with uses of from traits.api import HasTraits, Instance, Str
class Child(HasTraits):
name = Str()
class Parent(HasTraits):
pass
foo = Parent()
foo.observe(print, "*:name")
foo.add_trait("child", Instance(Child)) |
Confirmed that the issue is separate from the changes in this PR. I've opened #1503 for this. |
From investigating #1503, the behaviour of I'm now wondering whether to restrict the grammar for now so that |
Another potentially fun case: listening to |
I am curious now what happens when you filter on metadata not as the last item (eg. |
I haven't checked (will do that shortly), but I'd expect it not to fail for matching traits that don't have an |
Yep, it's perfectly happy. Here's the test script: from traits.api import Event, HasTraits, Instance
class HasUpdated(HasTraits):
updated = Event()
class LacksUpdated(HasTraits):
pass
class A(HasTraits):
foo = Instance(HasUpdated, fancy=True)
bar = Instance(LacksUpdated, fancy=True)
def print_event(obj, name, old, new):
print("Change event:", obj, name, old, new)
a = A(foo=HasUpdated(), bar=LacksUpdated())
a.on_trait_change(print_event, "+fancy:updated")
a.foo.updated = True # Prints event as expected And the output:
The from traits.api import Event, HasTraits, Instance
from traits.observation.api import match
class HasUpdated(HasTraits):
updated = Event()
class LacksUpdated(HasTraits):
pass
class A(HasTraits):
foo = Instance(HasUpdated, fancy=True)
bar = Instance(LacksUpdated, fancy=True)
def matcher(name, trait):
return getattr(trait, "fancy", None) is not None
a = A(foo=HasUpdated(), bar=LacksUpdated())
a.observe(print, match(matcher, notify=False).trait("updated"))
a.foo.updated = True Output:
It's not obvious what the right thing to do is here. In general, the lack of tolerance of But for a For this PR, I think I'm going to change the grammar to only allow |
Change of plans; to avoid confusion, I'll merge this as-is, and create a new PR for the above change. |
This PR adds anytrait-handling for the 'observe' framework, with mini-language support via the "*" character. Specifically, it adds:
anytrait
function for use in the expression language. This is exposed intraits.observation.api
.anytrait
method toObserverExpression
.Examples: after
We can print all changes to children's traits by doing:
Then we'll see results like:
More simply, we can just listen to all traits on the parent:
Checklist
docs/source/traits_api_reference
)docs/source/traits_user_manual
)[ ] Update type annotation hints inNot applicabletraits-stubs
Fixes #1435