GH-84976: Re-introduce `datetime.py` and fix reprs

Without the change to the reprs, pure-python classes would have a repr
of `datetime._pydatetime.time`, etc.
This commit is contained in:
Paul Ganssle 2023-03-23 11:36:22 -04:00 committed by T. Wouters
parent 65c4a2b326
commit 0a5cd984b2
3 changed files with 27 additions and 29 deletions

View File

@ -16,6 +16,13 @@ from operator import index as _index
def _cmp(x, y): def _cmp(x, y):
return 0 if x == y else 1 if x > y else -1 return 0 if x == y else 1 if x > y else -1
def _get_class_module(self):
module_name = self.__class__.__module__
if module_name == '_pydatetime':
return 'datetime'
else:
return module_name
MINYEAR = 1 MINYEAR = 1
MAXYEAR = 9999 MAXYEAR = 9999
_MAXORDINAL = 3652059 # date.max.toordinal() _MAXORDINAL = 3652059 # date.max.toordinal()
@ -706,7 +713,7 @@ class timedelta:
args.append("microseconds=%d" % self._microseconds) args.append("microseconds=%d" % self._microseconds)
if not args: if not args:
args.append('0') args.append('0')
return "%s.%s(%s)" % (self.__class__.__module__, return "%s.%s(%s)" % (_get_class_module(self),
self.__class__.__qualname__, self.__class__.__qualname__,
', '.join(args)) ', '.join(args))
@ -1016,7 +1023,7 @@ class date:
>>> repr(dt) >>> repr(dt)
'datetime.datetime(2010, 1, 1, 0, 0, tzinfo=datetime.timezone.utc)' 'datetime.datetime(2010, 1, 1, 0, 0, tzinfo=datetime.timezone.utc)'
""" """
return "%s.%s(%d, %d, %d)" % (self.__class__.__module__, return "%s.%s(%d, %d, %d)" % (_get_class_module(self),
self.__class__.__qualname__, self.__class__.__qualname__,
self._year, self._year,
self._month, self._month,
@ -1510,7 +1517,7 @@ class time:
s = ", %d" % self._second s = ", %d" % self._second
else: else:
s = "" s = ""
s= "%s.%s(%d, %d%s)" % (self.__class__.__module__, s= "%s.%s(%d, %d%s)" % (_get_class_module(self),
self.__class__.__qualname__, self.__class__.__qualname__,
self._hour, self._minute, s) self._hour, self._minute, s)
if self._tzinfo is not None: if self._tzinfo is not None:
@ -2065,7 +2072,7 @@ class datetime(date):
del L[-1] del L[-1]
if L[-1] == 0: if L[-1] == 0:
del L[-1] del L[-1]
s = "%s.%s(%s)" % (self.__class__.__module__, s = "%s.%s(%s)" % (_get_class_module(self),
self.__class__.__qualname__, self.__class__.__qualname__,
", ".join(map(str, L))) ", ".join(map(str, L)))
if self._tzinfo is not None: if self._tzinfo is not None:
@ -2372,10 +2379,10 @@ class timezone(tzinfo):
if self is self.utc: if self is self.utc:
return 'datetime.timezone.utc' return 'datetime.timezone.utc'
if self._name is None: if self._name is None:
return "%s.%s(%r)" % (self.__class__.__module__, return "%s.%s(%r)" % (_get_class_module(self),
self.__class__.__qualname__, self.__class__.__qualname__,
self._offset) self._offset)
return "%s.%s(%r, %r)" % (self.__class__.__module__, return "%s.%s(%r, %r)" % (_get_class_module(self),
self.__class__.__qualname__, self.__class__.__qualname__,
self._offset, self._name) self._offset, self._name)
@ -2638,26 +2645,3 @@ _EPOCH = datetime(1970, 1, 1, tzinfo=timezone.utc)
# small dst() may get within its bounds; and it doesn't even matter if some # small dst() may get within its bounds; and it doesn't even matter if some
# perverse time zone returns a negative dst()). So a breaking case must be # perverse time zone returns a negative dst()). So a breaking case must be
# pretty bizarre, and a tzinfo subclass can override fromutc() if it is. # pretty bizarre, and a tzinfo subclass can override fromutc() if it is.
try:
from _datetime import *
except ImportError:
pass
else:
# Clean up unused names
del (_DAYNAMES, _DAYS_BEFORE_MONTH, _DAYS_IN_MONTH, _DI100Y, _DI400Y,
_DI4Y, _EPOCH, _MAXORDINAL, _MONTHNAMES, _build_struct_time,
_check_date_fields, _check_time_fields,
_check_tzinfo_arg, _check_tzname, _check_utc_offset, _cmp, _cmperror,
_date_class, _days_before_month, _days_before_year, _days_in_month,
_format_time, _format_offset, _index, _is_leap, _isoweek1monday, _math,
_ord2ymd, _time, _time_class, _tzinfo_class, _wrap_strftime, _ymd2ord,
_divide_and_round, _parse_isoformat_date, _parse_isoformat_time,
_parse_hh_mm_ss_ff, _IsoCalendarDate, _isoweek_to_gregorian,
_find_isoformat_datetime_separator, _FRACTION_CORRECTION,
_is_ascii_digit)
# XXX Since import * above excludes names that start with _,
# docstring does not get overwritten. In the future, it may be
# appropriate to maintain a single module level docstring and
# remove the following line.
from _datetime import __doc__

9
Lib/datetime.py Normal file
View File

@ -0,0 +1,9 @@
try:
from _datetime import *
from _datetime import __doc__
except ImportError:
from _pydatetime import *
from _pydatetime import __doc__
__all__ = ("date", "datetime", "time", "timedelta", "timezone", "tzinfo",
"MINYEAR", "MAXYEAR")

View File

@ -0,0 +1,5 @@
Create a new ``Lib/_pydatetime.py`` file that defines the Python version of
the ``datetime`` module, and make ``datetime`` import the contents of the
new library only if the C implementation is missing. Currently, the full
Python implementation is defined and then deleted if the C implementation is
not available, slowing down ``import datetime`` unnecessarily.