diff --git a/py/test/config.py b/py/test/config.py index 14508bc31..a2cfbf9e4 100644 --- a/py/test/config.py +++ b/py/test/config.py @@ -118,6 +118,14 @@ class Config(object): except KeyError: return self.conftest.rget(name, path) + def getvalue_from_confpath(self, name, path): + """ same as previous, but returns only value from explicit + conftest path + """ + if isinstance(path, str): + path = py.path.local(path) + return self.conftest.rget_path(name, path) + def initsession(self): """ return an initialized session object. """ cls = self._getsessionclass() diff --git a/py/test/conftesthandle.py b/py/test/conftesthandle.py index 9602d9713..d20b953c6 100644 --- a/py/test/conftesthandle.py +++ b/py/test/conftesthandle.py @@ -11,6 +11,7 @@ class Conftest(object): """ def __init__(self, path=None): self._path2confmods = {} + self._path2conftest_files = {} # direct cache of conftest files, to avoid confusion if path is not None: self.setinitial([path]) @@ -41,45 +42,62 @@ class Conftest(object): except KeyError: dp = path.dirpath() if dp == path: - return [importconfig(defaultconftestpath)] + return [self.importconfig(defaultconftestpath)] clist = self.getconftestmodules(dp) conftestpath = path.join("conftest.py") if conftestpath.check(file=1): - clist.append(importconfig(conftestpath)) + clist.append(self.importconfig(conftestpath)) self._path2confmods[path] = clist # be defensive: avoid changes from caller side to # affect us by always returning a copy of the actual list return clist[:] + def getconftest(self, path): + """ Return a direct module of that path + """ + try: + return self._path2conftest_files[path] + except KeyError: + conftestpath = path.join("conftest.py") + if conftestpath.check(file=1): + return self.importconfig(conftestpath) + raise AttributeError + # we raise here AttributeError to unify error reporting in case + # of lack of variable in conftest or lack of file, but we do not want to + # hide ImportError + # XXX no real use case, may probably go #def lget(self, name, path=None): # modules = self.getconftestmodules(path) # return self._get(name, modules) def rget(self, name, path=None): - return self._rget(name, path)[0] - - def _rget(self, name, path=None): modules = self.getconftestmodules(path) modules.reverse() return self._get(name, modules) - def rget_with_confmod(self, name, path=None): - return self._rget(name, path) + def rget_path(self, name, path): + """ can raise AttributeError + """ + return getattr(self.getconftest(path), name) def _get(self, name, modules): for mod in modules: try: - return getattr(mod, name), mod + return getattr(mod, name) except AttributeError: continue raise KeyError, name -def importconfig(configpath): - if not configpath.dirpath('__init__.py').check(file=1): - # HACK: we don't want any "globally" imported conftest.py, - # prone to conflicts and subtle problems - modname = str(configpath).replace('.', configpath.sep) - return configpath.pyimport(modname=modname) - else: - return configpath.pyimport() + def importconfig(self, configpath): + # We could have used caching here, but it's redundant since + # they're cached on path anyway, so we use it only when doing rget_path + if not configpath.dirpath('__init__.py').check(file=1): + # HACK: we don't want any "globally" imported conftest.py, + # prone to conflicts and subtle problems + modname = str(configpath).replace('.', configpath.sep) + mod = configpath.pyimport(modname=modname) + else: + mod = configpath.pyimport() + self._path2conftest_files[configpath.dirpath()] = mod + return mod diff --git a/py/test/rsession/hostmanage.py b/py/test/rsession/hostmanage.py index cae0a31ff..2a75cd377 100644 --- a/py/test/rsession/hostmanage.py +++ b/py/test/rsession/hostmanage.py @@ -41,20 +41,24 @@ class HostInfo(object): class HostRSync(py.execnet.RSync): """ An rsync wrapper which filters out *~, .svn/ and *.pyc """ - def __init__(self, rsync_roots): + def __init__(self, config): py.execnet.RSync.__init__(self, delete=True) - self.rsync_roots = rsync_roots + self.config = config def filter(self, path): if path.endswith('.pyc') or path.endswith('~'): return False dir, base = os.path.split(path) + try: + rsync_roots = self.config.getvalue_from_confpath("dist_rsyncroots", + dir) + except AttributeError: + rsync_roots = None if base == '.svn': return False - if dir != self.sourcedir: + if rsync_roots is None: return True - else: - return self.rsync_roots is None or path in self.rsync_roots + return base in rsync_roots class DummyGateway(object): pass @@ -64,10 +68,9 @@ class HostOptions(object): as different function parameters, mostly related to tests only """ - def __init__(self, rsync_roots=None, remote_python="python", + def __init__(self, remote_python="python", optimise_localhost=True, do_sync=True, create_gateways=True): - self.rsync_roots = rsync_roots self.remote_python = remote_python self.optimise_localhost = optimise_localhost self.do_sync = do_sync @@ -145,7 +148,7 @@ class HostManager(object): rsynced = {} if self.options.do_sync: - rsync = HostRSync(self.options.rsync_roots) + rsync = HostRSync(self.config) for host in hosts: if not self.need_rsync(rsynced, host.hostname, host.relpath): reporter(report.HostReady(host)) diff --git a/py/test/rsession/rsession.py b/py/test/rsession/rsession.py index 87633d02f..31c5da74b 100644 --- a/py/test/rsession/rsession.py +++ b/py/test/rsession/rsession.py @@ -150,7 +150,7 @@ class RSession(AbstractSession): """ main loop for running tests. """ args = self.config.args - sshhosts, remotepython, rsync_roots = self.read_distributed_config() + sshhosts, remotepython = self.read_distributed_config() reporter, startserverflag = self.init_reporter(reporter, sshhosts, RemoteReporter) reporter, checkfun = self.wrap_reporter(reporter) @@ -158,8 +158,7 @@ class RSession(AbstractSession): reporter(report.TestStarted(sshhosts)) done_dict = {} - hostopts = HostOptions(rsync_roots=rsync_roots, - remote_python=remotepython, + hostopts = HostOptions(remote_python=remotepython, optimise_localhost=self.optimise_localhost) hostmanager = HostManager(sshhosts, self.config, hostopts) try: @@ -194,26 +193,11 @@ class RSession(AbstractSession): def read_distributed_config(self): """ Read from conftest file the configuration of distributed testing """ - try: - conftest = self.config.conftest - value, mod = conftest.rget_with_confmod('dist_rsync_roots') - except KeyError: - rsync_roots = [self.config.topdir] # our best guess likely - else: - assert isinstance(value, (list,tuple)), value - base = py.path.local(mod.__file__).dirpath() - print "base", base - rsync_roots = [base.join(path, abs=True) - for path in value] - for root in rsync_roots: - assert root.check(dir=1) - #rsync_roots = value - print "rsync_roots", rsync_roots sshhosts = [HostInfo(i) for i in self.config.getvalue("dist_hosts")] parse_directories(sshhosts) remotepython = self.config.getvalue("dist_remotepython") - return sshhosts, remotepython, rsync_roots + return sshhosts, remotepython def dispatch_tests(self, nodes, reporter, checkfun, done_dict): colitems = self.config.getcolitems() diff --git a/py/test/rsession/testing/test_rsession.py b/py/test/rsession/testing/test_rsession.py index a37fd8adf..077331363 100644 --- a/py/test/rsession/testing/test_rsession.py +++ b/py/test/rsession/testing/test_rsession.py @@ -161,8 +161,7 @@ class TestRSessionRemote: teardown_events = [] config = py.test.config._reparse([]) - opts = HostOptions(optimise_localhost=False, - rsync_roots=[py.path.local(py.__file__).dirpath()]) + opts = HostOptions(optimise_localhost=False) hm = HostManager(hosts, config, opts) nodes = hm.init_hosts(setup_events.append) hm.teardown_hosts(teardown_events.append, @@ -189,8 +188,7 @@ class TestRSessionRemote: allevents = [] config = py.test.config._reparse([]) - opts = HostOptions(optimise_localhost=False, - rsync_roots=[py.path.local(py.__file__).dirpath()]) + opts = HostOptions(optimise_localhost=False) hm = HostManager(hosts, config, opts) nodes = hm.init_hosts(allevents.append) @@ -237,8 +235,7 @@ class TestRSessionRemote: from py.__.test.rsession.master import defaultconftestnames defaultconftestnames.append("custom") try: - opts = HostOptions(optimise_localhost=False, - rsync_roots=[py.path.local(py.__file__).dirpath()]) + opts = HostOptions(optimise_localhost=False) hm = HostManager(hosts, config, opts) nodes = hm.init_hosts(allevents.append) diff --git a/py/test/rsession/testing/test_rsync.py b/py/test/rsession/testing/test_rsync.py new file mode 100644 index 000000000..821f10d99 --- /dev/null +++ b/py/test/rsession/testing/test_rsync.py @@ -0,0 +1,30 @@ + +""" RSync filter test +""" + +import py +from py.__.test.rsession.hostmanage import HostRSync + +def test_rsync(): + tmpdir = py.test.ensuretemp("rsync_rsession") + tmpdir.ensure("a", dir=True) + tmpdir.ensure("b", dir=True) + tmpdir.ensure("conftest.py").write(py.code.Source(""" + dist_rsyncroots = ['a'] + """)) + tmpdir.join("a").ensure("x") + adir = tmpdir.join("a").ensure("xy", dir=True) + adir.ensure("conftest.py").write(py.code.Source(""" + dist_rsyncroots = ['b', 'conftest.py'] + """)) + adir.ensure("a", dir=True) + adir.ensure("b", dir=True) + config = py.test.config._reparse([str(tmpdir)]) + h = HostRSync(config) + h.sourcedir = config.topdir + assert h.filter(str(tmpdir.join("a"))) + assert not h.filter(str(tmpdir.join("b"))) + assert h.filter(str(tmpdir.join("a").join("x"))) + assert h.filter(str(adir.join("conftest.py"))) + assert not h.filter(str(adir.join("a"))) + assert h.filter(str(adir.join("b"))) diff --git a/py/test/rsession/testing/test_slave.py b/py/test/rsession/testing/test_slave.py index f8524beb2..ce1f6a7fc 100644 --- a/py/test/rsession/testing/test_slave.py +++ b/py/test/rsession/testing/test_slave.py @@ -179,4 +179,3 @@ def test_pidinfo(): os._exit(0) # check if this really exits py.test.raises(OSError, "os.waitpid(pid, 0)") - diff --git a/py/test/testing/test_conftesthandle.py b/py/test/testing/test_conftesthandle.py index 713af0646..c94a2ccbd 100644 --- a/py/test/testing/test_conftesthandle.py +++ b/py/test/testing/test_conftesthandle.py @@ -67,9 +67,12 @@ class TestConftestValueAccessGlobal: def test_value_access_path(self): topdir = self.basedir.join("adir", "b") + topdir.ensure("xx", dir=True) conftest = Conftest(topdir) - _, mod = conftest.rget_with_confmod("a") - assert py.path.local(mod.__file__).dirpath() == topdir + assert conftest.rget_path("a", topdir) == 1.5 + assert conftest.rget_path("a", topdir.dirpath()) == 1 + py.test.raises(AttributeError, "conftest.rget_path('a', topdir.join('xx'))") + #assert py.path.local(mod.__file__).dirpath() == topdir class TestConftestValueAccessInPackage(TestConftestValueAccessGlobal): def setup_class(cls):