# HG changeset patch -- Bitbucket.org # Project pytest-xdist # URL http://bitbucket.org/hpk42/pytest-xdist/overview # User holger krekel <hol...@merlinux.eu> # Date 1289033880 -3600 # Node ID 922c00c8c2fa0bebe693cab54301a01c43159e55 # Parent 724fe27731c76cf8a91472cf8cdacfb336365765 adapt to pytest changes, add looponfailingdirs ini-option
--- a/tox.ini +++ b/tox.ini @@ -16,5 +16,5 @@ deps= pytest pypi pexpect -[pytest] -addopts = -rf +#[pytest] +#addopts = -rf --- a/xdist/dsession.py +++ b/xdist/dsession.py @@ -301,7 +301,7 @@ class DSession: runner = self.config.pluginmanager.getplugin("runner") fspath = nodeid.split("::")[0] msg = "Slave %r crashed while running %r" %(slave.gateway.id, nodeid) - rep = runner.TestReport(nodeid, (), fspath, (fspath, None, fspath), (), + rep = runner.TestReport(nodeid, (fspath, None, fspath), (), "failed", msg, "???") enrich_report_with_platform_data(rep, slave) self.config.hook.pytest_runtest_logreport(report=rep) @@ -350,6 +350,6 @@ def enrich_report_with_platform_data(rep ver = "%s.%s.%s" % d['version_info'][:3] infoline = "[%s] %s -- Python %s %s" % ( d['id'], d['sysplatform'], ver, d['executable']) - # XXX more structured longrepr? + # XXX more structured longrepr? rep.longrepr = infoline + "\n\n" + str(rep.longrepr) --- a/xdist/__init__.py +++ b/xdist/__init__.py @@ -1,2 +1,2 @@ # -__version__ = '1.5a4' +__version__ = '1.5a5' --- a/testing/test_slavemanage.py +++ b/testing/test_slavemanage.py @@ -11,7 +11,7 @@ def pytest_funcarg__hookrecorder(request def pytest_funcarg__hook(request): from xdist import newhooks - from pytest._core import HookRelay, PluginManager + from pytest.main import HookRelay, PluginManager from pytest import hookspec return HookRelay([hookspec, newhooks], PluginManager()) --- a/testing/test_remote.py +++ b/testing/test_remote.py @@ -156,6 +156,8 @@ class TestSlaveInteractor: assert not ev.kwargs ev = slave.popevent() assert ev.name == "collectreport" + ev = slave.popevent() + assert ev.name == "collectreport" rep = unserialize_report(ev.name, ev.kwargs['data']) assert rep.skipped ev = slave.popevent("collectionfinish") @@ -168,6 +170,8 @@ class TestSlaveInteractor: assert not ev.kwargs ev = slave.popevent() assert ev.name == "collectreport" + ev = slave.popevent() + assert ev.name == "collectreport" rep = unserialize_report(ev.name, ev.kwargs['data']) assert rep.failed ev = slave.popevent("collectionfinish") --- a/xdist/plugin.py +++ b/xdist/plugin.py @@ -142,7 +142,7 @@ where the configuration file was found. """ import sys -import py +import py, pytest def pytest_addoption(parser): group = parser.getgroup("xdist", "distributed and subprocess testing") @@ -178,6 +178,8 @@ def pytest_addoption(parser): ' remote distributed testing.', type="pathlist") parser.addini('rsyncignore', 'list of (relative) paths to be ignored ' 'for rsyncing.', type="pathlist") + parser.addini("looponfailroots", type="pathlist", + help="directories to check for changes", default=[py.path.local()]) # ------------------------------------------------------------------------- # distributed testing hooks @@ -218,10 +220,10 @@ def check_options(config): usepdb = config.option.usepdb # a core option if val("looponfail"): if usepdb: - raise config.Error("--pdb incompatible with --looponfail.") + raise pytest.UsageError("--pdb incompatible with --looponfail.") elif val("dist") != "no": if usepdb: - raise config.Error("--pdb incompatible with distributing tests.") + raise pytest.UsageError("--pdb incompatible with distributing tests.") def pytest_runtest_protocol(item): --- a/xdist/looponfail.py +++ b/xdist/looponfail.py @@ -7,21 +7,22 @@ the controlling process which should best never happen. """ -import py +import py, pytest import sys import execnet def looponfail_main(config): remotecontrol = RemoteControl(config) - # XXX better configure rootdir - gettopdir = config.pluginmanager.getplugin("session").gettopdir - rootdirs = [gettopdir(config.args)] + rootdirs = config.getini("looponfailroots") statrecorder = StatRecorder(rootdirs) try: while 1: remotecontrol.loop_once() if not remotecontrol.failures and remotecontrol.wasfailing: continue # the last failures passed, let's immediately rerun all + repr_pytest_looponfailinfo( + failreports=remotecontrol.failures, + rootdirs=rootdirs) statrecorder.waitonchange(checkinterval=2.0) except KeyboardInterrupt: print() @@ -29,7 +30,6 @@ def looponfail_main(config): class RemoteControl(object): def __init__(self, config): self.config = config - self.remote_topdir = None self.failures = [] def trace(self, *args): @@ -70,8 +70,8 @@ class RemoteControl(object): def runsession(self): try: - self.trace("sending", (self.remote_topdir, self.failures)) - self.channel.send((self.remote_topdir, self.failures)) + self.trace("sending", self.failures) + self.channel.send(self.failures) try: return self.channel.receive() except self.channel.RemoteError: @@ -85,15 +85,11 @@ class RemoteControl(object): self.setup() self.wasfailing = self.failures and len(self.failures) result = self.runsession() - topdir, failures, reports, collection_failed = result + failures, reports, collection_failed = result if collection_failed: reports = ["Collection failed, keeping previous failure set"] else: - self.remote_topdir, self.failures = topdir, failures - - repr_pytest_looponfailinfo( - failreports=reports, - rootdirs=[self.remote_topdir],) + self.failures = failures def repr_pytest_looponfailinfo(failreports, rootdirs): tr = py.io.TerminalWriter() @@ -147,23 +143,29 @@ class SlaveFailSession: def pytest_collection(self, session): self.session = session - self.collection = session.collection - self.topdir, self.trails = self.current_command - if self.topdir and self.trails: - self.topdir = py.path.local(self.topdir) - self.collection.topdir = self.topdir + self.collection = collection = session.collection + self.trails = self.current_command + hook = self.collection.ihook + try: + items = collection.perform_collect(self.trails or None) + except pytest.UsageError: + items = collection.perform_collect(None) + hook.pytest_collection_modifyitems(config=session.config, items=items) + hook.pytest_collection_finish(collection=collection) + return True + + if self.trails: col = self.collection items = [] for trail in self.trails: - names = col._parsearg(trail, base=self.topdir) + names = col._parsearg(trail) try: for node in col.matchnodes([col._topcollector], names): items.extend(col.genitems(node)) - except self.config.Error: + except pytest.UsageError: pass # ignore collect errors / vanished tests self.collection.items = items return True - self.topdir = session.collection.topdir def pytest_runtest_logreport(self, report): if report.failed: @@ -189,8 +191,7 @@ class SlaveFailSession: loc = rep.longrepr loc = str(getattr(loc, 'reprcrash', loc)) failreports.append(loc) - topdir = str(self.topdir) - self.channel.send((topdir, trails, failreports, self.collection_failed)) + self.channel.send((trails, failreports, self.collection_failed)) class StatRecorder: def __init__(self, rootdirlist): --- a/xdist/remote.py +++ b/xdist/remote.py @@ -53,8 +53,8 @@ class SlaveInteractor: if name == "runtests": ids = kwargs['ids'] for nodeid in ids: - for item in self.collection.getbyid(nodeid): - self.config.hook.pytest_runtest_protocol(item=item) + item = self._id2item[nodeid] + self.config.hook.pytest_runtest_protocol(item=item) elif name == "runtests_all": for item in self.collection.items: self.config.hook.pytest_runtest_protocol(item=item) @@ -63,9 +63,13 @@ class SlaveInteractor: return True def pytest_collection_finish(self, collection): - ids = [collection.getid(item) for item in collection.items] + self._id2item = {} + ids = [] + for item in collection.items: + self._id2item[item.nodeid] = item + ids.append(item.nodeid) self.sendevent("collectionfinish", - topdir=str(collection.topdir), + topdir=str(collection.fspath), ids=ids) #def pytest_runtest_logstart(self, nodeid, location, fspath): --- a/setup.py +++ b/setup.py @@ -10,7 +10,7 @@ from setuptools import setup setup( name="pytest-xdist", - version='1.5a4', + version='1.5a5', description='py.test xdist plugin for distributed testing and loop-on-failing modes', long_description=__doc__, license='GPLv2 or later', _______________________________________________ py-svn mailing list py-svn@codespeak.net http://codespeak.net/mailman/listinfo/py-svn