Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
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
3 changes: 3 additions & 0 deletions .cliffignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# Skip commits by their SHA1

e8759bdeb573cd9304d1fb6e0501906ea9cb865a
7 changes: 5 additions & 2 deletions .example-input.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,13 @@ author_email: hasansezertasan@gmail.com
short_description: A Python project example.
include_cli: false
include_web: false
web_framework: fastapi
include_tui: false
include_gui: false
include_mcp: false
include_c_extensions: false
include_profiling: false
include_pycrucible: false
include_pydantic_settings: false
release_automation: none
dependency_management: none
Expand All @@ -20,6 +24,5 @@ include_pants: false
include_codecov: false
include_mise: false
include_trunk: false
include_poe: false
include_commitizen: false
use_precommit: false
include_precommit: false
5 changes: 3 additions & 2 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,9 @@
# Pre-commit: uv run --locked tox run -e pre-commit
# Build: uv build
# Run CLI: uv run --locked <repo-name> version
# Run FastAPI: uv run --locked fastapi dev <repo-name>.web:app
# Run FastAPI: uv run --locked fastapi dev <repo-name>.web.app:app
# Serve docs: uv run --only-group docs mkdocs serve
# Profile: uv run --locked tox run -e profile (if profiling enabled)
# Trunk check: trunk check (if configured)
# Pants lint: pants lint :: (if configured)
```
Expand All @@ -27,4 +28,4 @@
- **Structure**: Code in `src/{{github_repo_name}}/`, tests in `tests/`
- **Tools**: Ruff (full rules, complexity ≤5), MyPy/Pyright strict, pytest + coverage, pre-commit
- **Template**: `.jinja` files, `{{variables}}`, `{% raw %}` for Jinja escaping
- **Optional Tools**: Poe (poethepoet) for task running, configurable via `include_poe`; Commitizen for version management, configurable via `include_commitizen`
- **Optional Tools**: mise for task running (configurable via `include_mise`); Commitizen for version management (configurable via `include_commitizen`)
170 changes: 110 additions & 60 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ This file provides guidance to Claude Code (claude.ai/code) when working with co
This is a **Copier template** for generating modern Python packages with comprehensive tooling. The `template/` directory contains Jinja2-templated files that are rendered when users run `copier copy` to scaffold new Python projects.

Key architecture:

- Template files use `.jinja` extension and contain variables like `{{github_repo_name}}`, `{{author_full_name}}`, etc.
- Template variables are defined in `copier.yml`
- The `example/` directory shows a rendered example using `.example-input.yml` as answers
Expand All @@ -25,14 +26,16 @@ copier copy --data-file .example-input.yml --defaults . /tmp/test-project

# Actually generate the example project
copier copy --data-file .example-input.yml --defaults . example/

# Force regenerate (overwrites existing)
copier copy --data-file .example-input.yml --defaults . example/ --force
```

### Working with Generated Projects

Commands that would run in a generated project (useful for testing):
Commands for the `example/` directory (or any generated project):

```bash
# Navigate to example directory
cd example/

# Install dependencies
Expand All @@ -48,12 +51,21 @@ uv run --locked tox run -e style
uv run --locked tox run -e 3.10
uv run --locked tox run -e 3.14

# Run the CLI
uv run --locked <repo-name> version
uv run --locked <repo-name> info
# Run a single test file
uv run --locked pytest tests/test_smoke.py -v

# Run the CLI (if include_cli=true)
uv run --locked example version
uv run --locked example info

# Run the FastAPI web app (if include_web=true)
uv run --locked fastapi dev example.web.app:app

# Run the FastAPI web app
uv run --locked fastapi dev <repo-name>.web:app
# Run the TUI (if include_tui=true)
uv run --locked example-tui

# Run the GUI (if include_gui=true)
uv run --locked example-gui

# Run pre-commit hooks
uv run --locked tox run -e pre-commit
Expand All @@ -63,6 +75,9 @@ uv run --locked tox run -e docs-build

# Serve docs locally
uv run --locked tox run -e docs-server

# Profiling (if include_profiling=true)
uv run --locked tox run -e profile
```

### Linting and Pre-commit
Expand All @@ -77,66 +92,91 @@ pre-commit install

## Template Architecture

### Jinja2 Template Structure

The template uses Copier's Jinja2 templating with these key patterns:
### Jinja2 Template Patterns

1. **Variable Substitution**: `{{github_repo_name}}` renders to the user's repo name
2. **Dynamic File Paths**: `src/{{github_repo_name}}/` creates package directories with user-provided names
3. **TODO Markers**: `TODO @{{github_user}}:` generates actionable TODOs in the rendered project
4. **Raw Blocks**: `{% raw %}${{ github.ref_name }}{% endraw %}` preserves GitHub Actions syntax
5. **Conditional Files**: `{% if condition %}filename{% endif %}.jinja` includes file only when condition is true

