Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .docker/python/Dockerfile
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
FROM python:3.13.5
FROM python:3.14.7
ARG PACKAGE="core"

COPY --from=ghcr.io/astral-sh/uv:latest /uv /bin/uv
COPY --from=ghcr.io/astral-sh/uv:0.12.13 /uv /bin/uv

WORKDIR /app

Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/code-quality.yml
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ jobs:

steps:
- name: Checkout
uses: actions/checkout@v4
uses: actions/checkout@v7

- name: Initialize CodeQL
uses: github/codeql-action/init@v3
Expand Down
10 changes: 5 additions & 5 deletions .github/workflows/python.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ on:
- "**"

env:
UV_VERSION: "0.6.5"
UV_VERSION: "0.12.13"

concurrency:
group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }}
Expand All @@ -19,19 +19,19 @@ jobs:
runs-on: ubuntu-24.04
steps:
- name: Checkout source code
uses: actions/checkout@v4
uses: actions/checkout@v7

- name: Set up python
id: setup-python
uses: actions/setup-python@v5
uses: actions/setup-python@v7
with:
python-version-file: ".python-version"

- name: Set up uv
run: curl -LsSf https://astral.sh/uv/${{ env.UV_VERSION }}/install.sh | sh

- name: Restore uv cache
uses: actions/cache@v4
uses: actions/cache@v6
with:
path: /tmp/.uv-cache
key: uv-${{ runner.os }}-${{ hashFiles('uv.lock') }}
Expand All @@ -43,7 +43,7 @@ jobs:
run: uv sync --all-extras --dev --frozen

- name: Set up pre-commit cache
uses: actions/cache@v4
uses: actions/cache@v6
with:
path: ~/.cache/pre-commit
key: pre-commit-${{ runner.os }}-${{ hashFiles('.pre-commit-config.yaml') }}
Expand Down
58 changes: 11 additions & 47 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,12 @@ ci:
skip: []

default_language_version:
python: python3.13
python: python3.14

repos:
# general checks (see here: https://pre-commit.com/hooks.html)
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v5.0.0
rev: v6.0.0
hooks:
- id: check-yaml
args: [--allow-multiple-documents]
Expand All @@ -17,60 +17,24 @@ repos:

# ruff - linting + formatting
- repo: https://github.com/astral-sh/ruff-pre-commit
rev: "v0.12.1"
rev: "v0.16.7"
hooks:
- id: ruff
name: ruff
- id: ruff-format
name: ruff-format

# mypy - lint-like type checking
- repo: https://github.com/pre-commit/mirrors-mypy
rev: v1.16.1
# ty - static type checking
- repo: https://github.com/astral-sh/ty-pre-commit
rev: v0.0.80
hooks:
- id: mypy
name: mypy
additional_dependencies:
[
types-PyYAML,
types-requests,
pydantic,
python-dotenv,
pyyaml-env-tag,
]

# docformatter - formats docstrings to follow PEP 257
- repo: https://github.com/pycqa/docformatter
# todo: replace when >v1.7.5 will be published
rev: 06907d0267368b49b9180eed423fae5697c1e909
hooks:
- id: docformatter
name: docformatter
args:
[
-r,
-i,
--pre-summary-newline,
--make-summary-multi-line,
--wrap-summaries,
"90",
--wrap-descriptions,
"90",
src,
]

# bandit - find common security issues
- repo: https://github.com/pycqa/bandit
rev: 1.8.5
hooks:
- id: bandit
name: bandit
args: ["-r", "src", "-x", "*/tests/*"]
pass_filenames: false
- id: ty
name: ty

# prettier - formatting JS, CSS, JSON, Markdown, ...
- repo: https://github.com/pre-commit/mirrors-prettier
rev: v3.1.0
# note: pre-commit/mirrors-prettier is archived; rbubley/mirrors-prettier is the maintained fork
- repo: https://github.com/rbubley/mirrors-prettier
rev: v3.9.6
hooks:
- id: prettier
exclude: ^uv.lock
2 changes: 1 addition & 1 deletion .python-version
Original file line number Diff line number Diff line change
@@ -1 +1 @@
3.13.5
3.14.7
90 changes: 90 additions & 0 deletions Justfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
IMAGE := "my-python-application:latest"
DOCKERFILE := ".docker/python/Dockerfile"

# Show all available recipes
default:
@just --list

# Install all dependencies from the lockfile
sync:
uv sync

# Install dependencies and register the pre-commit hooks
install: sync
uv run pre-commit install

# Run the CLI, e.g. `just run user list`
run *ARGS:
uv run core {{ ARGS }}

# Run the test suite, e.g. `just test -k users`
test *ARGS:
uv run pytest {{ ARGS }}

# Run the test suite with a coverage report
test-cov:
uv run pytest --cov=src

# Lint with ruff
lint:
uv run ruff check .

# Lint with ruff and apply the safe fixes
lint-fix:
uv run ruff check . --fix

# Format with ruff
fmt:
uv run ruff format .

# Report formatting problems without rewriting files
fmt-check:
uv run ruff format . --check

# Static type analysis with ty
typecheck:
uv run ty check

# Security scan only (bandit rules, already part of `just lint`)
security:
uv run ruff check . --select S

# Run every pre-commit hook against all files
hooks:
uv run pre-commit run --all-files

# Full read-only quality gate: lint (incl. security), formatting, types, tests
check: lint fmt-check typecheck test

# Reformat and autofix, then run the full quality gate
fix: fmt lint-fix check

