From 56a936993cec70ed4d4db9b7c0a45b152c02b865 Mon Sep 17 00:00:00 2001 From: holger krekel Date: Sat, 2 Jan 2010 22:48:53 +0100 Subject: [PATCH] enhance figleaf setup, enabled by default now (requires --figleaf). Generalize internal ability to show "hints" at the end of "-h". --HG-- branch : trunk --- CHANGELOG | 4 ++++ py/impl/test/config.py | 1 + py/impl/test/parseopt.py | 19 ++++++++++++++----- py/impl/test/pluginmanager.py | 21 +++++++++++---------- py/plugin/pytest_default.py | 5 +++-- py/plugin/pytest_doctest.py | 2 +- py/plugin/pytest_figleaf.py | 24 +++++++++++++----------- testing/plugin/test_pytest_figleaf.py | 4 ++-- testing/pytest/test_parseopt.py | 10 ++-------- testing/pytest/test_pluginmanager.py | 15 +++++++-------- 10 files changed, 58 insertions(+), 47 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 4bac2e2bf..ea26b37a7 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -40,6 +40,10 @@ Changes between 1.X and 1.1.1 - change: the first pytest_collect_directory hook to return something 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 code failed and prevented the capturing setup code from running. diff --git a/py/impl/test/config.py b/py/impl/test/config.py index 4a47748c2..99e66a096 100644 --- a/py/impl/test/config.py +++ b/py/impl/test/config.py @@ -92,6 +92,7 @@ class Config(object): assert not hasattr(self, 'args'), ( "can only parse cmdline args at most once per Config object") self._preparse(args) + self._parser.hints.extend(self.pluginmanager._hints) args = self._parser.parse_setoption(args, self.option) if not args: args.append(py.std.os.getcwd()) diff --git a/py/impl/test/parseopt.py b/py/impl/test/parseopt.py index b1edf6118..8e282f337 100644 --- a/py/impl/test/parseopt.py +++ b/py/impl/test/parseopt.py @@ -24,7 +24,7 @@ class Parser: self._groups = [] self._processopt = processopt self._usage = usage - self.epilog = "" + self.hints = [] def processoption(self, option): if self._processopt: @@ -56,9 +56,7 @@ class Parser: self._anonymous.addoption(*opts, **attrs) def parse(self, args): - optparser = optparse.OptionParser(usage=self._usage) - # make sure anaonymous group is at the end - optparser.epilog = self.epilog + optparser = MyOptionParser(self) groups = self._groups + [self._anonymous] for group in groups: if group.options: @@ -100,4 +98,15 @@ class OptionGroup: self.parser.processoption(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 "" diff --git a/py/impl/test/pluginmanager.py b/py/impl/test/pluginmanager.py index 90fbd6884..2b8f882fa 100644 --- a/py/impl/test/pluginmanager.py +++ b/py/impl/test/pluginmanager.py @@ -9,7 +9,7 @@ from py.impl.test.outcome import Skipped default_plugins = ( "default runner capture terminal mark skipping tmpdir monkeypatch " "recwarn pdb pastebin unittest helpconfig nose assertion genscript " - "logxml").split() + "logxml figleaf").split() def check_old_use(mod, modname): clsname = modname[len('pytest_'):].capitalize() + "Plugin" @@ -19,10 +19,11 @@ class PluginManager(object): def __init__(self): self.registry = Registry() self._name2plugin = {} + self._hints = [] self.hook = HookRelay(hookspecs=hookspec, registry=self.registry) self.register(self) for spec in default_plugins: - self.import_plugin(spec) + self.import_plugin(spec) def _getpluginname(self, plugin, name): if name is None: @@ -123,15 +124,17 @@ class PluginManager(object): raise except Skipped: e = py.std.sys.exc_info()[1] - self._warn("could not import plugin %r, reason: %r" %( - (modname, e.msg))) + self._hints.append("skipped plugin %r: %s" %((modname, e.msg))) else: check_old_use(mod, modname) self.register(mod) self.consider_module(mod) - def _warn(self, msg): - print ("===WARNING=== %s" % (msg,)) + def pytest_terminal_summary(self, terminalreporter): + 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] if str(e).find(importspec) == -1: raise - #print "syspath:", py.std.sys.path - #print "curdir:", py.std.os.getcwd() - return __import__(importspec) # show the original exception - + # show the original exception, not the failing internal one + return __import__(importspec) class MultiCall: diff --git a/py/plugin/pytest_default.py b/py/plugin/pytest_default.py index d1e6fdcf8..e458d3fa9 100644 --- a/py/plugin/pytest_default.py +++ b/py/plugin/pytest_default.py @@ -80,8 +80,9 @@ def pytest_addoption(parser): if execnet: add_dist_options(parser) else: - parser.epilog = ( - "'execnet>=1.0.0b4' package required for --looponfailing / distributed testing.") + parser.hints.append( + "'execnet>=1.0.0b4' required for --looponfailing / distributed testing." + ) def add_dist_options(parser): # see http://pytest.org/help/dist") diff --git a/py/plugin/pytest_doctest.py b/py/plugin/pytest_doctest.py index 5d23a0b11..f041ff662 100644 --- a/py/plugin/pytest_doctest.py +++ b/py/plugin/pytest_doctest.py @@ -18,7 +18,7 @@ from py.impl.code.code import TerminalRepr, ReprFileLocation import doctest def pytest_addoption(parser): - group = parser.getgroup("doctest options") + group = parser.getgroup("general") group.addoption("--doctest-modules", action="store_true", default=False, help="search all python files for doctests", diff --git a/py/plugin/pytest_figleaf.py b/py/plugin/pytest_figleaf.py index 4af711001..94689ec04 100644 --- a/py/plugin/pytest_figleaf.py +++ b/py/plugin/pytest_figleaf.py @@ -3,28 +3,30 @@ write and report coverage data with 'figleaf'. """ import py - -py.test.importorskip("figleaf.annotate_html") -import figleaf +py.test.importorskip("figleaf") +import figleaf.annotate_html def pytest_addoption(parser): group = parser.getgroup('figleaf options') - group.addoption('-F', action='store_true', default=False, + group.addoption('--figleaf', action='store_true', default=False, dest = 'figleaf', help=('trace python coverage with figleaf and write HTML ' 'for files below the current working dir')) - group.addoption('--figleaf-data', action='store', default='.figleaf', - dest='figleafdata', - help='path to coverage tracing file.') - group.addoption('--figleaf-html', action='store', default='html', - dest='figleafhtml', - help='path to the coverage html dir.') + group.addoption('--fig-data', action='store', default='.figleaf', + dest='figleafdata', metavar="dir", + help='set tracing file, default: ".figleaf".') + group.addoption('--fig-html', action='store', default='html', + dest='figleafhtml', metavar="dir", + help='set html reporting dir, default "html").') def pytest_configure(config): - figleaf.start() + if config.getvalue("figleaf"): + figleaf.start() def pytest_terminal_summary(terminalreporter): config = terminalreporter.config + if not config.getvalue("figleaf"): + return datafile = py.path.local(config.getvalue('figleafdata')) tw = terminalreporter._tw tw.sep('-', 'figleaf') diff --git a/testing/plugin/test_pytest_figleaf.py b/testing/plugin/test_pytest_figleaf.py index 7e016e4cf..bfc86f047 100644 --- a/testing/plugin/test_pytest_figleaf.py +++ b/testing/plugin/test_pytest_figleaf.py @@ -2,16 +2,16 @@ import py def test_functional(testdir): py.test.importorskip("figleaf") - testdir.plugins.append("figleaf") testdir.makepyfile(""" def f(): x = 42 def test_whatever(): pass """) - result = testdir.runpytest('-F') + result = testdir.runpytest('--figleaf') assert result.ret == 0 assert result.stdout.fnmatch_lines([ '*figleaf html*' ]) #print result.stdout.str() + diff --git a/testing/pytest/test_parseopt.py b/testing/pytest/test_parseopt.py index 573ac04b2..a616ca12d 100644 --- a/testing/pytest/test_parseopt.py +++ b/testing/pytest/test_parseopt.py @@ -8,12 +8,6 @@ class TestParser: out, err = capsys.readouterr() 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): parser = parseopt.Parser() group = parser.addgroup("hello", description="desc") @@ -117,9 +111,9 @@ class TestParser: def test_addoption_parser_epilog(testdir): testdir.makeconftest(""" def pytest_addoption(parser): - parser.epilog = "hello world" + parser.hints.append("hello world") """) result = testdir.runpytest('--help') #assert result.ret != 0 - assert result.stdout.fnmatch_lines(["*hello world*"]) + assert result.stdout.fnmatch_lines(["*hint: hello world*"]) diff --git a/testing/pytest/test_pluginmanager.py b/testing/pytest/test_pluginmanager.py index 7f164d2a5..f457ead06 100644 --- a/testing/pytest/test_pluginmanager.py +++ b/testing/pytest/test_pluginmanager.py @@ -16,18 +16,17 @@ class TestBootstrapping: """) def test_plugin_skip(self, testdir, monkeypatch): - testdir.makepyfile(pytest_skipping1=""" + p = testdir.makepyfile(pytest_skipping1=""" import py 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([ - "*WARNING*could not import plugin*skipping1*hello*" - ]) - monkeypatch.setenv("PYTEST_PLUGINS", "skipping1") - result = testdir.runpytest() - result.stdout.fnmatch_lines([ - "*WARNING*could not import plugin*skipping1*hello*" + "*hint*skipping2*hello*", + "*hint*skipping1*hello*", ]) def test_consider_env_plugin_instantiation(self, testdir, monkeypatch):