How can I make homebrew's python and pyenv live together?
Question:
After switching to python 3.4.3 from 2.7.9 (which was quite simple), I often wish to test some of my scripts with python 2.7.9 before sharing them with colleagues. I am using a OSX yosemite platform with everything compiled from homebrew.
The situation was quite ugly (setting PATH
es and PYTHONPATH
at each step) – until I discovered pyenv which does this very easily and is easily installed using homebrew. So far, so good.
However, now that I am using this version of python, it does not necessarily play well with that of homebrew. Moreover, I found that I could switch back to the system’s python, and more generally that pyenv could access that:
$ pyenv versions
system
2.7.9
* 3.4.3 (set by /usr/local/var/pyenv/version)
but how could I also add entries for the python
s compiled by homebrew?
Answers:
You can install pyenv in your home directory (as described in pyenv’s installation guide), and then create a symlink at ~/.pyenv/versions
to $(brew --cellar)/python
:
ln -s $(brew --cellar python)/* ~/.pyenv/versions/
The way Homebrew works nowadays, this will pick up both 2.x and 3.x.
Well if you want the pyenv pythons and homebrew pythons to live together you need to make the name of the homebrew pythons something other than the version. Otherwise they will clash with the directory names that pyenv uses. For example, if you want to install pyenv python 2.7.11 and homebrew python 2.7.11 you could do something like this.
for i in `ls $(brew --cellar python)/`; do
ln -s $(brew --cellar python)/$i $HOME/.pyenv/versions/$i-brew;
done
for i in `ls $(brew --cellar python3)/`; do
ln -s $(brew --cellar python)/$i $HOME/.pyenv/versions/$i-brew;
done
Essentially this will create a directory in $HOME/.pyenv/versions appended with ‘-brew’ so that it won’t clash with the pyenv pythons.
Just to add to @johnizzo1‘s answer, python2 is now python@2
, so you should change the python3 for loop to something like:
for i in `ls $(brew --cellar python)/`; do
ln -s $(brew --cellar python)/$i $HOME/.pyenv/versions/$i-brew;
done
for i in `ls $(brew --cellar python@2)/`; do
ln -s $(brew --cellar python@2)/$i $HOME/.pyenv/versions/$i-brew;
done
A handy function to relink versions:
pyenv-brew-relink() {
rm -f "$HOME/.pyenv/versions/*-brew"
for i in $(brew --cellar python)/*; do
ln -s --force $i $HOME/.pyenv/versions/${i##/*/}-brew;
done
for i in $(brew --cellar python@2)/*; do
ln -s --force $i $HOME/.pyenv/versions/${i##/*/}-brew;
done
}
pyenv will use system
as default version when version is not specified.
When you install python@3 by homebrew and pyenv’s version is specified to system
, python
points to python 2.x
in the system and python3
points to python@3
which installed by homebrew.
So usually we don’t need to manually add version to pyenv.
In 2020, after `ln -s /outside/python/x.x.x ~/.pyenv/versions/x.x.x`, you need `pyenv rehash` to rehash shims.
Example: add macos system python 2.7 to pyenv
ln -s /System/Library/Frameworks/Python.framework/Versions/2.7 ~/.pyenv/versions/2.7
pyenv rehash
Pulling all the bits of the previous answers together for one actually working ring to bind them:
pyenv-brew-relink() {
rm -f "$HOME/.pyenv/versions/*-brew"
for i in $(brew --cellar)/python* ; do
ln -s -f "$p" "$HOME/.pyenv/versions/${i##/*/}-brew"
done
pyenv rehash
}
[2022]
The python3 versions in homebrew is now in the format of [email protected]
so, updated shell
#!/bin/bash
pyenv-brew-relink() {
rm -f "$HOME/.pyenv/versions/*-brew"
for i in $(brew --cellar)/python* ; do
for p in $i/*; do
echo $p
ln -s -f $p $HOME/.pyenv/versions/${p##/*/}-brew
done
done
pyenv rehash
}
pyenv-brew-relink
After switching to python 3.4.3 from 2.7.9 (which was quite simple), I often wish to test some of my scripts with python 2.7.9 before sharing them with colleagues. I am using a OSX yosemite platform with everything compiled from homebrew.
The situation was quite ugly (setting PATH
es and PYTHONPATH
at each step) – until I discovered pyenv which does this very easily and is easily installed using homebrew. So far, so good.
However, now that I am using this version of python, it does not necessarily play well with that of homebrew. Moreover, I found that I could switch back to the system’s python, and more generally that pyenv could access that:
$ pyenv versions
system
2.7.9
* 3.4.3 (set by /usr/local/var/pyenv/version)
but how could I also add entries for the python
s compiled by homebrew?
You can install pyenv in your home directory (as described in pyenv’s installation guide), and then create a symlink at ~/.pyenv/versions
to $(brew --cellar)/python
:
ln -s $(brew --cellar python)/* ~/.pyenv/versions/
The way Homebrew works nowadays, this will pick up both 2.x and 3.x.
Well if you want the pyenv pythons and homebrew pythons to live together you need to make the name of the homebrew pythons something other than the version. Otherwise they will clash with the directory names that pyenv uses. For example, if you want to install pyenv python 2.7.11 and homebrew python 2.7.11 you could do something like this.
for i in `ls $(brew --cellar python)/`; do
ln -s $(brew --cellar python)/$i $HOME/.pyenv/versions/$i-brew;
done
for i in `ls $(brew --cellar python3)/`; do
ln -s $(brew --cellar python)/$i $HOME/.pyenv/versions/$i-brew;
done
Essentially this will create a directory in $HOME/.pyenv/versions appended with ‘-brew’ so that it won’t clash with the pyenv pythons.
Just to add to @johnizzo1‘s answer, python2 is now python@2
, so you should change the python3 for loop to something like:
for i in `ls $(brew --cellar python)/`; do
ln -s $(brew --cellar python)/$i $HOME/.pyenv/versions/$i-brew;
done
for i in `ls $(brew --cellar python@2)/`; do
ln -s $(brew --cellar python@2)/$i $HOME/.pyenv/versions/$i-brew;
done
A handy function to relink versions:
pyenv-brew-relink() {
rm -f "$HOME/.pyenv/versions/*-brew"
for i in $(brew --cellar python)/*; do
ln -s --force $i $HOME/.pyenv/versions/${i##/*/}-brew;
done
for i in $(brew --cellar python@2)/*; do
ln -s --force $i $HOME/.pyenv/versions/${i##/*/}-brew;
done
}
pyenv will use system
as default version when version is not specified.
When you install python@3 by homebrew and pyenv’s version is specified to system
, python
points to python 2.x
in the system and python3
points to python@3
which installed by homebrew.
So usually we don’t need to manually add version to pyenv.
In 2020, after `ln -s /outside/python/x.x.x ~/.pyenv/versions/x.x.x`, you need `pyenv rehash` to rehash shims.
Example: add macos system python 2.7 to pyenv
ln -s /System/Library/Frameworks/Python.framework/Versions/2.7 ~/.pyenv/versions/2.7
pyenv rehash
Pulling all the bits of the previous answers together for one actually working ring to bind them:
pyenv-brew-relink() {
rm -f "$HOME/.pyenv/versions/*-brew"
for i in $(brew --cellar)/python* ; do
ln -s -f "$p" "$HOME/.pyenv/versions/${i##/*/}-brew"
done
pyenv rehash
}
[2022]
The python3 versions in homebrew is now in the format of [email protected]
so, updated shell
#!/bin/bash
pyenv-brew-relink() {
rm -f "$HOME/.pyenv/versions/*-brew"
for i in $(brew --cellar)/python* ; do
for p in $i/*; do
echo $p
ln -s -f $p $HOME/.pyenv/versions/${p##/*/}-brew
done
done
pyenv rehash
}
pyenv-brew-relink