### Template Variables (copier.yml)

Required inputs:

- `github_user`, `github_repo_name`, `author_full_name`, `author_email`, `short_description`

Optional components (all boolean):

- `include_cli` - Typer CLI
- `include_web` - Web app + Dockerfile (framework choice: FastAPI or Litestar)
- `include_gui` - Tkinter GUI
- `include_tui` - Textual TUI
- `include_mcp` - MCP (Model Context Protocol) server
- `include_c_extensions` - Cython support with multi-platform wheels
- `include_profiling` - py-spy, scalene, cProfile tools
- `include_pycrucible` - PyCrucible for standalone executables
- `include_pydantic_settings` - pydantic-settings for config

Framework choices (when parent option is enabled):

- `web_framework` - fastapi/litestar (when `include_web` is true)

Tooling options:

- `release_automation` - none/release-please/release-it/release-drafter
- `dependency_management` - none/renovate/dependabot
- `include_pants`, `include_codecov`, `include_trunk`
- `include_mise` - mise for tool version management and task running
- `include_commitizen` - Commitizen versioning
- `include_precommit` - pre-commit hooks

### Generated Project Structure

Projects created from this template have:
Root modules in `src/{{github_repo_name}}/`:

- **CLI Application**: Typer-based CLI in `cli.py.jinja` with `version` and `info` commands
- **Web Application**: FastAPI stub in `web.py.jinja` with `/version` and `/info` endpoints
- **Core Modules**:
- `__metadata__.py.jinja`: Project name constant
- `dirs.py.jinja`: Platform-aware directory management using `platformdirs`
- `config.py.jinja`: Configuration placeholder
- `logging_setup.py.jinja`: Centralized logging setup
- `core.py` and `utils.py`: Empty stubs for user code
- **Entry Points**: Both CLI (`project.scripts`) and GUI (`project.gui-scripts`) entry points configured in `pyproject.toml`
- `__init__.py`, `__main__.py`, `__metadata__.py` - Package setup
- `_version.py` - Auto-generated by hatch-vcs (excluded from coverage)

### Dependency Groups
Subpackages (each with `__init__.py` and `app.py`):

Generated projects use uv dependency groups:
- `core/` - Core infrastructure (always included):
- `dirs.py` - Platform-aware directories
- `logging_setup.py` - Centralized logging
- `config.py` - Configuration (uses pydantic-settings if enabled)
- `utils/` - Utility functions (always included)
- `cli/` - Typer CLI with `version` and `info` commands (conditional)
- `web/` - FastAPI with `/version` and `/info` endpoints (conditional)
- `gui/` - Tkinter GUI launcher (conditional)
- `tui/` - Textual TUI (conditional)
- `mcp/` - MCP server with `version` and `info` tools (conditional)

- `dev`: Development dependencies (includes tox, tox-uv, style, test)
- `style`: Linting/formatting tools (ruff, mypy, pyright, ty, pyrefly, vulture, slotscheck, taplo, validate-pyproject, typos, actionlint)
- `test`: Testing tools (pytest, coverage, pytest-xdist, pytest-rerunfailures, pytest-mock, pytest-dependency)
- `docs`: MkDocs for documentation
- `tool`: Project management tools (commitizen, copier, poethepoet)
- `pre-commit`: Pre-commit framework and uv integration
Other conditional files:

### Build System
- `_c_extension.pyx`, `.pxd`, `.pyi` - Cython extension files
- `profile.py` - Profiling script

- **Builder**: `hatchling` with `hatch-vcs` plugin
- **Versioning**: Git-based versioning (tags) via hatch-vcs, fallback to 0.1.0
- **Version File**: Auto-generated `_version.py` (excluded from coverage)
- **Build Command**: `uv build` creates wheels and sdist
Test packages mirror source structure in `tests/`:

### CI/CD Workflows
- `tests/cli/`, `tests/web/`, `tests/gui/`, `tests/tui/`, `tests/mcp/` (each conditional)

Generated projects include GitHub Actions:
Entry points configured in `pyproject.toml`:

1. **CI** (`.github/workflows/ci.yml.jinja`):
- Runs `uv run --locked tox run` on Windows, Ubuntu, macOS
- Matrix tests across all supported Python versions (3.10-3.14)
- Triggered on push to main/master and PRs
- `project.scripts`: `pkg.cli.app:app`, `pkg.tui.app:main`, `pkg.web.app:main`, `pkg.mcp.app:main`
- `project.gui-scripts`: `pkg.gui.app:main` (launches without terminal)

