Skip to content

Commit ef843dc

Browse files
barneygalegaborbernat
authored andcommitted
Use POSIX shell rules for creating posargs string on non-Windows platforms (#1336)
* Use POSIX shell rules for creating posargs string on non-Windows platforms. Closes #1336 * pre-commit run --all-files
1 parent bc31722 commit ef843dc

File tree

4 files changed

+24
-2
lines changed

4 files changed

+24
-2
lines changed

CONTRIBUTORS

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ Anthon van der Neuth
88
Anthony Sottile
99
Ashley Whetter
1010
Asmund Grammeltwedt
11+
Barney Gale
1112
Barry Warsaw
1213
Bartolome Sanchez Salado
1314
Benoit Pierre

docs/changelog/1336.bugfix.rst

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
tox used Windows shell rules on non-Windows platforms when transforming
2+
positional arguments to a string - by :user:`barneygale`.

src/tox/config/__init__.py

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,12 @@
3939
from .parallel import add_parallel_config, add_parallel_flags
4040
from .reporter import add_verbosity_commands
4141

42+
try:
43+
from shlex import quote as shlex_quote
44+
except ImportError:
45+
from pipes import quote as shlex_quote
46+
47+
4248
hookimpl = tox.hookimpl
4349
"""DEPRECATED - REMOVE - this is left for compatibility with plugins importing this from here.
4450
@@ -1674,7 +1680,10 @@ def getargvlist(cls, reader, value, replace=True):
16741680
@classmethod
16751681
def processcommand(cls, reader, command, replace=True):
16761682
posargs = getattr(reader, "posargs", "")
1677-
posargs_string = list2cmdline([x for x in posargs if x])
1683+
if sys.platform.startswith("win"):
1684+
posargs_string = list2cmdline([x for x in posargs if x])
1685+
else:
1686+
posargs_string = " ".join([shlex_quote(x) for x in posargs if x])
16781687

16791688
# Iterate through each word of the command substituting as
16801689
# appropriate to construct the new command string. This

tests/unit/config/test_config.py

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -730,8 +730,18 @@ def test_argvlist_posargs_with_quotes(self, newconfig):
730730
cmd1 -f {posargs}
731731
"""
732732
)
733+
# The operating system APIs for launching processes differ between
734+
# Windows and other OSs. On Windows, the command line is passed as a
735+
# string (and not a list of strings). Python uses the MS C runtime
736+
# rules for splitting this string into `sys.argv`, and those rules
737+
# differ from POSIX shell rules in their treatment of quoted arguments.
738+
if sys.platform.startswith("win"):
739+
substitutions = ["foo", "'bar", "baz'"]
740+
else:
741+
substitutions = ["foo", "bar baz"]
742+
733743
reader = SectionReader("section", config._cfg)
734-
reader.addsubstitutions(["foo", "'bar", "baz'"])
744+
reader.addsubstitutions(substitutions)
735745
assert reader.getargvlist("key1") == []
736746
x = reader.getargvlist("key2")
737747
assert x == [["cmd1", "-f", "foo", "bar baz"]]

0 commit comments

Comments
 (0)