diff options
author | holger krekel <holger@merlinux.eu> | 2015-12-14 12:01:15 +0100 |
---|---|---|
committer | holger krekel <holger@merlinux.eu> | 2015-12-14 12:01:15 +0100 |
commit | 8ddad172739638b930b0752e40f9fba681005aee (patch) | |
tree | 83f0ba1f60dcae8848c41507851c810fe0115929 | |
parent | bbaf73824cfe0c5268aecc44cd9e61cceac9996d (diff) | |
download | tox-8ddad172739638b930b0752e40f9fba681005aee.tar.gz |
fix issue294: re-allow cross-section substitution for setenv setting.2.3.1
-rw-r--r-- | CHANGELOG | 7 | ||||
-rw-r--r-- | setup.py | 2 | ||||
-rw-r--r-- | tests/test_config.py | 33 | ||||
-rw-r--r-- | tox/__init__.py | 2 | ||||
-rw-r--r-- | tox/config.py | 27 |
5 files changed, 56 insertions, 15 deletions
@@ -1,4 +1,9 @@ -2.3.0 (unreleased) +2.3.1 +----- + +- fix issue294: re-allow cross-section substitution for setenv. + +2.3.0 ----- - DEPRECATE use of "indexservers" in tox.ini. It complicates @@ -48,7 +48,7 @@ def main(): description='virtualenv-based automation of test activities', long_description=open("README.rst").read(), url='http://tox.testrun.org/', - version='2.3.0.dev3', + version='2.3.1', license='http://opensource.org/licenses/MIT', platforms=['unix', 'linux', 'osx', 'cygwin', 'win32'], author='holger krekel', diff --git a/tests/test_config.py b/tests/test_config.py index f727a1f..6176641 100644 --- a/tests/test_config.py +++ b/tests/test_config.py @@ -1672,8 +1672,7 @@ class TestSetenv: assert envconfig.setenv['VAL'] == envconfig.envdir assert str(envconfig.envdir) in envconfig.commands[0] - @pytest.mark.xfail(reason="we don't implement cross-section substitution for setenv") - def test_setenv_cross_section_subst(self, monkeypatch, newconfig): + def test_setenv_cross_section_subst_issue294(self, monkeypatch, newconfig): """test that we can do cross-section substitution with setenv""" monkeypatch.delenv('TEST', raising=False) config = newconfig(""" @@ -1687,6 +1686,36 @@ class TestSetenv: envconfig = config.envconfigs["python"] assert envconfig.setenv["NOT_TEST"] == "defaultvalue" + def test_setenv_cross_section_subst_twice(self, monkeypatch, newconfig): + """test that we can do cross-section substitution with setenv""" + monkeypatch.delenv('TEST', raising=False) + config = newconfig(""" + [section] + x = NOT_TEST={env:TEST:defaultvalue} + [section1] + y = {[section]x} + + [testenv] + setenv = {[section1]y} + """) + envconfig = config.envconfigs["python"] + assert envconfig.setenv["NOT_TEST"] == "defaultvalue" + + def test_setenv_cross_section_mixed(self, monkeypatch, newconfig): + """test that we can do cross-section substitution with setenv""" + monkeypatch.delenv('TEST', raising=False) + config = newconfig(""" + [section] + x = NOT_TEST={env:TEST:defaultvalue} + + [testenv] + setenv = {[section]x} + y = 7 + """) + envconfig = config.envconfigs["python"] + assert envconfig.setenv["NOT_TEST"] == "defaultvalue" + assert envconfig.setenv["y"] == "7" + class TestIndexServer: def test_indexserver(self, tmpdir, newconfig): diff --git a/tox/__init__.py b/tox/__init__.py index 0e69ae9..053386b 100644 --- a/tox/__init__.py +++ b/tox/__init__.py @@ -1,5 +1,5 @@ # -__version__ = '2.3.0.dev3' +__version__ = '2.3.1' from .hookspecs import hookspec, hookimpl # noqa diff --git a/tox/config.py b/tox/config.py index ad80269..079dff3 100644 --- a/tox/config.py +++ b/tox/config.py @@ -889,7 +889,7 @@ class SectionReader: return self._getdict(value, default=default, sep=sep) def getdict_setenv(self, name, default=None, sep="\n"): - value = self.getstring(name, None, replace=False) + value = self.getstring(name, None, replace=True, crossonly=True) definitions = self._getdict(value, default=default, sep=sep) self._setenv = SetenvDict(definitions, reader=self) return self._setenv @@ -931,7 +931,7 @@ class SectionReader: def getargv(self, name, default=""): return self.getargvlist(name, default)[0] - def getstring(self, name, default=None, replace=True): + def getstring(self, name, default=None, replace=True, crossonly=False): x = None for s in [self.section_name] + self.fallbacksections: try: @@ -946,7 +946,7 @@ class SectionReader: x = self._apply_factors(x) if replace and x and hasattr(x, 'replace'): - x = self._replace(x, name=name) + x = self._replace(x, name=name, crossonly=crossonly) # print "getstring", self.section_name, name, "returned", repr(x) return x @@ -963,14 +963,14 @@ class SectionReader: lines = s.strip().splitlines() return '\n'.join(filter(None, map(factor_line, lines))) - def _replace(self, value, name=None, section_name=None): + def _replace(self, value, name=None, section_name=None, crossonly=False): if '{' not in value: return value section_name = section_name if section_name else self.section_name self._subststack.append((section_name, name)) try: - return Replacer(self).do_replace(value) + return Replacer(self, crossonly=crossonly).do_replace(value) finally: assert self._subststack.pop() == (section_name, name) @@ -982,22 +982,28 @@ class Replacer: (?:(?P<sub_type>[^[:{}]+):)? # optional sub_type for special rules (?P<substitution_value>[^{}]*) # substitution key [}] - ''', - re.VERBOSE) + ''', re.VERBOSE) - def __init__(self, reader): + def __init__(self, reader, crossonly=False): self.reader = reader + self.crossonly = crossonly def do_replace(self, x): return self.RE_ITEM_REF.sub(self._replace_match, x) def _replace_match(self, match): g = match.groupdict() + sub_value = g['substitution_value'] + if self.crossonly: + if sub_value.startswith("["): + return self._substitute_from_other_section(sub_value) + # in crossonly we return all other hits verbatim + start, end = match.span() + return match.string[start:end] # special case: opts and packages. Leave {opts} and # {packages} intact, they are replaced manually in # _venv.VirtualEnv.run_install_command. - sub_value = g['substitution_value'] if sub_value in ('opts', 'packages'): return '{%s}' % sub_value @@ -1048,7 +1054,8 @@ class Replacer: raise ValueError('%s already in %s' % ( (section, item), self.reader._subststack)) x = str(cfg[section][item]) - return self.reader._replace(x, name=item, section_name=section) + return self.reader._replace(x, name=item, section_name=section, + crossonly=self.crossonly) raise tox.exception.ConfigError( "substitution key %r not found" % key) |