Python Environment Management for Rubyists – a Guide

Python has always been an intriguing language to me, but I’ve never been a huge fan of its syntax. I have always liked Lisps, though. Thus, when I discovered Hy a few months ago, I was completely smitten. Then I tried to set up a development environment, and was caught in a morass of old tooling and poorly explained transitions. Python 2? Python 3? Pip? Setuptools? Easy_install? Ugh.

Thankfully, I’ve now discovered a few tools that make managing multiple versions of Python and your projects libraries a breeze (on Mac/Linux systems, at least). In this post, I’ll walk you through a basic Python setup to get you rolling on a new project.

Python Package Management

When confronting the problem of managing library dependencies, I was massively confused. Over the course of Python’s evolution, there have been many tools for managing and distributing packages. Googling around, you’ll find (at minimum) references to distutils, setuptools, easy_install, and pip.

Luckily, until you want to start distributing your own libraries, you can pretty much forget about everything but pip. As Anton Kovalyov quipped on Twitter, “easy_install is the internet explorer of Python package managers.” (It is only used to install pip when setting up your development environment)

Pip has an extremely easy to use interface, similar to other well-known package managers like bundler or npm.

Python Version Management

In Ruby, tools like rbenv make it a snap to install and manage which version of Ruby is being used for a project. By simply dropping a file called .ruby-version containing your desired Ruby version in your project directory, rbenv will automatically update shims to point at the correct Ruby install. Combined with bundler to manage package versions, you have a full language versioning system.

For quite some time, Python has had the ability to isolate the module dependencies for a project using a utility called virtualenv. Virtualenv allows you to source a shell script to activate a particular Python environment, with isolated packages and a specific Python version, which I found pretty awesome. Virtualenv does not, however, provide any facilities for managing installed Pythons.

Thankfully, an enterprising developer forked rbenv to create pyenv, which works very similarly to rbenv. When combined with pyenv-virtualenv, it allows you to automatically activate a Python virtualenv on a per-project basis.

To install pyenv and pyenv-virtualenv with Homebrew on a Mac:

  1. brew install pyenv
  2. brew install pyenv-virtualenv
  3. Add the following lines to your .bash_profile to put the pyenv shims in your $PATH:

    if which pyenv > /dev/null; then eval "$(pyenv init -)"; fi
    if which pyenv-virtualenv-init > /dev/null; then eval "$(pyenv virtualenv-init -)"; fi
  4. Close and reopen your terminal so the $PATH changes propagate

And to set up a fresh Python environment for a new project:

  1. pyenv install 3.4.2
  2. cd /my/project/dir
  3. pyenv virtualenv 3.4.2 my_project_env
  4. Drop a .python-version containing my_project_env into your current directory
    pyenv local my_project_env

Congratulations. Now whenever you cd into this project directory, pyenv-virtualenv will activate the “my_project_env” virtualenv, and all your package installs will be scoped to the “my_project_env” virtualenv.