Switch from deprecated imp to importlib

This commit is contained in:
Anthony Sottile
2019-06-22 15:02:32 -07:00
parent 3d01dd3adf
commit 4cd08f9b52
13 changed files with 182 additions and 242 deletions
+13
View File
@@ -633,6 +633,19 @@ class TestInvocationVariants:
result.stdout.fnmatch_lines(["collected*0*items*/*1*errors"])
def test_pyargs_only_imported_once(self, testdir):
pkg = testdir.mkpydir("foo")
pkg.join("test_foo.py").write("print('hello from test_foo')\ndef test(): pass")
pkg.join("conftest.py").write(
"def pytest_configure(config): print('configuring')"
)
result = testdir.runpytest("--pyargs", "foo.test_foo", "-s", syspathinsert=True)
# should only import once
assert result.outlines.count("hello from test_foo") == 1
# should only configure once
assert result.outlines.count("configuring") == 1
def test_cmdline_python_package(self, testdir, monkeypatch):
import warnings
+2 -2
View File
@@ -137,8 +137,8 @@ class TestImportHookInstallation:
"hamster.py": "",
"test_foo.py": """\
def test_foo(pytestconfig):
assert pytestconfig.pluginmanager.rewrite_hook.find_module('ham') is not None
assert pytestconfig.pluginmanager.rewrite_hook.find_module('hamster') is None
assert pytestconfig.pluginmanager.rewrite_hook.find_spec('ham') is not None
assert pytestconfig.pluginmanager.rewrite_hook.find_spec('hamster') is None
""",
}
testdir.makepyfile(**contents)
+62 -53
View File
@@ -1,5 +1,6 @@
import ast
import glob
import importlib
import os
import py_compile
import stat
@@ -117,6 +118,37 @@ class TestAssertionRewrite:
result = testdir.runpytest_subprocess()
assert "warnings" not in "".join(result.outlines)
def test_rewrites_plugin_as_a_package(self, testdir):
pkgdir = testdir.mkpydir("plugin")
pkgdir.join("__init__.py").write(
"import pytest\n"
"@pytest.fixture\n"
"def special_asserter():\n"
" def special_assert(x, y):\n"
" assert x == y\n"
" return special_assert\n"
)
testdir.makeconftest('pytest_plugins = ["plugin"]')
testdir.makepyfile("def test(special_asserter): special_asserter(1, 2)\n")
result = testdir.runpytest()
result.stdout.fnmatch_lines(["*assert 1 == 2*"])
def test_honors_pep_235(self, testdir, monkeypatch):
# note: couldn't make it fail on macos with a single `sys.path` entry
# note: these modules are named `test_*` to trigger rewriting
testdir.tmpdir.join("test_y.py").write("x = 1")
xdir = testdir.tmpdir.join("x").ensure_dir()
xdir.join("test_Y").ensure_dir().join("__init__.py").write("x = 2")
testdir.makepyfile(
"import test_y\n"
"import test_Y\n"
"def test():\n"
" assert test_y.x == 1\n"
" assert test_Y.x == 2\n"
)
monkeypatch.syspath_prepend(xdir)
testdir.runpytest().assert_outcomes(passed=1)
def test_name(self, request):
def f():
assert False
@@ -831,8 +863,9 @@ def test_rewritten():
monkeypatch.setattr(
hook, "_warn_already_imported", lambda code, msg: warnings.append(msg)
)
hook.find_module("test_remember_rewritten_modules")
hook.load_module("test_remember_rewritten_modules")
spec = hook.find_spec("test_remember_rewritten_modules")
module = importlib.util.module_from_spec(spec)
hook.exec_module(module)
hook.mark_rewrite("test_remember_rewritten_modules")
hook.mark_rewrite("test_remember_rewritten_modules")
assert warnings == []
@@ -872,33 +905,6 @@ def test_rewritten():
class TestAssertionRewriteHookDetails:
def test_loader_is_package_false_for_module(self, testdir):
testdir.makepyfile(
test_fun="""
def test_loader():
assert not __loader__.is_package(__name__)
"""
)
result = testdir.runpytest()
result.stdout.fnmatch_lines(["* 1 passed*"])
def test_loader_is_package_true_for_package(self, testdir):
testdir.makepyfile(
test_fun="""
def test_loader():
assert not __loader__.is_package(__name__)
def test_fun():
assert __loader__.is_package('fun')
def test_missing():
assert not __loader__.is_package('pytest_not_there')
"""
)
testdir.mkpydir("fun")
result = testdir.runpytest()
result.stdout.fnmatch_lines(["* 3 passed*"])
def test_sys_meta_path_munged(self, testdir):
testdir.makepyfile(
"""
@@ -917,7 +923,7 @@ class TestAssertionRewriteHookDetails:
state = AssertionState(config, "rewrite")
source_path = tmpdir.ensure("source.py")
pycpath = tmpdir.join("pyc").strpath
assert _write_pyc(state, [1], source_path.stat(), pycpath)
assert _write_pyc(state, [1], os.stat(source_path.strpath), pycpath)
@contextmanager
def atomic_write_failed(fn, mode="r", overwrite=False):
@@ -979,7 +985,7 @@ class TestAssertionRewriteHookDetails:
assert len(contents) > strip_bytes
pyc.write(contents[:strip_bytes], mode="wb")
assert _read_pyc(source, str(pyc)) is None # no error
assert _read_pyc(str(source), str(pyc)) is None # no error
def test_reload_is_same(self, testdir):
# A file that will be picked up during collecting.
@@ -1186,14 +1192,17 @@ def test_rewrite_infinite_recursion(testdir, pytestconfig, monkeypatch):
# make a note that we have called _write_pyc
write_pyc_called.append(True)
# try to import a module at this point: we should not try to rewrite this module
assert hook.find_module("test_bar") is None
assert hook.find_spec("test_bar") is None
return original_write_pyc(*args, **kwargs)
monkeypatch.setattr(rewrite, "_write_pyc", spy_write_pyc)
monkeypatch.setattr(sys, "dont_write_bytecode", False)
hook = AssertionRewritingHook(pytestconfig)
assert hook.find_module("test_foo") is not None
spec = hook.find_spec("test_foo")
assert spec is not None
module = importlib.util.module_from_spec(spec)
hook.exec_module(module)
assert len(write_pyc_called) == 1
@@ -1201,11 +1210,11 @@ class TestEarlyRewriteBailout:
@pytest.fixture
def hook(self, pytestconfig, monkeypatch, testdir):
"""Returns a patched AssertionRewritingHook instance so we can configure its initial paths and track
if imp.find_module has been called.
if PathFinder.find_spec has been called.
"""
import imp
import importlib.machinery
self.find_module_calls = []
self.find_spec_calls = []
self.initial_paths = set()
class StubSession:
@@ -1214,22 +1223,22 @@ class TestEarlyRewriteBailout:
def isinitpath(self, p):
return p in self._initialpaths
def spy_imp_find_module(name, path):
self.find_module_calls.append(name)
return imp.find_module(name, path)
def spy_find_spec(name, path):
self.find_spec_calls.append(name)
return importlib.machinery.PathFinder.find_spec(name, path)
hook = AssertionRewritingHook(pytestconfig)
# use default patterns, otherwise we inherit pytest's testing config
hook.fnpats[:] = ["test_*.py", "*_test.py"]
monkeypatch.setattr(hook, "_imp_find_module", spy_imp_find_module)
monkeypatch.setattr(hook, "_find_spec", spy_find_spec)
hook.set_session(StubSession())
testdir.syspathinsert()
return hook
def test_basic(self, testdir, hook):
"""
Ensure we avoid calling imp.find_module when we know for sure a certain module will not be rewritten
to optimize assertion rewriting (#3918).
Ensure we avoid calling PathFinder.find_spec when we know for sure a certain
module will not be rewritten to optimize assertion rewriting (#3918).
"""
testdir.makeconftest(
"""
@@ -1244,24 +1253,24 @@ class TestEarlyRewriteBailout:
self.initial_paths.add(foobar_path)
# conftest files should always be rewritten
assert hook.find_module("conftest") is not None
assert self.find_module_calls == ["conftest"]
assert hook.find_spec("conftest") is not None
assert self.find_spec_calls == ["conftest"]
# files matching "python_files" mask should always be rewritten
assert hook.find_module("test_foo") is not None
assert self.find_module_calls == ["conftest", "test_foo"]
assert hook.find_spec("test_foo") is not None
assert self.find_spec_calls == ["conftest", "test_foo"]
# file does not match "python_files": early bailout
assert hook.find_module("bar") is None
assert self.find_module_calls == ["conftest", "test_foo"]
assert hook.find_spec("bar") is None
assert self.find_spec_calls == ["conftest", "test_foo"]
# file is an initial path (passed on the command-line): should be rewritten
assert hook.find_module("foobar") is not None
assert self.find_module_calls == ["conftest", "test_foo", "foobar"]
assert hook.find_spec("foobar") is not None
assert self.find_spec_calls == ["conftest", "test_foo", "foobar"]
def test_pattern_contains_subdirectories(self, testdir, hook):
"""If one of the python_files patterns contain subdirectories ("tests/**.py") we can't bailout early
because we need to match with the full path, which can only be found by calling imp.find_module.
because we need to match with the full path, which can only be found by calling PathFinder.find_spec
"""
p = testdir.makepyfile(
**{
@@ -1273,8 +1282,8 @@ class TestEarlyRewriteBailout:
)
testdir.syspathinsert(p.dirpath())
hook.fnpats[:] = ["tests/**.py"]
assert hook.find_module("file") is not None
assert self.find_module_calls == ["file"]
assert hook.find_spec("file") is not None
assert self.find_spec_calls == ["file"]
@pytest.mark.skipif(
sys.platform.startswith("win32"), reason="cannot remove cwd on Windows"
+5
View File
@@ -1,3 +1,4 @@
import os.path
import sys
import py
@@ -53,6 +54,10 @@ class TestPort:
def test_matching(self, match, pattern, path):
assert match(pattern, path)
def test_matching_abspath(self, match):
abspath = os.path.abspath(os.path.join("tests/foo.py"))
assert match("tests/foo.py", abspath)
@pytest.mark.parametrize(
"pattern, path",
[