traits
traits copied to clipboard
Date traits accepts datetime values, expect TraitsError instead
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.
[Summarizing a discussion from another (Enthought-private) channel here]
There are two problems to solve here:
- There's currently no easy way to explicitly exclude
datetime
objects from being valid inDate
traits. - Traits users don't expect
Date
to acceptdatetime
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 addallow_datetime=...
to silence the warning. - In Traits 8.0, change the default for
allow_datetime
toFalse
.
So the proposed solution for (1) is:
- Create a new first-class
Date
trait type, replacing the current implementation (which isDate = BaseInstance(datetime.date, editor=date_editor)
). It should probably inherit directly fromTraitType
, not fromBaseInstance
. - Include
allow_none
andallow_datetime
keyword arguments toDate
. For backwards compatibility, they'd both have to default toTrue
.
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.
Related core Python issue, though it's not very informative: https://bugs.python.org/issue28878