enhance figleaf setup, enabled by default now (requires --figleaf). Generalize internal ability to show "hints" at the end of "-h".
--HG-- branch : trunk
This commit is contained in:
parent
1b6391d814
commit
56a936993c
|
@ -40,6 +40,10 @@ Changes between 1.X and 1.1.1
|
||||||
- change: the first pytest_collect_directory hook to return something
|
- change: the first pytest_collect_directory hook to return something
|
||||||
will now prevent further hooks to be called.
|
will now prevent further hooks to be called.
|
||||||
|
|
||||||
|
- change: pytest figleaf now requires --figleaf to run and is turned
|
||||||
|
on by default (requires the 'figleaf' package though). Change
|
||||||
|
long command line options to be a bit shorter (see py.test -h).
|
||||||
|
|
||||||
- robustify capturing to survive if custom pytest_runtest_setup
|
- robustify capturing to survive if custom pytest_runtest_setup
|
||||||
code failed and prevented the capturing setup code from running.
|
code failed and prevented the capturing setup code from running.
|
||||||
|
|
||||||
|
|
|
@ -92,6 +92,7 @@ class Config(object):
|
||||||
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._preparse(args)
|
self._preparse(args)
|
||||||
|
self._parser.hints.extend(self.pluginmanager._hints)
|
||||||
args = self._parser.parse_setoption(args, self.option)
|
args = self._parser.parse_setoption(args, self.option)
|
||||||
if not args:
|
if not args:
|
||||||
args.append(py.std.os.getcwd())
|
args.append(py.std.os.getcwd())
|
||||||
|
|
|
@ -24,7 +24,7 @@ class Parser:
|
||||||
self._groups = []
|
self._groups = []
|
||||||
self._processopt = processopt
|
self._processopt = processopt
|
||||||
self._usage = usage
|
self._usage = usage
|
||||||
self.epilog = ""
|
self.hints = []
|
||||||
|
|
||||||
def processoption(self, option):
|
def processoption(self, option):
|
||||||
if self._processopt:
|
if self._processopt:
|
||||||
|
@ -56,9 +56,7 @@ class Parser:
|
||||||
self._anonymous.addoption(*opts, **attrs)
|
self._anonymous.addoption(*opts, **attrs)
|
||||||
|
|
||||||
def parse(self, args):
|
def parse(self, args):
|
||||||
optparser = optparse.OptionParser(usage=self._usage)
|
optparser = MyOptionParser(self)
|
||||||
# make sure anaonymous group is at the end
|
|
||||||
optparser.epilog = self.epilog
|
|
||||||
groups = self._groups + [self._anonymous]
|
groups = self._groups + [self._anonymous]
|
||||||
for group in groups:
|
for group in groups:
|
||||||
if group.options:
|
if group.options:
|
||||||
|
@ -100,4 +98,15 @@ class OptionGroup:
|
||||||
self.parser.processoption(option)
|
self.parser.processoption(option)
|
||||||
self.options.append(option)
|
self.options.append(option)
|
||||||
|
|
||||||
|
|
||||||
|
class MyOptionParser(optparse.OptionParser):
|
||||||
|
def __init__(self, parser):
|
||||||
|
self._parser = parser
|
||||||
|
optparse.OptionParser.__init__(self, usage=parser._usage)
|
||||||
|
def format_epilog(self, formatter):
|
||||||
|
hints = self._parser.hints
|
||||||
|
if hints:
|
||||||
|
s = "\n".join(["hint: " + x for x in hints]) + "\n"
|
||||||
|
s = "\n" + s + "\n"
|
||||||
|
return s
|
||||||
|
return ""
|
||||||
|
|
|
@ -9,7 +9,7 @@ from py.impl.test.outcome import Skipped
|
||||||
default_plugins = (
|
default_plugins = (
|
||||||
"default runner capture terminal mark skipping tmpdir monkeypatch "
|
"default runner capture terminal mark skipping tmpdir monkeypatch "
|
||||||
"recwarn pdb pastebin unittest helpconfig nose assertion genscript "
|
"recwarn pdb pastebin unittest helpconfig nose assertion genscript "
|
||||||
"logxml").split()
|
"logxml figleaf").split()
|
||||||
|
|
||||||
def check_old_use(mod, modname):
|
def check_old_use(mod, modname):
|
||||||
clsname = modname[len('pytest_'):].capitalize() + "Plugin"
|
clsname = modname[len('pytest_'):].capitalize() + "Plugin"
|
||||||
|
@ -19,10 +19,11 @@ class PluginManager(object):
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.registry = Registry()
|
self.registry = Registry()
|
||||||
self._name2plugin = {}
|
self._name2plugin = {}
|
||||||
|
self._hints = []
|
||||||
self.hook = HookRelay(hookspecs=hookspec, registry=self.registry)
|
self.hook = HookRelay(hookspecs=hookspec, registry=self.registry)
|
||||||
self.register(self)
|
self.register(self)
|
||||||
for spec in default_plugins:
|
for spec in default_plugins:
|
||||||
self.import_plugin(spec)
|
self.import_plugin(spec)
|
||||||
|
|
||||||
def _getpluginname(self, plugin, name):
|
def _getpluginname(self, plugin, name):
|
||||||
if name is None:
|
if name is None:
|
||||||
|
@ -123,15 +124,17 @@ class PluginManager(object):
|
||||||
raise
|
raise
|
||||||
except Skipped:
|
except Skipped:
|
||||||
e = py.std.sys.exc_info()[1]
|
e = py.std.sys.exc_info()[1]
|
||||||
self._warn("could not import plugin %r, reason: %r" %(
|
self._hints.append("skipped plugin %r: %s" %((modname, e.msg)))
|
||||||
(modname, e.msg)))
|
|
||||||
else:
|
else:
|
||||||
check_old_use(mod, modname)
|
check_old_use(mod, modname)
|
||||||
self.register(mod)
|
self.register(mod)
|
||||||
self.consider_module(mod)
|
self.consider_module(mod)
|
||||||
|
|
||||||
def _warn(self, msg):
|
def pytest_terminal_summary(self, terminalreporter):
|
||||||
print ("===WARNING=== %s" % (msg,))
|
tw = terminalreporter._tw
|
||||||
|
if terminalreporter.config.option.traceconfig:
|
||||||
|
for hint in self._hints:
|
||||||
|
tw.line("hint: %s" % hint)
|
||||||
|
|
||||||
#
|
#
|
||||||
#
|
#
|
||||||
|
@ -201,10 +204,8 @@ def importplugin(importspec):
|
||||||
e = py.std.sys.exc_info()[1]
|
e = py.std.sys.exc_info()[1]
|
||||||
if str(e).find(importspec) == -1:
|
if str(e).find(importspec) == -1:
|
||||||
raise
|
raise
|
||||||
#print "syspath:", py.std.sys.path
|
# show the original exception, not the failing internal one
|
||||||
#print "curdir:", py.std.os.getcwd()
|
return __import__(importspec)
|
||||||
return __import__(importspec) # show the original exception
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class MultiCall:
|
class MultiCall:
|
||||||
|
|
|
@ -80,8 +80,9 @@ def pytest_addoption(parser):
|
||||||
if execnet:
|
if execnet:
|
||||||
add_dist_options(parser)
|
add_dist_options(parser)
|
||||||
else:
|
else:
|
||||||
parser.epilog = (
|
parser.hints.append(
|
||||||
"'execnet>=1.0.0b4' package required for --looponfailing / distributed testing.")
|
"'execnet>=1.0.0b4' required for --looponfailing / distributed testing."
|
||||||
|
)
|
||||||
|
|
||||||
def add_dist_options(parser):
|
def add_dist_options(parser):
|
||||||
# see http://pytest.org/help/dist")
|
# see http://pytest.org/help/dist")
|
||||||
|
|
|
@ -18,7 +18,7 @@ from py.impl.code.code import TerminalRepr, ReprFileLocation
|
||||||
import doctest
|
import doctest
|
||||||
|
|
||||||
def pytest_addoption(parser):
|
def pytest_addoption(parser):
|
||||||
group = parser.getgroup("doctest options")
|
group = parser.getgroup("general")
|
||||||
group.addoption("--doctest-modules",
|
group.addoption("--doctest-modules",
|
||||||
action="store_true", default=False,
|
action="store_true", default=False,
|
||||||
help="search all python files for doctests",
|
help="search all python files for doctests",
|
||||||
|
|
|
@ -3,28 +3,30 @@ write and report coverage data with 'figleaf'.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
import py
|
import py
|
||||||
|
py.test.importorskip("figleaf")
|
||||||
py.test.importorskip("figleaf.annotate_html")
|
import figleaf.annotate_html
|
||||||
import figleaf
|
|
||||||
|
|
||||||
def pytest_addoption(parser):
|
def pytest_addoption(parser):
|
||||||
group = parser.getgroup('figleaf options')
|
group = parser.getgroup('figleaf options')
|
||||||
group.addoption('-F', action='store_true', default=False,
|
group.addoption('--figleaf', action='store_true', default=False,
|
||||||
dest = 'figleaf',
|
dest = 'figleaf',
|
||||||
help=('trace python coverage with figleaf and write HTML '
|
help=('trace python coverage with figleaf and write HTML '
|
||||||
'for files below the current working dir'))
|
'for files below the current working dir'))
|
||||||
group.addoption('--figleaf-data', action='store', default='.figleaf',
|
group.addoption('--fig-data', action='store', default='.figleaf',
|
||||||
dest='figleafdata',
|
dest='figleafdata', metavar="dir",
|
||||||
help='path to coverage tracing file.')
|
help='set tracing file, default: ".figleaf".')
|
||||||
group.addoption('--figleaf-html', action='store', default='html',
|
group.addoption('--fig-html', action='store', default='html',
|
||||||
dest='figleafhtml',
|
dest='figleafhtml', metavar="dir",
|
||||||
help='path to the coverage html dir.')
|
help='set html reporting dir, default "html").')
|
||||||
|
|
||||||
def pytest_configure(config):
|
def pytest_configure(config):
|
||||||
figleaf.start()
|
if config.getvalue("figleaf"):
|
||||||
|
figleaf.start()
|
||||||
|
|
||||||
def pytest_terminal_summary(terminalreporter):
|
def pytest_terminal_summary(terminalreporter):
|
||||||
config = terminalreporter.config
|
config = terminalreporter.config
|
||||||
|
if not config.getvalue("figleaf"):
|
||||||
|
return
|
||||||
datafile = py.path.local(config.getvalue('figleafdata'))
|
datafile = py.path.local(config.getvalue('figleafdata'))
|
||||||
tw = terminalreporter._tw
|
tw = terminalreporter._tw
|
||||||
tw.sep('-', 'figleaf')
|
tw.sep('-', 'figleaf')
|
||||||
|
|
|
@ -2,16 +2,16 @@ import py
|
||||||
|
|
||||||
def test_functional(testdir):
|
def test_functional(testdir):
|
||||||
py.test.importorskip("figleaf")
|
py.test.importorskip("figleaf")
|
||||||
testdir.plugins.append("figleaf")
|
|
||||||
testdir.makepyfile("""
|
testdir.makepyfile("""
|
||||||
def f():
|
def f():
|
||||||
x = 42
|
x = 42
|
||||||
def test_whatever():
|
def test_whatever():
|
||||||
pass
|
pass
|
||||||
""")
|
""")
|
||||||
result = testdir.runpytest('-F')
|
result = testdir.runpytest('--figleaf')
|
||||||
assert result.ret == 0
|
assert result.ret == 0
|
||||||
assert result.stdout.fnmatch_lines([
|
assert result.stdout.fnmatch_lines([
|
||||||
'*figleaf html*'
|
'*figleaf html*'
|
||||||
])
|
])
|
||||||
#print result.stdout.str()
|
#print result.stdout.str()
|
||||||
|
|
||||||
|
|
|
@ -8,12 +8,6 @@ class TestParser:
|
||||||
out, err = capsys.readouterr()
|
out, err = capsys.readouterr()
|
||||||
assert out.find("xyz") != -1
|
assert out.find("xyz") != -1
|
||||||
|
|
||||||
def test_epilog(self):
|
|
||||||
parser = parseopt.Parser()
|
|
||||||
assert not parser.epilog
|
|
||||||
parser.epilog += "hello"
|
|
||||||
assert parser.epilog == "hello"
|
|
||||||
|
|
||||||
def test_group_add_and_get(self):
|
def test_group_add_and_get(self):
|
||||||
parser = parseopt.Parser()
|
parser = parseopt.Parser()
|
||||||
group = parser.addgroup("hello", description="desc")
|
group = parser.addgroup("hello", description="desc")
|
||||||
|
@ -117,9 +111,9 @@ class TestParser:
|
||||||
def test_addoption_parser_epilog(testdir):
|
def test_addoption_parser_epilog(testdir):
|
||||||
testdir.makeconftest("""
|
testdir.makeconftest("""
|
||||||
def pytest_addoption(parser):
|
def pytest_addoption(parser):
|
||||||
parser.epilog = "hello world"
|
parser.hints.append("hello world")
|
||||||
""")
|
""")
|
||||||
result = testdir.runpytest('--help')
|
result = testdir.runpytest('--help')
|
||||||
#assert result.ret != 0
|
#assert result.ret != 0
|
||||||
assert result.stdout.fnmatch_lines(["*hello world*"])
|
assert result.stdout.fnmatch_lines(["*hint: hello world*"])
|
||||||
|
|
||||||
|
|
|
@ -16,18 +16,17 @@ class TestBootstrapping:
|
||||||
""")
|
""")
|
||||||
|
|
||||||
def test_plugin_skip(self, testdir, monkeypatch):
|
def test_plugin_skip(self, testdir, monkeypatch):
|
||||||
testdir.makepyfile(pytest_skipping1="""
|
p = testdir.makepyfile(pytest_skipping1="""
|
||||||
import py
|
import py
|
||||||
py.test.skip("hello")
|
py.test.skip("hello")
|
||||||
""")
|
""")
|
||||||
result = testdir.runpytest("-p", "skipping1")
|
p.copy(p.dirpath("pytest_skipping2.py"))
|
||||||
|
monkeypatch.setenv("PYTEST_PLUGINS", "skipping2")
|
||||||
|
result = testdir.runpytest("-p", "skipping1", "--traceconfig")
|
||||||
|
assert result.ret == 0
|
||||||
result.stdout.fnmatch_lines([
|
result.stdout.fnmatch_lines([
|
||||||
"*WARNING*could not import plugin*skipping1*hello*"
|
"*hint*skipping2*hello*",
|
||||||
])
|
"*hint*skipping1*hello*",
|
||||||
monkeypatch.setenv("PYTEST_PLUGINS", "skipping1")
|
|
||||||
result = testdir.runpytest()
|
|
||||||
result.stdout.fnmatch_lines([
|
|
||||||
"*WARNING*could not import plugin*skipping1*hello*"
|
|
||||||
])
|
])
|
||||||
|
|
||||||
def test_consider_env_plugin_instantiation(self, testdir, monkeypatch):
|
def test_consider_env_plugin_instantiation(self, testdir, monkeypatch):
|
||||||
|
|
Loading…
Reference in New Issue