Tox with Pyenv & Poetry to Test Projects with Multiple Python Versions

Recently, I was working on Limber Framework and I wanted to increase the availability of the framework by supporting multiple versions of Python. However, in order to say that the framework can work with a version of Python, I need to check that there’s no issues with that particular version, i.e. run the automated tests. Manually running the tests for each supported version of Python will require a lot of work, which will only grow as the project develops. Therefore, an automated approach is needed and after doing some research I came across tox.

tox describes itself as a “command line driven CI frontend and development task automation tool”, and one of the automated tasks it can do is run tests with different Python versions. However, I found that getting tox to work was not so straight forward and required some research. This post will cover what this research found and how to get tox to use pyenv and poetry to test a project against multiple versions of Python.

Installing tox

While tox will create a new environment for each version of Python that it tests, tox itself can be installed into the project’s virtual environment, as follows:

$ poetry shell
$ poetry add tox

To tell tox which versions of Python to test a configuration file is required at the root of the project called tox.ini:

envlist = py38,py39

Inside tox.ini is a section called tox with a property called envlist which lists the versions of Python to test, in this case 3.8 and 3.9.

Using poetry for the virtual environment

To get tox to use poetry to build the virtual environment the tox.ini file needs updating to the following:

isolated_build = True
envlist = py38,py39

whitelist_externals = poetry
commands =
  poetry install -v
  poetry run pytest tests/

First, isolated_build is set to True which tells tox to use a virtual environment when building the source distribution.

Second, a new section called testenv has been added with the properties whitelist_externals and commands. whitelist_externals prevents tox from raising a warning and, in this case, allows the use of poetry. commands lists the steps needed to run the tests. Here poetry installs the dependencies into the virtual environment and then runs the tests using pytest.

Configuring pyenv with multiple versions of Python

The final piece of the puzzle involves configuring the project with multiple versions of Python using pyenv so that tox can find the versions that it’s testing. In this case, Python 3.8 and 3.9 is being tested, therefore, they must be installed:

$ pyenv install 3.8.6
$ pyenv install 3.9.0

Next, the project should be set with these versions:

$ pyenv local 3.9.0 3.8.6

A new file called .python-version is created with the following content:


Running tox

With the instructions to run the tests and the different versions of Python set, tox can now be run:

$ tox

tox will then execute the tests for Python 3.8 and 3.9:

___________________________________ summary ____________________________________
  py38: commands succeeded
  py39: commands succeeded
  congratulations :)