Skip to content

Commit de281fd

Browse files
committed
Add lazy import filter
1 parent 9eef03c commit de281fd

21 files changed

+343
-11
lines changed

Include/import.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,16 @@ PyAPI_FUNC(int) PyImport_AppendInittab(
8888
PyObject* (*initfunc)(void)
8989
);
9090

91+
typedef enum {
92+
PyLazyImportsMode_Default,
93+
PyLazyImportsMode_ForcedOff,
94+
PyLazyImportsMode_ForcedOn,
95+
} PyImport_LazyImportsMode;
96+
97+
PyAPI_FUNC(int) PyImport_SetLazyImports(PyImport_LazyImportsMode mode, PyObject *filter);
98+
99+
PyAPI_FUNC(PyImport_LazyImportsMode) PyImport_LazyImportsEnabled(void);
100+
91101
#ifndef Py_LIMITED_API
92102
# define Py_CPYTHON_IMPORT_H
93103
# include "cpython/import.h"

Include/internal/pycore_ceval.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -298,7 +298,7 @@ PyAPI_FUNC(void) _PyEval_FormatExcUnbound(PyThreadState *tstate, PyCodeObject *c
298298
PyAPI_FUNC(void) _PyEval_FormatKwargsError(PyThreadState *tstate, PyObject *func, PyObject *kwargs);
299299
PyAPI_FUNC(PyObject *) _PyEval_ImportFrom(PyThreadState *, PyObject *, PyObject *);
300300
PyAPI_FUNC(PyObject *) _PyEval_LazyImportName(PyThreadState *tstate, PyObject *builtins, PyObject *globals,
301-
PyObject *locals, PyObject *name, PyObject *fromlist, PyObject *level);
301+
PyObject *locals, PyObject *name, PyObject *fromlist, PyObject *level, int lazy);
302302
PyAPI_FUNC(PyObject *) _PyEval_LazyImportFrom(PyThreadState *tstate, PyObject *v, PyObject *name);
303303
PyAPI_FUNC(PyObject *) _PyEval_ImportName(PyThreadState *tstate, PyObject *builtins, PyObject *globals, PyObject *locals,
304304
PyObject *name, PyObject *fromlist, PyObject *level);

Include/internal/pycore_global_objects_fini_generated.h

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Include/internal/pycore_global_strings.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -574,6 +574,7 @@ struct _Py_global_strings {
574574
STRUCT_FOR_ID(last_type)
575575
STRUCT_FOR_ID(last_value)
576576
STRUCT_FOR_ID(latin1)
577+
STRUCT_FOR_ID(lazy)
577578
STRUCT_FOR_ID(leaf_size)
578579
STRUCT_FOR_ID(legacy)
579580
STRUCT_FOR_ID(len)

Include/internal/pycore_interp_structs.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -314,6 +314,8 @@ struct _import_state {
314314
#endif
315315
PyObject *import_func;
316316
PyObject *lazy_import_func;
317+
int lazy_imports_mode;
318+
PyObject *lazy_imports_filter;
317319
/* The global import lock. */
318320
_PyRecursiveMutex lock;
319321
/* diagnostic info in PyImport_ImportModuleLevelObject() */

Include/internal/pycore_runtime_init_generated.h

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Include/internal/pycore_unicodeobject_generated.h

Lines changed: 4 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Lib/importlib/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@
5959

6060
from ._bootstrap import __import__
6161

62-
from _imp import lazy_import
62+
from _imp import lazy_import, set_lazy_imports
6363

6464

6565
def invalidate_caches():

Lib/test/test_import/__init__.py

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2548,6 +2548,8 @@ def tearDown(self):
25482548
if key.startswith('test.test_import.data.lazy_imports'):
25492549
del sys.modules[key]
25502550

2551+
importlib.set_lazy_imports(None, None)
2552+
25512553
def test_basic_unused(self):
25522554
try:
25532555
import test.test_import.data.lazy_imports.basic_unused
@@ -2564,6 +2566,54 @@ def test_basic_used(self):
25642566

25652567
self.assertTrue("test.test_import.data.lazy_imports.basic2" in sys.modules)
25662568

2569+
def test_global_off(self):
2570+
try:
2571+
import test.test_import.data.lazy_imports.global_off
2572+
except ImportError as e:
2573+
self.fail('lazy import failed')
2574+
2575+
self.assertTrue("test.test_import.data.lazy_imports.basic2" in sys.modules)
2576+
2577+
def test_global_on(self):
2578+
try:
2579+
import test.test_import.data.lazy_imports.global_on
2580+
except ImportError as e:
2581+
self.fail('lazy import failed')
2582+
2583+
self.assertFalse("test.test_import.data.lazy_imports.basic2" in sys.modules)
2584+
2585+
def test_global_filter(self):
2586+
try:
2587+
import test.test_import.data.lazy_imports.global_filter
2588+
except ImportError as e:
2589+
self.fail('lazy import failed')
2590+
2591+
self.assertTrue("test.test_import.data.lazy_imports.basic2" in sys.modules)
2592+
2593+
def test_global_filter_true(self):
2594+
try:
2595+
import test.test_import.data.lazy_imports.global_filter_true
2596+
except ImportError as e:
2597+
self.fail('lazy import failed')
2598+
2599+
self.assertFalse("test.test_import.data.lazy_imports.basic2" in sys.modules)
2600+
2601+
def test_global_filter_from(self):
2602+
try:
2603+
import test.test_import.data.lazy_imports.global_filter
2604+
except ImportError as e:
2605+
self.fail('lazy import failed')
2606+
2607+
self.assertTrue("test.test_import.data.lazy_imports.basic2" in sys.modules)
2608+
2609+
def test_global_filter_from_true(self):
2610+
try:
2611+
import test.test_import.data.lazy_imports.global_filter_true
2612+
except ImportError as e:
2613+
self.fail('lazy import failed')
2614+
2615+
self.assertFalse("test.test_import.data.lazy_imports.basic2" in sys.modules)
2616+
25672617

25682618
class TestSinglePhaseSnapshot(ModuleSnapshot):
25692619
"""A representation of a single-phase init module for testing.
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
import importlib
2+
3+
def filter(module_name, imported_name, from_list):
4+
assert module_name == __name__
5+
assert imported_name == "test.test_import.data.lazy_imports.basic2"
6+
return False
7+
8+
importlib.set_lazy_imports(None, filter)
9+
10+
lazy import test.test_import.data.lazy_imports.basic2 as basic2

0 commit comments

Comments
 (0)