Skip to content

Commit 7c49405

Browse files
committed
Don't allow __lazy_imports__ to work in try/except
1 parent c8c8838 commit 7c49405

File tree

5 files changed

+66
-73
lines changed

5 files changed

+66
-73
lines changed

Lib/test/test_import/__init__.py

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2630,6 +2630,22 @@ def test_compatibility_mode_used(self):
26302630

26312631
self.assertTrue("test.test_import.data.lazy_imports.basic2" in sys.modules)
26322632

2633+
def test_compatibility_mode_func(self):
2634+
try:
2635+
import test.test_import.data.lazy_imports.compatibility_mode_func
2636+
except ImportError as e:
2637+
self.fail('lazy import failed')
2638+
2639+
self.assertTrue("test.test_import.data.lazy_imports.basic2" in sys.modules)
2640+
2641+
def test_compatibility_mode_try_except(self):
2642+
try:
2643+
import test.test_import.data.lazy_imports.compatibility_mode_try_except
2644+
except ImportError as e:
2645+
self.fail('lazy import failed')
2646+
2647+
self.assertTrue("test.test_import.data.lazy_imports.basic2" in sys.modules)
2648+
26332649
def test_compatibility_mode_relative(self):
26342650
try:
26352651
import test.test_import.data.lazy_imports.basic_compatibility_mode_relative
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
__lazy_modules__ = ['test.test_import.data.lazy_imports.basic2']
2+
import test.test_import.data.lazy_imports.basic2
3+
test.test_import.data.lazy_imports.basic2.f()
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
__lazy_modules__ = ['test.test_import.data.lazy_imports.basic2']
2+
def f():
3+
import test.test_import.data.lazy_imports.basic2
4+
5+
f()
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
__lazy_modules__ = ['test.test_import.data.lazy_imports.basic2']
2+
try:
3+
import test.test_import.data.lazy_imports.basic2
4+
except:
5+
pass

Python/ceval.c

Lines changed: 37 additions & 73 deletions
Original file line numberDiff line numberDiff line change
@@ -2986,81 +2986,10 @@ _PyEval_SliceIndexNotNone(PyObject *v, Py_ssize_t *pi)
29862986
return 1;
29872987
}
29882988

