Skip to content

Commit a99b9d9

Browse files
gh-102251: Explicitly free state for test modules with state in test_import (#105085)
Co-authored-by: Erlend E. Aasland <[email protected]>
1 parent 60cfc6d commit a99b9d9

File tree

2 files changed

+31
-5
lines changed

2 files changed

+31
-5
lines changed

Lib/test/test_import/__init__.py

+10-4
Original file line numberDiff line numberDiff line change
@@ -2320,6 +2320,7 @@ def test_variants(self):
23202320
self.add_module_cleanup(name)
23212321
with self.subTest(name):
23222322
loaded = self.load(name)
2323+
self.addCleanup(loaded.module._clear_module_state)
23232324

23242325
self.check_common(loaded)
23252326
self.assertIsNot(loaded.snapshot.state_initialized, None)
@@ -2379,14 +2380,19 @@ def test_with_reinit_reloaded(self):
23792380
# Keep a reference around.
23802381
basic = self.load(self.NAME)
23812382

2382-
for name in [
2383-
f'{self.NAME}_with_reinit', # m_size == 0
2384-
f'{self.NAME}_with_state', # m_size > 0
2383+
for name, has_state in [
2384+
(f'{self.NAME}_with_reinit', False), # m_size == 0
2385+
(f'{self.NAME}_with_state', True), # m_size > 0
23852386
]:
23862387
self.add_module_cleanup(name)
2387-
with self.subTest(name):
2388+
with self.subTest(name=name, has_state=has_state):
23882389
loaded = self.load(name)
2390+
if has_state:
2391+
self.addCleanup(loaded.module._clear_module_state)
2392+
23892393
reloaded = self.re_load(name, loaded.module)
2394+
if has_state:
2395+
self.addCleanup(reloaded.module._clear_module_state)
23902396

23912397
self.check_common(loaded)
23922398
self.check_common(reloaded)

Modules/_testsinglephase.c

+21-1
Original file line numberDiff line numberDiff line change
@@ -248,6 +248,25 @@ basic__clear_globals(PyObject *self, PyObject *Py_UNUSED(ignored))
248248
basic__clear_globals_doc}
249249

250250

251+
PyDoc_STRVAR(basic__clear_module_state_doc, "_clear_module_state()\n\
252+
\n\
253+
Free the module state and set it to uninitialized.");
254+
255+
static PyObject *
256+
basic__clear_module_state(PyObject *self, PyObject *Py_UNUSED(ignored))
257+
{
258+
module_state *state = get_module_state(self);
259+
if (state != NULL) {
260+
clear_state(state);
261+
}
262+
Py_RETURN_NONE;
263+
}
264+
265+
#define _CLEAR_MODULE_STATE_METHODDEF \
266+
{"_clear_module_state", basic__clear_module_state, METH_NOARGS, \
267+
basic__clear_module_state_doc}
268+
269+
251270
/*********************************************/
252271
/* the _testsinglephase module (and aliases) */
253272
/*********************************************/
@@ -408,7 +427,7 @@ PyInit__testsinglephase_with_reinit(void)
408427
/* the _testsinglephase_with_state module */
409428
/******************************************/
410429

411-
/* This ia less typical of legacy extensions in the wild:
430+
/* This is less typical of legacy extensions in the wild:
412431
- single-phase init (same as _testsinglephase above)
413432
- has some module state
414433
- supports repeated initialization
@@ -424,6 +443,7 @@ static PyMethodDef TestMethods_WithState[] = {
424443
LOOK_UP_SELF_METHODDEF,
425444
SUM_METHODDEF,
426445
STATE_INITIALIZED_METHODDEF,
446+
_CLEAR_MODULE_STATE_METHODDEF,
427447
{NULL, NULL} /* sentinel */
428448
};
429449

0 commit comments

Comments
 (0)