Skip to content

Commit

Permalink
Merge b502b0e into 080b722
Browse files Browse the repository at this point in the history
  • Loading branch information
corranwebster committed Feb 7, 2018
2 parents 080b722 + b502b0e commit 3b704f7
Show file tree
Hide file tree
Showing 6 changed files with 155 additions and 57 deletions.
65 changes: 55 additions & 10 deletions traits/ctraits.c
Original file line number Diff line number Diff line change
Expand Up @@ -203,6 +203,51 @@ static int call_notifiers ( PyListObject *, PyListObject *,
notifications? */
#define TRAIT_NO_VALUE_TEST 0x00000100


/*-----------------------------------------------------------------------------
| Default value type constants (see `default_value_for` method)
+----------------------------------------------------------------------------*/

/* The default_value of the trait is the default value */
#define CONSTANT_DEFAULT_VALUE 0

/* The default_value of the trait is Missing */
#define MISSING_DEFAULT_VALUE 1

/* The object containing the trait is the default value */
#define OBJECT_DEFAULT_VALUE 2

/* A new copy of the list specified by default_value is the default value */
#define LIST_COPY_DEFAULT_VALUE 3

/* A new copy of the dict specified by default_value is the default value */
#define DICT_COPY_DEFAULT_VALUE 4

/* A new instance of TraitListObject constructed using the default_value list
is the default value */
#define TRAIT_LIST_OBJECT_DEFAULT_VALUE 5

/* A new instance of TraitDictObject constructed using the default_value dict
is the default value */
#define TRAIT_DICT_OBJECT_DEFAULT_VALUE 6

/* The default_value is a tuple of the form: (*callable*, *args*, *kw*),
where *callable* is a callable, *args* is a tuple, and *kw* is either a
dictionary or None. The default value is the result obtained by invoking
``callable(\*args, \*\*kw)`` */
#define CALLABLE_AND_ARGS_DEFAULT_VALUE 7

/* The default_value is a callable. The default value is the result obtained
by invoking *default_value*(*object*), where *object* is the object
containing the trait. If the trait has a validate() method, the validate()
method is also called to validate the result */
#define CALLABLE_DEFAULT_VALUE 8

/* A new instance of TraitSetObject constructed using the default_value set
is the default value */
#define TRAIT_SET_OBJECT_DEFAULT_VALUE 9


/*-----------------------------------------------------------------------------
| 'CTrait' instance definition:
+----------------------------------------------------------------------------*/
Expand Down Expand Up @@ -1606,36 +1651,36 @@ default_value_for ( trait_object * trait,
PyObject * result = NULL, * value, * dv, * kw, * tuple;

switch ( trait->default_value_type ) {
case 0:
case 1:
case CONSTANT_DEFAULT_VALUE:
case MISSING_DEFAULT_VALUE:
result = trait->default_value;
if (result == NULL) {
result = Py_None;
}
Py_INCREF( result );
break;
case 2:
case OBJECT_DEFAULT_VALUE:
result = (PyObject *) obj;
Py_INCREF( obj );
break;
case 3:
case LIST_COPY_DEFAULT_VALUE:
return PySequence_List( trait->default_value );
case 4:
case DICT_COPY_DEFAULT_VALUE:
return PyDict_Copy( trait->default_value );
case 5:
case TRAIT_LIST_OBJECT_DEFAULT_VALUE:
return call_class( TraitListObject, trait, obj, name,
trait->default_value );
case 6:
case TRAIT_DICT_OBJECT_DEFAULT_VALUE:
return call_class( TraitDictObject, trait, obj, name,
trait->default_value );
case 7:
case CALLABLE_AND_ARGS_DEFAULT_VALUE:
dv = trait->default_value;
kw = PyTuple_GET_ITEM( dv, 2 );
if ( kw == Py_None )
kw = NULL;
return PyObject_Call( PyTuple_GET_ITEM( dv, 0 ),
PyTuple_GET_ITEM( dv, 1 ), kw );
case 8:
case CALLABLE_DEFAULT_VALUE:
if ( (tuple = PyTuple_New( 1 )) == NULL )
return NULL;
PyTuple_SET_ITEM( tuple, 0, (PyObject *) obj );
Expand All @@ -1648,7 +1693,7 @@ default_value_for ( trait_object * trait,
return value;
}
break;
case 9:
case TRAIT_SET_OBJECT_DEFAULT_VALUE:
return call_class( TraitSetObject, trait, obj, name,
trait->default_value );
}
Expand Down
33 changes: 20 additions & 13 deletions traits/has_traits.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,9 @@
StaticAnyTraitChangeNotifyWrapper, StaticTraitChangeNotifyWrapper,
TraitChangeNotifyWrapper)

from .trait_handlers import TraitType
from .trait_handlers import (
TraitType, MISSING_DEFAULT_VALUE, TRAIT_LIST_OBJECT_DEFAULT_VALUE,
CALLABLE_DEFAULT_VALUE)

from .trait_base import (Missing, SequenceTypes, TraitsCache, Undefined,
add_article, is_none, not_event, not_false)
Expand Down Expand Up @@ -171,41 +173,41 @@ def _get_def ( class_name, class_dict, bases, method ):
"""
if method[0:2] == '__':
method = '_%s%s' % ( class_name, method )

result = class_dict.get( method )
if ((result is not None) and
is_function_type(result) and
(getattr( result, 'on_trait_change', None ) is None)):
return result

for base in bases:
result = getattr( base, method, None )
if ((result is not None) and
is_unbound_method_type(result) and \
(getattr( result, 'on_trait_change', None ) is None)):
return result

return None
else:
def _get_def ( class_name, class_dict, bases, method ):
""" Gets the definition of a specified method (if any).
"""
if method[0:2] == '__':
method = '_%s%s' % ( class_name, method )

result = class_dict.get( method )
if ((result is not None) and
is_function_type(result) and
(getattr( result, 'on_trait_change', None ) is None)):
return result

for base in bases:
result = getattr( base, method, None )
if ((result is not None) and
is_unbound_method_type(result) and \
(getattr( result.im_func, 'on_trait_change', None ) is None)):
return result

return None


Expand Down Expand Up @@ -588,13 +590,14 @@ def __init__ ( self, cls, class_name, bases, class_dict, is_category ):
class_traits[ name ] = value = ictrait( default_value )
# Make sure that the trait now has the default value
# has the correct initializer.
value.default_value(1, value.default)
value.default_value(
MISSING_DEFAULT_VALUE, value.default)
del class_dict[ name ]
override_bases = []
handler = value.handler
if (handler is not None) and handler.is_mapped:
class_traits[ name + '_' ] = _mapped_trait_for(
value )
value )
break

# Process all HasTraits base classes:
Expand Down Expand Up @@ -730,7 +733,7 @@ def __init__ ( self, cls, class_name, bases, class_dict, is_category ):
_add_notifiers( trait._notifiers( 1 ), handlers )

if default is not None:
trait.default_value( 8, default )
trait.default_value(CALLABLE_DEFAULT_VALUE, default)

# Handle the case of properties whose value depends upon the value
# of other traits:
Expand Down Expand Up @@ -2191,7 +2194,7 @@ def class_editable_traits ( cls ):
return names

class_editable_traits = classmethod( class_editable_traits )

def visible_traits ( self ):
"""Returns an alphabetically sorted list of the names of non-event
trait attributes associated with the current object, that should be GUI visible
Expand Down Expand Up @@ -2741,7 +2744,11 @@ def _sync_trait_items_modified ( self, object, name, old, event ):
def _is_list_trait ( self, trait_name ):
handler = self.base_trait( trait_name ).handler

return ((handler is not None) and (handler.default_value_type == 5))
return (
(handler is not None)
and
(handler.default_value_type == TRAIT_LIST_OBJECT_DEFAULT_VALUE)
)

#---------------------------------------------------------------------------
# Add a new trait:
Expand Down Expand Up @@ -2971,7 +2978,7 @@ def traits ( self, **metadata ):
values of all keywords to be included in the result.
"""
traits = self.__base_traits__.copy()

# Update with instance-defined traits.
for name, trt in self._instance_traits().items():
if name[-6:] != "_items":
Expand Down
65 changes: 50 additions & 15 deletions traits/trait_handlers.py
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,41 @@

CallableTypes = ( FunctionType, MethodType )


#: Default value types
#: The default value type has not been specified
UNSPECIFIED_DEFAULT_VALUE = -1
#: The default_value of the trait is the default value.
CONSTANT_DEFAULT_VALUE = 0
#: The default_value of the trait is Missing.
MISSING_DEFAULT_VALUE = 1
#: The object containing the trait is the default value.
OBJECT_DEFAULT_VALUE = 2
#: A new copy of the list specified by default_value is the default value.
LIST_COPY_DEFAULT_VALUE = 3
#: A new copy of the dict specified by default_value is the default value.
DICT_COPY_DEFAULT_VALUE = 4
#: A new instance of TraitListObject constructed using the default_value list
#: is the default value.
TRAIT_LIST_OBJECT_DEFAULT_VALUE = 5
#: A new instance of TraitDictObject constructed using the default_value dict
#: is the default value.
TRAIT_DICT_OBJECT_DEFAULT_VALUE = 6
#: The default_value is a tuple of the form: (*callable*, *args*, *kw*),
#: where *callable* is a callable, *args* is a tuple, and *kw* is either a
#: dictionary or None. The default value is the result obtained by invoking
#: ``callable(\*args, \*\*kw)``.
CALLABLE_AND_ARGS_DEFAULT_VALUE = 7
#: The default_value is a callable. The default value is the result obtained
#: by invoking *default_value*(*object*), where *object* is the object
#: containing the trait. If the trait has a validate() method, the validate()
#: method is also called to validate the result.
CALLABLE_DEFAULT_VALUE = 8
#: A new instance of TraitSetObject constructed using the default_value set
#: is the default value.
TRAIT_SET_OBJECT_DEFAULT_VALUE = 9


# Mapping from trait metadata 'type' to CTrait 'type':
trait_types = {
'python': 1,
Expand Down Expand Up @@ -132,7 +167,7 @@ class BaseTraitHandler ( object ):
wider range of cases, such as interactions with other components.
"""

default_value_type = -1
default_value_type = UNSPECIFIED_DEFAULT_VALUE
has_items = False
is_mapped = False
editor = None
Expand Down Expand Up @@ -453,21 +488,21 @@ def get_default_value ( self ):
dv = self.default_value
dvt = self.default_value_type
if dvt < 0:
dvt = 0
if isinstance( dv, TraitListObject ):
dvt = 5
elif isinstance( dv, list ):
dvt = 3
elif isinstance( dv, TraitDictObject ):
dvt = 6
elif isinstance( dv, dict ):
dvt = 4
elif isinstance( dv, TraitSetObject ):
dvt = 9
dvt = CONSTANT_DEFAULT_VALUE
if isinstance(dv, TraitListObject):
dvt = TRAIT_LIST_OBJECT_DEFAULT_VALUE
elif isinstance(dv, list):
dvt = LIST_COPY_DEFAULT_VALUE
elif isinstance(dv, TraitDictObject):
dvt = TRAIT_DICT_OBJECT_DEFAULT_VALUE
elif isinstance(dv, dict):
dvt = DICT_COPY_DEFAULT_VALUE
elif isinstance(dv, TraitSetObject):
dvt = TRAIT_SET_OBJECT_DEFAULT_VALUE

self.default_value_type = dvt

return ( dvt, dv )
return (dvt, dv)

def clone ( self, default_value = Missing, **metadata ):
""" Clones the contents of this object into a new instance of the same
Expand Down Expand Up @@ -2177,7 +2212,7 @@ class Hand(HasTraits):
list.
"""
info_trait = None
default_value_type = 5
default_value_type = TRAIT_LIST_OBJECT_DEFAULT_VALUE
_items_event = None

def __init__ ( self, trait = None, minlen = 0, maxlen = sys.maxint,
Expand Down Expand Up @@ -2966,7 +3001,7 @@ class WorkoutClass(HasTraits):
be floats (i.e., their most recently recorded weight).
"""
info_trait = None
default_value_type = 6
default_value_type = TRAIT_DICT_OBJECT_DEFAULT_VALUE
_items_event = None

def __init__ ( self, key_trait = None, value_trait = None,
Expand Down

0 comments on commit 3b704f7

Please sign in to comment.