Python Project Makefile with Virtual Environment
Build a Makefile for Python projects managing virtual environments, pip dependencies, testing with pytest, linting with flake8/mypy, and packaging.
Detailed Explanation
Python Development with Make
Python projects benefit enormously from Makefiles. Virtual environment creation, dependency installation, linting, testing, and packaging all become single commands.
Virtual Environment Management
PYTHON ?= python3
VENV = .venv
BIN = $(VENV)/bin
$(VENV)/bin/activate: requirements.txt
$(PYTHON) -m venv $(VENV)
$(BIN)/pip install --upgrade pip
$(BIN)/pip install -r requirements.txt
@touch $(VENV)/bin/activate
venv: $(VENV)/bin/activate
This target tracks requirements.txt as a dependency. The virtual environment is only recreated when requirements change. The @touch ensures the activation script's modification time is updated for accurate dependency checking.
Testing and Linting
test: venv
$(BIN)/python -m pytest tests/ -v --cov=src --cov-report=html
lint: venv
$(BIN)/python -m flake8 src/ tests/
$(BIN)/python -m mypy src/
$(BIN)/python -m black --check src/ tests/
format: venv
$(BIN)/python -m black src/ tests/
$(BIN)/python -m isort src/ tests/
All tools run from the virtual environment, ensuring consistent versions. The lint target chains multiple checks — if any fails, the subsequent ones do not run.
Packaging
dist: venv
$(BIN)/python -m build
publish: dist
$(BIN)/python -m twine upload dist/*
Build a wheel and source distribution, then upload to PyPI. The publish target depends on dist, ensuring the package is built first.
Development Workflow
run: venv
$(BIN)/python src/main.py
shell: venv
$(BIN)/ipython
clean:
rm -rf $(VENV) dist build *.egg-info .pytest_cache .mypy_cache htmlcov
find . -name '*.pyc' -delete
find . -name '__pycache__' -type d -exec rm -rf {} +
The clean target removes the virtual environment, build artifacts, and all compiled Python files (.pyc).
Best Practices
- Always use
$(BIN)/pythoninstead of activating the venv, so Make commands work without sourcing activate - Pin exact dependency versions in
requirements.txtfor reproducibility - Separate development dependencies into
requirements-dev.txt
Use Case
Managing a Python library or application where you need reproducible virtual environment setup, automated testing with coverage, type checking with mypy, and one-command packaging for PyPI.