Skip to content

Commit 1700e33

Browse files
committed
pythongh-123880: Allow recursive import of single-phase-init modules
1 parent e9eedf1 commit 1700e33

File tree

1 file changed

+13
-5
lines changed

1 file changed

+13
-5
lines changed

Python/import.c

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -815,6 +815,8 @@ static int clear_singlephase_extension(PyInterpreterState *interp,
815815

816816
// Currently, this is only used for testing.
817817
// (See _testinternalcapi.clear_extension().)
818+
// If adding another use uses, careful about modules that import themselves
819+
// recursively (see gh-123880)
818820
int
819821
_PyImport_ClearExtension(PyObject *name, PyObject *filename)
820822
{
@@ -1322,12 +1324,16 @@ _extensions_cache_set(PyObject *path, PyObject *name,
13221324
value = entry == NULL
13231325
? NULL
13241326
: (struct extensions_cache_value *)entry->value;
1325-
/* We should never be updating an existing cache value. */
1326-
assert(value == NULL);
13271327
if (value != NULL) {
1328-
PyErr_Format(PyExc_SystemError,
1329-
"extension module %R is already cached", name);
1330-
goto finally;
1328+
/* gh-123880: If there's an existing cache value, it means a module is
1329+
* being imported recursively from its PyInit_* or Py_mod_* function.
1330+
* (That function presumably handles returning a partially
1331+
* constructed module in such a case.)
1332+
* We can reuse the existing cache value; it is owned byt the cache.
1333+
* (Entries get removed from it in exceptional circumstances,
1334+
* after interpreter shutdown, and in runtime shutdown.)
1335+
*/
1336+
goto finally_oldvalue;
13311337
}
13321338
newvalue = alloc_extensions_cache_value();
13331339
if (newvalue == NULL) {
@@ -1392,6 +1398,7 @@ _extensions_cache_set(PyObject *path, PyObject *name,
13921398
cleanup_old_cached_def(&olddefbase);
13931399
}
13941400

1401+
finally_oldvalue:
13951402
extensions_lock_release();
13961403
if (key != NULL) {
13971404
hashtable_destroy_str(key);
@@ -2128,6 +2135,7 @@ import_run_extension(PyThreadState *tstate, PyModInitFunction p0,
21282135
}
21292136

21302137

2138+
// Used in _PyImport_ClearExtension; see notes there
21312139
static int
21322140
clear_singlephase_extension(PyInterpreterState *interp,
21332141
PyObject *name, PyObject *path)

0 commit comments

Comments
 (0)