Commits

offbyone committed f84d37e Merge

Bare {posargs} fix merged

Comments (0)

Files changed (3)

 -----------------
 
 - fix issue3 - fix example on frontpage
+- fix a problem with parsing {posargs} in tox commands (spotted by goodwill)
 
 1.0
 -----------------
 - fix issue 23 / apply some ReST fixes
 - change the positional argument specifier to use {posargs:} syntax and
   fix issues #15 and #10 by refining the argument parsing method (Chris Rose)
-- remove use of inipkg lazy importing logic - 
+- remove use of inipkg lazy importing logic -
   the namespace/imports are anyway very small with tox.
 - fix a fspath related assertion to work with debian installs which uses
   symlinks
 - show path of the underlying virtualenv invocation and bootstrap
-  virtualenv.py into a working subdir 
+  virtualenv.py into a working subdir
 - added a CONTRIBUTORS file
 
 0.9

tests/test_config.py

         argv = conf.commands
         assert argv[0] == ["cmd1", "hello"]
 
+    def test_rewrite_simple_posargs(self, tmpdir, newconfig):
+        inisource = """
+            [testenv:py24]
+            args_are_paths = True
+            changedir = tests
+            commands = cmd1 {posargs}
+        """
+        conf = newconfig([], inisource).envconfigs['py24']
+        argv = conf.commands
+        assert argv[0] == ["cmd1"]
+
+        conf = newconfig(["tests/hello"], inisource).envconfigs['py24']
+        argv = conf.commands
+        assert argv[0] == ["cmd1", "tests/hello"]
+
+        tmpdir.ensure("tests", "hello")
+        conf = newconfig(["tests/hello"], inisource).envconfigs['py24']
+        argv = conf.commands
+        assert argv[0] == ["cmd1", "hello"]
+
 class TestGlobalOptions:
     def test_notest(self, newconfig):
         config = newconfig([], "")
         return str(self._subs[key])
 
     def _replace_posargs(self, match):
+        return self._do_replace_posargs(lambda: match.group('substitution_value'))
+
+    def _do_replace_posargs(self, value_func):
         posargs = self._subs.get('_posargs', None)
 
         if posargs:
             return " ".join(posargs)
 
-        if match.group('substitution_value'):
-            return match.group('substitution_value')
-        else:
-            return ''
+        value = value_func()
+        if value:
+            return value
+
+        return ''
 
     def _replace_env(self, match):
         envkey = match.group('substitution_value')
                 "substitution key %r not found" % sub_key)
         return '"%s"' % str(self._subs[sub_key]).replace('"', r'\"')
 
+    def _is_bare_posargs(self, groupdict):
+        return groupdict.get('substitution_value', None) == 'posargs' \
+               and not groupdict.get('sub_type')
+
     def _replace_match(self, match):
         g = match.groupdict()
+
+        # special case: posargs. If there is a 'posargs' substitution value
+        # and no type, handle it as empty posargs
+        if self._is_bare_posargs(g):
+            return self._do_replace_posargs(lambda: '')
+
         handlers = {
             'posargs' : self._replace_posargs,
             'env' : self._replace_env,
             None : self._replace_substitution,
             }
         try:
-            handler = handlers.get(g['sub_type'])
+            sub_type = g['sub_type']
         except KeyError:
-            raise tox.exception.ConfigError("No support for the %s substitution type" % g['sub_type'])
-        else:
-            return handler(match)
+            raise tox.exception.ConfigError("Malformed substitution; no substitution type provided")
+
+        try:
+            handler = handlers[sub_type]
+        except KeyError:
+            raise tox.exception.ConfigError("No support for the %s substitution type" % sub_type)
+
+        return handler(match)
 
     def _replace(self, x, rexpattern = re.compile("\{.+?\}")):
         if '{' in x: