Differences between Pyenv and Pipx
Contents
I have been told that pipx is a very good tool to install and run Python
applications in isolated environments. That description almost immediately
reminds me of another tool - pyenv. Even though they address different
needs, I find myself mixing them up. The purpose of this post is to describe
what the tools try to accomplish and how they go about doing so. A pre-requisite
to this discussion is an introduction to how the system $PATH environment
variable is used.
Introducing $PATH
At a fundamental level, $PATH is an environment variable which consists of
a list of directories separated by colons (:). Here is a quick example,
|
|
When a command is entered, the OS scans this group of directories (in the order
given) for a corresponding executable to run. For example, assume we wish to
run the docker-compose executable. Here are the different attempts the OS
makes,
|
|
If it is unable to find the executable within any of the directories on the
$PATH , an error message is returned to the user.
A … divergence, or an exception to the above behaviour is when shims are
involved. You can think of them as light-weight utilities which process the
name of the executable searched for within the directory and respond
accordingly.
About pyenv
pyenv is a tool to help manage different Python environments on the same
system. For example, one might have Python 2.7 installed for one project and
Python 3.8 installed for another. On this system, if we were to randomly run
$ python --help which version would we reasonably expect to answer?
One approach is to manually manage everything, adding or removing entries from
$PATH as needed. This gets messy and troublesome. A better alternative is
to use the pyenv tool. When installed and initialized, pyenv adds a
custom shim to the $PATH environment variable. The end result looks
something like this,
|
|
At the point, every command executed is processed via pyenv (via the shim).
If it decides that it is a Python-related command, pyenv will redirect
execution to the corrsponding Python executable.
For the most part, this works very well. An interesting side-effect of this
design, is that the pyenv tool needs to be active on the system. In
contrast, pipx does not.
About pipx
As per the official documentation “pipx is a tool to help you install and run end-user applications written in Python”. It will be helpful to understand what we mean by “end-user applications” in this context. The background is that Python and PyPI allow developers to distribute code with “console script entry points”. These allow users to call into the Python code from the command line, effectively acting as standalong applications.
pipx is a tool to install and run any of these standalone applications in a safe, convenient and reliable way.
On hearing all that, I expected to install pipx as a global tool on my
system, similar to what I did for pyenv. It greatly confused me that this
was not the case. In fact if you want to keep environments isolated, the
easiest way to use pipx is to create a new Python virtual envrionment and just
install it via pip ! Something like this,
|
|
At this point, let us assume that we want to install the pycowsay CLI tool
from PyPI. Since pipx is already present in our current virtualenv, all we
need to do is,
|
|
Running the above command will create a new virtualenv at
/home/USER/.local/pipx/venvs and a symbolic link in the
/home/USER/.local/bin directory which points to the executable within the
virtualenv.
What is most remarkable is that we can now delete the virtualenv created for
pipx, but our installation of pycowsay will still be present!
|
|
Oookay. That was disappointing. Looks like my original intuition about pipx
being dependant on the virtualenv from where it gets installed from is accurate.
In this scenario, what I would like to happen is for pycowsay to pick up my
“root” Python 3.8.5 executable. Hmm… according to the pipx docs, that
might be possible. Lets give this a shot,
|
|
Yay! That worked!!
In conclusion, this is going to my general approach to installing things via
pipx,
|
|