Skip to content

Commit b48f51e

Browse files
committed
Use Path() objects to store conftest files
Using Path().resolve() is better than py.path.realpath because it resolves to the correct path/drive in case-insensitive file systems (#5792): >>> from py.path import local >>> from pathlib import Path >>> >>> local('d:\\projects').realpath() local('d:\\projects') >>> Path('d:\\projects').resolve() WindowsPath('D:/projects') Fix #5819
1 parent cf5b544 commit b48f51e

File tree

2 files changed

+39
-8
lines changed

2 files changed

+39
-8
lines changed

src/_pytest/config/__init__.py

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -414,10 +414,7 @@ def _getconftestmodules(self, path):
414414
continue
415415
conftestpath = parent.join("conftest.py")
416416
if conftestpath.isfile():
417-
# Use realpath to avoid loading the same conftest twice
418-
# with build systems that create build directories containing
419-
# symlinks to actual files.
420-
mod = self._importconftest(conftestpath.realpath())
417+
mod = self._importconftest(conftestpath)
421418
clist.append(mod)
422419
self._dirpath2confmods[directory] = clist
423420
return clist
@@ -432,8 +429,14 @@ def _rget_with_confmod(self, name, path):
432429
raise KeyError(name)
433430

434431
def _importconftest(self, conftestpath):
432+
# Use a resolved Path object as key to avoid loading the same conftest twice
433+
# with build systems that create build directories containing
434+
# symlinks to actual files.
435+
# Using Path().resolve() is better than py.path.realpath because
436+
# it resolves to the correct path/drive in case-insensitive file systems (#5792)
437+
key = Path(str(conftestpath)).resolve()
435438
try:
436-
return self._conftestpath2mod[conftestpath]
439+
return self._conftestpath2mod[key]
437440
except KeyError:
438441
pkgpath = conftestpath.pypkgpath()
439442
if pkgpath is None:
@@ -450,7 +453,7 @@ def _importconftest(self, conftestpath):
450453
raise ConftestImportFailure(conftestpath, sys.exc_info())
451454

452455
self._conftest_plugins.add(mod)
453-
self._conftestpath2mod[conftestpath] = mod
456+
self._conftestpath2mod[key] = mod
454457
dirpath = conftestpath.dirpath()
455458
if dirpath in self._dirpath2confmods:
456459
for path, mods in self._dirpath2confmods.items():

testing/test_conftest.py

Lines changed: 30 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
1+
import os
12
import textwrap
3+
from pathlib import Path
24

35
import py
46

@@ -163,11 +165,12 @@ def test_setinitial_conftest_subdirs(testdir, name):
163165
subconftest = sub.ensure("conftest.py")
164166
conftest = PytestPluginManager()
165167
conftest_setinitial(conftest, [sub.dirpath()], confcutdir=testdir.tmpdir)
168+
key = Path(str(subconftest)).resolve()
166169
if name not in ("whatever", ".dotdir"):
167-
assert subconftest in conftest._conftestpath2mod
170+
assert key in conftest._conftestpath2mod
168171
assert len(conftest._conftestpath2mod) == 1
169172
else:
170-
assert subconftest not in conftest._conftestpath2mod
173+
assert key not in conftest._conftestpath2mod
171174
assert len(conftest._conftestpath2mod) == 0
172175

173176

@@ -275,6 +278,31 @@ def fixture():
275278
assert result.ret == ExitCode.OK
276279

277280

281+
@pytest.mark.skipif(
282+
os.path.normcase("x") != os.path.normcase("X"),
283+
reason="only relevant for case insensitive file systems",
284+
)
285+
def test_conftest_badcase(testdir):
286+
"""Check conftest.py loading when directory casing is wrong (#5792)."""
287+
testdir.tmpdir.mkdir("JenkinsRoot").mkdir("test")
288+
source = {"setup.py": "", "test/__init__.py": "", "test/conftest.py": ""}
289+
testdir.makepyfile(**{"JenkinsRoot/%s" % k: v for k, v in source.items()})
290+
291+
testdir.tmpdir.join("jenkinsroot/test").chdir()
292+
result = testdir.runpytest()
293+
assert result.ret == ExitCode.NO_TESTS_COLLECTED
294+
295+
296+
def test_conftest_uppercase(testdir):
297+
"""Check conftest.py whose qualified name contains uppercase characters (#5819)"""
298+
source = {"__init__.py": "", "Foo/conftest.py": "", "Foo/__init__.py": ""}
299+
testdir.makepyfile(**source)
300+
301+
testdir.tmpdir.chdir()
302+
result = testdir.runpytest()
303+
assert result.ret == ExitCode.NO_TESTS_COLLECTED
304+
305+
278306
def test_no_conftest(testdir):
279307
testdir.makeconftest("assert 0")
280308
result = testdir.runpytest("--noconftest")

0 commit comments

Comments
 (0)