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
22 changes: 22 additions & 0 deletions .editorconfig
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
root = true

[*]
charset = utf-8
end_of_line = lf
insert_final_newline = true
trim_trailing_whitespace = true
indent_style = space
indent_size = 4

[*.py]
indent_size = 4
max_line_length = 120

[*.{yml,yaml,json,toml}]
indent_size = 2

[*.md]
trim_trailing_whitespace = false

[Makefile]
indent_style = tab
30 changes: 30 additions & 0 deletions .github/ISSUE_TEMPLATE/bug_report.md
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
---
name: Bug report
about: Something isn't working as expected
labels: bug
---

## Problem

<!-- Describe what happened and what you expected. Keep it short. -->

## Steps to reproduce

1.
2.
3.

## Expected behavior

## Actual behavior

## Environment

- Python version:
- OS:

## Logs or error output

```
paste here
```
17 changes: 17 additions & 0 deletions .github/ISSUE_TEMPLATE/feature_request.md
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
---
name: Feature request
about: Suggest something new or an improvement
labels: enhancement
---

## Problem

<!-- Describe the gap or inconvenience. -->

## Proposal

<!-- Describe the change you want. -->

## Alternatives

<!-- List other approaches only if they matter. -->
18 changes: 18 additions & 0 deletions .github/PULL_REQUEST_TEMPLATE.md
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
## What this does

<!-- One or two sentences. Explain what changed and why. -->

## Changes

-

## Testing

- [ ] `ruff check .` passes
- [ ] `mypy src` passes
- [ ] `pytest tests --cov=src` passes
- [ ] Tested manually (describe what you checked)

## Notes

<!-- Add reviewer context here if needed. Remove this section if it is empty. -->
58 changes: 58 additions & 0 deletions .github/workflows/quality_tests.yml
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
name: Quality tests

on:
push:
branches: [main]
pull_request:

jobs:
code-style:
name: Code style
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v5

- uses: actions/setup-python@v5
with:
python-version: "3.14"

- name: Install Poetry
run: pipx install poetry

- name: Install dependencies
run: poetry install --no-interaction

- name: Run Ruff
run: poetry run ruff check .

- name: Run MyPy
run: poetry run mypy src

tests-and-coverage:
name: Tests and coverage
runs-on: ubuntu-latest
# Disable this job until the coverage gate is needed again.
if: ${{ false }}

steps:
- uses: actions/checkout@v5

- uses: actions/setup-python@v5
with:
python-version: "3.14"

- name: Install Poetry
run: pipx install poetry

- name: Install dependencies
run: poetry install --no-interaction

- name: Run tests and coverage
run: |
poetry run pytest tests \
--cov=src \
--cov-report=term-missing \
-q \
-ra \
--durations=10
32 changes: 32 additions & 0 deletions .github/workflows/release.yml
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
name: Release

on:
push:
branches:
- main

jobs:
release:
runs-on: ubuntu-latest
permissions:
contents: write
issues: write
pull-requests: write

env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

steps:
- uses: actions/checkout@v5
with:
fetch-depth: 0

- uses: actions/setup-node@v5
with:
node-version: "24"

- name: Release
uses: cycjimmy/semantic-release-action@v4
with:
extra_plugins: |
conventional-changelog-conventionalcommits@8
32 changes: 32 additions & 0 deletions .pre-commit-config.yaml
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
default_language_version:
python: python3.14

exclude: >
(?x)^(
.*\.pytest_cache/|
.*\.ruff_cache/|
.*\.venv/
)

repos:
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v5.0.0
hooks:
- id: check-added-large-files
- id: check-ast
- id: debug-statements

- repo: https://github.com/astral-sh/ruff-pre-commit
rev: v0.15.14
hooks:
- id: ruff-check
args: [--fix]
- id: ruff-format

