deprecate direct definition of Directory, Module, ... in conftest.py's,
add some pytest collect related tests + some refinements. --HG-- branch : trunk
This commit is contained in:
parent
d3b20e8d24
commit
f5ea19858c
|
@ -14,11 +14,16 @@ Changes between 1.X and 1.1.1
|
|||
- allow pytest_generate_tests to be defined in classes as well
|
||||
|
||||
- deprecate usage of 'disabled' attribute in favour of pytestmark
|
||||
- deprecate definition of Directory, Module, Class and Function nodes
|
||||
in conftest.py files. Use pytest collect hooks instead.
|
||||
|
||||
- collection/item node specific runtest/collect hooks are only called exactly
|
||||
on matching conftest.py files, i.e. ones which are exactly below
|
||||
the filesystem path of an item
|
||||
|
||||
- change: the first pytest_collect_directory hook to return something
|
||||
will now prevent further hooks to be called.
|
||||
|
||||
- robustify capturing to survive if custom pytest_runtest_setup
|
||||
code failed and prevented the capturing setup code from running.
|
||||
|
||||
|
|
|
@ -36,10 +36,10 @@ class Node(object):
|
|||
- configuration/options for setup/teardown
|
||||
stdout/stderr capturing and execution of test items
|
||||
"""
|
||||
def __init__(self, name, parent=None):
|
||||
def __init__(self, name, parent=None, config=None):
|
||||
self.name = name
|
||||
self.parent = parent
|
||||
self.config = getattr(parent, 'config', None)
|
||||
self.config = config or parent.config
|
||||
self.fspath = getattr(parent, 'fspath', None)
|
||||
self.ihook = HookProxy(self)
|
||||
|
||||
|
@ -353,9 +353,9 @@ class Collector(Node):
|
|||
return traceback
|
||||
|
||||
class FSCollector(Collector):
|
||||
def __init__(self, fspath, parent=None):
|
||||
def __init__(self, fspath, parent=None, config=None):
|
||||
fspath = py.path.local(fspath)
|
||||
super(FSCollector, self).__init__(fspath.basename, parent)
|
||||
super(FSCollector, self).__init__(fspath.basename, parent, config=config)
|
||||
self.fspath = fspath
|
||||
|
||||
def __getstate__(self):
|
||||
|
|
|
@ -156,16 +156,20 @@ class Config(object):
|
|||
pkgpath = path.pypkgpath()
|
||||
if pkgpath is None:
|
||||
pkgpath = path.check(file=1) and path.dirpath() or path
|
||||
Dir = self._getcollectclass("Directory", pkgpath)
|
||||
col = Dir(pkgpath)
|
||||
col.config = self
|
||||
tmpcol = py.test.collect.Directory(pkgpath, config=self)
|
||||
col = tmpcol.ihook.pytest_collect_directory(path=pkgpath, parent=tmpcol)
|
||||
col.parent = None
|
||||
return col._getfsnode(path)
|
||||
|
||||
def _getcollectclass(self, name, path):
|
||||
try:
|
||||
return self.getvalue(name, path)
|
||||
cls = self.getvalue(name, path)
|
||||
except KeyError:
|
||||
return getattr(py.test.collect, name)
|
||||
else:
|
||||
py.log._apiwarn(">1.1", "%r was found in a conftest.py file, "
|
||||
"use pytest_collect hooks instead." % (cls,))
|
||||
return cls
|
||||
|
||||
def getconftest_pathlist(self, name, path=None):
|
||||
""" return a matching value, which needs to be sequence
|
||||
|
|
|
@ -315,9 +315,9 @@ class Function(FunctionMixin, py.test.collect.Item):
|
|||
and executing a Python callable test object.
|
||||
"""
|
||||
_genid = None
|
||||
def __init__(self, name, parent=None, args=None,
|
||||
def __init__(self, name, parent=None, args=None, config=None,
|
||||
callspec=None, callobj=_dummy):
|
||||
super(Function, self).__init__(name, parent)
|
||||
super(Function, self).__init__(name, parent, config=config)
|
||||
self._args = args
|
||||
if self._isyieldedfunction():
|
||||
assert not callspec, "yielded functions (deprecated) cannot have funcargs"
|
||||
|
|
|
@ -26,6 +26,7 @@ def pytest_unconfigure(config):
|
|||
|
||||
def pytest_collect_directory(path, parent):
|
||||
""" return Collection node or None for the given path. """
|
||||
pytest_collect_directory.firstresult = True
|
||||
|
||||
def pytest_collect_file(path, parent):
|
||||
""" return Collection node or None for the given path. """
|
||||
|
|
|
@ -3,8 +3,9 @@ import os
|
|||
from py.plugin.pytest_resultlog import generic_path, ResultLog
|
||||
from py.impl.test.collect import Node, Item, FSCollector
|
||||
|
||||
def test_generic_path():
|
||||
p1 = Node('a')
|
||||
def test_generic_path(testdir):
|
||||
config = testdir.Config()
|
||||
p1 = Node('a', config=config)
|
||||
assert p1.fspath is None
|
||||
p2 = Node('B', parent=p1)
|
||||
p3 = Node('()', parent = p2)
|
||||
|
@ -13,7 +14,7 @@ def test_generic_path():
|
|||
res = generic_path(item)
|
||||
assert res == 'a.B().c'
|
||||
|
||||
p0 = FSCollector('proj/test')
|
||||
p0 = FSCollector('proj/test', config=config)
|
||||
p1 = FSCollector('proj/test/a', parent=p0)
|
||||
p2 = Node('B', parent=p1)
|
||||
p3 = Node('()', parent = p2)
|
||||
|
|
|
@ -193,31 +193,6 @@ class TestPrunetraceback:
|
|||
])
|
||||
|
||||
class TestCustomConftests:
|
||||
def test_non_python_files(self, testdir):
|
||||
testdir.makepyfile(conftest="""
|
||||
import py
|
||||
class CustomItem(py.test.collect.Item):
|
||||
def run(self):
|
||||
pass
|
||||
class Directory(py.test.collect.Directory):
|
||||
def consider_file(self, fspath):
|
||||
if fspath.ext == ".xxx":
|
||||
return CustomItem(fspath.basename, parent=self)
|
||||
""")
|
||||
checkfile = testdir.makefile(ext="xxx", hello="world")
|
||||
testdir.makepyfile(x="")
|
||||
testdir.maketxtfile(x="")
|
||||
config = testdir.parseconfig()
|
||||
dircol = config.getfsnode(checkfile.dirpath())
|
||||
colitems = dircol.collect()
|
||||
assert len(colitems) == 1
|
||||
assert colitems[0].name == "hello.xxx"
|
||||
assert colitems[0].__class__.__name__ == "CustomItem"
|
||||
|
||||
item = config.getfsnode(checkfile)
|
||||
assert item.name == "hello.xxx"
|
||||
assert item.__class__.__name__ == "CustomItem"
|
||||
|
||||
def test_collectignore_exclude_on_option(self, testdir):
|
||||
testdir.makeconftest("""
|
||||
collect_ignore = ['hello', 'test_world.py']
|
||||
|
@ -237,3 +212,23 @@ class TestCustomConftests:
|
|||
names = [rep.collector.name for rep in reprec.getreports("pytest_collectreport")]
|
||||
assert 'hello' in names
|
||||
assert 'test_world.py' in names
|
||||
|
||||
def test_pytest_fs_collect_hooks_are_seen(self, testdir):
|
||||
testdir.makeconftest("""
|
||||
import py
|
||||
class MyDirectory(py.test.collect.Directory):
|
||||
pass
|
||||
class MyModule(py.test.collect.Module):
|
||||
pass
|
||||
def pytest_collect_directory(path, parent):
|
||||
return MyDirectory(path, parent)
|
||||
def pytest_collect_file(path, parent):
|
||||
return MyModule(path, parent)
|
||||
""")
|
||||
testdir.makepyfile("def test_x(): pass")
|
||||
result = testdir.runpytest("--collectonly")
|
||||
result.stdout.fnmatch_lines([
|
||||
"*MyDirectory*",
|
||||
"*MyModule*",
|
||||
"*test_x*"
|
||||
])
|
||||
|
|
|
@ -48,12 +48,6 @@ class TestConftestValueAccessGlobal:
|
|||
conftest.getconftestmodules(basedir.join('b'))
|
||||
assert len(conftest._path2confmods) == snap1 + 2
|
||||
|
||||
def test_default_Module_setting_is_visible_always(self, basedir, testdir):
|
||||
basedir.copy(testdir.tmpdir)
|
||||
config = testdir.Config()
|
||||
colclass = config._getcollectclass("Module", testdir.tmpdir)
|
||||
assert colclass == py.test.collect.Module
|
||||
|
||||
def test_default_has_lower_prio(self, basedir):
|
||||
conftest = ConftestWithSetinitial(basedir.join("adir"))
|
||||
assert conftest.rget('Directory') == 3
|
||||
|
|
|
@ -37,15 +37,19 @@ class TestCollectDeprecated:
|
|||
def join(self, name):
|
||||
if name == "somefile.py":
|
||||
return self.Module(self.fspath.join(name), parent=self)
|
||||
Directory = MyDirectory
|
||||
|
||||
def pytest_collect_directory(path, parent):
|
||||
return MyDirectory(path, parent)
|
||||
""")
|
||||
p = testdir.makepyfile(somefile="""
|
||||
subconf = testdir.mkpydir("subconf")
|
||||
somefile = subconf.join("somefile.py")
|
||||
somefile.write(py.code.Source("""
|
||||
def check(): pass
|
||||
class Cls:
|
||||
def check2(self): pass
|
||||
""")
|
||||
config = testdir.parseconfig()
|
||||
dirnode = config.getfsnode(p.dirpath())
|
||||
"""))
|
||||
config = testdir.parseconfig(somefile)
|
||||
dirnode = config.getfsnode(somefile.dirpath())
|
||||
colitems = dirnode.collect()
|
||||
w = recwarn.pop(DeprecationWarning)
|
||||
assert w.filename.find("conftest.py") != -1
|
||||
|
@ -120,6 +124,7 @@ class TestCollectDeprecated:
|
|||
""")
|
||||
modcol = testdir.getmodulecol("def test_func2(): pass")
|
||||
funcitem = modcol.collect()[0]
|
||||
w = recwarn.pop(DeprecationWarning) # for defining conftest.Function
|
||||
assert funcitem.name == 'test_func2'
|
||||
funcitem._deprecated_testexecution()
|
||||
w = recwarn.pop(DeprecationWarning)
|
||||
|
@ -136,6 +141,8 @@ class TestCollectDeprecated:
|
|||
""")
|
||||
modcol = testdir.getmodulecol("def test_some2(): pass")
|
||||
funcitem = modcol.collect()[0]
|
||||
w = recwarn.pop(DeprecationWarning)
|
||||
assert "conftest.py" in str(w.message)
|
||||
|
||||
recwarn.clear()
|
||||
funcitem._deprecated_testexecution()
|
||||
|
@ -169,6 +176,7 @@ class TestCollectDeprecated:
|
|||
col = config.getfsnode(testme)
|
||||
assert col.collect() == []
|
||||
|
||||
|
||||
|
||||
class TestDisabled:
|
||||
def test_disabled_module(self, recwarn, testdir):
|
||||
|
@ -211,6 +219,31 @@ class TestDisabled:
|
|||
""")
|
||||
reprec.assertoutcome(skipped=2)
|
||||
|
||||
@py.test.mark.multi(name="Directory Module Class Function".split())
|
||||
def test_function_deprecated_run_execute(self, name, testdir, recwarn):
|
||||
testdir.makeconftest("""
|
||||
import py
|
||||
class %s(py.test.collect.%s):
|
||||
pass
|
||||
""" % (name, name))
|
||||
p = testdir.makepyfile("""
|
||||
class TestClass:
|
||||
def test_method(self):
|
||||
pass
|
||||
def test_function():
|
||||
pass
|
||||
""")
|
||||
config = testdir.parseconfig()
|
||||
if name == "Directory":
|
||||
config.getfsnode(testdir.tmpdir)
|
||||
elif name in ("Module", "File"):
|
||||
config.getfsnode(p)
|
||||
else:
|
||||
fnode = config.getfsnode(p)
|
||||
recwarn.clear()
|
||||
fnode.collect()
|
||||
w = recwarn.pop(DeprecationWarning)
|
||||
assert "conftest.py" in str(w.message)
|
||||
|
||||
def test_config_cmdline_options(recwarn, testdir):
|
||||
testdir.makepyfile(conftest="""
|
||||
|
@ -267,3 +300,80 @@ def test_dist_conftest_options(testdir):
|
|||
"*1 passed*",
|
||||
])
|
||||
|
||||
def test_conftest_non_python_items(recwarn, testdir):
|
||||
testdir.makepyfile(conftest="""
|
||||
import py
|
||||
class CustomItem(py.test.collect.Item):
|
||||
def run(self):
|
||||
pass
|
||||
class Directory(py.test.collect.Directory):
|
||||
def consider_file(self, fspath):
|
||||
if fspath.ext == ".xxx":
|
||||
return CustomItem(fspath.basename, parent=self)
|
||||
""")
|
||||
checkfile = testdir.makefile(ext="xxx", hello="world")
|
||||
testdir.makepyfile(x="")
|
||||
testdir.maketxtfile(x="")
|
||||
config = testdir.parseconfig()
|
||||
recwarn.clear()
|
||||
dircol = config.getfsnode(checkfile.dirpath())
|
||||
w = recwarn.pop(DeprecationWarning)
|
||||
assert str(w.message).find("conftest.py") != -1
|
||||
colitems = dircol.collect()
|
||||
assert len(colitems) == 1
|
||||
assert colitems[0].name == "hello.xxx"
|
||||
assert colitems[0].__class__.__name__ == "CustomItem"
|
||||
|
||||
item = config.getfsnode(checkfile)
|
||||
assert item.name == "hello.xxx"
|
||||
assert item.__class__.__name__ == "CustomItem"
|
||||
|
||||
def test_extra_python_files_and_functions(testdir):
|
||||
testdir.makepyfile(conftest="""
|
||||
import py
|
||||
class MyFunction(py.test.collect.Function):
|
||||
pass
|
||||
class Directory(py.test.collect.Directory):
|
||||
def consider_file(self, path):
|
||||
if path.check(fnmatch="check_*.py"):
|
||||
return self.Module(path, parent=self)
|
||||
return super(Directory, self).consider_file(path)
|
||||
class myfuncmixin:
|
||||
Function = MyFunction
|
||||
def funcnamefilter(self, name):
|
||||
return name.startswith('check_')
|
||||
class Module(myfuncmixin, py.test.collect.Module):
|
||||
def classnamefilter(self, name):
|
||||
return name.startswith('CustomTestClass')
|
||||
class Instance(myfuncmixin, py.test.collect.Instance):
|
||||
pass
|
||||
""")
|
||||
checkfile = testdir.makepyfile(check_file="""
|
||||
def check_func():
|
||||
assert 42 == 42
|
||||
class CustomTestClass:
|
||||
def check_method(self):
|
||||
assert 23 == 23
|
||||
""")
|
||||
# check that directory collects "check_" files
|
||||
config = testdir.parseconfig()
|
||||
col = config.getfsnode(checkfile.dirpath())
|
||||
colitems = col.collect()
|
||||
assert len(colitems) == 1
|
||||
assert isinstance(colitems[0], py.test.collect.Module)
|
||||
|
||||
# check that module collects "check_" functions and methods
|
||||
config = testdir.parseconfig(checkfile)
|
||||
col = config.getfsnode(checkfile)
|
||||
assert isinstance(col, py.test.collect.Module)
|
||||
colitems = col.collect()
|
||||
assert len(colitems) == 2
|
||||
funccol = colitems[0]
|
||||
assert isinstance(funccol, py.test.collect.Function)
|
||||
assert funccol.name == "check_func"
|
||||
clscol = colitems[1]
|
||||
assert isinstance(clscol, py.test.collect.Class)
|
||||
colitems = clscol.collect()[0].collect()
|
||||
assert len(colitems) == 1
|
||||
assert colitems[0].name == "check_method"
|
||||
|
||||
|
|
|
@ -4,7 +4,7 @@ class TestModule:
|
|||
def test_module_file_not_found(self, testdir):
|
||||
tmpdir = testdir.tmpdir
|
||||
fn = tmpdir.join('nada','no')
|
||||
col = py.test.collect.Module(fn)
|
||||
col = py.test.collect.Module(fn, config=testdir.Config())
|
||||
col.config = testdir.parseconfig(tmpdir)
|
||||
py.test.raises(py.error.ENOENT, col.collect)
|
||||
|
||||
|
@ -213,13 +213,13 @@ class TestFunction:
|
|||
|
||||
def test_function_equality(self, testdir, tmpdir):
|
||||
config = testdir.reparseconfig()
|
||||
f1 = py.test.collect.Function(name="name",
|
||||
f1 = py.test.collect.Function(name="name", config=config,
|
||||
args=(1,), callobj=isinstance)
|
||||
f2 = py.test.collect.Function(name="name",
|
||||
f2 = py.test.collect.Function(name="name",config=config,
|
||||
args=(1,), callobj=py.builtin.callable)
|
||||
assert not f1 == f2
|
||||
assert f1 != f2
|
||||
f3 = py.test.collect.Function(name="name",
|
||||
f3 = py.test.collect.Function(name="name", config=config,
|
||||
args=(1,2), callobj=py.builtin.callable)
|
||||
assert not f3 == f2
|
||||
assert f3 != f2
|
||||
|
@ -227,7 +227,7 @@ class TestFunction:
|
|||
assert not f3 == f1
|
||||
assert f3 != f1
|
||||
|
||||
f1_b = py.test.collect.Function(name="name",
|
||||
f1_b = py.test.collect.Function(name="name", config=config,
|
||||
args=(1,), callobj=isinstance)
|
||||
assert f1 == f1_b
|
||||
assert not f1 != f1_b
|
||||
|
@ -242,9 +242,9 @@ class TestFunction:
|
|||
param = 1
|
||||
funcargs = {}
|
||||
id = "world"
|
||||
f5 = py.test.collect.Function(name="name",
|
||||
f5 = py.test.collect.Function(name="name", config=config,
|
||||
callspec=callspec1, callobj=isinstance)
|
||||
f5b = py.test.collect.Function(name="name",
|
||||
f5b = py.test.collect.Function(name="name", config=config,
|
||||
callspec=callspec2, callobj=isinstance)
|
||||
assert f5 != f5b
|
||||
assert not (f5 == f5b)
|
||||
|
@ -313,55 +313,21 @@ class TestSorting:
|
|||
|
||||
|
||||
class TestConftestCustomization:
|
||||
def test_extra_python_files_and_functions(self, testdir):
|
||||
testdir.makepyfile(conftest="""
|
||||
def test_pytest_pycollect_makeitem(self, testdir):
|
||||
testdir.makeconftest("""
|
||||
import py
|
||||
class MyFunction(py.test.collect.Function):
|
||||
pass
|
||||
class Directory(py.test.collect.Directory):
|
||||
def consider_file(self, path):
|
||||
if path.check(fnmatch="check_*.py"):
|
||||
return self.Module(path, parent=self)
|
||||
return super(Directory, self).consider_file(path)
|
||||
class myfuncmixin:
|
||||
Function = MyFunction
|
||||
def funcnamefilter(self, name):
|
||||
return name.startswith('check_')
|
||||
class Module(myfuncmixin, py.test.collect.Module):
|
||||
def classnamefilter(self, name):
|
||||
return name.startswith('CustomTestClass')
|
||||
class Instance(myfuncmixin, py.test.collect.Instance):
|
||||
pass
|
||||
def pytest_pycollect_makeitem(collector, name, obj):
|
||||
if name == "some":
|
||||
return MyFunction(name, collector)
|
||||
""")
|
||||
checkfile = testdir.makepyfile(check_file="""
|
||||
def check_func():
|
||||
assert 42 == 42
|
||||
class CustomTestClass:
|
||||
def check_method(self):
|
||||
assert 23 == 23
|
||||
""")
|
||||
# check that directory collects "check_" files
|
||||
config = testdir.parseconfig()
|
||||
col = config.getfsnode(checkfile.dirpath())
|
||||
colitems = col.collect()
|
||||
assert len(colitems) == 1
|
||||
assert isinstance(colitems[0], py.test.collect.Module)
|
||||
|
||||
# check that module collects "check_" functions and methods
|
||||
config = testdir.parseconfig(checkfile)
|
||||
col = config.getfsnode(checkfile)
|
||||
assert isinstance(col, py.test.collect.Module)
|
||||
colitems = col.collect()
|
||||
assert len(colitems) == 2
|
||||
funccol = colitems[0]
|
||||
assert isinstance(funccol, py.test.collect.Function)
|
||||
assert funccol.name == "check_func"
|
||||
clscol = colitems[1]
|
||||
assert isinstance(clscol, py.test.collect.Class)
|
||||
colitems = clscol.collect()[0].collect()
|
||||
assert len(colitems) == 1
|
||||
assert colitems[0].name == "check_method"
|
||||
|
||||
testdir.makepyfile("def some(): pass")
|
||||
result = testdir.runpytest("--collectonly")
|
||||
result.stdout.fnmatch_lines([
|
||||
"*MyFunction*some*",
|
||||
])
|
||||
|
||||
def test_makeitem_non_underscore(self, testdir, monkeypatch):
|
||||
modcol = testdir.getmodulecol("def _hello(): pass")
|
||||
l = []
|
||||
|
|
Loading…
Reference in New Issue