[Traits] dirty trait metadata

Hi,

Consider the following:

-----------------
from numpy import *
from enthought.traits.api import *
class Data(HasTraits):
     x = Array
     def _x_changed(self, value):
         print value

x = linspace(0, 1)
d = Data(x=x)
-------------------

Now I'd like to always call _x_changed when the x trait is set.  Thus, 
I'd like this to work:

x *= 2
d.x = x # Should call _x_changed

Is there a simple way of doing this?  I know that I could achieve this 
if I implemented x as a Property(Array) but is there an easier way?

Thanks.
prabhu
Robert Kern | 6 Sep 00:23

Re: [Traits] dirty trait metadata

On Fri, Sep 5, 2008 at 14:43, Prabhu Ramachandran
<prabhu@...> wrote:
> Hi,
>
> Consider the following:
>
> -----------------
> from numpy import *
> from enthought.traits.api import *
> class Data(HasTraits):
>     x = Array
>     def _x_changed(self, value):
>         print value
>
> x = linspace(0, 1)
> d = Data(x=x)
> -------------------
>
> Now I'd like to always call _x_changed when the x trait is set.  Thus,
> I'd like this to work:
>
> x *= 2
> d.x = x # Should call _x_changed
>
> Is there a simple way of doing this?  I know that I could achieve this
> if I implemented x as a Property(Array) but is there an easier way?

I don't think so. The comparison logic is in C
(ctraits.c:setattr_trait), and there are no hooks for this.

(Continue reading)

Re: [Traits] dirty trait metadata

Robert Kern wrote:

>> Is there a simple way of doing this?  I know that I could achieve this
>> if I implemented x as a Property(Array) but is there an easier way?
> 
> I don't think so. The comparison logic is in C
> (ctraits.c:setattr_trait), and there are no hooks for this.
> 
> If you only need coarse-grained notifications, you might consider
> using an updated Event. This:

OK, so I came up with a new trait type that does this nicely with 
minimal fuss and also does the validation right.  Attached is the code 
along with a complete test case.  A quick example:

ArrayOrNone = Either(None, Array)
class Data(HasTraits):
     x = ShadowProperty(ArrayOrNone)
     # Test attribute.
     _test = Any
     def _x_changed(self, value):
         self._test = value.copy()

This automatically builds the shadow _x trait and always calls back 
_x_changed.  The ShadowProperty can be made smarter so it optionally 
checks to see if the value changed and only then fire the handler but 
thats easy to do.  I'll likely do it.  I think this is a common enough 
use case this solves (the shadow getter/setter stuff) that this may be a 
worthy addition to traits.  Maybe it is already there somewhere?

(Continue reading)

Re: [Traits] dirty trait metadata

Prabhu Ramachandran wrote:
> This automatically builds the shadow _x trait and always calls back 
> _x_changed.  The ShadowProperty can be made smarter so it optionally 
> checks to see if the value changed and only then fire the handler but 
> thats easy to do.  I'll likely do it.  I think this is a common enough 

Now done with docs etc.  I'll check it in for the time being into mayavi 
somewhere (maybe e.mayavi.core.traits).

cheers,
prabhu

from enthought.traits.api import TraitType
from enthought.traits.traits import trait_cast
import numpy

##########################################################################
# `ShadowProperty` trait type.
##########################################################################
class ShadowProperty(TraitType):

    # Not really necessary but specifies the attribute up front.
    trait_type = None

    # Call the notifiers smartly only when the value has really changed.
    # If this is set to False, the notification will always occur.
    smart_notify = True

(Continue reading)

Robert Kern | 6 Sep 12:14

Re: [Traits] dirty trait metadata

On Sat, Sep 6, 2008 at 00:33, Prabhu Ramachandran
<prabhu@...> wrote:
> Robert Kern wrote:
>
>>> Is there a simple way of doing this?  I know that I could achieve this
>>> if I implemented x as a Property(Array) but is there an easier way?
>>
>> I don't think so. The comparison logic is in C
>> (ctraits.c:setattr_trait), and there are no hooks for this.
>>
>> If you only need coarse-grained notifications, you might consider
>> using an updated Event. This:
>
> OK, so I came up with a new trait type that does this nicely with minimal
> fuss and also does the validation right.

What's the use case again? For the one you demonstrated (notification
that an array's contents have changed), I don't think the
ShadowProperty semantics are particularly the obvious way to do issue
that notification.

--

-- 
Robert Kern

"I have come to believe that the whole world is an enigma, a harmless
enigma that is made terrible by our own mad attempt to interpret it as
though it had an underlying truth."
 -- Umberto Eco

Re: [Traits] dirty trait metadata