- repo: local
hooks:
- id: mypy
name: mypy
entry: poetry run mypy src --no-incremental
language: system
pass_filenames: false
37 changes: 37 additions & 0 deletions .releaserc.json
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
{
"branches": ["main"],
"tagFormat": "v${version}",
"plugins": [
[
"@semantic-release/commit-analyzer",
{
"preset": "conventionalcommits",
"releaseRules": [
{ "type": "feat", "release": "minor" },
{ "type": "fix", "release": "patch" },
{ "breaking": true, "release": "major" },
{ "type": "refactor", "release": false },
{ "type": "docs", "release": false },
{ "type": "test", "release": false },
{ "type": "ci", "release": false }
]
}
],
[
"@semantic-release/release-notes-generator",
{
"preset": "conventionalcommits"
}
],
[
"@semantic-release/github",
{
"draft": true,
"name": " v${nextRelease.version}",
"successComment": false,
"labels": false,
"releasedLabels": false
}
]
]
}
31 changes: 31 additions & 0 deletions CONTRIBUTING.md
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
# Contributing

This repository is a template. The same workflow applies to projects started from it.

## Setup

```bash
poetry install
poetry run pre-commit install
```

## Before a pull request

```bash
poetry run ruff check .
poetry run mypy src
poetry run pytest tests --cov=src
```

These checks run in CI on every pull request.

## Style

- Keep business logic in `src/`, not in scripts.
- Add type hints to new code. `mypy` runs in strict mode.
- Add tests for new modules and non-trivial logic.

## Pull request

- Keep the change small and focused.
- Commit messages on `main` drive the release version. Use [conventional commits](https://www.conventionalcommits.org/): `fix:`, `feat:`, or `feat!:` for breaking changes. See [README.md](README.md#versioning).
99 changes: 97 additions & 2 deletions README.md
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,97 @@
# python-project-template
A clean starting point for small Python projects.
# python project template

A starting point for small Python projects.

It keeps the default setup in one place. It uses text files, predictable tooling, and the same checks in local development and CI.

<div align="center">
<img src="docs/images/img-template-header.png" width="500"/>
</div>

---

## What is included

- `src/` and `tests/` layout, ready for a package
- Poetry for dependency management
- Ruff for linting and formatting
- Mypy in strict mode
- Pytest with coverage
- Pre-commit hooks that run the same checks as CI
- GitHub Actions for code style and tests
- `.editorconfig` for consistent formatting across editors
- Issue and PR templates
- Semantic version releases from conventional commits

---

## Tooling

- Python 3.14, Poetry
- Ruff, Mypy, Pytest

---

## Use this template

1. Click **Use this template** on GitHub (or `git clone` and re-init).
2. Rename the package in `pyproject.toml` (`[tool.poetry] name` and `packages`).
3. Replace this README with one for your actual project.
4. Update `LICENSE` copyright year/name if needed.

## Quick start

```bash
poetry install
poetry run pre-commit install
```

### Virtual environment on macOS

Install Python 3.14 if it is not installed:

```bash
brew install python@3.14
```

Point Poetry at it and create the virtual environment:

```bash
poetry env use 3.14
poetry install
```

Activate it in your shell:

```bash
eval "$(poetry env activate)"
```

To deactivate:

```bash
deactivate
```

`poetry run <command>` works without activating the environment. Use activation only if you want `python` or `pytest` to resolve directly.

## Checks

```bash
poetry run ruff check .
poetry run mypy src
poetry run pytest tests --cov=src
```

These checks run in CI on every pull request. See [CONTRIBUTING.md](CONTRIBUTING.md).

## Versioning

Every push to `main` runs [semantic-release](https://github.com/semantic-release/semantic-release). It reads commit messages, decides the version bump, and creates a `vX.Y.Z` tag with a draft GitHub release.

| Commit prefix | Bump |
|---|---|
| `fix:` | patch |
| `feat:` | minor |
| `feat!:` / `BREAKING CHANGE:` in body | major |
| `docs:`, `test:`, `ci:`, `refactor:` | none |
Loading
Loading