-
Notifications
You must be signed in to change notification settings - Fork 2
feat: add cookiecutter template for interactive package generation #183
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Conversation
- Add cookiecutter.json with interactive prompts for package configuration - Support configurable Python version ranges (min/max versions) - Add post-generation hooks to clean up unused files based on user choices - Convert all template files to use cookiecutter variables - Add conditional GitHub Actions workflows for testing and docs - Add conditional pre-commit configuration - Simplify documentation to minimal home page only - Update main README with cookiecutter usage instructions Users can now generate customized Python packages by running: cookiecutter https://github.com/shenxiangzhuang/mppt.git 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <[email protected]>
for more information, see https://pre-commit.ci
WalkthroughAdds a Cookiecutter-based project template with post-generation hooks, CI workflows (tests, docs), template code (hello, quick_sort), tests, docs site (MkDocs), and repository configs (pyproject, pre-commit, LICENSE, README). Root README onboarding expanded; root pyproject adds cookiecutter as a dev dependency. Changes
Sequence Diagram(s)sequenceDiagram
autonumber
actor User
participant Cookiecutter
participant Template as Project Template
participant Hook as post_gen_project.py
participant FS as Filesystem
User->>Cookiecutter: Run with cookiecutter.json
Cookiecutter->>Template: Render files with answers
Template->>Hook: Invoke post-gen hook
Hook->>Hook: Generate Python classifiers
Hook->>FS: Update pyproject.toml classifiers
alt include_docs == "n"
Hook->>FS: Remove docs/ and mkdocs.yml
end
alt include_pre_commit == "n"
Hook->>FS: Remove .pre-commit-config.yaml
end
alt include_github_actions == "n"
Hook->>FS: Remove .github/
end
Hook-->>User: Generation complete
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Possibly related PRs
Suggested labels
Poem
Tip 🔌 Remote MCP (Model Context Protocol) integration is now available!Pro plan users can now connect to remote MCP servers from the Integrations page. Connect with popular remote MCPs such as Notion and Linear to add more context to your reviews and chats. ✨ Finishing Touches
🧪 Generate unit tests
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. 🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
SupportNeed help? Create a ticket on our support page for assistance with any issues or questions. CodeRabbit Commands (Invoked using PR/Issue comments)Type Other keywords and placeholders
CodeRabbit Configuration File (
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 11
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (3)
pyproject.toml (1)
49-52
: Fix Bug Tracker URL (currently points to GitHub Pages, not Issues)"Bug Tracker" should link to the repository issues, not the website.
-"Bug Tracker" = "https://shenxiangzhuang.github.io/mppt/issues" +"Bug Tracker" = "https://github.com/shenxiangzhuang/mppt/issues"{{cookiecutter.package_name}}/README.md (1)
67-68
: Hide “refer to the documentation” when docs are excluded.When include_docs = "n", this sentence points to non-existent docs.
-For more details on customization options, refer to the documentation. +{%- if cookiecutter.include_docs == "y" -%} +For more details on customization options, refer to the documentation. +{%- endif -%}{{cookiecutter.package_name}}/CHANGELOG.md (1)
5-85
: Make the changelog template-agnostic; remove upstream mppt-specific history and links.This file will ship into every generated project. Embedding your own repository’s historical releases (e.g., PR links to shenxiangzhuang/mppt and Sphinx entries while the template uses MkDocs) will confuse consumers and create broken links in newly generated repos.
Recommend replacing past version sections with a neutral Keep a Changelog–style skeleton that users can fill in.
Apply this diff to replace the version history with a minimal, template-agnostic scaffold:
@@ ## [Unreleased] - -## [0.7.0] - 2025-04-25 - -### Added - -* add(test): add mutmut pkg by @shenxiangzhuang in [#164](https://github.com/shenxiangzhuang/mppt/pull/164) -* add(doc): sphinx-immaterial theme by @shenxiangzhuang in [#165](https://github.com/shenxiangzhuang/mppt/pull/165) - -### Changed - -* chore(linting): update Ruff lint configuration by @shenxiangzhuang in [#157](https://github.com/shenxiangzhuang/mppt/pull/157) -* pkg: remove lock file by @shenxiangzhuang in [#158](https://github.com/shenxiangzhuang/mppt/pull/158) -* chore: remove dev container by @shenxiangzhuang in [#161](https://github.com/shenxiangzhuang/mppt/pull/161) - -### CI/CD - -* ci: uv cache prune by @shenxiangzhuang in [#150](https://github.com/shenxiangzhuang/mppt/pull/150) -* ci(publish): use pypi trusted publisher by @shenxiangzhuang in [#162](https://github.com/shenxiangzhuang/mppt/pull/162) - -## [0.6.0] - 2025-03-06 - -### Added - -- CI: add mypy and ruff in test workflow - -### Changed - -- Linter & formatter: use ruff only, remove isort, black, flake8 - -## [0.5.0] - 2025-01-03 - -### Changed - -- Use uv to manage the package rather than poetry (#106) -- Drop the support for Python 3.8 (#110) - -## [0.4.0] - 2024-06-11 - -### Added - -- Poetry: Add commitizen, a conventional commit tool (#71) -- Add `py.typed` file to support type hinting (#70) -- Add sql linter: SQLFluff (#58) -- Add task runner just (#50) -- Add package management tool uv (#49) -- Add Locust as a load testing tool (#39) - -## [0.3.0] - 2023-12-14 - -### Added - -- Add ruff as extra linter and formatter: both in dependency and pre-commit (#31) -- Add more details about the linters and formatters with the resource from Google SRE book -- Add doctest (#34) - -## [0.2.0] - 2023-12-01 - -### Added - -- Documentations for all the features (#20) -- Quick sort implementation for hypothesis testing (#22) - -### Changed - -- Change package management from Rye to Poetry (#15, #19) - -### Removed - -- Sweep AI App - -## [0.1.1] - 2023-08-15 - -### Changed - -- reorg this package template - -## [0.1.0] - 2023-08-15 - -### Added - -- add this package template + +### Added +* ... + +### Changed +* ... + +### Deprecated +* ... + +### Removed +* ... + +### Fixed +* ... + +### Security +* ...I can push a follow-up commit that also adds a short header explaining “Keep a Changelog” and SemVer, if you want.
🧹 Nitpick comments (29)
{{cookiecutter.package_name}}/{{cookiecutter.package_name}}/__init__.py (1)
1-1
: Template the docstring to the generated package nameHard-coding "MPPT" leaks the template’s own name into generated projects. Prefer a cookiecutter variable so every new package has an accurate docstring.
-"""MPPT Module.""" +"""{{ cookiecutter.package_name }} package."""If you’d like, we can also expose a resilient version in generated packages (optional):
from importlib.metadata import PackageNotFoundError, version try: __version__ = version("{{ cookiecutter.package_name }}") except PackageNotFoundError: # Package is not installed (e.g., working from a checkout) __version__ = "0.0.0"pyproject.toml (2)
110-112
: Consider deriving Ruff target-version from the template’s min PythonYou advertise configurable Python version ranges in the template; keeping Ruff’s target-version aligned with the minimum supported Python for the generated project will avoid false positives/negatives.
For example (adjust variable name to your cookiecutter.json schema):
# If min Python is e.g. "3.9", becomes "py39" target-version = "py{{ cookiecutter.min_python|replace('.', '') }}"
34-35
: Update Cookiecutter version pin to latest 2.xPlease pin Cookiecutter to the most recent 2.x release to avoid untracked breaking changes:
• In pyproject.toml, change:
- "cookiecutter", + "cookiecutter>=2.6.0,<3",Cookiecutter 2.6.0 is the latest stable release (published Feb 21 2024) and adds support for Python 3.12, ensuring full compatibility with Python 3.9+ (github.com, cookiecutter.readthedocs.io)
You can revisit this pin when a 3.x release becomes stable.
{{cookiecutter.package_name}}/.pre-commit-config.yaml (1)
17-21
: Avoid heavy "types-all" in mypy hook; pass config and let deps drive stubsInstalling types-all pulls many stubs and slows hooks. Prefer using your project’s dependencies (and explicit type stubs when needed) and point mypy to pyproject config.
- - repo: https://github.com/pre-commit/mirrors-mypy - rev: v1.11.2 - hooks: - - id: mypy - additional_dependencies: [types-all] + - repo: https://github.com/pre-commit/mirrors-mypy + rev: v1.11.2 + hooks: + - id: mypy + args: [--config-file=pyproject.toml]If you really want broad stubs for the template, consider a smaller curated list (e.g., types-requests) instead of types-all.
{{cookiecutter.package_name}}/.github/workflows/build_docs.yaml (2)
20-31
: Optional: cache dependencies and add concurrency to avoid redundant buildssetup-uv supports caching; concurrency prevents duplicate runs on rapid pushes.
Add after "on" (or at job level if you prefer):
+concurrency: + group: docs-${{ github.ref }} + cancel-in-progress: trueAnd enable caching (example; verify exact inputs for setup-uv):
- name: Install uv uses: astral-sh/setup-uv@v3 with: version: "latest" + enable-cache: true
15-18
: Upgrade GitHub Action to setup-python v5 for improved caching and compatibility
- File:
{{cookiecutter.package_name}}/.github/workflows/build_docs.yaml
(lines 15–18)- uses: actions/setup-python@v4 + uses: actions/setup-python@v5v5 is the current stable major release (e.g. v5.2.0 as of Aug 29, 2025) and includes several non-breaking enhancements over v4:
- Adds architecture (arch) to cache keys, preventing cross-arch cache collisions on runners (github.com)
- Includes explicit “.zip” extension for Windows package downloads to ensure compatibility with
Expand-Archive
on self-hosted Windows runners (github.com)- Supports newer Python versions (including experimental “free-threaded” builds like 3.13t) and reading from
.tool-versions
files (github.com)Since this workflow pins Python 3.9, there are no breaking changes—upgrade and validate via CI to take advantage of these fixes and improvements.
{{cookiecutter.package_name}}/{{cookiecutter.package_name}}/hello.py (1)
17-33
: Consider widening accepted numeric types for add().Right now the signature forces float; ints work at runtime but can be flagged by strict type checkers. If you want this template to be friendlier for beginners, accept real numbers and document coercion to float.
Apply this minimal change to the signature and return type while keeping behavior identical:
-def add(a: float, b: float) -> float: +from numbers import Real + +def add(a: Real, b: Real) -> float: """Adds two numbers together.Optionally add a quick doctest showing mixed int/float usage:
>>> add(1, 2.5) 3.5{{cookiecutter.package_name}}/tests/test_hello.py (1)
4-6
: Strengthen the assertion to catch regressions.Asserting only the type could miss errors like changed content. Assert the exact greeting as well.
def test_hello() -> None: - msg = hello() - assert isinstance(msg, str) + msg = hello() + assert isinstance(msg, str) + assert msg == "Hello, World!"Optional: add a small test for add() to exercise the second public function:
def test_add() -> None: from {{ cookiecutter.package_name }}.hello import add assert add(1, 2) == 3 assert add(1.5, 2.5) == 4.0{{cookiecutter.package_name}}/docs/index.md (1)
21-36
: Nice, concise dev workflow; minor consistency nit.You promote uv for env and dev flows—great. Consider mirroring that in the Installation section (e.g., uv pip install ...) or add a note that pip is fine for end users while uv is recommended for contributors.
{{cookiecutter.package_name}}/{{cookiecutter.package_name}}/sort.py (1)
4-21
: Readable, correct quick sort; small clarity refactor recommended.Function is correct for floats and aligns with tests. For readability and debug-ability, split the one-liner into named parts without changing behavior. Also, consider the worst-case O(n^2) due to first-element pivot; acceptable for teaching, but call it out in the docstring.
def quick_sort(xs: list[float]) -> list[float]: - """Quick sort: A very radical implementation. + """Quick sort: simple recursive implementation (demonstration). @@ - if len(xs) <= 1: - return xs - return [*quick_sort([x for x in xs[1:] if x <= xs[0]]), xs[0], *quick_sort([x for x in xs[1:] if x > xs[0]])] + if len(xs) <= 1: + return xs + pivot, rest = xs[0], xs[1:] + left = [x for x in rest if x <= pivot] + right = [x for x in rest if x > pivot] + return [*quick_sort(left), pivot, *quick_sort(right)]If you want better average/worst-case behavior without losing clarity, sample a pivot (or use median-of-three). I can provide a version gated by a small threshold to fall back to built-in sorted() for very long inputs.
{{cookiecutter.package_name}}/tests/test_sort.py (1)
10-13
: Good property test; add non-mutating and idempotency checks.Two lightweight properties help catch accidental in-place mutation and ensure stability of results across repeated calls.
Additional tests (can be added below):
from copy import copy class TestQuickSort: @given(items=float_list) @settings(max_examples=300) def test_non_mutating(self, items: list[float]) -> None: original = copy(items) quick_sort(items) assert items == original @given(items=float_list) @settings(max_examples=200) def test_idempotent(self, items: list[float]) -> None: once = quick_sort(items) twice = quick_sort(once) assert once == twice{{cookiecutter.package_name}}/README.md (1)
31-39
: Windows activation hint (PowerShell) — minor usability tweak.PowerShell users typically run .venv\Scripts\Activate.ps1. Consider mentioning it.
- source .venv/bin/activate # On Windows: .venv\Scripts\activate + source .venv/bin/activate # Windows (CMD): .venv\Scripts\activate | Windows (PowerShell): .venv\Scripts\Activate.ps1README.md (2)
25-35
: Recommend pinning to a tag/commit for reproducible template generation.Unpinned cookiecutter pulls can change behavior over time. Suggest a --checkout to a released tag.
- cookiecutter https://github.com/shenxiangzhuang/mppt.git + # Pin to a release tag (recommended) for reproducibility + cookiecutter https://github.com/shenxiangzhuang/mppt.git --checkout vX.Y.ZWhen you cut the next release, consider updating the README to the latest tag.
49-51
: Optional: Note pre-commit step for Cookiecutter path when enabled.You already show pre-commit in Option 2. Adding a short “if enabled” note here keeps both paths consistent.
uv sync --all-extras --dev + # If you enabled pre-commit during generation: + uv run pre-commit installcookiecutter.json (2)
10-14
: License set could include MPL-2.0 and LGPL-3.0.Consider broadening choices; MIT/Apache/MPL cover most needs. If you prefer minimalism, ignore.
- "license": ["MIT", "Apache-2.0", "BSD-3-Clause", "GPL-3.0", "LGPL-2.1"], + "license": ["MIT", "Apache-2.0", "BSD-3-Clause", "MPL-2.0", "GPL-3.0", "LGPL-3.0"],
24-33
: Verify assets in _copy_without_render exist.docs/overrides/main.html may not be present. If not, remove it to avoid cookiecutter warnings.
{{cookiecutter.package_name}}/mkdocs.yml (3)
33-54
: Remove duplicate feature entry.content.code.annotate appears twice.
features: - content.action.edit - content.action.view - announce.dismiss - - content.code.annotate - content.tabs.link - content.tooltips - header.autohide - navigation.instant - navigation.tracking - navigation.tabs - navigation.tabs.sticky - navigation.indexes - navigation.prune - navigation.sections - navigation.top - search.highlight - search.share - search.suggest - toc.follow # - toc.integrate - - content.code.annotate + - content.code.annotate
1-7
: Add edit_uri and site_url; make links resilient to default branch changes.content.action.edit/view works best with edit_uri. Also consider site_url for canonical links.
site_name: {{ cookiecutter.package_name }} repo_url: https://github.com/{{ cookiecutter.github_username }}/{{ cookiecutter.package_name }} repo_name: {{ cookiecutter.github_username }}/{{ cookiecutter.package_name }} +edit_uri: edit/{{ cookiecutter.default_branch }}/docs/ +site_url: https://{{ cookiecutter.github_username }}.github.io/{{ cookiecutter.package_name }}/ site_description: {{ cookiecutter.project_short_description }} site_author: {{ cookiecutter.author_name }} copyright: Copyright © {% now 'utc', '%Y' %} {{ cookiecutter.author_name }}
57-61
: Point social link to the repository rather than the user (clearer CTA).extra: social: - icon: fontawesome/brands/github - link: https://github.com/{{ cookiecutter.github_username }}/ + link: https://github.com/{{ cookiecutter.github_username }}/{{ cookiecutter.package_name }}{{cookiecutter.package_name}}/.github/workflows/test.yaml (4)
19-20
: Update setup-python to v5.actions/setup-python@v5 is current and has improvements over v4.
- uses: actions/setup-python@v4 + uses: actions/setup-python@v5
1-8
: Tighten default workflow permissions.Set least-privilege permissions at the workflow level.
name: Test on: push: branches: [ master, main ] pull_request: branches: [ master, main ] + +permissions: + contents: read
9-16
: Optional: add concurrency to cancel redundant runs on the same PR/branch.jobs: test: + concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true runs-on: ubuntu-latest
37-44
: Bump Codecov action to v4 and simplify config.v3 is legacy. v4 reduces maintenance; keep fail_ci_if_error as you prefer.
- - name: Upload coverage to Codecov - uses: codecov/codecov-action@v3 + - name: Upload coverage to Codecov + uses: codecov/codecov-action@v4 with: file: ./coverage.xml flags: unittests name: codecov-umbrella fail_ci_if_error: false{{cookiecutter.package_name}}/CHANGELOG.md (1)
27-49
: Unify unordered list marker to satisfy markdownlint (MD004).You mix “” and “-” for bullets. Pick one (you already use “” earlier). If you decide to keep the historical sections, apply:
- - CI: add mypy and ruff in test workflow + * CI: add mypy and Ruff in test workflowRepeat similarly for other “- ” bullets in the file.
If you run markdownlint locally, MD004 should pass after normalizing list markers. Want me to open a small PR to standardize linting across docs?
Also applies to: 55-57, 63-64, 68-68, 72-72, 78-78, 84-84
hooks/post_gen_project.py (3)
18-35
: Validate inputs and handle edge cases in generate_python_versions.Right now, invalid inputs (e.g., min > max) silently yield odd results, and only 3.x is supported. Add basic validation and clearer behavior.
def generate_python_versions(min_version, max_version): """Generate list of Python versions between min and max (inclusive).""" - # Extract major and minor versions - min_parts = min_version.split(".") - max_parts = max_version.split(".") - - min_major, min_minor = int(min_parts[0]), int(min_parts[1]) - max_major, max_minor = int(max_parts[0]), int(max_parts[1]) - - versions = [] - - # For now, assume all versions are 3.x - if min_major == 3 and max_major == 3: - for minor in range(min_minor, max_minor + 1): - versions.append(f"3.{minor}") - - return versions + try: + min_major, min_minor = map(int, min_version.split(".")[:2]) + max_major, max_minor = map(int, max_version.split(".")[:2]) + except (ValueError, AttributeError) as e: + raise ValueError(f"Invalid python version(s): {min_version!r}, {max_version!r}") from e + + if (min_major, min_minor) > (max_major, max_minor): + raise ValueError(f"Min version {min_version} cannot be greater than max version {max_version}.") + + # For now, support only Python 3.x explicitly. + if min_major != 3 or max_major != 3: + # Return just the single version when majors differ or are unsupported. + return [f"{min_major}.{min_minor}"] if (min_major, min_minor) == (max_major, max_minor) else [] + + return [f"3.{minor}" for minor in range(min_minor, max_minor + 1)]
49-56
: Avoid trailing comma in the last classifier entry.Some TOML parsers are strict about trailing commas in arrays. Build the list with join so only inter-item commas are emitted.
- # Generate classifiers - classifiers = [] - for version in python_versions: - classifiers.append(f' "Programming Language :: Python :: {version}",') - - # Replace the Python version classifiers placeholder - replacement = "\n".join(classifiers) + # Generate classifiers + classifiers = [f' "Programming Language :: Python :: {version}"' for version in python_versions] + + # Replace the Python version classifiers placeholder + replacement = ",\n".join(classifiers)If you want to be fully robust, we can switch to editing with a TOML library; but for a one-shot post-gen hook, join-based string replace is fine.
9-16
: Make remove_file_or_dir symlink-safe.rmtree on a directory symlink can raise errors. Treat symlinks like files.
def remove_file_or_dir(file_path): """Remove file or directory if it exists.""" if os.path.exists(file_path): - if os.path.isdir(file_path): + if os.path.islink(file_path) or os.path.isfile(file_path): + os.remove(file_path) + elif os.path.isdir(file_path): shutil.rmtree(file_path) - else: - os.remove(file_path){{cookiecutter.package_name}}/pyproject.toml (2)
10-16
: Optional: add the generic “Python :: 3” classifier for discoverability.Helps PyPI search and aligns with Trove classifier guidance.
classifiers = [ "Development Status :: {{ cookiecutter.development_status }}", "Intended Audience :: Science/Research", "Intended Audience :: Developers", "Operating System :: OS Independent", + "Programming Language :: Python :: 3", # PYTHON_VERSION_CLASSIFIERS_PLACEHOLDER ]
109-111
: Make Ruff target-version dynamic to the chosen minimum Python version.This keeps linting and autofixes aligned with supported syntax.
-# Assume Python 3.9 -target-version = "py39" +# Match the chosen minimum Python version +target-version = "py{{ cookiecutter.python_min_version | replace('.', '') }}"If min is 3.12, Ruff should print “Target version: py312” in its verbose output.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
💡 Knowledge Base configuration:
- MCP integration is disabled by default for public repositories
- Jira integration is disabled by default for public repositories
- Linear integration is disabled by default for public repositories
You can enable these sources in your CodeRabbit configuration.
📒 Files selected for processing (18)
README.md
(1 hunks)cookiecutter.json
(1 hunks)hooks/post_gen_project.py
(1 hunks)pyproject.toml
(1 hunks){{cookiecutter.package_name}}/.github/workflows/build_docs.yaml
(1 hunks){{cookiecutter.package_name}}/.github/workflows/test.yaml
(1 hunks){{cookiecutter.package_name}}/.pre-commit-config.yaml
(1 hunks){{cookiecutter.package_name}}/CHANGELOG.md
(1 hunks){{cookiecutter.package_name}}/LICENSE
(1 hunks){{cookiecutter.package_name}}/README.md
(1 hunks){{cookiecutter.package_name}}/docs/index.md
(1 hunks){{cookiecutter.package_name}}/mkdocs.yml
(1 hunks){{cookiecutter.package_name}}/pyproject.toml
(1 hunks){{cookiecutter.package_name}}/tests/test_hello.py
(1 hunks){{cookiecutter.package_name}}/tests/test_sort.py
(1 hunks){{cookiecutter.package_name}}/{{cookiecutter.package_name}}/__init__.py
(1 hunks){{cookiecutter.package_name}}/{{cookiecutter.package_name}}/hello.py
(1 hunks){{cookiecutter.package_name}}/{{cookiecutter.package_name}}/sort.py
(1 hunks)
🧰 Additional context used
🧬 Code graph analysis (3)
{{cookiecutter.package_name}}/tests/test_sort.py (1)
{{cookiecutter.package_name}}/{{cookiecutter.package_name}}/sort.py (1)
quick_sort
(4-21)
{{cookiecutter.package_name}}/tests/test_hello.py (1)
{{cookiecutter.package_name}}/{{cookiecutter.package_name}}/hello.py (1)
hello
(4-14)
{{cookiecutter.package_name}}/{{cookiecutter.package_name}}/sort.py (1)
tests/test_sort.py (2)
TestQuickSort
(9-13)test_float
(12-13)
🪛 LanguageTool
{{cookiecutter.package_name}}/README.md
[style] ~8-~8: Using many exclamation marks might seem excessive (in this case: 9 exclamation marks for a text that’s 2459 characters long)
Context: ...on)](https://github.com/astral-sh/ruff) {%- if cookiecutter.include_pre_commit == "y" %}
{%- endif %} {%- if cookiecutter.include_github_actions == "y" %} {%- if cookiecutter.include_docs == "y" %} [](https://github.com/{{ cookiecutter.github_username }}/{{ cookiecutter.package_name }}/actions/workflows/build_docs.yaml) {%- endif %} [](https://github.com/{{ cookiecutter.github_username }}/{{ cookiecutter.package_name }}/actions/workflows/test.yaml) {%- endif %} {%- if cookiecutter.include_codecov == "y" %} [
{{cookiecutter.package_name}}/CHANGELOG.md
[grammar] ~14-~14: There might be a mistake here.
Context: ...nfiguration by @shenxiangzhuang in #157 * pkg: remove lock file by @shenxiangzhuan...
(QB_NEW_EN)
[grammar] ~15-~15: There might be a mistake here.
Context: ...e lock file by @shenxiangzhuang in #158 * chore: remove dev container by @shenxian...
(QB_NEW_EN)
[grammar] ~55-~55: There might be a mistake here.
Context: ....0] - 2023-12-14 ### Added - Add ruff as extra linter and formatter: both in dep...
(QB_NEW_EN)
[grammar] ~56-~56: There might be a mistake here.
Context: ...inters and formatters with the resource from Google SRE book - Add doctest (#34) ##...
(QB_NEW_EN)
[grammar] ~63-~63: There might be a mistake here.
Context: ...ocumentations for all the features (#20) - Quick sort implementation for hypothesis...
(QB_NEW_EN)
README.md
[grammar] ~37-~37: There might be a mistake here.
Context: ...r the prompts to customize your project: - Project name - Author information ...
(QB_NEW_EN)
[grammar] ~38-~38: There might be a mistake here.
Context: ...ustomize your project: - Project name - Author information - GitHub username ...
(QB_NEW_EN)
[grammar] ~39-~39: There might be a mistake here.
Context: ... - Project name - Author information - GitHub username - Package description...
(QB_NEW_EN)
[grammar] ~40-~40: There might be a mistake here.
Context: ... Author information - GitHub username - Package description - Python versions...
(QB_NEW_EN)
[grammar] ~41-~41: There might be a mistake here.
Context: ...GitHub username - Package description - Python versions to support - Optional...
(QB_NEW_EN)
[grammar] ~42-~42: There might be a mistake here.
Context: ...cription - Python versions to support - Optional features (docs, pre-commit, Git...
(QB_NEW_EN)
🪛 markdownlint-cli2 (0.17.2)
{{cookiecutter.package_name}}/README.md
3-3: Bare URL used
(MD034, no-bare-urls)
4-4: Bare URL used
(MD034, no-bare-urls)
5-5: Bare URL used
(MD034, no-bare-urls)
6-6: Bare URL used
(MD034, no-bare-urls)
15-15: Bare URL used
(MD034, no-bare-urls)
17-17: Bare URL used
(MD034, no-bare-urls)
20-20: Bare URL used
(MD034, no-bare-urls)
{{cookiecutter.package_name}}/CHANGELOG.md
27-27: Unordered list style
Expected: asterisk; Actual: dash
(MD004, ul-style)
31-31: Unordered list style
Expected: asterisk; Actual: dash
(MD004, ul-style)
37-37: Unordered list style
Expected: asterisk; Actual: dash
(MD004, ul-style)
38-38: Unordered list style
Expected: asterisk; Actual: dash
(MD004, ul-style)
44-44: Unordered list style
Expected: asterisk; Actual: dash
(MD004, ul-style)
45-45: Unordered list style
Expected: asterisk; Actual: dash
(MD004, ul-style)
46-46: Unordered list style
Expected: asterisk; Actual: dash
(MD004, ul-style)
47-47: Unordered list style
Expected: asterisk; Actual: dash
(MD004, ul-style)
48-48: Unordered list style
Expected: asterisk; Actual: dash
(MD004, ul-style)
49-49: Unordered list style
Expected: asterisk; Actual: dash
(MD004, ul-style)
55-55: Unordered list style
Expected: asterisk; Actual: dash
(MD004, ul-style)
56-56: Unordered list style
Expected: asterisk; Actual: dash
(MD004, ul-style)
57-57: Unordered list style
Expected: asterisk; Actual: dash
(MD004, ul-style)
63-63: Unordered list style
Expected: asterisk; Actual: dash
(MD004, ul-style)
64-64: Unordered list style
Expected: asterisk; Actual: dash
(MD004, ul-style)
68-68: Unordered list style
Expected: asterisk; Actual: dash
(MD004, ul-style)
72-72: Unordered list style
Expected: asterisk; Actual: dash
(MD004, ul-style)
78-78: Unordered list style
Expected: asterisk; Actual: dash
(MD004, ul-style)
84-84: Unordered list style
Expected: asterisk; Actual: dash
(MD004, ul-style)
🪛 YAMLlint (1.37.1)
{{cookiecutter.package_name}}/mkdocs.yml
[error] 3-3: syntax error: expected , but found ''
(syntax)
{{cookiecutter.package_name}}/.github/workflows/test.yaml
[error] 35-35: syntax error: found character '%' that cannot start any token
(syntax)
🔇 Additional comments (8)
{{cookiecutter.package_name}}/.pre-commit-config.yaml (2)
1-9
: Pre-commit base hooks look goodSolid baseline: YAML checks, EOL/trailing whitespace fixes, large-file guard. Good choices for a template.
10-16
: Ruff hook configuration looks goodRunning ruff with --fix followed by ruff-format is a sensible default for generated repos.
{{cookiecutter.package_name}}/{{cookiecutter.package_name}}/hello.py (1)
4-14
: LGTM: Simple, pure function with clear doctest.The hello() implementation and documentation look good and are easy to test and maintain.
{{cookiecutter.package_name}}/mkdocs.yml (1)
1-73
: FYI on YAML lints against templated files.The reported YAML syntax error is from Jinja control blocks and placeholders prior to rendering. Consider excluding cookiecutter templates from YAML linting or adding a pre-generation lint step.
{{cookiecutter.package_name}}/.github/workflows/test.yaml (2)
18-22
: Good use of Jinja raw to preserve GitHub expressions.The $ + raw-wrapped {{ matrix.python-version }} approach will render correctly post-cookiecutter.
35-35
: About the YAMLlint error on line 35.This error is due to Jinja control structures ({%- if ... %}) in a yet-to-be-rendered template. It’s safe to ignore at template time; consider excluding template files from YAML linting.
hooks/post_gen_project.py (1)
63-81
: Verify documentation URLs in pyproject.toml templateBefore merging, please confirm that your template’s
pyproject.toml
indeed has unconditional “Documentation” and “Release Notes” URL entries, and update it so they only appear whencookiecutter.include_docs
is"y"
.• Locate your
pyproject.toml
Jinja template (e.g.{{cookiecutter.project_slug}}/pyproject.toml
or similar)
• Wrap anydocumentation = "…"
orrelease-notes = "…"
keys in a Jinja conditional:{% if cookiecutter.include_docs == "y" %} documentation = "https://{{ cookiecutter.github_username }}.github.io/{{ cookiecutter.repo_name }}/" release-notes = "https://{{ cookiecutter.github_username }}.github.io/{{ cookiecutter.repo_name }}/CHANGELOG.html" {% endif %}• Ensure
update_pyproject_toml()
does not reinsert those keys unconditionally.By gating those entries, you’ll avoid generating broken URLs when
include_docs == "n"
.{{cookiecutter.package_name}}/pyproject.toml (1)
47-53
: Gate docs-related URLs behindinclude_docs
To prevent broken links when documentation isn’t generated, wrap the “Documentation” and “Release Notes” entries in a Jinja conditional that checks
cookiecutter.include_docs
.• File:
{{cookiecutter.package_name}}/pyproject.toml
• Section:[project.urls]
(around lines 47–53)Suggested diff:
[project.urls] "Homepage" = "https://{{ cookiecutter.github_username }}.github.io/{{ cookiecutter.package_name }}" "Bug Tracker" = "https://github.com/{{ cookiecutter.github_username }}/{{ cookiecutter.package_name }}/issues" -"Documentation" = "https://{{ cookiecutter.github_username }}.github.io/{{ cookiecutter.package_name }}" -"Release Notes" = "https://{{ cookiecutter.github_username }}.github.io/{{ cookiecutter.package_name }}/changelog/" +{%- if cookiecutter.include_docs == "y" %} + "Documentation" = "https://{{ cookiecutter.github_username }}.github.io/{{ cookiecutter.package_name }}" + "Release Notes" = "https://{{ cookiecutter.github_username }}.github.io/{{ cookiecutter.package_name }}/changelog/" +{%- endif %} "Source Code" = "https://github.com/{{ cookiecutter.github_username }}/{{ cookiecutter.package_name }}"Please test by generating the project with
include_docs = "n"
to confirm those entries are omitted.
name: Build Docs | ||
|
||
on: | ||
push: | ||
branches: [ master, main ] | ||
pull_request: | ||
branches: [ master, main ] | ||
|
||
jobs: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Set explicit token permissions (write needed to push gh-pages)
MkDocs gh-deploy pushes to gh-pages. Without contents: write, this can fail depending on repo defaults. Recommend read by default, write only for deploy job.
name: Build Docs
on:
push:
branches: [ master, main ]
pull_request:
branches: [ master, main ]
+
+permissions:
+ contents: read
And in deploy job:
deploy-docs:
runs-on: ubuntu-latest
if: github.ref == 'refs/heads/master' || github.ref == 'refs/heads/main'
needs: build-docs
+ permissions:
+ contents: write
🤖 Prompt for AI Agents
{{cookiecutter.package_name}}/.github/workflows/build_docs.yaml lines 1-9: the
workflow does not declare explicit token permissions so gh-deploy may fail to
push to gh-pages; add a top-level minimal permissions block (e.g., contents:
read) to restrict default scope, and in the deploy job override permissions to
allow pushing (e.g., permissions: contents: write) so the job that runs MkDocs
gh-deploy can push to gh-pages; ensure the deploy job uses the default
GITHUB_TOKEN (or the appropriate token) so these permissions apply.
steps: | ||
- uses: actions/checkout@v4 | ||
- name: Set up Python | ||
uses: actions/setup-python@v4 | ||
with: | ||
python-version: "3.9" | ||
|
||
- name: Install uv | ||
uses: astral-sh/setup-uv@v3 | ||
with: | ||
version: "latest" | ||
|
||
- name: Install dependencies | ||
run: | | ||
uv sync --extra docs --dev | ||
|
||
- name: Build documentation | ||
run: | | ||
uv run mkdocs build --strict |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fix YAML indentation for steps (workflow will fail to parse)
List items under "steps:" must be indented beneath it. Currently they are at the same indent level as "steps:" which breaks parsing.
- steps:
- - uses: actions/checkout@v4
- - name: Set up Python
- uses: actions/setup-python@v4
- with:
- python-version: "3.9"
- - name: Install uv
- uses: astral-sh/setup-uv@v3
- with:
- version: "latest"
- - name: Install dependencies
- run: |
- uv sync --extra docs --dev
- - name: Build documentation
- run: |
- uv run mkdocs build --strict
+ steps:
+ - uses: actions/checkout@v4
+ - name: Set up Python
+ uses: actions/setup-python@v4
+ with:
+ python-version: "3.9"
+ - name: Install uv
+ uses: astral-sh/setup-uv@v3
+ with:
+ version: "latest"
+ - name: Install dependencies
+ run: |
+ uv sync --extra docs --dev
+ - name: Build documentation
+ run: |
+ uv run mkdocs build --strict
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
steps: | |
- uses: actions/checkout@v4 | |
- name: Set up Python | |
uses: actions/setup-python@v4 | |
with: | |
python-version: "3.9" | |
- name: Install uv | |
uses: astral-sh/setup-uv@v3 | |
with: | |
version: "latest" | |
- name: Install dependencies | |
run: | | |
uv sync --extra docs --dev | |
- name: Build documentation | |
run: | | |
uv run mkdocs build --strict | |
steps: | |
- uses: actions/checkout@v4 | |
- name: Set up Python | |
uses: actions/setup-python@v4 | |
with: | |
python-version: "3.9" | |
- name: Install uv | |
uses: astral-sh/setup-uv@v3 | |
with: | |
version: "latest" | |
- name: Install dependencies | |
run: | | |
uv sync --extra docs --dev | |
- name: Build documentation | |
run: | | |
uv run mkdocs build --strict |
🤖 Prompt for AI Agents
In {{cookiecutter.package_name}}/.github/workflows/build_docs.yaml around lines
13 to 31, the top-level list items for the job steps are not indented under
"steps:" which makes the YAML invalid; fix by indenting every step entry (the
lines starting with "- uses:" and "- name:") one additional indentation level
under "steps:", and ensure their nested keys (uses, name, with, run, and the
block contents) are consistently indented further beneath each step so the steps
list and their inner mappings form valid YAML.
steps: | ||
- uses: actions/checkout@v4 | ||
with: | ||
fetch-depth: 0 | ||
- name: Set up Python | ||
uses: actions/setup-python@v4 | ||
with: | ||
python-version: "3.9" | ||
|
||
- name: Install uv | ||
uses: astral-sh/setup-uv@v3 | ||
with: | ||
version: "latest" | ||
|
||
- name: Install dependencies | ||
run: | | ||
uv sync --extra docs --dev | ||
|
||
- name: Deploy documentation | ||
run: | | ||
uv run mkdocs gh-deploy --force |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fix indentation for deploy steps as well
Same indentation issue in the deploy-docs job.
- steps:
- - uses: actions/checkout@v4
- with:
- fetch-depth: 0
- - name: Set up Python
- uses: actions/setup-python@v4
- with:
- python-version: "3.9"
- - name: Install uv
- uses: astral-sh/setup-uv@v3
- with:
- version: "latest"
- - name: Install dependencies
- run: |
- uv sync --extra docs --dev
- - name: Deploy documentation
- run: |
- uv run mkdocs gh-deploy --force
+ steps:
+ - uses: actions/checkout@v4
+ with:
+ fetch-depth: 0
+ - name: Set up Python
+ uses: actions/setup-python@v4
+ with:
+ python-version: "3.9"
+ - name: Install uv
+ uses: astral-sh/setup-uv@v3
+ with:
+ version: "latest"
+ - name: Install dependencies
+ run: |
+ uv sync --extra docs --dev
+ - name: Deploy documentation
+ run: |
+ uv run mkdocs gh-deploy --force
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
steps: | |
- uses: actions/checkout@v4 | |
with: | |
fetch-depth: 0 | |
- name: Set up Python | |
uses: actions/setup-python@v4 | |
with: | |
python-version: "3.9" | |
- name: Install uv | |
uses: astral-sh/setup-uv@v3 | |
with: | |
version: "latest" | |
- name: Install dependencies | |
run: | | |
uv sync --extra docs --dev | |
- name: Deploy documentation | |
run: | | |
uv run mkdocs gh-deploy --force | |
steps: | |
- uses: actions/checkout@v4 | |
with: | |
fetch-depth: 0 | |
- name: Set up Python | |
uses: actions/setup-python@v4 | |
with: | |
python-version: "3.9" | |
- name: Install uv | |
uses: astral-sh/setup-uv@v3 | |
with: | |
version: "latest" | |
- name: Install dependencies | |
run: | | |
uv sync --extra docs --dev | |
- name: Deploy documentation | |
run: | | |
uv run mkdocs gh-deploy --force |
🤖 Prompt for AI Agents
In {{cookiecutter.package_name}}/.github/workflows/build_docs.yaml around lines
38 to 58, the deploy steps under the job share incorrect indentation (deploy
steps aligned with other top-level steps) which can break the workflow; fix by
indenting the "Install uv", "Install dependencies", and "Deploy documentation"
step blocks so they are nested under the correct job/steps mapping (match the
same indentation level as the preceding steps in that job), ensuring each step
uses the same two-space/consistent indentation as the rest of the YAML file.
```python | ||
from {{ cookiecutter.package_name }} import hello | ||
|
||
print(hello()) | ||
``` |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Quick Start import is incorrect and will raise a TypeError.
from {{ cookiecutter.package_name }} import hello imports the hello module, not the hello() function; calling hello() will fail. Either re-export hello in init.py or import the function from the submodule here. Since init.py (in this template) doesn’t re-export, fix the snippet.
-```python
-from {{ cookiecutter.package_name }} import hello
-
-print(hello())
-```
+```python
+from {{ cookiecutter.package_name }}.hello import hello
+
+print(hello())
+```
Alternative (if you prefer the original import style): export hello in {{cookiecutter.package_name}}/init.py by adding:
from .hello import hello # re-export for convenience
__all__ = ["hello"]
🤖 Prompt for AI Agents
In {{cookiecutter.package_name}}/docs/index.md around lines 13 to 17 the Quick
Start uses "from {{ cookiecutter.package_name }} import hello" which imports the
module, causing a TypeError when calling hello(); update the snippet to import
the function from the submodule (i.e., import hello from
{{cookiecutter.package_name}}.hello) so print(hello()) works, or alternatively
add a re-export in {{cookiecutter.package_name}}/__init__.py by importing and
exposing hello (and adding it to __all__) so the original import style becomes
valid.
@@ -0,0 +1,21 @@ | |||
MIT License | |||
|
|||
Copyright (c) 2023 Mathew Shen |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Template the copyright header (year and name)
Hard-coded “2023 Mathew Shen” will be wrong for most users and over time. Use cookiecutter vars (and a dynamic year).
-Copyright (c) 2023 Mathew Shen
+Copyright (c) {{ cookiecutter.year }} {{ cookiecutter.full_name }}
If not already present, add to cookiecutter.json:
{
"full_name": "Your Name",
"year": "{% now 'utc', '%Y' %}"
}
🤖 Prompt for AI Agents
In {{cookiecutter.package_name}}/LICENSE around line 3, the copyright header is
hard-coded as “2023 Mathew Shen”; replace it with cookiecutter template
variables so it renders the package author and current year (e.g. use
{{cookiecutter.year}} and {{cookiecutter.full_name}} in the LICENSE file), and
if cookiecutter.json does not already include these keys add "full_name" and
"year" (with year set to "{% now 'utc', '%Y' %}") so new projects populate
correctly.
"Operating System :: OS Independent", | ||
# PYTHON_VERSION_CLASSIFIERS_PLACEHOLDER | ||
] | ||
requires-python = ">= {{ cookiecutter.python_min_version }}" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
💡 Verification agent
🧩 Analysis chain
Honor max Python version in requires-python.
PR goal includes configurable min/max versions. Encode the upper bound using the “next minor” convention.
-requires-python = ">= {{ cookiecutter.python_min_version }}"
+requires-python = ">= {{ cookiecutter.python_min_version }}, < {{ cookiecutter.python_max_version.split('.')[0] }}.{{ (cookiecutter.python_max_version.split('.')[1] | int) + 1 }}"
After generation, ensure pip shows the correct Requires-Python in metadata: python -m build && twine check dist/*
.
🏁 Script executed:
#!/usr/bin/env bash
set -e
# Locate cookiecutter.json
found=$(fd -e json cookiecutter.json || true)
echo "cookiecutter.json path: $found"
if [ -n "$found" ]; then
echo "---- cookiecutter.json content ----"
cat "$found"
echo "---- Searching for python_max_version ----"
rg -n "python_max_version" -C2 "$found" || true
fi
# Locate all pyproject.toml files
pyfiles=$(fd -e toml pyproject.toml)
echo "pyproject.toml files found:"
echo "$pyfiles"
for file in $pyfiles; do
echo "==== $file ===="
echo "---- First 30 lines ----"
head -n 30 "$file"
echo "---- Searching for requires-python ----"
rg -n "requires-python" -C2 "$file" || true
done
Length of output: 4654
Add an upper bound to requires-python
To honor the configurable max‐version, the requires-python
field must include an upper bound using the “next minor” convention.
• File: {{cookiecutter.package_name}}/pyproject.toml
(around line 17)
• Replace:
- requires-python = ">= {{ cookiecutter.python_min_version }}"
with:
requires-python = ">= {{ cookiecutter.python_min_version }}, < {{ cookiecutter.python_max_version.split('.')[0] }}.{{ (cookiecutter.python_max_version.split('.')[1] | int) + 1 }}"
After making this change, build and inspect the wheel metadata to confirm the upper bound is applied:
python -m build && twine check dist/*
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
requires-python = ">= {{ cookiecutter.python_min_version }}" | |
requires-python = ">= {{ cookiecutter.python_min_version }}, < {{ cookiecutter.python_max_version.split('.')[0] }}.{{ (cookiecutter.python_max_version.split('.')[1] | int) + 1 }}" |
🤖 Prompt for AI Agents
In {{cookiecutter.package_name}}/pyproject.toml around line 17, the
requires-python field only sets a lower bound and must include an upper bound
using the “next minor” convention (e.g., if python_min_version is X.Y, require
">= X.Y, < X.(Y+1)"); update the requires-python entry accordingly to compute
and include that next-minor upper bound, save the file, then build and verify
the wheel metadata with: python -m build && twine check dist/* to confirm the
upper bound appears.
[](https://pypi.org/project/{{ cookiecutter.package_name }}/) | ||
[](https://pypi.org/project/{{ cookiecutter.package_name }}/) | ||
[](https://pepy.tech/projects/{{ cookiecutter.package_name }}) | ||
[](https://github.com/{{ cookiecutter.github_username }}/{{ cookiecutter.package_name }}/blob/master/LICENSE) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Make license badge branch-agnostic (master → HEAD).
Hardcoding master will 404 if the default branch is main. Use HEAD to work for both.
-[](https://github.com/{{ cookiecutter.github_username }}/{{ cookiecutter.package_name }}/blob/master/LICENSE)
+[](https://github.com/{{ cookiecutter.github_username }}/{{ cookiecutter.package_name }}/blob/HEAD/LICENSE)
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
[](https://github.com/{{ cookiecutter.github_username }}/{{ cookiecutter.package_name }}/blob/master/LICENSE) | |
[](https://github.com/{{ cookiecutter.github_username }}/{{ cookiecutter.package_name }}/blob/HEAD/LICENSE) |
🧰 Tools
🪛 markdownlint-cli2 (0.17.2)
6-6: Bare URL used
(MD034, no-bare-urls)
🤖 Prompt for AI Agents
In {{cookiecutter.package_name}}/README.md around line 6, the GitHub license
badge link hardcodes the "master" branch which breaks repositories using "main";
update the badge URL to use "HEAD" instead of "master" so the badge points to
the repository's default branch and won't 404.
[](https://codecov.io/gh/{{ cookiecutter.github_username }}/{{ cookiecutter.package_name }}) | ||
{%- endif %} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Parametrize Codecov badge branch (avoid master-only).
If the repo default branch is main, the badge may be wrong. Either omit the branch or template it. Recommended: add a cookiecutter default_branch variable (see cookiecutter.json comment) and use it here.
-{%- if cookiecutter.include_codecov == "y" %}
-[](https://codecov.io/gh/{{ cookiecutter.github_username }}/{{ cookiecutter.package_name }})
+{%- if cookiecutter.include_codecov == "y" %}
+[](https://codecov.io/gh/{{ cookiecutter.github_username }}/{{ cookiecutter.package_name }})
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
[](https://codecov.io/gh/{{ cookiecutter.github_username }}/{{ cookiecutter.package_name }}) | |
{%- endif %} | |
{%- if cookiecutter.include_codecov == "y" %} | |
[](https://codecov.io/gh/{{ cookiecutter.github_username }}/{{ cookiecutter.package_name }}) | |
{%- endif %} |
🧰 Tools
🪛 markdownlint-cli2 (0.17.2)
20-20: Bare URL used
(MD034, no-bare-urls)
🤖 Prompt for AI Agents
In {{cookiecutter.package_name}}/README.md around lines 20-21 the Codecov badge
hardcodes the branch as "master", which breaks projects whose default branch is
"main"; add a cookiecutter variable (e.g., default_branch) in cookiecutter.json
with a sensible default and replace the hardcoded "master" in the badge URL with
that templated variable (or remove the /branch/... segment entirely to avoid
pinning a branch), and also update cookiecutter.json comments to document the
new default_branch option.
"package_name": "my_python_package", | ||
"project_short_description": "A modern Python package", | ||
"author_name": "Your Name", | ||
"author_email": "[email protected]", | ||
"github_username": "yourusername", | ||
"version": "0.1.0", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Separate distribution name from import package name to avoid invalid module names.
Using a single package_name for both the PyPI distribution and the Python import package breaks when users include hyphens (valid on PyPI, invalid for Python modules). Introduce package_import_name and use it for the inner Python package directory and import paths.
{
"package_name": "my_python_package",
+ "package_import_name": "my_python_package",
"project_short_description": "A modern Python package",
"author_name": "Your Name",
"author_email": "[email protected]",
"github_username": "yourusername",
"version": "0.1.0",
+ "default_branch": ["main", "master"],
Follow-ups (outside this file):
- Rename the inner package directory to {{ cookiecutter.package_import_name }}/
- In pyproject.toml: [project].name = "{{ cookiecutter.package_name }}", but source layout, package includes, and any module imports should reference package_import_name.
- Replace occurrences of {{ cookiecutter.package_name }} in import paths with {{ cookiecutter.package_import_name }}.
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
"package_name": "my_python_package", | |
"project_short_description": "A modern Python package", | |
"author_name": "Your Name", | |
"author_email": "[email protected]", | |
"github_username": "yourusername", | |
"version": "0.1.0", | |
"package_name": "my_python_package", | |
"package_import_name": "my_python_package", | |
"project_short_description": "A modern Python package", | |
"author_name": "Your Name", | |
"author_email": "[email protected]", | |
"github_username": "yourusername", | |
"version": "0.1.0", | |
"default_branch": ["main", "master"], |
🤖 Prompt for AI Agents
In cookiecutter.json around lines 2 to 7, the template uses a single
package_name for both the PyPI distribution and the Python import package which
fails when distribution names contain hyphens; add a new key package_import_name
(e.g. a sanitized Python identifier) and update the template so package_name
remains the distribution name while package_import_name is used for the inner
package directory and import paths; follow up by renaming the inner package
directory to {{ cookiecutter.package_import_name }}, setting [project].name =
"{{ cookiecutter.package_name }}" in pyproject.toml, and replacing any
occurrences of {{ cookiecutter.package_name }} in imports or package includes
with {{ cookiecutter.package_import_name }}.
"python_min_version": ["3.9", "3.10", "3.11", "3.12", "3.13"], | ||
"python_max_version": ["3.9", "3.10", "3.11", "3.12", "3.13"], |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Guard against selecting an invalid Python version range.
It’s possible to pick min > max. Add a post_gen validation to fail fast or auto-correct.
Proposed post_gen snippet (in hooks/post_gen_project.py):
min_v = tuple(map(int, "{{ cookiecutter.python_min_version }}".split(".")))
max_v = tuple(map(int, "{{ cookiecutter.python_max_version }}".split(".")))
if min_v > max_v:
raise SystemExit(f"python_min_version ({min_v}) cannot exceed python_max_version ({max_v}).")
🤖 Prompt for AI Agents
In cookiecutter.json around lines 8-9 the template allows selecting a
python_min_version that can be greater than python_max_version; add a
hooks/post_gen_project.py that parses both selected version strings into tuples
of integers, compares them, and either raises a SystemExit with a clear message
if min_v > max_v or swaps/auto-corrects them before continuing (choose one
behavior and implement consistently); ensure the validation runs immediately
after project generation and uses the cookiecutter context values "{{
cookiecutter.python_min_version }}" and "{{ cookiecutter.python_max_version }}"
when building the tuples.
Users can now generate customized Python packages by running: cookiecutter https://github.com/shenxiangzhuang/mppt.git
🤖 Generated with Claude Code
Summary by CodeRabbit