Skip to content

notify on default creation#383

Merged
minrk merged 2 commits intoipython:masterfrom
rmorshea:notify_default
Mar 28, 2017
Merged

notify on default creation#383
minrk merged 2 commits intoipython:masterfrom
rmorshea:notify_default

Conversation

@rmorshea
Copy link
Copy Markdown
Contributor

@rmorshea rmorshea commented Mar 22, 2017

Summary

Notify upon the creation of a default value. The current scheme for this event report is:

{
    'name': <the trait's name>,
    'owner': <it's HasTraits object>,
    'value': <default value>
    'type': 'default',
}

A Possible Use Case

A @go_between decorator that effectively turns traits into properties, but still has the added benefits of traitlets validation.

import functools
from traitlets import *


def go_between(public, proxy):
    return GoBetween(public, proxy)


class GoBetween(DefaultHandler):

    def __init__(self, public, proxy):
        super(GoBetween, self).__init__(public)
        self.proxy = proxy

    def _init_call(self, func):
        @functools.wraps(func)
        def wrapper(owner):
            if not hasattr(owner, self.proxy):
                # Solely in order to assign a default value to the proxy
                # trait as would be expected of the public one were there
                # no go between applied to it.
                default = getattr(type(owner), self.trait_name).default()
                setattr(owner, self.proxy, default)
            return func(owner)
        self.func = wrapper
        return self

    def instance_init(self, obj):
        # reset the value after a default is generated
        # and after a new value is assigned.
        obj.observe(self._reset, self.trait_name, "change")
        obj.observe(self._reset, self.trait_name, "default")

    def _reset(self, data):
        try:
            # delete the value which is currently present
            # doing so will cause the default generator to
            # be called again.
            del data.owner._trait_values[data.name]
        except:
            pass
        else:
            if hasattr(data, "new"):
                # the data is a change notification and
                # we assign the new value to a proxy trait
                # which was specified in the decorator.
                setattr(data.owner, self.proxy, data.new)
            # otherwise it was a default notification
            # and we don't need to worry about it


class Foo(HasTraits):
    bar = Int()

    @go_between("bar", "_bar")
    def access_bar(self):
        return self._bar + 5

f = Foo()

print(f.bar)
f.bar = 10
print(f.bar)

@minrk minrk added this to the 5.0 milestone Mar 24, 2017
@minrk minrk merged commit 79c2551 into ipython:master Mar 28, 2017
@minrk
Copy link
Copy Markdown
Member

minrk commented Aug 10, 2017

This has broken widgets because it calls notify_change with events that are not change events. We either need to ensure that these events are supersets of change events, or trigger a different call that notify_change

@Carreau Carreau added 5.0-re-review Need to re-review for potential API impact changes. 5.0-minor rereviewed, minor change need to be put in changelog. and removed 5.0-re-review Need to re-review for potential API impact changes. labels Jun 4, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

5.0-minor rereviewed, minor change need to be put in changelog.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants