Ejemplo n.º 1
0
    def get(self, obj, cls=None):
        # Call notify_access with event type fetch
        # If and only if one event exists, a return value will be produced
        # This return value is saved as the current value in obj._trait_values
        # Then call super get
        try:
            r = obj.notify_access(
                T.Bunch(
                    name=self.name,
                    value=obj._trait_values[self.name],
                    owner=self,
                    type="fetch",
                ))

            old_value = obj._trait_values[self.name]

            if r is not None and r != old_value:
                logger.debug(
                    "Response from callback event 'fetch' on property {} does not match previous value. Overloading existing value {} with new value {}"
                    .format(self.name, old_value, r))
                obj._trait_values[self.name] = r
        except KeyError:
            pass

        return super().get(obj, cls=cls)
Ejemplo n.º 2
0
    def notify_access(self, bunch):
        if not isinstance(bunch, T.Bunch):
            # cast to bunch if given a dict
            bunch = T.Bunch(bunch)
        name, type = bunch.name, bunch.type

        callables = []
        callables.extend(self._trait_notifiers.get(name, {}).get(type, []))
        callables.extend(self._trait_notifiers.get(name, {}).get(T.All, []))
        callables.extend(self._trait_notifiers.get(T.All, {}).get(type, []))
        callables.extend(self._trait_notifiers.get(T.All, {}).get(T.All, []))

        # Call them all now
        # Traits catches and logs errors here.  I allow them to raise
        if len(callables) > 1:
            raise TypeError(
                "Maximum number of callables allowed for a single attribute using the 'fetch' event is 1. Please check the documentation of DiTTo"
            )
        for c in callables:
            # Bound methods have an additional 'self' argument.

            if isinstance(c, _CallbackWrapper):
                c = c.__call__
            elif isinstance(c, EventHandler) and c.name is not None:
                c = getattr(self, c.name)

            return c(bunch)
Ejemplo n.º 3
0
    def remove_traits(self, *names):
        "Remove traits that were dynamically added to the HasTraits instance"
        # Thanks to our guarantee from our `add_traits` that:
        # - `type(self)` is a singleton class and nobody else cares about it
        # - all relevant `TraitType`s are set on `type(self).__dict__` and nowhere else
        # to remove traits... we just delete them from `type(self)`. Pretty simple.
        if not names:
            return

        cls = type(self)
        for name in names:
            try:
                old = self._trait_values.pop(name)
            except KeyError:
                raise ValueError("The trait {} does not exist on {}".format(
                    name, self))
            delattr(cls, name)
            # to play by the rules (and make the map update on parameter deletion),
            # we notify that the trait is deleted. but `delete` is a non-standard
            # event, so don't expect anyone to be listening.
            self.notify_change(
                traitlets.Bunch(
                    name=name,
                    old=old,
                    new=traitlets.Undefined,
                    owner=self,
                    type="delete",
                ))
Ejemplo n.º 4
0
    def _on_change(self, change):
        self._notify_object.notify_change(
            traitlets.Bunch(change, name=self._notify_name,
                            key=change["name"]))
        # ^ NOTE(gabe): Bunch is workaround for traitlets bug https://github.com/ipython/traitlets/pull/536

        new_contents = self._make_widget_contents()
        self.widget.children = new_contents
Ejemplo n.º 5
0
    def remove_traits(self, *names):
        """
        Remove traits that were dynamically added to the HasTraits instance

        If you are manipulating a ParameterSet generated from a layer, instead
        use :meth:`update <descarteslabs.workflows.interactive.ParameterSet.update>`,
        which handles adding and removing traits in a more delclarative way.

        Example
        -------
        >>> import traitlets
        >>> import descarteslabs.workflows as wf
        >>> class Listener(traitlets.HasTraits):
        ...     @traitlets.observe("param")
        ...     def handler(self, change):
        ...         print(change['key'])
        ...         print(change)
        >>> listener = Listener()
        >>> ps = wf.interactive.ParameterSet(listener, "param", foo=traitlets.Float()) # doctest: +SKIP
        >>> ps.foo = 1.1 # doctest: +SKIP
        foo
        {'name': 'param',
         'old': 0.0,
         'new': 1.1,
         'owner': ParameterSet({'foo': 1.1}),
         'type': 'change',
         'key': 'foo'
         }
        >>> ps.add_traits(bar=traitlets.Unicode()) # doctest: +SKIP
        >>> ps.bar = 'quix' # doctest: +SKIP
        bar
        {'name': 'param',
         'old': '',
         'new': 'quix',
         'owner': ParameterSet({'bar': 'quix', 'foo': 1.1}),
         'type': 'change',
         'key': 'bar'
         }
        >>> ps.remove_traits("foo") # doctest: +SKIP
        >>> ps.foo = 2.2 # doctest: +SKIP
        >>> # ^ nothing is printed, `foo` is no longer a trait
        >>> ps.to_dict() # doctest: +SKIP
        {'bar': 'quix'}
        """
        # Thanks to our guarantee from our `add_traits` that:
        # - `type(self)` is a singleton class and nobody else cares about it
        # - all relevant `TraitType`s are set on `type(self).__dict__` and nowhere else
        # to remove traits... we just delete them from `type(self)`. Pretty simple.
        if not names:
            return

        cls = type(self)
        for name in names:
            try:
                old = self._trait_values.pop(name)
            except KeyError:
                raise ValueError("The trait {} does not exist on {}".format(
                    name, self))
            delattr(cls, name)
            # to play by the rules (and make the map update on parameter deletion),
            # we notify that the trait is deleted. but `delete` is a non-standard
            # event, so don't expect anyone to be listening.
            self.notify_change(
                traitlets.Bunch(
                    name=name,
                    old=old,
                    new=traitlets.Undefined,
                    owner=self,
                    type="delete",
                ))