Skip to content

Instantly share code, notes, and snippets.

@Shuyib
Last active October 4, 2026 14:33
Show Gist options
  • Select an option

  • Save Shuyib/ae87774fd82c69706803725db9a681dc to your computer and use it in GitHub Desktop.

Select an option

Save Shuyib/ae87774fd82c69706803725db9a681dc to your computer and use it in GitHub Desktop.
Data science and Machine learning Makefile for Python projects or in general :)
# 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!"
@Shuyib

Shuyib commented Apr 26, 2023 •

Copy link
Copy Markdown
Author

Template for Julia needs edits

# 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 julia version virtual environment
venv/bin/activate: 
	# create virtual environment
	julia -e 'using Pkg; Pkg.add("VirtualEnvironments"); using VirtualEnvironments; VirtualEnvironments.build()'
  
activate:
	# activate virtual environment
	julia -e 'using Pkg; Pkg.activate("."); Pkg.instantiate()'

install: venv/bin/activate  # prerequisite
	# install common packages
	julia -e 'using Pkg; Pkg.add("PyCall"); Pkg.add("PyPlot"); Pkg.add("Statistics")
    
docstring: activate
	# format docstrings
	julia -e 'using Pkg; Pkg.add("Documenter"); using Documenter; Documenter.generate("docs")'
  
format: activate 
	# format code
	julia -e 'using Pkg; Pkg.add("JuliaFormatter"); using JuliaFormatter; format("src")'
  
clean:
	# clean directory of cache files
	julia -e 'using Pkg; Pkg.gc()'

lint: activate install format
	# lint code
	julia -e 'using Pkg; Pkg.add("Lint"); using Lint; lint("src")'
  
test: activate install format
	# test code
	julia -e 'using Pkg; Pkg.add("Test"); using Test; include("test/runtests.jl")'
  
run: activate install format
	# run julia script
	julia src/main.jl
  
docker_build: Dockerfile
	# build julia container
	#docker build -t plot-timeseries-app:v0 .
  
docker_run_test: Dockerfile
	# linting Dockerfile
	docker run --rm -i hadolint/hadolint < Dockerfile

docker_clean: Dockerfile docker_build
	# remove dangling images, containers, volumes and networks
	docker system prune -a
  
docker_run: 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

@Shuyib

Shuyib commented Jul 24, 2024 •

Copy link
Copy Markdown
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

@Shuyib

Shuyib commented May 17, 2025

Copy link
Copy Markdown
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