[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.
This commit is contained in:
neonene 2024-07-03 17:22:51 +09:00 committed by GitHub
parent 85971492b7
commit 2c3aa527fd
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 39 additions and 20 deletions

View file

@ -52,25 +52,6 @@ except ImportError:
pass
#
# This is copied from test_import/__init__.py.
def no_rerun(reason):
"""Skip rerunning for a particular test.
WARNING: Use this decorator with care; skipping rerunning makes it
impossible to find reference leaks. Provide a clear reason for skipping the
test using the 'reason' parameter.
"""
def deco(func):
_has_run = False
def wrapper(self):
nonlocal _has_run
if _has_run:
self.skipTest(reason)
func(self)
_has_run = True
return wrapper
return deco
pickle_loads = {pickle.loads, pickle._loads}
pickle_choices = [(pickle, pickle, proto)
@ -6420,7 +6401,6 @@ class IranTest(ZoneInfoTest):
@unittest.skipIf(_testcapi is None, 'need _testcapi module')
@no_rerun("the encapsulated datetime C API does not support reloading")
class CapiTest(unittest.TestCase):
def setUp(self):
# Since the C API is not present in the _Pure tests, skip all tests
@ -6889,6 +6869,38 @@ class ExtensionModuleTests(unittest.TestCase):
""")
script_helper.assert_python_ok('-c', script)
def test_update_type_cache(self):
# gh-120782
script = textwrap.dedent("""
import sys
for i in range(5):
import _datetime
assert _datetime.date.max > _datetime.date.min
assert _datetime.time.max > _datetime.time.min
assert _datetime.datetime.max > _datetime.datetime.min
assert _datetime.timedelta.max > _datetime.timedelta.min
assert _datetime.date.__dict__["min"] is _datetime.date.min
assert _datetime.date.__dict__["max"] is _datetime.date.max
assert _datetime.date.__dict__["resolution"] is _datetime.date.resolution
assert _datetime.time.__dict__["min"] is _datetime.time.min
assert _datetime.time.__dict__["max"] is _datetime.time.max
assert _datetime.time.__dict__["resolution"] is _datetime.time.resolution
assert _datetime.datetime.__dict__["min"] is _datetime.datetime.min
assert _datetime.datetime.__dict__["max"] is _datetime.datetime.max
assert _datetime.datetime.__dict__["resolution"] is _datetime.datetime.resolution
assert _datetime.timedelta.__dict__["min"] is _datetime.timedelta.min
assert _datetime.timedelta.__dict__["max"] is _datetime.timedelta.max
assert _datetime.timedelta.__dict__["resolution"] is _datetime.timedelta.resolution
assert _datetime.timezone.__dict__["min"] is _datetime.timezone.min
assert _datetime.timezone.__dict__["max"] is _datetime.timezone.max
assert _datetime.timezone.__dict__["utc"] is _datetime.timezone.utc
assert isinstance(_datetime.timezone.min, _datetime.tzinfo)
assert isinstance(_datetime.timezone.max, _datetime.tzinfo)
assert isinstance(_datetime.timezone.utc, _datetime.tzinfo)
del sys.modules['_datetime']
""")
script_helper.assert_python_ok('-c', script)
def load_tests(loader, standard_tests, pattern):
standard_tests.addTest(ZoneInfoCompleteTest())

View file

@ -0,0 +1 @@
Fix wrong references of the :mod:`datetime` types after reloading the module.

View file

@ -7339,6 +7339,12 @@ _datetime_exec(PyObject *module)
static_assert(DI100Y == 25 * DI4Y - 1, "DI100Y");
assert(DI100Y == days_before_year(100+1));
if (reloading) {
for (size_t i = 0; i < Py_ARRAY_LENGTH(capi_types); i++) {
PyType_Modified(capi_types[i]);
}
}
if (set_current_module(interp, module) < 0) {
goto error;
}