From 8cc57deabb68959ad4302aa627e8078a414953e3 Mon Sep 17 00:00:00 2001 From: Wulian233 <1055917385@qq.com> Date: Tue, 11 Feb 2025 19:55:50 +0800 Subject: [PATCH 1/6] Use `EnvironmentVarGuard` for `datetimetester.py` to manage environment varibales --- Lib/test/datetimetester.py | 68 +++++++++---------- ...-02-11-19-55-12.gh-issue-128438.ZIAn_5.rst | 2 + 2 files changed, 34 insertions(+), 36 deletions(-) create mode 100644 Misc/NEWS.d/next/Tests/2025-02-11-19-55-12.gh-issue-128438.ZIAn_5.rst diff --git a/Lib/test/datetimetester.py b/Lib/test/datetimetester.py index 25a3015c4e19ce..989ad1e59f5614 100644 --- a/Lib/test/datetimetester.py +++ b/Lib/test/datetimetester.py @@ -20,7 +20,7 @@ from test import support from test.support import is_resource_enabled, ALWAYS_EQ, LARGEST, SMALLEST -from test.support import script_helper, warnings_helper +from test.support import os_helper, script_helper, warnings_helper import datetime as datetime_module from datetime import MINYEAR, MAXYEAR @@ -6571,42 +6571,38 @@ def test_system_transitions(self): self.zonename.startswith('right/')): self.skipTest("Skipping %s" % self.zonename) tz = self.tz - TZ = os.environ.get('TZ') - os.environ['TZ'] = self.zonename - try: - _time.tzset() - for udt, shift in tz.transitions(): - if udt.year >= 2037: - # System support for times around the end of 32-bit time_t - # and later is flaky on many systems. - break - s0 = (udt - datetime(1970, 1, 1)) // SEC - ss = shift // SEC # shift seconds - for x in [-40 * 3600, -20*3600, -1, 0, - ss - 1, ss + 20 * 3600, ss + 40 * 3600]: - s = s0 + x - sdt = datetime.fromtimestamp(s) - tzdt = datetime.fromtimestamp(s, tz).replace(tzinfo=None) - self.assertEquivDatetimes(sdt, tzdt) - s1 = sdt.timestamp() - self.assertEqual(s, s1) - if ss > 0: # gap - # Create local time inside the gap - dt = datetime.fromtimestamp(s0) - shift / 2 - ts0 = dt.timestamp() - ts1 = dt.replace(fold=1).timestamp() - self.assertEqual(ts0, s0 + ss / 2) - self.assertEqual(ts1, s0 - ss / 2) - # gh-83861 - utc0 = dt.astimezone(timezone.utc) - utc1 = dt.replace(fold=1).astimezone(timezone.utc) - self.assertEqual(utc0, utc1 + timedelta(0, ss)) - finally: - if TZ is None: - del os.environ['TZ'] - else: - os.environ['TZ'] = TZ + with os_helper.EnvironmentVarGuard() as env: + env.set('TZ', self.zonename) _time.tzset() + try: + for udt, shift in tz.transitions(): + if udt.year >= 2037: + # System support for times around the end of 32-bit time_t + # and later is flaky on many systems. + break + s0 = (udt - datetime(1970, 1, 1)) // SEC + ss = shift // SEC # shift seconds + for x in [-40 * 3600, -20*3600, -1, 0, + ss - 1, ss + 20 * 3600, ss + 40 * 3600]: + s = s0 + x + sdt = datetime.fromtimestamp(s) + tzdt = datetime.fromtimestamp(s, tz).replace(tzinfo=None) + self.assertEquivDatetimes(sdt, tzdt) + s1 = sdt.timestamp() + self.assertEqual(s, s1) + if ss > 0: # gap + # Create local time inside the gap + dt = datetime.fromtimestamp(s0) - shift / 2 + ts0 = dt.timestamp() + ts1 = dt.replace(fold=1).timestamp() + self.assertEqual(ts0, s0 + ss / 2) + self.assertEqual(ts1, s0 - ss / 2) + # gh-83861 + utc0 = dt.astimezone(timezone.utc) + utc1 = dt.replace(fold=1).astimezone(timezone.utc) + self.assertEqual(utc0, utc1 + timedelta(0, ss)) + finally: + _time.tzset() class ZoneInfoCompleteTest(unittest.TestSuite): diff --git a/Misc/NEWS.d/next/Tests/2025-02-11-19-55-12.gh-issue-128438.ZIAn_5.rst b/Misc/NEWS.d/next/Tests/2025-02-11-19-55-12.gh-issue-128438.ZIAn_5.rst new file mode 100644 index 00000000000000..e4250dd573b0a8 --- /dev/null +++ b/Misc/NEWS.d/next/Tests/2025-02-11-19-55-12.gh-issue-128438.ZIAn_5.rst @@ -0,0 +1,2 @@ +Use ``EnvironmentVarGuard`` for ``datetimetester.py`` to manage environment +varibales From ebffc4af9dc15103b78e15dc4774bcd0a11340d6 Mon Sep 17 00:00:00 2001 From: Wulian233 <1055917385@qq.com> Date: Thu, 13 Feb 2025 04:45:47 +0800 Subject: [PATCH 2/6] Delete Misc/NEWS.d/next/Tests/2025-02-11-19-55-12.gh-issue-128438.ZIAn_5.rst --- .../next/Tests/2025-02-11-19-55-12.gh-issue-128438.ZIAn_5.rst | 2 -- 1 file changed, 2 deletions(-) delete mode 100644 Misc/NEWS.d/next/Tests/2025-02-11-19-55-12.gh-issue-128438.ZIAn_5.rst diff --git a/Misc/NEWS.d/next/Tests/2025-02-11-19-55-12.gh-issue-128438.ZIAn_5.rst b/Misc/NEWS.d/next/Tests/2025-02-11-19-55-12.gh-issue-128438.ZIAn_5.rst deleted file mode 100644 index e4250dd573b0a8..00000000000000 --- a/Misc/NEWS.d/next/Tests/2025-02-11-19-55-12.gh-issue-128438.ZIAn_5.rst +++ /dev/null @@ -1,2 +0,0 @@ -Use ``EnvironmentVarGuard`` for ``datetimetester.py`` to manage environment -varibales From d9eda29702f73a8523a15113cc682cea26aa729a Mon Sep 17 00:00:00 2001 From: Wulian233 <1055917385@qq.com> Date: Sat, 22 Feb 2025 13:32:08 +0800 Subject: [PATCH 3/6] use context manager --- Lib/test/datetimetester.py | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/Lib/test/datetimetester.py b/Lib/test/datetimetester.py index 989ad1e59f5614..da6770c14a8075 100644 --- a/Lib/test/datetimetester.py +++ b/Lib/test/datetimetester.py @@ -1,5 +1,6 @@ """Test the datetime module.""" import bisect +import contextlib import copy import decimal import io @@ -6557,6 +6558,16 @@ def test_gaps(self): ldt = tz.fromutc(udt.replace(tzinfo=tz)) self.assertEqual(ldt.fold, 0) + @contextlib.contextmanager + def _change_tz(new_tzinfo): + try: + with os_helper.EnvironmentVarGuard() as env: + env["TZ"] = new_tzinfo + _time.tzset() + yield + finally: + _time.tzset() + @unittest.skipUnless( hasattr(_time, "tzset"), "time module has no attribute tzset" ) @@ -6571,9 +6582,7 @@ def test_system_transitions(self): self.zonename.startswith('right/')): self.skipTest("Skipping %s" % self.zonename) tz = self.tz - with os_helper.EnvironmentVarGuard() as env: - env.set('TZ', self.zonename) - _time.tzset() + with self._change_tz(self.zonename): try: for udt, shift in tz.transitions(): if udt.year >= 2037: From 283758c80e8c5a6bcaaf5712f08aca09162f841b Mon Sep 17 00:00:00 2001 From: Wulian233 <1055917385@qq.com> Date: Sat, 22 Feb 2025 13:51:03 +0800 Subject: [PATCH 4/6] finish --- Lib/test/datetimetester.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Lib/test/datetimetester.py b/Lib/test/datetimetester.py index da6770c14a8075..a4c63c2bc7449a 100644 --- a/Lib/test/datetimetester.py +++ b/Lib/test/datetimetester.py @@ -6559,6 +6559,7 @@ def test_gaps(self): self.assertEqual(ldt.fold, 0) @contextlib.contextmanager + @staticmethod def _change_tz(new_tzinfo): try: with os_helper.EnvironmentVarGuard() as env: @@ -6591,7 +6592,7 @@ def test_system_transitions(self): break s0 = (udt - datetime(1970, 1, 1)) // SEC ss = shift // SEC # shift seconds - for x in [-40 * 3600, -20*3600, -1, 0, + for x in [-40 * 3600, -20 * 3600, -1, 0, ss - 1, ss + 20 * 3600, ss + 40 * 3600]: s = s0 + x sdt = datetime.fromtimestamp(s) From 55e78088ca3eb82ccdc3975ebdc04fd6df45b8f4 Mon Sep 17 00:00:00 2001 From: Wulian233 <1055917385@qq.com> Date: Sat, 22 Feb 2025 14:03:19 +0800 Subject: [PATCH 5/6] classmethod --- Lib/test/datetimetester.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Lib/test/datetimetester.py b/Lib/test/datetimetester.py index a4c63c2bc7449a..78d121c80b0d95 100644 --- a/Lib/test/datetimetester.py +++ b/Lib/test/datetimetester.py @@ -6558,9 +6558,9 @@ def test_gaps(self): ldt = tz.fromutc(udt.replace(tzinfo=tz)) self.assertEqual(ldt.fold, 0) + @classmethod @contextlib.contextmanager - @staticmethod - def _change_tz(new_tzinfo): + def _change_tz(cls, new_tzinfo): try: with os_helper.EnvironmentVarGuard() as env: env["TZ"] = new_tzinfo From e594012c445ef48d8aa2757b532a90c7eabf08de Mon Sep 17 00:00:00 2001 From: Wulian233 <1055917385@qq.com> Date: Sat, 22 Feb 2025 16:35:57 +0800 Subject: [PATCH 6/6] finish --- Lib/test/datetimetester.py | 55 ++++++++++++++++++-------------------- 1 file changed, 26 insertions(+), 29 deletions(-) diff --git a/Lib/test/datetimetester.py b/Lib/test/datetimetester.py index 78d121c80b0d95..6ef1b2b9d1e16a 100644 --- a/Lib/test/datetimetester.py +++ b/Lib/test/datetimetester.py @@ -6584,35 +6584,32 @@ def test_system_transitions(self): self.skipTest("Skipping %s" % self.zonename) tz = self.tz with self._change_tz(self.zonename): - try: - for udt, shift in tz.transitions(): - if udt.year >= 2037: - # System support for times around the end of 32-bit time_t - # and later is flaky on many systems. - break - s0 = (udt - datetime(1970, 1, 1)) // SEC - ss = shift // SEC # shift seconds - for x in [-40 * 3600, -20 * 3600, -1, 0, - ss - 1, ss + 20 * 3600, ss + 40 * 3600]: - s = s0 + x - sdt = datetime.fromtimestamp(s) - tzdt = datetime.fromtimestamp(s, tz).replace(tzinfo=None) - self.assertEquivDatetimes(sdt, tzdt) - s1 = sdt.timestamp() - self.assertEqual(s, s1) - if ss > 0: # gap - # Create local time inside the gap - dt = datetime.fromtimestamp(s0) - shift / 2 - ts0 = dt.timestamp() - ts1 = dt.replace(fold=1).timestamp() - self.assertEqual(ts0, s0 + ss / 2) - self.assertEqual(ts1, s0 - ss / 2) - # gh-83861 - utc0 = dt.astimezone(timezone.utc) - utc1 = dt.replace(fold=1).astimezone(timezone.utc) - self.assertEqual(utc0, utc1 + timedelta(0, ss)) - finally: - _time.tzset() + for udt, shift in tz.transitions(): + if udt.year >= 2037: + # System support for times around the end of 32-bit time_t + # and later is flaky on many systems. + break + s0 = (udt - datetime(1970, 1, 1)) // SEC + ss = shift // SEC # shift seconds + for x in [-40 * 3600, -20 * 3600, -1, 0, + ss - 1, ss + 20 * 3600, ss + 40 * 3600]: + s = s0 + x + sdt = datetime.fromtimestamp(s) + tzdt = datetime.fromtimestamp(s, tz).replace(tzinfo=None) + self.assertEquivDatetimes(sdt, tzdt) + s1 = sdt.timestamp() + self.assertEqual(s, s1) + if ss > 0: # gap + # Create local time inside the gap + dt = datetime.fromtimestamp(s0) - shift / 2 + ts0 = dt.timestamp() + ts1 = dt.replace(fold=1).timestamp() + self.assertEqual(ts0, s0 + ss / 2) + self.assertEqual(ts1, s0 - ss / 2) + # gh-83861 + utc0 = dt.astimezone(timezone.utc) + utc1 = dt.replace(fold=1).astimezone(timezone.utc) + self.assertEqual(utc0, utc1 + timedelta(0, ss)) class ZoneInfoCompleteTest(unittest.TestSuite):