2. **CD** (`.github/workflows/cd.yml.jinja`):
- Triggered on GitHub Release publication
- Builds with `uv build`
- Publishes to PyPI using Trusted Publishing (`uv publish --trusted-publishing always`)
- Attaches build artifacts to GitHub Release
- Requires `publish` environment with id-token write permissions
### Build System

3. **Other Workflows**:
- `check-pr-title.yml.jinja`: Validates PR titles follow conventional commits
- `release-drafter.yml.jinja`: Auto-generates release notes
- **Builder**: `hatchling` with `hatch-vcs` plugin
- **Versioning**: Git tags via hatch-vcs, fallback to 0.1.0
- **Build Command**: `uv build`

### CI/CD Workflows

1. **CI** (`ci.yml.jinja`): Matrix tests on Windows/Ubuntu/macOS, Python 3.10-3.14
2. **CD** (`cd.yml.jinja`): PyPI trusted publishing on GitHub Release
3. **Release automation**: release-please, release-it, or release-drafter (configurable)
4. **PR title linting**: Validates conventional commits format

### PyPI Trusted Publishing Setup

Expand All @@ -150,14 +190,23 @@ For generated projects to publish to PyPI:
- Workflow: `cd.yml`
- Environment: `publish`

## Code Style Guidelines

- **Imports**: Absolute only, grouped stdlib→third-party→local (ruff enforced)
- **Formatting**: Ruff, 88 chars, LF endings
- **Types**: Strict typing required, `from typing import ...`
- **Naming**: snake_case vars/functions, PascalCase classes, UPPER_CASE constants
- **Complexity**: Max cyclomatic complexity of 5 (ruff mccabe)
- **Structure**: Code in `src/{{github_repo_name}}/`, tests in `tests/`

## Template Modification Guidelines

### Adding New Template Files

1. Create file in `template/` with `.jinja` extension
2. Use `{{variable_name}}` for Copier variable substitution
3. Test by regenerating `example/` directory
4. Update this CLAUDE.md if the file introduces new architecture
2. For conditional files, use `{% if condition %}filename{% endif %}.jinja` naming
3. Use `{{variable_name}}` for Copier variable substitution
4. Test by regenerating `example/` directory

### Modifying Template Variables

Expand All @@ -166,22 +215,23 @@ For generated projects to publish to PyPI:
3. Update all `.jinja` files that reference the variable
4. Regenerate example to verify

### Important Template Conventions
### Template Conventions

- **Escaping**: Use `{% raw %}{% endraw %}` to preserve Jinja2 syntax in generated files (e.g., for GitHub Actions)
- **File Naming**: Dynamic directories use `{{variable}}` format (e.g., `src/{{github_repo_name}}/`)
- **Escaping**: Use `{% raw %}{% endraw %}` for GitHub Actions syntax
- **Comments**: Template-only comments use `{# #}`, generated comments use `#`
- **TODOs**: Use `TODO @{{github_user}}:` pattern for actionable items in generated projects
- **TODOs**: Use `TODO @{{github_user}}:` pattern for actionable items

### Testing Template Changes

Always test changes by:

1. Regenerating the example: `copier copy --data-file .example-input.yml --defaults . example/ --force`
2. Running style checks in example: `cd example && uv run --locked tox run -e style`
3. Running tests in example: `cd example && uv run --locked tox run`
2. Running style checks: `cd example && uv run --locked tox run -e style`
3. Running tests: `cd example && uv run --locked tox run`

## Copier-Specific Behavior

- **Subdirectory**: `_subdirectory: template` in `copier.yml` means Copier renders from `template/` not root
- **Answers File**: `{{_copier_conf.answers_file}}.jinja` becomes `.copier-answers.yml` for update tracking
- **Update Workflow**: Users can run `copier update` to pull template changes into their project
- **Subdirectory**: `_subdirectory: template` means Copier renders from `template/` not root
- **Answers File**: `{{_copier_conf.answers_file}}.jinja` becomes `.copier-answers.yml`
- **Update Workflow**: Users run `copier update` to pull template changes
- **Post-copy Task**: `git init` runs automatically after scaffolding
45 changes: 40 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,11 @@ Copier template for a modern, typed Python package/CLI with `uv`, `hatch`, `tox`
## What this template includes

