Python Virtual Envs

Disclaimer: I fully admit I'm not a detail-oriented person, and as such, I'm satisfied when things work, not necessarily when things work the right way or even why they do so. Like most Python topics, there is more than one way to make or choose a Python virtual environment, and you should do what's right for you, and, ideally, leave me out of it.

Let's set the scene. You're a relatively new Python user, happily writing amazing scripts that automate those button clicks that seem absurd in hindsight. You've ventured beyond core Python, pip installing third party modules with glee. You've even got multiple projects going, using a mix of shared and exclusive modules. It works great for a while, perhaps years! But, the time comes when one project requires X module version A, and another project requires X module version B. Without some fancy footwork, you can only have one version of each module installed at a time.

You've fallen victim to one Python's classic blunders: never install modules globally. Rather, use a virtual environment. No one tells you this until it's too late, sorry to say.

You can think of virtual environments as a self-contained bundle of Python plus a segregated set of modules. Unfortunately, or luckily, depending on your perspective, there are several options for creating virtual environments. This blog post is intended to serve as a starting point for avoiding choice overload when it comes to creating a virtual environment. It is simply the way I do it, and you can do whatever you want in order to segregate your Python environments. You can find some basic advice at the end of each section, but just know that there are many ways to solve this problem, with a variety of tools.

1. Use recommended tool

Especially when you're starting out, trust repo owners to help you choose the best environment for a project. There may be a good reason they recommend a certain method. If they recommend poetry, try to use poetry. If there is no recommendation, go ahead and choose something else.

2. Use venv

venv is what I assume most people mean when they say "virtual environment". The usage is like:

$ python3 -m venv .venv     # create a new env in a directory called ".venv"
$ source .venv/bin/activate # activate the env in the ".venv" directory

The first command creates a new environment, including, among other things, a Python binary, a known directory in which new modules will be installed (e.g. .venv/lib/python3.8/site-packages/), and a method to install new packages (pip). Once you activate the environment with the second command, all packages installed with that pip will be places in that site-packages directory.

venv is an excellent tool to spend time learning. It is my most used environment type, and good for situations in which:

3. Use direnv

If you like venv, you'll love direnv. Once you've installed direnv, the usage is like:

$ echo 'layout_python3' > .envrc # create a file ".envrc" containing the text "layout_python3"
$ direnv allow                   # refresh the direnv to acknowledge the change

The first command creates a .envrc file with a quick instruction for direnv that this is for python 3. The second command prompts direnv to acknowledge that this directory contains a .envrc and get to work building a new environment. In essence, a new venv is created in the directory, but also, because direnv recognizes this directory the environment will automatically be activated on entry and deactivated on exit. Handy! In addition, you can add export and other commands to the .envrc, allowing you to load and unload environment variables for this directory only.

direnv is great in situations where:

4. Use conda

conda is another very popular environment manager (like venv) and also functions as a package manager (like pip). Once installed, conda usage is like:

$ conda create -n env_name # create a new conda environment called "env_name"
$ conda activate env_name  # activate environment

Similar to venv, the first command creates the environment and the second activates it. Unlike venv, conda environments are created and accessible globally, meaning you can easily activate conda environments wherever they are needed. New packages are then installed through conda install rather than pip, although you can also install packages using pip. The nice thing about conda environments is that all conda-installed packages are reconciled against each other to ensure compatibility. However, the annoying thing is that this reconciliation can take...

...f o r e v e r.

(Ignore the text in the tweet above, I'm pretty sure it works in conda now)

A major reason for geospatial developers to consider conda environments is that GDAL python bindings are notoriously difficult to install correctly through pip. If you run into issues creating a functional environment containing GDAL python bindings, consider installing in a conda environment with conda install -c conda-forge gdal.

conda definitely has its place, and that is where:

5. Use mamba

mamba is a newer spin-off of conda. I haven't used it much, but the idea of mamba is that it behaves like conda, only faster. You do need to have both conda and mamba installed in order to use mamba. To create a mamba environment:

$ mamba create -n env_name # create a new mamba environment called "env_name"
$ conda activate env_name  # activate environment with conda

As mentioned, I don't have much to say about mamba, but if your conda environment is taking too long to build, keep mamba in mind.

Use something else entirely

Other popular environment management tools that I have no real opinion about include:

That's all I've got. Enjoy you virtual environments! Get in touch with me on Twitter if you want to continue the discussion!