diff --git a/changelog/4956.feature.rst b/changelog/4956.feature.rst new file mode 100644 index 000000000..ab8357cda --- /dev/null +++ b/changelog/4956.feature.rst @@ -0,0 +1 @@ +pytester's ``testdir.spawn`` uses ``tmpdir`` as HOME/USERPROFILE directory. diff --git a/src/_pytest/pytester.py b/src/_pytest/pytester.py index 1360d8d2f..605451630 100644 --- a/src/_pytest/pytester.py +++ b/src/_pytest/pytester.py @@ -508,6 +508,10 @@ class Testdir(object): # Discard outer pytest options. mp.delenv("PYTEST_ADDOPTS", raising=False) + # Environment (updates) for inner runs. + tmphome = str(self.tmpdir) + self._env_run_update = {"HOME": tmphome, "USERPROFILE": tmphome} + def __repr__(self): return "" % (self.tmpdir,) @@ -804,8 +808,8 @@ class Testdir(object): try: # Do not load user config (during runs only). mp_run = MonkeyPatch() - mp_run.setenv("HOME", str(self.tmpdir)) - mp_run.setenv("USERPROFILE", str(self.tmpdir)) + for k, v in self._env_run_update.items(): + mp_run.setenv(k, v) finalizers.append(mp_run.undo) # When running pytest inline any plugins active in the main test @@ -1045,9 +1049,7 @@ class Testdir(object): env["PYTHONPATH"] = os.pathsep.join( filter(None, [os.getcwd(), env.get("PYTHONPATH", "")]) ) - # Do not load user config. - env["HOME"] = str(self.tmpdir) - env["USERPROFILE"] = env["HOME"] + env.update(self._env_run_update) kw["env"] = env if stdin is Testdir.CLOSE_STDIN: @@ -1233,7 +1235,12 @@ class Testdir(object): if sys.platform.startswith("freebsd"): pytest.xfail("pexpect does not work reliably on freebsd") logfile = self.tmpdir.join("spawn.out").open("wb") - child = pexpect.spawn(cmd, logfile=logfile) + + # Do not load user config. + env = os.environ.copy() + env.update(self._env_run_update) + + child = pexpect.spawn(cmd, logfile=logfile, env=env) self.request.addfinalizer(logfile.close) child.timeout = expect_timeout return child diff --git a/testing/test_pytester.py b/testing/test_pytester.py index b76d413b7..54d364ca1 100644 --- a/testing/test_pytester.py +++ b/testing/test_pytester.py @@ -559,3 +559,29 @@ def test_popen_default_stdin_stderr_and_stdin_None(testdir): assert stdout.splitlines() == [b"", b"stdout"] assert stderr.splitlines() == [b"stderr"] assert proc.returncode == 0 + + +def test_spawn_uses_tmphome(testdir): + import os + + tmphome = str(testdir.tmpdir) + + # Does use HOME only during run. + assert os.environ.get("HOME") != tmphome + + testdir._env_run_update["CUSTOMENV"] = "42" + + p1 = testdir.makepyfile( + """ + import os + + def test(): + assert os.environ["HOME"] == {tmphome!r} + assert os.environ["CUSTOMENV"] == "42" + """.format( + tmphome=tmphome + ) + ) + child = testdir.spawn_pytest(str(p1)) + out = child.read() + assert child.wait() == 0, out.decode("utf8")