Get started with pyenv & poetry. Saviours in the python chaos!

Get started with pyenv & poetry. Saviours in the python chaos!


An introduction to pyenv and poetry for python!

There’s no denying it. Python is one of the most widely used programming languages today. Especially within Data Science. However, there are few languages that can cause such chaos and frustration as python. Handling different python-installations and dependencies can be a nightmare!

Let’s be thankful for pyenv and poetry, candles that light up the python darkness! In this post I will show you how to install these two tools, and some basic usage examples.


pyenv is a python installation manager. It allows you to install and run multiple python installations, on the same machine. pyenv manages the different versions for you, so that you will avoid the chaos illustrated in the above picture. Don’t ever again install a python version any other way!

Illustrates the hierarchy that pyenv uses to decide which installed python version to use. From

Setup & get started with pyenv

You can follow the steps below for installing on macOS. I’m using Homebrew, but see the pyenv documentation for alternative installation methods.

# Install pyenv.
brew install pyenv

# Add pyenv initializer to shell startup script.
echo -e 'export PYENV_ROOT="$HOME/.pyenv"
export PATH="$PYENV_ROOT/bin:$PATH"
eval "$(pyenv init --path)"
eval "$(pyenv init -)"' >> ~/.bash_profile

# Reload your profile.
source ~/.bash_profile

With pyenv installed, you can install any python version that you would like. Below I am installing some python versions. Depending on which directory you’re in, pyenv will point to your specified python version.

# See all available python installations.
pyenv install --list

# Install some python versions.
pyenv install  3.7.5
pyenv install  2.7.17
pyenv install  3.8.0

# See all python installations that you have installed.
pyenv versions

# Set the default/global from one of the python versions.
pyenv global 3.8.0

# In the current directory, set the python version. This creates the file .python-version.
pyenv local 2.7.17

# To see which python is currently being used.
pyenv version


poetry is a packaging and dependency manager. It resolves your library dependencies, and can build and publish your project to be distributed on your private pypi repository. In the beginning of December 2019, version 1.0.0 was finally released!

The main file of your poetry project is the pyproject.toml file. Define the requirements, the dev-requirements and project metadata in this file. poetry uses the .toml file to resolve the dependencies of your defined requirements, and creates the poetry.lock file. Then poetry creates a virtual environment and installs everything from the .lock file.

(Some alternatives to poetry for virtual environments are virtualenv, conda, venv or pipenv. I’ve used them all, especially pipenv. However, I believe that poetry is superior!)

Setup poetry

As of writing, poetry is not yet available on Homebrew. Follow the steps below for installing it.

# Install poetry via curl
curl -sSL | python

# Add poetry to your shell
export PATH="$HOME/.poetry/bin:$PATH"

# For tab completion in your shell, see the documentation
poetry help completions

# Configure poetry to create virtual environments inside the project's root directory
poetry config true

With poetry installed, I can now create a python project. I will define a project catered for data science. poetry will install a virtual environment based on python 3.7.5, that I have already installed with pyenv. I will include data analytics libraries like pandas and scipy, along with jupyter notebook. In addition I will include the ML libraries scikit-learn and a specific pre-release version of tensorflow. Finally, I will specify black and flake8 for formatting and style guiding.

# Specify the python version for the local directory using pyenv
pyenv local 3.7.5

# Create a new project, and directory
poetry new hugos-ds-poetry-demo

# Specify some libraries
cd hugos-ds-poetry-demo
poetry add pandas numpy scipy tensorflow=2.1.0rc2 tensorflow-text matplotlib scikit-learn jupyter ipykernel

# Specify some dev libraries
poetry add --dev black flake8

With the above commands, I have created a pyproject.toml file as well as a poetry.lock file. poetry has installed the virtual environment for this project in hugos-ds-poetry-demo/.venv. The pyproject.toml file looks as follows.

name = "hugos-ds-poetry-demo"
version = "0.1.0"
description = ""
authors = ["Hugo Hjertén <>"]

python = "^3.7"
pandas = "^0.25.3"
numpy = "^1.18.0"
scipy = "^1.4.1"
tensorflow = "2.1.0rc2"
tensorflow-text = "^2.0.1"
matplotlib = "^3.1.2"
scikit-learn = "^0.22"
jupyter = "^1.0.0"
ipykernel = "^5.1.3"

pytest = "^5.2"
black = "^19.10b0"
flake8 = "^3.7.9"

requires = ["poetry>=0.12"]
build-backend = "poetry.masonry.api"

Get started with poetry

# The contents of my directory.

I have added the hugos-ds-poetry-demo/ file. It’s contents are the the same as below.

'''An example file that imports some of the installed modules'''

