1 new commit in tox: https://bitbucket.org/hpk42/tox/commits/c70e7e6a4c2e/ Changeset: c70e7e6a4c2e User: hpk42 Date: 2015-04-22 19:30:11+00:00 Summary: Merged in wmyll6/tox/fix-issue-120-commands-subs (pull request #143)
fix issue #120: section subs in commands doesn't work Affected #: 2 files diff -r 7fb0ae11640dc5416ba58d58e2858cfe7d7f7c07 -r c70e7e6a4c2e2386e51158ae1d4a8f693069acb8 tests/test_config.py --- a/tests/test_config.py +++ b/tests/test_config.py @@ -208,6 +208,52 @@ assert getcontextname() == "jenkins" +class TestIniParserAgainstCommandsKey: + """Test parsing commands with substitutions""" + + def test_command_substitution_from_other_section(self, newconfig): + config = newconfig(""" + [section] + key = whatever + [testenv] + commands = + echo {[section]key} + """) + reader = IniReader(config._cfg) + x = reader.getargvlist("testenv", "commands") + assert x == [["echo", "whatever"]] + + def test_command_substitution_from_other_section_multiline(self, newconfig): + """Ensure referenced multiline commands form from other section injected as multiple commands.""" + config = newconfig(""" + [section] + commands = + cmd1 param11 param12 + # comment is omitted + cmd2 param21 \ + param22 + [base] + commands = cmd 1 \ + 2 3 4 + cmd 2 + [testenv] + commands = + {[section]commands} + {[section]commands} + # comment is omitted + echo {[base]commands} + """) + reader = IniReader(config._cfg) + x = reader.getargvlist("testenv", "commands") + assert x == [ + "cmd1 param11 param12".split(), + "cmd2 param21 param22".split(), + "cmd1 param11 param12".split(), + "cmd2 param21 param22".split(), + ["echo", "cmd", "1", "2", "3", "4", "cmd", "2"], + ] + + class TestIniParser: def test_getdefault_single(self, tmpdir, newconfig): config = newconfig(""" @@ -318,6 +364,14 @@ x = reader.getdefault("section", "key3") assert x == "" + def test_value_matches_section_substituion(self): + assert is_section_substitution("{[setup]commands}") + + def test_value_doesn_match_section_substitution(self): + assert is_section_substitution("{[ ]commands}") is None + assert is_section_substitution("{[setup]}") is None + assert is_section_substitution("{[setup] commands}") is None + def test_getdefault_other_section_substitution(self, newconfig): config = newconfig(""" [section] @@ -329,18 +383,6 @@ x = reader.getdefault("testenv", "key") assert x == "true" - def test_command_substitution_from_other_section(self, newconfig): - config = newconfig(""" - [section] - key = whatever - [testenv] - commands = - echo {[section]key} - """) - reader = IniReader(config._cfg) - x = reader.getargvlist("testenv", "commands") - assert x == [["echo", "whatever"]] - def test_argvlist(self, tmpdir, newconfig): config = newconfig(""" [section] @@ -382,7 +424,6 @@ x = reader.getargvlist("section", "key2") assert x == [["cmd1", "with", "space", "grr"]] - def test_argvlist_quoting_in_command(self, tmpdir, newconfig): config = newconfig(""" [section] @@ -394,7 +435,6 @@ x = reader.getargvlist("section", "key1") assert x == [["cmd1", "with space", "after the comment"]] - def test_argvlist_positional_substitution(self, tmpdir, newconfig): config = newconfig(""" [section] @@ -483,7 +523,6 @@ expected = ['py.test', '-n5', '--junitxml=ENV_LOG_DIR/junit-ENV_NAME.xml', 'hello', 'world'] assert reader.getargvlist('section', 'key')[0] == expected - def test_getargv(self, newconfig): config = newconfig(""" [section] @@ -493,7 +532,6 @@ expected = ['some', 'command', 'with quoting'] assert reader.getargv('section', 'key') == expected - def test_getpath(self, tmpdir, newconfig): config = newconfig(""" [section] @@ -514,13 +552,14 @@ key5=yes """) reader = IniReader(config._cfg) - assert reader.getbool("section", "key1") == True - assert reader.getbool("section", "key1a") == True - assert reader.getbool("section", "key2") == False - assert reader.getbool("section", "key2a") == False + assert reader.getbool("section", "key1") is True + assert reader.getbool("section", "key1a") is True + assert reader.getbool("section", "key2") is False + assert reader.getbool("section", "key2a") is False py.test.raises(KeyError, 'reader.getbool("section", "key3")') py.test.raises(tox.exception.ConfigError, 'reader.getbool("section", "key5")') + class TestConfigTestEnv: def test_commentchars_issue33(self, tmpdir, newconfig): config = newconfig(""" @@ -1559,7 +1598,7 @@ 'word', ' ', '[]', ' ', '[literal]', ' ', '{something}', ' ', '{some:other thing}', ' ', 'w', '{ord}', ' ', 'w', '{or}', 'd', ' ', 'w', '{ord}', ' ', 'w', '{o:rd}', ' ', 'w', '{o:r}', 'd', ' ', '{w:or}', 'd', ' ', 'w[]ord', ' ', '{posargs:{a key}}', - ] + ] assert parsed == expected @@ -1582,7 +1621,6 @@ parsed = list(p.words()) assert parsed == ['nosetests', ' ', '-v', ' ', '-a', ' ', '!deferred', ' ', '--with-doctest', ' ', '[]'] - @pytest.mark.skipif("sys.platform != 'win32'") def test_commands_with_backslash(self, newconfig): config = newconfig([r"hello\world"], """ diff -r 7fb0ae11640dc5416ba58d58e2858cfe7d7f7c07 -r c70e7e6a4c2e2386e51158ae1d4a8f693069acb8 tox/_config.py --- a/tox/_config.py +++ b/tox/_config.py @@ -22,7 +22,14 @@ for version in '24,25,26,27,30,31,32,33,34,35'.split(','): default_factors['py' + version] = 'python%s.%s' % tuple(version) + def parseconfig(args=None, pkg=None): + """ + :param list[str] args: Optional list of arguments. + :type pkg: str + :rtype: :class:`Config` + :raise SystemExit: toxinit file is not found + """ if args is None: args = sys.argv[1:] parser = prepare_parse(pkg) @@ -509,16 +516,23 @@ def __str__(self): if self.indexserver: if self.indexserver.name == "default": - return self.name - return ":%s:%s" %(self.indexserver.name, self.name) + return self.name + return ":%s:%s" % (self.indexserver.name, self.name) return str(self.name) __repr__ = __str__ + class IndexServerConfig: def __init__(self, name, url=None): self.name = name self.url = url + +#: Check value matches substitution form +#: of referencing value from other section. E.g. {[base]commands} +is_section_substitution = re.compile("{\[[^{}\s]+\]\S+?}").match + + RE_ITEM_REF = re.compile( r''' (?<!\\)[{] @@ -570,13 +584,31 @@ return value def getargvlist(self, section, name): - s = self.getdefault(section, name, '', replace=False) - #if s is None: - # raise tox.exception.ConfigError( - # "no command list %r defined in section [%s]" %(name, section)) - commandlist = [] + """Get arguments for every parsed command. + + :param str section: Section name in the configuration. + :param str name: Key name in a section. + :rtype: list[list[str]] + :raise :class:`tox.exception.ConfigError`: + line-continuation ends nowhere while resolving for specified section + """ + content = self.getdefault(section, name, '', replace=False) + return self._parse_commands(section, name, content) + + def _parse_commands(self, section, name, content): + """Parse commands from key content in specified section. + + :param str section: Section name in the configuration. + :param str name: Key name in a section. + :param str content: Content stored by key. + + :rtype: list[list[str]] + :raise :class:`tox.exception.ConfigError`: + line-continuation ends nowhere while resolving for specified section + """ + commands = [] current_command = "" - for line in s.split("\n"): + for line in content.splitlines(): line = line.rstrip() i = line.find("#") if i != -1: @@ -587,14 +619,19 @@ current_command += " " + line[:-1] continue current_command += line - commandlist.append(self._processcommand(current_command)) + + if is_section_substitution(current_command): + replaced = self._replace(current_command) + commands.extend(self._parse_commands(section, name, replaced)) + else: + commands.append(self._processcommand(current_command)) current_command = "" else: if current_command: raise tox.exception.ConfigError( - "line-continuation for [%s] %s ends nowhere" % + "line-continuation ends nowhere while resolving for [%s] %s" % (section, name)) - return commandlist + return commands def _processcommand(self, command): posargs = getattr(self, "posargs", None) Repository URL: https://bitbucket.org/hpk42/tox/ -- This is a commit notification from bitbucket.org. You are receiving this because you have the service enabled, addressing the recipient of this email. _______________________________________________ pytest-commit mailing list pytest-commit@python.org https://mail.python.org/mailman/listinfo/pytest-commit