Skip to content
Merged
Show file tree
Hide file tree
Changes from 7 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions Lib/importlib/_bootstrap.py
Original file line number Diff line number Diff line change
Expand Up @@ -1307,6 +1307,14 @@ def _sanity_check(name, package, level):

def _find_and_load_unlocked(name, import_):
path = None
sys.audit(
"import",
name,
path,
getattr(sys, "path", None),
getattr(sys, "meta_path", None),
getattr(sys, "path_hooks", None)
)
parent = name.rpartition('.')[0]
parent_spec = None
if parent:
Expand Down
83 changes: 83 additions & 0 deletions Lib/test/audit-tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import contextlib
import os
import sys
import unittest.mock


class TestHook:
Expand Down Expand Up @@ -672,6 +673,88 @@ def hook(event, args):
assertEqual(event_script_path, tmp_file.name)
assertEqual(remote_event_script_path, tmp_file.name)

def test_import_module():
import importlib

with TestHook() as hook:
importlib.import_module("importlib") # already imported, won't get logged
importlib.import_module("email") # standard library module
importlib.import_module("pythoninfo") # random module
importlib.import_module(".audit_test_data.submodule", "test") # relative import
importlib.import_module("test.audit_test_data.submodule2") # absolute import
importlib.import_module("_testcapi") # extension module

actual = [a for e, a in hook.seen if e == "import"]
assertSequenceEqual(
[
("email", None, sys.path, sys.meta_path, sys.path_hooks),
("pythoninfo", None, sys.path, sys.meta_path, sys.path_hooks),
("test.audit_test_data.submodule", None, sys.path, sys.meta_path, sys.path_hooks),
("test.audit_test_data", None, sys.path, sys.meta_path, sys.path_hooks),
("test.audit_test_data.submodule2", None, sys.path, sys.meta_path, sys.path_hooks),
("_testcapi", None, sys.path, sys.meta_path, sys.path_hooks),
("_testcapi", unittest.mock.ANY, None, None, None)
],
actual,
)

def test_builtin__import__():
import importlib # noqa: F401

with TestHook() as hook:
__import__("importlib")
__import__("email")
__import__("pythoninfo")
__import__("audit_test_data.submodule", level=1, globals={"__package__": "test"})
__import__("test.audit_test_data.submodule2")
__import__("_testcapi")

actual = [a for e, a in hook.seen if e == "import"]
assertSequenceEqual(
[
("email", None, sys.path, sys.meta_path, sys.path_hooks),
("pythoninfo", None, sys.path, sys.meta_path, sys.path_hooks),
("test.audit_test_data.submodule", None, sys.path, sys.meta_path, sys.path_hooks),
("test.audit_test_data", None, sys.path, sys.meta_path, sys.path_hooks),
("test.audit_test_data.submodule2", None, sys.path, sys.meta_path, sys.path_hooks),
("_testcapi", None, sys.path, sys.meta_path, sys.path_hooks),
("_testcapi", unittest.mock.ANY, None, None, None)
],
actual,
)

def test_import_statement():
import importlib # noqa: F401
# Set __package__ so relative imports work
old_package = globals().get("__package__", None)
globals()["__package__"] = "test"

with TestHook() as hook:
import importlib # noqa: F401
import email # noqa: F401
import pythoninfo # noqa: F401
from .audit_test_data import submodule # noqa: F401
import test.audit_test_data.submodule2 # noqa: F401
import _testcapi # noqa: F401

globals()["__package__"] = old_package

actual = [a for e, a in hook.seen if e == "import"]
# Import statement ordering is different because the package is
# loaded first and then the submodule
assertSequenceEqual(
[
("email", None, sys.path, sys.meta_path, sys.path_hooks),
("pythoninfo", None, sys.path, sys.meta_path, sys.path_hooks),
("test.audit_test_data", None, sys.path, sys.meta_path, sys.path_hooks),
("test.audit_test_data.submodule", None, sys.path, sys.meta_path, sys.path_hooks),
("test.audit_test_data.submodule2", None, sys.path, sys.meta_path, sys.path_hooks),
("_testcapi", None, sys.path, sys.meta_path, sys.path_hooks),
("_testcapi", unittest.mock.ANY, None, None, None)
],
actual,
)

if __name__ == "__main__":
from test.support import suppress_msvcrt_asserts

Expand Down
Empty file.
Empty file.
Empty file.
9 changes: 9 additions & 0 deletions Lib/test/test_audit.py
Original file line number Diff line number Diff line change
Expand Up @@ -331,5 +331,14 @@ def test_sys_remote_exec(self):
if returncode:
self.fail(stderr)

def test_import_module(self):
self.do_test("test_import_module")

def test_builtin__import__(self):
self.do_test("test_builtin__import__")

def test_import_statement(self):
self.do_test("test_import_statement")

if __name__ == "__main__":
unittest.main()
1 change: 1 addition & 0 deletions Makefile.pre.in
Original file line number Diff line number Diff line change
Expand Up @@ -2590,6 +2590,7 @@ TESTSUBDIRS= idlelib/idle_test \
test/test_ast \
test/test_ast/data \
test/archivetestdata \
test/audit_test_data \
test/audiodata \
test/certdata \
test/certdata/capath \
Expand Down
27 changes: 0 additions & 27 deletions Python/import.c
Original file line number Diff line number Diff line change
Expand Up @@ -3681,33 +3681,6 @@ import_find_and_load(PyThreadState *tstate, PyObject *abs_name)

PyTime_t t1 = 0, accumulated_copy = accumulated;

PyObject *sys_path, *sys_meta_path, *sys_path_hooks;
if (PySys_GetOptionalAttrString("path", &sys_path) < 0) {
return NULL;
}
if (PySys_GetOptionalAttrString("meta_path", &sys_meta_path) < 0) {
Py_XDECREF(sys_path);
return NULL;
}
if (PySys_GetOptionalAttrString("path_hooks", &sys_path_hooks) < 0) {
Py_XDECREF(sys_meta_path);
Py_XDECREF(sys_path);
return NULL;
}
if (_PySys_Audit(tstate, "import", "OOOOO",
abs_name, Py_None, sys_path ? sys_path : Py_None,
sys_meta_path ? sys_meta_path : Py_None,
sys_path_hooks ? sys_path_hooks : Py_None) < 0) {
Py_XDECREF(sys_path_hooks);
Py_XDECREF(sys_meta_path);
Py_XDECREF(sys_path);
return NULL;
}
Py_XDECREF(sys_path_hooks);
Py_XDECREF(sys_meta_path);
Py_XDECREF(sys_path);


/* XOptions is initialized after first some imports.
* So we can't have negative cache before completed initialization.
* Anyway, importlib._find_and_load is much slower than
Expand Down
Loading