import pandas as pd
import numpy as np
import tensorflow as tf
import tensorflow_text as text
import matplotlib.pyplot as plt

if __name__ == "__main__":
    # If the modules can't be imported, the following print won't happen
    print("Successfully imported the modules!")

I can now run this python script from within that virtual environment.

# Try running the script outside your virtual environment. This won't work.
python hugos_ds_poetry_demo/

# Run the script within your virtual environment, using the 'run'-command.
poetry run python hugos_ds_poetry_demo/

# Spawn a shell within your virtual environment.
poetry shell

# Try running the script again, after having spawned the shell within your virtual environment.
python hugos_ds_poetry_demo/


Above I have just provided you with the bare minimum to get you started. For more details, please see the documentation for pyenv and poetry! Your python life will be that much easier once you start using them both!


Use clean python versions

If you intend to use poetry and pyenv, use clean python versions. In your pyproject.toml file you define the python version dependency, and individual library dependencies. pyenv gives the possibility of installing python versions like ironpython, cpython, anaconda and miniconda versions. For example, the anaconda python installation comes with many libraries preinstalled. These preinstalled libraries won’t show up in your pyproject.toml or poetry.lock file. Any dependencies baked into the non-clean python version will not be specified. This makes it very difficult to share and recreate your environment/project.

Using jupyter with poetry

jupyter works with kernels, and will not work out of the box with your virtual environment that poetry created for you. If you wish to work in a jupyter notebook based on your virtual environment, you need to create a kernel for that virtual environment. The code below explains how. The prerequisite is that you have added both jupyter and ipykernel as dependencies in your poetry project.

# Make sure to run the command within your virtual environment. The 'poetry run' command ensures this
# Best practice is to use the same name for your kernel as the project.
poetry run ipython kernel install --user --name=hugos-ds-poetry-demo

Death of virtual environments – PEP 582

Developing with python is constantly becoming easier and better, thanks to libs and enhancements by the growing python community. One such Python Enhancement Proposals (PEP) is PEP 582. This will avoid the steps to create, activate or deactivate “virtual environments”. So let’s cross our fingers for this to be implemented asap! :)

Problems installing python versions with pyenv

No tool is perfect, and unfortunately there are some drawbacks and issues when installing python versions with pyenv. For instance, there is a delay from when a new python version has been released, to when it is available in pyenv. New versions of python are available with upgrades of pyenv.

When installing a python version with pyenv you might encounter the following error, zipimport.ZipImportError: can't decompress data; zlib not available. This is explained in more detail here, but the following fix might work for you.

# If you are experiencing zipimport.ZipImportError, the following fix might help!
brew install zlib
brew install sqlite
export LDFLAGS="${LDFLAGS} -L/usr/local/opt/zlib/lib"
export CPPFLAGS="${CPPFLAGS} -I/usr/local/opt/zlib/include"
export LDFLAGS="${LDFLAGS} -L/usr/local/opt/sqlite/lib"
export CPPFLAGS="${CPPFLAGS} -I/usr/local/opt/sqlite/include"
export PKG_CONFIG_PATH="${PKG_CONFIG_PATH} /usr/local/opt/zlib/lib/pkgconfig"
export PKG_CONFIG_PATH="${PKG_CONFIG_PATH} /usr/local/opt/sqlite/lib/pkgconfig"

Another error that you might encounter is ar: internal ranlib command failed. For me, moving/removing the ar and ranlib directories did the trick.

# If you are experiencing 'ar: internal ranlib command failed', the following fix might help!
sudo mv /opt/local/bin/ranlib    /opt/local/bin/ranlib-backup
sudo mv /opt/local/bin/ar        /opt/local/bin/ar-backup

Hugo Hjerten

As a software engineer, Hugo pays a lot of attention to detail, and is adamant about well structured and maintainable code. His go-to language is Python. As a dataOps Engineer, Hugo is passionate about reducing the end-to-end cycle time of getting value from data. Combining good software and data engineering practices is an up and coming area that he stays on top of. As a project leader, Hugo is positive and motivating. Being a quick learner, he is excited about trying new areas.

