mirror of
https://github.com/python/cpython.git
synced 2025-08-04 00:48:58 +00:00
bpo-32403: Faster date and datetime constructors (#4993)
* Add tests for date subclass alternate constructors * Switch over alternate date constructors to fast path * Switch datetime constructors to fastpath, fix bpo-32404 * Add fast path for datetime in date subclass constructor * Set fold in constructor in datetime.combine * Add news entries.
This commit is contained in:
parent
6b5a27975a
commit
9f1b7b93f5
4 changed files with 171 additions and 45 deletions
|
@ -1552,6 +1552,50 @@ class TestDate(HarmlessMixedComparison, unittest.TestCase):
|
|||
self.assertEqual(dt1.toordinal(), dt2.toordinal())
|
||||
self.assertEqual(dt2.newmeth(-7), dt1.year + dt1.month - 7)
|
||||
|
||||
def test_subclass_alternate_constructors(self):
|
||||
# Test that alternate constructors call the constructor
|
||||
class DateSubclass(self.theclass):
|
||||
def __new__(cls, *args, **kwargs):
|
||||
result = self.theclass.__new__(cls, *args, **kwargs)
|
||||
result.extra = 7
|
||||
|
||||
return result
|
||||
|
||||
args = (2003, 4, 14)
|
||||
d_ord = 731319 # Equivalent ordinal date
|
||||
d_isoformat = '2003-04-14' # Equivalent isoformat()
|
||||
|
||||
base_d = DateSubclass(*args)
|
||||
self.assertIsInstance(base_d, DateSubclass)
|
||||
self.assertEqual(base_d.extra, 7)
|
||||
|
||||
# Timestamp depends on time zone, so we'll calculate the equivalent here
|
||||
ts = datetime.combine(base_d, time(0)).timestamp()
|
||||
|
||||
test_cases = [
|
||||
('fromordinal', (d_ord,)),
|
||||
('fromtimestamp', (ts,)),
|
||||
('fromisoformat', (d_isoformat,)),
|
||||
]
|
||||
|
||||
for constr_name, constr_args in test_cases:
|
||||
for base_obj in (DateSubclass, base_d):
|
||||
# Test both the classmethod and method
|
||||
with self.subTest(base_obj_type=type(base_obj),
|
||||
constr_name=constr_name):
|
||||
constr = getattr(base_obj, constr_name)
|
||||
|
||||
dt = constr(*constr_args)
|
||||
|
||||
# Test that it creates the right subclass
|
||||
self.assertIsInstance(dt, DateSubclass)
|
||||
|
||||
# Test that it's equal to the base object
|
||||
self.assertEqual(dt, base_d)
|
||||
|
||||
# Test that it called the constructor
|
||||
self.assertEqual(dt.extra, 7)
|
||||
|
||||
def test_pickling_subclass_date(self):
|
||||
|
||||
args = 6, 7, 23
|
||||
|
@ -2420,6 +2464,54 @@ class TestDateTime(TestDate):
|
|||
self.assertEqual(dt2.newmeth(-7), dt1.year + dt1.month +
|
||||
dt1.second - 7)
|
||||
|
||||
def test_subclass_alternate_constructors_datetime(self):
|
||||
# Test that alternate constructors call the constructor
|
||||
class DateTimeSubclass(self.theclass):
|
||||
def __new__(cls, *args, **kwargs):
|
||||
result = self.theclass.__new__(cls, *args, **kwargs)
|
||||
result.extra = 7
|
||||
|
||||
return result
|
||||
|
||||
args = (2003, 4, 14, 12, 30, 15, 123456)
|
||||
d_isoformat = '2003-04-14T12:30:15.123456' # Equivalent isoformat()
|
||||
utc_ts = 1050323415.123456 # UTC timestamp
|
||||
|
||||
base_d = DateTimeSubclass(*args)
|
||||
self.assertIsInstance(base_d, DateTimeSubclass)
|
||||
self.assertEqual(base_d.extra, 7)
|
||||
|
||||
# Timestamp depends on time zone, so we'll calculate the equivalent here
|
||||
ts = base_d.timestamp()
|
||||
|
||||
test_cases = [
|
||||
('fromtimestamp', (ts,)),
|
||||
# See https://bugs.python.org/issue32417
|
||||
# ('fromtimestamp', (ts, timezone.utc)),
|
||||
('utcfromtimestamp', (utc_ts,)),
|
||||
('fromisoformat', (d_isoformat,)),
|
||||
('strptime', (d_isoformat, '%Y-%m-%dT%H:%M:%S.%f')),
|
||||
('combine', (date(*args[0:3]), time(*args[3:]))),
|
||||
]
|
||||
|
||||
for constr_name, constr_args in test_cases:
|
||||
for base_obj in (DateTimeSubclass, base_d):
|
||||
# Test both the classmethod and method
|
||||
with self.subTest(base_obj_type=type(base_obj),
|
||||
constr_name=constr_name):
|
||||
constr = getattr(base_obj, constr_name)
|
||||
|
||||
dt = constr(*constr_args)
|
||||
|
||||
# Test that it creates the right subclass
|
||||
self.assertIsInstance(dt, DateTimeSubclass)
|
||||
|
||||
# Test that it's equal to the base object
|
||||
self.assertEqual(dt, base_d.replace(tzinfo=None))
|
||||
|
||||
# Test that it called the constructor
|
||||
self.assertEqual(dt.extra, 7)
|
||||
|
||||
def test_fromisoformat_datetime(self):
|
||||
# Test that isoformat() is reversible
|
||||
base_dates = [
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue