Skip to content

Commit 08ee204

Browse files
committed
Allow {posargs} in setenv
Fixes #1695
1 parent ff853ed commit 08ee204

File tree

4 files changed

+40
-15
lines changed

4 files changed

+40
-15
lines changed

CONTRIBUTORS

+1
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ Jake Windle
4848
Jannis Leidel
4949
Joachim Brandon LeBlanc
5050
Johannes Christ
51+
John Mark Vandenberg
5152
Jon Dufresne
5253
Josh Smeaton
5354
Josh Snyder

docs/changelog/1695.feature.rst

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Allow {posargs} in setenv. - by :user:`jayvdb`

src/tox/config/__init__.py

+23-15
Original file line numberDiff line numberDiff line change
@@ -1559,7 +1559,9 @@ def __repr__(self):
15591559

15601560

15611561
class SectionReader:
1562-
def __init__(self, section_name, cfgparser, fallbacksections=None, factors=(), prefix=None):
1562+
def __init__(
1563+
self, section_name, cfgparser, fallbacksections=None, factors=(), prefix=None, posargs=""
1564+
):
15631565
if prefix is None:
15641566
self.section_name = section_name
15651567
else:
@@ -1570,6 +1572,7 @@ def __init__(self, section_name, cfgparser, fallbacksections=None, factors=(), p
15701572
self._subs = {}
15711573
self._subststack = []
15721574
self._setenv = None
1575+
self.posargs = posargs
15731576

15741577
def get_environ_value(self, name):
15751578
if self._setenv is None:
@@ -1695,6 +1698,17 @@ def getstring(self, name, default=None, replace=True, crossonly=False, no_fallba
16951698
x = self._replace_if_needed(x, name, replace, crossonly)
16961699
return x
16971700

1701+
def getposargs(self, default=None):
1702+
if self.posargs:
1703+
posargs = self.posargs
1704+
if sys.platform.startswith("win"):
1705+
posargs_string = list2cmdline([x for x in posargs if x])
1706+
else:
1707+
posargs_string = " ".join([shlex_quote(x) for x in posargs if x])
1708+
return posargs_string
1709+
else:
1710+
return default or ""
1711+
16981712
def _replace_if_needed(self, x, name, replace, crossonly):
16991713
if replace and x and hasattr(x, "replace"):
17001714
x = self._replace(x, name=name, crossonly=crossonly)
@@ -1781,6 +1795,9 @@ def _replace_match(self, match):
17811795
if not any(g.values()):
17821796
return os.pathsep
17831797

1798+
if sub_value == "posargs":
1799+
return self.reader.getposargs(match.group("default_value"))
1800+
17841801
try:
17851802
sub_type = g["sub_type"]
17861803
except KeyError:
@@ -1794,6 +1811,8 @@ def _replace_match(self, match):
17941811
if is_interactive():
17951812
return match.group("substitution_value")
17961813
return match.group("default_value")
1814+
if sub_type == "posargs":
1815+
return self.reader.getposargs(match.group("substitution_value"))
17971816
if sub_type is not None:
17981817
raise tox.exception.ConfigError(
17991818
"No support for the {} substitution type".format(sub_type),
@@ -1887,28 +1906,17 @@ def getargvlist(cls, reader, value, replace=True):
18871906

18881907
@classmethod
18891908
def processcommand(cls, reader, command, replace=True):
1890-
posargs = getattr(reader, "posargs", "")
1891-
if sys.platform.startswith("win"):
1892-
posargs_string = list2cmdline([x for x in posargs if x])
1893-
else:
1894-
posargs_string = " ".join([shlex_quote(x) for x in posargs if x])
1895-
18961909
# Iterate through each word of the command substituting as
18971910
# appropriate to construct the new command string. This
18981911
# string is then broken up into exec argv components using
18991912
# shlex.
19001913
if replace:
19011914
newcommand = ""
19021915
for word in CommandParser(command).words():
1903-
if word == "{posargs}" or word == "[]":
1904-
newcommand += posargs_string
1916+
if word == "[]":
1917+
newcommand += reader.getposargs()
19051918
continue
1906-
elif word.startswith("{posargs:") and word.endswith("}"):
1907-
if posargs:
1908-
newcommand += posargs_string
1909-
continue
1910-
else:
1911-
word = word[9:-1]
1919+
19121920
new_arg = ""
19131921
new_word = reader._replace(word)
19141922
new_word = reader._replace(new_word)

tests/unit/config/test_config.py

+15
Original file line numberDiff line numberDiff line change
@@ -441,6 +441,21 @@ def test_command_env_substitution(self, newconfig):
441441
assert envconfig.commands == [["ls", "testvalue"]]
442442
assert envconfig.setenv["TEST"] == "testvalue"
443443

444+
def test_command_env_substitution_posargs(self, newconfig):
445+
"""Ensure {posargs} values are substituted correctly."""
446+
config = newconfig(
447+
"""
448+
[testenv:py27]
449+
setenv =
450+
TEST={posargs:default}
451+
commands =
452+
ls {env:TEST}
453+
""",
454+
)
455+
envconfig = config.envconfigs["py27"]
456+
assert envconfig.commands == [["ls", "default"]]
457+
assert envconfig.setenv["TEST"] == "default"
458+
444459
def test_command_env_substitution_global(self, newconfig):
445460
"""Ensure referenced {env:key:default} values are substituted correctly."""
446461
config = newconfig(

0 commit comments

Comments
 (0)