6 Sep 08:01
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
def __init__(self, trait_type, **metadata):
"""Defines a shadow property trait that is best explained by
example::
class Thing(HasTraits):
x = ShadowProperty(Float, smart_notify=False)
def _x_changed(self, value):
print value
In this example, the actual value of the property (`x`) will be
stored in `_x` and `_x_changed` will be called regardless
whether the value actually changed or not. If `smart_notify` is
set to `True` then the handler is called only if the value has
actually changed.
Note that the validation uses the validation of the specified
`trait_type` parameter.
"""
self.trait_type = trait_cast(trait_type)
if 'smart_notify' in metadata:
self.smart_notify = metadata.pop('smart_notify')
super(ShadowProperty, self).__init__(**metadata)
def validate(self, object, name, value):
"""Validates that a specified value is valid for this trait.
"""
trt = self.trait_type
if trt is not None and hasattr(trt, 'validate'):
value = trt.validate(object, name, value)
return value
def get(self, object, name):
"""Get the value of the trait."""
shadow = self._get_shadow(name)
d = object.__dict__
if shadow in d:
return d[shadow]
else:
return None
def set(self, object, name, value):
"""Set the value of the trait."""
old = self.get(object, name)
shadow = self._get_shadow(name)
object.__dict__[shadow] = value
# Fire a trait property changed.
fire = True
if self.smart_notify:
if old is value:
fire = False
if fire:
object.trait_property_changed(name, old, value)
def _get_shadow(self, name):
"""Get the shadow attribute name to use."""
return '_' + name
# -------------- test --------------------
from enthought.traits.api import HasTraits, Either, Array, Any, TraitError
import unittest
ArrayOrNone = Either(None, Array)
class DataNotSmart(HasTraits):
x = ShadowProperty(ArrayOrNone, smart_notify=False)
# Test attribute.
_test = Any
def _x_changed(self, value):
self._test = value.copy()
class DataSmart(HasTraits):
x = ShadowProperty(ArrayOrNone, smart_notify=True)
# Test attribute.
_test = Any
def _x_changed(self, value):
self._test = value.copy()
class TestShadowProperty(unittest.TestCase):
def test_shadow_property_smart(self):
"Test if the shadow property trait type works correctly."
x = numpy.linspace(0, 1)
d = DataSmart(x=x)
self.assertEqual(numpy.all(d.x == x), True)
self.assertEqual(numpy.all(d._x == x), True)
self.assertEqual(numpy.all(d._test == x), True)
old = x.copy()
x *= 2
d.x = x
self.assertEqual(numpy.all(d.x == x), True)
self.assertEqual(numpy.all(d._x == x), True)
# Notifier shouldn't be called.
self.assertEqual(numpy.all(d._test == old), True)
def test_shadow_property_not_smart(self):
"Test if the shadow property trait type works correctly."
x = numpy.linspace(0, 1)
d = DataNotSmart(x=x)
self.assertEqual(numpy.all(d.x == x), True)
self.assertEqual(numpy.all(d._x == x), True)
self.assertEqual(numpy.all(d._test == x), True)
x *= 2
d.x = x
self.assertEqual(numpy.all(d.x == x), True)
self.assertEqual(numpy.all(d._x == x), True)
self.assertEqual(numpy.all(d._test == x), True)
def test_type_checking(self):
"Test if the validation works correctly."
x = numpy.linspace(0, 1)
d = DataNotSmart(x=x)
self.assertRaises(TraitError, d.__setattr__, 'x', 'hey')
if __name__ == '__main__':
unittest.main()
_______________________________________________ Enthought-dev mailing list Enthought-dev@... https://mail.enthought.com/mailman/listinfo/enthought-dev
RSS Feed