Backpressure for dummies
A toy example showing how lacking backpressure may lead to failures and how to add it.
Using various tools to make python environments working automagically also with emacs
TL;DR
Using direnv, pyenv and a few other plugins you can automagically make your shell or Emacs activate and deactivate python environment as you step in or out project folders
It’s now 5+ months that I am using Emacs as my main IDE. Getting used to it has been an interesting experience, as well as a massive time sink. For now I don’t see any reasons to go back to PyCharm, although I have never been a power user, so my perception of its value is probably a partial one. At the same time, given how steep the Emacs learning curve is, and how good modern IDEs are, I don’t think I will sell Emacs as a worthy investment either.
Creating an effective, and modern IDEs with Emacs is a lot of work, which doesn’t end with your Emacs config (you can find mine here my github). It also took me a while to make Emacs works effectively with different python projects and their related working environment. Specifically I wanted the LSP and various other code checkers to use the right python virtual environment when reading or editing python files belonging to different projects and environments. Eventually I succeded and this post is going to describe the final result.
.envrc
file. You can find here the docs covering PythonWhat do we gain by using so many tools?
Install direnv
, pyenv
, pyenv-virtualenv
, emacs-direnv
and emacs pyvenv
as per their documentation. Below I am also going to cover some specific configuration steps for the first two tools, the third shouldn’t require any config, while for the fourth and fifth should be enough follow their docs.
Now we need add to our preferred shell startup file (.zshrc
and zshenv
in my case) the environment variables needed for pyenv to work. Following the pyenv documentaion should be enough. There is also a useful snippet you can to your startup file so that the active environment name shows up in the terminal.
My .zshrc
after this step
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# Automatic venv activation
command -v pyenv >/dev/null || export PATH="$PYENV_ROOT/bin:$PATH"
eval "$(pyenv init --path)"
# show on terminal the activate virtualenv name
setopt PROMPT_SUBST
show_virtual_env() {
if [[ -n "$VIRTUAL_ENV" && -n "$DIRENV_DIR" ]]; then
echo "($(basename $VIRTUAL_ENV))"
fi
}
PS1='$(show_virtual_env)'$PS1
# needed for automatically activating virtual env
eval "$(pyenv virtualenv-init -)"
My .zshenv
after this step
1
2
export PYENV_ROOT="$HOME/.pyenv"
export PATH="$PYENV_ROOT/bin:$PATH"
Also, when using Ubuntu this setup leads to the following error whenever I entered a directory containing a .envrc
file
direnv: PS1 cannot be exported. For more information see https://github.com/direnv/direnv/wiki/PS1
Adding unset PS1
at the end of the .envrc
was enough to make it go away.
Worth mentioning that different shells may require slightly different scripts for showing the activate virtual env. This resource could be helpful to figure out the right one for you.
In order to make direnv
work nicely with pyenv it will be necessary to create a .direnvrc
file in your home and add the following script to it
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
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
pyenv local --unset
}
layout_activate() {
if [ -n "$(which pyenv)" ]; then
source $(pyenv root)/versions/$1/bin/activate
fi
}
and also add eval "$(direnv hook zsh)"
to your shell startup script, again it will change depending on your preference.
Just to give my whole setup. I also add two other environment variables, one to tell virtualwrapper where the environments are, and one to do the same for Poetry. Not that I have to necessarily use them, but it’s nice to have them already there in case I want to.
At this point whenever you creat a new python project it is enough to do the followings.
Create a new environment pyenv virtualenv 3.10.6 new-environment
Create a .envrc
file in the root directory of the new python project, and add the following two lines to it
1
2
layout activate new-environment
unset PS1
The last step is telling direnv that it can trust the newly create .envrc
file by running direnv allow
.
Finally you should be good to go and finally enjoy some magic!
Creating a poetry environment is then a simple as running pyenv local your-python-version-of-interest
inside the poetry project folder and then creating the new project manually or through the standard poetry workflow.
At this point you should have gain the following functionalities:
cd
in the directory with the .envrc
file the new environment will be active, you cd
out and it’s not active anymore.envrc
file the LSP and various linters you may use will now what python version and libraries to considerIt took me some time to come up with this setup, but I found it to be a game changer when using emacs with python projects. I hope it may be so also for others, including you :-).
by the way these are the relevant bits in my emacs config
1
2
3
4
5
6
7
8
9
(use-package direnv
:config
(direnv-mode))
(use-package pyvenv
:init
(setenv "WORKON_HOME" (substitute-in-file-name "${WORKON_HOME}"))
:config
(pyvenv-mode 1))
A slightly annoying thing of this approach is that it will create both python versions and virtual env in the same folder (ie .pyenv/versions
). In case you don’t want this to happen you can use the standard venv
workflow directly by explicitly referring to the python version of interest. Something like this ~/.pyenv/versions/3.10.6/bin/python -m venv ~/.pyenv/versions/my-new-env
or alternatively pyenv local 3.10.6 && python -m venv ~/.pyenv/versions/my-new-env
Time taken to write post: 4 hours
A toy example showing how lacking backpressure may lead to failures and how to add it.
A simple piece on how to patch objects and use pytest fixtures in tests at the same time
Using various tools to make python environments working automagically also with emacs
On the benefits of documenting your work and how it can impact your share of the pie
Looking back at 2021 to look forward at 2022
Several ideas worth remembering from Sandi Metz’s book 99 bottles of OOP
Can we do better than a straightforward pickle.dump?
Why interviewing time to time is useful and what I learned so far by doing so
Interesting readings of the month
Interesting readings of the month
Use case of the Strategy pattern in a data science application
Interesting readings of the month
Considerations on how practicing writing can help improving how we communicate and how we think
an overview of what eigenvectors and eigenvalues are and why they make PCA work
A possible pattern for replicating programmatically AJAX POST requests when scraping webpages using Scrapy