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:
holger krekel 2010-01-02 22:48:53 +01:00
parent 1b6391d814
commit 56a936993c
10 changed files with 58 additions and 47 deletions

View File

@ -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.

View File

@ -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())

View File

@ -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 ""

View File

@ -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:

View File

@ -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")

View File

@ -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",

View File

@ -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')

View File

@ -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()

View File

@ -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*"])

View File

@ -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):