Skip to content

Commit 9422e10

Browse files
authored
Fix regression due to different cases on Windows (#5840)
Fix regression due to different cases on Windows
2 parents 73c5b7f + 5c3b4a6 commit 9422e10

File tree

4 files changed

+29
-27
lines changed

4 files changed

+29
-27
lines changed

changelog/5819.bugfix.rst

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Windows: Fix regression with conftest whose qualified name contains uppercase
2+
characters (introduced by #5792).

src/_pytest/config/__init__.py

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,6 @@
3030
from _pytest.compat import importlib_metadata
3131
from _pytest.outcomes import fail
3232
from _pytest.outcomes import Skipped
33-
from _pytest.pathlib import unique_path
3433
from _pytest.warning_types import PytestConfigWarning
3534

3635
hookimpl = HookimplMarker("pytest")
@@ -367,7 +366,7 @@ def _set_initial_conftests(self, namespace):
367366
"""
368367
current = py.path.local()
369368
self._confcutdir = (
370-
unique_path(current.join(namespace.confcutdir, abs=True))
369+
current.join(namespace.confcutdir, abs=True)
371370
if namespace.confcutdir
372371
else None
373372
)
@@ -406,13 +405,11 @@ def _getconftestmodules(self, path):
406405
else:
407406
directory = path
408407

409-
directory = unique_path(directory)
410-
411408
# XXX these days we may rather want to use config.rootdir
412409
# and allow users to opt into looking into the rootdir parent
413410
# directories instead of requiring to specify confcutdir
414411
clist = []
415-
for parent in directory.parts():
412+
for parent in directory.realpath().parts():
416413
if self._confcutdir and self._confcutdir.relto(parent):
417414
continue
418415
conftestpath = parent.join("conftest.py")
@@ -432,12 +429,14 @@ def _rget_with_confmod(self, name, path):
432429
raise KeyError(name)
433430

434431
def _importconftest(self, conftestpath):
435-
# Use realpath to avoid loading the same conftest twice
432+
# Use a resolved Path object as key to avoid loading the same conftest twice
436433
# with build systems that create build directories containing
437434
# symlinks to actual files.
438-
conftestpath = unique_path(conftestpath)
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()
439438
try:
440-
return self._conftestpath2mod[conftestpath]
439+
return self._conftestpath2mod[key]
441440
except KeyError:
442441
pkgpath = conftestpath.pypkgpath()
443442
if pkgpath is None:
@@ -454,7 +453,7 @@ def _importconftest(self, conftestpath):
454453
raise ConftestImportFailure(conftestpath, sys.exc_info())
455454

456455
self._conftest_plugins.add(mod)
457-
self._conftestpath2mod[conftestpath] = mod
456+
self._conftestpath2mod[key] = mod
458457
dirpath = conftestpath.dirpath()
459458
if dirpath in self._dirpath2confmods:
460459
for path, mods in self._dirpath2confmods.items():

src/_pytest/pathlib.py

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@
1111
from os.path import expanduser
1212
from os.path import expandvars
1313
from os.path import isabs
14-
from os.path import normcase
1514
from os.path import sep
1615
from posixpath import sep as posix_sep
1716

@@ -335,12 +334,3 @@ def fnmatch_ex(pattern, path):
335334
def parts(s):
336335
parts = s.split(sep)
337336
return {sep.join(parts[: i + 1]) or sep for i in range(len(parts))}
338-
339-
340-
def unique_path(path):
341-
"""Returns a unique path in case-insensitive (but case-preserving) file
342-
systems such as Windows.
343-
344-
This is needed only for ``py.path.local``; ``pathlib.Path`` handles this
345-
natively with ``resolve()``."""
346-
return type(path)(normcase(str(path.realpath())))

testing/test_conftest.py

Lines changed: 19 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
1-
import os.path
1+
import os
22
import textwrap
3+
from pathlib import Path
34

45
import py
56

67
import pytest
78
from _pytest.config import PytestPluginManager
89
from _pytest.main import ExitCode
9-
from _pytest.pathlib import unique_path
1010

1111

1212
def ConftestWithSetinitial(path):
@@ -143,11 +143,11 @@ def test_conftestcutdir(testdir):
143143
# but we can still import a conftest directly
144144
conftest._importconftest(conf)
145145
values = conftest._getconftestmodules(conf.dirpath())
146-
assert values[0].__file__.startswith(str(unique_path(conf)))
146+
assert values[0].__file__.startswith(str(conf))
147147
# and all sub paths get updated properly
148148
values = conftest._getconftestmodules(p)
149149
assert len(values) == 1
150-
assert values[0].__file__.startswith(str(unique_path(conf)))
150+
assert values[0].__file__.startswith(str(conf))
151151

152152

153153
def test_conftestcutdir_inplace_considered(testdir):
@@ -156,7 +156,7 @@ def test_conftestcutdir_inplace_considered(testdir):
156156
conftest_setinitial(conftest, [conf.dirpath()], confcutdir=conf.dirpath())
157157
values = conftest._getconftestmodules(conf.dirpath())
158158
assert len(values) == 1
159-
assert values[0].__file__.startswith(str(unique_path(conf)))
159+
assert values[0].__file__.startswith(str(conf))
160160

161161

162162
@pytest.mark.parametrize("name", "test tests whatever .dotdir".split())
@@ -165,11 +165,12 @@ def test_setinitial_conftest_subdirs(testdir, name):
165165
subconftest = sub.ensure("conftest.py")
166166
conftest = PytestPluginManager()
167167
conftest_setinitial(conftest, [sub.dirpath()], confcutdir=testdir.tmpdir)
168+
key = Path(str(subconftest)).resolve()
168169
if name not in ("whatever", ".dotdir"):
169-
assert unique_path(subconftest) in conftest._conftestpath2mod
170+
assert key in conftest._conftestpath2mod
170171
assert len(conftest._conftestpath2mod) == 1
171172
else:
172-
assert subconftest not in conftest._conftestpath2mod
173+
assert key not in conftest._conftestpath2mod
173174
assert len(conftest._conftestpath2mod) == 0
174175

175176

@@ -282,7 +283,7 @@ def fixture():
282283
reason="only relevant for case insensitive file systems",
283284
)
284285
def test_conftest_badcase(testdir):
285-
"""Check conftest.py loading when directory casing is wrong."""
286+
"""Check conftest.py loading when directory casing is wrong (#5792)."""
286287
testdir.tmpdir.mkdir("JenkinsRoot").mkdir("test")
287288
source = {"setup.py": "", "test/__init__.py": "", "test/conftest.py": ""}
288289
testdir.makepyfile(**{"JenkinsRoot/%s" % k: v for k, v in source.items()})
@@ -292,6 +293,16 @@ def test_conftest_badcase(testdir):
292293
assert result.ret == ExitCode.NO_TESTS_COLLECTED
293294

294295

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+
295306
def test_no_conftest(testdir):
296307
testdir.makeconftest("assert 0")
297308
result = testdir.runpytest("--noconftest")

0 commit comments

Comments
 (0)