Fix regression due to different cases on Windows (#5840)

Fix regression due to different cases on Windows
This commit is contained in:
Bruno Oliveira 2019-09-13 18:11:12 -03:00 committed by GitHub
commit 9422e10322
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 29 additions and 27 deletions

View File

@ -0,0 +1,2 @@
Windows: Fix regression with conftest whose qualified name contains uppercase
characters (introduced by #5792).

View File

@ -30,7 +30,6 @@ from _pytest._code import filter_traceback
from _pytest.compat import importlib_metadata from _pytest.compat import importlib_metadata
from _pytest.outcomes import fail from _pytest.outcomes import fail
from _pytest.outcomes import Skipped from _pytest.outcomes import Skipped
from _pytest.pathlib import unique_path
from _pytest.warning_types import PytestConfigWarning from _pytest.warning_types import PytestConfigWarning
hookimpl = HookimplMarker("pytest") hookimpl = HookimplMarker("pytest")
@ -367,7 +366,7 @@ class PytestPluginManager(PluginManager):
""" """
current = py.path.local() current = py.path.local()
self._confcutdir = ( self._confcutdir = (
unique_path(current.join(namespace.confcutdir, abs=True)) current.join(namespace.confcutdir, abs=True)
if namespace.confcutdir if namespace.confcutdir
else None else None
) )
@ -406,13 +405,11 @@ class PytestPluginManager(PluginManager):
else: else:
directory = path directory = path
directory = unique_path(directory)
# XXX these days we may rather want to use config.rootdir # XXX these days we may rather want to use config.rootdir
# and allow users to opt into looking into the rootdir parent # and allow users to opt into looking into the rootdir parent
# directories instead of requiring to specify confcutdir # directories instead of requiring to specify confcutdir
clist = [] clist = []
for parent in directory.parts(): for parent in directory.realpath().parts():
if self._confcutdir and self._confcutdir.relto(parent): if self._confcutdir and self._confcutdir.relto(parent):
continue continue
conftestpath = parent.join("conftest.py") conftestpath = parent.join("conftest.py")
@ -432,12 +429,14 @@ class PytestPluginManager(PluginManager):
raise KeyError(name) raise KeyError(name)
def _importconftest(self, conftestpath): def _importconftest(self, conftestpath):
# Use realpath to avoid loading the same conftest twice # Use a resolved Path object as key to avoid loading the same conftest twice
# with build systems that create build directories containing # with build systems that create build directories containing
# symlinks to actual files. # symlinks to actual files.
conftestpath = unique_path(conftestpath) # Using Path().resolve() is better than py.path.realpath because
# it resolves to the correct path/drive in case-insensitive file systems (#5792)
key = Path(str(conftestpath)).resolve()
try: try:
return self._conftestpath2mod[conftestpath] return self._conftestpath2mod[key]
except KeyError: except KeyError:
pkgpath = conftestpath.pypkgpath() pkgpath = conftestpath.pypkgpath()
if pkgpath is None: if pkgpath is None:
@ -454,7 +453,7 @@ class PytestPluginManager(PluginManager):
raise ConftestImportFailure(conftestpath, sys.exc_info()) raise ConftestImportFailure(conftestpath, sys.exc_info())
self._conftest_plugins.add(mod) self._conftest_plugins.add(mod)
self._conftestpath2mod[conftestpath] = mod self._conftestpath2mod[key] = mod
dirpath = conftestpath.dirpath() dirpath = conftestpath.dirpath()
if dirpath in self._dirpath2confmods: if dirpath in self._dirpath2confmods:
for path, mods in self._dirpath2confmods.items(): for path, mods in self._dirpath2confmods.items():

View File

@ -11,7 +11,6 @@ from functools import partial
from os.path import expanduser from os.path import expanduser
from os.path import expandvars from os.path import expandvars
from os.path import isabs from os.path import isabs
from os.path import normcase
from os.path import sep from os.path import sep
from posixpath import sep as posix_sep from posixpath import sep as posix_sep
@ -335,12 +334,3 @@ def fnmatch_ex(pattern, path):
def parts(s): def parts(s):
parts = s.split(sep) parts = s.split(sep)
return {sep.join(parts[: i + 1]) or sep for i in range(len(parts))} return {sep.join(parts[: i + 1]) or sep for i in range(len(parts))}
def unique_path(path):
"""Returns a unique path in case-insensitive (but case-preserving) file
systems such as Windows.
This is needed only for ``py.path.local``; ``pathlib.Path`` handles this
natively with ``resolve()``."""
return type(path)(normcase(str(path.realpath())))

View File

@ -1,12 +1,12 @@
import os.path import os
import textwrap import textwrap
from pathlib import Path
import py import py
import pytest import pytest
from _pytest.config import PytestPluginManager from _pytest.config import PytestPluginManager
from _pytest.main import ExitCode from _pytest.main import ExitCode
from _pytest.pathlib import unique_path
def ConftestWithSetinitial(path): def ConftestWithSetinitial(path):
@ -143,11 +143,11 @@ def test_conftestcutdir(testdir):
# but we can still import a conftest directly # but we can still import a conftest directly
conftest._importconftest(conf) conftest._importconftest(conf)
values = conftest._getconftestmodules(conf.dirpath()) values = conftest._getconftestmodules(conf.dirpath())
assert values[0].__file__.startswith(str(unique_path(conf))) assert values[0].__file__.startswith(str(conf))
# and all sub paths get updated properly # and all sub paths get updated properly
values = conftest._getconftestmodules(p) values = conftest._getconftestmodules(p)
assert len(values) == 1 assert len(values) == 1
assert values[0].__file__.startswith(str(unique_path(conf))) assert values[0].__file__.startswith(str(conf))
def test_conftestcutdir_inplace_considered(testdir): def test_conftestcutdir_inplace_considered(testdir):
@ -156,7 +156,7 @@ def test_conftestcutdir_inplace_considered(testdir):
conftest_setinitial(conftest, [conf.dirpath()], confcutdir=conf.dirpath()) conftest_setinitial(conftest, [conf.dirpath()], confcutdir=conf.dirpath())
values = conftest._getconftestmodules(conf.dirpath()) values = conftest._getconftestmodules(conf.dirpath())
assert len(values) == 1 assert len(values) == 1
assert values[0].__file__.startswith(str(unique_path(conf))) assert values[0].__file__.startswith(str(conf))
@pytest.mark.parametrize("name", "test tests whatever .dotdir".split()) @pytest.mark.parametrize("name", "test tests whatever .dotdir".split())
@ -165,11 +165,12 @@ def test_setinitial_conftest_subdirs(testdir, name):
subconftest = sub.ensure("conftest.py") subconftest = sub.ensure("conftest.py")
conftest = PytestPluginManager() conftest = PytestPluginManager()
conftest_setinitial(conftest, [sub.dirpath()], confcutdir=testdir.tmpdir) conftest_setinitial(conftest, [sub.dirpath()], confcutdir=testdir.tmpdir)
key = Path(str(subconftest)).resolve()
if name not in ("whatever", ".dotdir"): if name not in ("whatever", ".dotdir"):
assert unique_path(subconftest) in conftest._conftestpath2mod assert key in conftest._conftestpath2mod
assert len(conftest._conftestpath2mod) == 1 assert len(conftest._conftestpath2mod) == 1
else: else:
assert subconftest not in conftest._conftestpath2mod assert key not in conftest._conftestpath2mod
assert len(conftest._conftestpath2mod) == 0 assert len(conftest._conftestpath2mod) == 0
@ -282,7 +283,7 @@ def test_conftest_symlink_files(testdir):
reason="only relevant for case insensitive file systems", reason="only relevant for case insensitive file systems",
) )
def test_conftest_badcase(testdir): def test_conftest_badcase(testdir):
"""Check conftest.py loading when directory casing is wrong.""" """Check conftest.py loading when directory casing is wrong (#5792)."""
testdir.tmpdir.mkdir("JenkinsRoot").mkdir("test") testdir.tmpdir.mkdir("JenkinsRoot").mkdir("test")
source = {"setup.py": "", "test/__init__.py": "", "test/conftest.py": ""} source = {"setup.py": "", "test/__init__.py": "", "test/conftest.py": ""}
testdir.makepyfile(**{"JenkinsRoot/%s" % k: v for k, v in source.items()}) testdir.makepyfile(**{"JenkinsRoot/%s" % k: v for k, v in source.items()})
@ -292,6 +293,16 @@ def test_conftest_badcase(testdir):
assert result.ret == ExitCode.NO_TESTS_COLLECTED assert result.ret == ExitCode.NO_TESTS_COLLECTED
def test_conftest_uppercase(testdir):
"""Check conftest.py whose qualified name contains uppercase characters (#5819)"""
source = {"__init__.py": "", "Foo/conftest.py": "", "Foo/__init__.py": ""}
testdir.makepyfile(**source)
testdir.tmpdir.chdir()
result = testdir.runpytest()
assert result.ret == ExitCode.NO_TESTS_COLLECTED
def test_no_conftest(testdir): def test_no_conftest(testdir):
testdir.makeconftest("assert 0") testdir.makeconftest("assert 0")
result = testdir.runpytest("--noconftest") result = testdir.runpytest("--noconftest")