pypa / setuptools

Official project repository for the Setuptools build system
https://pypi.org/project/setuptools/
MIT License
2.49k stars 1.18k forks source link

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

Open altendky opened 5 years ago

altendky commented 5 years ago

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()) ```
AWhetter commented 3 years ago

As a separate issue but with a (possibly) similar fix, doing a develop install in a virtualenv that has been created in a deeply nested directory can result in a script with a shebang that's too long. Using distlib (or at least distlib's method of generating the shebang) would also solve this problem.