Skip to content

CRESYM/python-boilerplate

Repository files navigation

python-boilerplate

This boilerplate repository can be used to kickstart Python projects and demonstrates modern tools and practices for building reliable, maintainable, and high‑quality code.

UV

We use UV as the Python package and environment manager.

What it is

uv is a fast replacement for pip/virtualenv/poetry that:

  • Manages dependencies
  • Creates virtual environments
  • Reproducibly installs packages via a lockfile

It ensure consistent environments across machines. Use uv.lock to reproduce the exact same setup anywhere.

Why we use it

  • Fast dependency resolution
  • Reproducible environments (uv sync)
  • Works well in CI pipelines

Basic usage

# install Python
uv python install 3.11

# install dependencies
uv sync --dev

# add dependencies
uv add pandas

# run commands inside the environment
uv run pytest
uv run ruff check .

More details available on the UV website: https://docs.astral.sh/uv/

Formatting, Linting, Type hints

To ensure code quality, we enforce automated checks that validate style, detect bugs early, and improve maintainability.


Tools used

  • Ruff → linting + formatting
  • Mypy → static type checking

Formatting (Ruff formatter)

What it is

Formatting ensures your code follows a consistent style automatically, without manual effort.

Example:

# before
def add(a,b):return a+b

# after
def add(a, b):
    return a + b

Why it matters

  • No debates about code style
  • Cleaner diffs in pull requests
  • Easier collaboration

Commands

# format code
uv run ruff format .

# check formatting without modifying files
uv run ruff format --check .

Linting (Ruff)

What is linting?

Linting analyzes your code for:

  • Bugs
  • Bad practices
  • Style issues

It does static analysis without running the code.

Examples of issues detected

import math  # ❌ unused import

def compute(x):
    if x == None:  # ❌ bad practice
        return 0
    return x

Ruff will flag:

  • Unused imports
  • Incorrect comparisons (== None instead of is None)
  • Undefined variables
  • Complexity issues

Why it matters

  • Prevents common bugs early
  • Enforces best practices
  • Keeps the codebase clean

Commands

# check for issues
uv run ruff check .

# automatically fix issues when possible
uv run ruff check . --fix

Type hinting (Mypy)

What are type hints?

Type hints explicitly define the expected types of variables, inputs, and outputs in your code.

Example:

def add(a: int, b: int) -> int:
    return a + b

This means:

  • a and b must be integers
  • the function returns an integer

What is static type checking?

Mypy checks that your code respects these type definitions without running it.

Example:

def add(a: int, b: int) -> int:
    return a + b

add(1, "hello")  # ❌ error detected by mypy

Mypy will raise an error because "hello" is not an int.

Why type hinting matters

  • Catches bugs before runtime
  • Acts as documentation
  • Improves IDE autocompletion
  • Makes large codebases easier to understand

Commands

# run type checking
uv run mypy .

How they work together

Tool Purpose When it helps
Ruff (lint) Detect bugs & bad patterns Before running code
Ruff (fmt) Enforce style Always
Mypy Validate types During development

Summary:

  • Formatting → makes code consistent automatically
  • Linting → detects bugs and bad practices early
  • Type hints → make code safer and self-documented

Documentation

We use MkDocs for documentation.

What it does

  • Generates a static documentation website
  • Automatically deployed via CI/CD

How it works

The comments left under commands using docstrings is used to create a documentation website. As such, functions should be described using the following format:

def calculate_average(values: list[float]) -> float:
    """
    *function explanation and description*

    Args:
        values: A non-empty list of floating-point numbers.

    Returns:
        The arithmetic mean of the input values.

    Raises:
        ValueError: If the input list is empty.

    Examples:
        >>> calculate_average([1.0, 2.0, 3.0])
        2.0
    """
    if not values:
        raise ValueError("values must not be empty")

    return sum(values) / len(values)

Deployment

Docs are deployed to GitHub Pages after merge to main.

- name: Deploy docs to GitHub Pages
  run: uv run mkdocs gh-deploy --force

Why it matters

Documentation:

  • Improves onboarding
  • Serves as living reference
  • Acts as implicit specification of behavior

Testing

