From 96c863b3c1d3974be59ad633f1516eb6b0e67b89 Mon Sep 17 00:00:00 2001 From: holger krekel Date: Mon, 3 Aug 2009 11:56:56 +0200 Subject: [PATCH] rename pocoo to "pastebin" plugin, write documentation, implement whole-session-pasting --HG-- branch : 1.0.x --- doc/test/plugin/index.txt | 2 +- doc/test/plugin/iocapture.txt | 4 +- doc/test/plugin/links.txt | 30 +++---- doc/test/plugin/pocoo.txt | 31 ------- makepluginlist.py | 2 +- py/io/terminalwriter.py | 9 +- py/test/defaultconftest.py | 2 +- py/test/plugin/pytest_iocapture.py | 4 +- py/test/plugin/pytest_pastebin.py | 130 +++++++++++++++++++++++++++++ py/test/plugin/pytest_pocoo.py | 63 -------------- py/test/plugin/pytest_terminal.py | 2 +- 11 files changed, 155 insertions(+), 124 deletions(-) create mode 100644 py/test/plugin/pytest_pastebin.py delete mode 100644 py/test/plugin/pytest_pocoo.py diff --git a/doc/test/plugin/index.txt b/doc/test/plugin/index.txt index f7e6cee6d..d1ba3ea7e 100644 --- a/doc/test/plugin/index.txt +++ b/doc/test/plugin/index.txt @@ -28,7 +28,7 @@ restdoc_ perform ReST syntax, local and remote reference tests on .rst/.txt file Plugins for generic reporting and failure logging ================================================= -pocoo_ submit failure information to paste.pocoo.org +pastebin_ submit failure or test session information to a pastebin service. resultlog_ resultlog plugin for machine-readable logging of test results. diff --git a/doc/test/plugin/iocapture.txt b/doc/test/plugin/iocapture.txt index c3a01d658..8639a3711 100644 --- a/doc/test/plugin/iocapture.txt +++ b/doc/test/plugin/iocapture.txt @@ -113,8 +113,8 @@ command line options ``-s`` shortcut for --capture=no. -``--capture=capture`` - set IO capturing method during tests: sys|fd|no. +``--capture=method`` + set capturing method during tests: fd (default)|sys|no. Start improving this plugin in 30 seconds ========================================= diff --git a/doc/test/plugin/links.txt b/doc/test/plugin/links.txt index 8735f6ebc..b43aac69d 100644 --- a/doc/test/plugin/links.txt +++ b/doc/test/plugin/links.txt @@ -1,33 +1,33 @@ -.. _`pytest_recwarn.py`: http://bitbucket.org/hpk42/py-trunk/raw/69bd12627e4d304c89c2003842703ccb10dfe838/py/test/plugin/pytest_recwarn.py -.. _`pytest_iocapture.py`: http://bitbucket.org/hpk42/py-trunk/raw/69bd12627e4d304c89c2003842703ccb10dfe838/py/test/plugin/pytest_iocapture.py -.. _`pytest_monkeypatch.py`: http://bitbucket.org/hpk42/py-trunk/raw/69bd12627e4d304c89c2003842703ccb10dfe838/py/test/plugin/pytest_monkeypatch.py +.. _`pytest_recwarn.py`: http://bitbucket.org/hpk42/py-trunk/raw/6f105e72c160bd25ad7bbd4d30b1e4e92f275939/py/test/plugin/pytest_recwarn.py +.. _`pytest_iocapture.py`: http://bitbucket.org/hpk42/py-trunk/raw/6f105e72c160bd25ad7bbd4d30b1e4e92f275939/py/test/plugin/pytest_iocapture.py +.. _`pytest_monkeypatch.py`: http://bitbucket.org/hpk42/py-trunk/raw/6f105e72c160bd25ad7bbd4d30b1e4e92f275939/py/test/plugin/pytest_monkeypatch.py +.. _`pytest_keyword.py`: http://bitbucket.org/hpk42/py-trunk/raw/6f105e72c160bd25ad7bbd4d30b1e4e92f275939/py/test/plugin/pytest_keyword.py +.. _`pastebin`: pastebin.html .. _`plugins`: index.html -.. _`pytest_doctest.py`: http://bitbucket.org/hpk42/py-trunk/raw/69bd12627e4d304c89c2003842703ccb10dfe838/py/test/plugin/pytest_doctest.py +.. _`pytest_doctest.py`: http://bitbucket.org/hpk42/py-trunk/raw/6f105e72c160bd25ad7bbd4d30b1e4e92f275939/py/test/plugin/pytest_doctest.py .. _`terminal`: terminal.html .. _`hooklog`: hooklog.html -.. _`pytest_restdoc.py`: http://bitbucket.org/hpk42/py-trunk/raw/69bd12627e4d304c89c2003842703ccb10dfe838/py/test/plugin/pytest_restdoc.py +.. _`pytest_restdoc.py`: http://bitbucket.org/hpk42/py-trunk/raw/6f105e72c160bd25ad7bbd4d30b1e4e92f275939/py/test/plugin/pytest_restdoc.py +.. _`pytest_hooklog.py`: http://bitbucket.org/hpk42/py-trunk/raw/6f105e72c160bd25ad7bbd4d30b1e4e92f275939/py/test/plugin/pytest_hooklog.py +.. _`pytest_pastebin.py`: http://bitbucket.org/hpk42/py-trunk/raw/6f105e72c160bd25ad7bbd4d30b1e4e92f275939/py/test/plugin/pytest_pastebin.py +.. _`pytest_figleaf.py`: http://bitbucket.org/hpk42/py-trunk/raw/6f105e72c160bd25ad7bbd4d30b1e4e92f275939/py/test/plugin/pytest_figleaf.py .. _`xfail`: xfail.html -.. _`pytest_pocoo.py`: http://bitbucket.org/hpk42/py-trunk/raw/69bd12627e4d304c89c2003842703ccb10dfe838/py/test/plugin/pytest_pocoo.py -.. _`pytest_keyword.py`: http://bitbucket.org/hpk42/py-trunk/raw/69bd12627e4d304c89c2003842703ccb10dfe838/py/test/plugin/pytest_keyword.py -.. _`pytest_figleaf.py`: http://bitbucket.org/hpk42/py-trunk/raw/69bd12627e4d304c89c2003842703ccb10dfe838/py/test/plugin/pytest_figleaf.py -.. _`pytest_hooklog.py`: http://bitbucket.org/hpk42/py-trunk/raw/69bd12627e4d304c89c2003842703ccb10dfe838/py/test/plugin/pytest_hooklog.py .. _`contact`: ../../contact.html -.. _`pocoo`: pocoo.html .. _`checkout the py.test development version`: ../../download.html#checkout .. _`oejskit`: oejskit.html .. _`unittest`: unittest.html .. _`iocapture`: iocapture.html -.. _`pytest_xfail.py`: http://bitbucket.org/hpk42/py-trunk/raw/69bd12627e4d304c89c2003842703ccb10dfe838/py/test/plugin/pytest_xfail.py +.. _`pytest_xfail.py`: http://bitbucket.org/hpk42/py-trunk/raw/6f105e72c160bd25ad7bbd4d30b1e4e92f275939/py/test/plugin/pytest_xfail.py .. _`figleaf`: figleaf.html .. _`extend`: ../extend.html -.. _`pytest_terminal.py`: http://bitbucket.org/hpk42/py-trunk/raw/69bd12627e4d304c89c2003842703ccb10dfe838/py/test/plugin/pytest_terminal.py +.. _`pytest_terminal.py`: http://bitbucket.org/hpk42/py-trunk/raw/6f105e72c160bd25ad7bbd4d30b1e4e92f275939/py/test/plugin/pytest_terminal.py .. _`recwarn`: recwarn.html -.. _`pytest_pdb.py`: http://bitbucket.org/hpk42/py-trunk/raw/69bd12627e4d304c89c2003842703ccb10dfe838/py/test/plugin/pytest_pdb.py +.. _`pytest_pdb.py`: http://bitbucket.org/hpk42/py-trunk/raw/6f105e72c160bd25ad7bbd4d30b1e4e92f275939/py/test/plugin/pytest_pdb.py .. _`monkeypatch`: monkeypatch.html .. _`resultlog`: resultlog.html .. _`keyword`: keyword.html .. _`restdoc`: restdoc.html -.. _`pytest_unittest.py`: http://bitbucket.org/hpk42/py-trunk/raw/69bd12627e4d304c89c2003842703ccb10dfe838/py/test/plugin/pytest_unittest.py +.. _`pytest_unittest.py`: http://bitbucket.org/hpk42/py-trunk/raw/6f105e72c160bd25ad7bbd4d30b1e4e92f275939/py/test/plugin/pytest_unittest.py .. _`doctest`: doctest.html -.. _`pytest_resultlog.py`: http://bitbucket.org/hpk42/py-trunk/raw/69bd12627e4d304c89c2003842703ccb10dfe838/py/test/plugin/pytest_resultlog.py +.. _`pytest_resultlog.py`: http://bitbucket.org/hpk42/py-trunk/raw/6f105e72c160bd25ad7bbd4d30b1e4e92f275939/py/test/plugin/pytest_resultlog.py .. _`pdb`: pdb.html diff --git a/doc/test/plugin/pocoo.txt b/doc/test/plugin/pocoo.txt index c4c3b5d9a..e69de29bb 100644 --- a/doc/test/plugin/pocoo.txt +++ b/doc/test/plugin/pocoo.txt @@ -1,31 +0,0 @@ - -pytest_pocoo plugin -=================== - -submit failure information to paste.pocoo.org - -.. contents:: - :local: - - - -command line options --------------------- - - -``-P, --pocoo-sendfailures`` - send failures to http://paste.pocoo.org paste service - -Start improving this plugin in 30 seconds -========================================= - - -Do you find the above documentation or the plugin itself lacking? - -1. Download `pytest_pocoo.py`_ plugin source code -2. put it somewhere as ``pytest_pocoo.py`` into your import path -3. a subsequent ``py.test`` run will use your local version - -Further information: extend_ documentation, other plugins_ or contact_. - -.. include:: links.txt diff --git a/makepluginlist.py b/makepluginlist.py index 70bd69faa..1b355e0f1 100644 --- a/makepluginlist.py +++ b/makepluginlist.py @@ -9,7 +9,7 @@ plugins = [ ('Plugins for other testing styles and languages', 'unittest doctest oejskit restdoc'), ('Plugins for generic reporting and failure logging', - 'pocoo resultlog terminal',), + 'pastebin resultlog terminal',), ('internal plugins / core functionality', 'pdb keyword hooklog') #('internal plugins / core functionality', diff --git a/py/io/terminalwriter.py b/py/io/terminalwriter.py index 98eeb7c78..85390e7c2 100644 --- a/py/io/terminalwriter.py +++ b/py/io/terminalwriter.py @@ -201,13 +201,8 @@ class TerminalWriter(object): self._file.flush() def line(self, s='', **kw): - if s: - s = self.markup(s, **kw) - self._file.write(s + '\n') - else: - self._file.write('\n') - self._file.flush() - + self.write(s, **kw) + self.write('\n') class Win32ConsoleWriter(object): diff --git a/py/test/defaultconftest.py b/py/test/defaultconftest.py index a57d5fcfc..6c39d859e 100644 --- a/py/test/defaultconftest.py +++ b/py/test/defaultconftest.py @@ -10,6 +10,6 @@ Generator = py.test.collect.Generator Function = py.test.collect.Function Instance = py.test.collect.Instance -pytest_plugins = "default runner iocapture terminal keyword xfail tmpdir execnetcleanup monkeypatch recwarn pdb unittest".split() +pytest_plugins = "default runner iocapture terminal keyword xfail tmpdir execnetcleanup monkeypatch recwarn pdb pastebin unittest".split() conf_capture = "fd" diff --git a/py/test/plugin/pytest_iocapture.py b/py/test/plugin/pytest_iocapture.py index 33a53f586..a59075a9b 100644 --- a/py/test/plugin/pytest_iocapture.py +++ b/py/test/plugin/pytest_iocapture.py @@ -89,8 +89,8 @@ def pytest_addoption(parser): group._addoption('-s', action="store_const", const="no", dest="capture", help="shortcut for --capture=no.") group._addoption('--capture', action="store", default=None, - metavar="capture", type="choice", choices=['fd', 'sys', 'no'], - help="set IO capturing method during tests: sys|fd|no.") + metavar="method", type="choice", choices=['fd', 'sys', 'no'], + help="set capturing method during tests: fd (default)|sys|no.") def addouterr(rep, outerr): repr = getattr(rep, 'longrepr', None) diff --git a/py/test/plugin/pytest_pastebin.py b/py/test/plugin/pytest_pastebin.py new file mode 100644 index 000000000..3d2cbc2af --- /dev/null +++ b/py/test/plugin/pytest_pastebin.py @@ -0,0 +1,130 @@ +""" +submit failure or test session information to a pastebin service. + +Usage +---------- + +**Creating a URL for each test failure**:: + + py.test --pastebin=failed + +This will submit full failure information to a remote Paste service and +provide a URL for each failure. You may select tests as usual or add +for example ``-x`` if you only want to send one particular failure. + +**Creating a URL for a whole test session log**:: + + py.test --pastebin=all + +Currently only pasting to the http://paste.pocoo.org service is implemented. + +""" +import py, sys + +class url: + base = "http://paste.pocoo.org" + xmlrpc = base + "/xmlrpc/" + show = base + "/show/" + +def pytest_addoption(parser): + group = parser.getgroup("general") + group._addoption('--pastebin', metavar="mode", + action='store', dest="pastebin", default=None, + type="choice", choices=['failed', 'all'], + help="send failed|all info to Pocoo pastebin service.") + +def pytest_configure(__call__, config): + import tempfile + __call__.execute() + if config.option.pastebin == "all": + config._pastebinfile = tempfile.TemporaryFile() + tr = config.pluginmanager.impname2plugin['terminalreporter'] + oldwrite = tr._tw.write + def tee_write(s, **kwargs): + oldwrite(s, **kwargs) + config._pastebinfile.write(str(s)) + tr._tw.write = tee_write + +def pytest_unconfigure(config): + if hasattr(config, '_pastebinfile'): + config._pastebinfile.seek(0) + sessionlog = config._pastebinfile.read() + config._pastebinfile.close() + del config._pastebinfile + proxyid = getproxy().newPaste("python", sessionlog) + pastebinurl = "%s%s" % (url.show, proxyid) + print >>sys.stderr, "session-log:", pastebinurl + tr = config.pluginmanager.impname2plugin['terminalreporter'] + del tr._tw.__dict__['write'] + +def getproxy(): + return py.std.xmlrpclib.ServerProxy(url.xmlrpc).pastes + +def pytest_terminal_summary(terminalreporter): + if terminalreporter.config.option.pastebin != "failed": + return + tr = terminalreporter + if 'failed' in tr.stats: + terminalreporter.write_sep("=", "Sending information to Paste Service") + if tr.config.option.debug: + terminalreporter.write_line("xmlrpcurl: %s" %(url.xmlrpc,)) + serverproxy = getproxy() + for rep in terminalreporter.stats.get('failed'): + try: + msg = rep.longrepr.reprtraceback.reprentries[-1].reprfileloc + except AttributeError: + msg = tr._getfailureheadline(rep) + tw = py.io.TerminalWriter(stringio=True) + rep.toterminal(tw) + s = tw.stringio.getvalue() + assert len(s) + proxyid = serverproxy.newPaste("python", s) + pastebinurl = "%s%s" % (url.show, proxyid) + tr.write_line("%s --> %s" %(msg, pastebinurl)) + + +class TestPasting: + def pytest_funcarg__pastebinlist(self, request): + mp = request.getfuncargvalue("monkeypatch") + pastebinlist = [] + class MockProxy: + def newPaste(self, language, code): + pastebinlist.append((language, code)) + mp.setitem(globals(), 'getproxy', MockProxy) + return pastebinlist + + def test_failed(self, testdir, pastebinlist): + testpath = testdir.makepyfile(""" + import py + def test_pass(): + pass + def test_fail(): + assert 0 + def test_skip(): + py.test.skip("") + """) + reprec = testdir.inline_run(testpath, "--paste=failed") + assert len(pastebinlist) == 1 + assert pastebinlist[0][0] == "python" + s = pastebinlist[0][1] + assert s.find("def test_fail") != -1 + assert reprec.countoutcomes() == [1,1,1] + + def test_all(self, testdir, pastebinlist): + testpath = testdir.makepyfile(""" + import py + def test_pass(): + pass + def test_fail(): + assert 0 + def test_skip(): + py.test.skip("") + """) + reprec = testdir.inline_run(testpath, "--pastebin=all") + assert reprec.countoutcomes() == [1,1,1] + assert len(pastebinlist) == 1 + assert pastebinlist[0][0] == "python" + s = pastebinlist[0][1] + for x in 'test_fail test_skip skipped'.split(): + assert s.find(x), (s, x) + diff --git a/py/test/plugin/pytest_pocoo.py b/py/test/plugin/pytest_pocoo.py deleted file mode 100644 index 4f48269c8..000000000 --- a/py/test/plugin/pytest_pocoo.py +++ /dev/null @@ -1,63 +0,0 @@ -""" -submit failure information to paste.pocoo.org -""" -import py - -class url: - base = "http://paste.pocoo.org" - xmlrpc = base + "/xmlrpc/" - show = base + "/show/" - -def pytest_addoption(parser): - group = parser.addgroup("pocoo plugin") - group.addoption('-P', '--pocoo-sendfailures', - action='store_true', dest="pocoo_sendfailures", - help="send failures to %s paste service" %(url.base,)) - -def getproxy(): - return py.std.xmlrpclib.ServerProxy(url.xmlrpc).pastes - -def pytest_terminal_summary(terminalreporter): - if terminalreporter.config.option.pocoo_sendfailures: - tr = terminalreporter - if 'failed' in tr.stats and tr.config.option.tbstyle != "no": - terminalreporter.write_sep("=", "Sending failures to %s" %(url.base,)) - terminalreporter.write_line("xmlrpcurl: %s" %(url.xmlrpc,)) - #print self.__class__.getproxy - #print self.__class__, id(self.__class__) - serverproxy = getproxy() - for ev in terminalreporter.stats.get('failed'): - tw = py.io.TerminalWriter(stringio=True) - ev.toterminal(tw) - s = tw.stringio.getvalue() - # XXX add failure summary - assert len(s) - terminalreporter.write_line("newpaste() ...") - proxyid = serverproxy.newPaste("python", s) - terminalreporter.write_line("%s%s\n" % (url.show, proxyid)) - break - - -def test_toproxy(testdir, monkeypatch): - l = [] - class MockProxy: - def newPaste(self, language, code): - l.append((language, code)) - monkeypatch.setitem(globals(), 'getproxy', MockProxy) - testdir.plugins.insert(0, globals()) - testpath = testdir.makepyfile(""" - import py - def test_pass(): - pass - def test_fail(): - assert 0 - def test_skip(): - py.test.skip("") - """) - reprec = testdir.inline_run(testpath, "-P") - assert len(l) == 1 - assert l[0][0] == "python" - s = l[0][1] - assert s.find("def test_fail") != -1 - assert reprec.countoutcomes() == [1,1,1] - diff --git a/py/test/plugin/pytest_terminal.py b/py/test/plugin/pytest_terminal.py index 9347aa63c..d432838da 100644 --- a/py/test/plugin/pytest_terminal.py +++ b/py/test/plugin/pytest_terminal.py @@ -18,7 +18,7 @@ def pytest_configure(config): name = attr.split("_")[-1] assert hasattr(self.reporter._tw, name), name setattr(reporter._tw, name, getattr(config, attr)) - config.pluginmanager.register(reporter) + config.pluginmanager.register(reporter, 'terminalreporter') class TerminalReporter: def __init__(self, config, file=None):