Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

pytester: remove special handling of env during inner runs #6219

Merged
merged 1 commit into from
Nov 22, 2019

Conversation

blueyed
Copy link
Contributor

@blueyed blueyed commented Nov 18, 2019

No description provided.

@blueyed blueyed force-pushed the testdir-use-monkeypatch branch from 7908b3f to ba5b75c Compare November 18, 2019 15:02
@blueyed blueyed force-pushed the testdir-use-monkeypatch branch from d47d808 to ca7aa67 Compare November 18, 2019 15:42
Copy link
Member

@RonnyPfannschmidt RonnyPfannschmidt left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

sorry i missed that detail before

@RonnyPfannschmidt RonnyPfannschmidt self-requested a review November 18, 2019 16:57
Copy link
Member

@RonnyPfannschmidt RonnyPfannschmidt left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

sorry, also pressed the wrong button

@blueyed blueyed force-pushed the testdir-use-monkeypatch branch 2 times, most recently from 6e50749 to 8c47ce9 Compare November 18, 2019 21:02
blueyed added a commit to blueyed/pytest that referenced this pull request Nov 18, 2019
This gets done via the fixture itself.
Ref: pytest-dev#6219 (comment)
@blueyed blueyed force-pushed the testdir-use-monkeypatch branch 2 times, most recently from 2a3918d to 1c008e4 Compare November 18, 2019 22:09
@blueyed
Copy link
Contributor Author

blueyed commented Nov 18, 2019

I've extended test_testdir_respects_monkeypatch to show what this is meant to achieve: if a test uses monkeypatch.setenv("HOME", …) itself, it should also be used by the inner test run then.
Reworked the patch for this, not using the global monkeypatch fixture, but only for env updates.

@blueyed blueyed changed the title pytester: use monkeypatch fixture pytester: respect monkeypatch fixture for inner runs Nov 18, 2019
@nicoddemus
Copy link
Member

I've extended test_testdir_respects_monkeypatch to show what this is meant to achieve: if a test uses monkeypatch.setenv("HOME", …) itself, it should also be used by the inner test run then.
Reworked the patch for this, not using the global monkeypatch fixture, but only for env updates.

Hmmm what if we just set HOME and USERPROFILE during Testdir.__init__? Then tests which call monkeypatch.setenv("HOME", ...) will override the initial setting... something like this:

diff --git a/src/_pytest/pytester.py b/src/_pytest/pytester.py
index ca780a9f5..63384261b 100644
--- a/src/_pytest/pytester.py
+++ b/src/_pytest/pytester.py
@@ -359,8 +359,8 @@ def LineMatcher_fixture(request: FixtureRequest) -> "Type[LineMatcher]":
 
 
 @pytest.fixture
-def testdir(request: FixtureRequest, tmpdir_factory) -> "Testdir":
-    return Testdir(request, tmpdir_factory)
+def testdir(request: FixtureRequest, tmpdir_factory, monkeypatch) -> "Testdir":
+    return Testdir(request, tmpdir_factory, monkeypatch)
 
 
 @pytest.fixture
@@ -524,7 +524,7 @@ class Testdir:
     class TimeoutExpired(Exception):
         pass
 
-    def __init__(self, request, tmpdir_factory):
+    def __init__(self, request, tmpdir_factory, monkeypatch):
         self.request = request
         self._mod_collections = WeakKeyDictionary()
         name = request.function.__name__
@@ -547,7 +547,12 @@ class Testdir:
 
         # Environment (updates) for inner runs.
         tmphome = str(self.tmpdir)
-        self._env_run_update = {"HOME": tmphome, "USERPROFILE": tmphome}
+        self.monkeypatch = monkeypatch
+        if sys.platform.startswith("win"):
+            self.monkeypatch.setenv("USERPROFILE", tmphome)
+        else:
+            self.monkeypatch.setenv("HOME", tmphome)
+        self.monkeypatch.delenv("PYTEST_ADDOPTS", raising=False)
 
     def __repr__(self):
         return "<Testdir {!r}>".format(self.tmpdir)
@@ -853,12 +858,6 @@ class Testdir:
         plugins = list(plugins)
         finalizers = []
         try:
-            # Do not load user config (during runs only).
-            mp_run = MonkeyPatch()
-            for k, v in self._env_run_update.items():
-                mp_run.setenv(k, v)
-            finalizers.append(mp_run.undo)
-
             # Any sys.module or sys.path changes done while running pytest
             # inline should be reverted after the test run completes to avoid
             # clashing with later inline tests run within the same pytest test,
@@ -1091,7 +1090,6 @@ class Testdir:
         env["PYTHONPATH"] = os.pathsep.join(
             filter(None, [os.getcwd(), env.get("PYTHONPATH", "")])
         )
-        env.update(self._env_run_update)
         kw["env"] = env
 
         if stdin is Testdir.CLOSE_STDIN:
@@ -1261,11 +1259,7 @@ class Testdir:
             pytest.skip("pexpect.spawn not available")
         logfile = self.tmpdir.join("spawn.out").open("wb")
 
