Merge pull request #11315 from bluetech/pytest-monkeypatch-chdir
pytester: use `monkeypatch.chdir()` for dir changing
This commit is contained in:
commit
1a16bac131
|
@ -0,0 +1,3 @@
|
||||||
|
The :fixture:`pytester` fixture now uses the :fixture:`monkeypatch` fixture to manage the current working directory.
|
||||||
|
If you use ``pytester`` in combination with :func:`monkeypatch.undo() <pytest.MonkeyPatch.undo>`, the CWD might get restored.
|
||||||
|
Use :func:`monkeypatch.context() <pytest.MonkeyPatch.context>` instead.
|
|
@ -625,14 +625,6 @@ class RunResult:
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
class CwdSnapshot:
|
|
||||||
def __init__(self) -> None:
|
|
||||||
self.__saved = os.getcwd()
|
|
||||||
|
|
||||||
def restore(self) -> None:
|
|
||||||
os.chdir(self.__saved)
|
|
||||||
|
|
||||||
|
|
||||||
class SysModulesSnapshot:
|
class SysModulesSnapshot:
|
||||||
def __init__(self, preserve: Optional[Callable[[str], bool]] = None) -> None:
|
def __init__(self, preserve: Optional[Callable[[str], bool]] = None) -> None:
|
||||||
self.__preserve = preserve
|
self.__preserve = preserve
|
||||||
|
@ -696,15 +688,14 @@ class Pytester:
|
||||||
#: be added to the list. The type of items to add to the list depends on
|
#: be added to the list. The type of items to add to the list depends on
|
||||||
#: the method using them so refer to them for details.
|
#: the method using them so refer to them for details.
|
||||||
self.plugins: List[Union[str, _PluggyPlugin]] = []
|
self.plugins: List[Union[str, _PluggyPlugin]] = []
|
||||||
self._cwd_snapshot = CwdSnapshot()
|
|
||||||
self._sys_path_snapshot = SysPathsSnapshot()
|
self._sys_path_snapshot = SysPathsSnapshot()
|
||||||
self._sys_modules_snapshot = self.__take_sys_modules_snapshot()
|
self._sys_modules_snapshot = self.__take_sys_modules_snapshot()
|
||||||
self.chdir()
|
|
||||||
self._request.addfinalizer(self._finalize)
|
self._request.addfinalizer(self._finalize)
|
||||||
self._method = self._request.config.getoption("--runpytest")
|
self._method = self._request.config.getoption("--runpytest")
|
||||||
self._test_tmproot = tmp_path_factory.mktemp(f"tmp-{name}", numbered=True)
|
self._test_tmproot = tmp_path_factory.mktemp(f"tmp-{name}", numbered=True)
|
||||||
|
|
||||||
self._monkeypatch = mp = monkeypatch
|
self._monkeypatch = mp = monkeypatch
|
||||||
|
self.chdir()
|
||||||
mp.setenv("PYTEST_DEBUG_TEMPROOT", str(self._test_tmproot))
|
mp.setenv("PYTEST_DEBUG_TEMPROOT", str(self._test_tmproot))
|
||||||
# Ensure no unexpected caching via tox.
|
# Ensure no unexpected caching via tox.
|
||||||
mp.delenv("TOX_ENV_DIR", raising=False)
|
mp.delenv("TOX_ENV_DIR", raising=False)
|
||||||
|
@ -735,7 +726,6 @@ class Pytester:
|
||||||
"""
|
"""
|
||||||
self._sys_modules_snapshot.restore()
|
self._sys_modules_snapshot.restore()
|
||||||
self._sys_path_snapshot.restore()
|
self._sys_path_snapshot.restore()
|
||||||
self._cwd_snapshot.restore()
|
|
||||||
|
|
||||||
def __take_sys_modules_snapshot(self) -> SysModulesSnapshot:
|
def __take_sys_modules_snapshot(self) -> SysModulesSnapshot:
|
||||||
# Some zope modules used by twisted-related tests keep internal state
|
# Some zope modules used by twisted-related tests keep internal state
|
||||||
|
@ -760,7 +750,7 @@ class Pytester:
|
||||||
|
|
||||||
This is done automatically upon instantiation.
|
This is done automatically upon instantiation.
|
||||||
"""
|
"""
|
||||||
os.chdir(self.path)
|
self._monkeypatch.chdir(self.path)
|
||||||
|
|
||||||
def _makefile(
|
def _makefile(
|
||||||
self,
|
self,
|
||||||
|
|
|
@ -1080,14 +1080,14 @@ class TestImport:
|
||||||
name = "pointsback123"
|
name = "pointsback123"
|
||||||
ModuleType = type(os)
|
ModuleType = type(os)
|
||||||
p = tmpdir.ensure(name + ".py")
|
p = tmpdir.ensure(name + ".py")
|
||||||
|
with monkeypatch.context() as mp:
|
||||||
for ending in (".pyc", "$py.class", ".pyo"):
|
for ending in (".pyc", "$py.class", ".pyo"):
|
||||||
mod = ModuleType(name)
|
mod = ModuleType(name)
|
||||||
pseudopath = tmpdir.ensure(name + ending)
|
pseudopath = tmpdir.ensure(name + ending)
|
||||||
mod.__file__ = str(pseudopath)
|
mod.__file__ = str(pseudopath)
|
||||||
monkeypatch.setitem(sys.modules, name, mod)
|
mp.setitem(sys.modules, name, mod)
|
||||||
newmod = p.pyimport()
|
newmod = p.pyimport()
|
||||||
assert mod == newmod
|
assert mod == newmod
|
||||||
monkeypatch.undo()
|
|
||||||
mod = ModuleType(name)
|
mod = ModuleType(name)
|
||||||
pseudopath = tmpdir.ensure(name + "123.py")
|
pseudopath = tmpdir.ensure(name + "123.py")
|
||||||
mod.__file__ = str(pseudopath)
|
mod.__file__ = str(pseudopath)
|
||||||
|
|
|
@ -854,7 +854,11 @@ raise ValueError()
|
||||||
reprtb = p.repr_traceback(excinfo)
|
reprtb = p.repr_traceback(excinfo)
|
||||||
assert len(reprtb.reprentries) == 3
|
assert len(reprtb.reprentries) == 3
|
||||||
|
|
||||||
def test_traceback_short_no_source(self, importasmod, monkeypatch) -> None:
|
def test_traceback_short_no_source(
|
||||||
|
self,
|
||||||
|
importasmod,
|
||||||
|
monkeypatch: pytest.MonkeyPatch,
|
||||||
|
) -> None:
|
||||||
mod = importasmod(
|
mod = importasmod(
|
||||||
"""
|
"""
|
||||||
def func1():
|
def func1():
|
||||||
|
@ -866,14 +870,14 @@ raise ValueError()
|
||||||
excinfo = pytest.raises(ValueError, mod.entry)
|
excinfo = pytest.raises(ValueError, mod.entry)
|
||||||
from _pytest._code.code import Code
|
from _pytest._code.code import Code
|
||||||
|
|
||||||
monkeypatch.setattr(Code, "path", "bogus")
|
with monkeypatch.context() as mp:
|
||||||
|
mp.setattr(Code, "path", "bogus")
|
||||||
p = FormattedExcinfo(style="short")
|
p = FormattedExcinfo(style="short")
|
||||||
reprtb = p.repr_traceback_entry(excinfo.traceback[-2])
|
reprtb = p.repr_traceback_entry(excinfo.traceback[-2])
|
||||||
lines = reprtb.lines
|
lines = reprtb.lines
|
||||||
last_p = FormattedExcinfo(style="short")
|
last_p = FormattedExcinfo(style="short")
|
||||||
last_reprtb = last_p.repr_traceback_entry(excinfo.traceback[-1], excinfo)
|
last_reprtb = last_p.repr_traceback_entry(excinfo.traceback[-1], excinfo)
|
||||||
last_lines = last_reprtb.lines
|
last_lines = last_reprtb.lines
|
||||||
monkeypatch.undo()
|
|
||||||
assert lines[0] == " func1()"
|
assert lines[0] == " func1()"
|
||||||
|
|
||||||
assert last_lines[0] == ' raise ValueError("hello")'
|
assert last_lines[0] == ' raise ValueError("hello")'
|
||||||
|
|
|
@ -895,7 +895,11 @@ def test_rewritten():
|
||||||
)
|
)
|
||||||
|
|
||||||
@pytest.mark.skipif('"__pypy__" in sys.modules')
|
@pytest.mark.skipif('"__pypy__" in sys.modules')
|
||||||
def test_pyc_vs_pyo(self, pytester: Pytester, monkeypatch) -> None:
|
def test_pyc_vs_pyo(
|
||||||
|
self,
|
||||||
|
pytester: Pytester,
|
||||||
|
monkeypatch: pytest.MonkeyPatch,
|
||||||
|
) -> None:
|
||||||
pytester.makepyfile(
|
pytester.makepyfile(
|
||||||
"""
|
"""
|
||||||
import pytest
|
import pytest
|
||||||
|
@ -905,13 +909,13 @@ def test_rewritten():
|
||||||
)
|
)
|
||||||
p = make_numbered_dir(root=Path(pytester.path), prefix="runpytest-")
|
p = make_numbered_dir(root=Path(pytester.path), prefix="runpytest-")
|
||||||
tmp = "--basetemp=%s" % p
|
tmp = "--basetemp=%s" % p
|
||||||
monkeypatch.setenv("PYTHONOPTIMIZE", "2")
|
with monkeypatch.context() as mp:
|
||||||
monkeypatch.delenv("PYTHONDONTWRITEBYTECODE", raising=False)
|
mp.setenv("PYTHONOPTIMIZE", "2")
|
||||||
monkeypatch.delenv("PYTHONPYCACHEPREFIX", raising=False)
|
mp.delenv("PYTHONDONTWRITEBYTECODE", raising=False)
|
||||||
|
mp.delenv("PYTHONPYCACHEPREFIX", raising=False)
|
||||||
assert pytester.runpytest_subprocess(tmp).ret == 0
|
assert pytester.runpytest_subprocess(tmp).ret == 0
|
||||||
tagged = "test_pyc_vs_pyo." + PYTEST_TAG
|
tagged = "test_pyc_vs_pyo." + PYTEST_TAG
|
||||||
assert tagged + ".pyo" in os.listdir("__pycache__")
|
assert tagged + ".pyo" in os.listdir("__pycache__")
|
||||||
monkeypatch.undo()
|
|
||||||
monkeypatch.delenv("PYTHONDONTWRITEBYTECODE", raising=False)
|
monkeypatch.delenv("PYTHONDONTWRITEBYTECODE", raising=False)
|
||||||
monkeypatch.delenv("PYTHONPYCACHEPREFIX", raising=False)
|
monkeypatch.delenv("PYTHONPYCACHEPREFIX", raising=False)
|
||||||
assert pytester.runpytest_subprocess(tmp).ret == 1
|
assert pytester.runpytest_subprocess(tmp).ret == 1
|
||||||
|
|
|
@ -236,15 +236,15 @@ class TestImportPath:
|
||||||
name = "pointsback123"
|
name = "pointsback123"
|
||||||
p = tmp_path.joinpath(name + ".py")
|
p = tmp_path.joinpath(name + ".py")
|
||||||
p.touch()
|
p.touch()
|
||||||
|
with monkeypatch.context() as mp:
|
||||||
for ending in (".pyc", ".pyo"):
|
for ending in (".pyc", ".pyo"):
|
||||||
mod = ModuleType(name)
|
mod = ModuleType(name)
|
||||||
pseudopath = tmp_path.joinpath(name + ending)
|
pseudopath = tmp_path.joinpath(name + ending)
|
||||||
pseudopath.touch()
|
pseudopath.touch()
|
||||||
mod.__file__ = str(pseudopath)
|
mod.__file__ = str(pseudopath)
|
||||||
monkeypatch.setitem(sys.modules, name, mod)
|
mp.setitem(sys.modules, name, mod)
|
||||||
newmod = import_path(p, root=tmp_path)
|
newmod = import_path(p, root=tmp_path)
|
||||||
assert mod == newmod
|
assert mod == newmod
|
||||||
monkeypatch.undo()
|
|
||||||
mod = ModuleType(name)
|
mod = ModuleType(name)
|
||||||
pseudopath = tmp_path.joinpath(name + "123.py")
|
pseudopath = tmp_path.joinpath(name + "123.py")
|
||||||
pseudopath.touch()
|
pseudopath.touch()
|
||||||
|
|
|
@ -2,7 +2,6 @@ import os
|
||||||
import subprocess
|
import subprocess
|
||||||
import sys
|
import sys
|
||||||
import time
|
import time
|
||||||
from pathlib import Path
|
|
||||||
from types import ModuleType
|
from types import ModuleType
|
||||||
from typing import List
|
from typing import List
|
||||||
|
|
||||||
|
@ -11,7 +10,6 @@ import pytest
|
||||||
from _pytest.config import ExitCode
|
from _pytest.config import ExitCode
|
||||||
from _pytest.config import PytestPluginManager
|
from _pytest.config import PytestPluginManager
|
||||||
from _pytest.monkeypatch import MonkeyPatch
|
from _pytest.monkeypatch import MonkeyPatch
|
||||||
from _pytest.pytester import CwdSnapshot
|
|
||||||
from _pytest.pytester import HookRecorder
|
from _pytest.pytester import HookRecorder
|
||||||
from _pytest.pytester import LineMatcher
|
from _pytest.pytester import LineMatcher
|
||||||
from _pytest.pytester import Pytester
|
from _pytest.pytester import Pytester
|
||||||
|
@ -301,17 +299,6 @@ def test_assert_outcomes_after_pytest_error(pytester: Pytester) -> None:
|
||||||
result.assert_outcomes(passed=0)
|
result.assert_outcomes(passed=0)
|
||||||
|
|
||||||
|
|
||||||
def test_cwd_snapshot(pytester: Pytester) -> None:
|
|
||||||
foo = pytester.mkdir("foo")
|
|
||||||
bar = pytester.mkdir("bar")
|
|
||||||
os.chdir(foo)
|
|
||||||
snapshot = CwdSnapshot()
|
|
||||||
os.chdir(bar)
|
|
||||||
assert Path().absolute() == bar
|
|
||||||
snapshot.restore()
|
|
||||||
assert Path().absolute() == foo
|
|
||||||
|
|
||||||
|
|
||||||
class TestSysModulesSnapshot:
|
class TestSysModulesSnapshot:
|
||||||
key = "my-test-module"
|
key = "my-test-module"
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue