Skip to content

Commit b03e27d

Browse files
committed
re scope bug fix
1 parent cfa863b commit b03e27d

4 files changed

Lines changed: 88 additions & 110 deletions

File tree

Include/internal/pycore_import.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,9 @@ 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_ResolveLazyImportFromAttr(
43+
PyThreadState *tstate, PyObject *package_name,
44+
PyObject *name, PyObject *attr);
4245
extern PyObject * _PyImport_TryLoadLazySubmodule(
4346
PyObject *mod_name, PyObject *attr_name);
4447
extern PyObject * _PyImport_LazyImportModuleLevelObject(

Lib/test/test_import/__init__.py

Lines changed: 0 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,6 @@
2929
from unittest import mock
3030
import _imp
3131

32-
from test import support
3332
from test.support import os_helper
3433
from test.support import (
3534
STDLIB_DIR,
@@ -417,27 +416,6 @@ def test_from_import_missing_attr_path_is_canonical(self):
417416
self.assertIn(cm.exception.name, {'posixpath', 'ntpath'})
418417
self.assertIsNotNone(cm.exception)
419418

420-
@support.requires_subprocess()
421-
def test_from_import_module_attr_from_non_package(self):
422-
code = textwrap.dedent("""
423-
import sys
424-
import types
425-
426-
module_name = 'test_from_import_module_attr_from_non_package'
427-
child_name = f'{module_name}.child'
428-
module = types.ModuleType(module_name)
429-
child = types.ModuleType(child_name)
430-
module.child = child
431-
sys.modules[module_name] = module
432-
433-
# A plain module can expose a module-valued attribute without
434-
# being a package, so from-import must return the attribute as-is.
435-
from test_from_import_module_attr_from_non_package import child as imported
436-
assert imported is child
437-
assert child_name not in sys.modules, child_name
438-
""")
439-
script_helper.assert_python_ok("-c", code)
440-
441419
def test_from_import_star_invalid_type(self):
442420
with ready_to_import() as (name, path):
443421
with open(path, 'w', encoding='utf-8') as f:

Python/ceval.c

Lines changed: 1 addition & 87 deletions
Original file line numberDiff line numberDiff line change
@@ -3123,99 +3123,13 @@ _PyEval_LazyImportName(PyThreadState *tstate, PyObject *builtins,
31233123
return res;
31243124
}
31253125

3126-
static PyObject *
3127-
import_from_resolve_module_attr(PyThreadState *tstate, PyObject *package_name,
3128-
PyObject *name, PyObject *attr)
3129-
{
3130-
if (!PyModule_Check(attr) || package_name == NULL
3131-
|| !PyUnicode_Check(package_name)) {
3132-
return Py_NewRef(attr);
3133-
}
3134-
3135-
/* Only packages can legitimately republish importable submodules here.
3136-
Plain modules may expose arbitrary module-valued attributes. */
3137-
PyObject *package = PyImport_GetModule(package_name);
3138-
if (package == NULL) {
3139-
if (_PyErr_Occurred(tstate)) {
3140-
return NULL;
3141-
}
3142-
return Py_NewRef(attr);
3143-
}
3144-
3145-
int is_package = PyObject_HasAttrWithError(package, &_Py_ID(__path__));
3146-
Py_DECREF(package);
3147-
if (is_package <= 0) {
3148-
if (is_package < 0) {
3149-
return NULL;
3150-
}
3151-
return Py_NewRef(attr);
3152-
}
3153-
3154-
PyObject *fullmodname = PyUnicode_FromFormat("%U.%U", package_name, name);
3155-
if (fullmodname == NULL) {
3156-
return NULL;
3157-
}
3158-
3159-
PyObject *attr_name;
3160-
if (PyObject_GetOptionalAttr(attr, &_Py_ID(__name__), &attr_name) < 0) {
3161-
Py_DECREF(fullmodname);
3162-
return NULL;
3163-
}
3164-
3165-
int matches = (attr_name != NULL && PyUnicode_Check(attr_name))
3166-
? PyObject_RichCompareBool(attr_name, fullmodname, Py_EQ)
3167-
: 0;
3168-
Py_XDECREF(attr_name);
3169-
if (matches <= 0) {
3170-
/* Not the canonical submodule (matches == 0), or compare failed
3171-
(matches < 0, exception set). */
3172-
Py_DECREF(fullmodname);
3173-
return matches < 0 ? NULL : Py_NewRef(attr);
3174-
}
3175-
3176-
/* If the package still caches a submodule object after its entry was
3177-
removed from sys.modules, import the canonical submodule again. */
3178-
PyObject *submod = PyImport_GetModule(fullmodname);
3179-
if (submod == NULL && !_PyErr_Occurred(tstate)) {
3180-
PyObject *imported = PyImport_ImportModuleLevelObject(
3181-
fullmodname, NULL, NULL, NULL, 0);
3182-
if (imported == NULL) {
3183-
Py_DECREF(fullmodname);
3184-
return NULL;
3185-
}
3186-
Py_DECREF(imported);
3187-
submod = PyImport_GetModule(fullmodname);
3188-
}
3189-
Py_DECREF(fullmodname);
3190-
if (submod != NULL) {
3191-
return submod;
3192-
}
3193-
if (_PyErr_Occurred(tstate)) {
3194-
return NULL;
3195-
}
3196-
return Py_NewRef(attr);
3197-
}
3198-
31993126
PyObject *
32003127
_PyEval_ImportFrom(PyThreadState *tstate, PyObject *v, PyObject *name)
32013128
{
32023129
PyObject *x;
32033130
PyObject *fullmodname, *mod_name, *origin, *mod_name_or_unknown, *errmsg, *spec;
32043131

32053132
if (PyObject_GetOptionalAttr(v, name, &x) != 0) {
3206-
if (x != NULL && PyModule_Check(x)) {
3207-
PyObject *resolved;
3208-
if (PyObject_GetOptionalAttr(v, &_Py_ID(__name__), &mod_name) < 0) {
3209-
Py_DECREF(x);
3210-
return NULL;
3211-
}
3212-
/* If this is a cached submodule, resolve it through sys.modules
3213-
so from-import repairs stale package entries. */
3214-
resolved = import_from_resolve_module_attr(tstate, mod_name, name, x);
3215-
Py_XDECREF(mod_name);
3216-
Py_DECREF(x);
3217-
return resolved;
3218-
}
32193133
return x;
32203134
}
32213135
/* Issue #17636: in case this failed because of a circular relative
@@ -3397,7 +3311,7 @@ _PyEval_LazyImportFrom(PyThreadState *tstate, _PyInterpreterFrame *frame, PyObje
33973311
return NULL;
33983312
}
33993313
if (ret != NULL) {
3400-
PyObject *resolved = import_from_resolve_module_attr(
3314+
PyObject *resolved = _PyImport_ResolveLazyImportFromAttr(
34013315
tstate, d->lz_from, name, ret);
34023316
Py_DECREF(ret);
34033317
Py_DECREF(mod);

Python/import.c

Lines changed: 84 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3885,6 +3885,76 @@ _PyImport_ResolveName(PyThreadState *tstate, PyObject *name,
38853885
return resolve_name(tstate, name, globals, level);
38863886
}
38873887

3888+
PyObject *
3889+
_PyImport_ResolveLazyImportFromAttr(PyThreadState *tstate,
3890+
PyObject *package_name,
3891+
PyObject *name, PyObject *attr)
3892+
{
3893+
/* Lazy from-imports repair evicted package submodules without
3894+
changing eager from-import behavior. */
3895+
if (!PyModule_Check(attr) || package_name == NULL
3896+
|| !PyUnicode_Check(package_name)) {
3897+
return Py_NewRef(attr);
3898+
}
3899+
3900+
PyObject *package = PyImport_GetModule(package_name);
3901+
if (package == NULL) {
3902+
if (_PyErr_Occurred(tstate)) {
3903+
return NULL;
3904+
}
3905+
return Py_NewRef(attr);
3906+
}
3907+
3908+
int is_package = PyObject_HasAttrWithError(package, &_Py_ID(__path__));
3909+
Py_DECREF(package);
3910+
if (is_package <= 0) {
3911+
if (is_package < 0) {
3912+
return NULL;
3913+
}
3914+
return Py_NewRef(attr);
3915+
}
3916+
3917+
PyObject *fullmodname = PyUnicode_FromFormat("%U.%U", package_name, name);
3918+
if (fullmodname == NULL) {
3919+
return NULL;
3920+
}
3921+
3922+
PyObject *attr_name;
3923+
if (PyObject_GetOptionalAttr(attr, &_Py_ID(__name__), &attr_name) < 0) {
3924+
Py_DECREF(fullmodname);
3925+
return NULL;
3926+
}
3927+
3928+
int matches = (attr_name != NULL && PyUnicode_Check(attr_name))
3929+
? PyObject_RichCompareBool(attr_name, fullmodname, Py_EQ)
3930+
: 0;
3931+
Py_XDECREF(attr_name);
3932+
if (matches <= 0) {
3933+
Py_DECREF(fullmodname);
3934+
return matches < 0 ? NULL : Py_NewRef(attr);
3935+
}
3936+
3937+
PyObject *submod = import_get_module(tstate, fullmodname);
3938+
if (submod == NULL && !_PyErr_Occurred(tstate)) {
3939+
PyObject *imported = PyImport_ImportModuleLevelObject(
3940+
fullmodname, NULL, NULL, NULL, 0);
3941+
if (imported == NULL) {
3942+
Py_DECREF(fullmodname);
3943+
return NULL;
3944+
}
3945+
Py_DECREF(imported);
3946+
submod = import_get_module(tstate, fullmodname);
3947+
}
3948+
Py_DECREF(fullmodname);
3949+
if (submod != NULL) {
3950+
return submod;
3951+
}
3952+
if (_PyErr_Occurred(tstate)) {
3953+
return NULL;
3954+
}
3955+
return Py_NewRef(attr);
3956+
}
3957+
38883958
PyObject *
38893959
_PyImport_LoadLazyImportTstate(PyThreadState *tstate, PyObject *lazy_import)
38903960
{
@@ -4004,7 +4074,20 @@ _PyImport_LoadLazyImportTstate(PyThreadState *tstate, PyObject *lazy_import)
40044074

40054075
if (lz->lz_attr != NULL && PyUnicode_Check(lz->lz_attr)) {
40064076
PyObject *from = obj;
4007-
obj = _PyEval_ImportFrom(tstate, from, lz->lz_attr);
4077+
obj = NULL;
4078+
PyObject *attr;
4079+
if (PyObject_GetOptionalAttr(from, lz->lz_attr, &attr) < 0) {
4080+
Py_DECREF(from);
4081+
goto error;
4082+
}
4083+
if (attr != NULL) {
4084+
obj = _PyImport_ResolveLazyImportFromAttr(
4085+
tstate, lz->lz_from, lz->lz_attr, attr);
4086+
Py_DECREF(attr);
4087+
}
4088+
else {
4089+
obj = _PyEval_ImportFrom(tstate, from, lz->lz_attr);
4090+
}
40084091
Py_DECREF(from);
40094092
if (obj == NULL) {
40104093
goto error;

0 commit comments

Comments
 (0)