summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorsunmy2019 <59365878+sunmy2019@users.noreply.github.com>2023-05-31 21:12:10 (GMT)
committerGitHub <noreply@github.com>2023-05-31 21:12:10 (GMT)
commita99b9d911e0f8cb11b3436bdd8eb649b15d01a50 (patch)
treef226e9abeb19a2f22bdaf52eebf824a62e350bcc
parent60cfc6d1ae01c89f9b390ea5eb6a582c8a53f971 (diff)
downloadcpython-a99b9d911e0f8cb11b3436bdd8eb649b15d01a50.zip
cpython-a99b9d911e0f8cb11b3436bdd8eb649b15d01a50.tar.gz
cpython-a99b9d911e0f8cb11b3436bdd8eb649b15d01a50.tar.bz2
gh-102251: Explicitly free state for test modules with state in test_import (#105085)
Co-authored-by: Erlend E. Aasland <erlend.aasland@protonmail.com>
-rw-r--r--Lib/test/test_import/__init__.py14
-rw-r--r--Modules/_testsinglephase.c22
2 files changed, 31 insertions, 5 deletions
diff --git a/Lib/test/test_import/__init__.py b/Lib/test/test_import/__init__.py
index e2384a0..227c912 100644
--- a/Lib/test/test_import/__init__.py
+++ b/Lib/test/test_import/__init__.py
@@ -2320,6 +2320,7 @@ class SinglephaseInitTests(unittest.TestCase):
self.add_module_cleanup(name)
with self.subTest(name):
loaded = self.load(name)
+ self.addCleanup(loaded.module._clear_module_state)
self.check_common(loaded)
self.assertIsNot(loaded.snapshot.state_initialized, None)
@@ -2379,14 +2380,19 @@ class SinglephaseInitTests(unittest.TestCase):
# Keep a reference around.
basic = self.load(self.NAME)
- for name in [
- f'{self.NAME}_with_reinit', # m_size == 0
- f'{self.NAME}_with_state', # m_size > 0
+ for name, has_state in [
+ (f'{self.NAME}_with_reinit', False), # m_size == 0
+ (f'{self.NAME}_with_state', True), # m_size > 0
]:
self.add_module_cleanup(name)
- with self.subTest(name):
+ with self.subTest(name=name, has_state=has_state):
loaded = self.load(name)
+ if has_state:
+ self.addCleanup(loaded.module._clear_module_state)
+
reloaded = self.re_load(name, loaded.module)
+ if has_state:
+ self.addCleanup(reloaded.module._clear_module_state)
self.check_common(loaded)
self.check_common(reloaded)
diff --git a/Modules/_testsinglephase.c b/Modules/_testsinglephase.c
index 8e6973f..dca7abf 100644
--- a/Modules/_testsinglephase.c
+++ b/Modules/_testsinglephase.c
@@ -248,6 +248,25 @@ basic__clear_globals(PyObject *self, PyObject *Py_UNUSED(ignored))
basic__clear_globals_doc}
+PyDoc_STRVAR(basic__clear_module_state_doc, "_clear_module_state()\n\
+\n\
+Free the module state and set it to uninitialized.");
+
+static PyObject *
+basic__clear_module_state(PyObject *self, PyObject *Py_UNUSED(ignored))
+{
+ module_state *state = get_module_state(self);
+ if (state != NULL) {
+ clear_state(state);
+ }
+ Py_RETURN_NONE;
+}
+
+#define _CLEAR_MODULE_STATE_METHODDEF \
+ {"_clear_module_state", basic__clear_module_state, METH_NOARGS, \
+ basic__clear_module_state_doc}
+
+
/*********************************************/
/* the _testsinglephase module (and aliases) */
/*********************************************/
@@ -408,7 +427,7 @@ finally:
/* the _testsinglephase_with_state module */
/******************************************/
-/* This ia less typical of legacy extensions in the wild:
+/* This is less typical of legacy extensions in the wild:
- single-phase init (same as _testsinglephase above)
- has some module state
- supports repeated initialization
@@ -424,6 +443,7 @@ static PyMethodDef TestMethods_WithState[] = {
LOOK_UP_SELF_METHODDEF,
SUM_METHODDEF,
STATE_INITIALIZED_METHODDEF,
+ _CLEAR_MODULE_STATE_METHODDEF,
{NULL, NULL} /* sentinel */
};