traits icon indicating copy to clipboard operation
traits copied to clipboard

Date traits accepts datetime values, expect TraitsError instead

Open kitchoi opened this issue 6 years ago • 3 comments

When an attribute has a Date type, then it is meant to be just Date, not Date and Time. So I would expect assigning a datetime object to a Date trait to fail, but it does not.

import datetime
from traits.api import Date, HasTraits

class A(HasTraits):
     date = Date()
>>> a = A()
>>> a.date = datetime.datetime(1920, 3, 2)  # Expect to raise TraitsError here
>>> a.date
datetime.datetime(1920, 3, 2, 0, 0)

This behaviour comes from the fact that datetime is a subclass of date in Python:

>>> isinstance(datetime.datetime(1920, 3, 2), datetime.date)
True

See also https://bugs.python.org/issue28878

Propose deprecating allowing datetime objects for Date type.

kitchoi avatar Apr 30 '18 13:04 kitchoi

[Summarizing a discussion from another (Enthought-private) channel here]

There are two problems to solve here:

  1. There's currently no easy way to explicitly exclude datetime objects from being valid in Date traits.
  2. Traits users don't expect Date to accept datetime objects in the first place, and the fact that they do so is likely a source of subtle or late-discovered bugs.

Of those two, the second problem seems hard to solve quickly, but we can do something about the first one. How about an allow_datetime piece of metadata on the Date trait? It would have to default to True for backwards compatibility, but it at least gives a way for a user to exclude datetimes. The intended validation semantics for allow_datetime=False would be isinstance(value, datetime.date) and not isinstance(value, datetime.datetime)

For the second problem, we could potentially do something like:

  • In Traits 7.0, raise a DeprecationWarning about a change to the default, with users able to add allow_datetime=... to silence the warning.
  • In Traits 8.0, change the default for allow_datetime to False.

mdickinson avatar Feb 01 '21 12:02 mdickinson

So the proposed solution for (1) is:

  • Create a new first-class Date trait type, replacing the current implementation (which is Date = BaseInstance(datetime.date, editor=date_editor)). It should probably inherit directly from TraitType, not from BaseInstance.
  • Include allow_none and allow_datetime keyword arguments to Date. For backwards compatibility, they'd both have to default to True.

There are likely other "features" that Date currently inherits by being a BaseInstance in disguise, but I suspect none that user code will care about.

mdickinson avatar Feb 01 '21 12:02 mdickinson

Related core Python issue, though it's not very informative: https://bugs.python.org/issue28878

mdickinson avatar Feb 03 '21 11:02 mdickinson