[traits] probably a trivial question..

classic Classic list List threaded Threaded
9 messages Options
Reply | Threaded
Open this post in threaded view
|

[traits] probably a trivial question..

Pearu Peterson
Hi,

I have a trait definition

  data = Dict

  def _data_changed(self):
    ...

where data is a dictionary with, say, list values.
When changing the list values directly, say, appending an item to a list,
it seems that the _data_changed is not called. So my question is: how to
trigger a data change event when modifying the content of a mutable data object?

Thanks,
Pearu
_______________________________________________
Enthought-Dev mailing list
[hidden email]
https://mail.enthought.com/mailman/listinfo/enthought-dev
Reply | Threaded
Open this post in threaded view
|

Re: [traits] probably a trivial question..

Peter Wang
On Thu, Dec 9, 2010 at 8:50 AM, Pearu Peterson <[hidden email]> wrote:

> Hi,
> I have a trait definition
>  data = Dict
>  def _data_changed(self):
>    ...
>
> where data is a dictionary with, say, list values.
> When changing the list values directly, say, appending an item to a list,
> it seems that the _data_changed is not called. So my question is: how to
> trigger a data change event when modifying the content of a mutable data object?

def _data_items_changed(self, event):
  # event is a dict with keys "added", "changed", "removed"

Note that if you use the @on_trait_change("data") decorator, it
automatically notifies when items change or when the entire dict is
replaced as a whole.

-Peter
_______________________________________________
Enthought-Dev mailing list
[hidden email]
https://mail.enthought.com/mailman/listinfo/enthought-dev
Reply | Threaded
Open this post in threaded view
|

Re: [traits] probably a trivial question..

Corran Webster


On Thu, Dec 9, 2010 at 8:55 AM, Peter Wang <[hidden email]> wrote:
On Thu, Dec 9, 2010 at 8:50 AM, Pearu Peterson <[hidden email]> wrote:
Note that if you use the @on_trait_change("data") decorator, it
automatically notifies when items change or when the entire dict is
replaced as a whole.

I think it only fires for whole object replacement, not item changes:

In [1]: from enthought.traits.api import HasTraits, Dict, on_trait_change

In [2]: class Foo(HasTraits):
   ...:     d = Dict()
   ...:     c = Dict()
   ...:     def _c_items_changed(self, old, new):
   ...:         print 'c', old, new
   ...:     @on_trait_change('d')
   ...:     def d_change(self, old, new):
   ...:         print 'd', old, new
   ...:

In [3]: f = Foo()

In [4]: f.c
Out[4]: {}

In [5]: f.c['a'] = 5
c <undefined> <enthought.traits.trait_handlers.TraitDictEvent object at 0x12bc510>

In [6]: f.d['a'] = 5

Using @on_trait_change('d[]') doesn't work either.  This is probably a bug/misfeature.

-- Corran

_______________________________________________
Enthought-Dev mailing list
[hidden email]
https://mail.enthought.com/mailman/listinfo/enthought-dev
Reply | Threaded
Open this post in threaded view
|

Re: [traits] probably a trivial question..

Robert Kern
In reply to this post by Peter Wang
On Thu, Dec 9, 2010 at 8:55 AM, Peter Wang <[hidden email]> wrote:

> On Thu, Dec 9, 2010 at 8:50 AM, Pearu Peterson <[hidden email]> wrote:
>> Hi,
>> I have a trait definition
>>  data = Dict
>>  def _data_changed(self):
>>    ...
>>
>> where data is a dictionary with, say, list values.
>> When changing the list values directly, say, appending an item to a list,
>> it seems that the _data_changed is not called. So my question is: how to
>> trigger a data change event when modifying the content of a mutable data object?
>
> def _data_items_changed(self, event):
>  # event is a dict with keys "added", "changed", "removed"
>
> Note that if you use the @on_trait_change("data") decorator, it
> automatically notifies when items change or when the entire dict is
> replaced as a whole.

No, it doesn't. You still need @on_trait_change("data,data_items").

--
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
_______________________________________________
Enthought-Dev mailing list
[hidden email]
https://mail.enthought.com/mailman/listinfo/enthought-dev
Reply | Threaded
Open this post in threaded view
|

Re: [traits] probably a trivial question..

bryce hendrix-2
In reply to this post by Corran Webster
You have to declare your function with the right signature in order to get dict events.

This page details what the signature is supposed to be:

This page details the syntax of the decorator:

On Thu, Dec 9, 2010 at 9:29 AM, Corran Webster <[hidden email]> wrote:


On Thu, Dec 9, 2010 at 8:55 AM, Peter Wang <[hidden email]> wrote:
On Thu, Dec 9, 2010 at 8:50 AM, Pearu Peterson <[hidden email]> wrote:
Note that if you use the @on_trait_change("data") decorator, it
automatically notifies when items change or when the entire dict is
replaced as a whole.

I think it only fires for whole object replacement, not item changes:

In [1]: from enthought.traits.api import HasTraits, Dict, on_trait_change

In [2]: class Foo(HasTraits):
   ...:     d = Dict()
   ...:     c = Dict()
   ...:     def _c_items_changed(self, old, new):
   ...:         print 'c', old, new
   ...:     @on_trait_change('d')
   ...:     def d_change(self, old, new):
   ...:         print 'd', old, new
   ...:

In [3]: f = Foo()

In [4]: f.c
Out[4]: {}

