Posted on :: 346 Words :: Tags: , ,

Makefiles are a great way to automate tasks in a project. They are a simple way to define a set of rules to build, test, and deploy a project. In this post, we will see how to use Makefiles in a Python project.

What is a Makefile?

Makefile is a special file containing a set of directives used to build software. It's essentially a script that helps automate common development tasks through a consistent interface.

  • Task Automation: Define repeatable commands as simple targets
  • Dependencies: Specify relationships between tasks
  • Incremental Builds: Only rebuild what's necessary based on file changes
  • Cross-platform: Works on Unix-like systems and Windows (with tools like WSL)

Basic Makefile Syntax

target: dependencies
    commands
  • target: The name of the task
  • dependencies: Other targets that must run first
  • commands: The actual commands to execute (must be indented with tabs)

Python Makefile

Below is a comprehensive Makefile for a modern Python project using uv for dependency management.

PROJECT_NAME := "myproject"

# Show help by default
.DEFAULT_GOAL := help

# Help target that reads from comments
help:
	@grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | sort | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-30s\033[0m %s\n", $$1, $$2}'

all: setup lint typing test ## Run all essential checks

setup: ## Install dependencies and set up pre-commit
	uv sync
	uv run pre-commit install

lint: ## Run code linting with ruff
	ruff check

format: ## Format code with ruff
	ruff format

typing: ## Run static type checking
	python -m mypy . --ignore-missing-imports --exclude ".*venv.*/"

test: ## Run unit tests with pytest
	uv run pytest tests/ -v --cov=$(PROJECT_NAME) --cov-report=term-missing

run: ## Run the project
	uv run python -m $(PROJECT_NAME)

clean: ## Remove build artifacts and cache files
	rm -rf build/ dist/ *.egg-info .coverage .mypy_cache .pytest_cache .ruff_cache

build-container: ## Build container image
	podman build -t $(PROJECT_NAME):test .

run-container: build-container ## Run container image
	podman run --rm $(PROJECT_NAME):test

pre-commit: ## Run pre-commit on staged files
	uv run pre-commit run

pre-commit-all: ## Run pre-commit on all files
	uv run pre-commit run --all-files