How I set up my Python projects using asdf and direnv
Tags: tooling, python, productivity
Published: 2023-06-30 20:33:24

I tend to do a lot of work in Python, and I think it can be mess to set up and fiddle with creating virtualenvs for each project, etc. For a long while, I used `pyenv` and `pyenv-virtualenv` to do this for me, but since I still used `asdf` for a bunch of other things (like `nodejs`, or other versions of other languages), I figured I should try to get their Python-plugin to play nicely with me and my setup as well.

Here's what I ended up with.

# 1. Install `asdf`

Go to the [asdf getting started page](https://asdf-vm.com/guide/getting-started.html) and follow the instructions for your operating system. Basically, you need to install `git` and `curl` in order to get `asdf` working.

# 2. Install asdf plugins

  ```
  asdf plugin-install python
  asdf plugin-install direnv
  ```

# 3. Install and configure direnv

`asdf direnv setup --shell bash --version latest`

# 4. Install a python version

First, make sure to install the suggested build dependencies for your operating system. These are listed in [the `pyenv` README](https://github.com/pyenv/pyenv/wiki#suggested-build-environment).

After that, you can run the command to install a Python version: `asdf install python 3.11.4`

# 5. Create a sample project

  ```
  git init hello_world
  cd hello_world
  echo "layout python" > .envrc
  direnv allow
  asdf local python 3.11.4
  echo ".direnv/" >> .gitignore
  ```

Running `python --version` will now print `Python 3.11.4`

The `layout python` part that went into your .envrc tells direnv to set up Python with a virtualenv and put that in the `.direnv/<python-version>` directory (in this case `.direnv/python-3.11`). This means that any packages you `pip install` will end up in there. Therefore, make sure to add that directory to your `.gitignore` file, so that you don't accidentally vendor all of your dependencies, unless that's what you want.

The `direnv allow` part is there to allow direnv to automatically load stuff when you switch to this directory. If you don't do this now, you will get a warning the next time you `cd hello_world`, saying that you haven't allowed the `.envrc` in this directory to run stuff locally. It's there as a security measure.

# 6. Commit your setup

  ```
  git add .gitignore .tool-versions .envrc
  git commit -m "Initial python/direnv setup"
  ```

# 7. Get this to work with your editor

So, how to get this goodness picked up automatically by your editor/IDE then? I mean, if you can't automatically run tests from inside Emacs/(neo)vim/VSCode/whatever, then it's not much use anyway.

Luckily, at least Visual Studio Code picks this up automatically, and even prompts you for the `direnv allow` part separately, so if you only use VSCode as your daily driver, you can probably skip the manual `direnv allow` step in the terminal. I imagine PyCharm and other more fully fleshed out IDEs also provide this luxury.

For Emacs or (neo)vim, you will need to configure whatever plugin you are using to use a shell where you have direnv configured, so with the above example, it should work if you shell out using `bash` rather than `sh`. If you configured direnv to use `zsh`, then maybe you should consider having your editor use `zsh` when shelling out.