In [5]: f.c['a'] = 5
c <undefined> <enthought.traits.trait_handlers.TraitDictEvent object at 0x12bc510>

In [6]: f.d['a'] = 5

Using @on_trait_change('d[]') doesn't work either.  This is probably a bug/misfeature.

-- Corran

_______________________________________________
Enthought-Dev mailing list
[hidden email]
https://mail.enthought.com/mailman/listinfo/enthought-dev



_______________________________________________
Enthought-Dev mailing list
[hidden email]
https://mail.enthought.com/mailman/listinfo/enthought-dev
Reply | Threaded
Open this post in threaded view
|

Re: [traits] probably a trivial question..

Peter Wang
In reply to this post by Robert Kern
On Thu, Dec 9, 2010 at 9:43 AM, Robert Kern <[hidden email]> wrote:
>> Note that if you use the @on_trait_change("data") decorator, it
>> automatically notifies when items change or when the entire dict is
>> replaced as a whole.
>
> No, it doesn't. You still need @on_trait_change("data,data_items").

You're right, I was thinking of List traits and the [] naming
protocol.  Apologies, Pearu!

-Peter
_______________________________________________
Enthought-Dev mailing list
[hidden email]
https://mail.enthought.com/mailman/listinfo/enthought-dev
Reply | Threaded
Open this post in threaded view
|

Re: [traits] probably a trivial question..

Pearu Peterson
Thanks all, for the suggestions!
However, my situations is a little more subtle.
Here's a simple example:

# test.py
from enthought.traits.api import HasStrictTraits, Dict, on_trait_change

class Foo (HasStrictTraits):

    d = Dict

    @on_trait_change('d, d_items')
    def bar(self):
        print 'bar:',self.d

foo = Foo(d = dict(l = [1,2]))

for line in '''\
foo.d = {}
foo.d['l1'] = [3,4]
foo.d['l1'].append(5)
'''.splitlines ():
    print 'Executing line %r:' % (line)
    exec (line)
    print
print 'end'
# eof

Running the script test.py, I get the following output:

bar: {'l': [1, 2]}
Executing line 'foo.d = {}':
bar: {}

Executing line "foo.d['l1'] = [3,4]":
bar: {'l1': [3, 4]}

Executing line "foo.d['l1'].append(5)":

end

The last execution illustrates my problem: the dictionary item is
changed but the bar method is not called.
I would be happy if I could send some notification event to traits
saying that the dictionary d has changed
after the append call. Is this possible?

Btw, a similar problem arises when using Array trait and some code
changes the array in-place. It would
be nice if the corresponding code could send a change notification
event to traits.

Thanks,
Pearu
_______________________________________________
Enthought-Dev mailing list
[hidden email]
https://mail.enthought.com/mailman/listinfo/enthought-dev
Reply | Threaded
Open this post in threaded view
|

Re: [traits] probably a trivial question..

Pearu Peterson
Reading the traits sources, I found that trait_property_changed method
solves the problem:

  foo.trait_property_changed('d', foo.d)

will call the change notifiers.

I wonder if the old_value argument in trait_property_changed could be
made optional as well.

Best regards,
Pearu

On Fri, Dec 10, 2010 at 11:24 AM, Pearu Peterson
<[hidden email]> wrote:

> Thanks all, for the suggestions!
> However, my situations is a little more subtle.
> Here's a simple example:
>
> # test.py
> from enthought.traits.api import HasStrictTraits, Dict, on_trait_change
>
> class Foo (HasStrictTraits):
>
>    d = Dict
>
>    @on_trait_change('d, d_items')
>    def bar(self):
>        print 'bar:',self.d
>
> foo = Foo(d = dict(l = [1,2]))
>
> for line in '''\
> foo.d = {}
> foo.d['l1'] = [3,4]
> foo.d['l1'].append(5)
> '''.splitlines ():
>    print 'Executing line %r:' % (line)
>    exec (line)
>    print
> print 'end'
> # eof
>
> Running the script test.py, I get the following output:
>
> bar: {'l': [1, 2]}
> Executing line 'foo.d = {}':
> bar: {}
>
> Executing line "foo.d['l1'] = [3,4]":
> bar: {'l1': [3, 4]}
>
> Executing line "foo.d['l1'].append(5)":
>
> end
>
> The last execution illustrates my problem: the dictionary item is
> changed but the bar method is not called.
> I would be happy if I could send some notification event to traits
> saying that the dictionary d has changed
> after the append call. Is this possible?
>
> Btw, a similar problem arises when using Array trait and some code
> changes the array in-place. It would
> be nice if the corresponding code could send a change notification
> event to traits.
>
> Thanks,
> Pearu
>
_______________________________________________
Enthought-Dev mailing list
[hidden email]
https://mail.enthought.com/mailman/listinfo/enthought-dev
Reply | Threaded
Open this post in threaded view
|

Re: [traits] probably a trivial question..

Pearu Peterson
On Fri, Dec 10, 2010 at 12:27 PM, Pearu Peterson
<[hidden email]> wrote:
> Reading the traits sources, I found that trait_property_changed method
> solves the problem:
>
>  foo.trait_property_changed('d', foo.d)

foo.trait_property_changed('d', None)

works too.

Pearu
_______________________________________________
Enthought-Dev mailing list
[hidden email]
https://mail.enthought.com/mailman/listinfo/enthought-dev