diff --git a/changelog/4108.bugfix.rst b/changelog/4108.bugfix.rst new file mode 100644 index 00000000000..d136d59961f --- /dev/null +++ b/changelog/4108.bugfix.rst @@ -0,0 +1,5 @@ +Resolve symbolic links 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. diff --git a/src/_pytest/fixtures.py b/src/_pytest/fixtures.py index 3dec56a351e..1829cf411a4 100644 --- a/src/_pytest/fixtures.py +++ b/src/_pytest/fixtures.py @@ -1175,7 +1175,7 @@ def getfixtureinfo(self, node, func, cls, funcargs=True): def pytest_plugin_registered(self, plugin): nodeid = None try: - p = py.path.local(plugin.__file__) + p = py.path.local(plugin.__file__).realpath() except AttributeError: pass else: diff --git a/src/_pytest/main.py b/src/_pytest/main.py index bf4faaf6a9c..0171bda0cd3 100644 --- a/src/_pytest/main.py +++ b/src/_pytest/main.py @@ -490,7 +490,7 @@ def _collect(self, arg): from _pytest.python import Package names = self._parsearg(arg) - argpath = names.pop(0) + argpath = names.pop(0).realpath() paths = [] root = self diff --git a/testing/acceptance_test.py b/testing/acceptance_test.py index e324f55abbc..2a6c7574028 100644 --- a/testing/acceptance_test.py +++ b/testing/acceptance_test.py @@ -753,16 +753,26 @@ def join_pythonpath(*dirs): monkeypatch.syspath_prepend(p) # module picked up in symlink-ed directory: + # It picks up local/lib/foo/bar (symlink) via sys.path. result = testdir.runpytest("--pyargs", "-v", "foo.bar") testdir.chdir() assert result.ret == 0 - result.stdout.fnmatch_lines( - [ - "*lib/foo/bar/test_bar.py::test_bar*PASSED*", - "*lib/foo/bar/test_bar.py::test_other*PASSED*", - "*2 passed*", - ] - ) + if hasattr(py.path.local, "mksymlinkto"): + result.stdout.fnmatch_lines( + [ + "lib/foo/bar/test_bar.py::test_bar <- local/lib/foo/bar/test_bar.py PASSED*", + "lib/foo/bar/test_bar.py::test_other <- local/lib/foo/bar/test_bar.py PASSED*", + "*2 passed*", + ] + ) + else: + result.stdout.fnmatch_lines( + [ + "local/lib/foo/bar/test_bar.py::test_bar PASSED*", + "local/lib/foo/bar/test_bar.py::test_other PASSED*", + "*2 passed*", + ] + ) def test_cmdline_python_package_not_exists(self, testdir): result = testdir.runpytest("--pyargs", "tpkgwhatv") diff --git a/testing/test_conftest.py b/testing/test_conftest.py index 07da5d5eeab..a2df0ae376b 100644 --- a/testing/test_conftest.py +++ b/testing/test_conftest.py @@ -4,7 +4,7 @@ import py import pytest from _pytest.config import PytestPluginManager -from _pytest.main import EXIT_NOTESTSCOLLECTED, EXIT_USAGEERROR +from _pytest.main import EXIT_NOTESTSCOLLECTED, EXIT_OK, EXIT_USAGEERROR @pytest.fixture(scope="module", params=["global", "inpackage"]) @@ -186,6 +186,52 @@ def pytest_addoption(parser): assert "warning: could not load initial" not in result.stdout.str() +@pytest.mark.skipif( + not hasattr(py.path.local, "mksymlinkto"), + reason="symlink not available on this platform", +) +def test_conftest_symlink(testdir): + """Ensure that conftest.py is used for resolved symlinks.""" + realtests = testdir.tmpdir.mkdir("real").mkdir("app").mkdir("tests") + testdir.tmpdir.join("symlinktests").mksymlinkto(realtests) + testdir.makepyfile( + **{ + "real/app/tests/test_foo.py": "def test1(fixture): pass", + "real/conftest.py": textwrap.dedent( + """ + import pytest + + print("conftest_loaded") + + @pytest.fixture + def fixture(): + print("fixture_used") + """ + ), + } + ) + result = testdir.runpytest("-vs", "symlinktests") + result.stdout.fnmatch_lines( + [ + "*conftest_loaded*", + "real/app/tests/test_foo.py::test1 fixture_used", + "PASSED", + ] + ) + assert result.ret == EXIT_OK + + realtests.ensure("__init__.py") + result = testdir.runpytest("-vs", "symlinktests/test_foo.py::test1") + result.stdout.fnmatch_lines( + [ + "*conftest_loaded*", + "real/app/tests/test_foo.py::test1 fixture_used", + "PASSED", + ] + ) + assert result.ret == EXIT_OK + + def test_no_conftest(testdir): testdir.makeconftest("assert 0") result = testdir.runpytest("--noconftest")