Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

pip install virtualenv embeds absolute path to Python interpreter #5048

Closed
jameshfisher opened this issue Mar 2, 2018 · 19 comments
Closed
Labels
auto-locked Outdated issues that have been locked by automation OS: macos MacOS specific project: virtualenv Related to virtualenv resolution: invalid Invalid issue/PR

Comments

@jameshfisher
Copy link
Contributor

Pip version:

$ pip --version
pip 9.0.1 from /usr/local/lib/python2.7/site-packages (python 2.7)

Python version:

$ python --version
Python 2.7.14
$ which python
/usr/local/opt/python@2/libexec/bin/python

Operating system: macOS 10.13.3

Description:

This morning, when I ran virtualenv, I got this:

$ virtualenv
-bash: /usr/local/bin/virtualenv: /usr/local/opt/python/bin/python2.7: bad interpreter: No such file or directory

virtualenv only started behaving this way today. It worked yesterday. It broke because virtualenv is a Python script which embeds the absolute path to a Python interpreter which went away:

$ which virtualenv
/usr/local/bin/virtualenv
$ head -1 /usr/local/bin/virtualenv
#!/usr/local/opt/python/bin/python2.7

It appears that this absolute path is generated dynamically! After pip uninstall virtualenv && pipinstall virtualenv, I get a new absolute path to a new Python interpreter:

$ head -1 /usr/local/bin/virtualenv
#!/usr/local/opt/python@2/bin/python2.7

This behavior is not idiomatic, and causes pip-installed packages to break in confusing ways when the path to the interpreter changes!

The idiomatic behavior is for virtualenv to resolve Python from my PATH at runtime, not at install time. For example, the script could begin with a portable interpreter command, e.g. #!/usr/bin/env python. Why is this not the case?

@pfmoore
Copy link
Member

pfmoore commented Mar 2, 2018

That's correct and by design. Resolving from PATH is a potential source of errors, as the Python interpreter active on your PATH may not even have virtualenv installed (it's perfectly acceptable and supported to run the virtualenv script via its absolute path, without it being on PATH at all).

the absolute path to a Python interpreter which went away

You don't explain how the Python interpreter "went away", but if you uninstall and reinstall a Python installation, you should be uninstalling and reinstalling any packages as well. And moving a Python installation (via OS commands rather than reinstall) isn't supported by Python.

@jameshfisher
Copy link
Contributor Author

For future visitors, the immediate fix is:

pip uninstall virtualenv && pip install virtualenv

I have since found that my Python interpreter at /usr/local/opt/python/bin/python2.7 went away because it was part of the Homebrew python package, which on 1st March 2018 was upgraded to Python 3.x. Here's a related discussion in Homebrew support.

Apparently, brew considers it acceptable to make breaking changes to absolute paths, but virtualenv does not consider this acceptable. Thus these two tools are not stable when used together.

(Arguably, the root problem is the Python community's decision to release a new programming language under a name which was already taken.)

@pradyunsg
Copy link
Member

This is something that has occurred due to a change downstream, by Homebrew, to your system configuration. I don't see anything actionable here from pip's end.

Feel free to close this @jameshfisher! :)

@pradyunsg pradyunsg added OS: macos MacOS specific resolution: invalid Invalid issue/PR S: awaiting response Waiting for a response/more information project: virtualenv Related to virtualenv labels Mar 10, 2018
@pradyunsg
Copy link
Member

See also: Homebrew/homebrew-core#25060

@jameshfisher
Copy link
Contributor Author

jameshfisher commented Mar 10, 2018

Homebrew have reversed their decision to make python point to Python 3, which fixes this immediate issue.

I still see it as weird that pip trawls my PATH at install time, instead of following convention; and I don't understand the reasoning for it. But it's clear that this is not going to change, so I'm closing.

@MikeMcQuaid
Copy link

Hi, Homebrew lead maintainer here 👋. Obviously it's up to pip how this is handled but in our case we generally appreciate applications who consume our binaries to not realpath their way to the location because every version is installed into a separate prefix. The path to the symlink e.g. /usr/local/opt/python/bin/python or /usr/local/bin/python will be consistent across python upgrades and removals where /usr/local/Cellar/python/3.6.4_3/bin/python will go away if a user runs brew cleanup and will obviously not receive security updates.

Homebrew does all it can to address this by ensuring that applications are exposed to the symlinked paths and rewriting things which refer to the Cellar but obviously we cannot do this for applications outside Homebrew. This is also not something we can change on our end without essentially starting the project again from scratch.

@dstufft
Copy link
Member

dstufft commented Mar 12, 2018

Hmm, I don't remember calling realpath on hashbang lines, I think we just use the value of sys.executable. I can't dig into that right now and I don't have Python installed from Homebrew, does /usr/local/bin/python -c "import sys; print(sys.executable)" return /usr/local/bin/python or /usr/local/Cellar/python/3.6.4_3/bin/python (or similar).

@pfmoore
Copy link
Member

pfmoore commented Mar 12, 2018

What we (technically distlib, as we just vendor distlib for console script handling) do is put sys.executable into the script. We do this because the script references the Python module(s) that were installed alongside the script, so if we were to use a different Python interpreter, the script wouldn't work anyway, as it would have a different site-packages.

If Homebrew wants to have scripts link to a generic name, they could patch sys.executable to reflect that - but in doing so, they'd need to make sure site-packages was managed appropriately. In the original issue here, even if the shebang line had pointed to the new interpreter, the command still would't have worked, as virtualenv wasn't installed in that interpreter (if it had been, the script would have been overwritten with the new interpreter).

@dentarg
Copy link

dentarg commented Mar 12, 2018

@dstufft I have python and python@2 installed from Homebrew, here's what it returns

$ brew -v
Homebrew 1.5.10-6-g700a4b4
Homebrew/homebrew-core (git revision 6a709; last commit 2018-03-12)
$ ls -ahl =python
lrwxr-xr-x  1 dentarg  admin    38B Mar 12 10:34 /usr/local/bin/python@ -> ../Cellar/python@2/2.7.14_3/bin/python

$ /usr/local/bin/python -c "import sys; print(sys.executable)"
/usr/local/opt/python@2/bin/python2.7
$ ls -ahl =python3
lrwxr-xr-x  1 dentarg  admin    36B Mar 12 10:33 /usr/local/bin/python3@ -> ../Cellar/python/3.6.4_4/bin/python3

$ /usr/local/bin/python3 -c "import sys; print(sys.executable)"
/usr/local/opt/python/bin/python3.6

@bjay1404
Copy link

It look me a long time to stumble upon this! I'm having the same problem with clean installs

ipython
zsh: /usr/local/bin/ipython: bad interpreter: /usr/local/opt/python/bin/python2.7: no such file or directory

@bjay1404
Copy link

Looks like this is why

 $ /usr/local/bin/python -c "import sys; print(sys.executable)"
/usr/local/opt/python@2/bin/python2.7

@MikeMcQuaid
Copy link

I think we just use the value of sys.executable

Thanks, this is helpful and explains the issues here 👍

@ilovezfs
Copy link

ilovezfs commented Mar 13, 2018

Sorry but I don't think it's using sys.executable or that anything has been explained yet. As you can see above, sys.executable is printing the opt path but virtualenvs are actually using the realpath.

bash-3.2$ virtualenv -ppython3 venv
Running virtualenv with interpreter /usr/local/bin/python3
Using base prefix '/usr/local/Cellar/python/3.6.4_4/Frameworks/Python.framework/Versions/3.6'
New python executable in /Users/joe/virtualenvs/venv/bin/python3.6
Also creating executable in /Users/joe/virtualenvs/venv/bin/python
Installing setuptools, pip, wheel...done.
bash-3.2$ ls -l venv/.Python 
lrwxr-xr-x  1 joe  staff  80 Mar 13 01:56 venv/.Python -> /usr/local/Cellar/python/3.6.4_4/Frameworks/Python.framework/Versions/3.6/Python
bash-3.2$ cat venv/lib/python3.6/orig-prefix.txt
/usr/local/Cellar/python/3.6.4_4/Frameworks/Python.framework/Versions/3.6bash-3.2$

but

bash-3.2$ python3 -c "import sys; print(sys.executable)"
/usr/local/opt/python/bin/python3.6

@bumperjeep
Copy link

To be clear, I'm having a problem outside of virtualenv

@pradyunsg
Copy link
Member

I think we should have a new issue for any further discussions here.

@pradyunsg pradyunsg removed the S: awaiting response Waiting for a response/more information label Mar 19, 2018
@foresmac
Copy link

If anyone finds their way here by searching for the error, there is an easier solution if you keep both Python 2.x and Python 3.x on your system. Homebrew Python 2 keeps your pip installed packages in /usr/local/lib/python2.7/site-packages, and if you installed virtualenv with Python 2 it's still there. So all I did was rewrite the hash-bang in /usr/local/bin/virtualenv like so:

> which python
/usr/local/bin/python

or

> which python2
/usr/local/bin/python2

Update the hash-bang to one of the above values and everything works.

@exipilis
Copy link

exipilis commented Sep 7, 2018

Kudos to @foresmac . Editing /usr/local/bin/virtualenv file works like a charm.

@LUSUDEV
Copy link

LUSUDEV commented Sep 22, 2018

Antes de instalar Django vamos a crear nuestro entorno virtual, para ello realizamos el siguiente
comando: mkvirtualenv -p /usr/bin/python2.7 proyecto. Asegúrense de que la
dirección de Python 2.7 en sus sistemas estén correctas.

#mkvirtualenv -p /usr/bin/python2.7 proyecto. listo en mi caso fue estos que me decías que The path /usr/local/bin/python2.7 (from --python=/usr/local/bin/python3.6) does not exist me faltava el puntu al final.

@lock
Copy link

lock bot commented Jun 1, 2019

This thread has been automatically locked since there has not been any recent activity after it was closed. Please open a new issue for related bugs.

@lock lock bot added the auto-locked Outdated issues that have been locked by automation label Jun 1, 2019
@lock lock bot locked as resolved and limited conversation to collaborators Jun 1, 2019
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
auto-locked Outdated issues that have been locked by automation OS: macos MacOS specific project: virtualenv Related to virtualenv resolution: invalid Invalid issue/PR
Projects
None yet
Development

No branches or pull requests