plugin cleanups
* make pytest_eventlog.py work again by adding a hack to the registry, rename * disable resultdb hook plugin, it needs merging with resultlog * add some docstrings, streamline bits --HG-- branch : trunk
This commit is contained in:
parent
219e627f87
commit
d1f24aa251
|
@ -63,6 +63,7 @@ class Registry:
|
||||||
"""
|
"""
|
||||||
Manage Plugins: Load plugins and manage calls to plugins.
|
Manage Plugins: Load plugins and manage calls to plugins.
|
||||||
"""
|
"""
|
||||||
|
logfile = None
|
||||||
MultiCall = MultiCall
|
MultiCall = MultiCall
|
||||||
|
|
||||||
def __init__(self, plugins=None):
|
def __init__(self, plugins=None):
|
||||||
|
@ -130,6 +131,11 @@ class HookCall:
|
||||||
"for api call to %r" % self.name)
|
"for api call to %r" % self.name)
|
||||||
attr = self.registry.listattr(self.name, extra=self.extralookup)
|
attr = self.registry.listattr(self.name, extra=self.extralookup)
|
||||||
mc = MultiCall(attr, **kwargs)
|
mc = MultiCall(attr, **kwargs)
|
||||||
|
# XXX this should be doable from a hook impl:
|
||||||
|
if self.registry.logfile:
|
||||||
|
self.registry.logfile.write("%s(**%s) # firstresult=%s\n" %
|
||||||
|
(self.name, kwargs, self.firstresult))
|
||||||
|
self.registry.logfile.flush()
|
||||||
return mc.execute(firstresult=self.firstresult)
|
return mc.execute(firstresult=self.firstresult)
|
||||||
|
|
||||||
comregistry = Registry()
|
comregistry = Registry()
|
||||||
|
|
|
@ -18,6 +18,7 @@ def pytest_funcarg__testdir(request):
|
||||||
basename = request.module.__name__.split(".")[-1]
|
basename = request.module.__name__.split(".")[-1]
|
||||||
if basename.startswith("pytest_"):
|
if basename.startswith("pytest_"):
|
||||||
testdir.plugins.append(vars(request.module))
|
testdir.plugins.append(vars(request.module))
|
||||||
|
testdir.plugins.append(basename)
|
||||||
else:
|
else:
|
||||||
pass # raise ValueError("need better support code")
|
pass # raise ValueError("need better support code")
|
||||||
return testdir
|
return testdir
|
||||||
|
|
|
@ -1,4 +1,9 @@
|
||||||
|
"""
|
||||||
|
automatically collect and execute doctests.
|
||||||
|
"""
|
||||||
|
|
||||||
import py
|
import py
|
||||||
|
from py.__.code.excinfo import Repr, ReprFileLocation
|
||||||
|
|
||||||
def pytest_addoption(parser):
|
def pytest_addoption(parser):
|
||||||
group = parser.addgroup("doctest options")
|
group = parser.addgroup("doctest options")
|
||||||
|
@ -13,8 +18,6 @@ def pytest_collect_file(path, parent):
|
||||||
if path.check(fnmatch="test_*.txt"):
|
if path.check(fnmatch="test_*.txt"):
|
||||||
return DoctestTextfile(path, parent)
|
return DoctestTextfile(path, parent)
|
||||||
|
|
||||||
from py.__.code.excinfo import Repr, ReprFileLocation
|
|
||||||
|
|
||||||
class ReprFailDoctest(Repr):
|
class ReprFailDoctest(Repr):
|
||||||
def __init__(self, reprlocation, lines):
|
def __init__(self, reprlocation, lines):
|
||||||
self.reprlocation = reprlocation
|
self.reprlocation = reprlocation
|
||||||
|
|
|
@ -1,45 +0,0 @@
|
||||||
import py
|
|
||||||
|
|
||||||
""" expected to fail.
|
|
||||||
"""
|
|
||||||
|
|
||||||
class EventlogPlugin:
|
|
||||||
""" log pytest events to a file. """
|
|
||||||
def pytest_addoption(self, parser):
|
|
||||||
parser.addoption("--eventlog", dest="eventlog",
|
|
||||||
help="write all pytest events to the given file.")
|
|
||||||
|
|
||||||
def pytest_configure(self, config):
|
|
||||||
eventlog = config.getvalue("eventlog")
|
|
||||||
if eventlog:
|
|
||||||
self.eventlogfile = open(eventlog, 'w')
|
|
||||||
|
|
||||||
def pytest_unconfigure(self, config):
|
|
||||||
if hasattr(self, 'eventlogfile'):
|
|
||||||
self.eventlogfile.close()
|
|
||||||
del self.eventlogfile
|
|
||||||
|
|
||||||
def pyevent(self, eventname, args, kwargs):
|
|
||||||
if hasattr(self, 'eventlogfile'):
|
|
||||||
f = self.eventlogfile
|
|
||||||
print >>f, eventname, args, kwargs
|
|
||||||
f.flush()
|
|
||||||
|
|
||||||
# ===============================================================================
|
|
||||||
# plugin tests
|
|
||||||
# ===============================================================================
|
|
||||||
|
|
||||||
@py.test.mark.xfail
|
|
||||||
def test_generic(plugintester):
|
|
||||||
plugintester.hookcheck()
|
|
||||||
|
|
||||||
testdir = plugintester.testdir()
|
|
||||||
testdir.makepyfile("""
|
|
||||||
def test_pass():
|
|
||||||
pass
|
|
||||||
""")
|
|
||||||
testdir.runpytest("--eventlog=event.log")
|
|
||||||
s = testdir.tmpdir.join("event.log").read()
|
|
||||||
assert s.find("testrunstart") != -1
|
|
||||||
assert s.find("ItemTestReport") != -1
|
|
||||||
assert s.find("testrunfinish") != -1
|
|
|
@ -1,3 +1,6 @@
|
||||||
|
"""
|
||||||
|
cleanup gateways that were instantiated during a test function run.
|
||||||
|
"""
|
||||||
import py
|
import py
|
||||||
|
|
||||||
def pytest_configure(config):
|
def pytest_configure(config):
|
||||||
|
|
|
@ -1,3 +1,6 @@
|
||||||
|
"""
|
||||||
|
write and report coverage data using the 'figleaf' module.
|
||||||
|
"""
|
||||||
import py
|
import py
|
||||||
|
|
||||||
figleaf = py.test.importorskip("figleaf")
|
figleaf = py.test.importorskip("figleaf")
|
||||||
|
|
|
@ -0,0 +1,36 @@
|
||||||
|
""" log calling of plugin hooks to a file. """
|
||||||
|
import py
|
||||||
|
|
||||||
|
def pytest_addoption(parser):
|
||||||
|
parser.addoption("--hooklog", dest="hooklog", default=None,
|
||||||
|
help="write hook calls to the given file.")
|
||||||
|
|
||||||
|
def pytest_configure(config):
|
||||||
|
hooklog = config.getvalue("hooklog")
|
||||||
|
if hooklog:
|
||||||
|
assert not config.pluginmanager.comregistry.logfile
|
||||||
|
config.pluginmanager.comregistry.logfile = open(hooklog, 'w')
|
||||||
|
|
||||||
|
def pytest_unconfigure(config):
|
||||||
|
f = config.pluginmanager.comregistry.logfile
|
||||||
|
if f:
|
||||||
|
f.close()
|
||||||
|
config.pluginmanager.comregistry.logfile = None
|
||||||
|
|
||||||
|
# ===============================================================================
|
||||||
|
# plugin tests
|
||||||
|
# ===============================================================================
|
||||||
|
|
||||||
|
def test_generic(plugintester):
|
||||||
|
plugintester.hookcheck()
|
||||||
|
|
||||||
|
def test_functional(testdir):
|
||||||
|
testdir.makepyfile("""
|
||||||
|
def test_pass():
|
||||||
|
pass
|
||||||
|
""")
|
||||||
|
testdir.runpytest("--hooklog=hook.log")
|
||||||
|
s = testdir.tmpdir.join("hook.log").read()
|
||||||
|
assert s.find("pytest_testrunstart") != -1
|
||||||
|
assert s.find("ItemTestReport") != -1
|
||||||
|
assert s.find("testrunfinish") != -1
|
|
@ -1,12 +1,22 @@
|
||||||
|
"""
|
||||||
|
'capsys' and 'capfd' funcargs for capturing stdout/stderror either
|
||||||
|
by intercepting sys.stdout/stderr or File Descriptors 1/2.
|
||||||
|
|
||||||
|
Calling the reset() method of the capture funcargs gives
|
||||||
|
a out/err tuple of strings representing the captured streams.
|
||||||
|
You can call reset() multiple times each time getting
|
||||||
|
the chunk of output that was captured between the invocations.
|
||||||
|
|
||||||
|
"""
|
||||||
import py
|
import py
|
||||||
|
|
||||||
def pytest_funcarg__stdcapture(request):
|
def pytest_funcarg__capsys(request):
|
||||||
""" capture writes to sys.stdout/sys.stderr. """
|
""" capture writes to sys.stdout/sys.stderr. """
|
||||||
capture = Capture(py.io.StdCapture)
|
capture = Capture(py.io.StdCapture)
|
||||||
request.addfinalizer(capture.finalize)
|
request.addfinalizer(capture.finalize)
|
||||||
return capture
|
return capture
|
||||||
|
|
||||||
def pytest_funcarg__stdcapturefd(request):
|
def pytest_funcarg__capfd(request):
|
||||||
""" capture writes to filedescriptors 1 and 2"""
|
""" capture writes to filedescriptors 1 and 2"""
|
||||||
capture = Capture(py.io.StdCaptureFD)
|
capture = Capture(py.io.StdCaptureFD)
|
||||||
request.addfinalizer(capture.finalize)
|
request.addfinalizer(capture.finalize)
|
||||||
|
@ -31,19 +41,19 @@ def test_generic(plugintester):
|
||||||
class TestCapture:
|
class TestCapture:
|
||||||
def test_std_functional(self, testdir):
|
def test_std_functional(self, testdir):
|
||||||
reprec = testdir.inline_runsource("""
|
reprec = testdir.inline_runsource("""
|
||||||
def test_hello(stdcapture):
|
def test_hello(capsys):
|
||||||
print 42
|
print 42
|
||||||
out, err = stdcapture.reset()
|
out, err = capsys.reset()
|
||||||
assert out.startswith("42")
|
assert out.startswith("42")
|
||||||
""")
|
""")
|
||||||
reprec.assertoutcome(passed=1)
|
reprec.assertoutcome(passed=1)
|
||||||
|
|
||||||
def test_stdfd_functional(self, testdir):
|
def test_stdfd_functional(self, testdir):
|
||||||
reprec = testdir.inline_runsource("""
|
reprec = testdir.inline_runsource("""
|
||||||
def test_hello(stdcapturefd):
|
def test_hello(capfd):
|
||||||
import os
|
import os
|
||||||
os.write(1, "42")
|
os.write(1, "42")
|
||||||
out, err = stdcapturefd.reset()
|
out, err = capfd.reset()
|
||||||
assert out.startswith("42")
|
assert out.startswith("42")
|
||||||
""")
|
""")
|
||||||
reprec.assertoutcome(passed=1)
|
reprec.assertoutcome(passed=1)
|
||||||
|
|
|
@ -1,17 +1,15 @@
|
||||||
import os
|
|
||||||
"""
|
"""
|
||||||
provides the "monkeypatch" funcarg for safely patching objects,
|
"monkeypatch" funcarg for safely patching objects,
|
||||||
dictionaries and environment variables during the execution of
|
dictionaries and environment variables during the execution of
|
||||||
a test. There are three helper functions:
|
a test. "monkeypatch" has three helper functions:
|
||||||
|
|
||||||
monkeypatch.setattr(obj, name, value)
|
monkeypatch.setattr(obj, name, value)
|
||||||
monkeypatch.setitem(obj, name, value)
|
monkeypatch.setitem(obj, name, value)
|
||||||
monkeypatch.setenv(name, value)
|
monkeypatch.setenv(name, value)
|
||||||
|
|
||||||
After the test run all such modifications will be undone,
|
After the test has run modifications will be undone.
|
||||||
which may even mean deleting the attribute or dictionary entry
|
|
||||||
if it didn't exist before.
|
|
||||||
"""
|
"""
|
||||||
|
import os
|
||||||
|
|
||||||
def pytest_funcarg__monkeypatch(request):
|
def pytest_funcarg__monkeypatch(request):
|
||||||
monkeypatch = MonkeyPatch()
|
monkeypatch = MonkeyPatch()
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
""" XXX should be used sometime. """
|
||||||
from py.__.test.custompdb import post_mortem
|
from py.__.test.custompdb import post_mortem
|
||||||
|
|
||||||
def pytest_item_runtest_finished(item, excinfo, outerr):
|
def pytest_item_runtest_finished(item, excinfo, outerr):
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
"""pylint plugin
|
"""pylint plugin
|
||||||
|
|
||||||
|
|
||||||
XXX: Currently in progress, NOT IN WORKING STATE.
|
XXX: Currently in progress, NOT IN WORKING STATE.
|
||||||
"""
|
"""
|
||||||
import py
|
import py
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
"""
|
"""
|
||||||
pytes plugin for easing testing of pytest runs themselves.
|
funcargs and support code for testing py.test functionality.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import py
|
import py
|
||||||
|
|
|
@ -1,8 +1,5 @@
|
||||||
"""
|
"""
|
||||||
|
"recwarn" funcarg for asserting that warnings are shown to a user.
|
||||||
provides "recwarn" funcarg for asserting warnings to be shown
|
|
||||||
to a user. See the test at the bottom for an example.
|
|
||||||
|
|
||||||
"""
|
"""
|
||||||
import py
|
import py
|
||||||
import os
|
import os
|
||||||
|
|
|
@ -1,3 +1,7 @@
|
||||||
|
"""
|
||||||
|
perform ReST specific tests on .txt files, including
|
||||||
|
linkchecks and remote URL checks.
|
||||||
|
"""
|
||||||
import py
|
import py
|
||||||
|
|
||||||
def pytest_addoption(parser):
|
def pytest_addoption(parser):
|
||||||
|
|
|
@ -1,7 +1,3 @@
|
||||||
import py
|
|
||||||
from pytest_resultlog import ResultLog
|
|
||||||
|
|
||||||
class ResultdbPlugin:
|
|
||||||
"""XXX in progress: resultdb plugin for database logging of test results.
|
"""XXX in progress: resultdb plugin for database logging of test results.
|
||||||
|
|
||||||
Saves test results to a datastore.
|
Saves test results to a datastore.
|
||||||
|
@ -11,7 +7,13 @@ class ResultdbPlugin:
|
||||||
Also mixes in some early ideas about an archive abstraction for test
|
Also mixes in some early ideas about an archive abstraction for test
|
||||||
results.
|
results.
|
||||||
"""
|
"""
|
||||||
def pytest_addoption(self, parser):
|
import py
|
||||||
|
|
||||||
|
py.test.skip("XXX needs to be merged with resultlog")
|
||||||
|
|
||||||
|
from pytest_resultlog import ResultLog
|
||||||
|
|
||||||
|
def pytest_addoption(parser):
|
||||||
group = parser.addgroup("resultdb", "resultdb plugin options")
|
group = parser.addgroup("resultdb", "resultdb plugin options")
|
||||||
group.addoption('--resultdb', action="store", dest="resultdb",
|
group.addoption('--resultdb', action="store", dest="resultdb",
|
||||||
metavar="path",
|
metavar="path",
|
||||||
|
@ -20,7 +22,8 @@ class ResultdbPlugin:
|
||||||
dest="resultdbformat", default='json',
|
dest="resultdbformat", default='json',
|
||||||
help="data format (json, sqlite)")
|
help="data format (json, sqlite)")
|
||||||
|
|
||||||
def pytest_configure(self, config):
|
def pytest_configure(config):
|
||||||
|
# XXX using config.XYZ is not good
|
||||||
if config.getvalue('resultdb'):
|
if config.getvalue('resultdb'):
|
||||||
if config.option.resultdb:
|
if config.option.resultdb:
|
||||||
# local import so missing module won't crash py.test
|
# local import so missing module won't crash py.test
|
||||||
|
@ -33,22 +36,16 @@ class ResultdbPlugin:
|
||||||
except ImportError:
|
except ImportError:
|
||||||
raise config.Error('Could not import simplejson module')
|
raise config.Error('Could not import simplejson module')
|
||||||
if config.option.resultdbformat.lower() == 'json':
|
if config.option.resultdbformat.lower() == 'json':
|
||||||
self.resultdb = ResultDB(JSONResultArchive,
|
resultdb = ResultDB(JSONResultArchive,
|
||||||
config.option.resultdb)
|
config.option.resultdb)
|
||||||
elif config.option.resultdbformat.lower() == 'sqlite':
|
elif config.option.resultdbformat.lower() == 'sqlite':
|
||||||
self.resultdb = ResultDB(SQLiteResultArchive,
|
resultdb = ResultDB(SQLiteResultArchive,
|
||||||
config.option.resultdb)
|
config.option.resultdb)
|
||||||
else:
|
else:
|
||||||
raise config.Error('Unknown --resultdb_format: %s' %
|
raise config.Error('Unknown --resultdb_format: %s' %
|
||||||
config.option.resultdbformat)
|
config.option.resultdbformat)
|
||||||
|
|
||||||
config.pluginmanager.register(self.resultdb)
|
config.pluginmanager.register(resultdb)
|
||||||
|
|
||||||
def pytest_unconfigure(self, config):
|
|
||||||
if hasattr(self, 'resultdb'):
|
|
||||||
del self.resultdb
|
|
||||||
#config.pluginmanager.unregister(self.resultdb)
|
|
||||||
|
|
||||||
|
|
||||||
class JSONResultArchive(object):
|
class JSONResultArchive(object):
|
||||||
def __init__(self, archive_path):
|
def __init__(self, archive_path):
|
||||||
|
@ -328,8 +325,7 @@ class TestWithFunctionIntegration:
|
||||||
assert x.startswith(" ")
|
assert x.startswith(" ")
|
||||||
assert "XXX" in "".join(lines[1:])
|
assert "XXX" in "".join(lines[1:])
|
||||||
|
|
||||||
def test_log_test_outcomes(self, plugintester):
|
def test_log_test_outcomes(self, testdir):
|
||||||
testdir = plugintester.testdir()
|
|
||||||
mod = testdir.makepyfile(test_mod="""
|
mod = testdir.makepyfile(test_mod="""
|
||||||
import py
|
import py
|
||||||
def test_pass(): pass
|
def test_pass(): pass
|
||||||
|
|
|
@ -10,8 +10,6 @@ this code is somewhat derived from Guido Wesdorps
|
||||||
|
|
||||||
http://johnnydebris.net/svn/projects/py_unittest
|
http://johnnydebris.net/svn/projects/py_unittest
|
||||||
|
|
||||||
$HeadURL: https://codespeak.net/svn/py/branch/pytestplugin/contrib/py_unittest/conftest.py $
|
|
||||||
$Id: conftest.py 60979 2009-01-14 22:29:32Z hpk $
|
|
||||||
"""
|
"""
|
||||||
import py
|
import py
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,8 @@
|
||||||
"""
|
"""
|
||||||
mark and report specially about "expected to fail" tests.
|
mark tests as expected-to-fail and report them separately.
|
||||||
|
|
||||||
|
example:
|
||||||
|
|
||||||
for marking and reporting "expected to fail" tests.
|
|
||||||
@py.test.mark.xfail("needs refactoring")
|
@py.test.mark.xfail("needs refactoring")
|
||||||
def test_hello():
|
def test_hello():
|
||||||
...
|
...
|
||||||
|
@ -29,7 +30,7 @@ def pytest_report_teststatus(rep):
|
||||||
elif rep.failed:
|
elif rep.failed:
|
||||||
return "xpassed", "P", "xpass"
|
return "xpassed", "P", "xpass"
|
||||||
|
|
||||||
# a hook implemented called by the terminalreporter instance/plugin
|
# called by the terminalreporter instance/plugin
|
||||||
def pytest_terminal_summary(terminalreporter):
|
def pytest_terminal_summary(terminalreporter):
|
||||||
tr = terminalreporter
|
tr = terminalreporter
|
||||||
xfailed = tr.stats.get("xfailed")
|
xfailed = tr.stats.get("xfailed")
|
||||||
|
|
Loading…
Reference in New Issue