Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

PrefixList validation tracebacks are chained #1155

Closed
mdickinson opened this issue May 22, 2020 · 4 comments
Closed

PrefixList validation tracebacks are chained #1155

mdickinson opened this issue May 22, 2020 · 4 comments
Labels
resolution: duplicate This issue is a duplicate of another issue type: cleanup
Milestone

Comments

@mdickinson
Copy link
Member

mdickinson commented May 22, 2020

Validation exceptions from assignment to a PrefixList trait have some unnecessary chaining; this is going to clutter logs and consoles. It would be good to get rid of this.

This is probably not specific to PrefixList.

>>> from traits.api import HasTraits, PrefixList
>>> class A(HasTraits):
...     foo = PrefixList(["yes", "no"])
... 
>>> a = A()
>>> a.foo = "bogus"
Traceback (most recent call last):
  File "/Users/mdickinson/Enthought/ETS/traits/traits/trait_type.py", line 355, in _value_for
    return self.value_for(value)
  File "/Users/mdickinson/Enthought/ETS/traits/traits/trait_types.py", line 2629, in value_for
    raise TraitError(
traits.trait_errors.TraitError: The value of a PrefixList trait must be 'yes' or 'no' (or any unique prefix), but a value of 'bogus' <class 'str'> was specified.

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/Users/mdickinson/Enthought/ETS/traits/traits/trait_type.py", line 357, in _value_for
    self.error(object, name, value)
  File "/Users/mdickinson/Enthought/ETS/traits/traits/base_trait_handler.py", line 74, in error
    raise TraitError(
traits.trait_errors.TraitError: The 'foo' trait of an A instance must be 'yes' or 'no' (or any unique prefix), but a value of 'bogus' <class 'str'> was specified.

Assigning to the 6.1 milestone to see if there's anything we can reasonably do about this before the release. If not, it can be bumped.

@mdickinson mdickinson added this to the 6.1.0 release milestone May 22, 2020
@kitchoi
Copy link
Contributor

kitchoi commented Jun 1, 2020

One way to fix is to do raise ... from None in

def error(self, object, name, value):
"""Raises a TraitError exception.
This method is called by the validate() method when an assigned value
is not valid. Raising a TraitError exception either notifies the user
of the problem, or, in the case of compound traits, provides a chance
for another trait handler to handle to validate the value.
Parameters
----------
object : object
The object whose attribute is being assigned.
name : str
The name of the attribute being assigned.
value : object
The proposed new value for the attribute.
"""
raise TraitError(
object, name, self.full_info(object, name, value), value
)

But this is perhaps too general and removed from the context where the exception came from. There are probably situations where the chained traceback is helpful. We could add a flag in BaseTraitHandler.error to optionally raise ... from None I suppose. Does this worth the extra code branch?

@mdickinson
Copy link
Member Author

Bumping to 6.2.0

@mdickinson
Copy link
Member Author

"Fixed" in #1563 for PrefixList and PrefixMap, by replacing their use of value_for with plain old validate.

More generally, any TraitType subclass that uses the value_for method for its validation will have this issue. PrefixList and PrefixMap are the only TraitType subclasses in the current main branch that use value_for. Given that the symptoms are mild and that the prevalence of the issue seems tiny, it doesn't seem worth fixing this more generally.

Relevant code:

  • traits/traits/trait_type.py

    Lines 155 to 161 in 0e74444

    ``value_for ( self, value )``
    As another alternative to implementing the ``validate`` method, you
    can instead implement the ``value_for`` method, which receives only
    the ``value`` being assigned. It should return the validated form of
    ``value`` if it is valid, or raise a ``TraitError`` if the value is not
    valid.
  • traits/traits/trait_type.py

    Lines 402 to 404 in 0e74444

    validate = getattr(self, "value_for", None)
    if validate is not None:
    validate = self._value_for

@mdickinson
Copy link
Member Author

This was a duplicate of #955, and was fixed in #1564.

@mdickinson mdickinson added the resolution: duplicate This issue is a duplicate of another issue label Oct 8, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
resolution: duplicate This issue is a duplicate of another issue type: cleanup
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants