Tooling a Python Project: Part 1, Basic Tooling

In this two part series, we’re gong to take a look at some of the most important tools to be aware of when starting a new Python project.  For this series we’ll assume you’re using Python 3 since the Python 2 EOL is coming up in 2020. Let’s dive in.

Poetry

In order to get started, you’ll want to install poetry.  Poetry is a relatively new package and dependency manager for Python that makes managing your virtual environment, dependencies, and other metadata much simpler.  Poetry can be installed via pip.

Running poetry init will prompt you with a set of configuration options for your package.  You should take the time to fill these out now (especially license and package name) with the correct values, although they can be changed later.  Poetry stores these values in pyproject.toml if you ever need to modify them.

After running poetry init, your project will be set up to use poetry.  Some important commands to be aware of in poetry:

  • poetry add/remove – Adds or removes a dependency by package name
  • poetry shell – Spawns a shell within the virtual environment managed by poetry, handy for running scripts
  • poetry install – Installs all dependencies from the lock file.  You’ll want to run this command if you’ve just cloned a poetry project

You can view the full list of commands by running poetry help

Virtual Environment Management

One main difference between Poetry and the “older” way of managing a python project’s dependencies is the apparent lack of a virtual environment.  In actuality, there is still a virtual environment, poetry is just managing all that under the hood.  You can configure the virtual environment path if you need more control.  If you ever need to nuke your environment and start over, you can find them at the path specified in the previous link (depending on your operating system).

Tests

Pytest is the go to choice for testing in Python.  To get started install Pytest as a dev dependency with Poetry

poetry add --dev pytest

Create a test directory (mkdir test) and then touch test/test_nothing.py

Editing <tt>test_nothing.py</tt> we add:

def test_nothing():
    assert 1 == 1

And in order to run our test suite we just need to run pytest which will automatically discover test files in the test directory (by default).  All functions beginning with test_ in any Python files within the test directory will be run.  You should see output like this:

platform linux -- Python 3.6.8, pytest-5.2.2, py-1.8.0, pluggy-0.13.0
rootdir: /home/adam/code/python-tooling
collected 1 item 
test/test_nothing.py .                                                                                                                     

For a more in depth look at pytest, check out the official documentation as well as the talks and tutorials.

Testing with Multiple Versions of Python

Occasionally we may need to run tests against multiple versions of the Python interpreter.  This is especially common if we’re building a library and we want to make sure that it’s not using any modern features that may not have existed in older versions of Python.

Tox is the tool to use to run against different Python versions.  Tox accepts a configuration file and runs your test case suite in each version of the interpreter that you target.  There’s even an integration guide for tox and pytest.

Linting

There are a lot of linters available for Python but personally I prefer flake8.  There are integrations available for a variety of editors and it has an easy command line interface to run from your CI environment.  It also covers a wide variety of potential violations. Install flake8 as a dev dependency in poetry:

poetry add --dev flake8

You can run flake8 over your entire module by running

flake8 path/to/code/

Which will show line numbers and error codes of violations.  Over time, you’ll likely find a number of violations that you simply don’t care to fix.  These can include whitespace errors, import order issues, or other minor stylistic things which you may prefer that flake8 marks as violations.  In order to ignore these minor issues, you can use the --ignore argument such as:

flake8 --ignore E24,W504 path/to/code/

Wrapping Up

After setting up poetry, pytest, and flake8, you have the basic tools that any successful python project needs.  In the next post, we’ll take a look at some optional tools that can add a bit more structure to your project.  Stay tuned!