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
|
||||
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
|
||||
during collection/loading of test modules. Thanks to Marc Schlaich
|
||||
for the complete PR.
|
||||
|
|
|
@ -31,7 +31,7 @@ def pytest_addoption(parser):
|
|||
|
||||
@pytest.mark.tryfirst
|
||||
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
|
||||
if ns.capture == "no":
|
||||
return
|
||||
|
|
|
@ -449,38 +449,27 @@ class Conftest(object):
|
|||
""" the single place for accessing values and interacting
|
||||
towards conftest modules from pytest objects.
|
||||
"""
|
||||
def __init__(self, onimport=None, confcutdir=None):
|
||||
def __init__(self, onimport=None):
|
||||
self._path2confmods = {}
|
||||
self._onimport = onimport
|
||||
self._conftestpath2mod = {}
|
||||
self._confcutdir = confcutdir
|
||||
self._confcutdir = None
|
||||
|
||||
def setinitial(self, args):
|
||||
""" try to find a first anchor path for looking up global values
|
||||
from conftests. This function is usually called _before_
|
||||
argument parsing. conftest files may add command line options
|
||||
and we thus have no completely safe way of determining
|
||||
which parts of the arguments are actually related to options
|
||||
and which are file system paths. We just try here to get
|
||||
bootstrapped ...
|
||||
def setinitial(self, namespace):
|
||||
""" load initial conftest files given a preparsed "namespace".
|
||||
As conftest files may add their own command line options
|
||||
which have arguments ('--my-opt somepath') we might get some
|
||||
false positives. All builtin and 3rd party plugins will have
|
||||
been loaded, however, so common options will not confuse our logic
|
||||
here.
|
||||
"""
|
||||
current = py.path.local()
|
||||
opt = '--confcutdir'
|
||||
for i in range(len(args)):
|
||||
opt1 = str(args[i])
|
||||
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
|
||||
self._confcutdir = current.join(namespace.confcutdir, abs=True) \
|
||||
if namespace.confcutdir else None
|
||||
testpaths = namespace.file_or_dir
|
||||
foundanchor = False
|
||||
for arg in args:
|
||||
if hasattr(arg, 'startswith') and arg.startswith("--"):
|
||||
continue
|
||||
anchor = current.join(arg, abs=1)
|
||||
for path in testpaths:
|
||||
anchor = current.join(path, abs=1)
|
||||
if exists(anchor): # we found some file object
|
||||
self._try_load_conftest(anchor)
|
||||
foundanchor = True
|
||||
|
@ -676,8 +665,8 @@ class Config(object):
|
|||
plugins += self._conftest.getconftestmodules(fspath)
|
||||
return plugins
|
||||
|
||||
def pytest_load_initial_conftests(self, parser, args):
|
||||
self._conftest.setinitial(args)
|
||||
def pytest_load_initial_conftests(self, early_config):
|
||||
self._conftest.setinitial(early_config.known_args_namespace)
|
||||
pytest_load_initial_conftests.trylast = True
|
||||
|
||||
def _initini(self, args):
|
||||
|
@ -693,6 +682,7 @@ class Config(object):
|
|||
self.pluginmanager.consider_preparse(args)
|
||||
self.pluginmanager.consider_setuptools_entrypoints()
|
||||
self.pluginmanager.consider_env()
|
||||
self.known_args_namespace = self._parser.parse_known_args(args)
|
||||
self.hook.pytest_load_initial_conftests(early_config=self,
|
||||
args=args, parser=self._parser)
|
||||
|
||||
|
@ -710,7 +700,6 @@ class Config(object):
|
|||
|
||||
def parse(self, args):
|
||||
# parse given cmdline arguments into this config object.
|
||||
# Note that this can only be called once per testing process.
|
||||
assert not hasattr(self, 'args'), (
|
||||
"can only parse cmdline args at most once per Config object")
|
||||
self._origargs = args
|
||||
|
|
|
@ -148,7 +148,7 @@ class TestConfigAPI:
|
|||
assert config.getvalue('x') == 1
|
||||
config.option.x = 2
|
||||
assert config.getvalue('x') == 2
|
||||
config = testdir.parseconfig([str(o)])
|
||||
config = testdir.parseconfig(str(o))
|
||||
assert config.getvalue('x') == 1
|
||||
|
||||
def test_getconftest_pathlist(self, testdir, tmpdir):
|
||||
|
|
|
@ -20,19 +20,26 @@ def pytest_funcarg__basedir(request):
|
|||
|
||||
def ConftestWithSetinitial(path):
|
||||
conftest = Conftest()
|
||||
conftest.setinitial([path])
|
||||
conftest_setinitial(conftest, [path])
|
||||
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:
|
||||
def test_basic_init(self, basedir):
|
||||
conftest = Conftest()
|
||||
conftest.setinitial([basedir.join("adir")])
|
||||
conftest_setinitial(conftest, [basedir.join("adir")])
|
||||
assert conftest.rget("a") == 1
|
||||
|
||||
def test_onimport(self, basedir):
|
||||
l = []
|
||||
conftest = Conftest(onimport=l.append)
|
||||
conftest.setinitial([basedir.join("adir"),
|
||||
conftest_setinitial(conftest, [basedir.join("adir"),
|
||||
'--confcutdir=%s' % basedir])
|
||||
assert len(l) == 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")
|
||||
ConftestWithSetinitial(tmpdir.join("adir-1.0", "b"))
|
||||
|
||||
def test_doubledash_not_considered(testdir):
|
||||
def test_doubledash_considered(testdir):
|
||||
conf = testdir.mkdir("--option")
|
||||
conf.join("conftest.py").ensure()
|
||||
conftest = Conftest()
|
||||
conftest.setinitial([conf.basename, conf.basename])
|
||||
conftest_setinitial(conftest, [conf.basename, conf.basename])
|
||||
l = conftest.getconftestmodules(None)
|
||||
assert len(l) == 0
|
||||
assert len(l) == 1
|
||||
|
||||
def test_issue151_load_all_conftests(testdir):
|
||||
names = "code proj src".split()
|
||||
|
@ -114,7 +121,7 @@ def test_issue151_load_all_conftests(testdir):
|
|||
p.ensure("conftest.py")
|
||||
|
||||
conftest = Conftest()
|
||||
conftest.setinitial(names)
|
||||
conftest_setinitial(conftest, names)
|
||||
d = list(conftest._conftestpath2mod.values())
|
||||
assert len(d) == len(names)
|
||||
|
||||
|
@ -142,8 +149,8 @@ def test_conftest_global_import(testdir):
|
|||
def test_conftestcutdir(testdir):
|
||||
conf = testdir.makeconftest("")
|
||||
p = testdir.mkdir("x")
|
||||
conftest = Conftest(confcutdir=p)
|
||||
conftest.setinitial([testdir.tmpdir])
|
||||
conftest = Conftest()
|
||||
conftest_setinitial(conftest, [testdir.tmpdir], confcutdir=p)
|
||||
l = conftest.getconftestmodules(p)
|
||||
assert len(l) == 0
|
||||
l = conftest.getconftestmodules(conf.dirpath())
|
||||
|
@ -160,34 +167,18 @@ def test_conftestcutdir(testdir):
|
|||
|
||||
def test_conftestcutdir_inplace_considered(testdir):
|
||||
conf = testdir.makeconftest("")
|
||||
conftest = Conftest(confcutdir=conf.dirpath())
|
||||
conftest.setinitial([conf.dirpath()])
|
||||
conftest = Conftest()
|
||||
conftest_setinitial(conftest, [conf.dirpath()], confcutdir=conf.dirpath())
|
||||
l = conftest.getconftestmodules(conf.dirpath())
|
||||
assert len(l) == 1
|
||||
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())
|
||||
def test_setinitial_conftest_subdirs(testdir, name):
|
||||
sub = testdir.mkdir(name)
|
||||
subconftest = sub.ensure("conftest.py")
|
||||
conftest = Conftest()
|
||||
conftest.setinitial([sub.dirpath(), '--confcutdir=%s' % testdir.tmpdir])
|
||||
conftest_setinitial(conftest, [sub.dirpath()], confcutdir=testdir.tmpdir)
|
||||
if name not in ('whatever', '.dotdir'):
|
||||
assert subconftest in conftest._conftestpath2mod
|
||||
assert len(conftest._conftestpath2mod) == 1
|
||||
|
@ -205,6 +196,26 @@ def test_conftest_confcutdir(testdir):
|
|||
result = testdir.runpytest("-h", "--confcutdir=%s" % x, x)
|
||||
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):
|
||||
ct1 = testdir.makeconftest("")
|
||||
sub = testdir.mkdir("sub")
|
||||
|
|
Loading…
Reference in New Issue