- uv-first workflow with dependency groups (dev, style, test, docs, tool, pre-commit) and tox-uv runners across Python 3.10–3.14; builds via `hatchling`/`hatch-vcs` with versions from Git tags.
- Optional components: Typer CLI entrypoint, FastAPI web app, Textual TUI, Tkinter GUI, C extensions via Cython with multi-platform wheel building, logging/config modules, type hints, and a `py.typed` marker plus corresponding tests; container-ready `Dockerfile`.
- Optional components: Typer CLI entrypoint, FastAPI web app, Textual TUI, Tkinter GUI, C extensions via Cython with multi-platform wheel building, profiling tools (py-spy, scalene, cProfile), logging/config modules, type hints, and a `py.typed` marker plus corresponding tests; container-ready `Dockerfile`.
- QA stack: pytest with coverage/xdist/reruns (and `.codecov.yml`), ruff, mypy, pyright, ty, pyrefly, vulture, slotscheck, taplo, validate-pyproject, typos, actionlint.
- Docs and site: MkDocs scaffold (`docs/index.md`) with GitHub Pages deploy workflow.
- Automation and hygiene: CI/CD workflows (matrix tests, trusted-publishing to PyPI, gh-pages), configurable release automation (release-please/release-it/release-drafter), PR title linting, issue/PR templates, dependency management (Renovate/Dependabot), optional Commitizen, pre-commit (with pre-commit-uv), devcontainer, VS Code launch config, gitignore, FUNDING, and LICENSE.
- Extra tooling: Optional Trunk config (hadolint/markdownlint/etc.), Pants config, `.dockerignore`, and badge-rich README template for generated projects.
- Extra tooling: Optional Trunk config (hadolint/markdownlint/etc.), Pants config, `.dockerignore`, badge-rich README template, and enhanced VS Code launch.json for debugging (current file, tests, attach, entry points).

## Inputs

Expand All @@ -25,6 +25,8 @@ Copier will prompt for:
- `include_gui` (include Tkinter GUI)
- `include_tui` (include Textual TUI)
- `include_c_extensions` (include C extensions support using Cython)
- `include_profiling` (include profiling and performance tools)
- `include_pycrucible` (include PyCrucible for standalone executables)
- `include_pydantic_settings` (use pydantic-settings for configuration)
- `release_automation` (none/release-please/release-it/release-drafter)
- `dependency_management` (none/renovate/dependabot)
Expand All @@ -34,11 +36,10 @@ Copier will prompt for:
- `include_citation` (include CITATION.cff)
- `include_pants` (include Pants build system)
- `include_codecov` (include Codecov configuration)
- `include_mise` (include mise tool version management)
- `include_mise` (include mise for tool version management and task running)
- `include_trunk` (include Trunk linting/formatting)
- `include_poe` (include Poe task runner)
- `include_commitizen` (include Commitizen)
- `use_precommit` (use pre-commit hooks)
- `include_precommit` (use pre-commit hooks)

## Scaffold a project

Expand Down Expand Up @@ -78,12 +79,45 @@ Enable PyPI once per project for `.github/workflows/cd.yml`:
7. Set `Environment name` to `publish` (or your chosen env).
8. Save.

### Docker Hub setup (if `include_web` is enabled)

Enable Docker Hub publishing (integrated in `.github/workflows/cd.yml`):

1. Create a [Docker Hub Access Token](https://hub.docker.com/settings/security).
2. In your GitHub repository, go to Settings → Secrets and variables → Actions.
3. Add two repository secrets:
- `DOCKERHUB_USERNAME`: Your Docker Hub username
- `DOCKERHUB_TOKEN`: Your Docker Hub access token
4. On release, the workflow will build and push multi-arch images (amd64/arm64) to Docker Hub.

### Release steps

1. Draft a GitHub Release (tag = version).
2. Update `CHANGELOG.md` with the new version details.
3. Publish the release.
4. `cd.yml` will build the wheel/sdist with uv, publish to PyPI via trusted publishing, and upload artifacts to the GitHub Release.
5. If `include_web` is enabled, `cd.yml` also builds and pushes Docker images to Docker Hub.
6. If `include_pycrucible` is enabled, `cd.yml` also builds standalone executables for Windows, macOS, and Linux.

### CD workflow structure

The unified `cd.yml` orchestrates all release jobs:

```text
build ─────┬──► pypi-publish ──────────────────────┐
│ │
├──► build-executables (if pycrucible) ─┼──► attach-github-release
│ (parallel: ubuntu/windows/macos) │
│ │
└──► docker-publish (if web) ───────────┘
(pushes to Docker Hub independently)
```

- **build**: Builds the Python wheel/sdist with uv
- **pypi-publish**: Publishes to PyPI via trusted publishing
- **build-executables**: Builds standalone executables for 3 platforms (conditional)
- **docker-publish**: Builds and pushes multi-arch Docker images (conditional)
- **attach-github-release**: Attaches all artifacts to the GitHub Release

## Author

Expand All @@ -98,4 +132,5 @@ This template is not intended to be used for malicious purposes. The author is n
This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.

<!-- Refs -->

[author]: https://github.com/hasansezertasan
Loading