Skip to content

datetime.datetime is not Liskov-substitutable for datetime.date, but it's typed as if it were #3805

Closed

Description

@glyph

Consider this code:

import datetime

def compare_dates(x: datetime.date, y: datetime.date) -> bool:
    return x > y

compare_dates(datetime.datetime.now(), datetime.date.today())

Under mypy, it typechecks. Mypy's job is to prevent runtime TypeErrors, right? At runtime:

Traceback (most recent call last):
  File "<input>", line 1, in <module>
    compare_dates(datetime.datetime.now(), datetime.date.today())
  File "<input>", line 2, in compare_dates
    return x > y
TypeError: can't compare datetime.datetime to datetime.date

I think #2487 was wrong, and it actually makes more sense to type datetime.date and datetime.datetime separately.

Perhaps this is a mypy bug though? Maybe just because something's a subclass, doesn't mean it should be a subtype? Or a bug in datetime because it shouldn't do this?

I'm not sure. But practically speaking this makes any code working with date objects in mypy somewhat misleading and fraught.

Activity

  1. glyph commented on Mar 3, 2020

    @glyph
    ContributorAuthor

    (It seems like mypy is aware of the substitutability problem here, and they've all been type:ignore'd away?

    def __le__(self, other: datetime) -> bool: ... # type: ignore
    def __lt__(self, other: datetime) -> bool: ... # type: ignore
    def __ge__(self, other: datetime) -> bool: ... # type: ignore
    def __gt__(self, other: datetime) -> bool: ... # type: ignore
    )

  2. srittau commented on Mar 4, 2020

    @srittau
    Collaborator

    datetime is a subclass of date and can generally be used in place of it. Not reflecting this relationship in the stubs would cause countless other problems. I don't think there is a good way to represent that datetime violates the LSP in typeshed. Please note that that is true for many classes as well. Nevertheless it has been my experience that generally it's better for stubs to follow the implementation as closely as possibly, but we can't guard against all peculiarities of implementations.

  3. glyph commented on Mar 11, 2020

    @glyph
    ContributorAuthor

    @srittau the presence of those four type: ignores suggests to me that there's something missing from the stubs, though; this isn't just a matter of the stubs accurately representing the code and losing some information; mypy is telling us that this is a broken thing to do, the information is being thrown away.

  4. srittau commented on Mar 11, 2020

    @srittau
    Collaborator

    There is not much typeshed can do here. The implementation does not adhere to the LSP, the stubs follow that implementation.

  5. glyph commented on Jun 17, 2020

    @glyph
    ContributorAuthor

    @srittau This is still a bug - where should it be filed? Mypy? Core python?

  6. srittau commented on Jun 17, 2020

    @srittau
    Collaborator

    Python core decided to violate the LSP with this class hierarchy and mypy decided to warn about LSP violations. Either of those places, although I am sure that the mypy developers see the warning as a feature.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions