From 85130ad7364701e212b54d93c977200178f590ae Mon Sep 17 00:00:00 2001 From: privatedumbo Date: Thu, 18 Jun 2026 16:39:15 +0200 Subject: [PATCH] chore: modernize python template MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Rename CLAUDE.md โ†’ AGENTS.md (always included, no opt-in) - Remove include_claude_code copier question - Default Python to 3.14, drop 3.12 - Tighten poe check (mypy on package only) and poe test (bare pytest) - Add poe setup task (sync + install-hooks) - Add .editorconfig - Replace foo/bar placeholder with hello() - README leads with single 'uv run poe setup' command - Remove list[str]/List[str] hint from AGENTS.md (obvious since 3.9) --- .github/workflows/ci.yaml | 1 - .gitignore | 1 + CLAUDE.md => AGENTS.md | 3 +- README.md | 21 ++++++------ copier.yaml | 14 ++------ template/.editorconfig | 12 +++++++ ...DE.md{% endif %}.jinja => AGENTS.md.jinja} | 2 +- template/README.md.jinja | 12 ++----- template/scripts/app.toml.jinja | 8 +++-- template/tests/test_core.py.jinja | 6 ++-- template/{{project_slug}}/main.py.jinja | 6 ++-- tests/test_template.py | 32 +++++-------------- 12 files changed, 53 insertions(+), 65 deletions(-) rename CLAUDE.md => AGENTS.md (96%) create mode 100644 template/.editorconfig rename template/{{% if include_claude_code %}CLAUDE.md{% endif %}.jinja => AGENTS.md.jinja} (96%) diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 5ab41e3..d4c93d6 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -79,7 +79,6 @@ jobs: --data "license=MIT" \ --data "include_docker=${{ matrix.include_docker }}" \ --data "include_github_actions=${{ matrix.include_github_actions }}" \ - --data "include_claude_code=false" \ --trust - name: ๐Ÿ“‚ List generated files diff --git a/.gitignore b/.gitignore index 3699ce3..771357c 100644 --- a/.gitignore +++ b/.gitignore @@ -216,3 +216,4 @@ __marimo__/ .streamlit/secrets.toml .DS_Store +.claude/ diff --git a/CLAUDE.md b/AGENTS.md similarity index 96% rename from CLAUDE.md rename to AGENTS.md index 547eefc..04a72bd 100644 --- a/CLAUDE.md +++ b/AGENTS.md @@ -17,7 +17,7 @@ python-template/ โ”‚ โ”œโ”€โ”€ *.jinja # Jinja templates (rendered) โ”‚ โ””โ”€โ”€ * # Static files (copied as-is) โ”œโ”€โ”€ tests/ # Tests for template generation -โ””โ”€โ”€ CLAUDE.md # This file +โ””โ”€โ”€ AGENTS.md # This file ``` ## Template File Conventions @@ -35,6 +35,7 @@ python-template/ ### Available Commands ```bash uv run poe sync # Sync dependencies +uv run poe setup # Sync + install hooks uv run poe format # Format code with ruff uv run poe lint # Lint with ruff uv run poe check # Type check with mypy diff --git a/README.md b/README.md index 13052d2..509cd11 100644 --- a/README.md +++ b/README.md @@ -17,12 +17,15 @@ A [Copier](https://copier.readthedocs.io/) template for modern Python projects. - ๐Ÿ” **[Mypy](https://mypy.readthedocs.io/)** - Static type checker - ๐Ÿงช **[Pytest](https://docs.pytest.org/)** - Testing framework with coverage -### Infrastructure (Optional) +### Always Included - ๐Ÿ›ซ **Pre-commit hooks** - Automated code quality checks +- ๐Ÿค– **AGENTS.md** - Best practices for AI-assisted development + +### Optional + - ๐Ÿณ **Docker** - Multi-stage builds optimized for Python/UV - ๐Ÿ”„ **GitHub Actions** - CI/CD pipeline -- ๐Ÿค– **Claude Code** - Best practices for AI-assisted development --- @@ -30,7 +33,7 @@ A [Copier](https://copier.readthedocs.io/) template for modern Python projects. ### Prerequisites -- Python 3.12+ +- Python 3.13+ - [Copier](https://copier.readthedocs.io/) (`pipx install copier` or `uv tool install copier`) ### Generate a New Project @@ -54,11 +57,11 @@ Copier will ask you a series of questions to customize your project: | `author_name` | Author's full name | - | | `author_email` | Author's email | - | | `github_username` | GitHub username/organization | - | -| `python_version` | Minimum Python version | 3.13 | +| `python_version` | Minimum Python version | 3.14 | | `license` | Project license | MIT | | `include_docker` | Include Docker support | Yes | | `include_github_actions` | Include GitHub Actions CI/CD | Yes | -| `include_claude_code` | Include Claude Code configuration | No | + ### Example @@ -88,17 +91,15 @@ Let's configure your new project! ๐ŸŽค GitHub username or organization name. johndoe ๐ŸŽค Minimum Python version for your project. - 3.13 (stable, recommended) + 3.14 (stable, recommended) ๐ŸŽค Open source license for your project. MIT (permissive, simple) ๐ŸŽค Include Docker support? Yes ๐ŸŽค Include GitHub Actions CI/CD? Yes -๐ŸŽค Include Claude Code configuration? - No - create .copier-answers.yml + create AGENTS.md create .gitignore create .pre-commit-config.yaml create .python-version @@ -180,7 +181,7 @@ python-template/ โ”‚ โ”œโ”€โ”€ scripts/ โ”‚ โ”‚ โ””โ”€โ”€ app.toml.jinja โ”‚ โ”œโ”€โ”€ .github/ # GitHub Actions (conditional) -โ”‚ โ”œโ”€โ”€ CLAUDE.md.jinja # Claude Code config (conditional) +โ”‚ โ”œโ”€โ”€ AGENTS.md.jinja # AI agent instructions (always included) โ”‚ โ”œโ”€โ”€ pyproject.toml.jinja โ”‚ โ”œโ”€โ”€ README.md.jinja โ”‚ โ”œโ”€โ”€ Dockerfile.jinja # Docker support (conditional) diff --git a/copier.yaml b/copier.yaml index 39a6586..5c1a02a 100644 --- a/copier.yaml +++ b/copier.yaml @@ -87,11 +87,10 @@ python_version: help: | Minimum Python version for your project. This sets requires-python and configures tooling. - default: "3.13" + default: "3.14" choices: - "3.12 (maintenance)": "3.12" - "3.13 (stable, recommended)": "3.13" - "3.14 (latest)": "3.14" + "3.13 (maintenance)": "3.13" + "3.14 (stable, recommended)": "3.14" license: type: str @@ -124,13 +123,6 @@ include_github_actions: Adds workflows for linting, testing, and type checking. default: true -include_claude_code: - type: bool - help: | - Include Claude Code configuration? - Adds a CLAUDE.md file with Python best practices for AI-assisted development. - default: false - # โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ # Computed Variables (internal use) # โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ diff --git a/template/.editorconfig b/template/.editorconfig new file mode 100644 index 0000000..cd45b0f --- /dev/null +++ b/template/.editorconfig @@ -0,0 +1,12 @@ +root = true + +[*] +indent_style = space +indent_size = 4 +end_of_line = lf +charset = utf-8 +trim_trailing_whitespace = true +insert_final_newline = true + +[*.{yaml,yml,toml}] +indent_size = 2 diff --git a/template/{% if include_claude_code %}CLAUDE.md{% endif %}.jinja b/template/AGENTS.md.jinja similarity index 96% rename from template/{% if include_claude_code %}CLAUDE.md{% endif %}.jinja rename to template/AGENTS.md.jinja index 7ad841c..4dedbc0 100644 --- a/template/{% if include_claude_code %}CLAUDE.md{% endif %}.jinja +++ b/template/AGENTS.md.jinja @@ -14,6 +14,7 @@ All tasks use `poe` (poethepoet), defined in `scripts/app.toml`: ``` +uv run poe setup # Sync dependencies + install hooks uv run poe sync # Sync all dependencies uv run poe install-hooks # Install pre-commit hooks uv run poe format # Format code with ruff @@ -44,7 +45,6 @@ Run `uv run poe flc` before committing. Run `uv run poe flct` for full validatio ### Type Hints - Use `str | None` instead of `Optional[str]` -- Use `list[str]` instead of `List[str]`, `dict[str, int]` instead of `Dict[str, int]` - Always include type hints for function parameters and return types ### Style diff --git a/template/README.md.jinja b/template/README.md.jinja index 7af02c1..a48948d 100644 --- a/template/README.md.jinja +++ b/template/README.md.jinja @@ -29,19 +29,13 @@ This project uses [UV](https://docs.astral.sh/) as package manager. You need to have it installed in your system. -Once you have that, you can run: +Once you have that, run: ```bash -uv run poe sync +uv run poe setup ``` -to create a virtual environment and install all the dependencies, including the development ones. - -You also need to install the pre-commit hooks with: - -```bash -uv run poe install-hooks -``` +This will create a virtual environment, install all dependencies, and set up pre-commit hooks. ### Formatting, Linting and Testing diff --git a/template/scripts/app.toml.jinja b/template/scripts/app.toml.jinja index aaebff4..e14ac8f 100644 --- a/template/scripts/app.toml.jinja +++ b/template/scripts/app.toml.jinja @@ -6,6 +6,10 @@ cmd = "uv sync --all-extras" help = "Install pre commit hooks." cmd = "uv run pre-commit install" +[tool.poe.tasks.setup] +help = "Sync dependencies and install pre-commit hooks." +sequence = [ "sync", "install-hooks" ] + [tool.poe.tasks.format] help = "Format code." cmd = "uv run ruff format ${POE_ROOT}" @@ -16,11 +20,11 @@ cmd = "uv run ruff check --fix ${POE_ROOT}" [tool.poe.tasks.check] help = "Run type checker." -cmd = "uv run mypy ${POE_ROOT}" +cmd = "uv run mypy {{ project_slug }}" [tool.poe.tasks.test] help = "Run tests." -cmd = "uv run pytest ${POE_ROOT}" +cmd = "uv run pytest" [tool.poe.tasks.flc] help = "`flc`: Format, lint, and check." diff --git a/template/tests/test_core.py.jinja b/template/tests/test_core.py.jinja index fe9c7ac..e0ec34c 100644 --- a/template/tests/test_core.py.jinja +++ b/template/tests/test_core.py.jinja @@ -1,5 +1,5 @@ -from {{ project_slug }}.main import foo +from {{ project_slug }}.main import hello -def test_foo() -> None: - assert foo() == "bar" +def test_hello() -> None: + assert hello() == "Hello from {{ project_slug }}!" diff --git a/template/{{project_slug}}/main.py.jinja b/template/{{project_slug}}/main.py.jinja index 3571ce8..6c306fc 100644 --- a/template/{{project_slug}}/main.py.jinja +++ b/template/{{project_slug}}/main.py.jinja @@ -1,6 +1,6 @@ -def foo() -> str: - return "bar" +def hello() -> str: + return "Hello from {{ project_slug }}!" if __name__ == "__main__": - foo() + print(hello()) # noqa: T201 diff --git a/tests/test_template.py b/tests/test_template.py index ba2dd20..8561a78 100644 --- a/tests/test_template.py +++ b/tests/test_template.py @@ -26,7 +26,6 @@ def default_answers() -> dict[str, str | bool]: "license": "MIT", "include_docker": True, "include_github_actions": True, - "include_claude_code": False, } @@ -49,6 +48,8 @@ def test_template_generates_successfully( assert (tmp_path / ".gitignore").exists() assert (tmp_path / ".pre-commit-config.yaml").exists() assert (tmp_path / "scripts" / "app.toml").exists() + assert (tmp_path / "AGENTS.md").exists() + assert (tmp_path / ".editorconfig").exists() # Check project structure assert (tmp_path / "test_project").is_dir() @@ -168,41 +169,24 @@ def test_template_skips_github_actions_when_disabled( assert not (tmp_path / ".github").exists() -def test_template_generates_claude_code_when_enabled( +def test_template_generates_agents_md( template_path: Path, default_answers: dict[str, str | bool], tmp_path: Path, ) -> None: - """Test that CLAUDE.md is generated when include_claude_code is True.""" - answers = {**default_answers, "include_claude_code": True} + """Test that AGENTS.md is always generated.""" run_copy( str(template_path), tmp_path, - data=answers, + data=default_answers, unsafe=True, ) - assert (tmp_path / "CLAUDE.md").exists() + assert (tmp_path / "AGENTS.md").exists() # Verify Python version is templated - claude_md = (tmp_path / "CLAUDE.md").read_text() - assert "3.13" in claude_md - - -def test_template_skips_claude_code_when_disabled( - template_path: Path, - default_answers: dict[str, str | bool], - tmp_path: Path, -) -> None: - """Test that CLAUDE.md is not generated when disabled.""" - run_copy( - str(template_path), - tmp_path, - data=default_answers, - unsafe=True, - ) - - assert not (tmp_path / "CLAUDE.md").exists() + agents_md = (tmp_path / "AGENTS.md").read_text() + assert "3.13" in agents_md def test_template_generates_license_mit(