Managing your Python project with a Makefile

(, en)

setuptools/requirements.txt-based projects

Python projects are nowadays quite straight-forward. If you use VSCode or PyCharm, the complete setup and handling of the project is taken care of. Still, I tend to keep a Makefile around, because

  1. I grew up using the terminal and somehow cannot let go
  2. Sooner or later you want to integrate parts of your deployment into a CI/CD pipeline

Now, for point 2 you could argue: isn’t it sufficient if I just dump the respective steps as YAML in the CI/CD pipeline config? I would argue: NO! Having a lot of code in the pipeline config makes it

This approach leads to:

  1. lean CI/CD pipeline config
  2. fat Makefiles, helper scripts and Dockerfiles

Here is my default template. It contains steps that I found useful over the years.

The idea is to copy this template and trim it down to your use-case

.PHONY: test help fmt install-editable lint git-setup

# same as `export PYTHONPATH="$PWD:$PYTHONPATH"`
# see also https://stackoverflow.com/a/18137056
mkfile_path := $(dir $(abspath $(lastword $(MAKEFILE_LIST))))
PYTHONPATH:=$(mkfile_path)..:$(PYTHONPATH)
export PYTHONPATH

VENV?=.venv
PIP=$(VENV)/bin/pip
PY=$(VENV)/bin/python

help: ## list targets with short description
	@awk 'BEGIN {FS = ":.*?## "} /^[a-zA-Z0-9._-]+:.*?## / {printf "\033[1m\033[36m%-38s\033[0m %s\n", $$1, $$2}' $(MAKEFILE_LIST)

test: ## run pytest
  . $(VENV)/bin/activate && pytest -rA -vvs --log-level INFO

lint: ## run flake8 to check the code
  . $(VENV)/bin/activate && flake8 src tests

install-editable:
  . $(VENV)/bin/activate && pip install -e .

fmt: ## run black to format the code
  . $(VENV)/bin/activate && black src tests

$(VENV)/init: ## init the virtual environment
	python3 -m venv $(VENV)
	touch $@

$(VENV)/requirements: requirements.txt $(VENV)/init ## install requirements
	$(PIP) install -r $<
	touch $@

You might want to

Poetry-based projects

Sometimes I use Poetry for my Python projects, in this case my Makefile looks a bit like this:

.PHONY: all clean test

# existing VIRTUAL_ENV might mess with poetry, so make sure it is gone
VIRTUAL_ENV=
unexport VIRTUAL_ENV

help:
	@awk 'BEGIN {FS = ":.*?## "} /^[a-zA-Z0-9._-]+:.*?## / {printf "\033[1m\033[36m%-38s\033[0m %s\n", $$1, $$2}' $(MAKEFILE_LIST)

test: ## run pytest
	poetry run pytest -rA -vvs --log-level INFO

install: ## install dependencies and the package to poetry venv
	poetry install

lint: ## run mypy and flake8 to check the code
	poetry run mypy src
	poetry run flake8 src tests

fmt: ## run black to format the code
	poetry run black src tests

See also