Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CONTRIBUTORS
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ Anthon van der Neuth
Anthony Sottile
Ashley Whetter
Asmund Grammeltwedt
Barney Gale
Barry Warsaw
Bartolome Sanchez Salado
Benoit Pierre
Expand Down
2 changes: 2 additions & 0 deletions docs/changelog/1336.bugfix.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
tox used Windows shell rules on non-Windows platforms when transforming
positional arguments to a string - by :user:`barneygale`.
11 changes: 10 additions & 1 deletion src/tox/config/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,12 @@
from .parallel import add_parallel_config, add_parallel_flags
from .reporter import add_verbosity_commands

try:
from shlex import quote as shlex_quote
except ImportError:
from pipes import quote as shlex_quote


hookimpl = tox.hookimpl
"""DEPRECATED - REMOVE - this is left for compatibility with plugins importing this from here.

Expand Down Expand Up @@ -1674,7 +1680,10 @@ def getargvlist(cls, reader, value, replace=True):
@classmethod
def processcommand(cls, reader, command, replace=True):
posargs = getattr(reader, "posargs", "")
posargs_string = list2cmdline([x for x in posargs if x])
if sys.platform.startswith("win"):
posargs_string = list2cmdline([x for x in posargs if x])
else:
posargs_string = " ".join([shlex_quote(x) for x in posargs if x])

# Iterate through each word of the command substituting as
# appropriate to construct the new command string. This
Expand Down
12 changes: 11 additions & 1 deletion tests/unit/config/test_config.py
Original file line number Diff line number Diff line change
Expand Up @@ -730,8 +730,18 @@ def test_argvlist_posargs_with_quotes(self, newconfig):
cmd1 -f {posargs}
"""
)
# The operating system APIs for launching processes differ between
# Windows and other OSs. On Windows, the command line is passed as a
# string (and not a list of strings). Python uses the MS C runtime
# rules for splitting this string into `sys.argv`, and those rules
# differ from POSIX shell rules in their treatment of quoted arguments.
if sys.platform.startswith("win"):
substitutions = ["foo", "'bar", "baz'"]
else:
substitutions = ["foo", "bar baz"]

reader = SectionReader("section", config._cfg)
reader.addsubstitutions(["foo", "'bar", "baz'"])
reader.addsubstitutions(substitutions)
assert reader.getargvlist("key1") == []
x = reader.getargvlist("key2")
assert x == [["cmd1", "-f", "foo", "bar baz"]]
Expand Down