I am working through the traits
presentation from PyCon 2010. At about 2:30:45 the presenter starts covering trait event notifications, which allow (among other things) the ability to automatically call a subroutine any time a trait
has changed.
I am running a modified copy of the example he gave... In this trial, I am trying to see whether I can fire a static event whenever I make a change to volume
or volume_inputs
.
# Filename: spinaltap.py
from traits.api import HasTraits, Range, List, Float
import traits
class Amplifier(HasTraits):
"""
Define an Amplifier (ref -> Spinal Tap) with Enthought's traits. Use traits
to enforce values boundaries on the Amplifier's attributes. Use events to
notify via the console when the volume trait is changed and when new volume
traits are added to inputs.
"""
# Define a volume trait as a Float between 0.0 and 11.0 (inclusive)
# see self._volume_changed()
volume = Range(value=5.0, trait=Float, low=0.0, high=11.0)
# Define an inputs trait as a List() containing volume traits
volume_inputs = List(volume) # <-- fire a static trait notification
# when another volume element is added
# see self._volume_inputs_changed()
def __init__(self, volume=5.0):
super(Amplifier, self).__init__()
self.volume = volume
self.volume_inputs.append(volume)
def _volume_changed(self, old, new):
# This is a static event listener for self.volume
# ^^^^^^^^^^^
if not (new in self.inputs):
self.inputs.append(self.volume)
if new == 11.0:
print("This one goes to eleven... so far, we have seen", self.inputs)
def _volume_inputs_changed(self, old, new):
# This is a static event listener for self.volume_inputs
# ^^^^^^^^^^^^^^^^^^
print("Check it out!!")
if __name__=='__main__':
spinal_tap = Amplifier()
candidate_volume = 4.0
spinal_tap.event_fired = False
print("- INITIAL_VALUE var volume_inputs = {}".format(spinal_tap.volume_inputs))
print("- APPEND a new volume of 4.0")
print(" - volume_inputs = {} # BEGIN".format(spinal_tap.volume_inputs))
print(" - volume_inputs.append({})".format(candidate_volume))
spinal_tap.volume_inputs.append(candidate_volume)
print(" - volume_inputs: {} # END".format(spinal_tap.volume_inputs))
if spinal_tap.event_fired is False:
print(" - Test FAILED: Traits did not fire _volume_inputs_changed()")
else:
print(" - Test PASSED: Traits fired _volume_inputs_changed()")
try:
spinal_tap.event_fired = False
print("- NEGATIVE Test... try to append 12.0. This should fail; 12.0 is out of bounds")
print(" - volume_inputs: {} # BEGIN".format(spinal_tap.volume_inputs))
candidate_volume = 12.0
print(" - volume_inputs.append({})".format(candidate_volume))
spinal_tap.volume_inputs.append(candidate_volume)
print(" - volume_inputs: {} # END".format(spinal_tap.volume_inputs))
if spinal_tap.event_fired is False:
print(" - Test FAILED: Traits did not fire _volume_inputs_changed()")
except traits.trait_errors.TraitError:
print(" - TraitError raised --> HERE <--")
print(" - volume_inputs: {} # END".format(spinal_tap.volume_inputs))
print(" - Test PASSED: traits correctly raised TraitError instead of appending {}.".format(candidate_volume))
Problem -> I never see any events from _volume_inputs_changed()
. No matter what example I cook up, I can't get a List
to fire an event.
In the output below, there is no evidence that _volume_inputs_changed()
ever fires.
[mpenning@Bucksnort ~]$ python spinaltap.py
- INITIAL_VALUE var volume_inputs = [5.0]
- APPEND a new volume of 4.0
- volume_inputs = [5.0] # BEGIN
- volume_inputs.append(4.0)
- volume_inputs: [5.0, 4.0] # END
- Test FAILED: Traits did not fire _volume_inputs_changed()
- NEGATIVE Test... try to append 12.0. This should fail; 12.0 is out of bounds
- volume_inputs: [5.0, 4.0] # BEGIN
- volume_inputs.append(12.0)
- TraitError raised --> HERE <--
- volume_inputs: [5.0, 4.0] # END
- Test PASSED: traits correctly raised TraitError instead of appending 12.0.
[mpenning@Bucksnort ~]$
Should a List()
be able to fire a static List()
event (such as _inputs_changed()
) when using traits? If so, am I doing something wrong?