Skip to content

Commit bf48d37

Browse files
committed
gh-152298: Propagate lazy submodule errors
1 parent fe0bfa3 commit bf48d37

3 files changed

Lines changed: 32 additions & 20 deletions

File tree

Include/internal/pycore_import.h

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,8 +39,10 @@ extern PyObject * _PyImport_GetAbsName(
3939
// Symbol is exported for the JIT on Windows builds.
4040
PyAPI_FUNC(PyObject *) _PyImport_LoadLazyImportTstate(
4141
PyThreadState *tstate, PyObject *lazy_import);
42-
extern PyObject * _PyImport_TryLoadLazySubmodule(
43-
PyObject *mod_name, PyObject *attr_name, PyObject *mod_dict);
42+
// Returns 1 with a new reference in result, 0 if not pending, or -1 on error.
43+
extern int _PyImport_TryLoadLazySubmodule(
44+
PyObject *mod_name, PyObject *attr_name, PyObject *mod_dict,
45+
PyObject **result);
4446
extern PyObject * _PyImport_LazyImportModuleLevelObject(
4547
PyThreadState *tstate, PyObject *name, PyObject *builtins,
4648
PyObject *globals, PyObject *locals, PyObject *fromlist, int level);

Objects/moduleobject.c

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1300,7 +1300,7 @@ _PyModule_IsPossiblyShadowing(PyObject *origin)
13001300
}
13011301

13021302
// Check if `name` is a lazily pending submodule of module `m`.
1303-
// Returns a new reference on success, or NULL with no error set.
1303+
// Returns a new reference on success, or NULL on miss or error.
13041304
static PyObject *
13051305
try_load_lazy_submodule(PyModuleObject *m, PyObject *name)
13061306
{
@@ -1313,11 +1313,11 @@ try_load_lazy_submodule(PyModuleObject *m, PyObject *name)
13131313
Py_DECREF(mod_name);
13141314
return NULL;
13151315
}
1316-
PyObject *result = _PyImport_TryLoadLazySubmodule(
1317-
mod_name, name, m->md_dict);
1316+
PyObject *result = NULL;
1317+
int lazy_rc = _PyImport_TryLoadLazySubmodule(
1318+
mod_name, name, m->md_dict, &result);
13181319
Py_DECREF(mod_name);
1319-
if (result == NULL) {
1320-
PyErr_Clear();
1320+
if (lazy_rc <= 0) {
13211321
return NULL;
13221322
}
13231323
return result;

Python/import.c

Lines changed: 23 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -4452,63 +4452,73 @@ register_from_lazy_on_parent(PyThreadState *tstate, PyObject *abs_name,
44524452
return res;
44534453
}
44544454

4455-
PyObject *
4455+
int
44564456
_PyImport_TryLoadLazySubmodule(PyObject *mod_name, PyObject *attr_name,
4457-
PyObject *mod_dict)
4457+
PyObject *mod_dict, PyObject **result)
44584458
{
4459+
*result = NULL;
4460+
44594461
PyInterpreterState *interp = _PyInterpreterState_GET();
44604462
PyObject *lazy_pending = LAZY_PENDING_SUBMODULES(interp);
44614463
if (lazy_pending == NULL) {
4462-
return NULL;
4464+
return 0;
44634465
}
44644466

44654467
PyObject *pending_set;
44664468
int rc = PyDict_GetItemRef(lazy_pending, mod_name, &pending_set);
4467-
if (rc <= 0) {
4468-
return NULL;
4469+
if (rc < 0) {
4470+
return -1;
4471+
}
4472+
if (rc == 0) {
4473+
return 0;
44694474
}
44704475

44714476
int contains = PySet_Contains(pending_set, attr_name);
4472-
if (contains <= 0) {
4477+
if (contains < 0) {
44734478
Py_DECREF(pending_set);
4474-
return NULL;
4479+
return -1;
4480+
}
4481+
if (contains == 0) {
4482+
Py_DECREF(pending_set);
4483+
return 0;
44754484
}
44764485

44774486
PyObject *full_name = PyUnicode_FromFormat("%U.%U", mod_name, attr_name);
44784487
if (full_name == NULL) {
44794488
Py_DECREF(pending_set);
4480-
return NULL;
4489+
return -1;
44814490
}
44824491

44834492
PyObject *mod = PyImport_ImportModuleLevelObject(
44844493
full_name, NULL, NULL, NULL, 0);
44854494
if (mod == NULL) {
44864495
Py_DECREF(pending_set);
44874496
Py_DECREF(full_name);
4488-
return NULL;
4497+
return -1;
44894498
}
44904499
Py_DECREF(mod);
44914500

44924501
PyObject *submod = PyImport_GetModule(full_name);
44934502
Py_DECREF(full_name);
44944503
if (submod == NULL) {
44954504
Py_DECREF(pending_set);
4496-
return NULL;
4505+
return -1;
44974506
}
44984507

44994508
if (PyDict_SetItem(mod_dict, attr_name, submod) < 0) {
45004509
Py_DECREF(pending_set);
45014510
Py_DECREF(submod);
4502-
return NULL;
4511+
return -1;
45034512
}
45044513

45054514
if (PySet_Discard(pending_set, attr_name) < 0) {
45064515
Py_DECREF(pending_set);
45074516
Py_DECREF(submod);
4508-
return NULL;
4517+
return -1;
45094518
}
45104519
Py_DECREF(pending_set);
4511-
return submod;
4520+
*result = submod;
4521+
return 1;
45124522
}
45134523

45144524
PyObject *

0 commit comments

Comments
 (0)