-
-
Notifications
You must be signed in to change notification settings - Fork 200
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
Deprecate on_trait_change and magic change handlers #61
Conversation
2a2c45e
to
fa4c133
Compare
PS: To handle the removal of the wrapped callbacks, I needed to write the wrapper to be comparable with the original function with |
- object : the HasTraits instance | ||
- old : the old value of the modified trait attribute | ||
- new : the new value of the modified trait attribute | ||
- name : the name ofthe modified trait attribute. |
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.
Missing space
@ellisonbg @sccolbert as per earlier discussion. |
@SylvainCorlay, tested both constructs, 👍 |
The old constructs worked too, but I didn't get any warnings when run in an IPython console. |
Hum, I am seeing the warnings in the notebook. |
For whatever reason my session is not printing |
By default, deprecation warnings are not printed in python. You have to either manually set the warnings filter to allow them, or start python with a special switch. |
@@ -547,6 +547,51 @@ def tag(self, **metadata): | |||
# The HasTraits implementation | |||
#----------------------------------------------------------------------------- | |||
|
|||
class _CbWrapper(object): |
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.
Can we make this _CallbackWrapper
? It feels more pythonic than using abbreviations.
handler : callable | ||
A callable that is called when a trait changes. Its | ||
signature can be handler() or handler(change), where change is a | ||
dictionary with the following optional keys: |
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.
Are the keys really optional?
@minrk, @ellisonbg - when you guys have a minute, it'd be great to hear your comments. |
Let me know what you think.
|
OK I see this one and will have a look... On Sun, Aug 9, 2015 at 1:49 PM, Sylvain Corlay notifications@github.com
Brian E. Granger |
I think the name of the key in the change dict of |
Good point! On Thu, Aug 27, 2015 at 8:43 AM, Sylvain Corlay notifications@github.com
Brian E. Granger |
So are we moving to 'emitter'? |
Hmm, yeah, I can see how "emitter" has a "signal oriented" connotation On Thu, Aug 27, 2015 at 8:49 AM, Sylvain Corlay notifications@github.com
Brian E. Granger |
Although in the signaling PR, there are two bridges between traits and signaling:
In the latter case especially, mixing two systems where one uses |
+1 on emitter because it's more like source :) |
Pushed |
To clarify @minrk I think you are the right person to make this call. In I am personally 50/50 on owner versus emitter. On Thu, Aug 27, 2015 at 11:10 AM, Sylvain Corlay notifications@github.com
Brian E. Granger |
'source' sounded generic and ambiguous, 'emitter' seems better. |
Owner also seems slightly preferable to emitter, but both seem just fine. I'm okay with letting the current state of this PR make the choice.
|
We are getting @jdfreder to weigh in right now... On Thu, Aug 27, 2015 at 11:54 AM, Min RK notifications@github.com wrote:
Brian E. Granger |
@jdfreder voted for emitter. I am still 50/50. On Thu, Aug 27, 2015 at 11:58 AM, Brian Granger ellisonbg@gmail.com wrote:
Brian E. Granger |
@ellisonbg I updated the PR as per what we agreed on during the call. |
Just to update the community - on a phone call we reached consensus on using owner for this as this usage of more about a property pattern than a signaling one. If we ever have a signally abstraction we all agree that emitter would be good in that context. |
Deprecate on_trait_change and magic change handlers
And great work! |
self.func = func | ||
return self | ||
|
||
def instance_init(self, inst): |
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.
It turns out that since this is being registered in the metaclass. The ObserveHandler
is preventing the function from being registered as a method at runtime like it normally would. instance_init
should instead read:
def instance_init(self, inst):
self.func = types.MethodType(self.func, inst)
setattr(inst, self.name, self.func)
for name in self.names:
inst.observe(self.func, name= name)
@rmorshea you are right. We should make it a bound method. Do you want to open a PR? |
Yep, I didn't see that No worries though, simply reimplement def __get__(self, inst, cls):
if inst is None:
return self
return MethodType(self.func, inst) The way it currently sits, it allocates a new bound method for each function for each instance. It then also consumes more space by storing the method on the instance, plus circular ref, etc. That's pretty wasteful and can cause some undue pain when people start creating lots of objects. |
I think that's a cleaner way to do it. What's the "circular ref" though, wouldn't the ObserveHander instance be garbage collected? |
The circular ref would be caused by the bound method holding a reference to the instance, and instance holding a reference to the bound method. It's not the end of the world, and the garbage collector would probably get to it eventually (unless the instance has a |
Gotcha, wasn't looking for it in the right place. |
Deprecation of
on_trait_change
and the signature of change handlersAs of now, this PR deprecates
on_trait_change
and the magic_*foo*_changed
handlers, to the benefit of newobserve
andunobserve
method. The signature of the handlers passed toobserve
is eitherdict
argument containing 'name', 'old', 'new' and 'owner', the HasTraits instance emitting the event.See the examples below.
Implementation of an
observe
decorator like in Atom:On the other side, atom implements a
observe
decoratorThe problem is that the registration of the callback requires access
self
attribute, which is not available when the decorator is called. The way it works in atom is that the@observe('age')
decorator replaces thedebug_print
method with a placeholder objectObserveHandler
holding the method to be registered, which is to be picked up and unwrapped by theAtomMeta
metaclass when instantiating the instance of (the counterpart to) HasTraits.Rather than augmenting the metaclass, I could achieve the same result by making our
ObserveHandler
inherit fromBaseDescriptor
, and implement the custom logic ininstance_init
.Example with traitlets: