How to use in class (mimic traitlets)
fitoprincipe opened this issue · comments
Hi! I finally decided to have a try with spectate
, but I am having trouble migrating from traitlets
.
This is what I'd do in traitlets
from traitlets import List, HasTraits, observe
class TestTrait(HasTraits):
attr = List()
number = 1
@observe('attr')
def _ob_attr(self, change):
print('number is {}'.format(self.number))
print(change)
But of course this do not work with spectate
from spectate import mvc
class TestSpec(object):
attr = mvc.List()
number = 1
@mvc.view(attr)
def _ob_attr(attr, change):
# print('number is {}'.format(self.number)) # can't access self
print(change)
I read this but couldn't find the right path.
Thanks
@fitoprincipe sorry this took so long for me to get to.
Spectate isn't really meant to replicate the behavior of Traitlets. Instead it's mostly focused on tracking changes to mutable data types, so there's not a great way to do that with Spectate.
With that said, Spectate can actually be used with Traitlets. I've made a PR to that effect:
Here's a working implementation:
from spectate import mvc
from traitlets import TraitType, HasTraits, observe
class Mutable(TraitType):
"""A base class for mutable traits using Spectate"""
_model_type = None
_event_type = None
def instance_init(self, obj):
default = self._model_type()
@mvc.view(default)
def callback(default, events):
change = dict(
self._make_change(events),
name=self.name,
type=self._event_type,
)
obj.notify_change(change)
setattr(obj, self.name, default)
def _make_change(self, events):
raise NotImplementedError()
class MutableDict(Mutable):
"""A mutable dictionary trait"""
_model_type = mvc.Dict
_event_type = "item"
def _make_change(self, events):
change = {"old": {}, "new": {}}
for e in events:
change["new"][e.key] = e.new
change["old"][e.key] = e.old
return change
Here's a HasTraits
class that uses the mutable dict trait:
class MyHasTraitsClass(HasTraits):
attr = MutableDict()
@observe("attr", type="item")
def _on_attr_change(self, change):
print(change)
Here's an example usage:
>>> mhtc = MyHasTraitsClass()
>>> mhtc.attr["a"] = 1
{'old': {'a': Undefined}, 'new': {'a': 1}, 'name': 'attr', 'type': 'item'}
Thank you @rmorshea ! I didn't have time to test it, but I will as soon as I have some =)
Hey @rmorshea just wanted to let you know that I got it working :) Thanks for your work here!
My implementation was a little different though, because I'm using it with jupyter notebooks.
I'll leave this open until I close #37
This is now briefly documented: https://python-spectate.readthedocs.io/en/latest/usage/spectate-in-traitlets.html
Here's a working implementation:
from spectate import mvc from traitlets import TraitType, HasTraits, observe class Mutable(TraitType): """A base class for mutable traits using Spectate""" _model_type = None _event_type = None def instance_init(self, obj): default = self._model_type() @mvc.view(default) def callback(default, events): change = dict( self._make_change(events), name=self.name, type=self._event_type, ) obj.notify_change(change) setattr(obj, self.name, default) def _make_change(self, events): raise NotImplementedError() class MutableDict(Mutable): """A mutable dictionary trait""" _model_type = mvc.Dict _event_type = "item" def _make_change(self, events): change = {"old": {}, "new": {}} for e in events: change["new"][e.key] = e.new change["old"][e.key] = e.old return changeHere's a
HasTraits
class that uses the mutable dict trait:class MyHasTraitsClass(HasTraits): attr = MutableDict() @observe("attr", type="item") def _on_attr_change(self, change): print(change)Here's an example usage:
>>> mhtc = MyHasTraitsClass() >>> mhtc.attr["a"] = 1 {'old': {'a': Undefined}, 'new': {'a': 1}, 'name': 'attr', 'type': 'item'}
How would you go about doing this if you wanted to track changes to a list traitlet rather than dict trailet? In other words, how
would you implement a MutableList traitlet using spectate?
Maybe my code helps @trbedwards
https://github.com/cytoscape/ipycytoscape/blob/35842c0171b64c03296c8a7014b01f45c8dad43a/ipycytoscape/cytoscape.py#L130-L160
(I think) the same principle applies.
I think @marimeireles's suggestion is accurate. @trbedwards, assuming the same implementation style, you'll just want to make a subclass of Mutable
whose _model_type
is an mvc.List
@trbedwards let me know if this section of the documentation could use some improvement: https://python-spectate.readthedocs.io/en/latest/usage/spectate-in-traitlets.html