We use pytest for automated testing.

Types of tests

  • Unit tests → small isolated functions
  • Integration tests → components working together
  • End-to-end tests → full system validation

Why testing matters

  • Prevents regressions
  • Ensures correctness
  • Improves confidence in code changes

Run tests

uv run pytest

Test coverage

To check whether your code is well tested, you can check how well your code is "covered" by tests.

Get coverage summary

Running uv run pytest --cov . will run the test coverage program. It will tell you if your code is well covered

➜  python-boilerplate git:(main) uv run pytest --cov .
================================================================= test session starts =================================================================
platform darwin -- Python 3.14.4, pytest-9.0.2, pluggy-1.6.0
rootdir: /Users/pcayetan/dev/python-boilerplate
configfile: pyproject.toml
testpaths: tests
plugins: cov-7.1.0
collected 1 item                                                                                                                                      

tests/test_main.py .                                                                                                                            [100%]

=================================================================== tests coverage ====================================================================
__________________________________________________ coverage: platform darwin, python 3.14.4-final-0 ___________________________________________________

Name                             Stmts   Miss  Cover   Missing
--------------------------------------------------------------
python_boilerplate/__init__.py       2      0   100%
python_boilerplate/main.py           6      3    50%   35-38
tests/test_main.py                   3      0   100%
--------------------------------------------------------------
TOTAL                               11      3    73%
Required test coverage of 50% reached. Total coverage: 72.73%
================================================================== 1 passed in 0.17s ==================================================================

Detailed HTML report

This report in HTML format details which specific functions or lines are not covered. To create it and open it in your web browser, run the following command:

uv run coverage html && open htmlcov/index.html

Pre-commit hook integration

Pre-commit automatically runs checks before code is committed.

What it enforces

  • Linting (Ruff)
  • Formatting
  • Type checking (Mypy)
  • Tests (pytest)

Why it matters

  • Prevents low-quality code from entering the repository
  • Reduces manual errors
  • Automates quality checks early

Usage

pre-commit install
pre-commit run --all-files

Config

The pre-commit hooks and the scripts run in that hook are configured in the .pre-commit-config.yaml file.

GitHub actions (CI/CD)

We use GitHub Actions to implement Continuous Integration and Delivery.

What is CI/CD?

  • CI (Continuous Integration)
    Every change:

    • is automatically tested
    • validated through quality checks
    • ensures it does not break the codebase
  • CD (Continuous Deployment/Delivery)
    After passing CI:

    • code is packaged
    • deployed automatically
    • releases become predictable and repeatable

Quality Gates

The CI job runs on every push and pull request:

- Lint → ruff check
- Format → ruff format --check
- Type check → mypy
- Tests → pytest

Purpose

These are quality gates:

  • Code must pass all checks before merging
  • Keeps the main branch always healthy

Automation

The docs-deploy job:

  • Runs only on main branch
  • Builds and deploys documentation
if: github.ref == 'refs/heads/main'

Benefits

  • No manual deployment
  • Always up-to-date documentation
  • Reliable release process

Git workflow & quality gates

Simple branching strategy

  • Create branches for:
    • Features (feature/...)
    • Fixes (fix/...)
  • Open a Pull Request
  • Run CI before merging

Typical workflow

  1. Create a branch
git checkout -b feature/my-feature
  1. Develop code

  2. Pre-commit runs locally (fast feedback)

  3. Push branch → open Pull Request

  4. CI runs automatically:

    • Lint ✅
    • Format ✅
    • Types ✅
    • Tests ✅
  5. Code review

  6. Merge into main

Why this improves quality

  • Automation → reduces manual errors
  • Collaboration → enforced code reviews
  • Continuous validation → prevents regressions
  • Quality gates → only clean code reaches main

Summary

This boilerplate demonstrates a modern Python workflow:

  • uv → dependency management
  • Ruff + Mypy → code quality
  • pytest → testing
  • pre-commit → local quality enforcement
  • GitHub Actions → CI/CD automation

Together, they implement DevOps best practices:

  • Faster development cycles
  • Higher code quality
  • Reliable and repeatable deployments

About

This boilerplate repository can be used to kickstart projects

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages