diff options
| author | Jason R. Coombs <jaraco@jaraco.com> | 2016-07-22 13:51:38 -0400 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2016-07-22 13:51:38 -0400 |
| commit | 6547430bf289c7285498303ea77eef56702c3a95 (patch) | |
| tree | 0dacce66723c7a87cafb21739158e44fbe813d37 /setuptools | |
| parent | 0269eaa527744320cdb42600927f9ef11900d4d7 (diff) | |
| parent | 3132833570c90d52f6c2a422506732e82d772cdd (diff) | |
| download | python-setuptools-git-6547430bf289c7285498303ea77eef56702c3a95.tar.gz | |
Merge pull request #616 from fkrull/issue398
Fix "failed to create process" issue on Windows
Diffstat (limited to 'setuptools')
| -rwxr-xr-x | setuptools/command/easy_install.py | 11 | ||||
| -rwxr-xr-x | setuptools/command/install_scripts.py | 5 | ||||
| -rw-r--r-- | setuptools/tests/test_easy_install.py | 27 | ||||
| -rw-r--r-- | setuptools/tests/test_install_scripts.py | 88 |
4 files changed, 114 insertions, 17 deletions
diff --git a/setuptools/command/easy_install.py b/setuptools/command/easy_install.py index 468b9be7..19f8286b 100755 --- a/setuptools/command/easy_install.py +++ b/setuptools/command/easy_install.py @@ -1987,8 +1987,17 @@ class CommandSpec(list): return self._render(self + list(self.options)) @staticmethod + def _strip_quotes(item): + _QUOTES = '"\'' + for q in _QUOTES: + if item.startswith(q) and item.endswith(q): + return item[1:-1] + return item + + @staticmethod def _render(items): - cmdline = subprocess.list2cmdline(items) + cmdline = subprocess.list2cmdline( + CommandSpec._strip_quotes(item.strip()) for item in items) return '#!' + cmdline + '\n' diff --git a/setuptools/command/install_scripts.py b/setuptools/command/install_scripts.py index be66cb22..16234273 100755 --- a/setuptools/command/install_scripts.py +++ b/setuptools/command/install_scripts.py @@ -1,6 +1,7 @@ from distutils import log import distutils.command.install_scripts as orig import os +import sys from pkg_resources import Distribution, PathMetadata, ensure_directory @@ -37,6 +38,10 @@ class install_scripts(orig.install_scripts): if is_wininst: exec_param = "python.exe" writer = ei.WindowsScriptWriter + if exec_param == sys.executable: + # In case the path to the Python executable contains a space, wrap + # it so it's not split up. + exec_param = [exec_param] # resolve the writer to the environment writer = writer.best() cmd = writer.command_spec_class.best().from_param(exec_param) diff --git a/setuptools/tests/test_easy_install.py b/setuptools/tests/test_easy_install.py index 2c17ac76..11299c7c 100644 --- a/setuptools/tests/test_easy_install.py +++ b/setuptools/tests/test_easy_install.py @@ -30,7 +30,7 @@ import setuptools.command.easy_install as ei from setuptools.command.easy_install import PthDistributions from setuptools.command import easy_install as easy_install_pkg from setuptools.dist import Distribution -from pkg_resources import working_set +from pkg_resources import normalize_path, working_set from pkg_resources import Distribution as PRDistribution import setuptools.tests.server import pkg_resources @@ -126,9 +126,10 @@ class TestEasyInstallTest: get_site_dirs should always return site dirs reported by site.getsitepackages. """ - mock_gsp = lambda: ['/setuptools/test/site-packages'] + path = normalize_path('/setuptools/test/site-packages') + mock_gsp = lambda: [path] monkeypatch.setattr(site, 'getsitepackages', mock_gsp, raising=False) - assert '/setuptools/test/site-packages' in ei.get_site_dirs() + assert path in ei.get_site_dirs() def test_all_site_dirs_works_without_getsitepackages(self, monkeypatch): monkeypatch.delattr(site, 'getsitepackages', raising=False) @@ -532,29 +533,32 @@ def make_trivial_sdist(dist_path, setup_py): dist.addfile(setup_py_file, fileobj=setup_py_bytes) +@pytest.mark.skipif( + sys.platform.startswith('java') and ei.is_sh(sys.executable), + reason="Test cannot run under java when executable is sh" +) class TestScriptHeader: non_ascii_exe = '/Users/José/bin/python' exe_with_spaces = r'C:\Program Files\Python33\python.exe' - @pytest.mark.skipif( - sys.platform.startswith('java') and ei.is_sh(sys.executable), - reason="Test cannot run under java when executable is sh" - ) def test_get_script_header(self): expected = '#!%s\n' % ei.nt_quote_arg(os.path.normpath(sys.executable)) actual = ei.ScriptWriter.get_script_header('#!/usr/local/bin/python') assert actual == expected + def test_get_script_header_args(self): expected = '#!%s -x\n' % ei.nt_quote_arg(os.path.normpath (sys.executable)) actual = ei.ScriptWriter.get_script_header('#!/usr/bin/python -x') assert actual == expected + def test_get_script_header_non_ascii_exe(self): actual = ei.ScriptWriter.get_script_header('#!/usr/bin/python', executable=self.non_ascii_exe) expected = '#!%s -x\n' % self.non_ascii_exe assert actual == expected + def test_get_script_header_exe_with_spaces(self): actual = ei.ScriptWriter.get_script_header('#!/usr/bin/python', executable='"' + self.exe_with_spaces + '"') expected = '#!"%s"\n' % self.exe_with_spaces @@ -596,15 +600,6 @@ class TestCommandSpec: assert len(cmd) == 2 assert '"' not in cmd.as_header() - def test_sys_executable(self): - """ - CommandSpec.from_string(sys.executable) should contain just that param. - """ - writer = ei.ScriptWriter.best() - cmd = writer.command_spec_class.from_string(sys.executable) - assert len(cmd) == 1 - assert cmd[0] == sys.executable - class TestWindowsScriptWriter: diff --git a/setuptools/tests/test_install_scripts.py b/setuptools/tests/test_install_scripts.py new file mode 100644 index 00000000..7393241f --- /dev/null +++ b/setuptools/tests/test_install_scripts.py @@ -0,0 +1,88 @@ +"""install_scripts tests +""" + +import io +import sys + +import pytest + +from setuptools.command.install_scripts import install_scripts +from setuptools.dist import Distribution +from . import contexts + + +class TestInstallScripts: + settings = dict( + name='foo', + entry_points={'console_scripts': ['foo=foo:foo']}, + version='0.0', + ) + unix_exe = '/usr/dummy-test-path/local/bin/python' + unix_spaces_exe = '/usr/bin/env dummy-test-python' + win32_exe = 'C:\\Dummy Test Path\\Program Files\\Python 3.3\\python.exe' + + def _run_install_scripts(self, install_dir, executable=None): + dist = Distribution(self.settings) + dist.script_name = 'setup.py' + cmd = install_scripts(dist) + cmd.install_dir = install_dir + if executable is not None: + bs = cmd.get_finalized_command('build_scripts') + bs.executable = executable + cmd.ensure_finalized() + with contexts.quiet(): + cmd.run() + + @pytest.mark.skipif(sys.platform == 'win32', reason='non-Windows only') + def test_sys_executable_escaping_unix(self, tmpdir, monkeypatch): + """ + Ensure that shebang is not quoted on Unix when getting the Python exe + from sys.executable. + """ + expected = '#!%s\n' % self.unix_exe + monkeypatch.setattr('sys.executable', self.unix_exe) + with tmpdir.as_cwd(): + self._run_install_scripts(str(tmpdir)) + with io.open(str(tmpdir.join('foo')), 'r') as f: + actual = f.readline() + assert actual == expected + + @pytest.mark.skipif(sys.platform != 'win32', reason='Windows only') + def test_sys_executable_escaping_win32(self, tmpdir, monkeypatch): + """ + Ensure that shebang is quoted on Windows when getting the Python exe + from sys.executable and it contains a space. + """ + expected = '#!"%s"\n' % self.win32_exe + monkeypatch.setattr('sys.executable', self.win32_exe) + with tmpdir.as_cwd(): + self._run_install_scripts(str(tmpdir)) + with io.open(str(tmpdir.join('foo-script.py')), 'r') as f: + actual = f.readline() + assert actual == expected + + @pytest.mark.skipif(sys.platform == 'win32', reason='non-Windows only') + def test_executable_with_spaces_escaping_unix(self, tmpdir): + """ + Ensure that shebang on Unix is not quoted, even when a value with spaces + is specified using --executable. + """ + expected = '#!%s\n' % self.unix_spaces_exe + with tmpdir.as_cwd(): + self._run_install_scripts(str(tmpdir), self.unix_spaces_exe) + with io.open(str(tmpdir.join('foo')), 'r') as f: + actual = f.readline() + assert actual == expected + + @pytest.mark.skipif(sys.platform != 'win32', reason='Windows only') + def test_executable_arg_escaping_win32(self, tmpdir): + """ + Ensure that shebang on Windows is quoted when getting a path with spaces + from --executable, that is itself properly quoted. + """ + expected = '#!"%s"\n' % self.win32_exe + with tmpdir.as_cwd(): + self._run_install_scripts(str(tmpdir), '"' + self.win32_exe + '"') + with io.open(str(tmpdir.join('foo-script.py')), 'r') as f: + actual = f.readline() + assert actual == expected |
