Merge pull request #5792 from dynatrace-oss-contrib/bugfix/badcase
Fix pytest with mixed up filename casing.
This commit is contained in:
commit
955e542210
1
AUTHORS
1
AUTHORS
|
@ -55,6 +55,7 @@ Charnjit SiNGH (CCSJ)
|
||||||
Chris Lamb
|
Chris Lamb
|
||||||
Christian Boelsen
|
Christian Boelsen
|
||||||
Christian Fetzer
|
Christian Fetzer
|
||||||
|
Christian Neumüller
|
||||||
Christian Theunert
|
Christian Theunert
|
||||||
Christian Tismer
|
Christian Tismer
|
||||||
Christopher Gilling
|
Christopher Gilling
|
||||||
|
|
|
@ -0,0 +1,3 @@
|
||||||
|
Windows: Fix error that occurs in certain circumstances when loading
|
||||||
|
``conftest.py`` from a working directory that has casing other than the one stored
|
||||||
|
in the filesystem (e.g., ``c:\test`` instead of ``C:\test``).
|
|
@ -30,6 +30,7 @@ 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")
|
||||||
|
@ -366,7 +367,7 @@ class PytestPluginManager(PluginManager):
|
||||||
"""
|
"""
|
||||||
current = py.path.local()
|
current = py.path.local()
|
||||||
self._confcutdir = (
|
self._confcutdir = (
|
||||||
current.join(namespace.confcutdir, abs=True)
|
unique_path(current.join(namespace.confcutdir, abs=True))
|
||||||
if namespace.confcutdir
|
if namespace.confcutdir
|
||||||
else None
|
else None
|
||||||
)
|
)
|
||||||
|
@ -405,19 +406,18 @@ 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.realpath().parts():
|
for parent in directory.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")
|
||||||
if conftestpath.isfile():
|
if conftestpath.isfile():
|
||||||
# Use realpath to avoid loading the same conftest twice
|
mod = self._importconftest(conftestpath)
|
||||||
# with build systems that create build directories containing
|
|
||||||
# symlinks to actual files.
|
|
||||||
mod = self._importconftest(conftestpath.realpath())
|
|
||||||
clist.append(mod)
|
clist.append(mod)
|
||||||
self._dirpath2confmods[directory] = clist
|
self._dirpath2confmods[directory] = clist
|
||||||
return clist
|
return clist
|
||||||
|
@ -432,6 +432,10 @@ 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
|
||||||
|
# with build systems that create build directories containing
|
||||||
|
# symlinks to actual files.
|
||||||
|
conftestpath = unique_path(conftestpath)
|
||||||
try:
|
try:
|
||||||
return self._conftestpath2mod[conftestpath]
|
return self._conftestpath2mod[conftestpath]
|
||||||
except KeyError:
|
except KeyError:
|
||||||
|
|
|
@ -11,6 +11,7 @@ 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
|
||||||
|
|
||||||
|
@ -334,3 +335,12 @@ 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())))
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
import os.path
|
||||||
import textwrap
|
import textwrap
|
||||||
|
|
||||||
import py
|
import py
|
||||||
|
@ -5,6 +6,7 @@ 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):
|
||||||
|
@ -141,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(conf))
|
assert values[0].__file__.startswith(str(unique_path(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(conf))
|
assert values[0].__file__.startswith(str(unique_path(conf)))
|
||||||
|
|
||||||
|
|
||||||
def test_conftestcutdir_inplace_considered(testdir):
|
def test_conftestcutdir_inplace_considered(testdir):
|
||||||
|
@ -154,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(conf))
|
assert values[0].__file__.startswith(str(unique_path(conf)))
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize("name", "test tests whatever .dotdir".split())
|
@pytest.mark.parametrize("name", "test tests whatever .dotdir".split())
|
||||||
|
@ -164,7 +166,7 @@ def test_setinitial_conftest_subdirs(testdir, name):
|
||||||
conftest = PytestPluginManager()
|
conftest = PytestPluginManager()
|
||||||
conftest_setinitial(conftest, [sub.dirpath()], confcutdir=testdir.tmpdir)
|
conftest_setinitial(conftest, [sub.dirpath()], confcutdir=testdir.tmpdir)
|
||||||
if name not in ("whatever", ".dotdir"):
|
if name not in ("whatever", ".dotdir"):
|
||||||
assert subconftest in conftest._conftestpath2mod
|
assert unique_path(subconftest) in conftest._conftestpath2mod
|
||||||
assert len(conftest._conftestpath2mod) == 1
|
assert len(conftest._conftestpath2mod) == 1
|
||||||
else:
|
else:
|
||||||
assert subconftest not in conftest._conftestpath2mod
|
assert subconftest not in conftest._conftestpath2mod
|
||||||
|
@ -275,6 +277,21 @@ def test_conftest_symlink_files(testdir):
|
||||||
assert result.ret == ExitCode.OK
|
assert result.ret == ExitCode.OK
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.skipif(
|
||||||
|
os.path.normcase("x") != os.path.normcase("X"),
|
||||||
|
reason="only relevant for case insensitive file systems",
|
||||||
|
)
|
||||||
|
def test_conftest_badcase(testdir):
|
||||||
|
"""Check conftest.py loading when directory casing is wrong."""
|
||||||
|
testdir.tmpdir.mkdir("JenkinsRoot").mkdir("test")
|
||||||
|
source = {"setup.py": "", "test/__init__.py": "", "test/conftest.py": ""}
|
||||||
|
testdir.makepyfile(**{"JenkinsRoot/%s" % k: v for k, v in source.items()})
|
||||||
|
|
||||||
|
testdir.tmpdir.join("jenkinsroot/test").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")
|
||||||
|
|
Loading…
Reference in New Issue