mirror of
https://github.com/python/cpython.git
synced 2025-08-31 05:58:33 +00:00
bpo-10381: Add timezone to datetime C API (#5032)
* Add timezone to datetime C API * Add documentation for timezone C API macros * Add dedicated tests for datetime type check macros * Remove superfluous C API test * Drop support for TimeZoneType in datetime C API * Expose UTC singleton to the datetime C API * Update datetime C-API documentation to include links * Add reference count information for timezone constructors
This commit is contained in:
parent
ccbe5818af
commit
04af5b1ba9
7 changed files with 329 additions and 11 deletions
|
@ -31,6 +31,8 @@ from datetime import timezone
|
|||
from datetime import date, datetime
|
||||
import time as _time
|
||||
|
||||
import _testcapi
|
||||
|
||||
# Needed by test_datetime
|
||||
import _strptime
|
||||
#
|
||||
|
@ -5443,6 +5445,185 @@ class ZoneInfoCompleteTest(unittest.TestSuite):
|
|||
class IranTest(ZoneInfoTest):
|
||||
zonename = 'Asia/Tehran'
|
||||
|
||||
|
||||
class CapiTest(unittest.TestCase):
|
||||
def setUp(self):
|
||||
# Since the C API is not present in the _Pure tests, skip all tests
|
||||
if self.__class__.__name__.endswith('Pure'):
|
||||
self.skipTest('Not relevant in pure Python')
|
||||
|
||||
# This *must* be called, and it must be called first, so until either
|
||||
# restriction is loosened, we'll call it as part of test setup
|
||||
_testcapi.test_datetime_capi()
|
||||
|
||||
def test_utc_capi(self):
|
||||
for use_macro in (True, False):
|
||||
capi_utc = _testcapi.get_timezone_utc_capi(use_macro)
|
||||
|
||||
with self.subTest(use_macro=use_macro):
|
||||
self.assertIs(capi_utc, timezone.utc)
|
||||
|
||||
def test_timezones_capi(self):
|
||||
est_capi, est_macro, est_macro_nn = _testcapi.make_timezones_capi()
|
||||
|
||||
exp_named = timezone(timedelta(hours=-5), "EST")
|
||||
exp_unnamed = timezone(timedelta(hours=-5))
|
||||
|
||||
cases = [
|
||||
('est_capi', est_capi, exp_named),
|
||||
('est_macro', est_macro, exp_named),
|
||||
('est_macro_nn', est_macro_nn, exp_unnamed)
|
||||
]
|
||||
|
||||
for name, tz_act, tz_exp in cases:
|
||||
with self.subTest(name=name):
|
||||
self.assertEqual(tz_act, tz_exp)
|
||||
|
||||
dt1 = datetime(2000, 2, 4, tzinfo=tz_act)
|
||||
dt2 = datetime(2000, 2, 4, tzinfo=tz_exp)
|
||||
|
||||
self.assertEqual(dt1, dt2)
|
||||
self.assertEqual(dt1.tzname(), dt2.tzname())
|
||||
|
||||
dt_utc = datetime(2000, 2, 4, 5, tzinfo=timezone.utc)
|
||||
|
||||
self.assertEqual(dt1.astimezone(timezone.utc), dt_utc)
|
||||
|
||||
def test_check_date(self):
|
||||
class DateSubclass(date):
|
||||
pass
|
||||
|
||||
d = date(2011, 1, 1)
|
||||
ds = DateSubclass(2011, 1, 1)
|
||||
dt = datetime(2011, 1, 1)
|
||||
|
||||
is_date = _testcapi.datetime_check_date
|
||||
|
||||
# Check the ones that should be valid
|
||||
self.assertTrue(is_date(d))
|
||||
self.assertTrue(is_date(dt))
|
||||
self.assertTrue(is_date(ds))
|
||||
self.assertTrue(is_date(d, True))
|
||||
|
||||
# Check that the subclasses do not match exactly
|
||||
self.assertFalse(is_date(dt, True))
|
||||
self.assertFalse(is_date(ds, True))
|
||||
|
||||
# Check that various other things are not dates at all
|
||||
args = [tuple(), list(), 1, '2011-01-01',
|
||||
timedelta(1), timezone.utc, time(12, 00)]
|
||||
for arg in args:
|
||||
for exact in (True, False):
|
||||
with self.subTest(arg=arg, exact=exact):
|
||||
self.assertFalse(is_date(arg, exact))
|
||||
|
||||
def test_check_time(self):
|
||||
class TimeSubclass(time):
|
||||
pass
|
||||
|
||||
t = time(12, 30)
|
||||
ts = TimeSubclass(12, 30)
|
||||
|
||||
is_time = _testcapi.datetime_check_time
|
||||
|
||||
# Check the ones that should be valid
|
||||
self.assertTrue(is_time(t))
|
||||
self.assertTrue(is_time(ts))
|
||||
self.assertTrue(is_time(t, True))
|
||||
|
||||
# Check that the subclass does not match exactly
|
||||
self.assertFalse(is_time(ts, True))
|
||||
|
||||
# Check that various other things are not times
|
||||
args = [tuple(), list(), 1, '2011-01-01',
|
||||
timedelta(1), timezone.utc, date(2011, 1, 1)]
|
||||
|
||||
for arg in args:
|
||||
for exact in (True, False):
|
||||
with self.subTest(arg=arg, exact=exact):
|
||||
self.assertFalse(is_time(arg, exact))
|
||||
|
||||
def test_check_datetime(self):
|
||||
class DateTimeSubclass(datetime):
|
||||
pass
|
||||
|
||||
dt = datetime(2011, 1, 1, 12, 30)
|
||||
dts = DateTimeSubclass(2011, 1, 1, 12, 30)
|
||||
|
||||
is_datetime = _testcapi.datetime_check_datetime
|
||||
|
||||
# Check the ones that should be valid
|
||||
self.assertTrue(is_datetime(dt))
|
||||
self.assertTrue(is_datetime(dts))
|
||||
self.assertTrue(is_datetime(dt, True))
|
||||
|
||||
# Check that the subclass does not match exactly
|
||||
self.assertFalse(is_datetime(dts, True))
|
||||
|
||||
# Check that various other things are not datetimes
|
||||
args = [tuple(), list(), 1, '2011-01-01',
|
||||
timedelta(1), timezone.utc, date(2011, 1, 1)]
|
||||
|
||||
for arg in args:
|
||||
for exact in (True, False):
|
||||
with self.subTest(arg=arg, exact=exact):
|
||||
self.assertFalse(is_datetime(arg, exact))
|
||||
|
||||
def test_check_delta(self):
|
||||
class TimeDeltaSubclass(timedelta):
|
||||
pass
|
||||
|
||||
td = timedelta(1)
|
||||
tds = TimeDeltaSubclass(1)
|
||||
|
||||
is_timedelta = _testcapi.datetime_check_delta
|
||||
|
||||
# Check the ones that should be valid
|
||||
self.assertTrue(is_timedelta(td))
|
||||
self.assertTrue(is_timedelta(tds))
|
||||
self.assertTrue(is_timedelta(td, True))
|
||||
|
||||
# Check that the subclass does not match exactly
|
||||
self.assertFalse(is_timedelta(tds, True))
|
||||
|
||||
# Check that various other things are not timedeltas
|
||||
args = [tuple(), list(), 1, '2011-01-01',
|
||||
timezone.utc, date(2011, 1, 1), datetime(2011, 1, 1)]
|
||||
|
||||
for arg in args:
|
||||
for exact in (True, False):
|
||||
with self.subTest(arg=arg, exact=exact):
|
||||
self.assertFalse(is_timedelta(arg, exact))
|
||||
|
||||
def test_check_tzinfo(self):
|
||||
class TZInfoSubclass(tzinfo):
|
||||
pass
|
||||
|
||||
tzi = tzinfo()
|
||||
tzis = TZInfoSubclass()
|
||||
tz = timezone(timedelta(hours=-5))
|
||||
|
||||
is_tzinfo = _testcapi.datetime_check_tzinfo
|
||||
|
||||
# Check the ones that should be valid
|
||||
self.assertTrue(is_tzinfo(tzi))
|
||||
self.assertTrue(is_tzinfo(tz))
|
||||
self.assertTrue(is_tzinfo(tzis))
|
||||
self.assertTrue(is_tzinfo(tzi, True))
|
||||
|
||||
# Check that the subclasses do not match exactly
|
||||
self.assertFalse(is_tzinfo(tz, True))
|
||||
self.assertFalse(is_tzinfo(tzis, True))
|
||||
|
||||
# Check that various other things are not tzinfos
|
||||
args = [tuple(), list(), 1, '2011-01-01',
|
||||
date(2011, 1, 1), datetime(2011, 1, 1)]
|
||||
|
||||
for arg in args:
|
||||
for exact in (True, False):
|
||||
with self.subTest(arg=arg, exact=exact):
|
||||
self.assertFalse(is_tzinfo(arg, exact))
|
||||
|
||||
def load_tests(loader, standard_tests, pattern):
|
||||
standard_tests.addTest(ZoneInfoCompleteTest())
|
||||
return standard_tests
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue