Virtualenv with pyenv gives wrong python version - python

I have pyenv installed on an up to date debian testing distribution, and have python 2.7.1 in it.
I create a virtualenv for a project with this version, but when activated it gives me the python system version (3.7).
Here is what I did:
$ pyenv virtualenv 2.7.16 my_project-2.7
Requirement already satisfied: virtualenv in /home/user/.local/lib/python2.7/site-packages (15.1.0)
You are using pip version 18.1, however version 19.1.1 is available.
You should consider upgrading via the 'pip install --upgrade pip' command.
Using base prefix '/usr'
New python executable in /home/user/.pyenv/versions/2.7.16/envs/my_project-2.7/bin/python
Installing setuptools, pip, wheel...
done.
Installing pip from https://bootstrap.pypa.io/get-pip.py...
Collecting pip
Using cached https://files.pythonhosted.org/packages/5c/e0/be401c003291b56efc55aeba6a80ab790d3d4cece2778288d65323009420/pip-19.1.1-py2.py3-none-any.whl
Installing collected packages: pip
Found existing installation: pip 19.1.1
Uninstalling pip-19.1.1:
Successfully uninstalled pip-19.1.1
Successfully installed pip-19.1.1
$ pyenv activate my_project-2.7
pyenv-virtualenv: prompt changing will be removed from future release. configure `export PYENV_VIRTUALENV_DISABLE_PROMPT=1' to simulate the behavior.
$ python --version
Python 3.7.3
$ pip --version
pip 19.1.1 from /home/user/.pyenv/versions/2.7.16/envs/my_project-2.7/lib/python3.7/site-packages/pip (python 3.7)
It is strange. The virtualenv is correctly set into ~/.pyenv/version/2.7.16, but I can see that pip come from /home/user/.pyenv/versions/2.7.16/envs/my_project-2.7/lib/python3.7/
I think I missed something, or I might have some mess in my python installation, but I can't find out what this python3.7 lib is doing here.
How can I have this virtualenv created for python2.7 ?
Edit
I tried to completely remove pyenv (removing the $(pyenv root) directory), then reinstall it with pyenv-installer but it did not change anything.
I created two virtualenvs for two projects I have (the above 2.7 and one in 3.5).
$ pyenv virtualenvs
2.7.16/envs/my_project-2.7 (created from /usr)
3.6.8/envs/other_project-3.6 (created from /home/user/.pyenv/versions/3.6.8)
my_project-2.7 (created from /usr)
other_project-3.6 (created from /home/user/.pyenv/versions/3.6.8)
I think the problem could be found from this created from /usr but I don't understand what it means. Why was this virtualenv not created from the pyenv python version ? Is it at all relevant ?
It seems that when I create a 3.+ virtual env, venv is used. But on 2.7, virtualenv is used and fails.

WFM as written if I install pyenv and pyenv-virtualenv from scratch according to the linked instructions.
I can see that pip come from /home/user/.pyenv/versions/2.7.16/envs/my_project-2.7/lib/python3.7/
This shows that most probably, that virtual environment already exists and has a wrong Python version.
I can only conjecture how it ended up like this. Most probably, you were messing with that virtualenv or with pyenv envvars by hand; or ran scripts/have something in your bash stratup scripts that do that. E.g. if you are using pyenv-virtualenv commands to manage your environments, you are not supposed to mix them with regular virtualenv commands.
Deleting this virtualenv with pyenv virtualenv-delete my_project-2.7 then recreating it should help.
If not, delete ~/.pyenv and everything relevant from your startup scripts, restart the shell and reinstall pyenv and pyenv-virtualenv.
For a less destructive fixing, you need to carefully inspect your shell environment (envvars, aliases, defined shell functions) and startup scripts for anything that might conflict with pyenv's work; if that doesn't help, debug pyenv machinery (export PS4='+(${BASH_SOURCE}:${LINENO}): ${FUNCNAME[0]:+${FUNCNAME[0]}(): }' helps here very much) to find out what exactly is happening.

Related

How does pipx know which Python version to use?

I'm a strong pyenv and poetry user that's beginning to use pipx and looking to learn more about how it works. Specifically, I'd like to understand how it determines which Python version to use when installing.
I've noticed that it seems to search PATH for existing references to applications when you pipx install <package> to make existing installations accessible globally. This, for instance, works well with pyenv where it pipx will find a version of the package you install across any Python versions installed via pyenv.
pipx install cookiecutter
⚠️ Note: cookiecutter was already on your PATH at ~/.pyenv/shims/cookiecutter
installed package cookiecutter 1.7.3, Python 3.9.6
These apps are now globally available
- cookiecutter
done! ✨ 🌟 ✨
But what if it's a package you've never installed before? And there's a package version compatible with 3.6, 3.7, 3.8 – how will it determine with Python version to use when installing this package?
I've found you can provide the Python version PipX should install the package into by providing it as an argument to the install command (see below).
More specifically, when using pyenv, you can switch to the version you desire to install into and then provide $(which python) to automatically provide the path to that python version...
pyenv shell 3.X.X
pipx install <package-name> --python $(which python)

Python's default venv environment [duplicate]

As part of the compilation step for a new python version, I fetch and run get-pip.py, to have the latest pip installed next to the python executable:
$ /opt/python/3.7.0/bin/python --version
Python 3.7.0
$ /opt/python/3.7.0/bin/pip --version
pip 18.0 from /opt/python/3.7.0/lib/python3.7/site-packages/pip (python 3.7)
I have 25 such versions under /opt/python, although I mostly use the five latest versions of each major.minor version that is not EOL. To setup an invironment I used to run virtualenv or my virtualenvutils with the -p /opt/python/X.Y.Z/bin/python option to get a virtual environment with a specific version.
With Python 3.7 this gives the imp module deprecation warning:
$ virtualenv -p /opt/python/3.7.0/bin/python /tmp/py37virtualenv
Running virtualenv with interpreter /opt/python/3.7.0/bin/python
Using base prefix '/opt/python/3.7.0'
/opt/util/virtualenvutils/lib/python3.6/site-packages/virtualenv.py:1041: DeprecationWarning: the imp module is deprecated in favour of importlib; see the module's documentation for alternative uses
import imp
New python executable in /tmp/py37virtualenv/bin/python
Installing setuptools, pip, wheel...done.
I have little hope this will be solved in virtualenv, as this has had a PendingDeprecationWarning at least since 2014 (as can be seen from the output in this question)
While investigating replacing virtualenv with python -m venv in virtualenvutils, I first created a new venv based virtual environment by hand:
$ /opt/python/3.7.0/bin/python -m venv /tmp/py37venv
$ /tmp/py37venv/bin/pip --version
pip 10.0.1 from /tmp/py37venv/lib/python3.7/site-packages/pip (python 3.7)
That has an old pip version! If you use it, you'll get:
You are using pip version 10.0.1, however version 18.0 is available.
You should consider upgrading via the 'pip install --upgrade pip' command
In the virtual environment created with virtualenv you immediately get the latest version:
$ /tmp/py37virtualenv/bin/pip --version
pip 18.0 from /tmp/py37virtualenv/lib/python3.7/site-packages/pip (python 3.7)
I can run a post-creation step:
/tmp/py37venv/bin/pip install -U --disable-pip-version-check pip
which will take extra time. And if there was a some security update for pip, this would imply running the non-secure version to get a secure version, an ideal point of attack.
From virtualenvutils it is trivial to do the multiple steps to create a pip-less virtualenv and then add pip using get-pip.py. From the command-line this is not so simple:
$ /opt/python/3.7.0/bin/python -m venv --without-pip /tmp/py37venvnopip
$ /tmp/py37venvnopip/bin/python -c "from urllib.request import urlopen; response = urlopen('https://bootstrap.pypa.io/get-pip'); open('/tmp/tmp_get_pip.py', 'w').write(response.read())"
$ /opt/python/3.7.0/bin/python /tmp/tmp_get_pip.py
......
$ /opt/python/3.7.0/bin/pip --version
pip 18.0 from /opt/python/3.7.0/lib/python3.7/site-packages/pip (python 3.7)
What is causing /opt/python/3.7.0/bin/python -m venv to take that old pip version? Is that the version available when 3.7.0 was released?
How can I update my install under /opt/python/3.7.0 in some way so that using /opt/python/3.7.0/bin/python -m venv creates a virtualenv with the latest pip version without reverting to scripts, aliases or using multiple commands? Having the latest pip installed under /opt/python/3.7.0 obviously is not enough.
There are two bundled wheels:
/opt/python/3.7.0/lib/python3.7/ensurepip/_bundled/setuptools-39.0.1-py2.py3-none-any.whl
/opt/python/3.7.0/lib/python3.7/ensurepip/_bundled/pip-10.0.1-py2.py3-none-any.whl
I suspect I need to update those. Is there a better way than updating those by hand? Some option for /some/python -m venv would be nice.
(And running /some/python -m ensurepip --upgrade doesn't do the trick)
Running the deprecated /opt/python/3.7.0/bin/pyvenv has the same old pip version problem.
The trick is not to install the bundled version of pip (which will almost always be out of date), but to use it to install the most current version from the internet.
Standard library venv offers a --without-pip flag that can help here. After creating the virtual environment without pip, you can then you can "execute" ensurepip's wheel directly thanks to Python's zip importer. This is both faster and less hacky than installing pip and then immediately using that same pip installation to uninstall itself and upgrade.
Code speaks louder than words, so here's an example bash function for the process I've described:
# in ~/.bashrc or wherever
function ve() {
local py="python3"
if [ ! -d ./.venv ]; then
echo "creating venv..."
if ! $py -m venv .venv --prompt=$(basename $PWD) --without-pip; then
echo "ERROR: Problem creating venv" >&2
return 1
else
local whl=$($py -c "import pathlib, ensurepip; whl = list(pathlib.Path(ensurepip.__path__[0]).glob('_bundled/pip*.whl'))[0]; print(whl)")
echo "boostrapping pip using $whl"
.venv/bin/python $whl/pip install --upgrade pip setuptools wheel
source .venv/bin/activate
fi
else
source .venv/bin/activate
fi
}
If you prefer the older project virtualenv, it also offers --no-pip, --no-setuptools, and --no-wheel flags to achieve the same on Python 2.7.
Note: Python 3.9+ venv has an --upgrade-deps option to immediately upgrade the pip/setuptools versions after creating an environment, see https://bugs.python.org/issue34556 for more info about that. I don't use this option because it still goes through an unnecessary install/uninstall of the vendored versions, which is inferior to the method of creating an environment with the latest versions directly as shown above.
I use upgrade-ensurepip to update those pip and setuptools wheel files that are part of the ensurepip package. It's not as elegant as being able to upgrade ensurepip via pip, but it's still preferable to doing it manually.
https://pypi.org/project/upgrade-ensurepip/
It is an expected behavior. python -m venv calls python -m ensurepip to install pip and This answer shows that ensurepip would only install the bundled version even with --upgrade option. There isn't any official option to update the bundled pip and setuptools.
Well I have also no good idea to fix this problem as it just is the designed behavior. I would like to give two suggestions:
Use pipenv. It is really good! And it will be the next-generation official package manager in the future(Although there is a big problem related to current Pypi's structure. In short, a package manager can only decide the dependencies with downloading the whole package. This gives a huge difficulty to building dependencies graph.).
Implement your custom EnvBuilder, actually there is an official example about this. And in the example, it also use get-pip.py to install the latest pip.

pip version is old in virtual environment [duplicate]

As part of the compilation step for a new python version, I fetch and run get-pip.py, to have the latest pip installed next to the python executable:
$ /opt/python/3.7.0/bin/python --version
Python 3.7.0
$ /opt/python/3.7.0/bin/pip --version
pip 18.0 from /opt/python/3.7.0/lib/python3.7/site-packages/pip (python 3.7)
I have 25 such versions under /opt/python, although I mostly use the five latest versions of each major.minor version that is not EOL. To setup an invironment I used to run virtualenv or my virtualenvutils with the -p /opt/python/X.Y.Z/bin/python option to get a virtual environment with a specific version.
With Python 3.7 this gives the imp module deprecation warning:
$ virtualenv -p /opt/python/3.7.0/bin/python /tmp/py37virtualenv
Running virtualenv with interpreter /opt/python/3.7.0/bin/python
Using base prefix '/opt/python/3.7.0'
/opt/util/virtualenvutils/lib/python3.6/site-packages/virtualenv.py:1041: DeprecationWarning: the imp module is deprecated in favour of importlib; see the module's documentation for alternative uses
import imp
New python executable in /tmp/py37virtualenv/bin/python
Installing setuptools, pip, wheel...done.
I have little hope this will be solved in virtualenv, as this has had a PendingDeprecationWarning at least since 2014 (as can be seen from the output in this question)
While investigating replacing virtualenv with python -m venv in virtualenvutils, I first created a new venv based virtual environment by hand:
$ /opt/python/3.7.0/bin/python -m venv /tmp/py37venv
$ /tmp/py37venv/bin/pip --version
pip 10.0.1 from /tmp/py37venv/lib/python3.7/site-packages/pip (python 3.7)
That has an old pip version! If you use it, you'll get:
You are using pip version 10.0.1, however version 18.0 is available.
You should consider upgrading via the 'pip install --upgrade pip' command
In the virtual environment created with virtualenv you immediately get the latest version:
$ /tmp/py37virtualenv/bin/pip --version
pip 18.0 from /tmp/py37virtualenv/lib/python3.7/site-packages/pip (python 3.7)
I can run a post-creation step:
/tmp/py37venv/bin/pip install -U --disable-pip-version-check pip
which will take extra time. And if there was a some security update for pip, this would imply running the non-secure version to get a secure version, an ideal point of attack.
From virtualenvutils it is trivial to do the multiple steps to create a pip-less virtualenv and then add pip using get-pip.py. From the command-line this is not so simple:
$ /opt/python/3.7.0/bin/python -m venv --without-pip /tmp/py37venvnopip
$ /tmp/py37venvnopip/bin/python -c "from urllib.request import urlopen; response = urlopen('https://bootstrap.pypa.io/get-pip'); open('/tmp/tmp_get_pip.py', 'w').write(response.read())"
$ /opt/python/3.7.0/bin/python /tmp/tmp_get_pip.py
......
$ /opt/python/3.7.0/bin/pip --version
pip 18.0 from /opt/python/3.7.0/lib/python3.7/site-packages/pip (python 3.7)
What is causing /opt/python/3.7.0/bin/python -m venv to take that old pip version? Is that the version available when 3.7.0 was released?
How can I update my install under /opt/python/3.7.0 in some way so that using /opt/python/3.7.0/bin/python -m venv creates a virtualenv with the latest pip version without reverting to scripts, aliases or using multiple commands? Having the latest pip installed under /opt/python/3.7.0 obviously is not enough.
There are two bundled wheels:
/opt/python/3.7.0/lib/python3.7/ensurepip/_bundled/setuptools-39.0.1-py2.py3-none-any.whl
/opt/python/3.7.0/lib/python3.7/ensurepip/_bundled/pip-10.0.1-py2.py3-none-any.whl
I suspect I need to update those. Is there a better way than updating those by hand? Some option for /some/python -m venv would be nice.
(And running /some/python -m ensurepip --upgrade doesn't do the trick)
Running the deprecated /opt/python/3.7.0/bin/pyvenv has the same old pip version problem.
The trick is not to install the bundled version of pip (which will almost always be out of date), but to use it to install the most current version from the internet.
Standard library venv offers a --without-pip flag that can help here. After creating the virtual environment without pip, you can then you can "execute" ensurepip's wheel directly thanks to Python's zip importer. This is both faster and less hacky than installing pip and then immediately using that same pip installation to uninstall itself and upgrade.
Code speaks louder than words, so here's an example bash function for the process I've described:
# in ~/.bashrc or wherever
function ve() {
local py="python3"
if [ ! -d ./.venv ]; then
echo "creating venv..."
if ! $py -m venv .venv --prompt=$(basename $PWD) --without-pip; then
echo "ERROR: Problem creating venv" >&2
return 1
else
local whl=$($py -c "import pathlib, ensurepip; whl = list(pathlib.Path(ensurepip.__path__[0]).glob('_bundled/pip*.whl'))[0]; print(whl)")
echo "boostrapping pip using $whl"
.venv/bin/python $whl/pip install --upgrade pip setuptools wheel
source .venv/bin/activate
fi
else
source .venv/bin/activate
fi
}
If you prefer the older project virtualenv, it also offers --no-pip, --no-setuptools, and --no-wheel flags to achieve the same on Python 2.7.
Note: Python 3.9+ venv has an --upgrade-deps option to immediately upgrade the pip/setuptools versions after creating an environment, see https://bugs.python.org/issue34556 for more info about that. I don't use this option because it still goes through an unnecessary install/uninstall of the vendored versions, which is inferior to the method of creating an environment with the latest versions directly as shown above.
I use upgrade-ensurepip to update those pip and setuptools wheel files that are part of the ensurepip package. It's not as elegant as being able to upgrade ensurepip via pip, but it's still preferable to doing it manually.
https://pypi.org/project/upgrade-ensurepip/
It is an expected behavior. python -m venv calls python -m ensurepip to install pip and This answer shows that ensurepip would only install the bundled version even with --upgrade option. There isn't any official option to update the bundled pip and setuptools.
Well I have also no good idea to fix this problem as it just is the designed behavior. I would like to give two suggestions:
Use pipenv. It is really good! And it will be the next-generation official package manager in the future(Although there is a big problem related to current Pypi's structure. In short, a package manager can only decide the dependencies with downloading the whole package. This gives a huge difficulty to building dependencies graph.).
Implement your custom EnvBuilder, actually there is an official example about this. And in the example, it also use get-pip.py to install the latest pip.

pip path: anaconda vs. native python (on macOS)

I am using macOS X and I installed native Python 3.8 in April, and the packages of this version are stored in:
/Users/hubert/Library/Python/3.8/lib/python/site-packages/
Some weeks later, in May, I installed Anaconda, but it uses a different path for it's packages:
/Users/hubert/opt/anaconda3/lib/python3.7/site-packages/
Today I needed to install a new package to be used in a native Python script. I typed:
pip install ffmpeg
I've got a success-message. But when I wanted to run my script, it couldn't find ffmpeg. I rebooted my Mac, but the script still couldn't find it. So I again tried pip install ffmpeg. Now I did get this message:
Requirement already satisfied: ffmpeg in ./opt/anaconda3/lib/python3.7/site-packages (1.4)
But obviously native Pythons wants to have it in the other path.
My questions:
Is it save to just copy the directories ffmpeg and ffmpeg-1.4.dist-info from the anaconda directory to the native directory?
How can I tell pip to use the native Python directory to install new packages?
Is it a good idea to merge the two site-packages directories? And if it's a good idea: What is the best way to let native Python 3.8 and Anaconda (which obviously uses Python 3.7) use the same site-packages directory?
Is it a good idea to modify site-packages manually?
Probably not. The problems you're having are the sorts of problems that virtual environment managers like Anaconda were created to avoid. If you start messing with site-packages, at a minimum you run the risk of creating a lot of new problems in your dependency tree. Unless you need to use two different python installations in the same shell prompt at the same time, your life will be much easier if you just use Anaconda to manage all your environments.
(Bear in mind that creating a new installation of Python 3.8 with ffmpeg installed is as easy as conda create -n mynewenv python=3.8 ffmpeg. Then run conda activate mynewenv whenever you want to use Python 3.8 with ffmpeg installed.)
How to install packages in the right place with pip
Use the right copy of pip
The easiest way is to make sure that you're using the right pip. On MacOS or Linux, you can do this by running which python or which pip before you start installing things. If you want to install to native Python, you'll probably have to run conda deactivate before you start running pip commands.
It's always possible that the pip in your search path is actually a symlink, so it's worth checking this with file -h $(which pip). (In my case, I have a couple of versions of Python installed with homebrew, which likes to symlink things into /usr/local/bin.)
Example
(base) ~ $ which python
/miniconda3/bin/python
(base) ~ $ which pip
/miniconda3/bin/pip
(base) ~ $ conda deactivate
~ $ which python
/usr/local/bin/python
~ $ which pip
/usr/local/bin/pip
~ $ file -h $(which pip)
/usr/local/bin/pip: symbolic link to ../Cellar/python#2/2.7.16_1/bin/pip
Note that the pip for your native installation of Python 3.8 is probably called pip3.
Check where pip is sending stuff
You can check to see where pip/pip3 is installing stuff by checking where a specific package was installed. This can be a way to double-check where things will be installed if it isn't obvious from which pip.
Example
~ $ pip list
Package Version
----------------------------- ---------
...
wheel 0.33.4
~ $ pip show wheel
Name: wheel
Version: 0.33.4
Summary: A built-package format for Python.
Home-page: https://github.com/pypa/wheel
Author: Daniel Holth
Author-email: dholth#fastmail.fm
License: MIT
Location: /usr/local/lib/python2.7/site-packages
Requires:
Required-by:
Note the Location line.

Multiple python installations and pip, dude, where is my site-packages?

As we all know, Mac OS ships with its own python pre installed.
The recommendation seems to be to leave that alone and use homebrew to install a fresh python into the system.
My issue is that after installing python (and pip) using homebrew, pip is installing packages into the Mac OS site-packages instead of my own. I have confirmed I am running the "homebrew" pip:
$ which pip
/usr/local/bin/pip
But then when I pip install something I can se it is installed at:
/lib/python2.7/site-packages
Pip should be installing at /usr/local/lib/python2.7/site-packages unless i'm miss understanding something.
The surprising thing is that checking with -V yields a surprising result:
pip -V
pip 7.1.0 from /usr/local/lib/python2.7/site-packages (python 2.7)
Running pip list just after running pip install does not show the packages that were supposedly just installed by it but went to the wrong site-packages.
Adding to this, the packages installed on the /lib/python2.7/site-packages are not recognized by my $PYTHONPATH and as such I cannot use them.
To add even more confusion, I decided to use a virtualenv, but I was amazed as even using pip with the virtualenv active kept installing to the /lib/python2.7/site-packages instead of the virtualenv site-packages.
So, somehow I ended up with a homebrew pip, that installs packages outside of the homebrew site-packages and a python interpreter that cant use the packages installed by pip.
How do you recommend I go about finding the root cause and having a smooth python experience? :)
You can easily find you site-packages directory by invoking this command
python -c 'import site; print(site.getsitepackages())'
I think after you activate a virtualenv your python path should point to that environments site-package location--if not it's probably not activated. Only once you activate it will you run pip so it installs in that virtual env's site-packages. if it's not activated, it will go in whatever other site-packages it already knows about:
Step 1: create a virtual env
a la... virtualenv venv
Do this only once!
Step 2: Activate the vitual env
something like source /venv/bin/activate
Needs doing every time you want to use this virtual environment
Step 3: run pip commands, watch them get installed in the virtual env site-packages!
If you do step 3 before step 2 your not actually using the virtual environment you created, so all bets are off--That's probably the reason pip is still installing to the old location.
Now, my overall recommendation is to go further and use pyenv to install specific version of python into your /Users/username/.pyenv folder and abandon both the default OSX and homebrew packages. It's simple and you can control easily the exact version of python to use by simple issuing of command to change versions.
THEN use virtualenv in python2 or pyvenv if in python3 (not to be confused with pyenv) to build vitual environments with their own local site-packages to store pip modules. When you activate a virtualenv, your $PYTHONPATH will switch to the specific location.
The flow would then be:
Use pyenv to pull down and switch to a specific version of python you want to use--overriding homebrew and the OSX version.
Create your vitrualenv. This will create a bin that will link to the pyenv python stack you just specified in the previous step.
Activate the virtual env, and proceed.
Totally control your environment!
For one, you could try updating pip with pip install --upgrade pip command, which might or might not redirect your pip path.
Two, and I should have really started with this one is to set the preferred pip executable path in the .bash_profile or .zshrc if you are using one. The way you do it (on Mac) is by holding Shift+Command+Period to reveal hidden files, going to the User folder and opening the .bash_profile/.zshrc with a text editor. Afterward, add the path/to/bin where the pip that you require is. Like export PATH="User/Username/anaconda3/bin:$PATH" or /usr/local/bin or path/to/venv/bin. Whatever code you write in the end will overwrite the previous one.
Three, if you don't wanna change your default pip, but rather wanna use a different version for that specific case just include the full path of the pip executable like /usr/local/bin/pip list or Users/Username/Desktop/venv/bin/pip install module.

Categories

Resources