Introducing PyENV

I mentioned pyenv in my post about Python print syntactic sugar and I received a few questions about what it is and why I use it so I thought I’d do a brief followup post about the why and how.

Having worked with ruby developers a fair chunk over the last few years I’ve had some exposure to a tool called rbenv, which provides a way to have multiple versions of ruby installed for your user. When you’re testing large upgrades or even small language changes being able to quickly change between versions, and even implementations, is a huge win. It’s even better to be able to play without risking the version of Python the operating system itself requires. Once I started to have more python in my day, and a split in code bases between 2.7 and 3.*, I decided I needed something that provided equivalent functionality. A quick search and I found a possible replacement - pyenv

I followed the pyenv installation instructions and once it was all done, and a fresh new shell opened, I wanted to see which versions were available to me.

> pyenv versions
* system (set by /home/dw/.pyenv/version)

python -V
Python 2.7.15

That’s both boring and what we expect to find. I wanted to experiment with a new feature from 3.8 so I listed all the available versions and then installed the best match.

    pyenv install --list | grep 3.8
      3.8-dev
      miniconda-3.8.3
      miniconda3-3.8.3

    pyenv install 3.8-dev
      Installing Python-3.8dev...
      Installed Python-3.8-dev to /home/dw/.pyenv/versions/3.8-dev

Now we’ve installed the version we want to experiment with we’ll create a directory to contain our code and enable a specific python version.

    # create and enter the directory
    mkdir py
    cd py

    # Check the available python versions
    $ pyenv versions
      * system (set by /home/dw/.pyenv/version)
      3.8-dev

    # and confirm which version we are using
    $ python
      Python 2.7.15 (default, Oct 15 2018, 15:26:09)

You can see which version is currently active by looking for the *. In our case (and the default) it’s the system version, which we can confirm by starting python. We can now change to the version we installed and use it as simply as we would the system one.

    # activate our chosen version...
    $ pyenv local 3.8-dev

    # and confirm it worked. Note the *
    $ pyenv versions
      system
      * 3.8-dev (set by /tmp/py/.python-version)

    $ python
    Python 3.8.0b2+ (heads/3.8:3d58b78, Jul 12 2019, 12:19:05)

We can now use a feature introduced in our chosen version to ensure everything has worked correctly -

    python -c 'user="Dean" ; print(f"User is {user=}")'
    User is user='Dean'

Once we’re finished we can reset the python version to the system one.

    $ pyenv local --unset

    $ pyenv versions
    * system (set by /home/dw/.pyenv/version)

Pyenv provides a great way to flip between different python versions and implementations and can bring flexibility to how you work with the requirements of different code bases. You can combine this isolation with the usual virtualenvs to help keep things even cleaner and separated.