Setting up pyenv and pyenv-virtualenv

I have a confession to make; I’ve only been using Python virtualenvs for about 6 months (I’ve been working with Python for ~2 years now).

To be honest, by the time I’d been introduced to them, I’d already royally screwed up my default Python’s site-packages, and I was developing on Windows, so virtualenvs just seemed like a lot of hassle. Anyway, everything mostly seemed to sort of work, so why change anything, right?

Wrong. However much hassle, you might think virtualenvs are, spending hours debugging some obscure issue because you and your colleague have ever-so-slightly different versions of some third-party Python library will always be worse.


pyenv is a lifesaver if you have to work with multiple versions of Python. Even if you don’t, I’d recommend installing it, as it makes installing new versions of Python insanely easy. How easy you ask?

$ pyenv install 3.5.0

Now that you’ve installed a new version, pyenv also makes it easy to change the default version used on your system:

$ pyenv global 3.5.0

You can even set multiple global versions at once:

$ pyenv global 2.7.10 3.5.0
$ python --version Python 2.7.10
Python 2.7.10
python2 --version Python 2.7.10
Python 2.7.10
$ python3 --version Python 3.5.0
Python 3.5.0

Note: whichever version you specify first will take precedence when you just type python.

pyenv also has a local command, but I’ll get onto that in a minute…


pyenv-virtualenv, as you might have guessed, combines excellently with pyenv. Creating a new virtualenv is as easy as:

$ pyenv virtualenv 3.5.0 project-virtualenv.3.5.0

where 3.5.0 is the version of Python that you want to use (that you’ve already installed with pyenv!), and project-virtualenv.3.5.0 is the name of your new virtualenv. I find appending the Python version to the end of the virtualenv name is a good habit to get into, as I never have to work out which version of Python I’m currently using.

Which leads me on to my next point; pyenv now treats this new virtualenv as a version of Python (you should see it listed if you run pyenv versions). Combining this with pyenv’s ability to set local versions, you can have pyenv automatically activate the correct virtualenv when you cd into the directory.

Automate all the things!

As easy as pyenv and pyenv-virtualenv make it create new virtualenvs, the automation can still be taken one step further. A lot of my work at the moment involves writing ad-hoc scripts to do some data-processing, creating a super-quick POC, or helping out colleagues who are using Python 2.7, and repeatedly typing out

$ mkdir ad-hoc-project 
$ cd ad-hoc-project
$ pyenv virtualenv 2.7.10 ad-hoc-project.2.7.10
$ pyenv local ad-hoc-project.2.7.10
$ pip install pylint # for Python linting in Sublime Text
$ pip install -r requirements.txt # Sometimes I'd be working on an existing repo

got a bit tedious. I quickly realised I could automate this with a bash function:

function pynew() { 
mkdir -p "$1" && cd "$1" && # don't fail if dir exists
pyenv virtualenv "$2" "$1"-"$2" && # create the new virtualenv
pyenv local "$1"-"$2" && # make virtualenv local Python version
pipup && # a bash alias for pip install --upgrade pip pip install
pylint && # for Python linting in Sublime Text
[ -e "requirements.txt" ] && # check if requirements.txt exists...
pip install -r requirements.txt # ...and if it does, install it

We can call the new bash function like so:

pynew ad-hoc-project 2.7.10



  • You can find installation instructions for pyenv here and pyenv-virtualenv here.
  • For more handy bash functions and aliases, you can check out my prefs GitHub repo. I’ll be doing a blog post on this soon.

Originally published at