fix issue436: improved finding of initial conftest files from command
line arguments by using the result of parse_known_args rather than the previous flaky heuristics. Thanks Marc Abramowitz for tests and initial fixing approaches in this area.
This commit is contained in:
parent
72b4534a0c
commit
3bca62e9e4
|
@ -11,6 +11,11 @@ NEXT (2.6)
|
||||||
- change skips into warnings for test classes with an __init__ and
|
- change skips into warnings for test classes with an __init__ and
|
||||||
callables in test modules which look like a test but are not functions.
|
callables in test modules which look like a test but are not functions.
|
||||||
|
|
||||||
|
- fix issue436: improved finding of initial conftest files from command
|
||||||
|
line arguments by using the result of parse_known_args rather than
|
||||||
|
the previous flaky heuristics. Thanks Marc Abramowitz for tests
|
||||||
|
and initial fixing approaches in this area.
|
||||||
|
|
||||||
- fix issue #479: properly handle nose/unittest(2) SkipTest exceptions
|
- fix issue #479: properly handle nose/unittest(2) SkipTest exceptions
|
||||||
during collection/loading of test modules. Thanks to Marc Schlaich
|
during collection/loading of test modules. Thanks to Marc Schlaich
|
||||||
for the complete PR.
|
for the complete PR.
|
||||||
|
|
|
@ -31,7 +31,7 @@ def pytest_addoption(parser):
|
||||||
|
|
||||||
@pytest.mark.tryfirst
|
@pytest.mark.tryfirst
|
||||||
def pytest_load_initial_conftests(early_config, parser, args, __multicall__):
|
def pytest_load_initial_conftests(early_config, parser, args, __multicall__):
|
||||||
ns = parser.parse_known_args(args)
|
ns = early_config.known_args_namespace
|
||||||
pluginmanager = early_config.pluginmanager
|
pluginmanager = early_config.pluginmanager
|
||||||
if ns.capture == "no":
|
if ns.capture == "no":
|
||||||
return
|
return
|
||||||
|
|
|
@ -449,38 +449,27 @@ class Conftest(object):
|
||||||
""" the single place for accessing values and interacting
|
""" the single place for accessing values and interacting
|
||||||
towards conftest modules from pytest objects.
|
towards conftest modules from pytest objects.
|
||||||
"""
|
"""
|
||||||
def __init__(self, onimport=None, confcutdir=None):
|
def __init__(self, onimport=None):
|
||||||
self._path2confmods = {}
|
self._path2confmods = {}
|
||||||
self._onimport = onimport
|
self._onimport = onimport
|
||||||
self._conftestpath2mod = {}
|
self._conftestpath2mod = {}
|
||||||
self._confcutdir = confcutdir
|
self._confcutdir = None
|
||||||
|
|
||||||
def setinitial(self, args):
|
def setinitial(self, namespace):
|
||||||
""" try to find a first anchor path for looking up global values
|
""" load initial conftest files given a preparsed "namespace".
|
||||||
from conftests. This function is usually called _before_
|
As conftest files may add their own command line options
|
||||||
argument parsing. conftest files may add command line options
|
which have arguments ('--my-opt somepath') we might get some
|
||||||
and we thus have no completely safe way of determining
|
false positives. All builtin and 3rd party plugins will have
|
||||||
which parts of the arguments are actually related to options
|
been loaded, however, so common options will not confuse our logic
|
||||||
and which are file system paths. We just try here to get
|
here.
|
||||||
bootstrapped ...
|
|
||||||
"""
|
"""
|
||||||
current = py.path.local()
|
current = py.path.local()
|
||||||
opt = '--confcutdir'
|
self._confcutdir = current.join(namespace.confcutdir, abs=True) \
|
||||||
for i in range(len(args)):
|
if namespace.confcutdir else None
|
||||||
opt1 = str(args[i])
|
testpaths = namespace.file_or_dir
|
||||||
if opt1.startswith(opt):
|
|
||||||
if opt1 == opt:
|
|
||||||
if len(args) > i:
|
|
||||||
p = current.join(args[i+1], abs=True)
|
|
||||||
elif opt1.startswith(opt + "="):
|
|
||||||
p = current.join(opt1[len(opt)+1:], abs=1)
|
|
||||||
self._confcutdir = p
|
|
||||||
break
|
|
||||||
foundanchor = False
|
foundanchor = False
|
||||||
for arg in args:
|
for path in testpaths:
|
||||||
if hasattr(arg, 'startswith') and arg.startswith("--"):
|
anchor = current.join(path, abs=1)
|
||||||
continue
|
|
||||||
anchor = current.join(arg, abs=1)
|
|
||||||
if exists(anchor): # we found some file object
|
if exists(anchor): # we found some file object
|
||||||
self._try_load_conftest(anchor)
|
self._try_load_conftest(anchor)
|
||||||
foundanchor = True
|
foundanchor = True
|
||||||
|
@ -676,8 +665,8 @@ class Config(object):
|
||||||
plugins += self._conftest.getconftestmodules(fspath)
|
plugins += self._conftest.getconftestmodules(fspath)
|
||||||
return plugins
|
return plugins
|
||||||
|
|
||||||
def pytest_load_initial_conftests(self, parser, args):
|
def pytest_load_initial_conftests(self, early_config):
|
||||||
self._conftest.setinitial(args)
|
self._conftest.setinitial(early_config.known_args_namespace)
|
||||||
pytest_load_initial_conftests.trylast = True
|
pytest_load_initial_conftests.trylast = True
|
||||||
|
|
||||||
def _initini(self, args):
|
def _initini(self, args):
|
||||||
|
@ -693,6 +682,7 @@ class Config(object):
|
||||||
self.pluginmanager.consider_preparse(args)
|
self.pluginmanager.consider_preparse(args)
|
||||||
self.pluginmanager.consider_setuptools_entrypoints()
|
self.pluginmanager.consider_setuptools_entrypoints()
|
||||||
self.pluginmanager.consider_env()
|
self.pluginmanager.consider_env()
|
||||||
|
self.known_args_namespace = self._parser.parse_known_args(args)
|
||||||
self.hook.pytest_load_initial_conftests(early_config=self,
|
self.hook.pytest_load_initial_conftests(early_config=self,
|
||||||
args=args, parser=self._parser)
|
args=args, parser=self._parser)
|
||||||
|
|
||||||
|
@ -710,7 +700,6 @@ class Config(object):
|
||||||
|
|
||||||
def parse(self, args):
|
def parse(self, args):
|
||||||
# parse given cmdline arguments into this config object.
|
# parse given cmdline arguments into this config object.
|
||||||
# Note that this can only be called once per testing process.
|
|
||||||
assert not hasattr(self, 'args'), (
|
assert not hasattr(self, 'args'), (
|
||||||
"can only parse cmdline args at most once per Config object")
|
"can only parse cmdline args at most once per Config object")
|
||||||
self._origargs = args
|
self._origargs = args
|
||||||
|
|
|
@ -148,7 +148,7 @@ class TestConfigAPI:
|
||||||
assert config.getvalue('x') == 1
|
assert config.getvalue('x') == 1
|
||||||
config.option.x = 2
|
config.option.x = 2
|
||||||
assert config.getvalue('x') == 2
|
assert config.getvalue('x') == 2
|
||||||
config = testdir.parseconfig([str(o)])
|
config = testdir.parseconfig(str(o))
|
||||||
assert config.getvalue('x') == 1
|
assert config.getvalue('x') == 1
|
||||||
|
|
||||||
def test_getconftest_pathlist(self, testdir, tmpdir):
|
def test_getconftest_pathlist(self, testdir, tmpdir):
|
||||||
|
|
|
@ -20,19 +20,26 @@ def pytest_funcarg__basedir(request):
|
||||||
|
|
||||||
def ConftestWithSetinitial(path):
|
def ConftestWithSetinitial(path):
|
||||||
conftest = Conftest()
|
conftest = Conftest()
|
||||||
conftest.setinitial([path])
|
conftest_setinitial(conftest, [path])
|
||||||
return conftest
|
return conftest
|
||||||
|
|
||||||
|
def conftest_setinitial(conftest, args, confcutdir=None):
|
||||||
|
class Namespace:
|
||||||
|
def __init__(self):
|
||||||
|
self.file_or_dir = args
|
||||||
|
self.confcutdir = str(confcutdir)
|
||||||
|
conftest.setinitial(Namespace())
|
||||||
|
|
||||||
class TestConftestValueAccessGlobal:
|
class TestConftestValueAccessGlobal:
|
||||||
def test_basic_init(self, basedir):
|
def test_basic_init(self, basedir):
|
||||||
conftest = Conftest()
|
conftest = Conftest()
|
||||||
conftest.setinitial([basedir.join("adir")])
|
conftest_setinitial(conftest, [basedir.join("adir")])
|
||||||
assert conftest.rget("a") == 1
|
assert conftest.rget("a") == 1
|
||||||
|
|
||||||
def test_onimport(self, basedir):
|
def test_onimport(self, basedir):
|
||||||
l = []
|
l = []
|
||||||
conftest = Conftest(onimport=l.append)
|
conftest = Conftest(onimport=l.append)
|
||||||
conftest.setinitial([basedir.join("adir"),
|
conftest_setinitial(conftest, [basedir.join("adir"),
|
||||||
'--confcutdir=%s' % basedir])
|
'--confcutdir=%s' % basedir])
|
||||||
assert len(l) == 1
|
assert len(l) == 1
|
||||||
assert conftest.rget("a") == 1
|
assert conftest.rget("a") == 1
|
||||||
|
@ -99,13 +106,13 @@ def test_conftest_in_nonpkg_with_init(tmpdir):
|
||||||
tmpdir.ensure("adir-1.0/__init__.py")
|
tmpdir.ensure("adir-1.0/__init__.py")
|
||||||
ConftestWithSetinitial(tmpdir.join("adir-1.0", "b"))
|
ConftestWithSetinitial(tmpdir.join("adir-1.0", "b"))
|
||||||
|
|
||||||
def test_doubledash_not_considered(testdir):
|
def test_doubledash_considered(testdir):
|
||||||
conf = testdir.mkdir("--option")
|
conf = testdir.mkdir("--option")
|
||||||
conf.join("conftest.py").ensure()
|
conf.join("conftest.py").ensure()
|
||||||
conftest = Conftest()
|
conftest = Conftest()
|
||||||
conftest.setinitial([conf.basename, conf.basename])
|
conftest_setinitial(conftest, [conf.basename, conf.basename])
|
||||||
l = conftest.getconftestmodules(None)
|
l = conftest.getconftestmodules(None)
|
||||||
assert len(l) == 0
|
assert len(l) == 1
|
||||||
|
|
||||||
def test_issue151_load_all_conftests(testdir):
|
def test_issue151_load_all_conftests(testdir):
|
||||||
names = "code proj src".split()
|
names = "code proj src".split()
|
||||||
|
@ -114,7 +121,7 @@ def test_issue151_load_all_conftests(testdir):
|
||||||
p.ensure("conftest.py")
|
p.ensure("conftest.py")
|
||||||
|
|
||||||
conftest = Conftest()
|
conftest = Conftest()
|
||||||
conftest.setinitial(names)
|
conftest_setinitial(conftest, names)
|
||||||
d = list(conftest._conftestpath2mod.values())
|
d = list(conftest._conftestpath2mod.values())
|
||||||
assert len(d) == len(names)
|
assert len(d) == len(names)
|
||||||
|
|
||||||
|
@ -142,8 +149,8 @@ def test_conftest_global_import(testdir):
|
||||||
def test_conftestcutdir(testdir):
|
def test_conftestcutdir(testdir):
|
||||||
conf = testdir.makeconftest("")
|
conf = testdir.makeconftest("")
|
||||||
p = testdir.mkdir("x")
|
p = testdir.mkdir("x")
|
||||||
conftest = Conftest(confcutdir=p)
|
conftest = Conftest()
|
||||||
conftest.setinitial([testdir.tmpdir])
|
conftest_setinitial(conftest, [testdir.tmpdir], confcutdir=p)
|
||||||
l = conftest.getconftestmodules(p)
|
l = conftest.getconftestmodules(p)
|
||||||
assert len(l) == 0
|
assert len(l) == 0
|
||||||
l = conftest.getconftestmodules(conf.dirpath())
|
l = conftest.getconftestmodules(conf.dirpath())
|
||||||
|
@ -160,34 +167,18 @@ def test_conftestcutdir(testdir):
|
||||||
|
|
||||||
def test_conftestcutdir_inplace_considered(testdir):
|
def test_conftestcutdir_inplace_considered(testdir):
|
||||||
conf = testdir.makeconftest("")
|
conf = testdir.makeconftest("")
|
||||||
conftest = Conftest(confcutdir=conf.dirpath())
|
conftest = Conftest()
|
||||||
conftest.setinitial([conf.dirpath()])
|
conftest_setinitial(conftest, [conf.dirpath()], confcutdir=conf.dirpath())
|
||||||
l = conftest.getconftestmodules(conf.dirpath())
|
l = conftest.getconftestmodules(conf.dirpath())
|
||||||
assert len(l) == 1
|
assert len(l) == 1
|
||||||
assert l[0].__file__.startswith(str(conf))
|
assert l[0].__file__.startswith(str(conf))
|
||||||
|
|
||||||
def test_setinitial_confcut(testdir):
|
|
||||||
conf = testdir.makeconftest("")
|
|
||||||
sub = testdir.mkdir("sub")
|
|
||||||
sub.chdir()
|
|
||||||
for opts in (["--confcutdir=%s" % sub, sub],
|
|
||||||
[sub, "--confcutdir=%s" % sub],
|
|
||||||
["--confcutdir=.", sub],
|
|
||||||
[sub, "--confcutdir", sub],
|
|
||||||
[str(sub), "--confcutdir", "."],
|
|
||||||
):
|
|
||||||
conftest = Conftest()
|
|
||||||
conftest.setinitial(opts)
|
|
||||||
assert conftest._confcutdir == sub
|
|
||||||
assert conftest.getconftestmodules(sub) == []
|
|
||||||
assert conftest.getconftestmodules(conf.dirpath()) == []
|
|
||||||
|
|
||||||
@pytest.mark.parametrize("name", 'test tests whatever .dotdir'.split())
|
@pytest.mark.parametrize("name", 'test tests whatever .dotdir'.split())
|
||||||
def test_setinitial_conftest_subdirs(testdir, name):
|
def test_setinitial_conftest_subdirs(testdir, name):
|
||||||
sub = testdir.mkdir(name)
|
sub = testdir.mkdir(name)
|
||||||
subconftest = sub.ensure("conftest.py")
|
subconftest = sub.ensure("conftest.py")
|
||||||
conftest = Conftest()
|
conftest = Conftest()
|
||||||
conftest.setinitial([sub.dirpath(), '--confcutdir=%s' % 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 subconftest in conftest._conftestpath2mod
|
||||||
assert len(conftest._conftestpath2mod) == 1
|
assert len(conftest._conftestpath2mod) == 1
|
||||||
|
@ -205,6 +196,26 @@ def test_conftest_confcutdir(testdir):
|
||||||
result = testdir.runpytest("-h", "--confcutdir=%s" % x, x)
|
result = testdir.runpytest("-h", "--confcutdir=%s" % x, x)
|
||||||
result.stdout.fnmatch_lines(["*--xyz*"])
|
result.stdout.fnmatch_lines(["*--xyz*"])
|
||||||
|
|
||||||
|
def test_conftest_existing_resultlog(testdir):
|
||||||
|
x = testdir.mkdir("tests")
|
||||||
|
x.join("conftest.py").write(py.code.Source("""
|
||||||
|
def pytest_addoption(parser):
|
||||||
|
parser.addoption("--xyz", action="store_true")
|
||||||
|
"""))
|
||||||
|
testdir.makefile(ext=".log", result="") # Writes result.log
|
||||||
|
result = testdir.runpytest("-h", "--resultlog", "result.log")
|
||||||
|
result.stdout.fnmatch_lines(["*--xyz*"])
|
||||||
|
|
||||||
|
def test_conftest_existing_junitxml(testdir):
|
||||||
|
x = testdir.mkdir("tests")
|
||||||
|
x.join("conftest.py").write(py.code.Source("""
|
||||||
|
def pytest_addoption(parser):
|
||||||
|
parser.addoption("--xyz", action="store_true")
|
||||||
|
"""))
|
||||||
|
testdir.makefile(ext=".xml", junit="") # Writes junit.xml
|
||||||
|
result = testdir.runpytest("-h", "--junitxml", "junit.xml")
|
||||||
|
result.stdout.fnmatch_lines(["*--xyz*"])
|
||||||
|
|
||||||
def test_conftest_import_order(testdir, monkeypatch):
|
def test_conftest_import_order(testdir, monkeypatch):
|
||||||
ct1 = testdir.makeconftest("")
|
ct1 = testdir.makeconftest("")
|
||||||
sub = testdir.mkdir("sub")
|
sub = testdir.mkdir("sub")
|
||||||
|
|
Loading…
Reference in New Issue