Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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
80 changes: 80 additions & 0 deletions Lib/test/audit-tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@
import contextlib
import os
import sys
import unittest.mock
from test.support import swap_item


class TestHook:
Expand Down Expand Up @@ -672,6 +674,84 @@ 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
with swap_item(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

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