# Build the Docker image
docker-build:
docker buildx build -f {{ DOCKERFILE }} -t {{ IMAGE }} .

# Run the CLI inside the Docker image, e.g. `just docker-run user list`
docker-run *ARGS:
docker run -it --rm {{ IMAGE }} core {{ ARGS }}

# Refresh the lockfile without changing pinned versions
lock:
uv lock

# Upgrade every dependency to the newest version the constraints allow
upgrade:
uv lock --upgrade
uv sync

# List dependencies that have a newer release available
outdated:
uv tree --outdated --depth 1

# Bump the pre-commit hooks to their latest revisions
hooks-update:
uv run pre-commit autoupdate

# Delete caches, build artifacts and coverage data
clean:
rm -rf .cache .ruff_cache .mypy_cache .coverage htmlcov dist build
find . -path ./.venv -prune -o -type d -name __pycache__ -exec rm -rf {} +
51 changes: 47 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
[![CodeQL](https://github.com/MrHDOLEK/python-boilerplate/actions/workflows/code-quality.yml/badge.svg?branch=main)](https://github.com/MrHDOLEK/python-boilerplate/actions/workflows/code-quality.yml)
[![GitHub CI](https://github.com/MrHDOLEK/python-boilerplate/actions/workflows/python.yml/badge.svg?branch=main)](https://github.com/MrHDOLEK/python-boilerplate/actions/workflows/python.yml)
[![GitHub license](https://img.shields.io/github/license/MrHDOLEK/python-boilerplate)](https://github.com/MrHDOLEK/python-boilerplate)
[![Python](https://img.shields.io/badge/python-3.13-blue.svg?logo=python&logoColor=white)](https://www.python.org/)
[![Python](https://img.shields.io/badge/python-3.14-blue.svg?logo=python&logoColor=white)](https://www.python.org/)

---

Expand Down Expand Up @@ -41,6 +41,38 @@ pre-commit install

## Tools & Features

### just

Command runner holding the shortcuts for every routine task. Recipes live in `Justfile`.

```bash
# Install just (pick one)
brew install just
uv tool install rust-just

# List every available recipe
just

# Run the CLI
just run user list

# Tests
just test
just test-cov

# Individual quality checks
just lint
just fmt
just typecheck
just security

# Full quality gate: lint, formatting, types, security, tests
just check

# Autofix formatting and lint, then run the gate
just fix
```

### uv

Fast Python package manager, written in Rust. Configuration in `pyproject.toml` and dependencies locked in `uv.lock`.
Expand All @@ -64,14 +96,26 @@ pre-commit run --all-files

### ruff

Fast Python linter and formatter. Rules defined in `pyproject.toml`.
Fast Python linter and formatter. Rules defined in `pyproject.toml`. The default rule set is
extended with `S` (flake8-bandit), so security scanning is part of an ordinary lint run.

```bash
# Format code
uv run ruff format .

# Check code
uv run ruff check .

# Security rules only
uv run ruff check . --select S
```

### ty

Fast static type checker from Astral. Configuration in `pyproject.toml` under `[tool.ty]`.

```bash
uv run ty check
```

### Testing
Expand Down Expand Up @@ -104,6 +148,5 @@ Learn more at these links:
- [uv](https://github.com/astral-sh/uv)
- [pre-commit](https://pre-commit.com/)
- [ruff](https://github.com/astral-sh/ruff)
- [mypy](http://mypy-lang.org/)
- [bandit](https://bandit.readthedocs.io/)
- [ty](https://docs.astral.sh/ty/)
- [pytest](https://docs.pytest.org/)
41 changes: 20 additions & 21 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,26 @@ description = "Example of monorepo setup using UV"
authors = [
{ name = "Aleksander Kowalski" }
]
requires-python = ">=3.13"
requires-python = ">=3.14"
readme = "README.md"
dependencies = [
"python-dotenv>=1.1.0",
"python-dotenv>=1.2.3",
"pyyaml-env-tag>=1.1",
]

[dependency-groups]
dev = [
"pytest>=9.1.1",
"pytest-cov>=7.1.0",
"ty>=0.0.80",
"ruff>=0.16.7",
"pre-commit>=4.6.2",
"types-PyYAML>=6.0.12.20260906",
"types-requests>=2.33.0.20260906",
"utils",
"core",
]

[tool.uv.sources]
utils = { workspace = true }
core = { workspace = true }
Expand All @@ -22,23 +35,13 @@ members = [
]

[tool.uv]
dev-dependencies = [
"pytest>=8.3.5",
"pytest-cov>=6.0.0",
"mypy>=1.15.0",
"bandit>=1.8.3",
"docformatter>=1.7.5",
"ruff>=0.9.10",
"pre-commit>=3.8.0",
"types-PyYAML>=6.0.12",
"types-requests>=2.32",
"utils",
"core",
]
package = false

[tool.ruff]
lint.extend-select = ["S"]
lint.ignore = ["E501"]
lint.per-file-ignores = { "**/tests/**" = ["S101"] }
format.docstring-code-format = true
extend-exclude = [
"__pycache__",
".eggs",
Expand All @@ -51,12 +54,8 @@ extend-exclude = [
]
line-length = 100

[tool.pyright]
exclude = [".venv", ".github", "docs", "tests"]
include = ["src"]
pythonVersion = "3.13"
venvPath = "."
venv = ".venv"
[tool.ty.environment]
python-version = "3.14"

[tool.pytest.ini_options]
cache_dir = "./.cache/pytest"
Expand Down
Loading
Loading