summaryrefslogtreecommitdiff
path: root/numpy/distutils/tests
diff options
context:
space:
mode:
authorEric Wieser <wieser.eric@gmail.com>2019-02-23 21:15:54 -0800
committerEric Wieser <wieser.eric@gmail.com>2019-02-23 22:35:10 -0800
commit77aee9c3069851e53a772d5b1f24392932d0801f (patch)
tree9f2f2ded6c26d5e63bcb1c8b66db5911cf18c451 /numpy/distutils/tests
parent490b8542c8d042f712cfe4671ebfc5a2afe8f8ae (diff)
downloadnumpy-77aee9c3069851e53a772d5b1f24392932d0801f.tar.gz
MAINT: Add functions to parse shell-strings in the platform-native way
There are places in distutils where we accept a single string from the user, and interpret it as a set of command line arguments. Previously, these were passed on as a string unmodified to exec_command, and interpreted by subprocess in a platform-specific way. Recent changes to distutils now pass a list of arguments to subprocess, meaning we have to split the strings ourselves. While `shlex.split` is perfect on posix systems, it is not a good approximation of either the old or the expected behavior on windows. Provides the building blocks needed to fix gh-12979
Diffstat (limited to 'numpy/distutils/tests')
-rw-r--r--numpy/distutils/tests/test_shell_utils.py79
1 files changed, 79 insertions, 0 deletions
diff --git a/numpy/distutils/tests/test_shell_utils.py b/numpy/distutils/tests/test_shell_utils.py
new file mode 100644
index 000000000..a0344244f
--- /dev/null
+++ b/numpy/distutils/tests/test_shell_utils.py
@@ -0,0 +1,79 @@
+from __future__ import division, absolute_import, print_function
+
+import pytest
+import subprocess
+import os
+import json
+import sys
+
+from numpy.distutils import _shell_utils
+
+argv_cases = [
+ [r'exe'],
+ [r'path/exe'],
+ [r'path\exe'],
+ [r'\\server\path\exe'],
+ [r'path to/exe'],
+ [r'path to\exe'],
+
+ [r'exe', '--flag'],
+ [r'path/exe', '--flag'],
+ [r'path\exe', '--flag'],
+ [r'path to/exe', '--flag'],
+ [r'path to\exe', '--flag'],
+
+ # flags containing literal quotes in their name
+ [r'path to/exe', '--flag-"quoted"'],
+ [r'path to\exe', '--flag-"quoted"'],
+ [r'path to/exe', '"--flag-quoted"'],
+ [r'path to\exe', '"--flag-quoted"'],
+]
+
+
+@pytest.fixture(params=[
+ _shell_utils.WindowsParser,
+ _shell_utils.PosixParser
+])
+def Parser(request):
+ return request.param
+
+
+@pytest.fixture
+def runner(Parser):
+ if Parser != _shell_utils.NativeParser:
+ pytest.skip('Unable to run with non-native parser')
+
+ if Parser == _shell_utils.WindowsParser:
+ return lambda cmd: subprocess.check_output(cmd)
+ elif Parser == _shell_utils.PosixParser:
+ # posix has no non-shell string parsing
+ return lambda cmd: subprocess.check_output(cmd, shell=True)
+ else:
+ raise NotImplementedError
+
+
+@pytest.mark.parametrize('argv', argv_cases)
+def test_join_matches_subprocess(Parser, runner, argv):
+ """
+ Test that join produces strings understood by subprocess
+ """
+ # invoke python to return its arguments as json
+ cmd = [
+ sys.executable, '-c',
+ 'import json, sys; print(json.dumps(sys.argv[1:]))'
+ ]
+ joined = Parser.join(cmd + argv)
+ json_out = runner(joined).decode()
+ assert json.loads(json_out) == argv
+
+
+@pytest.mark.parametrize('argv', argv_cases)
+def test_roundtrip(Parser, argv):
+ """
+ Test that split is the inverse operation of join
+ """
+ try:
+ joined = Parser.join(argv)
+ assert argv == Parser.split(joined)
+ except NotImplementedError:
+ pytest.skip("Not implemented")