Repository: theacodes/nox (python)

Issue:
reuse_existing should check the interpreter
If `reuse_existing=True` when creating a `Virtualenv`, but the interpreter has changed, then the environment should still be re-created.

Pull request:
Check whether interpreter changed and type (#123)
This is an attempt to fix #123 

The steps are the following
- Check virtualenv interpreter
- Check current interpreter
- If there is a match, do nothing. If they are different, recreate
- Check if the type of interpreter remains the same.

Not sure, but for the last case I made an assertion.

Patch:
diff --git a/nox/virtualenv.py b/nox/virtualenv.py
index 0e3bbca..67aee8a 100644
--- a/nox/virtualenv.py
+++ b/nox/virtualenv.py
@@ -313,12 +313,19 @@ class VirtualEnv(ProcessEnv):
         """Deletes any existing virtual environment"""
         if os.path.exists(self.location):
             if self.reuse_existing:
+                self._check_reused_environment()
                 return False
             else:
                 shutil.rmtree(self.location)
 
         return True
 
+    def _check_reused_environment(self) -> None:
+        """Check if reused environment type is the same."""
+        with open(os.path.join(self.location, "pyvenv.cfg")) as fp:
+            old_env = "virtualenv" if "virtualenv" in fp.read() else "venv"
+        assert old_env == self.venv_or_virtualenv
+
     @property
     def _resolved_interpreter(self) -> str:
         """Return the interpreter, appropriately resolved for the platform.
@@ -394,12 +401,25 @@ class VirtualEnv(ProcessEnv):
     def create(self) -> bool:
         """Create the virtualenv or venv."""
         if not self._clean_location():
-            logger.debug(
-                "Re-using existing virtual environment at {}.".format(
-                    self.location_name
-                )
+            original = nox.command.run(
+                [self._resolved_interpreter, "-c", "import sys; print(sys.prefix)"],
+                silent=True,
             )
-            return False
+            created = nox.command.run(
+                [
+                    os.path.join(self.location, "bin", "python"),
+                    "-c",
+                    "import sys; print(sys.real_prefix)",
+                ],
+                silent=True,
+            )
+            if original == created:
+                logger.debug(
+                    "Re-using existing virtual environment at {}.".format(
+                        self.location_name
+                    )
+                )
+                return False
 
         if self.venv_or_virtualenv == "virtualenv":
             cmd = [sys.executable, "-m", "virtualenv", self.location]


Test patch:
diff --git a/tests/test_virtualenv.py b/tests/test_virtualenv.py
index 75598d6..fb624cb 100644
--- a/tests/test_virtualenv.py
+++ b/tests/test_virtualenv.py
@@ -244,6 +244,9 @@ def test__clean_location(monkeypatch, make_one):
 
     # Don't re-use existing, but doesn't currently exist.
     # Should return True indicating that the venv needs to be created.
+    monkeypatch.setattr(
+        nox.virtualenv.VirtualEnv, "_check_reused_environment", mock.MagicMock()
+    )
     monkeypatch.delattr(nox.virtualenv.shutil, "rmtree")
     assert not dir_.check()
     assert venv._clean_location()
@@ -289,7 +292,7 @@ def test_bin_windows(make_one):
     assert dir_.join("Scripts").strpath == venv.bin
 
 
-def test_create(make_one):
+def test_create(monkeypatch, make_one):
     venv, dir_ = make_one()
     venv.create()
 
@@ -312,10 +315,26 @@ def test_create(make_one):
     dir_.ensure("test.txt")
     assert dir_.join("test.txt").check()
     venv.reuse_existing = True
+    monkeypatch.setattr(nox.virtualenv.nox.command, "run", mock.MagicMock())
     venv.create()
     assert dir_.join("test.txt").check()
 
 
+def test_create_check_interpreter(make_one, monkeypatch, tmpdir):
+    cmd_mock = mock.MagicMock(
+        side_effect=["python-1", "python-1", "python-2", "python-3", "python-4"]
+    )
+    monkeypatch.setattr(nox.virtualenv.nox.command, "run", cmd_mock)
+    test_dir = tmpdir.mkdir("pytest")
+    fp = test_dir.join("pyvenv.cfg")
+    fp.write("virtualenv")
+    venv, dir_ = make_one()
+    venv.reuse_existing = True
+    venv.location = test_dir.strpath
+    assert not venv.create()
+    assert venv.create()
+
+
 def test_create_venv_backend(make_one):
     venv, dir_ = make_one(venv=True)
     venv.create()