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
- I grew up using the terminal and somehow cannot let go
- 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
- difficult to migrate the code if you ever want to switch to a different platform
- easy to debug each step
- possible to kick off Makefile targets from other scripts or systems
This approach leads to:
- lean CI/CD pipeline config
- 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
- trim away the section connected to
PYTHONPATH
. I rarely use it. Usually I apply it to projects that already modify thePYTHONPATH
variable. - install requirements via
setup.py
(see also install_requires vs requirements files and pip-tools, which can derive arequirements.txt
file from setup.py)
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