-
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?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
{ | ||
"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", | ||
"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"], | ||
Comment on lines
+8
to
+9
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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
|
||
"license": ["MIT", "Apache-2.0", "BSD-3-Clause", "GPL-3.0", "LGPL-2.1"], | ||
"include_docs": ["y", "n"], | ||
"include_pre_commit": ["y", "n"], | ||
"include_github_actions": ["y", "n"], | ||
"include_codecov": ["y", "n"], | ||
"development_status": [ | ||
"1 - Planning", | ||
"2 - Pre-Alpha", | ||
"3 - Alpha", | ||
"4 - Beta", | ||
"5 - Production/Stable", | ||
"6 - Mature", | ||
"7 - Inactive" | ||
], | ||
"command_line_interface": ["Click", "Argparse", "None"], | ||
"_copy_without_render": [ | ||
"*.svg", | ||
"*.png", | ||
"*.jpg", | ||
"*.jpeg", | ||
"*.gif", | ||
"docs/overrides/main.html" | ||
] | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,84 @@ | ||
#!/usr/bin/env python3 | ||
"""Post-generation hook for cookiecutter template.""" | ||
|
||
import os | ||
import shutil | ||
import re | ||
|
||
|
||
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): | ||
shutil.rmtree(file_path) | ||
else: | ||
os.remove(file_path) | ||
|
||
|
||
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 | ||
|
||
|
||
def update_pyproject_toml(): | ||
"""Update pyproject.toml with correct Python version configuration.""" | ||
min_version = "{{ cookiecutter.python_min_version }}" | ||
max_version = "{{ cookiecutter.python_max_version }}" | ||
|
||
# Generate the list of supported Python versions | ||
python_versions = generate_python_versions(min_version, max_version) | ||
|
||
# Read the current pyproject.toml | ||
with open("pyproject.toml", "r") as f: | ||
content = f.read() | ||
|
||
# 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) | ||
content = content.replace(" # PYTHON_VERSION_CLASSIFIERS_PLACEHOLDER", replacement) | ||
|
||
# Write back the updated content | ||
with open("pyproject.toml", "w") as f: | ||
f.write(content) | ||
|
||
|
||
def main(): | ||
"""Remove files/directories based on configuration and fix Python versions.""" | ||
|
||
# Update Python version configuration | ||
update_pyproject_toml() | ||
|
||
# Remove docs if not included | ||
if "{{ cookiecutter.include_docs }}" == "n": | ||
remove_file_or_dir("docs") | ||
remove_file_or_dir("mkdocs.yml") | ||
|
||
# Remove pre-commit config if not included | ||
if "{{ cookiecutter.include_pre_commit }}" == "n": | ||
remove_file_or_dir(".pre-commit-config.yaml") | ||
|
||
# Remove GitHub Actions if not included | ||
if "{{ cookiecutter.include_github_actions }}" == "n": | ||
remove_file_or_dir(".github") | ||
|
||
|
||
if __name__ == "__main__": | ||
main() |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -31,6 +31,7 @@ dev = [ | |
"pytest-cov", | ||
"pytest-sugar", | ||
"hypothesis>=6.112.0", | ||
"cookiecutter", | ||
] | ||
docs = [ | ||
"mkdocs", | ||
|
Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
@@ -0,0 +1,58 @@ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
name: Build Docs | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
on: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
push: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
branches: [ master, main ] | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
pull_request: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
branches: [ master, main ] | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
jobs: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Comment on lines
+1
to
+9
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
build-docs: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
runs-on: ubuntu-latest | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
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 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Comment on lines
+13
to
+31
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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
Suggested change
🤖 Prompt for AI Agents
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
deploy-docs: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
runs-on: ubuntu-latest | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
if: github.ref == 'refs/heads/master' || github.ref == 'refs/heads/main' | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
needs: build-docs | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
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 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Comment on lines
+38
to
+58
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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
Suggested change
🤖 Prompt for AI Agents
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,44 @@ | ||
name: Test | ||
|
||
on: | ||
push: | ||
branches: [ master, main ] | ||
pull_request: | ||
branches: [ master, main ] | ||
|
||
jobs: | ||
test: | ||
runs-on: ubuntu-latest | ||
strategy: | ||
matrix: | ||
python-version: ["3.9", "3.10", "3.11", "3.12", "3.13"] | ||
|
||
steps: | ||
- uses: actions/checkout@v4 | ||
- name: Set up Python ${% raw %}{{ matrix.python-version }}{% endraw %} | ||
uses: actions/setup-python@v4 | ||
with: | ||
python-version: ${% raw %}{{ matrix.python-version }}{% endraw %} | ||
|
||
- name: Install uv | ||
uses: astral-sh/setup-uv@v3 | ||
with: | ||
version: "latest" | ||
|
||
- name: Install dependencies | ||
run: | | ||
uv sync --all-extras --dev | ||
|
||
- name: Run tests | ||
run: | | ||
uv run pytest --cov={{ cookiecutter.package_name }} --cov-report=xml | ||
{%- if cookiecutter.include_codecov == "y" %} | ||
|
||
- name: Upload coverage to Codecov | ||
uses: codecov/codecov-action@v3 | ||
with: | ||
file: ./coverage.xml | ||
flags: unittests | ||
name: codecov-umbrella | ||
fail_ci_if_error: false | ||
{%- endif %} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
repos: | ||
- repo: https://github.com/pre-commit/pre-commit-hooks | ||
rev: v4.6.0 | ||
hooks: | ||
- id: check-yaml | ||
- id: end-of-file-fixer | ||
- id: trailing-whitespace | ||
- id: check-added-large-files | ||
|
||
- repo: https://github.com/astral-sh/ruff-pre-commit | ||
rev: v0.6.9 | ||
hooks: | ||
- id: ruff | ||
args: [--fix, --exit-non-zero-on-fix] | ||
- id: ruff-format | ||
|
||
- repo: https://github.com/pre-commit/mirrors-mypy | ||
rev: v1.11.2 | ||
hooks: | ||
- id: mypy | ||
additional_dependencies: [types-all] |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,84 @@ | ||
# Changelog | ||
|
||
## [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 |
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.
Follow-ups (outside this file):
📝 Committable suggestion
🤖 Prompt for AI Agents