Last active
October 4, 2026 14:33
-
-
Save Shuyib/ae87774fd82c69706803725db9a681dc to your computer and use it in GitHub Desktop.
Data science and Machine learning Makefile for Python projects or in general :)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| # Thank you @Earthly https://www.youtube.com/watch?v=w2UeLF7EEwk | |
| # Can be adapted to pipenv, and poetry | |
| # Other languages coming soon especially R and Julia | |
| # .ONESHELL tells make to run each recipe line in a single shell | |
| .ONESHELL: | |
| .DEFAULT_GOAL := help | |
| # --- Configuration --- | |
| PYTHON := .venv/bin/python3 | |
| PIP := .venv/bin/pip3 | |
| DOCKER_IMAGE_NAME := test_app | |
| DOCKER_IMAGE_VERSION := v0.0.0 | |
| DOCKER_IMAGE_TAG := $(DOCKER_IMAGE_NAME):$(DOCKER_IMAGE_VERSION) | |
| REGISTRY_URL := registry.digitalocean.com/my-registry | |
| # ============================================================================== | |
| # 1. PACKAGE MANAGER DETECTION & ROUTING | |
| # ============================================================================== | |
| # Priority: uv > pipenv > poetry > standard venv/pip | |
| DETECT_UV := $(shell command -v uv 2> /dev/null) | |
| DETECT_PIPENV := $(shell command -v pipenv 2> /dev/null) | |
| DETECT_POETRY := $(shell command -v poetry 2> /dev/null) | |
| ifeq ($(DETECT_UV),) | |
| HAS_UV := 0 | |
| else | |
| HAS_UV := 1 | |
| endif | |
| ifeq ($(DETECT_PIPENV),) | |
| HAS_PIPENV := 0 | |
| else | |
| HAS_PIPENV := 1 | |
| endif | |
| ifeq ($(DETECT_POETRY),) | |
| HAS_POETRY := 0 | |
| else | |
| HAS_POETRY := 1 | |
| endif | |
| # Route commands based on availability | |
| ifeq ($(HAS_UV),1) | |
| PACKAGE_MANAGER := uv | |
| INSTALL_CMD := uv pip install -e . -r requirements.txt | |
| RUN_CMD := uv run | |
| LINT_CMD := uv run ruff check . | |
| else ifeq ($(HAS_PIPENV),1) | |
| PACKAGE_MANAGER := pipenv | |
| INSTALL_CMD := pipenv install --dev | |
| RUN_CMD := pipenv run | |
| LINT_CMD := pipenv run ruff check . | |
| else ifeq ($(HAS_POETRY),1) | |
| PACKAGE_MANAGER := poetry | |
| INSTALL_CMD := poetry install | |
| RUN_CMD := poetry run | |
| LINT_CMD := poetry run ruff check . | |
| else | |
| PACKAGE_MANAGER := pip (standard venv) | |
| INSTALL_CMD := .venv/bin/pip install --upgrade pip && .venv/bin/pip install -r requirements.txt | |
| RUN_CMD := .venv/bin/python | |
| LINT_CMD := .venv/bin/python -m ruff check . | |
| endif | |
| # ============================================================================== | |
| # 2. ENVIRONMENT & SETUP | |
| # ============================================================================== | |
| .PHONY: detect install clean setup_readme | |
| detect: ## Detect and show the selected package manager | |
| @echo "🔍 Package manager selected: $(PACKAGE_MANAGER)" | |
| @echo " UV detected: $(HAS_UV)" | |
| @echo " Pipenv detected: $(HAS_PIPENV)" | |
| @echo " Poetry detected: $(HAS_POETRY)" | |
| install: ## Install project dependencies | |
| @echo "📦 Installing dependencies using $(PACKAGE_MANAGER)..." | |
| @if [ "$(PACKAGE_MANAGER)" = "pip (standard venv)" ] && [ ! -d ".venv" ]; then \ | |
| python3 -m venv .venv; \ | |
| fi | |
| $(INSTALL_CMD) | |
| @echo "✅ Installation complete." | |
| clean: ## Clean cache directories and virtual environments | |
| @echo "🧹 Cleaning project..." | |
| rm -rf __pycache__ utils/__pycache__ testing/__pycache__ | |
| rm -rf .pytest_cache .ruff_cache .venv | |
| @echo "✅ Clean complete." | |
| setup_readme: ## Create a boilerplate README.md if one doesn't exist | |
| @if [ ! -f README.md ]; then \ | |
| echo "# Project Name\n\nDescription of the project.\n\n## Installation\n\n## Usage\n\n## License" > README.md; \ | |
| echo "✅ README.md created."; \ | |
| else \ | |
| echo "⚠️ README.md already exists."; \ | |
| fi | |
| # ============================================================================== | |
| # 3. CODE QUALITY & TESTING | |
| # ============================================================================== | |
| .PHONY: format lint ruff-fix docstring test run | |
| format: ## Format Python code using black | |
| @echo "🎨 Formatting code..." | |
| $(RUN_CMD) black *.py utils/*.py testing/*.py || echo "⚠️ Black not found, skipping." | |
| lint: ## Lint code using Ruff and Pylint | |
| @echo "🔎 Linting code..." | |
| $(LINT_CMD) | |
| $(RUN_CMD) pylint --disable=R,C --errors-only *.py utils/*.py testing/*.py || echo "⚠️ Pylint not found, skipping." | |
| ruff-fix: ## Run Ruff with autofix enabled | |
| @echo "🔧 Fixing code with Ruff..." | |
| $(LINT_CMD) --fix | |
| docstring: ## Format docstrings using pyment (NumPy style) | |
| @echo "📝 Formatting docstrings..." | |
| $(RUN_CMD) pyment -w -o numpydoc *.py | |
| test: ## Run tests using pytest | |
| @echo "🧪 Running tests..." | |
| $(RUN_CMD) pytest testing/ | |
| run: ## Run the main application (Example: app.py) | |
| @echo "🚀 Running application..." | |
| $(RUN_CMD) app.py | |
| # ============================================================================== | |
| # 4. UX & SYSTEM AUDITS (PyConKE '26 Framework) | |
| # | |
| # ============================================================================== | |
| .PHONY: audit-ux check-certainty check-relief check-calm check-speed | |
| audit-ux: check-certainty check-relief check-calm check-speed ## Run Edmin M's 4-Quadrant UX Audit | |
| @echo "\n✅ UX Audit Complete. Engineering is hard, but the user feels nothing but magic." | |
| @echo "==============================================================================\n" | |
| check-certainty: | |
| @echo "\n[ Quadrant I - CERTAINTY ]" | |
| @echo " - Idempotency: If the pipeline retries, do we get duplicate rows or a clean MERGE?" | |
| @echo " - Consistency: If the user double-clicks 'Submit', does it mutate state twice?" | |
| check-relief: | |
| @echo "\n[ Quadrant II - RELIEF ]" | |
| @echo " - Degradation: If the primary LLM fails, does the UI crash or fallback smoothly?" | |
| @echo " - State Recovery: If validation fails, is the user's configuration preserved?" | |
| check-calm: | |
| @echo "\n[ Quadrant III - CALM ]" | |
| @echo " - Resource Cleanup: If the socket closes mid-query, do compute resources stop?" | |
| @echo " - GPU Cycles: Are cancellation tokens propagated to PyTorch inference queues?" | |
| check-speed: | |
| @echo "\n[ Quadrant IV - SPEED ]" | |
| @echo " - Payload Size: Are we sending raw geometries or optimized payloads?" | |
| @echo " - Edge Constraints: How quickly does the edge device return TTFT?" | |
| # ============================================================================== | |
| # 5. PEER REVIEW & XAI PROMPTS | |
| # ============================================================================== | |
| .PHONY: review-code review-ds review-logging review-xai | |
| review-code: ## Display general code review heuristics | |
| @echo "#### General Code Review ####" | |
| @echo "1. Architecture (SOLID, DRY, KISS)" | |
| @echo "2. Reliability (Failover, Thread Safety)" | |
| @echo "3. Performance (Algorithmic efficiency, Memory I/O, Caching)" | |
| review-ds: ## Display Data Science specific review heuristics | |
| @echo "#### Data Science Review ####" | |
| @echo "1. Pipeline: Schema validation, Leakage checks, Imputation strategy." | |
| @echo "2. Modeling: Hyperparameters, CV strategy, Explainability (SHAP/LIME)." | |
| @echo "3. Production: TTFT, Drift Monitoring, Canary deployment readiness." | |
| @echo "4. Tracking: MLflow/W&B logging, artifact versioning." | |
| review-logging: ## Display Logging/Observability heuristics | |
| @echo "#### Logging Review ####" | |
| @echo "1. Are we using structured (JSON) logging instead of raw print()?" | |
| @echo "2. Are log levels (DEBUG, INFO, ERROR) appropriate?" | |
| @echo "3. Is sensitive data masked?" | |
| @echo "4. Are distributed trace IDs propagated across service boundaries?" | |
| review-xai: ## Display Explainability and Interpretability (XAI) guide | |
| @echo "#### Explainability & Interpretability (XAI) Check ####" | |
| @echo "Ref: PyConKE 2026 - Brian M (Building ML Pipelines)" | |
| @echo "" | |
| @echo "1. Baseline / Intrinsic Interpretability:" | |
| @echo " - Btw, did you check intrinsic feature importance first?" | |
| @echo " - (e.g., Have you looked at Gini impurity in your Random Forest before reaching for complex tools?)" | |
| @echo "" | |
| @echo "2. SHAP (Global & Local Explainability):" | |
| @echo " - Btw, did you run Permutation or Kernel SHAP for your model?" | |
| @echo " - Did you visualize the outputs using a SHAP beeswarm plot? " | |
| @echo " (Crucial for seeing both the magnitude AND direction of feature impacts on the model)" | |
| @echo "" | |
| @echo "3. LIME (Local Surrogate Models):" | |
| @echo " - Btw, did you use LIME to sample and fit a local surrogate model?" | |
| @echo " - Did you look at how the model behaves at the specific decision boundary for edge-case predictions?" | |
| @echo "" | |
| @echo "4. Delivery & Audience Check:" | |
| @echo " - Btw, did you explicitly ask the stakeholders how technical they are before presenting this?" | |
| @echo " - (Don't present a beeswarm plot to an audience that just needs the Gini impurity summary!)" | |
| # ============================================================================== | |
| # 6. DOCKER OPERATIONS | |
| # ============================================================================== | |
| .PHONY: docker-build docker-test docker-clean docker-run docker-push docker-info | |
| docker-build: Dockerfile ## Build the Docker container | |
| @echo "🐳 Building image: $(DOCKER_IMAGE_TAG)" | |
| docker build --platform linux/amd64 -t $(DOCKER_IMAGE_TAG) . | |
| docker-test: Dockerfile ## Lint the Dockerfile using Hadolint | |
| @echo "🐳 Linting Dockerfile..." | |
| docker run --rm -i hadolint/hadolint < Dockerfile | |
| docker-clean: ## Remove dangling images, volumes, and networks | |
| @echo "🐳 Pruning Docker system..." | |
| docker system prune -a | |
| docker-run: docker-build ## Run the built Docker container | |
| @echo "🐳 Running container..." | |
| docker run --platform linux/amd64 -p 8080:8080 $(DOCKER_IMAGE_TAG) | |
| docker-push: docker-build ## Push image to the configured registry | |
| @echo "🐳 Pushing $(DOCKER_IMAGE_TAG) to $(REGISTRY_URL)..." | |
| docker tag $(DOCKER_IMAGE_TAG) $(REGISTRY_URL)/$(DOCKER_IMAGE_TAG) | |
| docker push $(REGISTRY_URL)/$(DOCKER_IMAGE_TAG) | |
| docker-info: ## Show Docker image size and build history | |
| @echo "🐳 Image size for $(DOCKER_IMAGE_TAG):" | |
| @docker image ls $(DOCKER_IMAGE_TAG) --format "table {{.Repository}}:{{.Tag}}\t{{.Size}}\t{{.CreatedSince}}" | |
| @echo "\n🐳 Layer history:" | |
| @docker history $(DOCKER_IMAGE_TAG) | |
| # ============================================================================== | |
| # 7. HELP (Self-Documenting) & ALL | |
| # ============================================================================== | |
| .PHONY: help all | |
| help: ## Show this help message | |
| @echo "Usage: make [target]\n" | |
| @echo "Available targets:" | |
| @awk 'BEGIN {FS = ":.*##"; printf "\033[1m%-20s\033[0m %s\n", "Target", "Description"} \ | |
| /^[a-zA-Z_-]+:.*?##/ { printf "\033[36m%-20s\033[0m %s\n", $$1, $$2 }' $(MAKEFILE_LIST) | |
| all: install format lint test run docker-build docker-run docker-push ## Run the full CI/CD pipeline (Install -> Test -> Run -> Dockerize) | |
| @echo "🚀 Full pipeline execution complete!" |
Author
Author
An attempt for java script
# Thank you @Earthly https://www.youtube.com/watch?v=w2UeLF7EEwk
# Can be adapted to pipenv, and poetry
# Other languages coming soon especially R and Julia
# .ONESHELL tells make to run each recipe line in a single shell
.ONESHELL:
# .DEFAULT_GOAL tells make which target to run when no target is specified
.DEFAULT_GOAL := all
# Specify node location in virtual environment
NODE := node
# Specify npm location in virtual environment
NPM := npm
# Specify Docker container name
DOCKER_CONTAINER_NAME := test_app:v0.0.0
venv/bin/activate: requirements.txt
# create virtual environment
npm install -g venv
# make command executable
chmod +x venv/bin/activate
# activate virtual environment
. venv/bin/activate
activate:
# activate virtual environment
. venv/bin/activate
install: venv/bin/activate requirements.txt # prerequisite
# install commands
npm ci
docstring: activate
# format docstring
javascriptdoc -w -o numpydoc *.js
format: activate
# format code
prettier --write *.js utils/*.js testing/*.js
clean:
# clean directory of cache
rm -rf __pycache__ &&\
rm -rf utils/__pycache__ &&\
rm -rf testing/__pycache__ &&\
rm -rf .pytest_cache &&\
rm -rf .venv
lint: activate install format
# eslint or #jshint
# see the errors with
npm run lint
# fix the errors with npm run lint:fix
setup_readme: ## Create a README.md
@if [ ! -f README.md ]; then \
echo "# Project Name\n\
Description of the project.\n\n\
## Installation\n\
- Step 1\n\
- Step 2\n\n\
## Usage\n\
Explain how to use the project here.\n\n\
## Contributing\n\
Explain how to contribute to the project.\n\n\
## License\n\
License information." > README.md; \
echo "README.md created."; \
else \
test: activate install format
# test
npm test
run: activate install format lint
# run application
# example node app.js
docker_build: Dockerfile
# build container
docker build -t plot-timeseries-app:v0 .
docker_run_test: Dockerfile
# linting Dockerfile
docker run --rm -i hadolint/hadolint < Dockerfile
docker_clean: Dockerfile
# remove dangling images, containers, volumes and networks
docker system prune -a
docker_run: Dockerfile docker_build
# run docker
# docker run -e ENDPOINT_URL -e SECRET_KEY -e SPACES_ID -e SPACES_NAME plot-timeseries-app:v0
docker_push: docker_build
# push to registry
# docker tag <my-image> registry.digitalocean.com/<my-registry>/<my-image>
# docker push registry.digitalocean.com/<my-registry>/<my-image>
# .PHONY tells make that these targets do not represent actual files
.PHONY: activate format clean lint test build run docker_build docker_run docker_push docker_clean docker_run_test
all: install format lint test run docker_build docker_run docker_push
Author
For rust
# Makefile for a Rust project
.PHONY: help build build_release run run_release test lint fmt doc clean check_all docker_build docker_run docker_lint
# Default target to show help
.DEFAULT_GOAL := help
TARGET_NAME := $(shell basename $(CURDIR)) # Assumes project name is current directory name
TARGET_PATH_DEBUG := target/debug/$(TARGET_NAME)
TARGET_PATH_RELEASE := target/release/$(TARGET_NAME)
help: ## Show this help message
@echo "Available targets for Rust project:"
@grep -E '^[a-zA-Z0-9_-]+:.*?## .*$$' $(MAKEFILE_LIST) | sort | awk 'BEGIN {FS = ":.*?## "}; {printf "\\033[36m%-20s\\033[0m %s\\n", $$1, $$2}'
build: ## Build the Rust project (debug mode)
@echo "Building $(TARGET_NAME) (debug)..."
cargo build
build_release: ## Build the Rust project (release mode)
@echo "Building $(TARGET_NAME) (release)..."
cargo build --release
run: build ## Run the debug build of the project
@echo "Running $(TARGET_NAME) (debug)..."
cargo run
run_release: build_release ## Run the release build of the project
@echo "Running $(TARGET_NAME) (release)..."
cargo run --release
# Or directly: $(TARGET_PATH_RELEASE)
test: ## Run tests
@echo "Running tests..."
cargo test
lint: ## Lint code using clippy (errors on warnings)
@echo "Linting with clippy..."
cargo clippy --all-targets --all-features -- -D warnings
fmt: ## Format code using rustfmt
@echo "Formatting with rustfmt..."
cargo fmt --all
doc: ## Generate and open documentation
@echo "Generating documentation..."
cargo doc --open
clean: ## Clean build artifacts
@echo "Cleaning build artifacts..."
cargo clean
check_all: fmt lint test ## Run all checks (format, lint, test)
@echo "All checks passed."
# --- Docker Targets (Optional) ---
DOCKER_IMAGE_NAME ?= $(TARGET_NAME)-app
DOCKER_IMAGE_TAG ?= latest
DOCKERFILE ?= Dockerfile
docker_build: ## Build the Docker image
ifeq (,$(wildcard $(DOCKERFILE)))
@echo "Dockerfile not found. Skipping docker_build."
else
@echo "Building Docker image $(DOCKER_IMAGE_NAME):$(DOCKER_IMAGE_TAG)..."
docker build -t $(DOCKER_IMAGE_NAME):$(DOCKER_IMAGE_TAG) -f $(DOCKERFILE) .
endif
docker_run: ## Run the app in a Docker container (requires docker_build)
ifeq (,$(wildcard $(DOCKERFILE)))
@echo "Dockerfile not found. Skipping docker_run."
else
@echo "Running Docker container $(DOCKER_IMAGE_NAME):$(DOCKER_IMAGE_TAG)..."
docker run --rm -it $(DOCKER_IMAGE_NAME):$(DOCKER_IMAGE_TAG)
endif
docker_lint: ## Lint the Dockerfile using hadolint
ifeq (,$(wildcard $(DOCKERFILE)))
@echo "Dockerfile not found. Skipping docker_lint."
else
@echo "Linting $(DOCKERFILE) with hadolint..."
docker run --rm -i hadolint/hadolint < $(DOCKERFILE)
endif
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Template for Julia needs edits