Some times ago, I made a post entitled ‘Sandboxed Python with Pyenv, virtualenv and autoenv’ .
I’m a Ruby fan, and a rather poor python developer, however at the occasion of SC’17 , I was playing with jupyter notebooks and tensorflow within a Machine Learning tutorial , two components that made me really enjoy (for the first time) Python.
It was also the occasion to refresh my notes on virtualenv and to discover the excellent direnv tool, a better replacement to autoenv (from the own terms of autoenv author ).
Here are my updated notes to setup a clean and sandboxed environment for python projects (similar to what can be done in Ruby with RVM and project gemsets ).
Reference :
Installation
Under Mac OS X , prefer (as always) an installation through Homebrew :
1
2
3
$> brew update
$> brew install pyenv pyenv-virtualenv
$> brew install direnv
Under Linux , see pyenv-installer :
1
2
3
4
# Under Linux
$> curl -L https://raw.githubusercontent.com/pyenv/pyenv-installer/master/bin/pyenv-installer | bash
$> git clone https://github.com/pyenv/pyenv-virtualenv.git $( pyenv root) /plugins/pyenv-virtualenv
$> { apt-get | yum } install direnv
You probably want also to activate the pyenv bash/zsh completion
Configuration
Adapt your environment i.e. ~/.{profile | bash* | zsh* etc.} to support pyenv shims , virtualenv and direnv :
1
2
3
4
5
6
7
8
9
# Bash
$> echo 'eval "$(pyenv init -)"' >> ~/.bash_profile
$> echo 'eval "$(pyenv virtualenv-init -)"' >> ~/.bash_profile
$> echo 'eval "$(direnv hook bash)"' >> ~/.bashrc
#
# ZSH
$> echo 'eval "$(pyenv init -)"' >> ~/.zshenv
$> echo 'eval "$(pyenv virtualenv-init -)"' >> ~/.zshenv
$> echo 'eval "$(direnv hook zsh)"' >> ~/.zshrc
If you’re using oh-my-zsh , you probably want to enable the pyenv plugin
Now you can configure direnv :
1
$> mkdir -p ~/.config/direnv
You can now edit ~/.config/direnv/direnvrc to define the functions common and available to all your .envrc files. Add the following content :
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
# ~/.config/direnv/direnvrc: Global configuration for direnv to make it compliant
# with pyenv -- see https://direnv.net/
#
# Adapted from
# - https://github.com/direnv/direnv/wiki/Python#-pyenv and
# - https://github.com/direnv/direnv/wiki/Python#-virtualenvwrapper
#
# use a certain pyenv version
use_python() {
if [ -n "$(which pyenv)" ] ; then
local pyversion = $1
pyenv local ${ pyversion }
fi
}
layout_virtualenv() {
local pyversion = $1
local pvenv = $2
if [ -n "$(which pyenv-virtualenv)" ] ; then
pyenv virtualenv --force --quiet ${ pyversion } ${ pvenv } -${ pyversion }
fi
}
layout_activate() {
if [ -n "$(which pyenv)" ] ; then
local pyenvprefix = $( pyenv prefix)
local pyversion = $( pyenv version-name)
local pvenv = "$1"
source ${ pyenvprefix } /envs/${ pvenv } -${ pyversion } /bin/activate
fi
}
Time for the awesome magic
Install a few different pythons
1
2
3
4
5
6
7
$> pyenv install --list
$> pyenv install 2.6.9
$> pyenv install 2.7.14
$> pyenv install 3.1.5
$> pyenv install 3.2.6
$> pyenv install 3.4.7
$> pyenv install 3.5.4
Assuming you wish to configure you project hosted within the /path/to/myproject directory:
Define the expected python version under .python-version:
1
2
$> cd /path/to/myproject
$> echo '2.7.14' > .python-version
Define the expected name for the virtualenv under .python-virtualenv:
1
$> echo 'myenv' > .python-virtualenv
Define the direnv configuration file .envrc for your project (you can actually copy/paste the below content for all your files):
1
2
3
4
5
6
7
8
9
10
11
# -*- mode: sh; -*-
# (rootdir)/.envrc : direnv configuration file
# see https://direnv.net/
pyversion = $( head .python-version)
pvenv = $( head .python-virtualenv)
#
use python ${ pyversion }
# Create the virtualenv if not yet done
layout virtualenv ${ pyversion } ${ pvenv }
# activate it
layout activate ${ pvenv } -${ pyversion }
1
$> curl -o .envrc https://raw.githubusercontent.com/Falkor/dotfiles/master/direnv/envrc
Allow the .envrc file
1
2
3
4
$> direnv allow .
direnv: loading .envrc
direnv: using python 2.7.14
direnv: export +VIRTUAL_ENV ~PATH
Enjoy your sand-boxed environment
1
2
3
4
5
6
7
8
9
10
11
12
13
14
$> pip list
pip ( 9.0.1)
setuptools ( 37.0.0)
wheel ( 0.30.0)
#
# install your packages
$> pip install numpy scipy matplotlib
$> pip install jupyter ipykernel
$> python -m ipykernel install --user --name= $( head .python-virtualenv)
$> jupyter notebook
#
# freeze your environment to pass it around
$> pip freeze -l # List all the pip packages used in the virtual environment
$> pip freeze -l > requirements.txt # Dump it to a requirements file in the project folder
Leave your directory to unload the virtualenv and thus ensure the isolation:
1
2
3
4
5
6
7
8
$> pyenv version
2.7.14 ( set by /path/to/myproject/.python-version)
$> python -V
Python 2.7.14
$> cd
direnv: unloading
$> python -V
Python 2.7.10
Reminder : You can later on install all pip packages back from the requirements.txt file (generated by pip freeze -l > requirements.txt) via:
1
$> pip install -r requirements.txt