pypa / pypa/setuptools

Editable/develop install with spaces in path results in unusable #!

Open
#1,744 1 comment 1 reaction 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
Python
Stars
2.9k
Forks
1.4k
Avg merge
1d 1h
Merged PRs (30d)
1

Description

As I dig deeper I get a bit more confused but it seems that pip install --editable installs are not creating sensible #!s for POSIX when there are spaces in the path.

--editable

#!"/home/altendky/very_sneaky/venv with spaces/bin/python3"

regular

#!/bin/sh
'''exec' "/home/altendky/very_sneaky/venv with spaces/bin/python3" "$0" "$@"
' '''

The undesired results seem to come from:
https://github.com/pypa/setuptools/blob/7be2d14dcd669d6010621a8e5db23763a63cf55e/setuptools/command/easy_install.py#L2047

From what I can tell the regular result is built by distlib (vendored in pip).

https://bitbucket.org/pypa/distlib/src/3b0fd333c8fb15bc04e570a23ee4836caefb7951/distlib/scripts.py#lines-139:168

    def _build_shebang(self, executable, post_interp):
        """
        Build a shebang line. In the simple case (on Windows, or a shebang line
        which is not too long or contains spaces) use a simple formulation for
        the shebang. Otherwise, use /bin/sh as the executable, with a contrived
        shebang which allows the script to run either under Python or sh, using
        suitable quoting. Thanks to Harald Nordgren for his input.

        See also: http://www.in-ulm.de/~mascheck/various/shebang/#length
                  https://hg.mozilla.org/mozilla-central/file/tip/mach
        """
        if os.name != 'posix':
            simple_shebang = True
        else:
            # Add 3 for '#!' prefix and newline suffix.
            shebang_length = len(executable) + len(post_interp) + 3
            if sys.platform == 'darwin':
                max_shebang_length = 512
            else:
                max_shebang_length = 127
            simple_shebang = ((b' ' not in executable) and
                              (shebang_length <= max_shebang_length))

        if simple_shebang:
            result = b'#!' + executable + post_interp + b'\n'
        else:
            result = b'#!/bin/sh\n'
            result += b"'''exec' " + executable + post_interp + b' "$0" "$@"\n'
            result += b"' '''"
        return result

The details are provided from Linux. The original issue was reported to me from macOS.

Recreation Details
 ~/very_sneaky   master ●  virtualenv -p python3 venv\ with\ spaces
Running virtualenv with interpreter /home/altendky/.pyenv/shims/python3
Using base prefix '/home/altendky/.pyenv/versions/3.7.2'
New python executable in /home/altendky/very_sneaky/venv with spaces/bin/python3
Also creating executable in /home/altendky/very_sneaky/venv with spaces/bin/python
Installing setuptools, pip, wheel...
done.
 ✘  ~/very_sneaky   master ●  git clone https://github.com/ambv/black
Cloning into 'black'...
remote: Enumerating objects: 5, done.
remote: Counting objects: 100% (5/5), done.
remote: Compressing objects: 100% (5/5), done.
remote: Total 2494 (delta 0), reused 1 (delta 0), pack-reused 2489
Receiving objects: 100% (2494/2494), 3.00 MiB | 3.93 MiB/s, done.
Resolving deltas: 100% (1690/1690), done.
 ~/very_sneaky   master ●  venv\ with\ spaces/bin/pip install -e black
Obtaining file:///home/altendky/very_sneaky/black
  Installing build dependencies ... done
  Getting requirements to build wheel ... done
    Preparing wheel metadata ... done
Collecting appdirs (from black==19.3b0)
  Using cached https://files.pythonhosted.org/packages/56/eb/810e700ed1349edde4cbdc1b2a21e28cdf115f9faf263f6bbf8447c1abf3/appdirs-1.4.3-py2.py3-none-any.whl
Collecting toml>=0.9.4 (from black==19.3b0)
  Using cached https://files.pythonhosted.org/packages/a2/12/ced7105d2de62fa7c8fb5fce92cc4ce66b57c95fb875e9318dba7f8c5db0/toml-0.10.0-py2.py3-none-any.whl
Collecting attrs>=18.1.0 (from black==19.3b0)
  Using cached https://files.pythonhosted.org/packages/23/96/d828354fa2dbdf216eaa7b7de0db692f12c234f7ef888cc14980ef40d1d2/attrs-19.1.0-py2.py3-none-any.whl
Collecting click>=6.5 (from black==19.3b0)
  Using cached https://files.pythonhosted.org/packages/fa/37/45185cb5abbc30d7257104c434fe0b07e5a195a6847506c074527aa599ec/Click-7.0-py2.py3-none-any.whl
Installing collected packages: appdirs, toml, attrs, click, black
  Running setup.py develop for black
Successfully installed appdirs-1.4.3 attrs-19.1.0 black click-7.0 toml-0.10.0
 ~/very_sneaky   master ●  venv\ with\ spaces/bin/black --help
Failed to execute process 'venv with spaces/bin/black'. Reason:
The file 'venv with spaces/bin/black' does not exist or could not be executed.
 ✘  ~/very_sneaky   master ●  head venv\ with\ spaces/bin/black
#!"/home/altendky/very_sneaky/venv with spaces/bin/python3"
# EASY-INSTALL-ENTRY-SCRIPT: 'black','console_scripts','black'
__requires__ = 'black'
import re
import sys
from pkg_resources import load_entry_point

if __name__ == '__main__':
    sys.argv[0] = re.sub(r'(-script\.pyw?|\.exe)?$', '', sys.argv[0])
    sys.exit(

 ✘  ~/very_sneaky   master ●  venv\ with\ spaces/bin/pip freeze --all
appdirs==1.4.3
attrs==19.1.0
-e git+https://github.com/ambv/black@cea13f498418784e22f8fbd78db3f9240a2bad11#egg=black
Click==7.0
pip==19.0.3
setuptools==41.0.0
toml==0.10.0
wheel==0.33.1
 ~/very_sneaky   master ●  cat venv\ with\ spaces/bin/pip
#!/bin/sh
'''exec' "/home/altendky/very_sneaky/venv with spaces/bin/python3" "$0" "$@"
' '''
# -*- coding: utf-8 -*-
import re
import sys

from pip._internal import main

if __name__ == '__main__':
    sys.argv[0] = re.sub(r'(-script\.pyw?|\.exe)?$', '', sys.argv[0])
    sys.exit(main())

Contributor guide

No contributing guide indexed for this repository

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start at setuptools/command/easy_install.py around line 2047 and compare its script generation with the referenced distlib/scripts.py implementation. Reproduce an editable install in a POSIX virtual environment whose path contains spaces, then verify that the generated console script can be executed successfully.

Written by the indexing model from the issue text.

Assessment

Tech stack
python
Domain
build-system
Issue type
Bug
Difficulty
3/5
Estimated time
1-2 days
Activity status
Stale
Clarity
Clearly specified
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.