2989-
int
2990-
check_lazy_import_comatibility(PyThreadState *tstate, PyObject *lazy_modules,
2991-
PyObject *builtins, PyObject *globals, PyObject *locals,
2992-
PyObject *name, PyObject *fromlist, PyObject *level,
2993-
PyObject **mod)
2994-
{
2995-
int ilevel = PyLong_AsInt(level);
2996-
if (ilevel == -1 && _PyErr_Occurred(tstate)) {
2997-
return -1;
2998-
}
2999-
3000-
PyObject *abs_name = _PyImport_GetAbsName(tstate, name, globals, ilevel);
3001-
if (abs_name == NULL) {
3002-
return -1;
3003-
}
3004-
3005-
int contains = PySequence_Contains(lazy_modules, abs_name);
3006-
Py_DECREF(abs_name);
3007-
if (contains < 0) {
3008-
return -1;
3009-
} else if (contains == 0) {
3010-
*mod = NULL;
3011-
return 0;
3012-
}
3013-
3014-
_PyInterpreterFrame *frame = _PyEval_GetFrame();
3015-
if (frame == NULL) {
3016-
PyErr_SetString(PyExc_RuntimeError, "no current frame");
3017-
return -1;
3018-
}
3019-
3020-
PyObject *import_func;
3021-
if (PyMapping_GetOptionalItem(frame->f_builtins, &_Py_ID(__import__), &import_func) < 0) {
3022-
return -1;
3023-
}
3024-
3025-
if (import_func == NULL) {
3026-
_PyErr_SetString(tstate, PyExc_ImportError, "__import__ not found");
3027-
return -1;
3028-
}
3029-
3030-
PyObject *final_mod = _PyImport_LazyImportModuleLevelObject(tstate, name, import_func, globals,
3031-
locals, fromlist, ilevel);
3032-
Py_DECREF(import_func);
3033-
if (final_mod == NULL) {
3034-
return -1;
3035-
}
3036-
*mod = final_mod;
3037-
return 0;
3038-
}
3039-
30402989
PyObject *
30412990
_PyEval_ImportName(PyThreadState *tstate, PyObject *builtins, PyObject *globals, PyObject *locals,
30422991
PyObject *name, PyObject *fromlist, PyObject *level)
30432992
{
3044-
// Check if this module should be imported lazily due to the compatbility mode support via
3045-
// __lazy_modules__.
3046-
PyObject *lazy_modules;
3047-
if (globals != NULL &&
3048-
PyMapping_GetOptionalItem(globals, &_Py_ID(__lazy_modules__), &lazy_modules) < 0) {
3049-
return NULL;
3050-
}
3051-
3052-
PyObject *res;
3053-
if (lazy_modules != NULL) {
3054-
int lazy = check_lazy_import_comatibility(tstate, lazy_modules, builtins, globals,
3055-
locals, name, fromlist, level, &res);
3056-
Py_DECREF(lazy_modules);
3057-
if (lazy < 0) {
3058-
return NULL;
3059-
} else if (res != NULL) {
3060-
return res;
3061-
}
3062-
}
3063-
30642993
PyObject *import_func;
30652994
if (PyMapping_GetOptionalItem(builtins, &_Py_ID(__import__), &import_func) < 0) {
30662995
return NULL;
@@ -3070,7 +2999,7 @@ _PyEval_ImportName(PyThreadState *tstate, PyObject *builtins, PyObject *globals,
30702999
return NULL;
30713000
}
30723001

3073-
res = _PyEval_ImportNameWithImport(tstate, import_func, globals, locals, name, fromlist, level);
3002+
PyObject *res = _PyEval_ImportNameWithImport(tstate, import_func, globals, locals, name, fromlist, level);
30743003
Py_DECREF(import_func);
30753004
return res;
30763005
}
@@ -3102,10 +3031,37 @@ _PyEval_ImportNameWithImport(PyThreadState *tstate, PyObject *import_func, PyObj
31023031
return res;
31033032
}
31043033

3034+
int
3035+
check_lazy_import_comatibility(PyThreadState *tstate, PyObject *globals,
3036+
PyObject *name, PyObject *level)
3037+
{
3038+
// Check if this module should be imported lazily due to the compatbility mode support via
3039+
// __lazy_modules__.
3040+
PyObject *lazy_modules = NULL;
3041+
if (globals != NULL &&
3042+
PyMapping_GetOptionalItem(globals, &_Py_ID(__lazy_modules__), &lazy_modules) < 0) {
3043+
return -1;
3044+
} else if (lazy_modules == NULL) {
3045+
return 0;
3046+
}
3047+
3048+
int ilevel = PyLong_AsInt(level);
3049+
if (ilevel == -1 && _PyErr_Occurred(tstate)) {
3050+
return -1;
3051+
}
3052+
3053+
PyObject *abs_name = _PyImport_GetAbsName(tstate, name, globals, ilevel);
3054+
if (abs_name == NULL) {
3055+
return -1;
3056+
}
3057+
3058+
return PySequence_Contains(lazy_modules, abs_name);
3059+
}
31053060

31063061
PyObject *
31073062
_PyEval_LazyImportName(PyThreadState *tstate, PyObject *builtins, PyObject *globals,
3108-
PyObject *locals, PyObject *name, PyObject *fromlist, PyObject *level, int lazy)
3063+
PyObject *locals, PyObject *name, PyObject *fromlist, PyObject *level,
3064+
int lazy)
31093065
{
31103066
PyObject *res = NULL;
31113067
// Check if global policy overrides the local syntax
@@ -3120,6 +3076,14 @@ _PyEval_LazyImportName(PyThreadState *tstate, PyObject *builtins, PyObject *glob
31203076
break;
31213077
}
31223078

3079+
if (!lazy) {
3080+
// see if __lazy_imports__ forces this to be lazy
3081+
lazy = check_lazy_import_comatibility(tstate, globals, name, level);
3082+
if (lazy < 0) {
3083+
return NULL;
3084+
}
3085+
}
3086+
31233087
if (!lazy) {
31243088
// Not a lazy import or lazy imports are disabled, fallback to the regular import
31253089
return _PyEval_ImportName(tstate, builtins, globals, locals, name, fromlist, level);

0 commit comments

Comments
 (0)