f()
self.assertIn("only allowed at module level", str(cm.exception))
+ def test_lazy_import_exec_in_class(self):
+ """lazy import via exec() inside a class should raise SyntaxError."""
+ # exec() inside a class body also has non-module-level locals.
+ with self.assertRaises(SyntaxError) as cm:
+ class C:
+ exec("lazy import json")
+
+ self.assertIn("only allowed at module level", str(cm.exception))
+
@support.requires_subprocess()
def test_lazy_import_exec_at_module_level(self):
"""lazy import via exec() at module level should work."""
f = test.test_lazy_import.data.eager_import_func.f
self.assertEqual(type(f()), type(sys))
+ def test_exec_import_func(self):
+ """Implicit lazy imports via exec() inside functions should be eager."""
+ sys.set_lazy_imports("all")
+
+ def f():
+ exec("import test.test_lazy_import.data.basic2")
+
+ f()
+ self.assertIn("test.test_lazy_import.data.basic2", sys.modules)
+
+ def test_exec_import_func_with_lazy_modules(self):
+ """__lazy_modules__ should not make exec() imports lazy inside functions."""
+ globals()["__lazy_modules__"] = ["test.test_lazy_import.data.basic2"]
+ try:
+ def f():
+ exec("import test.test_lazy_import.data.basic2")
+
+ f()
+ self.assertIn("test.test_lazy_import.data.basic2", sys.modules)
+ finally:
+ del globals()["__lazy_modules__"]
+
+ def test_exec_import_class(self):
+ """Implicit lazy imports via exec() inside classes should be eager."""
+ sys.set_lazy_imports("all")
+
+ class C:
+ exec("import test.test_lazy_import.data.basic2")
+
+ self.assertIsNotNone(C)
+ self.assertIn("test.test_lazy_import.data.basic2", sys.modules)
+
+ def test_exec_import_class_with_lazy_modules(self):
+ """__lazy_modules__ should not make exec() imports lazy inside classes."""
+ globals()["__lazy_modules__"] = ["test.test_lazy_import.data.basic2"]
+ try:
+ class C:
+ exec("import test.test_lazy_import.data.basic2")
+
+ self.assertIsNotNone(C)
+ self.assertIn("test.test_lazy_import.data.basic2", sys.modules)
+ finally:
+ del globals()["__lazy_modules__"]
+
class WithStatementTests(unittest.TestCase):
"""Tests for lazy imports in with statement context."""
return res;
}
+static int
+is_lazy_import_module_level(void)
+{
+ _PyInterpreterFrame *frame = _PyEval_GetFrame();
+ return frame != NULL && frame->f_globals == frame->f_locals;
+}
+
PyObject *
_PyEval_LazyImportName(PyThreadState *tstate, PyObject *builtins,
PyObject *globals, PyObject *locals, PyObject *name,
PyObject *fromlist, PyObject *level, int lazy)
{
PyObject *res = NULL;
+ PyImport_LazyImportsMode mode = PyImport_GetLazyImportsMode();
// Check if global policy overrides the local syntax
- switch (PyImport_GetLazyImportsMode()) {
+ switch (mode) {
case PyImport_LAZY_NONE:
lazy = 0;
break;
case PyImport_LAZY_ALL:
- lazy = 1;
+ if (!lazy) {
+ lazy = is_lazy_import_module_level();
+ }
break;
case PyImport_LAZY_NORMAL:
break;
}
- if (!lazy && PyImport_GetLazyImportsMode() != PyImport_LAZY_NONE) {
+ if (!lazy && mode != PyImport_LAZY_NONE && is_lazy_import_module_level()) {
// See if __lazy_modules__ forces this to be lazy.
lazy = check_lazy_import_compatibility(tstate, globals, name, level);
if (lazy < 0) {