This Post Has 17 Comments

  1. Hugo Hjerten

    Received the following question on linkedin:
    Nice read! What features is it that are superior in poetry compared to for example Conda, and how is the transition when you move from development to production?

    Happy you liked it! :) An advantage with conda is that it’s language-agnostic and has support for binary packages. With conda you can install your specific python version directly into the virtual environment, which you cannot with poetry. The main contributor of poetry stresses the fact that poetry is not a python version manager. That’s why you need pyenv also :)

    However, what Poetry does really well is resolve dependencies for the libraries that you require in your project. Another major benefit of poetry over conda is how easy it is to recreate and share the environment, superior over the standard files.

    More or less, pipenv has these benefits over conda also. But where poetry wins over pipenv is that it is less buggy. It feels more mature and tested, even though its younger :) Even though pipenv is the recommended library dependency manager… With the recent release of 1.0.0 most of the previous smaller bugs are fixed!

    Also, packaging your project and publishing your custom python library to i.e. pypi, is super-easy with poetry!

    And we found going into production with poetry is really forgiving and easy!

    Long response… I guess I believe in poetry ;)

  2. Ian

    Great article, Hugo!

    If I may ask, what is the advantage of creating the .venv/ folder in the project’s root directory rather than in the default location?

    1. Hugo Hjerten

      Hi Ian! Happy you appreciated the article :)

      Creating the .venv directory in the project’s root folder is definitely a question of personal taste. I like having everything gathered in the same directory, rather than having the source code in one place and the executables in another. But the biggest reason for me is to make it easier to point out my executables to my IDE. No matter the python project, VS Code always finds the python executable with all of its libs in .venv. I find this very practicle!

      1. James

        Just wondering, do we not end up with multiple copies of the same libraries each time we create a project, which ends up taking more disk space. Is that what most people are willing to do as trade-off? Thanks,

        1. Hugo Hjerten

          Hi James! Yes, you’re completely right, each virtual environment is its own copy. I think it’s worth mentioning that you should make sure to only include the specific libraries that you actually need in your project. I.e, don’t include libraries that “might” come in handy later, but rather add the library first when you actually have a need for it.

          It sounds to me like you often use the same libraries in your different python projects? Either way, unless you have thousands of projects with tons of identical libraries in each project, I would claim that the little extra used disk space is worth it. Good luck!

  3. Nickolay

    Hi Hugo, thanks for the good job. Had nice time reading your article. I have a concern about one of the code samples:

    # Try running the script outside your virtual environment. This won’t work.
    python src/

    # Run the script within your virtual environment, using the ‘run’-command.
    poetry run python src/

    should be not ‘src’ but ‘hugos_ds_poetry_demo’ where you created your file to test the dependencies.

    1. Hugo Hjerten

      Thanks for taking the time to read the post, and pointing out the typo! I have updated the post :)

  4. Sjoerd

    Hey Hugo,

    You used Pyenv to install a Python version and Poetry to create a virtualenv using that version. I tried using a virtualenv created with Pyenv in Poetry but this makes a lot more sense so thanks for clearing it up :)

    1. Hugo Hjerten

      Happy it could be of help to you! :)

      1. Sjoerd

        Hey Hugo, FYI this article is now somewhat outdated since the Poetry installation process has changed slightly making some commands you’re suggesting obsolete, like export PATH=”$PYENV_ROOT/bin:$PATH”.

  5. Michael Klengel

    Hi Hugo,

    interesting article. I experienced a bug (most likely) in Poetry.

    The bug becomes a problem if you are working in a folder with a space in the folder name, e.g. “/Volumes/Macintosh SR0/Users/mklengel/Development” and using “poetry config true”.

    I’ve reported the possible bug here:

    My current workaround is “poetry config false” – I don’t like this, because VS Code doesn’t find the .venv folder in this case.


  6. John

    +1 for ‘poetry config true’ I didn’t know about that.

  7. isssam

    What is the benefit to use pyenv with poetry here?! , poetry install a version of python you specified in toml file in default location : ../cache/.poatry/your_virtual _env/python
    and every package you installed it’s in python folder in the same path, and every project can have isolated python version installed in virtual env folder (in poetry path) , so I think one must be used, (poetry or pyenv ) , don’t both

  8. Kevin Stech

    Just leaving this here as food for thought.
    1. pipenv integrates seamlessly with dotenv. poetry refuses to and requires upgrade to 1.2 prerelease + plugin
    2. pipenv falls neatly under pyenv, thus respecting local versions. pipenv will even use pyenv to install a missing version for you. poetry is not integrated and does not respect pyenv local version. feels more like 2 separate tools to manage and synchronize.
    3. pipenv has a simple npm-like scripts syntax in Pipfile. poetry has a much more obscure and finnicky scripts syntax that relates more to python package management than the environment shell.

  9. t

    Thank you for this helpful site!
    You have a typo:
    echo -e ‘export PYENV_ROOT=”$HOME/.pyenv”
    should read:
    echo -e ‘export PYENV_ROOT=”$HOME/.pyenv”‘
    missing the closing single quote

  10. W Connolly

    Just a quick note, it seems like poetry is now available on homebrew! I did a quick check when I started reading this article and it looks like it installed fine?

Leave a Reply