Skip to content

Commit 2c3aa52

Browse files
authored
[3.13] gh-120782: Update internal type cache when reloading datetime (GH-120829) (#120855)
* [3.13] gh-120782: Update internal type cache when reloading datetime When reloading _datetime module, the single-phase version did not invoke the PyInit__datetime function, whereas the current multi-phase version updates the static types through the module init. The outdated static type cache in the interpreter state needs to be invalidated at the end of reloading the multi-phase module.
1 parent 8597149 commit 2c3aa52

File tree

3 files changed

+39
-20
lines changed

3 files changed

+39
-20
lines changed

Lib/test/datetimetester.py

+32-20
Original file line numberDiff line numberDiff line change
@@ -52,25 +52,6 @@
5252
pass
5353
#
5454

55-
# This is copied from test_import/__init__.py.
56-
def no_rerun(reason):
57-
"""Skip rerunning for a particular test.
58-
59-
WARNING: Use this decorator with care; skipping rerunning makes it
60-
impossible to find reference leaks. Provide a clear reason for skipping the
61-
test using the 'reason' parameter.
62-
"""
63-
def deco(func):
64-
_has_run = False
65-
def wrapper(self):
66-
nonlocal _has_run
67-
if _has_run:
68-
self.skipTest(reason)
69-
func(self)
70-
_has_run = True
71-
return wrapper
72-
return deco
73-
7455
pickle_loads = {pickle.loads, pickle._loads}
7556

7657
pickle_choices = [(pickle, pickle, proto)
@@ -6420,7 +6401,6 @@ class IranTest(ZoneInfoTest):
64206401

64216402

64226403
@unittest.skipIf(_testcapi is None, 'need _testcapi module')
6423-
@no_rerun("the encapsulated datetime C API does not support reloading")
64246404
class CapiTest(unittest.TestCase):
64256405
def setUp(self):
64266406
# Since the C API is not present in the _Pure tests, skip all tests
@@ -6889,6 +6869,38 @@ def pickle_fake_date(datetime_) -> Type[FakeDate]:
68896869
""")
68906870
script_helper.assert_python_ok('-c', script)
68916871

6872+
def test_update_type_cache(self):
6873+
# gh-120782
6874+
script = textwrap.dedent("""
6875+
import sys
6876+
for i in range(5):
6877+
import _datetime
6878+
assert _datetime.date.max > _datetime.date.min
6879+
assert _datetime.time.max > _datetime.time.min
6880+
assert _datetime.datetime.max > _datetime.datetime.min
6881+
assert _datetime.timedelta.max > _datetime.timedelta.min
6882+
assert _datetime.date.__dict__["min"] is _datetime.date.min
6883+
assert _datetime.date.__dict__["max"] is _datetime.date.max
6884+
assert _datetime.date.__dict__["resolution"] is _datetime.date.resolution
6885+
assert _datetime.time.__dict__["min"] is _datetime.time.min
6886+
assert _datetime.time.__dict__["max"] is _datetime.time.max
6887+
assert _datetime.time.__dict__["resolution"] is _datetime.time.resolution
6888+
assert _datetime.datetime.__dict__["min"] is _datetime.datetime.min
6889+
assert _datetime.datetime.__dict__["max"] is _datetime.datetime.max
6890+
assert _datetime.datetime.__dict__["resolution"] is _datetime.datetime.resolution
6891+
assert _datetime.timedelta.__dict__["min"] is _datetime.timedelta.min
6892+
assert _datetime.timedelta.__dict__["max"] is _datetime.timedelta.max
6893+
assert _datetime.timedelta.__dict__["resolution"] is _datetime.timedelta.resolution
6894+
assert _datetime.timezone.__dict__["min"] is _datetime.timezone.min
6895+
assert _datetime.timezone.__dict__["max"] is _datetime.timezone.max
6896+
assert _datetime.timezone.__dict__["utc"] is _datetime.timezone.utc
6897+
assert isinstance(_datetime.timezone.min, _datetime.tzinfo)
6898+
assert isinstance(_datetime.timezone.max, _datetime.tzinfo)
6899+
assert isinstance(_datetime.timezone.utc, _datetime.tzinfo)
6900+
del sys.modules['_datetime']
6901+
""")
6902+
script_helper.assert_python_ok('-c', script)
6903+
68926904

68936905
def load_tests(loader, standard_tests, pattern):
68946906
standard_tests.addTest(ZoneInfoCompleteTest())
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Fix wrong references of the :mod:`datetime` types after reloading the module.

Modules/_datetimemodule.c

+6
Original file line numberDiff line numberDiff line change
@@ -7339,6 +7339,12 @@ _datetime_exec(PyObject *module)
73397339
static_assert(DI100Y == 25 * DI4Y - 1, "DI100Y");
73407340
assert(DI100Y == days_before_year(100+1));
73417341

7342+
if (reloading) {
7343+
for (size_t i = 0; i < Py_ARRAY_LENGTH(capi_types); i++) {
7344+
PyType_Modified(capi_types[i]);
7345+
}
7346+
}
7347+
73427348
if (set_current_module(interp, module) < 0) {
73437349
goto error;
73447350
}

0 commit comments

Comments
 (0)