-        # Do not load user config.
-        env = os.environ.copy()
-        env.update(self._env_run_update)
-
-        child = pexpect.spawn(cmd, logfile=logfile, env=env)
+        child = pexpect.spawn(cmd, logfile=logfile)
         self.request.addfinalizer(logfile.close)
         child.timeout = expect_timeout
         return child
diff --git a/testing/test_pytester.py b/testing/test_pytester.py
index 758e999dc..8a044cb1a 100644
--- a/testing/test_pytester.py
+++ b/testing/test_pytester.py
@@ -674,3 +674,26 @@ def test_run_result_repr():
         repr(r) == "<RunResult ret=99 len(stdout.lines)=3"
         " len(stderr.lines)=4 duration=0.50s>"
     )
+
+
+@pytest.mark.parametrize("method", ("setenv", "delenv"))
+def test_testdir_respects_monkeypatch(method, testdir, monkeypatch):
+    testdir.makepyfile("""
+        import os
+        def test_home():
+            print("HOME:", os.environ.get("HOME"))
+    """)
+
+    if method == "setenv":
+        monkeypatch.setenv("HOME", "anotherhome")
+    else:
+        assert method == "delenv"
+        monkeypatch.delenv("HOME", raising=False)
+
+    result = testdir.runpytest("-vs")
+
+    if method == "setenv":
+        result.stdout.fnmatch_lines("*HOME: anotherhome*")
+    else:
+        assert method == "delenv"
+        result.stdout.fnmatch_lines("*HOME: None*")

This of course changes the behavior a bit, because the environment variables will be changed for the entire run, not only for the inner run...


assert os.environ["PYTEST_ADDOPTS"] == "--orig-unused"
@pytest.mark.parametrize("method", ("setenv", "delenv"))
def test_testdir_respects_monkeypatch(method, testdir, monkeypatch):
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Regardless if we follow my previous suggestion about using monkeypatch during Testdir.__init__, can we have a more user facing test here? The test I posted also works on your branch, and tests the actual behavior we want:

@pytest.mark.parametrize("method", ("setenv", "delenv"))
def test_testdir_respects_monkeypatch(method, testdir, monkeypatch):
    testdir.makepyfile("""
        import os
        def test_home():
            print("HOME:", os.environ.get("HOME"))
    """)

    if method == "setenv":
        monkeypatch.setenv("HOME", "anotherhome")
    else:
        assert method == "delenv"
        monkeypatch.delenv("HOME", raising=False)

    result = testdir.runpytest("-vs")

    if method == "setenv":
        result.stdout.fnmatch_lines("*HOME: anotherhome*")
    else:
        assert method == "delenv"
        result.stdout.fnmatch_lines("*HOME: None*")

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not strictly opposed - my initial test was meant to be a unit test for _get_env_run_update (which would be gone then though). It's much faster though (1.2s for 100 runs (200 passes), compared to 20s for the above).

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well I fear that by testing the inner mechanism and not testing the expected behavior, we might introduce a regression later and fail to notice. But I will leave this one to you.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this is covered by existing/changed tests.

@blueyed
Copy link
Contributor Author

blueyed commented Nov 19, 2019

Hmmm what if we just set HOME and USERPROFILE during Testdir.__init__? Then tests which call monkeypatch.setenv("HOME", ...) will override the initial setting... something like this:

This of course changes the behavior a bit, because the environment variables will be changed for the entire run, not only for the inner run...

Which makes a difference for ~/.pdbrc etc. IIRC this was the main motivation for doing this during inner runs / for subprocesses only.
But it's still an issue in there then, of course, so e.g. with pdbpp I am using / experimenting with using the "real home" for its config (via pwd.getpwuid(os.getuid()).pw_dir). Therefore I'm not opposed to keeping it separate really (from the main monkeypatch used there).

It does not need to use the existing/global monkeypatch fixture in the first place anymore then though, does it?

@blueyed
Copy link
Contributor Author

blueyed commented Nov 19, 2019

I'll change it, removing _env_run_update.

@blueyed blueyed force-pushed the testdir-use-monkeypatch branch from 1c008e4 to e6d54f7 Compare November 19, 2019 01:00
@blueyed blueyed changed the title pytester: respect monkeypatch fixture for inner runs pytester: remove special handling of env during inner runs Nov 19, 2019
@blueyed
Copy link
Contributor Author

blueyed commented Nov 20, 2019

@RonnyPfannschmidt @nicoddemus
Is this good now?

@blueyed blueyed requested a review from nicoddemus November 22, 2019 17:18
@blueyed blueyed force-pushed the testdir-use-monkeypatch branch from e6d54f7 to b0ebcfb Compare November 22, 2019 20:50
@blueyed
Copy link
Contributor Author

blueyed commented Nov 22, 2019

@nicoddemus
Thanks.
Had to resolve a conflict - please check again.

@nicoddemus
Copy link
Member

LGTM 👍

@blueyed blueyed merged commit a4408eb into pytest-dev:features Nov 22, 2019
@blueyed blueyed deleted the testdir-use-monkeypatch branch November 22, 2019 21:41
@blueyed
Copy link
Contributor Author

blueyed commented Nov 22, 2019

Thanks for the reviews - this unblocks #6164 then.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants