diff --git a/docs/source/traits_api_reference/trait_types.rst b/docs/source/traits_api_reference/trait_types.rst index ab2ecb52b..491f1ffce 100644 --- a/docs/source/traits_api_reference/trait_types.rst +++ b/docs/source/traits_api_reference/trait_types.rst @@ -238,10 +238,11 @@ Traits .. autoclass:: ToolbarButton :show-inheritance: -.. autoclass:: Either +.. autoclass:: Union :show-inheritance: -.. autoclass:: Union +.. autoclass:: Either + :show-inheritance: .. autoclass:: Symbol :show-inheritance: diff --git a/docs/source/traits_user_manual/defining.rst b/docs/source/traits_user_manual/defining.rst index 9eee0ffce..d4afaa0fd 100644 --- a/docs/source/traits_user_manual/defining.rst +++ b/docs/source/traits_user_manual/defining.rst @@ -130,7 +130,7 @@ pass it as an argument to the trait:: account_balance = Float(10.0) -Most predefined traits are callable, [2]_ and can accept a default value and +Most predefined traits are callable [1]_, and can accept a default value and possibly other arguments; all that are callable can also accept metadata as keyword arguments. (See :ref:`other-predefined-traits` for information on trait signatures, and see :ref:`trait-metadata` for information on metadata @@ -269,7 +269,7 @@ the table. .. index:: PythonValue(), Range(), ReadOnly(), Regex() .. index:: Set() String(), This, Time() .. index:: ToolbarButton(), true, Tuple(), Type() -.. index:: undefined, UUID(), ValidatedTuple(), WeakRef() +.. index:: undefined, Union(), UUID(), ValidatedTuple(), WeakRef() .. _predefined-traits-beyond-simple-types-table: @@ -321,7 +321,7 @@ the table. +------------------+----------------------------------------------------------+ | Disallow | n/a | +------------------+----------------------------------------------------------+ -| Either | Either( *val1*\ [, *val2*, ..., *valN*, | +| Either [2]_ | Either( *val1*\ [, *val2*, ..., *valN*, | | | \*\*\ *metadata*] ) | +------------------+----------------------------------------------------------+ | Enum | Enum( *values*\ [, \*\*\ *metadata*] ) | @@ -408,7 +408,7 @@ the table. | Union | Union( *val1*\ [, *val2*, ..., *valN*, | | | \*\*\ *metadata*] ) | +------------------+----------------------------------------------------------+ -| UUID [4]_ | UUID( [\*\*\ *metadata*] ) | +| UUID | UUID( [\*\*\ *metadata*] ) | +------------------+----------------------------------------------------------+ | ValidatedTuple | ValidatedTuple( [\*\ *traits*, *fvalidate* = None, | | | *fvalidate_info* = '' , \*\*\ *metadata*] ) | @@ -638,56 +638,12 @@ prefix. Instantiating the class produces the following:: >>> print(bob.married) no -.. index:: Either trait - -.. _either: - -Either -:::::: -Another predefined trait that merits special explanation is Either. The -Either trait is intended for attributes that may take a value of more than -a single trait type, including None. The default value of Either is None, even -if None is not one of the types the user explicitly defines in the constructor, -but a different default value can be provided using the ``default`` argument. - -.. index:: - pair: Either trait; examples - -The following is an example of using Either:: - - # either.py --- Example of Either predefined trait - - from traits.api import HasTraits, Either, Str - - class Employee(HasTraits): - manager_name = Either(Str, None) - -This example defines an Employee class, which has a **manager_name** trait -attribute, which accepts either an Str instance or None as its value, and -will raise a TraitError if a value of any other type is assigned. For example:: - - >>> from traits.api import HasTraits, Either, Str - >>> class Employee(HasTraits): - ... manager_name = Either(Str, None) - ... - >>> steven = Employee(manager_name="Jenni") - >>> # Here steven's manager is named "Jenni" - >>> steven.manager_name - 'Jenni' - >>> eric = Employee(manager_name=None) - >>> # Eric is the boss, so he has no manager. - >>> eric.manager_name is None - True - >>> # Assigning a value that is neither a string nor None will fail. - >>> steven.manager_name = 5 - traits.trait_errors.TraitError: The 'manager_name' trait of an Employee instance must be a string or None, but a value of 5 was specified. - .. index:: Union trait .. _union: Union -:::::: +::::: The Union trait accepts a value that is considered valid by at least one of the traits in its definition. It is a simpler and therefore less error-prone alternative to the `Either` trait, which allows more complex constructs and @@ -719,7 +675,7 @@ attribute, which accepts either an Str instance or None as its value, a **salary** trait that accepts an instance of Salary or Float and will raise a TraitError if a value of any other type is assigned. For example:: - >>> from traits.api import HasTraits, Either, Str + >>> from traits.api import HasTraits, Str, Union >>> class Employee(HasTraits): ... manager_name = Union(Str, None) ... @@ -731,7 +687,7 @@ TraitError if a value of any other type is assigned. For example:: The following example illustrates the difference between `Either` and `Union`:: - >>> from traits.api import HasTraits, Either, Union, Str + >>> from traits.api import Either, HasTraits, Str, Union >>> class IntegerClass(HasTraits): ... primes = Either([2], None, {'3':6}, 5, 7, 11) ... @@ -744,6 +700,56 @@ The following example illustrates the difference between `Either` and `Union`:: ... primes = Union([2], None, {'3':6}, 5, 7, 11) ValueError: Union trait declaration expects a trait type or an instance of trait type or None, but got [2] instead +.. index:: Either trait + +.. _either: + +Either +:::::: + +.. note:: + The :class:`~.Either` trait type may eventually be deprecated, and should + not be used in new code. Use the more well-behaved :class:`~.Union` trait + type instead. + +Another predefined trait that merits special explanation is Either. The +Either trait is intended for attributes that may take a value of more than +a single trait type, including None. The default value of Either is None, even +if None is not one of the types the user explicitly defines in the constructor, +but a different default value can be provided using the ``default`` argument. + +.. index:: + pair: Either trait; examples + +The following is an example of using Either:: + + # either.py --- Example of Either predefined trait + + from traits.api import HasTraits, Either, Str + + class Employee(HasTraits): + manager_name = Either(Str, None) + +This example defines an Employee class, which has a **manager_name** trait +attribute, which accepts either an Str instance or None as its value, and +will raise a TraitError if a value of any other type is assigned. For example:: + + >>> from traits.api import HasTraits, Either, Str + >>> class Employee(HasTraits): + ... manager_name = Either(Str, None) + ... + >>> steven = Employee(manager_name="Jenni") + >>> # Here steven's manager is named "Jenni" + >>> steven.manager_name + 'Jenni' + >>> eric = Employee(manager_name=None) + >>> # Eric is the boss, so he has no manager. + >>> eric.manager_name is None + True + >>> # Assigning a value that is neither a string nor None will fail. + >>> steven.manager_name = 5 + traits.trait_errors.TraitError: The 'manager_name' trait of an Employee instance must be a string or None, but a value of 5 was specified. + .. _migration_either_to_union: @@ -1041,14 +1047,16 @@ the metadata attribute:: print(t.trait( 'any' ).is_trait_type( Str )) # False .. rubric:: Footnotes -.. [2] Most callable predefined traits are classes, but a few are functions. +.. [1] Most callable predefined traits are classes, but a few are functions. The distinction does not make a difference unless you are trying to extend an existing predefined trait. See the *Traits API Reference* for details on particular traits, and see Chapter 5 for details on extending existing traits. +.. [2] The :class:`~.Either` trait type is likely to be deprecated at some + point in the future. The :class:`~.Union` trait type should be preferred + to :class:`~.Either` in new code. .. [3] The Function and Method trait types are now deprecated. See |Function|, |Method| -.. [4] Available in Python 2.5. .. external urls diff --git a/traits/trait_numeric.py b/traits/trait_numeric.py index 28da99ec2..79ab4be2c 100644 --- a/traits/trait_numeric.py +++ b/traits/trait_numeric.py @@ -416,7 +416,7 @@ class ArrayOrNone(CArray): """ A coercing trait whose value may be either a NumPy array or None. This trait is designed to avoid the comparison issues with numpy arrays - that can arise from the use of constructs like Either(None, Array). + that can arise from the use of constructs like Union(None, Array). The default value is None. """ diff --git a/traits/trait_types.py b/traits/trait_types.py index e93de1f71..63d402f53 100644 --- a/traits/trait_types.py +++ b/traits/trait_types.py @@ -4124,6 +4124,13 @@ def __init__( class Either(TraitType): """ A trait type whose value can be any of of a specified list of traits. + .. note:: + + This class has some unusual corner-case behaviours and is not + recommended for use in new code. It may eventually be deprecated and + removed. For new code, consider using the :class:`~.Union` trait type + instead. + Parameters ---------- *traits