From 9521a0afabc0b05165dcf04e0c65580598504500 Mon Sep 17 00:00:00 2001 From: Mark Dickinson Date: Wed, 10 Aug 2022 10:08:12 +0100 Subject: [PATCH 1/4] Document that Either should not be used in new code --- .../traits_api_reference/trait_types.rst | 5 +++-- docs/source/traits_user_manual/defining.rst | 20 ++++++++++++------- traits/trait_numeric.py | 2 +- traits/trait_types.py | 5 +++++ 4 files changed, 22 insertions(+), 10 deletions(-) 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 09f6bc7cb..5615a94be 100644 --- a/docs/source/traits_user_manual/defining.rst +++ b/docs/source/traits_user_manual/defining.rst @@ -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 [4]_ | 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*] ) | @@ -644,6 +644,11 @@ prefix. Instantiating the class produces the following:: Either :::::: + +.. note:: + :class:`~.Either` 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 @@ -687,7 +692,7 @@ will raise a TraitError if a value of any other type is assigned. For example:: .. _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 +724,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 +736,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) ... @@ -1048,7 +1053,8 @@ the metadata attribute:: existing traits. .. [3] The Function and Method trait types are now deprecated. See |Function|, |Method| -.. [4] Available in Python 2.5. +.. [4] The Either trait type is likely to be deprecated at some point in the + future. The Union trait type should be preferred to Either in new code. .. external urls diff --git a/traits/trait_numeric.py b/traits/trait_numeric.py index a809fe1b3..2c09d779e 100644 --- a/traits/trait_numeric.py +++ b/traits/trait_numeric.py @@ -395,7 +395,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..904647712 100644 --- a/traits/trait_types.py +++ b/traits/trait_types.py @@ -4124,6 +4124,11 @@ def __init__( class Either(TraitType): """ A trait type whose value can be any of of a specified list of traits. + Note: this class has many 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 From 683cbe3c622712e8e9038f882ac3bf26aa85f183 Mon Sep 17 00:00:00 2001 From: Mark Dickinson Date: Wed, 10 Aug 2022 11:54:31 +0100 Subject: [PATCH 2/4] Wording tweaks, markup fixes --- docs/source/traits_user_manual/defining.rst | 10 ++++++---- traits/trait_types.py | 10 ++++++---- 2 files changed, 12 insertions(+), 8 deletions(-) diff --git a/docs/source/traits_user_manual/defining.rst b/docs/source/traits_user_manual/defining.rst index 5615a94be..400f9c594 100644 --- a/docs/source/traits_user_manual/defining.rst +++ b/docs/source/traits_user_manual/defining.rst @@ -646,8 +646,9 @@ Either :::::: .. note:: - :class:`~.Either` may eventually be deprecated, and should not be used in - new code. Use the more well-behaved :class:`~.Union` trait type instead. + 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 @@ -1053,8 +1054,9 @@ the metadata attribute:: existing traits. .. [3] The Function and Method trait types are now deprecated. See |Function|, |Method| -.. [4] The Either trait type is likely to be deprecated at some point in the - future. The Union trait type should be preferred to Either in new code. +.. [4] 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. .. external urls diff --git a/traits/trait_types.py b/traits/trait_types.py index 904647712..63d402f53 100644 --- a/traits/trait_types.py +++ b/traits/trait_types.py @@ -4124,10 +4124,12 @@ def __init__( class Either(TraitType): """ A trait type whose value can be any of of a specified list of traits. - Note: this class has many 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. + .. 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 ---------- From ba57e59850a5cbd4a2b11c0199d4770d3e0af870 Mon Sep 17 00:00:00 2001 From: Mark Dickinson Date: Wed, 10 Aug 2022 14:32:45 +0100 Subject: [PATCH 3/4] Fix footnote ordering --- docs/source/traits_user_manual/defining.rst | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/docs/source/traits_user_manual/defining.rst b/docs/source/traits_user_manual/defining.rst index 400f9c594..0e1017a90 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 @@ -321,7 +321,7 @@ the table. +------------------+----------------------------------------------------------+ | Disallow | n/a | +------------------+----------------------------------------------------------+ -| Either [4]_ | Either( *val1*\ [, *val2*, ..., *valN*, | +| Either [2]_ | Either( *val1*\ [, *val2*, ..., *valN*, | | | \*\*\ *metadata*] ) | +------------------+----------------------------------------------------------+ | Enum | Enum( *values*\ [, \*\*\ *metadata*] ) | @@ -1047,16 +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. -.. [3] The Function and Method trait types are now deprecated. See |Function|, - |Method| -.. [4] The :class:`~.Either` trait type is likely to be deprecated at some +.. [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| .. external urls From 1f257fbaf2b1e7877c3999a18bcfd20d5c13c892 Mon Sep 17 00:00:00 2001 From: Mark Dickinson Date: Wed, 10 Aug 2022 14:35:03 +0100 Subject: [PATCH 4/4] Move Either below Union in the docs --- docs/source/traits_user_manual/defining.rst | 100 ++++++++++---------- 1 file changed, 50 insertions(+), 50 deletions(-) diff --git a/docs/source/traits_user_manual/defining.rst b/docs/source/traits_user_manual/defining.rst index 0e1017a90..0b014e608 100644 --- a/docs/source/traits_user_manual/defining.rst +++ b/docs/source/traits_user_manual/defining.rst @@ -638,56 +638,6 @@ prefix. Instantiating the class produces the following:: >>> print(bob.married) no -.. 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. - .. index:: Union trait .. _union: @@ -750,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: