summaryrefslogtreecommitdiff
path: root/setuptools
diff options
context:
space:
mode:
authorJason R. Coombs <jaraco@jaraco.com>2016-07-22 13:51:38 -0400
committerGitHub <noreply@github.com>2016-07-22 13:51:38 -0400
commit6547430bf289c7285498303ea77eef56702c3a95 (patch)
tree0dacce66723c7a87cafb21739158e44fbe813d37 /setuptools
parent0269eaa527744320cdb42600927f9ef11900d4d7 (diff)
parent3132833570c90d52f6c2a422506732e82d772cdd (diff)
downloadpython-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-xsetuptools/command/easy_install.py11
-rwxr-xr-xsetuptools/command/install_scripts.py5
-rw-r--r--setuptools/tests/test_easy_install.py27
-rw-r--r--setuptools/tests/test_install_scripts.py88
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