Robert Kern wrote:
> On Sat, Sep 6, 2008 at 00:33, Prabhu Ramachandran
> <prabhu@...> wrote:
>> Robert Kern wrote:
>>
>>>> Is there a simple way of doing this?  I know that I could achieve this
>>>> if I implemented x as a Property(Array) but is there an easier way?
>>> I don't think so. The comparison logic is in C
>>> (ctraits.c:setattr_trait), and there are no hooks for this.
>>>
>>> If you only need coarse-grained notifications, you might consider
>>> using an updated Event. This:
>> OK, so I came up with a new trait type that does this nicely with minimal
>> fuss and also does the validation right.
> 
> What's the use case again? For the one you demonstrated (notification
> that an array's contents have changed), I don't think the
> ShadowProperty semantics are particularly the obvious way to do issue
> that notification.

The use case is mayavi's mlab sources.  I'd like the user to be able to say

  obj.mlab_source.x = new_x

That new_x may be the same old x but updated.  I'd rather not have the 
user do obj.mlab_source.updated_x = True or whatever after that.  This 
really isn't about notification that an array's contents have changed. 
It is more of an API issue and a user convenience more than anything.

In any case, I've checked it into mayavi so it doesn't affect anyone and 
(Continue reading)

David C. Morrill | 10 Sep 23:05

Re: [Traits] dirty trait metadata

Prabhu:

I just added support for the new 'comparison_mode' metadata, which can 
(legally) have one of the three values:

    - NO_COMPARE: Change fired on every assignment.
    - OBJECT_IDENTITY_COMPARE: Change fired if old value is not the same 
object as the new value.
    - RICH_COMPARE: Change fired if old value does not compare equal to 
the new value (the standard traits default).

So you should now be able to implement your example by declaring:

class Data(HasTraits):
    x = Array( comparison_mode = NO_COMPARE )

Of course, if you intend to use a lot of these, you should probably do something like:

NCArray = Array( comparison_mode = NO_COMPARE )

class Data(HasTraits):
    x = NCArray
    y = NCArray
    ...

The old 'rich_compare' metadata is now deprecated in favor of the new 'comparison_mode' metadata. I've
modified the default Array trait definition to use comparison_mode = OBJECT_IDENTITY_COMPARE instead
of the old rich_compare = False.

Hope this helps...
(Continue reading)

Prabhu Ramachandran | 11 Sep 22:32

Re: [Traits] dirty trait metadata

David C. Morrill wrote:
> I just added support for the new 'comparison_mode' metadata, which can 
> (legally) have one of the three values:
> 
>     - NO_COMPARE: Change fired on every assignment.
>     - OBJECT_IDENTITY_COMPARE: Change fired if old value is not the same 
> object as the new value.
>     - RICH_COMPARE: Change fired if old value does not compare equal to 
> the new value (the standard traits default).

That is excellent, thanks!  It solves my particular problem.

However, the question about notification on properties remains.  If I 
were to define something like this:

class Data(HasTraits):
    x = Property(Float)

    def _set_x(self, val):
        old = self._x
        self._x = val
        self.trait_property_changed('x', old, val)

d = Data()

Then even if someone did d.set(x=1, trait_change_notify=False), you'd 
get a notification that x changed, right?  My patch "fixed" that perhaps 
incorrectly but the solution was clean and solved the above issue.  I'd 
like to know your thoughts on this.

(Continue reading)

David C. Morrill | 12 Sep 00:52

Re: [Traits] dirty trait metadata

Prabhu Ramachandran wrote:
> However, the question about notification on properties remains.  If I 
> were to define something like this:
>
> class Data(HasTraits):
>     x = Property(Float)
>
>     def _set_x(self, val):
>         old = self._x
>         self._x = val
>         self.trait_property_changed('x', old, val)
>
> d = Data()
>
> Then even if someone did d.set(x=1, trait_change_notify=False), you'd 
> get a notification that x changed, right?  My patch "fixed" that perhaps 
> incorrectly but the solution was clean and solved the above issue.  I'd 
> like to know your thoughts on this.
>
>   

Yes, I have not forgotten this, although it would serve you better if 
you wrote up a ticket (and attached your patch to that as well). I know 
you have trouble creating tickets, but it does make it more trackable. 
If you do, please put it in the Traits 3.0.3 milestone, since the 3.0.2 
milestone is pretty much in the bag.

I understand what you want to do, and I believe the core of your 
solution is valid. The only problem I have is folding it into the 
solution we already have (and which your example is not using).
(Continue reading)

Prabhu Ramachandran | 13 Sep 20:01

Re: [Traits] dirty trait metadata

David C. Morrill wrote:
> Yes, I have not forgotten this, although it would serve you better if 
> you wrote up a ticket (and attached your patch to that as well). I know 
> you have trouble creating tickets, but it does make it more trackable. 
> If you do, please put it in the Traits 3.0.3 milestone, since the 3.0.2 
> milestone is pretty much in the bag.
[...]
> I've been busy this week trying to clean up the last few bugs in the 
> Traits 3.0.2 release, but I'll try to work on this next week. In the 
> meantime, please submit the ticket :-)

Done in 1682.

Thanks!

cheers,
prabhu

Gmane