mirror of
https://github.com/python/cpython.git
synced 2025-08-03 16:39:00 +00:00
[3.13] gh-123880: Allow recursive import of single-phase-init modules (GH-123950) (#124273)
gh-123880: Allow recursive import of single-phase-init modules (GH-123950)
(cherry picked from commit aee219f455
)
Co-authored-by: Petr Viktorin <encukou@gmail.com>
Co-authored-by: Shantanu <12621235+hauntsaninja@users.noreply.github.com>
Co-authored-by: Brett Cannon <brett@python.org>
This commit is contained in:
parent
8d5911ef6b
commit
de8dc92db7
6 changed files with 141 additions and 25 deletions
|
@ -814,6 +814,8 @@ static int clear_singlephase_extension(PyInterpreterState *interp,
|
|||
|
||||
// Currently, this is only used for testing.
|
||||
// (See _testinternalcapi.clear_extension().)
|
||||
// If adding another use, be careful about modules that import themselves
|
||||
// recursively (see gh-123880).
|
||||
int
|
||||
_PyImport_ClearExtension(PyObject *name, PyObject *filename)
|
||||
{
|
||||
|
@ -1321,12 +1323,16 @@ _extensions_cache_set(PyObject *path, PyObject *name,
|
|||
value = entry == NULL
|
||||
? NULL
|
||||
: (struct extensions_cache_value *)entry->value;
|
||||
/* We should never be updating an existing cache value. */
|
||||
assert(value == NULL);
|
||||
if (value != NULL) {
|
||||
PyErr_Format(PyExc_SystemError,
|
||||
"extension module %R is already cached", name);
|
||||
goto finally;
|
||||
/* gh-123880: If there's an existing cache value, it means a module is
|
||||
* being imported recursively from its PyInit_* or Py_mod_* function.
|
||||
* (That function presumably handles returning a partially
|
||||
* constructed module in such a case.)
|
||||
* We can reuse the existing cache value; it is owned by the cache.
|
||||
* (Entries get removed from it in exceptional circumstances,
|
||||
* after interpreter shutdown, and in runtime shutdown.)
|
||||
*/
|
||||
goto finally_oldvalue;
|
||||
}
|
||||
newvalue = alloc_extensions_cache_value();
|
||||
if (newvalue == NULL) {
|
||||
|
@ -1391,6 +1397,7 @@ finally:
|
|||
cleanup_old_cached_def(&olddefbase);
|
||||
}
|
||||
|
||||
finally_oldvalue:
|
||||
extensions_lock_release();
|
||||
if (key != NULL) {
|
||||
hashtable_destroy_str(key);
|
||||
|
@ -2127,6 +2134,7 @@ error:
|
|||
}
|
||||
|
||||
|
||||
// Used in _PyImport_ClearExtension; see notes there.
|
||||
static int
|
||||
clear_singlephase_extension(PyInterpreterState *interp,
|
||||
PyObject *name, PyObject *path)
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue