gh-49766: Make date-datetime comparison more symmetric and flexible (GH-114760)

Now the special comparison methods like `__eq__` and `__lt__` return
NotImplemented if one of comparands is date and other is datetime
instead of ignoring the time part and the time zone or forcefully
return "not equal" or raise TypeError.

It makes comparison of date and datetime subclasses more symmetric
and allows to change the default behavior by overriding
the special comparison methods in subclasses.

It is now the same as if date and datetime was independent classes.
This commit is contained in:
Serhiy Storchaka 2024-02-11 13:06:43 +02:00 committed by GitHub
parent d9d6909697
commit b104360788
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 91 additions and 84 deletions

View file

@ -556,10 +556,6 @@ def _check_tzinfo_arg(tz):
if tz is not None and not isinstance(tz, tzinfo):
raise TypeError("tzinfo argument must be None or of a tzinfo subclass")
def _cmperror(x, y):
raise TypeError("can't compare '%s' to '%s'" % (
type(x).__name__, type(y).__name__))
def _divide_and_round(a, b):
"""divide a by b and round result to the nearest integer
@ -1113,32 +1109,33 @@ class date:
# Comparisons of date objects with other.
def __eq__(self, other):
if isinstance(other, date):
if isinstance(other, date) and not isinstance(other, datetime):
return self._cmp(other) == 0
return NotImplemented
def __le__(self, other):
if isinstance(other, date):
if isinstance(other, date) and not isinstance(other, datetime):
return self._cmp(other) <= 0
return NotImplemented
def __lt__(self, other):
if isinstance(other, date):
if isinstance(other, date) and not isinstance(other, datetime):
return self._cmp(other) < 0
return NotImplemented
def __ge__(self, other):
if isinstance(other, date):
if isinstance(other, date) and not isinstance(other, datetime):
return self._cmp(other) >= 0
return NotImplemented
def __gt__(self, other):
if isinstance(other, date):
if isinstance(other, date) and not isinstance(other, datetime):
return self._cmp(other) > 0
return NotImplemented
def _cmp(self, other):
assert isinstance(other, date)
assert not isinstance(other, datetime)
y, m, d = self._year, self._month, self._day
y2, m2, d2 = other._year, other._month, other._day
return _cmp((y, m, d), (y2, m2, d2))
@ -2137,42 +2134,32 @@ class datetime(date):
def __eq__(self, other):
if isinstance(other, datetime):
return self._cmp(other, allow_mixed=True) == 0
elif not isinstance(other, date):
return NotImplemented
else:
return False
return NotImplemented
def __le__(self, other):
if isinstance(other, datetime):
return self._cmp(other) <= 0
elif not isinstance(other, date):
return NotImplemented
else:
_cmperror(self, other)
return NotImplemented
def __lt__(self, other):
if isinstance(other, datetime):
return self._cmp(other) < 0
elif not isinstance(other, date):
return NotImplemented
else:
_cmperror(self, other)
return NotImplemented
def __ge__(self, other):
if isinstance(other, datetime):
return self._cmp(other) >= 0
elif not isinstance(other, date):
return NotImplemented
else:
_cmperror(self, other)
return NotImplemented
def __gt__(self, other):
if isinstance(other, datetime):
return self._cmp(other) > 0
elif not isinstance(other, date):
return NotImplemented
else:
_cmperror(self, other)
return NotImplemented
def _cmp(self, other, allow_mixed=False):
assert isinstance(other, datetime)