diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index 22db34c..a2652e3 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -4,26 +4,72 @@ "customizations": { "vscode": { "settings": { - "python.testing.pytestEnabled": true, - "editor.formatOnSave": true, - "editor.codeActionsOnSave": { - "source.organizeImports": true, - "source.fixAll.ruff": true - }, - "[python]": { - "editor.defaultFormatter": "charliermarsh.ruff", - "editor.codeActionsOnSave": { - "source.organizeImports.ruff": true, - "source.fixAll.ruff": true + "todo-tree.regex.enableMultiLine": true, + "editor.rulers": [ + { + "column": 72, + "color": "#4a4f63" + }, + { + "column": 88, + "color": "#7a8ad1" + } + ], + "autoDocstring.docstringFormat": "google-notypes", + "autoDocstring.startOnNewLine": true, + "better-comments.tags": [ + { + "tag": "!!", + "color": "#F6FF33", + "strikethrough": false, + "backgroundColor": "transparent" + }, + { + "tag": "#!", + "color": "#3498DB", + "strikethrough": false, + "backgroundColor": "transparent" + }, + { + "tag": "TODO", + "color": "#FF8C00", + "strikethrough": false, + "backgroundColor": "transparent" + }, + { + "tag": "//", + "color": "#68FF33", + "strikethrough": false, + "backgroundColor": "transparent" + }, + { + "tag": "**", + "color": "#FF33EC", + "strikethrough": false, + "backgroundColor": "transparent" } + ], + "[python]": { + "editor.formatOnType": true + }, + "python.defaultInterpreterPath": "/home/jovyan/envs/env/bin/python", + "[jsonc]": { + "editor.defaultFormatter": "vscode.json-language-features" + }, + "[json]": { + "editor.defaultFormatter": "esbenp.prettier-vscode" }, - "editor.rulers": [88], - "ruff.lint.enable": true, - "ruff.format.enable": true, - "ruff.organizeImports": true, - "ruff.fixAll": true + "prettier.printWidth": 88, + "prettier.proseWrap": "always" }, - "extensions": ["ms-python.python", "charliermarsh.ruff"] + "extensions": [ + "njpwerner.autodocstring", + "aaron-bond.better-comments", + "esbenp.prettier-vscode", + "ms-python.python", + "ms-python.debugpy", + "Gruntfuggly.todo-tree" + ] } }, "features": { diff --git a/.devcontainer/setup.sh b/.devcontainer/setup.sh index 033415e..658115b 100644 --- a/.devcontainer/setup.sh +++ b/.devcontainer/setup.sh @@ -1,14 +1,10 @@ #!/bin/bash + set -e -echo "Checking for uv..." -if ! command -v uv &> /dev/null; then - echo "Installing uv..." - curl -LsSf https://astral.sh/uv/install.sh | sh > /dev/null 2>&1 - echo "✅ uv installed." -else - echo "✅ uv already installed." -fi +echo "Installing uv..." +curl -LsSf https://astral.sh/uv/install.sh | sh > /dev/null 2>&1 +echo "✅ uv installed." echo "Installing system dependencies..." sudo apt-get update > /dev/null 2>&1 diff --git a/.github/actions/build-mkdocs/action.yml b/.github/actions/build-mkdocs/action.yml index e97a5cc..fb2ddd0 100644 --- a/.github/actions/build-mkdocs/action.yml +++ b/.github/actions/build-mkdocs/action.yml @@ -40,7 +40,7 @@ runs: echo "Deploying Docs Version: ${{ inputs.docs-version }}" uv run mike deploy --push --update-aliases "${{ inputs.docs-version }}" latest - - name: Set Default Version + - name: Set Default Version to Docs shell: bash run: | echo "Setting 'Latest' as Default Version" diff --git a/.github/actions/setup-python-env/action.yml b/.github/actions/setup-python-env/action.yml index 0dfdf2b..2a553f6 100644 --- a/.github/actions/setup-python-env/action.yml +++ b/.github/actions/setup-python-env/action.yml @@ -18,9 +18,11 @@ runs: using: composite steps: - name: Install uv and set the Python version - uses: astral-sh/setup-uv@v5 + uses: astral-sh/setup-uv@v7 with: + version: "0.9.23" python-version: ${{ inputs.src-python-version }} + enable-cache: true - name: Install dependencies with uv id: install-deps diff --git a/.github/workflows/workflow.yml b/.github/workflows/workflow.yml index 3ab84cf..706cfcc 100644 --- a/.github/workflows/workflow.yml +++ b/.github/workflows/workflow.yml @@ -2,7 +2,7 @@ name: CI/CD Pipeline on: push: - branches: ["*"] + branches: [main, dev] pull_request: branches: [main, dev] @@ -18,14 +18,14 @@ jobs: - name: Checkout Repository uses: actions/checkout@v6 - - name: Setup Python & Install Dependencies + - name: Setup Python Environment uses: ./.github/actions/setup-python-env with: src-python-version: ${{ env.SRC_PYTHON_VERSION }} uv-group: "pipeline" uv-extra: "--all-extras" - build-deploy-mkdocs: + build-deploy-docs: if: github.ref == 'refs/heads/main' name: Build MkDocs Documentation runs-on: ubuntu-latest @@ -42,7 +42,7 @@ jobs: with: fetch-depth: 0 - - name: Setup Python & Install Dependencies + - name: Setup Python Environment uses: ./.github/actions/setup-python-env with: src-python-version: ${{ env.SRC_PYTHON_VERSION }} @@ -52,7 +52,7 @@ jobs: id: version uses: ./.github/actions/obtain-version - - name: Build MkDocs Site with Mike + - name: Build Documentation uses: ./.github/actions/build-mkdocs with: docs-version: ${{ steps.version.outputs.version }} @@ -61,7 +61,7 @@ jobs: if: github.ref == 'refs/heads/main' name: Create Release runs-on: ubuntu-latest - needs: build-deploy-mkdocs + needs: build-deploy-docs permissions: contents: write @@ -72,7 +72,7 @@ jobs: with: fetch-depth: 0 - - name: Setup Python & Install Dependencies + - name: Setup Python Environment uses: ./.github/actions/setup-python-env with: src-python-version: ${{ env.SRC_PYTHON_VERSION }} diff --git a/.gitignore b/.gitignore index fddd1a4..87a766c 100644 --- a/.gitignore +++ b/.gitignore @@ -3,7 +3,6 @@ /saved_objects/ /runs/ __pycache__/ -.vscode/ .mypy_cache/ /results/ *build/ diff --git a/Makefile b/Makefile index 8302f19..5a5de12 100644 --- a/Makefile +++ b/Makefile @@ -1,17 +1,16 @@ -# Declare all phony targets -.PHONY: install clean doc pipeline all +.PHONY: setup \ + clean-cache-temp-files \ + doc \ + pipeline all -# Default target .DEFAULT_GOAL := all -# Install project dependencies -install: +setup: @echo "Installing dependencies..." @uv sync --all-extras @echo "✅ Dependencies installed." -# Clean cache and temporary files -clean: +clean-cache-temp-files: @echo "Cleaning cache and temporary files..." @find . -type d -name __pycache__ -exec rm -rf {} + @find . -type d -name .pytest_cache -exec rm -rf {} + @@ -19,15 +18,12 @@ clean: @find . -type f \( -name '*.pyc' -o -name '*.pyo' \) -delete @echo "✅ Clean complete." -# Serve documentation locally doc: @echo "Serving documentation..." @uv run mkdocs serve -# Run code checks and tests -pipeline: clean +pipeline: clean-cache-temp-files @echo "✅ Pipeline complete." -# Run full workflow including install and docs -all: install pipeline doc +all: setup pipeline doc @echo "✅ All tasks complete." diff --git a/README.md b/README.md index 5356c11..e9ba855 100644 --- a/README.md +++ b/README.md @@ -12,12 +12,12 @@

-# 🐍 Python Project Template +# Python Project Template Python Project Template provides a ready-to-use structure for Python projects, -integrating best practices for code quality, testing, security, documentation, and -CI/CD. It helps developers start new projects quickly with a maintainable and -professional foundation. +integrating best practices for code quality, testing, security, documentation, and CI/CD. +It helps developers start new projects quickly with a maintainable and professional +foundation. ## Features @@ -32,9 +32,9 @@ And more. ## Getting Started -Before starting, ensure that you have required Python installed and a virtual -environment set up. It is recommended to create an isolated environment (e.g., using -`venv`) to manage dependencies cleanly. Additionally, ensure that +Before starting, ensure that you have required Python installed and a virtual environment +set up. It is recommended to create an isolated environment (e.g., using `venv`) to +manage dependencies cleanly. Additionally, ensure that [`uv`](https://github.com/astral-sh/uv) is installed in your environment to handle grouped dependency installations. @@ -80,4 +80,3 @@ make all This ensures that the project environment is fully prepared for development and validation. - diff --git a/cookiecutter.json b/cookiecutter.json index 630f53e..7f2d90c 100644 --- a/cookiecutter.json +++ b/cookiecutter.json @@ -12,6 +12,7 @@ "mkdocs_repo_url": "https://github.com/user-name/repo-name", "mkdocs_site_url": "https://repo-name-web-site", "add_dev_container_folder": ["yes", "no"], + "add_vscode_folder": ["yes", "no"], "add_notebooks_folder": ["yes", "no"], "add_prompts_folder": ["yes", "no"], "_copy_without_render": ["*action.yml", "*.js"] diff --git a/docs/index.md b/docs/index.md index 02106a4..a5a0700 100644 --- a/docs/index.md +++ b/docs/index.md @@ -12,12 +12,12 @@

-# 🐍 Python Project Template +# Python Project Template Python Project Template provides a ready-to-use structure for Python projects, -integrating best practices for code quality, testing, security, documentation, and -CI/CD. It helps developers start new projects quickly with a maintainable and -professional foundation. +integrating best practices for code quality, testing, security, documentation, and CI/CD. +It helps developers start new projects quickly with a maintainable and professional +foundation. ## Features @@ -32,9 +32,9 @@ And more. ## Getting Started -Before starting, ensure that you have required Python installed and a virtual -environment set up. It is recommended to create an isolated environment (e.g., using -`venv`) to manage dependencies cleanly. Additionally, ensure that +Before starting, ensure that you have required Python installed and a virtual environment +set up. It is recommended to create an isolated environment (e.g., using `venv`) to +manage dependencies cleanly. Additionally, ensure that [`uv`](https://github.com/astral-sh/uv) is installed in your environment to handle grouped dependency installations. @@ -80,4 +80,3 @@ make all This ensures that the project environment is fully prepared for development and validation. - diff --git a/hooks/post_gen_project.py b/hooks/post_gen_project.py index 81b8cac..361cdbb 100644 --- a/hooks/post_gen_project.py +++ b/hooks/post_gen_project.py @@ -1,17 +1,30 @@ -import os import shutil from pathlib import Path project_dir = Path.cwd() def remove(path: Path) -> None: + """ + Removes a file or directory at the specified path. + + If the path points to a file, it is deleted. If it points to a + directory, the entire directory tree is removed recursively. + + Args: + path: The filesystem path to remove. + + Returns: + None + """ + if path.is_file(): path.unlink() elif path.is_dir(): shutil.rmtree(path) -folders = { +folders: dict[str, str] = { ".devcontainer": "{{ cookiecutter.add_dev_container_folder }}", + ".vscode": "{{ cookiecutter.add_vscode_folder }}", "notebooks": "{{ cookiecutter.add_notebooks_folder }}", "prompts": "{{ cookiecutter.add_prompts_folder }}", } diff --git a/pyproject.toml b/pyproject.toml index e92e649..9b60d76 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "python-project-template" -version = "2.4.8" +version = "2.5.0" description = "Python project template" authors = [ {name = "Daniel Bazo Correa", email = "none@none.com"}, @@ -35,10 +35,10 @@ required-environments = [ [dependency-groups] documentation = [ "mkdocs==1.6.1", - "mkdocs-material==9.7.0", + "mkdocs-material==9.7.1", "mkdocs-git-revision-date-localized-plugin==1.5.0", "mkdocs-git-authors-plugin==0.10.0", "mkdocs-enumerate-headings-plugin==0.6.2", - "mkdocs-awesome-nav==3.2.0", + "mkdocs-awesome-nav==3.3.0", "mike==2.1.3" -] +] \ No newline at end of file diff --git a/uv.lock b/uv.lock index f4cc1b2..a1dc03c 100644 --- a/uv.lock +++ b/uv.lock @@ -1,5 +1,5 @@ version = 1 -revision = 3 +revision = 2 requires-python = ">=3.11" resolution-markers = [ "python_full_version >= '3.13' and sys_platform == 'linux'", @@ -408,7 +408,7 @@ wheels = [ [[package]] name = "mkdocs-awesome-nav" -version = "3.2.0" +version = "3.3.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "mkdocs", marker = "sys_platform == 'linux'" }, @@ -416,9 +416,9 @@ dependencies = [ { name = "pydantic", marker = "sys_platform == 'linux'" }, { name = "wcmatch", marker = "sys_platform == 'linux'" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/fc/59/d39d2ab15f667a07d978110efd67da14f77d3316ec69b29d69ebe8babdbd/mkdocs_awesome_nav-3.2.0.tar.gz", hash = "sha256:ec0eab7bbe94532d9b3f18ae9a54599b670069856b93df9f6ced1b4a62dfe510", size = 8947, upload-time = "2025-09-10T21:39:21.129Z" } +sdist = { url = "https://files.pythonhosted.org/packages/1f/96/d581c9ceae7d8c08c7456d1d2befbf3e9c7a52a6b03aebbe6dc1d46ffdac/mkdocs_awesome_nav-3.3.0.tar.gz", hash = "sha256:330edf4129995a7be8a9751edd8739d312fddf591c6cbd95ec80f12f4bfe8578", size = 9112, upload-time = "2025-12-02T20:10:46.11Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/f4/2a/dab5925d2d66a1620400e9b64127e576859a0d5dc0cb5ebda1c4f64601ef/mkdocs_awesome_nav-3.2.0-py3-none-any.whl", hash = "sha256:1acf17aaa0f13a5506d3bdb39965bae3136df18a9a2e1106190ebaae2c14d1b6", size = 12662, upload-time = "2025-09-10T21:39:20.302Z" }, + { url = "https://files.pythonhosted.org/packages/de/98/dc154a7f0bb25827d988dc31992917606d1ca9f5349077db045bb5cd9dbc/mkdocs_awesome_nav-3.3.0-py3-none-any.whl", hash = "sha256:bf80f14bff9571df79129bbdf103b4198589ee7616f8a29720ae2e7ac2455930", size = 12891, upload-time = "2025-12-02T20:10:45.054Z" }, ] [[package]] @@ -476,7 +476,7 @@ wheels = [ [[package]] name = "mkdocs-material" -version = "9.7.0" +version = "9.7.1" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "babel", marker = "sys_platform == 'linux'" }, @@ -491,9 +491,9 @@ dependencies = [ { name = "pymdown-extensions", marker = "sys_platform == 'linux'" }, { name = "requests", marker = "sys_platform == 'linux'" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/9c/3b/111b84cd6ff28d9e955b5f799ef217a17bc1684ac346af333e6100e413cb/mkdocs_material-9.7.0.tar.gz", hash = "sha256:602b359844e906ee402b7ed9640340cf8a474420d02d8891451733b6b02314ec", size = 4094546, upload-time = "2025-11-11T08:49:09.73Z" } +sdist = { url = "https://files.pythonhosted.org/packages/27/e2/2ffc356cd72f1473d07c7719d82a8f2cbd261666828614ecb95b12169f41/mkdocs_material-9.7.1.tar.gz", hash = "sha256:89601b8f2c3e6c6ee0a918cc3566cb201d40bf37c3cd3c2067e26fadb8cce2b8", size = 4094392, upload-time = "2025-12-18T09:49:00.308Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/04/87/eefe8d5e764f4cf50ed91b943f8e8f96b5efd65489d8303b7a36e2e79834/mkdocs_material-9.7.0-py3-none-any.whl", hash = "sha256:da2866ea53601125ff5baa8aa06404c6e07af3c5ce3d5de95e3b52b80b442887", size = 9283770, upload-time = "2025-11-11T08:49:06.26Z" }, + { url = "https://files.pythonhosted.org/packages/3e/32/ed071cb721aca8c227718cffcf7bd539620e9799bbf2619e90c757bfd030/mkdocs_material-9.7.1-py3-none-any.whl", hash = "sha256:3f6100937d7d731f87f1e3e3b021c97f7239666b9ba1151ab476cabb96c60d5c", size = 9297166, upload-time = "2025-12-18T09:48:56.664Z" }, ] [[package]] @@ -675,7 +675,7 @@ wheels = [ [[package]] name = "python-project-template" -version = "2.4.8" +version = "2.5.0" source = { virtual = "." } dependencies = [ { name = "cookiecutter", marker = "sys_platform == 'linux'" }, @@ -699,11 +699,11 @@ requires-dist = [{ name = "cookiecutter", specifier = "==2.6.0" }] documentation = [ { name = "mike", specifier = "==2.1.3" }, { name = "mkdocs", specifier = "==1.6.1" }, - { name = "mkdocs-awesome-nav", specifier = "==3.2.0" }, + { name = "mkdocs-awesome-nav", specifier = "==3.3.0" }, { name = "mkdocs-enumerate-headings-plugin", specifier = "==0.6.2" }, { name = "mkdocs-git-authors-plugin", specifier = "==0.10.0" }, { name = "mkdocs-git-revision-date-localized-plugin", specifier = "==1.5.0" }, - { name = "mkdocs-material", specifier = "==9.7.0" }, + { name = "mkdocs-material", specifier = "==9.7.1" }, ] [[package]] diff --git a/{{ cookiecutter.project_name }}/.devcontainer/devcontainer.json b/{{ cookiecutter.project_name }}/.devcontainer/devcontainer.json index 22db34c..a2652e3 100644 --- a/{{ cookiecutter.project_name }}/.devcontainer/devcontainer.json +++ b/{{ cookiecutter.project_name }}/.devcontainer/devcontainer.json @@ -4,26 +4,72 @@ "customizations": { "vscode": { "settings": { - "python.testing.pytestEnabled": true, - "editor.formatOnSave": true, - "editor.codeActionsOnSave": { - "source.organizeImports": true, - "source.fixAll.ruff": true - }, - "[python]": { - "editor.defaultFormatter": "charliermarsh.ruff", - "editor.codeActionsOnSave": { - "source.organizeImports.ruff": true, - "source.fixAll.ruff": true + "todo-tree.regex.enableMultiLine": true, + "editor.rulers": [ + { + "column": 72, + "color": "#4a4f63" + }, + { + "column": 88, + "color": "#7a8ad1" + } + ], + "autoDocstring.docstringFormat": "google-notypes", + "autoDocstring.startOnNewLine": true, + "better-comments.tags": [ + { + "tag": "!!", + "color": "#F6FF33", + "strikethrough": false, + "backgroundColor": "transparent" + }, + { + "tag": "#!", + "color": "#3498DB", + "strikethrough": false, + "backgroundColor": "transparent" + }, + { + "tag": "TODO", + "color": "#FF8C00", + "strikethrough": false, + "backgroundColor": "transparent" + }, + { + "tag": "//", + "color": "#68FF33", + "strikethrough": false, + "backgroundColor": "transparent" + }, + { + "tag": "**", + "color": "#FF33EC", + "strikethrough": false, + "backgroundColor": "transparent" } + ], + "[python]": { + "editor.formatOnType": true + }, + "python.defaultInterpreterPath": "/home/jovyan/envs/env/bin/python", + "[jsonc]": { + "editor.defaultFormatter": "vscode.json-language-features" + }, + "[json]": { + "editor.defaultFormatter": "esbenp.prettier-vscode" }, - "editor.rulers": [88], - "ruff.lint.enable": true, - "ruff.format.enable": true, - "ruff.organizeImports": true, - "ruff.fixAll": true + "prettier.printWidth": 88, + "prettier.proseWrap": "always" }, - "extensions": ["ms-python.python", "charliermarsh.ruff"] + "extensions": [ + "njpwerner.autodocstring", + "aaron-bond.better-comments", + "esbenp.prettier-vscode", + "ms-python.python", + "ms-python.debugpy", + "Gruntfuggly.todo-tree" + ] } }, "features": { diff --git a/{{ cookiecutter.project_name }}/.devcontainer/setup.sh b/{{ cookiecutter.project_name }}/.devcontainer/setup.sh index 033415e..658115b 100644 --- a/{{ cookiecutter.project_name }}/.devcontainer/setup.sh +++ b/{{ cookiecutter.project_name }}/.devcontainer/setup.sh @@ -1,14 +1,10 @@ #!/bin/bash + set -e -echo "Checking for uv..." -if ! command -v uv &> /dev/null; then - echo "Installing uv..." - curl -LsSf https://astral.sh/uv/install.sh | sh > /dev/null 2>&1 - echo "✅ uv installed." -else - echo "✅ uv already installed." -fi +echo "Installing uv..." +curl -LsSf https://astral.sh/uv/install.sh | sh > /dev/null 2>&1 +echo "✅ uv installed." echo "Installing system dependencies..." sudo apt-get update > /dev/null 2>&1 diff --git a/{{ cookiecutter.project_name }}/.github/actions/build-mkdocs/action.yml b/{{ cookiecutter.project_name }}/.github/actions/build-mkdocs/action.yml index e97a5cc..fb2ddd0 100644 --- a/{{ cookiecutter.project_name }}/.github/actions/build-mkdocs/action.yml +++ b/{{ cookiecutter.project_name }}/.github/actions/build-mkdocs/action.yml @@ -40,7 +40,7 @@ runs: echo "Deploying Docs Version: ${{ inputs.docs-version }}" uv run mike deploy --push --update-aliases "${{ inputs.docs-version }}" latest - - name: Set Default Version + - name: Set Default Version to Docs shell: bash run: | echo "Setting 'Latest' as Default Version" diff --git a/{{ cookiecutter.project_name }}/.github/actions/lint-code/action.yml b/{{ cookiecutter.project_name }}/.github/actions/lint-code/action.yml index 0e50814..a2e8165 100644 --- a/{{ cookiecutter.project_name }}/.github/actions/lint-code/action.yml +++ b/{{ cookiecutter.project_name }}/.github/actions/lint-code/action.yml @@ -10,27 +10,27 @@ inputs: runs: using: composite steps: - - name: Lint with ruff + - name: Lint with Ruff id: ruff run: | - echo "Running ruff linter..." + echo "Running Ruff..." uv run ruff check ${{ inputs.src-project-folder }}/ shell: bash - - name: Check imports with isort + - name: Checking Imports with isort run: | echo "Running isort..." uv run isort --check ${{ inputs.src-project-folder }}/ shell: bash - - name: Cognitive Complexity with complexipy + - name: Checking Cognitive Complexity with complexipy run: | echo "Running complexipy..." uv run complexipy -f ${{ inputs.src-project-folder }}/ shell: bash - - name: Check Mypy + - name: Running Mypy Type Checker run: | - echo "Running Mypy type checker..." + echo "Running Mypy..." uv run mypy ${{ inputs.src-project-folder }}/ shell: bash diff --git a/{{ cookiecutter.project_name }}/.github/actions/security/action.yml b/{{ cookiecutter.project_name }}/.github/actions/security/action.yml index 1ad3d42..93cb09f 100644 --- a/{{ cookiecutter.project_name }}/.github/actions/security/action.yml +++ b/{{ cookiecutter.project_name }}/.github/actions/security/action.yml @@ -19,5 +19,5 @@ runs: id: bandit shell: bash run: | - echo "Running Bandit Security Scanner..." + echo "Running Bandit..." uv run bandit -r "${{ inputs.src-project-folder }}/" --exclude "${{ inputs.src-exclude }}" diff --git a/{{ cookiecutter.project_name }}/.github/actions/setup-python-env/action.yml b/{{ cookiecutter.project_name }}/.github/actions/setup-python-env/action.yml index 0dfdf2b..2a553f6 100644 --- a/{{ cookiecutter.project_name }}/.github/actions/setup-python-env/action.yml +++ b/{{ cookiecutter.project_name }}/.github/actions/setup-python-env/action.yml @@ -18,9 +18,11 @@ runs: using: composite steps: - name: Install uv and set the Python version - uses: astral-sh/setup-uv@v5 + uses: astral-sh/setup-uv@v7 with: + version: "0.9.23" python-version: ${{ inputs.src-python-version }} + enable-cache: true - name: Install dependencies with uv id: install-deps diff --git a/{{ cookiecutter.project_name }}/.github/workflows/workflow.yaml b/{{ cookiecutter.project_name }}/.github/workflows/workflow.yaml index 51be3d3..0b1ae03 100644 --- a/{{ cookiecutter.project_name }}/.github/workflows/workflow.yaml +++ b/{{ cookiecutter.project_name }}/.github/workflows/workflow.yaml @@ -2,7 +2,7 @@ name: CI/CD Pipeline on: push: - branches: ["*"] + branches: [main, dev] pull_request: branches: [main, dev] @@ -13,38 +13,38 @@ env: jobs: setup-lint-test: - name: Setup, Lint, Test, and Secure Code + name: Setup, Lint, Test, and Security Check runs-on: ubuntu-latest steps: - name: Checkout Repository - uses: actions/checkout@v5 + uses: actions/checkout@v6 - - name: Setup Python & Install Dependencies + - name: Setup Python Environment uses: ./.github/actions/setup-python-env with: src-python-version: ${{'{{'}} env.SRC_PYTHON_VERSION {{'}}'}} uv-group: "pipeline" uv-extra: "--all-extras" - - name: Lint Code (ruff, Mypy, Complexipy) + - name: Lint Code uses: ./.github/actions/lint-code with: src-project-folder: ${{'{{'}} env.SRC_PROJECT_FOLDER {{'}}'}} - - name: Run Tests with Pytest + - name: Run Tests uses: ./.github/actions/test-code with: src-project-folder: ${{'{{'}} env.SRC_PROJECT_FOLDER {{'}}'}} src-tests-folder: ${{'{{'}} env.SRC_PROJECT_TESTS {{'}}'}} - - name: Run Bandit Security Scan + - name: Security Scan uses: ./.github/actions/security with: src-project-folder: ${{'{{'}} env.SRC_PROJECT_FOLDER {{'}}'}} src-exclude: ${{'{{'}} env.SRC_PROJECT_TESTS {{'}}'}} - build-deploy-mkdocs: + build-deploy-docs: if: github.ref == 'refs/heads/main' name: Build MkDocs Documentation runs-on: ubuntu-latest @@ -57,11 +57,11 @@ jobs: steps: - name: Checkout Repository - uses: actions/checkout@v5 + uses: actions/checkout@v6 with: fetch-depth: 0 - - name: Setup Python & Install Dependencies + - name: Setup Python Environment uses: ./.github/actions/setup-python-env with: src-python-version: ${{'{{'}} env.SRC_PYTHON_VERSION {{'}}'}} @@ -71,7 +71,7 @@ jobs: id: version uses: ./.github/actions/obtain-version - - name: Build MkDocs Site with Mike + - name: Build Documentation uses: ./.github/actions/build-mkdocs with: docs-version: ${{'{{'}} steps.version.outputs.version {{'}}'}} @@ -80,18 +80,18 @@ jobs: if: github.ref == 'refs/heads/main' name: Create Release runs-on: ubuntu-latest - needs: build-deploy-mkdocs + needs: build-deploy-docs permissions: contents: write steps: - name: Checkout Repository - uses: actions/checkout@v5 + uses: actions/checkout@v6 with: fetch-depth: 0 - - name: Setup Python & Install Dependencies + - name: Setup Python Environment uses: ./.github/actions/setup-python-env with: src-python-version: ${{'{{'}} env.SRC_PYTHON_VERSION {{'}}'}} diff --git a/{{ cookiecutter.project_name }}/.gitignore b/{{ cookiecutter.project_name }}/.gitignore index fddd1a4..87a766c 100644 --- a/{{ cookiecutter.project_name }}/.gitignore +++ b/{{ cookiecutter.project_name }}/.gitignore @@ -3,7 +3,6 @@ /saved_objects/ /runs/ __pycache__/ -.vscode/ .mypy_cache/ /results/ *build/ diff --git a/{{ cookiecutter.project_name }}/.vscode/extensions.json b/{{ cookiecutter.project_name }}/.vscode/extensions.json new file mode 100644 index 0000000..0282d21 --- /dev/null +++ b/{{ cookiecutter.project_name }}/.vscode/extensions.json @@ -0,0 +1,10 @@ +{ + "recommendations": [ + "njpwerner.autodocstring", + "aaron-bond.better-comments", + "esbenp.prettier-vscode", + "ms-python.python", + "ms-python.debugpy", + "Gruntfuggly.todo-tree" + ] +} \ No newline at end of file diff --git a/{{ cookiecutter.project_name }}/.vscode/settings.json b/{{ cookiecutter.project_name }}/.vscode/settings.json new file mode 100644 index 0000000..3e0aaad --- /dev/null +++ b/{{ cookiecutter.project_name }}/.vscode/settings.json @@ -0,0 +1,59 @@ +{ + "todo-tree.regex.enableMultiLine": true, + "editor.rulers": [ + { + "column": 72, + "color": "#4a4f63" + }, + { + "column": 88, + "color": "#7a8ad1" + } + ], + "autoDocstring.docstringFormat": "google-notypes", + "autoDocstring.startOnNewLine": true, + "better-comments.tags": [ + { + "tag": "!!", + "color": "#F6FF33", + "strikethrough": false, + "backgroundColor": "transparent" + }, + { + "tag": "#!", + "color": "#3498DB", + "strikethrough": false, + "backgroundColor": "transparent" + }, + { + "tag": "TODO", + "color": "#FF8C00", + "strikethrough": false, + "backgroundColor": "transparent" + }, + { + "tag": "//", + "color": "#68FF33", + "strikethrough": false, + "backgroundColor": "transparent" + }, + { + "tag": "**", + "color": "#FF33EC", + "strikethrough": false, + "backgroundColor": "transparent" + } + ], + "[python]": { + "editor.formatOnType": true + }, + "python.defaultInterpreterPath": "/home/jovyan/envs/env/bin/python", + "[jsonc]": { + "editor.defaultFormatter": "vscode.json-language-features" + }, + "[json]": { + "editor.defaultFormatter": "esbenp.prettier-vscode" + }, + "prettier.printWidth": 88, + "prettier.proseWrap": "always" +} diff --git a/{{ cookiecutter.project_name }}/Makefile b/{{ cookiecutter.project_name }}/Makefile index 0069120..61ab8a7 100644 --- a/{{ cookiecutter.project_name }}/Makefile +++ b/{{ cookiecutter.project_name }}/Makefile @@ -1,22 +1,23 @@ -# Declare all phony targets -.PHONY: install clean lint code_check tests doc check-dead-code pipeline all +.PHONY: setup \ + clean-cache-temp-files \ + lint code-check check-dead-code \ + tests \ + doc \ + pipeline all -# Default target .DEFAULT_GOAL := all -# Variables SRC_PROJECT_NAME ?= {{ cookiecutter.project_module_name }} SRC_PROJECT_TESTS ?= {{ cookiecutter.project_test_folder_name }} -SRC_ALL ?= . +SRC_PROJECT_NOTEBOOKS_FOLDER ?= notebooks -# Install project dependencies -install: +setup: @echo "Installing dependencies..." @uv sync --all-extras + @uv run pre-commit install @echo "✅ Dependencies installed." -# Clean cache and temporary files -clean: +clean-cache-temp-files: @echo "Cleaning cache and temporary files..." @find . -type d -name __pycache__ -exec rm -rf {} + @find . -type d -name .pytest_cache -exec rm -rf {} + @@ -24,45 +25,38 @@ clean: @find . -type f \( -name '*.pyc' -o -name '*.pyo' \) -delete @echo "✅ Clean complete." -# Check code formatting and linting lint: @echo "Running lint checks..." - @uv run isort $(SRC_ALL)/ - @uv run nbqa isort $(SRC_ALL)/ - @uv run ruff check --fix $(SRC_ALL)/ - @uv run ruff format $(SRC_ALL)/ - @uv run nbqa ruff $(SRC_ALL)/ + @uv run isort $(SRC_PROJECT_NAME)/ + @uv run nbqa isort $(SRC_PROJECT_NOTEBOOKS_FOLDER)/ + @uv run ruff check --fix $(SRC_PROJECT_NAME)/ + @uv run ruff format $(SRC_PROJECT_NAME)/ + @uv run nbqa ruff $(SRC_PROJECT_NOTEBOOKS_FOLDER)/ @echo "✅ Linting complete." -# Static analysis and security checks -code_check: +code-check: @echo "Running static code checks..." @uv run mypy $(SRC_PROJECT_NAME)/ @uv run complexipy -f $(SRC_PROJECT_NAME)/ @uv run bandit -r $(SRC_PROJECT_NAME)/ --exclude $(SRC_PROJECT_TESTS) @echo "✅ Code and security checks complete." -# Test the code, only if the tests directory exists +check-dead-code: + @echo "Checking dead code..." + @uv run deadcode $(SRC_PROJECT_NAME) + @echo "✅ Dead code check complete." + tests: @echo "Runing test per each backend..." @uv run pytest $(SRC_PROJECT_TESTS)/ @echo "✅ Tests complete." -# Serve documentation locally doc: @echo "Serving documentation..." @uv run mkdocs serve -# Check dead code -check-dead-code: - @echo "Checking dead code..." - @uv run deadcode $(SRC_PROJECT_NAME) - @echo "✅ Dead code check complete." - -# Run code checks and tests -pipeline: clean lint code_check tests +pipeline: clean-cache-temp-files lint code-check tests @echo "✅ Pipeline complete." -# Run full workflow including install and docs -all: install pipeline doc +all: setup pipeline doc @echo "✅ All tasks complete." diff --git a/{{ cookiecutter.project_name }}/pyproject.toml b/{{ cookiecutter.project_name }}/pyproject.toml index 6ee3f6e..ac0f668 100644 --- a/{{ cookiecutter.project_name }}/pyproject.toml +++ b/{{ cookiecutter.project_name }}/pyproject.toml @@ -36,24 +36,25 @@ required-environments = [ [dependency-groups] pipeline = [ "bandit==1.9.2", - "complexipy==5.0.0", - "mypy==1.19.0", - "pytest==9.0.1", + "complexipy==5.1.0", + "mypy==1.19.1", + "pytest==9.0.2", "pytest-order==1.3.0", - "ruff==0.14.7", + "ruff==0.14.11", "isort==7.0.0", "nbqa==1.9.1", "deadcode==2.4.1", + "pre-commit==4.5.1", ] documentation = [ "mkdocs==1.6.1", "mkdocstrings[python]==1.0.0", - "mkdocs-material==9.7.0", + "mkdocs-material==9.7.1", "mkdocs-git-revision-date-localized-plugin==1.5.0", "mkdocs-git-authors-plugin==0.10.0", "mkdocs-enumerate-headings-plugin==0.6.2", "mkdocs-jupyter==0.25.1", - "mkdocs-awesome-nav==3.2.0", + "mkdocs-awesome-nav==3.3.0", "mike==2.1.3" ] @@ -95,7 +96,7 @@ exclude = [ extend-exclude = ["*.ipynb"] [tool.ruff.lint] -select = ["E", "F", "UP", "B", "SIM", "I"] +select = ["E", "F", "UP", "B", "SIM"] ignore = ["E203"] [tool.ruff.lint.pydocstyle] @@ -103,16 +104,11 @@ convention = "google" [tool.ruff.format] quote-style = "double" -indent-style = "tab" +indent-style = "space" line-ending = "auto" docstring-code-format = true docstring-code-line-length = 88 -[tool.ruff.lint.isort] -case-sensitive = true -combine-as-imports = true -force-to-top = ["{{ cookiecutter.project_module_name }}"] - [tool.mypy] check_untyped_defs = true ignore_missing_imports = true