Skip to content

Commit 7268462

Browse files
committed
Resolve symlinks for args
This fixes running `pytest tests/test_foo.py::test_bar`, where `tests` is a symlink to `project/app/tests`: previously `project/app/conftest.py` would be ignored for fixtures then.
1 parent 24c83d7 commit 7268462

File tree

5 files changed

+71
-10
lines changed

5 files changed

+71
-10
lines changed

changelog/4108.bugfix.rst

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
Resolve symbolic links for args.
2+
3+
This fixes running ``pytest tests/test_foo.py::test_bar``, where ``tests``
4+
is a symlink to ``project/app/tests``:
5+
previously ``project/app/conftest.py`` would be ignored for fixtures then.

src/_pytest/fixtures.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1175,7 +1175,7 @@ def getfixtureinfo(self, node, func, cls, funcargs=True):
11751175
def pytest_plugin_registered(self, plugin):
11761176
nodeid = None
11771177
try:
1178-
p = py.path.local(plugin.__file__)
1178+
p = py.path.local(plugin.__file__).realpath()
11791179
except AttributeError:
11801180
pass
11811181
else:

src/_pytest/main.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -490,7 +490,7 @@ def _collect(self, arg):
490490
from _pytest.python import Package
491491

492492
names = self._parsearg(arg)
493-
argpath = names.pop(0)
493+
argpath = names.pop(0).realpath()
494494
paths = []
495495

496496
root = self

testing/acceptance_test.py

Lines changed: 17 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -753,16 +753,26 @@ def join_pythonpath(*dirs):
753753
monkeypatch.syspath_prepend(p)
754754

755755
# module picked up in symlink-ed directory:
756+
# It picks up local/lib/foo/bar (symlink) via sys.path.
756757
result = testdir.runpytest("--pyargs", "-v", "foo.bar")
757758
testdir.chdir()
758759
assert result.ret == 0
759-
result.stdout.fnmatch_lines(
760-
[
761-
"*lib/foo/bar/test_bar.py::test_bar*PASSED*",
762-
"*lib/foo/bar/test_bar.py::test_other*PASSED*",
763-
"*2 passed*",
764-
]
765-
)
760+
if hasattr(py.path.local, "mksymlinkto"):
761+
result.stdout.fnmatch_lines(
762+
[
763+
"lib/foo/bar/test_bar.py::test_bar <- local/lib/foo/bar/test_bar.py PASSED*",
764+
"lib/foo/bar/test_bar.py::test_other <- local/lib/foo/bar/test_bar.py PASSED*",
765+
"*2 passed*",
766+
]
767+
)
768+
else:
769+
result.stdout.fnmatch_lines(
770+
[
771+
"local/lib/foo/bar/test_bar.py::test_bar PASSED*",
772+
"local/lib/foo/bar/test_bar.py::test_other PASSED*",
773+
"*2 passed*",
774+
]
775+
)
766776

767777
def test_cmdline_python_package_not_exists(self, testdir):
768778
result = testdir.runpytest("--pyargs", "tpkgwhatv")

testing/test_conftest.py

Lines changed: 47 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
import py
55
import pytest
66
from _pytest.config import PytestPluginManager
7-
from _pytest.main import EXIT_NOTESTSCOLLECTED, EXIT_USAGEERROR
7+
from _pytest.main import EXIT_NOTESTSCOLLECTED, EXIT_OK, EXIT_USAGEERROR
88

99

1010
@pytest.fixture(scope="module", params=["global", "inpackage"])
@@ -186,6 +186,52 @@ def pytest_addoption(parser):
186186
assert "warning: could not load initial" not in result.stdout.str()
187187

188188

189+
@pytest.mark.skipif(
190+
not hasattr(py.path.local, "mksymlinkto"),
191+
reason="symlink not available on this platform",
192+
)
193+
def test_conftest_symlink(testdir):
194+
"""Ensure that conftest.py is used for resolved symlinks."""
195+
realtests = testdir.tmpdir.mkdir("real").mkdir("app").mkdir("tests")
196+
testdir.tmpdir.join("symlinktests").mksymlinkto(realtests)
197+
testdir.makepyfile(
198+
**{
199+
"real/app/tests/test_foo.py": "def test1(fixture): pass",
200+
"real/conftest.py": textwrap.dedent(
201+
"""
202+
import pytest
203+
204+
print("conftest_loaded")
205+
206+
@pytest.fixture
207+
def fixture():
208+
print("fixture_used")
209+
"""
210+
),
211+
}
212+
)
213+
result = testdir.runpytest("-vs", "symlinktests")
214+
result.stdout.fnmatch_lines(
215+
[
216+
"*conftest_loaded*",
217+
"real/app/tests/test_foo.py::test1 fixture_used",
218+
"PASSED",
219+
]
220+
)
221+
assert result.ret == EXIT_OK
222+
223+
realtests.ensure("__init__.py")
224+
result = testdir.runpytest("-vs", "symlinktests/test_foo.py::test1")
225+
result.stdout.fnmatch_lines(
226+
[
227+
"*conftest_loaded*",
228+
"real/app/tests/test_foo.py::test1 fixture_used",
229+
"PASSED",
230+
]
231+
)
232+
assert result.ret == EXIT_OK
233+
234+
189235
def test_no_conftest(testdir):
190236
testdir.makeconftest("assert 0")
191237
result = testdir.runpytest("--noconftest")

0 commit comments

Comments
 (0)