Skip to content

Commit 0adcc21

Browse files
authored
Support venv detection on Windows with mingw Python (#12545)
Closes #12544
1 parent 0ed2d79 commit 0adcc21

File tree

5 files changed

+23
-66
lines changed

5 files changed

+23
-66
lines changed

AUTHORS

+1
Original file line numberDiff line numberDiff line change
@@ -454,6 +454,7 @@ Yusuke Kadowaki
454454
Yutian Li
455455
Yuval Shimon
456456
Zac Hatfield-Dodds
457+
Zach Snicker
457458
Zachary Kneupper
458459
Zachary OBrien
459460
Zhouxin Qiu

changelog/12544.improvement.rst

+4
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
The _in_venv function now detects Python virtual environments by checking
2+
for a pyvenv.cfg file, ensuring reliable detection on various platforms.
3+
4+
-- by :user:`zachsnickers`.

doc/en/reference/reference.rst

+7-7
Original file line numberDiff line numberDiff line change
@@ -1702,13 +1702,13 @@ passed multiple times. The expected format is ``name=value``. For example::
17021702
This would tell ``pytest`` to not look into typical subversion or
17031703
sphinx-build directories or into any ``tmp`` prefixed directory.
17041704

1705-
Additionally, ``pytest`` will attempt to intelligently identify and ignore a
1706-
virtualenv by the presence of an activation script. Any directory deemed to
1707-
be the root of a virtual environment will not be considered during test
1708-
collection unless ``--collect-in-virtualenv`` is given. Note also that
1709-
``norecursedirs`` takes precedence over ``--collect-in-virtualenv``; e.g. if
1710-
you intend to run tests in a virtualenv with a base directory that matches
1711-
``'.*'`` you *must* override ``norecursedirs`` in addition to using the
1705+
Additionally, ``pytest`` will attempt to intelligently identify and ignore
1706+
a virtualenv. Any directory deemed to be the root of a virtual environment
1707+
will not be considered during test collection unless
1708+
``--collect-in-virtualenv`` is given. Note also that ``norecursedirs``
1709+
takes precedence over ``--collect-in-virtualenv``; e.g. if you intend to
1710+
run tests in a virtualenv with a base directory that matches ``'.*'`` you
1711+
*must* override ``norecursedirs`` in addition to using the
17121712
``--collect-in-virtualenv`` flag.
17131713

17141714

src/_pytest/main.py

+3-13
Original file line numberDiff line numberDiff line change
@@ -369,22 +369,12 @@ def pytest_runtestloop(session: Session) -> bool:
369369

370370
def _in_venv(path: Path) -> bool:
371371
"""Attempt to detect if ``path`` is the root of a Virtual Environment by
372-
checking for the existence of the appropriate activate script."""
373-
bindir = path.joinpath("Scripts" if sys.platform.startswith("win") else "bin")
372+
checking for the existence of the pyvenv.cfg file.
373+
[https://peps.python.org/pep-0405/]"""
374374
try:
375-
if not bindir.is_dir():
376-
return False
375+
return path.joinpath("pyvenv.cfg").is_file()
377376
except OSError:
378377
return False
379-
activates = (
380-
"activate",
381-
"activate.csh",
382-
"activate.fish",
383-
"Activate",
384-
"Activate.bat",
385-
"Activate.ps1",
386-
)
387-
return any(fname.name in activates for fname in bindir.iterdir())
388378

389379

390380
def pytest_ignore_collect(collection_path: Path, config: Config) -> bool | None:

testing/test_collection.py

+8-46
Original file line numberDiff line numberDiff line change
@@ -152,20 +152,8 @@ def test_ignored_certain_directories(self, pytester: Pytester) -> None:
152152
assert "test_notfound" not in s
153153
assert "test_found" in s
154154

155-
@pytest.mark.parametrize(
156-
"fname",
157-
(
158-
"activate",
159-
"activate.csh",
160-
"activate.fish",
161-
"Activate",
162-
"Activate.bat",
163-
"Activate.ps1",
164-
),
165-
)
166-
def test_ignored_virtualenvs(self, pytester: Pytester, fname: str) -> None:
167-
bindir = "Scripts" if sys.platform.startswith("win") else "bin"
168-
ensure_file(pytester.path / "virtual" / bindir / fname)
155+
def test_ignored_virtualenvs(self, pytester: Pytester) -> None:
156+
ensure_file(pytester.path / "virtual" / "pyvenv.cfg")
169157
testfile = ensure_file(pytester.path / "virtual" / "test_invenv.py")
170158
testfile.write_text("def test_hello(): pass", encoding="utf-8")
171159

@@ -179,23 +167,11 @@ def test_ignored_virtualenvs(self, pytester: Pytester, fname: str) -> None:
179167
result = pytester.runpytest("virtual")
180168
assert "test_invenv" in result.stdout.str()
181169

182-
@pytest.mark.parametrize(
183-
"fname",
184-
(
185-
"activate",
186-
"activate.csh",
187-
"activate.fish",
188-
"Activate",
189-
"Activate.bat",
190-
"Activate.ps1",
191-
),
192-
)
193170
def test_ignored_virtualenvs_norecursedirs_precedence(
194-
self, pytester: Pytester, fname: str
171+
self, pytester: Pytester
195172
) -> None:
196-
bindir = "Scripts" if sys.platform.startswith("win") else "bin"
197173
# norecursedirs takes priority
198-
ensure_file(pytester.path / ".virtual" / bindir / fname)
174+
ensure_file(pytester.path / ".virtual" / "pyvenv.cfg")
199175
testfile = ensure_file(pytester.path / ".virtual" / "test_invenv.py")
200176
testfile.write_text("def test_hello(): pass", encoding="utf-8")
201177
result = pytester.runpytest("--collect-in-virtualenv")
@@ -204,27 +180,13 @@ def test_ignored_virtualenvs_norecursedirs_precedence(
204180
result = pytester.runpytest("--collect-in-virtualenv", ".virtual")
205181
assert "test_invenv" in result.stdout.str()
206182

207-
@pytest.mark.parametrize(
208-
"fname",
209-
(
210-
"activate",
211-
"activate.csh",
212-
"activate.fish",
213-
"Activate",
214-
"Activate.bat",
215-
"Activate.ps1",
216-
),
217-
)
218-
def test__in_venv(self, pytester: Pytester, fname: str) -> None:
183+
def test__in_venv(self, pytester: Pytester) -> None:
219184
"""Directly test the virtual env detection function"""
220-
bindir = "Scripts" if sys.platform.startswith("win") else "bin"
221-
# no bin/activate, not a virtualenv
185+
# no pyvenv.cfg, not a virtualenv
222186
base_path = pytester.mkdir("venv")
223187
assert _in_venv(base_path) is False
224-
# with bin/activate, totally a virtualenv
225-
bin_path = base_path.joinpath(bindir)
226-
bin_path.mkdir()
227-
bin_path.joinpath(fname).touch()
188+
# with pyvenv.cfg, totally a virtualenv
189+
base_path.joinpath("pyvenv.cfg").touch()
228190
assert _in_venv(base_path) is True
229191

230192
def test_custom_norecursedirs(self, pytester: Pytester) -> None:

0 commit comments

Comments
 (0)