#------------------------------------------------------------------------------
#
# Copyright (c) 2008, Enthought, Inc.
# All rights reserved.
#
# This software is provided without warranty under the terms of the BSD
# license included in enthought/LICENSE.txt and may be redistributed only
# under the conditions described in the aforementioned license. The license
# is also available online at http://www.enthought.com/licenses/BSD.txt
#
# Thanks for using Enthought open source!
#
# Author: David C. Morrill
# Original Date: 04/01/2008
#
#------------------------------------------------------------------------------
""" Defines the TraitValue class, used for creating special, dynamic trait
values.
"""
#-------------------------------------------------------------------------------
# Imports:
#-------------------------------------------------------------------------------
from __future__ import absolute_import
from .trait_base import Undefined
from .traits import CTrait
from .has_traits import HasTraits, HasPrivateTraits
from .trait_errors import TraitError
from .trait_types import Tuple, Dict, Any, Str, Instance, Event, Callable
from .trait_handlers import TraitType, _read_only, _write_only, _arg_count
#-------------------------------------------------------------------------------
# 'BaseTraitValue' class:
#-------------------------------------------------------------------------------
[docs]class BaseTraitValue ( HasPrivateTraits ):
# Subclasses can define this trait as a property:
# value = Property
#-- Public Methods ---------------------------------------------------------
[docs] def as_ctrait ( self, original_trait ):
""" Returns the low-level C-based trait for this TraitValue.
"""
notifiers = original_trait._notifiers( 0 )
if self._ctrait is not None:
if (notifiers is None) or (len( notifiers ) == 0):
return self._ctrait
trait = CTrait( 0 )
trait.clone( self._ctrait )
else:
trait = self._as_ctrait( original_trait )
if ((trait is not None) and
(notifiers is not None) and
(len( notifiers ) > 0)):
trait._notifiers( 1 ).extend( notifiers )
return trait
#-- Private Methods --------------------------------------------------------
def _as_ctrait ( self, original_trait ):
""" Returns the low-level C-based trait for this TraitValue.
"""
value_trait = self.trait( 'value' )
if value_trait is None:
return None
if value_trait.type != 'property':
raise TraitError( "Invalid TraitValue specified." )
metadata = { 'type': 'property',
'_trait_value': self }
getter, setter, validate = value_trait.property()
read_only = (getter is _read_only)
if not read_only:
getter = self._getter
metadata[ 'transient' ] = True
if setter is not _write_only:
if read_only:
setter = self._read_only_setter
else:
setter = self._setter
metadata[ 'transient' ] = True
return self._property_trait( getter, setter, validate, metadata )
def _property_trait ( self, getter, setter, validate, metadata ):
""" Returns a properly constructed 'property' trait.
"""
n = 0
if validate is not None:
n = _arg_count( validate )
trait = CTrait( 4 )
trait.property( getter, _arg_count( getter ),
setter, _arg_count( setter ),
validate, n )
trait.value_allowed( True )
trait.value_property( True )
trait.__dict__ = metadata
return trait
def _getter ( self, object, name ):
return self.value
def _setter ( self, object, name, value ):
old_value = self.value
self.value = value
new_value = self.value
if new_value != old_value:
object.trait_property_changed( name, old_value, new_value )
def _read_only_setter ( self, object, name, value ):
self.value = value
object.trait_property_changed( name, Undefined, value )
#-------------------------------------------------------------------------------
# 'TraitValue' class:
#-------------------------------------------------------------------------------
[docs]class TraitValue ( BaseTraitValue ):
#: The callable used to define a default value:
default = Callable
#: The positional arguments to pass to the callable default value:
args = Tuple
#: The keyword arguments to pass to the callable default value:
kw = Dict
#: The trait to use as the new trait type:
type = Any
#: The object to delegate the new value to:
delegate = Instance( HasTraits )
#: The name of the trait on the delegate object to get the new value from:
name = Str
#-- Private Methods --------------------------------------------------------
def _as_ctrait ( self, original_trait ):
""" Returns the low-level C-based trait for this TraitValue.
"""
if self.default is not None:
trait = CTrait( 0 )
trait.clone( original_trait )
if original_trait.__dict__ is not None:
trait.__dict__ = original_trait.__dict__.copy()
trait.default_value( 7, ( self.default, self.args, self.kw ) )
elif self.type is not None:
type = self.type
try:
rc = issubclass( type, TraitType )
except:
rc = False
if rc:
type = type( *self.args, **self.kw )
if not isinstance( type, TraitType ):
raise TraitError( ("The 'type' attribute of a TraitValue "
"instance must be a TraitType instance or subclass, but a "
"value of %s was specified.") % self.trait )
self._ctrait = trait = type.as_ctrait()
trait.value_allowed( True )
elif self.delegate is None:
return None
else:
if self.name == '':
raise TraitError( "You must specify a non-empty string "
"value for the 'name' attribute when using the "
"'delegate' trait of a TraitValue instance." )
metadata = { 'type': 'property',
'_trait_value': self,
'transient': True }
getter = self._delegate_getter
setter = self._delegate_setter
validate = None
self.add_trait( 'value', Event() )
self.delegate.on_trait_change( self._delegate_modified, self.name )
trait = self._property_trait( getter, setter, validate, metadata )
return trait
def _delegate_getter ( self, object, name ):
return getattr( self.delegate, self.name )
def _delegate_setter ( self, object, name, value ):
setattr( self.delegate, self.name, value )
#-- Traits Event Handlers --------------------------------------------------
def _delegate_modified ( self ):
self.value = True
#-- Helper Function Definitions ------------------------------------------------
[docs]def SyncValue ( delegate, name ):
return TraitValue( delegate = delegate, name = name )
[docs]def TypeValue ( type ):
return TraitValue( type = type )
[docs]def DefaultValue ( default, args = (), kw = {} ):
return TraitValue( default = default, args = args, kw = kw )
#-------------------------------------------------------------------------------
# Tell the C-based traits module about the 'BaseTraitValue' class:
#-------------------------------------------------------------------------------
from . import ctraits
ctraits._value_class( BaseTraitValue )