diff --git a/Makefile b/Makefile index 5a5de12..2c43880 100644 --- a/Makefile +++ b/Makefile @@ -1,10 +1,13 @@ .PHONY: setup \ clean-cache-temp-files \ - doc \ + lint code-check \ + doc \ pipeline all .DEFAULT_GOAL := all +SRC_PROJECT_HOOKS ?= hooks + setup: @echo "Installing dependencies..." @uv sync --all-extras @@ -18,11 +21,25 @@ clean-cache-temp-files: @find . -type f \( -name '*.pyc' -o -name '*.pyo' \) -delete @echo "✅ Clean complete." +lint: + @echo "Running lint checks..." + @uv run isort $(SRC_PROJECT_HOOKS)/ + @uv run ruff check --fix $(SRC_PROJECT_HOOKS)/ + @uv run ruff format $(SRC_PROJECT_HOOKS)/ + @echo "✅ Linting complete." + +code-check: + @echo "Running static code checks..." + @uv run mypy $(SRC_PROJECT_HOOKS)/ + @uv run complexipy -f $(SRC_PROJECT_HOOKS)/ + @uv run bandit -r $(SRC_PROJECT_HOOKS)/ + @echo "✅ Code and security checks complete." + doc: @echo "Serving documentation..." @uv run mkdocs serve -pipeline: clean-cache-temp-files +pipeline: clean-cache-temp-files lint code-check @echo "✅ Pipeline complete." all: setup pipeline doc diff --git a/README.md b/README.md index e9ba855..0102e8a 100644 --- a/README.md +++ b/README.md @@ -38,7 +38,7 @@ manage dependencies cleanly. Additionally, ensure that [`uv`](https://github.com/astral-sh/uv) is installed in your environment to handle grouped dependency installations. -### 1. Generate Your Project +1. Generate Your Project Use Cookiecutter to create a new project from the template: @@ -48,7 +48,7 @@ cookiecutter https://github.com/danibcorr/python-project-template.git Follow the prompts to configure project metadata, package name, and other options. -### 2. Install Dependencies +2. Install Dependencies Activate your virtual environment and install all dependencies using the included `Makefile`: @@ -60,7 +60,7 @@ make install This installs development, testing, and documentation tools as defined in `pyproject.toml`. -### 3. Run the Pipeline +3. Run the Pipeline Execute the quality pipeline, which includes linting, type checking, security analysis, complexity checks, and test execution: @@ -69,7 +69,7 @@ complexity checks, and test execution: make pipeline ``` -### 4. Run the Full Workflow (Optional) +4. Run the Full Workflow (Optional) To perform a complete setup including dependency installation, full quality checks, and local documentation preview: diff --git a/docs/.nav.yml b/docs/.nav.yml index 1d95821..5cce7b8 100644 --- a/docs/.nav.yml +++ b/docs/.nav.yml @@ -1,7 +1,13 @@ nav: - Home: index.md - - Documentation: content/ + - Documentation: + - Overview: content/overview.md + - Getting Started: content/cookiecutter.md + - Makefile Commands: content/makefile-commands.md + - Configuration: content/pyproject-configuration.md + - Pre-commit Hooks: content/pre-commit-hooks.md + - CI/CD: content/ci-cd.md sort: ignore_case: true - type: alphabetical \ No newline at end of file + type: alphabetical diff --git a/docs/content/ci-cd.md b/docs/content/ci-cd.md new file mode 100644 index 0000000..e5693c9 --- /dev/null +++ b/docs/content/ci-cd.md @@ -0,0 +1,72 @@ +# Continuous Integration and Continuous Deployment with GitHub Actions + +## Overview of the Automation Strategy + +The continuous integration and continuous deployment (CI/CD) process is implemented +through GitHub Actions using a workflow definition located at +`.github/workflows/workflow.yml`. This workflow is designed to automate, in a unified and +reproducible manner, the validation, documentation generation, and release management +phases of the project lifecycle. By integrating these activities into a single automated +pipeline, the repository ensures consistency between code changes, documentation updates, +and published releases, while reducing manual intervention and the risk of human error. + +## Workflow Architecture and Execution Logic + +The workflow is composed of several logically separated jobs, each responsible for a +specific stage of the CI/CD process. These jobs are executed according to clearly defined +triggering conditions, primarily based on repository events and branch context. The +structure reflects a progressive validation model in which foundational checks are +performed first, followed by documentation deployment and release creation when the code +reaches a stable state. + +## Environment Setup and Dependency Initialization + +The initial job, referred to as the setup phase, is executed on every push and on every +pull request. Its primary purpose is to establish a controlled and reproducible execution +environment. During this phase, a Python runtime environment is provisioned, ensuring +that subsequent jobs operate under consistent interpreter conditions. All dependencies +defined under the `pipeline` group are then installed, which guarantees that the tools +required for validation, documentation generation, and automation are available before +any further processing occurs. This step functions as a foundational safeguard, as +failures at this stage prevent downstream jobs from executing under incomplete or +misconfigured conditions. + +## Documentation Build and Deployment on the Main Branch + +When changes are merged into the `main` branch, the workflow activates an additional job +dedicated to documentation management. In this phase, the project documentation is built +using MkDocs, a static site generator specifically designed for technical documentation. +The resulting site is then automatically deployed to GitHub Pages, ensuring that the +published documentation always reflects the current state of the main codebase. + +Version management of the documentation is handled through `mike`, which enables the +coexistence of multiple documentation versions corresponding to different project +releases. This approach allows users to consult documentation aligned with specific +versions of the software, thereby improving traceability and long-term maintainability. +The deployment process is fully automated and does not require manual approval once the +workflow conditions are satisfied. + +## Automated Release Creation and Versioning + +Also restricted to the `main` branch, the release creation job formalizes the delivery of +a new software version. During this stage, the workflow programmatically determines the +current project version and uses this information to create a new GitHub release. Release +notes are generated automatically, typically by aggregating relevant commit messages or +changes since the previous release. This ensures that each release is consistently +documented and that users have immediate access to a structured summary of modifications, +enhancements, and fixes. + +By integrating release creation into the CI/CD pipeline, the workflow enforces a direct +relationship between the main branch state and published artifacts, reducing +discrepancies between source code and released versions. + +## GitHub Pages Configuration and Activation + +For the automated documentation deployment to function correctly, GitHub Pages must be +configured to use GitHub Actions as its source. This configuration is performed within +the repository settings by navigating to the Pages section and selecting GitHub Actions +as the publication source. Once this setting is applied, every push to the `main` branch +triggers the documentation build and deployment process defined in the workflow. As a +result, the documentation site is continuously updated without requiring any additional +manual steps, ensuring alignment between the repository content and its public technical +documentation. diff --git a/docs/content/content.md b/docs/content/content.md deleted file mode 100644 index 4c30e51..0000000 --- a/docs/content/content.md +++ /dev/null @@ -1,133 +0,0 @@ -# Python Project Template Documentation - -## Overview - -The **Python Project Template** provides a comprehensive and structured foundation for -Python projects, integrating modern tooling to ensure code quality, static analysis, -security auditing, testing, documentation, and development automation. The template -promotes consistent, maintainable, and reproducible workflows, streamlining project -setup and enforcing adherence to established best practices. - -This framework is suitable for libraries, applications, and collaborative projects, -establishing a professional development environment from the outset. - -## Project Structure and Core Components - -### Makefile - -The Makefile defines reusable targets to automate common development tasks, including -dependency installation, workspace cleanup, linting, testing, static and security -analysis, and documentation management. Commands are executed using the syntax -`make `. - -#### `make install` - -Installs all project dependencies using [`uv`](https://github.com/astral-sh/uv) as -defined in `pyproject.toml`. Dependencies are organized into modular groups such as -`pipeline` and `documentation`, enabling selective installation according to the -required development context. - -#### `make clean` - -Removes temporary and cache files to restore a clean workspace. This includes Python -bytecode files (`.pyc`, `.pyo`) and cache directories such as `__pycache__`, -`.pytest_cache`, and `.mypy_cache`. Performing this step ensures reliable results for -linting, testing, and static analysis by eliminating residual artifacts from previous -runs. - -#### `make lint` - -Executes [Ruff](https://docs.astral.sh/ruff/) to enforce code formatting and static -analysis rules across source and test directories. This target promotes consistent -coding standards and prevents stylistic inconsistencies. - -#### `make code_check` - -Performs advanced code validation and security assessments, including: - -- **Mypy**: Validates type annotations and identifies type inconsistencies. -- **Complexipy**: Measures code complexity, highlighting potentially intricate or - hard-to-maintain logic. -- **Bandit**: Conducts static security analysis (SAST) to detect common vulnerabilities - and security issues within Python code. - -This step ensures that the codebase remains robust, maintainable, and secure. - -#### `make tests` - -Runs unit tests using [Pytest](https://docs.pytest.org/en/stable/). The command exits -gracefully if no tests are detected, making it suitable for partial implementations or -early-stage project setups. - -#### `make doc` - -Builds and serves project documentation locally with [MkDocs](https://www.mkdocs.org/), -allowing developers to preview documentation changes in real time before deployment. - -#### `make pipeline` - -Executes a complete quality pipeline that includes environment cleanup, linting, static -analysis, security checks, and test execution. This target is designed for continuous -integration workflows and pre-release verification. - -#### `make all` - -Performs the full project workflow, encompassing dependency installation, execution of -the full quality pipeline, and documentation build and preview. This target is -recommended for initial project setup and comprehensive workflow verification. - -### `pyproject.toml` - -The `pyproject.toml` file defines project metadata, dependency groups, and tool -configurations in accordance with modern Python standards. - -#### `[project]` - -Specifies core project metadata, including project name, version, description, Python -version compatibility, and runtime dependencies. This section adheres to -[PEP 621](https://peps.python.org/pep-0621/) standards. - -#### `[dependency-groups]` - -Organizes development dependencies into logical groups to enable modular installation: - -- **`pipeline`**: Includes tools for code quality, testing, and security assessment, - such as `pytest`, `pytest-order`, `ruff`, `mypy`, `bandit`, and `complexipy`. -- **`documentation`**: Contains tools for building and enhancing documentation, - including `mkdocs-material`, `mkdocstrings`, `mkdocs-jupyter`, and related plugins. - -This modular approach improves maintainability and flexibility of the development -environment. - -#### `[tool.ruff]` - -Configures Ruff for code linting and formatting, including rules for line length, -indentation, error detection, and docstring formatting. Certain directories, such as -`venv`, `dist`, and `.pytest_cache`, are excluded to optimize performance. - -#### `[tool.mypy]` - -Configures Mypy for static type checking. It enables detection of untyped functions, -ignores unresolved imports to accommodate missing type stubs, and excludes build and -cache directories. This configuration allows early detection of type-related errors, -improving code reliability. - -## GitHub Actions CI/CD - -The template includes a preconfigured GitHub Actions workflow located in -`.github/workflows`. This workflow is triggered automatically on pushes or pull requests -and performs the following steps: - -1. **Checkout and Python Setup** – Clones the repository and configures the Python - environment. -2. **Dependency Installation** – Installs all required packages for development, - testing, and documentation. -3. **Linting and Static Analysis** – Executes Ruff, Mypy, Bandit, and Complexipy to - enforce code quality, type safety, security, and maintainability. -4. **Testing** – Runs Pytest to validate functionality and detect regressions. -5. **Documentation** – Optionally builds and deploys project documentation to GitHub - Pages using MkDocs. - -This workflow ensures that all code changes are automatically validated, tested, and -documented, supporting continuous integration and promoting high-quality software -development practices. diff --git a/docs/content/cookiecutter.md b/docs/content/cookiecutter.md new file mode 100644 index 0000000..441ea54 --- /dev/null +++ b/docs/content/cookiecutter.md @@ -0,0 +1,53 @@ +# Cookiecutter + +## Introduction to Cookiecutter + +Cookiecutter is a command-line utility designed to generate project structures from +predefined templates. It enables developers to rapidly scaffold new projects by prompting +for configuration inputs and customizing the generated files according to the provided +responses. This approach ensures consistency across projects, reduces setup time, and +enforces best practices and organizational standards in project structure. + +## Configuration Variables + +The customization process is driven by a configuration file, typically named +`cookiecutter.json`, which defines the variables that the template expects. Each variable +corresponds to a specific aspect of the project, such as naming conventions, folder +structures, or optional features. During project generation, Cookiecutter interactively +prompts the user to provide values for these variables, thereby producing a project +tailored to the user’s specifications. The main configuration variables include: + +| Variable | Description | Example | +| -------------------------- | ----------------------------------------------- | ------------------------------ | +| `project_name` | Name of the project | `my-project` | +| `project_module_name` | Name of the Python module | `src` | +| `project_test_folder_name` | Name of the folder for tests | `tests` | +| `project_version_python` | Minimum required Python version | `3.11` | +| `mkdocs_repo_url` | URL of the repository for documentation | `https://github.com/user/repo` | +| `add_notebooks_folder` | Option to include a notebooks folder | `yes` / `no` | +| `add_prompts_folder` | Option to include a prompts folder | `yes` / `no` | +| `add_dev_container_folder` | Option to include a Dev Container configuration | `yes` / `no` | + +These variables enable fine-grained control over the structure and functionality of the +generated project, accommodating different workflows and development environments. + +## Project Generation Workflow + +The process of generating a project using Cookiecutter is straightforward. The user +executes the `cookiecutter` command with the URL or local path of the desired template +repository. Cookiecutter then sequentially prompts the user to provide values for each +configuration variable defined in `cookiecutter.json`. Once all responses are collected, +the tool automatically creates a new project directory populated with files and folders +customized according to the provided inputs. + +For example, executing: + +```bash +cookiecutter https://github.com/danibcorr/python-project-template.git +``` + +initiates the generation process. The user answers the interactive prompts, specifying +names, versions, and optional components. Upon completion, a fully scaffolded project +appears, reflecting the selected options and ready for immediate development. This +automated approach promotes reproducibility, reduces setup errors, and enforces a +consistent organizational structure across multiple projects. diff --git a/docs/content/makefile-commands.md b/docs/content/makefile-commands.md new file mode 100644 index 0000000..c319e75 --- /dev/null +++ b/docs/content/makefile-commands.md @@ -0,0 +1,135 @@ +# Makefile + +## Overview + +The project includes a `Makefile` designed to automate routine development tasks. Each +command is executed using the syntax `make ` and encapsulates a sequence of +actions that standardize workflows, enforce code quality, and simplify maintenance. By +centralizing these tasks, the `Makefile` ensures consistency across development +environments and reduces manual errors. + +## Environment Setup: `make setup` + +The `setup` command installs all necessary dependencies and configures pre-commit hooks +to enforce code standards automatically. It leverages `uv`, a high-performance Python +package manager, to install the required packages efficiently. Dependency groups include +`pipeline`, which contains tools for testing and linting, and `documentation`, which +includes MkDocs for building project documentation. Pre-commit hooks are configured to +validate code before each commit, preventing common errors and maintaining quality. This +command should be executed the first time the project is cloned or whenever dependencies +are updated. + +```bash +make setup +``` + +## Cleaning Temporary Files: `make clean-cache-temp-files` + +This command removes temporary files and caches that may cause inconsistencies or errors +during development. Specifically, it deletes compiled Python bytecode (`__pycache__/`), +pytest caches (`.pytest_cache/`), mypy caches (`.mypy_cache/`), and other compiled files +such as `*.pyc` and `*.pyo`. Regular use of this command ensures a clean environment, +particularly before running the complete pipeline or debugging unusual behavior. + +```bash +make clean-cache-temp-files +``` + +## Code Formatting and Automatic Fixes: `make lint` + +The `lint` command enforces coding standards and applies automatic fixes to improve code +readability and maintainability. It integrates several tools: + +- **isort**: Organizes imports alphabetically and categorically. +- **Ruff**: A high-performance linter that detects and fixes style issues. +- **nbqa**: Applies linting to Jupyter notebooks. + +Typical automatic fixes include removing unused imports, correcting spacing and +formatting, and reorganizing imports according to PEP 8 conventions. This command is +recommended before committing code or when performing routine code cleanup. + +```bash +make lint +``` + +## Static and Security Analysis: `make code-check` + +The `code-check` command performs an in-depth analysis to identify potential issues in +the codebase. It combines multiple tools: + +1. **Mypy**: A static type checker that validates type annotations and detects mismatched + types before runtime. +2. **Complexipy**: Measures cyclomatic complexity to identify functions that may be + difficult to maintain or require refactoring. +3. **Bandit**: Conducts static application security testing (SAST) to identify common + vulnerabilities, such as SQL injection risks, unsafe `eval()` usage, and hardcoded + credentials. It scans all code excluding test directories. + +This command is essential before merging changes into the main branch or during code +reviews to ensure robust, maintainable, and secure code. + +```bash +make code-check +``` + +## Dead Code Detection: `make check-dead-code` + +The `check-dead-code` command identifies unused or redundant code that can be safely +removed. It detects functions that are never called, uninstantiated classes, and +variables that are defined but not utilized. Running this command is particularly useful +during refactoring or when optimizing the codebase for maintainability. + +```bash +make check-dead-code +``` + +## Running Unit Tests: `make tests` + +This command executes all unit tests using Pytest. It supports structured test execution +via `pytest-order` and can generate coverage reports if configured. The `tests/` +directory is scanned recursively, ensuring that all modules are tested thoroughly. This +command should be run frequently after code modifications to verify correctness. + +```bash +make tests +``` + +## Documentation Management: `make doc` + +The `doc` command builds and serves project documentation locally using MkDocs. It +launches a development server (by default accessible at `http://127.0.0.1:8000`) and +automatically reloads pages when Markdown files are updated. This allows developers to +preview documentation as it will appear on GitHub Pages and ensures consistency between +local edits and published content. + +```bash +make doc +``` + +## Complete Code Quality Pipeline: `make pipeline` + +The `pipeline` command orchestrates the full sequence of code quality checks and testing. +It sequentially: + +1. Cleans caches and temporary files. +2. Runs linting and formatting. +3. Performs static analysis, complexity measurement, and security scanning. +4. Executes all unit tests. + +This command is particularly useful before pushing changes to the repository or as part +of a continuous integration (CI) workflow. + +```bash +make pipeline +``` + +## Full Workflow Execution: `make all` + +The `all` command executes the complete project setup and validation workflow. It +installs dependencies, runs the full code quality pipeline, and serves the documentation +locally. This command provides a comprehensive initialization process, ensuring the +development environment is fully configured and all systems are validated. + +```bash +make all +``` diff --git a/docs/content/overview.md b/docs/content/overview.md new file mode 100644 index 0000000..8cef29c --- /dev/null +++ b/docs/content/overview.md @@ -0,0 +1,48 @@ +# Python Project Template + +## Overview + +The **Python Project Template** is a pre-configured, ready-to-use scaffolding designed to +accelerate the creation of professional Python projects. It provides a complete directory +structure, integrated tooling, and automation mechanisms that enforce modern development +best practices. By using this template, developers can immediately focus on implementing +functionality rather than spending time on repetitive setup tasks, ensuring that new +projects maintain high standards for code quality, testing, security, and documentation. + +## Target Audience + +This template is intended for a wide range of users and project types: + +- Individual developers seeking to start projects with a professional and standardized + setup from the outset. +- Development teams aiming to enforce consistent workflows and project structures across + multiple repositories. +- Projects spanning domains such as data science, machine learning, APIs, Python + libraries, or general-purpose Python applications. + +By providing a common foundation, the template reduces onboarding time for new team +members and ensures reproducibility across projects. + +## Key Benefits + +The Python Project Template offers several advantages that streamline development +processes and enhance software quality: + +- **Time Efficiency**: The template allows developers to initialize a fully configured + project within minutes, avoiding the hours typically spent on manual setup. +- **Ensured Code Quality**: Preconfigured tools for linting, static type checking, + complexity analysis, and security evaluation help maintain high-quality, maintainable, + and secure codebases. +- **Automated Documentation**: Integration with MkDocs enables immediate generation and + deployment of project documentation to GitHub Pages, ensuring that documentation + remains synchronized with the code. +- **CI/CD Integration**: Built-in GitHub Actions workflows automatically perform code + validation, testing, and documentation deployment, reducing manual intervention and + errors. +- **Customizability**: Through Cookiecutter, the template can be adapted to specific + project requirements, allowing modification of structure, module names, and optional + components while preserving the standard workflow. + +By combining these features, the template not only accelerates project setup but also +enforces modern best practices, supporting sustainable, scalable, and maintainable Python +development. diff --git a/docs/content/pre-commit-hooks.md b/docs/content/pre-commit-hooks.md new file mode 100644 index 0000000..2d10efa --- /dev/null +++ b/docs/content/pre-commit-hooks.md @@ -0,0 +1,53 @@ +# Pre-Commit Hooks + +## Overview + +Pre-commit hooks are automated scripts configured to execute specific validations before +a Git commit is finalized. In this project, the pre-commit system is defined in the +`.pre-commit-config.yaml` file. Its primary purpose is to enforce code quality, detect +potential errors early, and prevent non-compliant code from entering the repository. By +integrating pre-commit hooks into the workflow, the project ensures that all committed +changes meet established coding standards and pass essential checks automatically. + +## Functionality + +When a developer attempts to commit changes, the pre-commit system automatically triggers +the full development pipeline by executing: + +```bash +make pipeline +``` + +This command performs a comprehensive sequence of actions, including: + +- Linting and formatting checks to ensure consistent code style. +- Type validation using Mypy to detect mismatches and type-related errors. +- Security analysis with Bandit to identify potential vulnerabilities in the code. +- Execution of all unit tests to confirm that functionality remains correct. + +If any of these checks fail, the commit is blocked, thereby preventing problematic code +from being added to the repository. + +## Advantages + +Integrating pre-commit hooks into the development workflow provides several key benefits: + +- **Quality Enforcement**: Only code that passes all validations can be committed, + maintaining a high standard across the codebase. +- **Early Issue Detection**: Errors are detected before code is pushed or reviewed, + reducing downstream debugging and rework. +- **Clean Git History**: By preventing commits that violate coding standards or fail + tests, the repository maintains a cleaner and more reliable history. + +## Temporary Bypass (Not Recommended) + +While it is possible to bypass pre-commit validations using the `--no-verify` flag: + +```bash +git commit --no-verify -m "commit message" +``` + +this approach is discouraged because it undermines the automated quality safeguards and +may introduce errors or inconsistencies into the codebase. Pre-commit hooks are intended +to be an integral part of the workflow, ensuring that each commit contributes to a +robust, secure, and maintainable project. diff --git a/docs/content/pyproject-configuration.md b/docs/content/pyproject-configuration.md new file mode 100644 index 0000000..03546c0 --- /dev/null +++ b/docs/content/pyproject-configuration.md @@ -0,0 +1,111 @@ +# `pyproject.toml` Configuration + +## Overview + +The `pyproject.toml` file serves as the central configuration hub for the project, +consolidating metadata, dependency management, and tool settings in a single, +standardized location. It follows the [PEP 621](https://peps.python.org/pep-0621/) +specification, which defines a uniform format for Python project metadata and facilitates +interoperability between tools. By leveraging `pyproject.toml`, the project achieves +modular dependency management, consistent tool behavior, and simplified setup for both +development and production environments. + +## Project Metadata: `[project]` Section + +The `[project]` section defines fundamental information about the project. This includes +the project name, version, description, author information, and the minimum supported +Python version. An example configuration is: + +```toml +[project] +name = "my-project" +version = "0.0.1" +description = "Project description" +authors = [{name = "Your Name", email = "your@email.com"}] +requires-python = ">=3.11" +``` + +These fields ensure that packaging tools, dependency managers, and documentation +generators can automatically retrieve key project information. This metadata also +standardizes versioning and distribution across different environments. + +## Dependency Management: `[dependency-groups]` Section + +Dependencies are organized into logical groups, allowing selective installation based on +project requirements. This modular approach supports both development and production +workflows. + +### `pipeline` Group: Development Tools + +The `pipeline` group includes tools essential for code quality, testing, security, and +automation: + +- `pytest` and `pytest-order`: Frameworks for running unit tests and controlling test + execution order. +- `ruff`: A high-performance linter and automatic formatter. +- `mypy`: Static type checker to detect type inconsistencies. +- `bandit`: Security analysis tool for detecting common vulnerabilities. +- `complexipy`: Measures cyclomatic complexity to identify potentially unmaintainable + code. +- `isort`: Sorts imports according to standard conventions. +- `nbqa`: Extends linting capabilities to Jupyter notebooks. +- `deadcode`: Detects unused or unreachable code. +- `pre-commit`: Manages Git pre-commit hooks for automated checks. + +### `documentation` Group: Documentation Tools + +The `documentation` group contains tools for building and maintaining project +documentation: + +- `mkdocs` and `mkdocs-material`: Static site generator and material design theme. +- `mkdocstrings`: Generates API documentation directly from Python docstrings. +- `mkdocs-jupyter`: Integrates Jupyter notebooks into documentation. +- `mike`: Provides versioned documentation management. +- Additional plugins: Enhance navigation, metadata handling, and site functionality. + +## Tool-Specific Configuration + +### Ruff: `[tool.ruff]` + +The Ruff linter is configured to enforce code style, detect errors, and simplify code +where possible: + +```toml +[tool.ruff] +line-length = 88 +indent-width = 4 +select = ["E", "F", "UP", "B", "SIM"] +``` + +- `E`: Enforces PEP 8 style guidelines. +- `F`: Detects Pyflakes errors such as unused imports. +- `UP`: Applies modern Python syntax checks and upgrades. +- `B`: Detects common programming bugs. +- `SIM`: Suggests code simplifications to improve readability. + +### Mypy: `[tool.mypy]` + +Mypy performs static type checking, ensuring type safety and consistency: + +```toml +[tool.mypy] +check_untyped_defs = true +ignore_missing_imports = true +``` + +- `check_untyped_defs = true`: Validates functions even if type annotations are missing. +- `ignore_missing_imports = true`: Avoids errors for third-party modules without type + stubs, preventing unnecessary interruptions. + +### isort: `[tool.isort]` + +isort enforces a standardized import order, improving code readability and +maintainability. Imports are grouped as follows: + +1. **STDLIB**: Python standard library modules. +2. **THIRDPARTY**: External dependencies installed via package managers. +3. **FIRSTPARTY**: Modules developed within the current project. +4. **LOCALFOLDER**: Relative imports for local submodules or packages. + +This grouping ensures that import statements remain organized and easy to navigate, +facilitating collaboration across multiple developers and modules. diff --git a/docs/index.md b/docs/index.md index a5a0700..56614b0 100644 --- a/docs/index.md +++ b/docs/index.md @@ -38,7 +38,7 @@ manage dependencies cleanly. Additionally, ensure that [`uv`](https://github.com/astral-sh/uv) is installed in your environment to handle grouped dependency installations. -### 1. Generate Your Project +1. Generate Your Project Use Cookiecutter to create a new project from the template: @@ -48,7 +48,7 @@ cookiecutter https://github.com/danibcorr/python-project-template.git Follow the prompts to configure project metadata, package name, and other options. -### 2. Install Dependencies +2. Install Dependencies Activate your virtual environment and install all dependencies using the included `Makefile`: @@ -60,7 +60,7 @@ make install This installs development, testing, and documentation tools as defined in `pyproject.toml`. -### 3. Run the Pipeline +3. Run the Pipeline Execute the quality pipeline, which includes linting, type checking, security analysis, complexity checks, and test execution: @@ -69,7 +69,7 @@ complexity checks, and test execution: make pipeline ``` -### 4. Run the Full Workflow (Optional) +4. Run the Full Workflow (Optional) To perform a complete setup including dependency installation, full quality checks, and local documentation preview: diff --git a/hooks/post_gen_project.py b/hooks/post_gen_project.py index 361cdbb..a305885 100644 --- a/hooks/post_gen_project.py +++ b/hooks/post_gen_project.py @@ -1,27 +1,33 @@ +# Standard libraries 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 not path.exists(): + return + if path.is_file(): path.unlink() elif path.is_dir(): shutil.rmtree(path) + folders: dict[str, str] = { ".devcontainer": "{{ cookiecutter.add_dev_container_folder }}", ".vscode": "{{ cookiecutter.add_vscode_folder }}", diff --git a/mkdocs.yml b/mkdocs.yml index cef8956..9f66c19 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -23,20 +23,26 @@ theme: icon: material/weather-sunny name: "Switch to dark mode" features: - - content.tabs.link + - announce.dismiss + - content.action.edit + - content.action.view - content.code.annotate - content.code.copy + - content.tabs.link - content.tooltips - - announce.dismiss - - navigation.tabs + - navigation.footer - navigation.instant - navigation.instant.prefetch - navigation.instant.preview - navigation.instant.progress - - navigation.sections + - navigation.indexes + - navigation.path + - navigation.tabs - navigation.top - navigation.tracking - - navigation.indexes + - navigation.sections + - search.highlight + - search.share - search.suggest - toc.follow - toc.integrate diff --git a/pyproject.toml b/pyproject.toml index 9b60d76..4d41e49 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "python-project-template" -version = "2.5.0" +version = "2.5.1" description = "Python project template" authors = [ {name = "Daniel Bazo Correa", email = "none@none.com"}, @@ -33,6 +33,13 @@ required-environments = [ ] [dependency-groups] +pipeline = [ + "bandit==1.9.2", + "complexipy==5.1.0", + "mypy==1.19.1", + "ruff==0.14.11", + "isort==7.0.0" +] documentation = [ "mkdocs==1.6.1", "mkdocs-material==9.7.1", @@ -41,4 +48,69 @@ documentation = [ "mkdocs-enumerate-headings-plugin==0.6.2", "mkdocs-awesome-nav==3.3.0", "mike==2.1.3" -] \ No newline at end of file +] + + +[tool.ruff] +line-length = 88 +indent-width = 4 +exclude = [ + ".bzr", + ".direnv", + ".eggs", + ".git", + ".git-rewrite", + ".hg", + ".ipynb_checkpoints", + ".mypy_cache", + ".nox", + ".pants.d", + ".pyenv", + ".pytest_cache", + ".pytype", + ".ruff_cache", + ".svn", + ".tox", + ".venv", + ".vscode", + "__pypackages__", + "_build", + "buck-out", + "build", + "dist", + "node_modules", + "site-packages", + "venv", +] +extend-exclude = ["*.ipynb"] + +[tool.ruff.lint] +select = ["E", "F", "UP", "B", "SIM"] +ignore = ["E203"] + +[tool.ruff.lint.pydocstyle] +convention = "google" + +[tool.ruff.format] +quote-style = "double" +indent-style = "space" +line-ending = "auto" +docstring-code-format = true +docstring-code-line-length = 88 + +[tool.mypy] +check_untyped_defs = true +ignore_missing_imports = true +exclude = [ + "^(build|dist|venv)", + ".venv/" +] +cache_dir = "/dev/null" + +[tool.isort] +known_first_party = ["{{ cookiecutter.project_module_name }}"] +sections = ["FUTURE", "STDLIB", "THIRDPARTY", "FIRSTPARTY", "LOCALFOLDER"] +import_heading_stdlib = "Standard libraries" +import_heading_thirdparty = "3pps" +import_heading_firstparty = "Own modules" +line_length = 88 \ No newline at end of file diff --git a/uv.lock b/uv.lock index a1dc03c..c6fcb93 100644 --- a/uv.lock +++ b/uv.lock @@ -57,6 +57,20 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/02/e3/a4fa1946722c4c7b063cc25043a12d9ce9b4323777f89643be74cef2993c/backrefs-6.1-py39-none-any.whl", hash = "sha256:a9e99b8a4867852cad177a6430e31b0f6e495d65f8c6c134b68c14c3c95bf4b0", size = 381058, upload-time = "2025-11-15T14:52:06.698Z" }, ] +[[package]] +name = "bandit" +version = "1.9.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "pyyaml", marker = "sys_platform == 'linux'" }, + { name = "rich", marker = "sys_platform == 'linux'" }, + { name = "stevedore", marker = "sys_platform == 'linux'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/cf/72/f704a97aac430aeb704fa16435dfa24fbeaf087d46724d0965eb1f756a2c/bandit-1.9.2.tar.gz", hash = "sha256:32410415cd93bf9c8b91972159d5cf1e7f063a9146d70345641cd3877de348ce", size = 4241659, upload-time = "2025-11-23T21:36:18.722Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/55/1a/5b0320642cca53a473e79c7d273071b5a9a8578f9e370b74da5daa2768d7/bandit-1.9.2-py3-none-any.whl", hash = "sha256:bda8d68610fc33a6e10b7a8f1d61d92c8f6c004051d5e946406be1fb1b16a868", size = 134377, upload-time = "2025-11-23T21:36:17.39Z" }, +] + [[package]] name = "beautifulsoup4" version = "4.14.3" @@ -93,11 +107,11 @@ wheels = [ [[package]] name = "certifi" -version = "2025.11.12" +version = "2026.1.4" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/a2/8c/58f469717fa48465e4a50c014a0400602d3c437d7c0c468e17ada824da3a/certifi-2025.11.12.tar.gz", hash = "sha256:d8ab5478f2ecd78af242878415affce761ca6bc54a22a27e026d7c25357c3316", size = 160538, upload-time = "2025-11-12T02:54:51.517Z" } +sdist = { url = "https://files.pythonhosted.org/packages/e0/2d/a891ca51311197f6ad14a7ef42e2399f36cf2f9bd44752b3dc4eab60fdc5/certifi-2026.1.4.tar.gz", hash = "sha256:ac726dd470482006e014ad384921ed6438c457018f4b3d204aea4281258b2120", size = 154268, upload-time = "2026-01-04T02:42:41.825Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/70/7d/9bc192684cea499815ff478dfcdc13835ddf401365057044fb721ec6bddb/certifi-2025.11.12-py3-none-any.whl", hash = "sha256:97de8790030bbd5c2d96b7ec782fc2f7820ef8dba6db909ccf95449f2d062d4b", size = 159438, upload-time = "2025-11-12T02:54:49.735Z" }, + { url = "https://files.pythonhosted.org/packages/e6/ad/3cc14f097111b4de0040c83a525973216457bbeeb63739ef1ed275c1c021/certifi-2026.1.4-py3-none-any.whl", hash = "sha256:9943707519e4add1115f44c2bc244f782c0249876bf51b6599fee1ffbedd685c", size = 152900, upload-time = "2026-01-04T02:42:40.15Z" }, ] [[package]] @@ -184,6 +198,48 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/d1/d6/3965ed04c63042e047cb6a3e6ed1a63a35087b6a609aa3a15ed8ac56c221/colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6", size = 25335, upload-time = "2022-10-25T02:36:20.889Z" }, ] +[[package]] +name = "complexipy" +version = "5.1.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "tomli", marker = "sys_platform == 'linux'" }, + { name = "typer", marker = "sys_platform == 'linux'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/cd/37/5367d70e04d971ccfaf0d270a9fac5dbbf26fc6823c25d8d2ec281fb58b6/complexipy-5.1.0.tar.gz", hash = "sha256:42e2c3dd6fc01c4b8a738307f1503c90acd58c5896fdbd193b3be22bb2efe4dd", size = 290590, upload-time = "2025-12-09T16:14:16.744Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/bb/61/d58cd89303b892d07ce223767a085eb85ad80cda449a7ca1944a59e07a1c/complexipy-5.1.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:8cc767625a6a25ffa07ccc38d089bf4d7d9fe3e1686d4ccb93f1f28674a55ab7", size = 2157805, upload-time = "2025-12-09T16:11:59.807Z" }, + { url = "https://files.pythonhosted.org/packages/2b/77/59cc3e39a968498bc0792c7da57046454ec4f07ffe18427ad97fa379ab69/complexipy-5.1.0-cp311-cp311-manylinux2014_armv7l.manylinux_2_17_armv7l.whl", hash = "sha256:babe436f0712f08601eb87025ffe53539f6dffad66b04ac1bfd934399f1bc821", size = 2109492, upload-time = "2025-12-09T16:12:01.703Z" }, + { url = "https://files.pythonhosted.org/packages/22/1c/d39ed50c049ddc531c3b5d5c59823fed78dea1d4d8a51f4d90dd462ed0d9/complexipy-5.1.0-cp311-cp311-manylinux2014_i686.manylinux_2_17_i686.whl", hash = "sha256:1edcb6939de6146583e399cd5cf5d04f603237dd74eb9c6e407ac2035d458d95", size = 2286247, upload-time = "2025-12-09T16:12:03.284Z" }, + { url = "https://files.pythonhosted.org/packages/01/78/ebe045688bd07fe9d31c014f50aa45b9355f78d4eafd616bb6359b088472/complexipy-5.1.0-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:6c4385acade08db360a1e8ea03fecd7d761e1ba6708ceb6c24bee2fdbe728246", size = 2517548, upload-time = "2025-12-09T16:12:05.209Z" }, + { url = "https://files.pythonhosted.org/packages/d3/f5/9ef44abbd48823f754e71c5469a3d1ea044a3b1edd4047baffe5982897e4/complexipy-5.1.0-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:d5c3d0a49d20f450a7161c61471b04aa4c2c9b565aef867eadb2bff5fb7a4141", size = 2303721, upload-time = "2025-12-09T16:12:06.828Z" }, + { url = "https://files.pythonhosted.org/packages/18/5e/ba43c6d0fea4b84b51ccf405c4ea1e307f608e54c58e56a972f64c92aecc/complexipy-5.1.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:2375f61a66bf664269468e6714cce0071930cb328d63156dc562612b666d7e54", size = 2212414, upload-time = "2025-12-09T16:12:08.414Z" }, + { url = "https://files.pythonhosted.org/packages/77/40/ef2215409198a0ed61ba3247a117a073e019010a18b0ecc2d909c1b47f13/complexipy-5.1.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:2f46d700a8212b08c21b1afb0f0e38b6b51d8012259c52b6a462797832ea72af", size = 2157109, upload-time = "2025-12-09T16:12:17.756Z" }, + { url = "https://files.pythonhosted.org/packages/20/65/64c9a6ab0b5ff34e595371ecd12cf56215d53621edf50dbfdb61e46722a9/complexipy-5.1.0-cp312-cp312-manylinux2014_armv7l.manylinux_2_17_armv7l.whl", hash = "sha256:961858226df07958472ebc579c186119b782b2b9b425e5ef7083807b44594c59", size = 2109236, upload-time = "2025-12-09T16:12:19.294Z" }, + { url = "https://files.pythonhosted.org/packages/7f/68/f4b41cdfa25a6cc0d5b424b6033489a0255e3b5d36d792c35cfd713dcae0/complexipy-5.1.0-cp312-cp312-manylinux2014_i686.manylinux_2_17_i686.whl", hash = "sha256:c9ed814e0eb833ddbb5594701761edc9938cd6d151b87bcc33b98133ef127e8a", size = 2286796, upload-time = "2025-12-09T16:12:20.785Z" }, + { url = "https://files.pythonhosted.org/packages/19/e9/b2dc94ce19d37c3288a7804813a0f7921540e70174a35306c0cf8a61c67b/complexipy-5.1.0-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:63f2060e72a628e18c196a856459fdb826afe46b8336e83d519e2572266226e3", size = 2515904, upload-time = "2025-12-09T16:12:22.381Z" }, + { url = "https://files.pythonhosted.org/packages/72/f4/2caf422006345ce15d7cabcd55f362dc4d9bf0e7fbe3ebc24e2412961ad2/complexipy-5.1.0-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:fc74d1da61159d03eadba7306183d155e32bf8c64e8dd18d4a81816bc784e605", size = 2298546, upload-time = "2025-12-09T16:12:24.189Z" }, + { url = "https://files.pythonhosted.org/packages/b7/82/7bf567fbe6b5cc4d2fd4ea116f77c6f1bd0337c90222b521abe1b6707b7a/complexipy-5.1.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:9bb8497897b85c30970bc62abf7307e3ddf14dccc51c6613382cfdb790881e84", size = 2212131, upload-time = "2025-12-09T16:12:25.739Z" }, + { url = "https://files.pythonhosted.org/packages/5d/3b/37e29cc60b9c27e18f680d19feba7961265efcb06adeee159fc52c27f077/complexipy-5.1.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:d2e7c8255cd2b9c1909307c68a88e8d43701f13611359b05fe2969bca5be9b2e", size = 2157109, upload-time = "2025-12-09T16:12:35.828Z" }, + { url = "https://files.pythonhosted.org/packages/f9/20/8ae2900c80b6bcd2928c9c786ed43bc98231e147c9bf2ffa3c7d08f4455e/complexipy-5.1.0-cp313-cp313-manylinux2014_armv7l.manylinux_2_17_armv7l.whl", hash = "sha256:7d14795e158903a03b801512990a55039589c82ecab0f93851e714de932bcb01", size = 2109235, upload-time = "2025-12-09T16:12:37.717Z" }, + { url = "https://files.pythonhosted.org/packages/f4/9d/11d27b601a063cea3ebd692ba6815212478defadb7571bab174cc6e301c6/complexipy-5.1.0-cp313-cp313-manylinux2014_i686.manylinux_2_17_i686.whl", hash = "sha256:d7ad9c9eee45f03a98622115558c623ab7df21ecaf5da48062ceeeafba16ee0e", size = 2286798, upload-time = "2025-12-09T16:12:39.658Z" }, + { url = "https://files.pythonhosted.org/packages/5c/c7/6d236f7a858547608a003d99a3a335efbeaf665bde78478557374ed02543/complexipy-5.1.0-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:d58a858c35bc02c0c0934fb938c3e927c91174fa3542fbf208d1e0c387181a15", size = 2515904, upload-time = "2025-12-09T16:12:41.312Z" }, + { url = "https://files.pythonhosted.org/packages/e8/da/4507e066b275390eb5bc3fc7122062da1eef48ab725d355fb423130a4daf/complexipy-5.1.0-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:7f50d199be8a210d024f49176ea38ccf86051aed53c8e7e7d3e3681254ca8899", size = 2298544, upload-time = "2025-12-09T16:12:42.972Z" }, + { url = "https://files.pythonhosted.org/packages/c6/d6/e69525d75f7daeb804f275b3e899442d892213445fcb2759cded28e8d9f4/complexipy-5.1.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:5c5750d2482cd0865dff5bfc55c6a1c2fe744076736cca9c48da28bdef4403a9", size = 2212129, upload-time = "2025-12-09T16:12:45.113Z" }, + { url = "https://files.pythonhosted.org/packages/c7/d5/2e9402fd2cfbb245522cea969012d8ff2118e2a6043d39e28384a937b97b/complexipy-5.1.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:3f4edeed6dcf10703dcda74029d898ab962fafe020e989b4087004c8e43903a8", size = 2157109, upload-time = "2025-12-09T16:12:53.524Z" }, + { url = "https://files.pythonhosted.org/packages/8d/1e/11e12651bb82f1d582ea8d5dc4a0605e77aee6fc712b417519a7aec5bc4b/complexipy-5.1.0-cp314-cp314-manylinux2014_armv7l.manylinux_2_17_armv7l.whl", hash = "sha256:4d4e2759dd65f0b49f790233a38bfc96daf166142f08d8448318e02a629cd83f", size = 2109235, upload-time = "2025-12-09T16:12:55.142Z" }, + { url = "https://files.pythonhosted.org/packages/35/43/5dd13d200e943841e3d6dd1ab3be7324a0aeabefe6653850235db969b2de/complexipy-5.1.0-cp314-cp314-manylinux2014_i686.manylinux_2_17_i686.whl", hash = "sha256:00f592477da6c8c0c7bf6900fde88d92027789bc86f6afc2ad084f37ed72f9f0", size = 2286796, upload-time = "2025-12-09T16:12:57.219Z" }, + { url = "https://files.pythonhosted.org/packages/f5/11/45ddcefb75a1e14b60a7a55743089aa1bf98e16174ed64fddf59e6b0b57a/complexipy-5.1.0-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:f5a644437a9379b2c71265163d5bb4ed6eacac592ff49f6051856dc1d1bc9228", size = 2515905, upload-time = "2025-12-09T16:12:59.061Z" }, + { url = "https://files.pythonhosted.org/packages/63/76/650a19b8ee66cbe3a12a2a9bd228d552b84316a51c57aa2cbb936e48bd61/complexipy-5.1.0-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:1c9162ac22f466060e1d11c72f57a85ce5c17863322030492f508f02effe4739", size = 2298545, upload-time = "2025-12-09T16:13:01.416Z" }, + { url = "https://files.pythonhosted.org/packages/6c/dd/8b22d8830b7406086f9ec37f344e1d9f3ebe073812a617af43e3af3a5caa/complexipy-5.1.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:db37b0a08d208f03c907a19d9a3798b99d4c74ada8aacbbe5ebc6996ab1706d9", size = 2212130, upload-time = "2025-12-09T16:13:02.964Z" }, + { url = "https://files.pythonhosted.org/packages/1b/06/7f0892801bfd1b87c91b6fc80043746e0cf586e90044211975a771fb01c1/complexipy-5.1.0-pp311-pypy311_pp73-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:d7172ce261119ee41914ab919dee56d03c845f329acf1e7bf78cb83502d9f75e", size = 2159186, upload-time = "2025-12-09T16:13:50.549Z" }, + { url = "https://files.pythonhosted.org/packages/ef/b7/abe4e65780d1fc2de8fbd0b4d30511c2fc8434bc5dff1478b6904d3be77d/complexipy-5.1.0-pp311-pypy311_pp73-manylinux2014_armv7l.manylinux_2_17_armv7l.whl", hash = "sha256:6c4c703b4b742c0a59cdd617a9b326b5160d0e6ef54bfb5cd16780889955f4d1", size = 2109605, upload-time = "2025-12-09T16:13:52.143Z" }, + { url = "https://files.pythonhosted.org/packages/f6/79/049c5c3b33f0c1da39c6fa7789b3228039ba1518b5e52b4dcd5b5d214637/complexipy-5.1.0-pp311-pypy311_pp73-manylinux2014_i686.manylinux_2_17_i686.whl", hash = "sha256:645db6074ed4bb76e5343b98b1a0782a37a5e2ec9abf7a8bac7c1e85709497ca", size = 2285573, upload-time = "2025-12-09T16:13:53.999Z" }, + { url = "https://files.pythonhosted.org/packages/fa/61/f18e641f3f6ff735ec473893733aed5e7027c9169c170cdd0e263fe57742/complexipy-5.1.0-pp311-pypy311_pp73-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:9e1a40f0ee5a67c6e2d6b11965cee06a250123602c720eaa3a859455bcf8c2ba", size = 2519555, upload-time = "2025-12-09T16:13:55.914Z" }, + { url = "https://files.pythonhosted.org/packages/0d/b9/72e61f961d92dfc99fd56ffed3be1fa1f9b6ebd085ba29e6f3805946a498/complexipy-5.1.0-pp311-pypy311_pp73-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:b8a874ff7e6e0358696ada43f76d09653e6318435723c9fd14c1e62525878d8a", size = 2305463, upload-time = "2025-12-09T16:13:57.606Z" }, + { url = "https://files.pythonhosted.org/packages/9b/15/c7cb46afd4348bf06be749911a0a6e5fbd5f6998163f515c907dc3a7cc86/complexipy-5.1.0-pp311-pypy311_pp73-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:8a5e280b627005dd72d893f4a195dbdd3dcfd1eff7929cfffa65303ae0138eb4", size = 2212919, upload-time = "2025-12-09T16:14:00.644Z" }, +] + [[package]] name = "cookiecutter" version = "2.6.0" @@ -229,14 +285,14 @@ wheels = [ [[package]] name = "gitpython" -version = "3.1.45" +version = "3.1.46" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "gitdb", marker = "sys_platform == 'linux'" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/9a/c8/dd58967d119baab745caec2f9d853297cec1989ec1d63f677d3880632b88/gitpython-3.1.45.tar.gz", hash = "sha256:85b0ee964ceddf211c41b9f27a49086010a190fd8132a24e21f362a4b36a791c", size = 215076, upload-time = "2025-07-24T03:45:54.871Z" } +sdist = { url = "https://files.pythonhosted.org/packages/df/b5/59d16470a1f0dfe8c793f9ef56fd3826093fc52b3bd96d6b9d6c26c7e27b/gitpython-3.1.46.tar.gz", hash = "sha256:400124c7d0ef4ea03f7310ac2fbf7151e09ff97f2a3288d64a440c584a29c37f", size = 215371, upload-time = "2026-01-01T15:37:32.073Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/01/61/d4b89fec821f72385526e1b9d9a3a0385dda4a72b206d28049e2c7cd39b8/gitpython-3.1.45-py3-none-any.whl", hash = "sha256:8908cb2e02fb3b93b7eb0f2827125cb699869470432cc885f019b8fd0fccff77", size = 208168, upload-time = "2025-07-24T03:45:52.517Z" }, + { url = "https://files.pythonhosted.org/packages/6a/09/e21df6aef1e1ffc0c816f0522ddc3f6dcded766c3261813131c78a704470/gitpython-3.1.46-py3-none-any.whl", hash = "sha256:79812ed143d9d25b6d176a10bb511de0f9c67b1fa641d82097b0ab90398a2058", size = 208620, upload-time = "2026-01-01T15:37:30.574Z" }, ] [[package]] @@ -250,14 +306,14 @@ wheels = [ [[package]] name = "importlib-metadata" -version = "8.7.0" +version = "8.7.1" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "zipp", marker = "sys_platform == 'linux'" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/76/66/650a33bd90f786193e4de4b3ad86ea60b53c89b669a5c7be931fac31cdb0/importlib_metadata-8.7.0.tar.gz", hash = "sha256:d13b81ad223b890aa16c5471f2ac3056cf76c5f10f82d6f9292f0b415f389000", size = 56641, upload-time = "2025-04-27T15:29:01.736Z" } +sdist = { url = "https://files.pythonhosted.org/packages/f3/49/3b30cad09e7771a4982d9975a8cbf64f00d4a1ececb53297f1d9a7be1b10/importlib_metadata-8.7.1.tar.gz", hash = "sha256:49fef1ae6440c182052f407c8d34a68f72efc36db9ca90dc0113398f2fdde8bb", size = 57107, upload-time = "2025-12-21T10:00:19.278Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/20/b0/36bd937216ec521246249be3bf9855081de4c5e06a0c9b4219dbeda50373/importlib_metadata-8.7.0-py3-none-any.whl", hash = "sha256:e5dd1551894c77868a30651cef00984d50e1002d06942a7101d34870c5f02afd", size = 27656, upload-time = "2025-04-27T15:29:00.214Z" }, + { url = "https://files.pythonhosted.org/packages/fa/5e/f8e9a1d23b9c20a551a8a02ea3637b4642e22c2626e3a13a9a29cdea99eb/importlib_metadata-8.7.1-py3-none-any.whl", hash = "sha256:5a1f80bf1daa489495071efbb095d75a634cf28a8bc299581244063b53176151", size = 27865, upload-time = "2025-12-21T10:00:18.329Z" }, ] [[package]] @@ -269,6 +325,15 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/a4/ed/1f1afb2e9e7f38a545d628f864d562a5ae64fe6f7a10e28ffb9b185b4e89/importlib_resources-6.5.2-py3-none-any.whl", hash = "sha256:789cfdc3ed28c78b67a06acb8126751ced69a3d5f79c095a98298cd8a760ccec", size = 37461, upload-time = "2025-01-03T18:51:54.306Z" }, ] +[[package]] +name = "isort" +version = "7.0.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/63/53/4f3c058e3bace40282876f9b553343376ee687f3c35a525dc79dbd450f88/isort-7.0.0.tar.gz", hash = "sha256:5513527951aadb3ac4292a41a16cbc50dd1642432f5e8c20057d414bdafb4187", size = 805049, upload-time = "2025-10-11T13:30:59.107Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/7f/ed/e3705d6d02b4f7aea715a353c8ce193efd0b5db13e204df895d38734c244/isort-7.0.0-py3-none-any.whl", hash = "sha256:1bcabac8bc3c36c7fb7b98a76c8abb18e0f841a3ba81decac7691008592499c1", size = 94672, upload-time = "2025-10-11T13:30:57.665Z" }, +] + [[package]] name = "jinja2" version = "3.1.6" @@ -281,6 +346,44 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/62/a1/3d680cbfd5f4b8f15abc1d571870c5fc3e594bb582bc3b64ea099db13e56/jinja2-3.1.6-py3-none-any.whl", hash = "sha256:85ece4451f492d0c13c5dd7c13a64681a86afae63a5f347908daf103ce6d2f67", size = 134899, upload-time = "2025-03-05T20:05:00.369Z" }, ] +[[package]] +name = "librt" +version = "0.7.7" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/b7/29/47f29026ca17f35cf299290292d5f8331f5077364974b7675a353179afa2/librt-0.7.7.tar.gz", hash = "sha256:81d957b069fed1890953c3b9c3895c7689960f233eea9a1d9607f71ce7f00b2c", size = 145910, upload-time = "2026-01-01T23:52:22.87Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/1c/ea/7d7a1ee7dfc1151836028eba25629afcf45b56bbc721293e41aa2e9b8934/librt-0.7.7-cp311-cp311-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:b8bb331aad734b059c4b450cd0a225652f16889e286b2345af5e2c3c625c3d85", size = 161705, upload-time = "2026-01-01T23:51:04.917Z" }, + { url = "https://files.pythonhosted.org/packages/45/a5/952bc840ac8917fbcefd6bc5f51ad02b89721729814f3e2bfcc1337a76d6/librt-0.7.7-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:467dbd7443bda08338fc8ad701ed38cef48194017554f4c798b0a237904b3f99", size = 171029, upload-time = "2026-01-01T23:51:06.09Z" }, + { url = "https://files.pythonhosted.org/packages/fa/bf/c017ff7da82dc9192cf40d5e802a48a25d00e7639b6465cfdcee5893a22c/librt-0.7.7-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:50d1d1ee813d2d1a3baf2873634ba506b263032418d16287c92ec1cc9c1a00cb", size = 184704, upload-time = "2026-01-01T23:51:07.549Z" }, + { url = "https://files.pythonhosted.org/packages/77/ec/72f3dd39d2cdfd6402ab10836dc9cbf854d145226062a185b419c4f1624a/librt-0.7.7-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:c7e5070cf3ec92d98f57574da0224f8c73faf1ddd6d8afa0b8c9f6e86997bc74", size = 180719, upload-time = "2026-01-01T23:51:09.062Z" }, + { url = "https://files.pythonhosted.org/packages/78/86/06e7a1a81b246f3313bf515dd9613a1c81583e6fd7843a9f4d625c4e926d/librt-0.7.7-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:bdb9f3d865b2dafe7f9ad7f30ef563c80d0ddd2fdc8cc9b8e4f242f475e34d75", size = 174537, upload-time = "2026-01-01T23:51:10.611Z" }, + { url = "https://files.pythonhosted.org/packages/83/08/f9fb2edc9c7a76e95b2924ce81d545673f5b034e8c5dd92159d1c7dae0c6/librt-0.7.7-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:8185c8497d45164e256376f9da5aed2bb26ff636c798c9dabe313b90e9f25b28", size = 195238, upload-time = "2026-01-01T23:51:11.762Z" }, + { url = "https://files.pythonhosted.org/packages/23/6f/0c86b5cb5e7ef63208c8cc22534df10ecc5278efc0d47fb8815577f3ca2f/librt-0.7.7-cp312-cp312-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:c9faaebb1c6212c20afd8043cd6ed9de0a47d77f91a6b5b48f4e46ed470703fe", size = 165320, upload-time = "2026-01-01T23:51:18.455Z" }, + { url = "https://files.pythonhosted.org/packages/16/37/df4652690c29f645ffe405b58285a4109e9fe855c5bb56e817e3e75840b3/librt-0.7.7-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1908c3e5a5ef86b23391448b47759298f87f997c3bd153a770828f58c2bb4630", size = 174216, upload-time = "2026-01-01T23:51:19.599Z" }, + { url = "https://files.pythonhosted.org/packages/9a/d6/d3afe071910a43133ec9c0f3e4ce99ee6df0d4e44e4bddf4b9e1c6ed41cc/librt-0.7.7-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:dbc4900e95a98fc0729523be9d93a8fedebb026f32ed9ffc08acd82e3e181503", size = 189005, upload-time = "2026-01-01T23:51:21.052Z" }, + { url = "https://files.pythonhosted.org/packages/d5/18/74060a870fe2d9fd9f47824eba6717ce7ce03124a0d1e85498e0e7efc1b2/librt-0.7.7-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:a7ea4e1fbd253e5c68ea0fe63d08577f9d288a73f17d82f652ebc61fa48d878d", size = 183961, upload-time = "2026-01-01T23:51:22.493Z" }, + { url = "https://files.pythonhosted.org/packages/7c/5e/918a86c66304af66a3c1d46d54df1b2d0b8894babc42a14fb6f25511497f/librt-0.7.7-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:ef7699b7a5a244b1119f85c5bbc13f152cd38240cbb2baa19b769433bae98e50", size = 177610, upload-time = "2026-01-01T23:51:23.874Z" }, + { url = "https://files.pythonhosted.org/packages/b2/d7/b5e58dc2d570f162e99201b8c0151acf40a03a39c32ab824dd4febf12736/librt-0.7.7-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:955c62571de0b181d9e9e0a0303c8bc90d47670a5eff54cf71bf5da61d1899cf", size = 199272, upload-time = "2026-01-01T23:51:25.341Z" }, + { url = "https://files.pythonhosted.org/packages/50/df/030b50614b29e443607220097ebaf438531ea218c7a9a3e21ea862a919cd/librt-0.7.7-cp313-cp313-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:9b4346b1225be26def3ccc6c965751c74868f0578cbcba293c8ae9168483d811", size = 165834, upload-time = "2026-01-01T23:51:32.278Z" }, + { url = "https://files.pythonhosted.org/packages/5d/e1/bd8d1eacacb24be26a47f157719553bbd1b3fe812c30dddf121c0436fd0b/librt-0.7.7-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:a10b8eebdaca6e9fdbaf88b5aefc0e324b763a5f40b1266532590d5afb268a4c", size = 174819, upload-time = "2026-01-01T23:51:33.461Z" }, + { url = "https://files.pythonhosted.org/packages/46/7d/91d6c3372acf54a019c1ad8da4c9ecf4fc27d039708880bf95f48dbe426a/librt-0.7.7-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:067be973d90d9e319e6eb4ee2a9b9307f0ecd648b8a9002fa237289a4a07a9e7", size = 189607, upload-time = "2026-01-01T23:51:34.604Z" }, + { url = "https://files.pythonhosted.org/packages/fa/ac/44604d6d3886f791fbd1c6ae12d5a782a8f4aca927484731979f5e92c200/librt-0.7.7-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:23d2299ed007812cccc1ecef018db7d922733382561230de1f3954db28433977", size = 184586, upload-time = "2026-01-01T23:51:35.845Z" }, + { url = "https://files.pythonhosted.org/packages/5c/26/d8a6e4c17117b7f9b83301319d9a9de862ae56b133efb4bad8b3aa0808c9/librt-0.7.7-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:6b6f8ea465524aa4c7420c7cc4ca7d46fe00981de8debc67b1cc2e9957bb5b9d", size = 178251, upload-time = "2026-01-01T23:51:37.018Z" }, + { url = "https://files.pythonhosted.org/packages/99/ab/98d857e254376f8e2f668e807daccc1f445e4b4fc2f6f9c1cc08866b0227/librt-0.7.7-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:f8df32a99cc46eb0ee90afd9ada113ae2cafe7e8d673686cf03ec53e49635439", size = 199853, upload-time = "2026-01-01T23:51:38.195Z" }, + { url = "https://files.pythonhosted.org/packages/0e/77/de50ff70c80855eb79d1d74035ef06f664dd073fb7fb9d9fb4429651b8eb/librt-0.7.7-cp314-cp314-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:2567cb48dc03e5b246927ab35cbb343376e24501260a9b5e30b8e255dca0d1d2", size = 163724, upload-time = "2026-01-01T23:51:45.571Z" }, + { url = "https://files.pythonhosted.org/packages/6e/19/f8e4bf537899bdef9e0bb9f0e4b18912c2d0f858ad02091b6019864c9a6d/librt-0.7.7-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6066c638cdf85ff92fc6f932d2d73c93a0e03492cdfa8778e6d58c489a3d7259", size = 172470, upload-time = "2026-01-01T23:51:46.823Z" }, + { url = "https://files.pythonhosted.org/packages/42/4c/dcc575b69d99076768e8dd6141d9aecd4234cba7f0e09217937f52edb6ed/librt-0.7.7-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a609849aca463074c17de9cda173c276eb8fee9e441053529e7b9e249dc8b8ee", size = 186806, upload-time = "2026-01-01T23:51:48.009Z" }, + { url = "https://files.pythonhosted.org/packages/fe/f8/4094a2b7816c88de81239a83ede6e87f1138477d7ee956c30f136009eb29/librt-0.7.7-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:add4e0a000858fe9bb39ed55f31085506a5c38363e6eb4a1e5943a10c2bfc3d1", size = 181809, upload-time = "2026-01-01T23:51:49.35Z" }, + { url = "https://files.pythonhosted.org/packages/1b/ac/821b7c0ab1b5a6cd9aee7ace8309c91545a2607185101827f79122219a7e/librt-0.7.7-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:a3bfe73a32bd0bdb9a87d586b05a23c0a1729205d79df66dee65bb2e40d671ba", size = 175597, upload-time = "2026-01-01T23:51:50.636Z" }, + { url = "https://files.pythonhosted.org/packages/71/f9/27f6bfbcc764805864c04211c6ed636fe1d58f57a7b68d1f4ae5ed74e0e0/librt-0.7.7-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:0ecce0544d3db91a40f8b57ae26928c02130a997b540f908cefd4d279d6c5848", size = 196506, upload-time = "2026-01-01T23:51:52.535Z" }, + { url = "https://files.pythonhosted.org/packages/96/47/7383a507d8e0c11c78ca34c9d36eab9000db5989d446a2f05dc40e76c64f/librt-0.7.7-cp314-cp314t-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:9b15e5d17812d4d629ff576699954f74e2cc24a02a4fc401882dd94f81daba45", size = 183870, upload-time = "2026-01-01T23:51:59.204Z" }, + { url = "https://files.pythonhosted.org/packages/a4/b8/50f3d8eec8efdaf79443963624175c92cec0ba84827a66b7fcfa78598e51/librt-0.7.7-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c084841b879c4d9b9fa34e5d5263994f21aea7fd9c6add29194dbb41a6210536", size = 194608, upload-time = "2026-01-01T23:52:00.419Z" }, + { url = "https://files.pythonhosted.org/packages/23/d9/1b6520793aadb59d891e3b98ee057a75de7f737e4a8b4b37fdbecb10d60f/librt-0.7.7-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:10c8fb9966f84737115513fecbaf257f9553d067a7dd45a69c2c7e5339e6a8dc", size = 206776, upload-time = "2026-01-01T23:52:01.705Z" }, + { url = "https://files.pythonhosted.org/packages/ff/db/331edc3bba929d2756fa335bfcf736f36eff4efcb4f2600b545a35c2ae58/librt-0.7.7-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:9b5fb1ecb2c35362eab2dbd354fd1efa5a8440d3e73a68be11921042a0edc0ff", size = 203206, upload-time = "2026-01-01T23:52:03.315Z" }, + { url = "https://files.pythonhosted.org/packages/b2/e1/6af79ec77204e85f6f2294fc171a30a91bb0e35d78493532ed680f5d98be/librt-0.7.7-cp314-cp314t-musllinux_1_2_i686.whl", hash = "sha256:d1454899909d63cc9199a89fcc4f81bdd9004aef577d4ffc022e600c412d57f3", size = 196697, upload-time = "2026-01-01T23:52:04.857Z" }, + { url = "https://files.pythonhosted.org/packages/f3/46/de55ecce4b2796d6d243295c221082ca3a944dc2fb3a52dcc8660ce7727d/librt-0.7.7-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:7ef28f2e7a016b29792fe0a2dd04dec75725b32a1264e390c366103f834a9c3a", size = 217193, upload-time = "2026-01-01T23:52:06.159Z" }, +] + [[package]] name = "markdown" version = "3.10" @@ -505,6 +608,42 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/5b/54/662a4743aa81d9582ee9339d4ffa3c8fd40a4965e033d77b9da9774d3960/mkdocs_material_extensions-1.3.1-py3-none-any.whl", hash = "sha256:adff8b62700b25cb77b53358dad940f3ef973dd6db797907c49e3c2ef3ab4e31", size = 8728, upload-time = "2023-11-22T19:09:43.465Z" }, ] +[[package]] +name = "mypy" +version = "1.19.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "librt", marker = "platform_python_implementation != 'PyPy' and sys_platform == 'linux'" }, + { name = "mypy-extensions", marker = "sys_platform == 'linux'" }, + { name = "pathspec", marker = "sys_platform == 'linux'" }, + { name = "typing-extensions", marker = "sys_platform == 'linux'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/f5/db/4efed9504bc01309ab9c2da7e352cc223569f05478012b5d9ece38fd44d2/mypy-1.19.1.tar.gz", hash = "sha256:19d88bb05303fe63f71dd2c6270daca27cb9401c4ca8255fe50d1d920e0eb9ba", size = 3582404, upload-time = "2025-12-15T05:03:48.42Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/67/af/3afa9cf880aa4a2c803798ac24f1d11ef72a0c8079689fac5cfd815e2830/mypy-1.19.1-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:2abb24cf3f17864770d18d673c85235ba52456b36a06b6afc1e07c1fdcd3d0e6", size = 12687629, upload-time = "2025-12-15T05:02:31.526Z" }, + { url = "https://files.pythonhosted.org/packages/2d/46/20f8a7114a56484ab268b0ab372461cb3a8f7deed31ea96b83a4e4cfcfca/mypy-1.19.1-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a009ffa5a621762d0c926a078c2d639104becab69e79538a494bcccb62cc0331", size = 13436933, upload-time = "2025-12-15T05:03:15.606Z" }, + { url = "https://files.pythonhosted.org/packages/5b/f8/33b291ea85050a21f15da910002460f1f445f8007adb29230f0adea279cb/mypy-1.19.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:f7cee03c9a2e2ee26ec07479f38ea9c884e301d42c6d43a19d20fb014e3ba925", size = 13661754, upload-time = "2025-12-15T05:02:26.731Z" }, + { url = "https://files.pythonhosted.org/packages/89/cc/2db6f0e95366b630364e09845672dbee0cbf0bbe753a204b29a944967cd9/mypy-1.19.1-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b64d987153888790bcdb03a6473d321820597ab8dd9243b27a92153c4fa50fd2", size = 12731616, upload-time = "2025-12-15T05:02:44.725Z" }, + { url = "https://files.pythonhosted.org/packages/00/be/dd56c1fd4807bc1eba1cf18b2a850d0de7bacb55e158755eb79f77c41f8e/mypy-1.19.1-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c35d298c2c4bba75feb2195655dfea8124d855dfd7343bf8b8c055421eaf0cf8", size = 13620847, upload-time = "2025-12-15T05:03:39.633Z" }, + { url = "https://files.pythonhosted.org/packages/6d/42/332951aae42b79329f743bf1da088cd75d8d4d9acc18fbcbd84f26c1af4e/mypy-1.19.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:34c81968774648ab5ac09c29a375fdede03ba253f8f8287847bd480782f73a6a", size = 13834976, upload-time = "2025-12-15T05:03:08.786Z" }, + { url = "https://files.pythonhosted.org/packages/05/bb/cdcf89678e26b187650512620eec8368fded4cfd99cfcb431e4cdfd19dec/mypy-1.19.1-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f859fb09d9583a985be9a493d5cfc5515b56b08f7447759a0c5deaf68d80506e", size = 12724581, upload-time = "2025-12-15T05:03:20.087Z" }, + { url = "https://files.pythonhosted.org/packages/d1/32/dd260d52babf67bad8e6770f8e1102021877ce0edea106e72df5626bb0ec/mypy-1.19.1-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c9a6538e0415310aad77cb94004ca6482330fece18036b5f360b62c45814c4ef", size = 13616252, upload-time = "2025-12-15T05:02:49.036Z" }, + { url = "https://files.pythonhosted.org/packages/71/d0/5e60a9d2e3bd48432ae2b454b7ef2b62a960ab51292b1eda2a95edd78198/mypy-1.19.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:da4869fc5e7f62a88f3fe0b5c919d1d9f7ea3cef92d3689de2823fd27e40aa75", size = 13840848, upload-time = "2025-12-15T05:02:55.95Z" }, + { url = "https://files.pythonhosted.org/packages/0a/c6/bdd60774a0dbfb05122e3e925f2e9e846c009e479dcec4821dad881f5b52/mypy-1.19.1-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:21761006a7f497cb0d4de3d8ef4ca70532256688b0523eee02baf9eec895e27b", size = 12740047, upload-time = "2025-12-15T05:03:33.168Z" }, + { url = "https://files.pythonhosted.org/packages/32/2a/66ba933fe6c76bd40d1fe916a83f04fed253152f451a877520b3c4a5e41e/mypy-1.19.1-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:28902ee51f12e0f19e1e16fbe2f8f06b6637f482c459dd393efddd0ec7f82045", size = 13601998, upload-time = "2025-12-15T05:03:13.056Z" }, + { url = "https://files.pythonhosted.org/packages/e3/da/5055c63e377c5c2418760411fd6a63ee2b96cf95397259038756c042574f/mypy-1.19.1-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:481daf36a4c443332e2ae9c137dfee878fcea781a2e3f895d54bd3002a900957", size = 13807476, upload-time = "2025-12-15T05:03:17.977Z" }, + { url = "https://files.pythonhosted.org/packages/8d/f4/4ce9a05ce5ded1de3ec1c1d96cf9f9504a04e54ce0ed55cfa38619a32b8d/mypy-1.19.1-py3-none-any.whl", hash = "sha256:f1235f5ea01b7db5468d53ece6aaddf1ad0b88d9e7462b86ef96fe04995d7247", size = 2471239, upload-time = "2025-12-15T05:03:07.248Z" }, +] + +[[package]] +name = "mypy-extensions" +version = "1.1.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/a2/6e/371856a3fb9d31ca8dac321cda606860fa4548858c0cc45d9d1d4ca2628b/mypy_extensions-1.1.0.tar.gz", hash = "sha256:52e68efc3284861e772bbcd66823fde5ae21fd2fdb51c62a211403730b916558", size = 6343, upload-time = "2025-04-22T14:54:24.164Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/79/7b/2c79738432f5c924bef5071f933bcc9efd0473bac3b4aa584a6f7c1c8df8/mypy_extensions-1.1.0-py3-none-any.whl", hash = "sha256:1be4cccdb0f2482337c4743e60421de3a356cd97508abadd57d47403e94f5505", size = 4963, upload-time = "2025-04-22T14:54:22.983Z" }, +] + [[package]] name = "natsort" version = "8.4.0" @@ -534,11 +673,11 @@ wheels = [ [[package]] name = "pathspec" -version = "0.12.1" +version = "1.0.3" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/ca/bc/f35b8446f4531a7cb215605d100cd88b7ac6f44ab3fc94870c120ab3adbf/pathspec-0.12.1.tar.gz", hash = "sha256:a482d51503a1ab33b1c67a6c3813a26953dbdc71c31dacaef9a838c4e29f5712", size = 51043, upload-time = "2023-12-10T22:30:45Z" } +sdist = { url = "https://files.pythonhosted.org/packages/4c/b2/bb8e495d5262bfec41ab5cb18f522f1012933347fb5d9e62452d446baca2/pathspec-1.0.3.tar.gz", hash = "sha256:bac5cf97ae2c2876e2d25ebb15078eb04d76e4b98921ee31c6f85ade8b59444d", size = 130841, upload-time = "2026-01-09T15:46:46.009Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/cc/20/ff623b09d963f88bfde16306a54e12ee5ea43e9b597108672ff3a408aad6/pathspec-0.12.1-py3-none-any.whl", hash = "sha256:a0d503e138a4c123b27490a4f7beda6a01c6f288df0e4a8b79c7eb0dc7b4cc08", size = 31191, upload-time = "2023-12-10T22:30:43.14Z" }, + { url = "https://files.pythonhosted.org/packages/32/2b/121e912bd60eebd623f873fd090de0e84f322972ab25a7f9044c056804ed/pathspec-1.0.3-py3-none-any.whl", hash = "sha256:e80767021c1cc524aa3fb14bedda9c34406591343cc42797b386ce7b9354fb6c", size = 55021, upload-time = "2026-01-09T15:46:44.652Z" }, ] [[package]] @@ -641,24 +780,24 @@ wheels = [ [[package]] name = "pymdown-extensions" -version = "10.17.2" +version = "10.20" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "markdown", marker = "sys_platform == 'linux'" }, { name = "pyyaml", marker = "sys_platform == 'linux'" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/25/6d/af5378dbdb379fddd9a277f8b9888c027db480cde70028669ebd009d642a/pymdown_extensions-10.17.2.tar.gz", hash = "sha256:26bb3d7688e651606260c90fb46409fbda70bf9fdc3623c7868643a1aeee4713", size = 847344, upload-time = "2025-11-26T15:43:57.004Z" } +sdist = { url = "https://files.pythonhosted.org/packages/3e/35/e3814a5b7df295df69d035cfb8aab78b2967cdf11fcfae7faed726b66664/pymdown_extensions-10.20.tar.gz", hash = "sha256:5c73566ab0cf38c6ba084cb7c5ea64a119ae0500cce754ccb682761dfea13a52", size = 852774, upload-time = "2025-12-31T19:59:42.211Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/93/78/b93cb80bd673bdc9f6ede63d8eb5b4646366953df15667eb3603be57a2b1/pymdown_extensions-10.17.2-py3-none-any.whl", hash = "sha256:bffae79a2e8b9e44aef0d813583a8fea63457b7a23643a43988055b7b79b4992", size = 266556, upload-time = "2025-11-26T15:43:55.162Z" }, + { url = "https://files.pythonhosted.org/packages/ea/10/47caf89cbb52e5bb764696fd52a8c591a2f0e851a93270c05a17f36000b5/pymdown_extensions-10.20-py3-none-any.whl", hash = "sha256:ea9e62add865da80a271d00bfa1c0fa085b20d133fb3fc97afdc88e682f60b2f", size = 268733, upload-time = "2025-12-31T19:59:40.652Z" }, ] [[package]] name = "pyparsing" -version = "3.2.5" +version = "3.3.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/f2/a5/181488fc2b9d093e3972d2a472855aae8a03f000592dbfce716a512b3359/pyparsing-3.2.5.tar.gz", hash = "sha256:2df8d5b7b2802ef88e8d016a2eb9c7aeaa923529cd251ed0fe4608275d4105b6", size = 1099274, upload-time = "2025-09-21T04:11:06.277Z" } +sdist = { url = "https://files.pythonhosted.org/packages/33/c1/1d9de9aeaa1b89b0186e5fe23294ff6517fce1bc69149185577cd31016b2/pyparsing-3.3.1.tar.gz", hash = "sha256:47fad0f17ac1e2cad3de3b458570fbc9b03560aa029ed5e16ee5554da9a2251c", size = 1550512, upload-time = "2025-12-23T03:14:04.391Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/10/5e/1aa9a93198c6b64513c9d7752de7422c06402de6600a8767da1524f9570b/pyparsing-3.2.5-py3-none-any.whl", hash = "sha256:e38a4f02064cf41fe6593d328d0512495ad1f3d8a91c4f73fc401b3079a59a5e", size = 113890, upload-time = "2025-09-21T04:11:04.117Z" }, + { url = "https://files.pythonhosted.org/packages/8b/40/2614036cdd416452f5bf98ec037f38a1afb17f327cb8e6b652d4729e0af8/pyparsing-3.3.1-py3-none-any.whl", hash = "sha256:023b5e7e5520ad96642e2c6db4cb683d3970bd640cdf7115049a6e9c3682df82", size = 121793, upload-time = "2025-12-23T03:14:02.103Z" }, ] [[package]] @@ -691,6 +830,13 @@ documentation = [ { name = "mkdocs-git-revision-date-localized-plugin", marker = "sys_platform == 'linux'" }, { name = "mkdocs-material", marker = "sys_platform == 'linux'" }, ] +pipeline = [ + { name = "bandit", marker = "sys_platform == 'linux'" }, + { name = "complexipy", marker = "sys_platform == 'linux'" }, + { name = "isort", marker = "sys_platform == 'linux'" }, + { name = "mypy", marker = "sys_platform == 'linux'" }, + { name = "ruff", marker = "sys_platform == 'linux'" }, +] [package.metadata] requires-dist = [{ name = "cookiecutter", specifier = "==2.6.0" }] @@ -705,6 +851,13 @@ documentation = [ { name = "mkdocs-git-revision-date-localized-plugin", specifier = "==1.5.0" }, { name = "mkdocs-material", specifier = "==9.7.1" }, ] +pipeline = [ + { name = "bandit", specifier = "==1.9.2" }, + { name = "complexipy", specifier = "==5.1.0" }, + { name = "isort", specifier = "==7.0.0" }, + { name = "mypy", specifier = "==1.19.1" }, + { name = "ruff", specifier = "==0.14.11" }, +] [[package]] name = "python-slugify" @@ -791,6 +944,36 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/25/7a/b0178788f8dc6cafce37a212c99565fa1fe7872c70c6c9c1e1a372d9d88f/rich-14.2.0-py3-none-any.whl", hash = "sha256:76bc51fe2e57d2b1be1f96c524b890b816e334ab4c1e45888799bfaab0021edd", size = 243393, upload-time = "2025-10-09T14:16:51.245Z" }, ] +[[package]] +name = "ruff" +version = "0.14.11" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/d4/77/9a7fe084d268f8855d493e5031ea03fa0af8cc05887f638bf1c4e3363eb8/ruff-0.14.11.tar.gz", hash = "sha256:f6dc463bfa5c07a59b1ff2c3b9767373e541346ea105503b4c0369c520a66958", size = 5993417, upload-time = "2026-01-08T19:11:58.322Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/f0/a6/a4c40a5aaa7e331f245d2dc1ac8ece306681f52b636b40ef87c88b9f7afd/ruff-0.14.11-py3-none-linux_armv6l.whl", hash = "sha256:f6ff2d95cbd335841a7217bdfd9c1d2e44eac2c584197ab1385579d55ff8830e", size = 12951208, upload-time = "2026-01-08T19:12:09.218Z" }, + { url = "https://files.pythonhosted.org/packages/a7/e5/5faab97c15bb75228d9f74637e775d26ac703cc2b4898564c01ab3637c02/ruff-0.14.11-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:53386375001773ae812b43205d6064dae49ff0968774e6befe16a994fc233caa", size = 12678447, upload-time = "2026-01-08T19:12:13.899Z" }, + { url = "https://files.pythonhosted.org/packages/1b/33/e9767f60a2bef779fb5855cab0af76c488e0ce90f7bb7b8a45c8a2ba4178/ruff-0.14.11-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:a697737dce1ca97a0a55b5ff0434ee7205943d4874d638fe3ae66166ff46edbe", size = 12758560, upload-time = "2026-01-08T19:11:42.55Z" }, + { url = "https://files.pythonhosted.org/packages/eb/84/4c6cf627a21462bb5102f7be2a320b084228ff26e105510cd2255ea868e5/ruff-0.14.11-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6845ca1da8ab81ab1dce755a32ad13f1db72e7fba27c486d5d90d65e04d17b8f", size = 13599296, upload-time = "2026-01-08T19:11:30.371Z" }, + { url = "https://files.pythonhosted.org/packages/88/e1/92b5ed7ea66d849f6157e695dc23d5d6d982bd6aa8d077895652c38a7cae/ruff-0.14.11-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:e36ce2fd31b54065ec6f76cb08d60159e1b32bdf08507862e32f47e6dde8bcbf", size = 15048981, upload-time = "2026-01-08T19:12:04.742Z" }, + { url = "https://files.pythonhosted.org/packages/61/df/c1bd30992615ac17c2fb64b8a7376ca22c04a70555b5d05b8f717163cf9f/ruff-0.14.11-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:590bcc0e2097ecf74e62a5c10a6b71f008ad82eb97b0a0079e85defe19fe74d9", size = 14633183, upload-time = "2026-01-08T19:11:40.069Z" }, + { url = "https://files.pythonhosted.org/packages/04/e9/fe552902f25013dd28a5428a42347d9ad20c4b534834a325a28305747d64/ruff-0.14.11-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:53fe71125fc158210d57fe4da26e622c9c294022988d08d9347ec1cf782adafe", size = 14050453, upload-time = "2026-01-08T19:11:37.555Z" }, + { url = "https://files.pythonhosted.org/packages/ae/93/f36d89fa021543187f98991609ce6e47e24f35f008dfe1af01379d248a41/ruff-0.14.11-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a35c9da08562f1598ded8470fcfef2afb5cf881996e6c0a502ceb61f4bc9c8a3", size = 13757889, upload-time = "2026-01-08T19:12:07.094Z" }, + { url = "https://files.pythonhosted.org/packages/b7/9f/c7fb6ecf554f28709a6a1f2a7f74750d400979e8cd47ed29feeaa1bd4db8/ruff-0.14.11-py3-none-manylinux_2_31_riscv64.whl", hash = "sha256:0f3727189a52179393ecf92ec7057c2210203e6af2676f08d92140d3e1ee72c1", size = 13955832, upload-time = "2026-01-08T19:11:55.064Z" }, + { url = "https://files.pythonhosted.org/packages/db/a0/153315310f250f76900a98278cf878c64dfb6d044e184491dd3289796734/ruff-0.14.11-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:eb09f849bd37147a789b85995ff734a6c4a095bed5fd1608c4f56afc3634cde2", size = 12586522, upload-time = "2026-01-08T19:11:35.356Z" }, + { url = "https://files.pythonhosted.org/packages/2f/2b/a73a2b6e6d2df1d74bf2b78098be1572191e54bec0e59e29382d13c3adc5/ruff-0.14.11-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:c61782543c1231bf71041461c1f28c64b961d457d0f238ac388e2ab173d7ecb7", size = 12724637, upload-time = "2026-01-08T19:11:47.796Z" }, + { url = "https://files.pythonhosted.org/packages/f0/41/09100590320394401cd3c48fc718a8ba71c7ddb1ffd07e0ad6576b3a3df2/ruff-0.14.11-py3-none-musllinux_1_2_i686.whl", hash = "sha256:82ff352ea68fb6766140381748e1f67f83c39860b6446966cff48a315c3e2491", size = 13145837, upload-time = "2026-01-08T19:11:32.87Z" }, + { url = "https://files.pythonhosted.org/packages/3b/d8/e035db859d1d3edf909381eb8ff3e89a672d6572e9454093538fe6f164b0/ruff-0.14.11-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:728e56879df4ca5b62a9dde2dd0eb0edda2a55160c0ea28c4025f18c03f86984", size = 13850469, upload-time = "2026-01-08T19:12:11.694Z" }, +] + +[[package]] +name = "shellingham" +version = "1.5.4" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/58/15/8b3609fd3830ef7b27b655beb4b4e9c62313a4e8da8c676e142cc210d58e/shellingham-1.5.4.tar.gz", hash = "sha256:8dbca0739d487e5bd35ab3ca4b36e11c4078f3a234bfce294b0a0291363404de", size = 10310, upload-time = "2023-10-24T04:13:40.426Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/e0/f9/0595336914c5619e5f28a1fb793285925a8cd4b432c9da0a987836c7f822/shellingham-1.5.4-py2.py3-none-any.whl", hash = "sha256:7ecfff8f2fd72616f7481040475a65b2bf8af90a56c89140852d1120324e8686", size = 9755, upload-time = "2023-10-24T04:13:38.866Z" }, +] + [[package]] name = "six" version = "1.17.0" @@ -811,11 +994,20 @@ wheels = [ [[package]] name = "soupsieve" -version = "2.8" +version = "2.8.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/89/23/adf3796d740536d63a6fbda113d07e60c734b6ed5d3058d1e47fc0495e47/soupsieve-2.8.1.tar.gz", hash = "sha256:4cf733bc50fa805f5df4b8ef4740fc0e0fa6218cf3006269afd3f9d6d80fd350", size = 117856, upload-time = "2025-12-18T13:50:34.655Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/48/f3/b67d6ea49ca9154453b6d70b34ea22f3996b9fa55da105a79d8732227adc/soupsieve-2.8.1-py3-none-any.whl", hash = "sha256:a11fe2a6f3d76ab3cf2de04eb339c1be5b506a8a47f2ceb6d139803177f85434", size = 36710, upload-time = "2025-12-18T13:50:33.267Z" }, +] + +[[package]] +name = "stevedore" +version = "5.6.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/6d/e6/21ccce3262dd4889aa3332e5a119a3491a95e8f60939870a3a035aabac0d/soupsieve-2.8.tar.gz", hash = "sha256:e2dd4a40a628cb5f28f6d4b0db8800b8f581b65bb380b97de22ba5ca8d72572f", size = 103472, upload-time = "2025-08-27T15:39:51.78Z" } +sdist = { url = "https://files.pythonhosted.org/packages/96/5b/496f8abebd10c3301129abba7ddafd46c71d799a70c44ab080323987c4c9/stevedore-5.6.0.tar.gz", hash = "sha256:f22d15c6ead40c5bbfa9ca54aa7e7b4a07d59b36ae03ed12ced1a54cf0b51945", size = 516074, upload-time = "2025-11-20T10:06:07.264Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/14/a0/bb38d3b76b8cae341dad93a2dd83ab7462e6dbcdd84d43f54ee60a8dc167/soupsieve-2.8-py3-none-any.whl", hash = "sha256:0cc76456a30e20f5d7f2e14a98a4ae2ee4e5abdc7c5ea0aafe795f344bc7984c", size = 36679, upload-time = "2025-08-27T15:39:50.179Z" }, + { url = "https://files.pythonhosted.org/packages/f4/40/8561ce06dc46fd17242c7724ab25b257a2ac1b35f4ebf551b40ce6105cfa/stevedore-5.6.0-py3-none-any.whl", hash = "sha256:4a36dccefd7aeea0c70135526cecb7766c4c84c473b1af68db23d541b6dc1820", size = 54428, upload-time = "2025-11-20T10:06:05.946Z" }, ] [[package]] @@ -827,6 +1019,50 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/a6/a5/c0b6468d3824fe3fde30dbb5e1f687b291608f9473681bbf7dabbf5a87d7/text_unidecode-1.3-py2.py3-none-any.whl", hash = "sha256:1311f10e8b895935241623731c2ba64f4c455287888b18189350b67134a822e8", size = 78154, upload-time = "2019-08-30T21:37:03.543Z" }, ] +[[package]] +name = "tomli" +version = "2.3.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/52/ed/3f73f72945444548f33eba9a87fc7a6e969915e7b1acc8260b30e1f76a2f/tomli-2.3.0.tar.gz", hash = "sha256:64be704a875d2a59753d80ee8a533c3fe183e3f06807ff7dc2232938ccb01549", size = 17392, upload-time = "2025-10-08T22:01:47.119Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/47/5c/24935fb6a2ee63e86d80e4d3b58b222dafaf438c416752c8b58537c8b89a/tomli-2.3.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:d1381caf13ab9f300e30dd8feadb3de072aeb86f1d34a8569453ff32a7dea4bf", size = 234832, upload-time = "2025-10-08T22:01:02.543Z" }, + { url = "https://files.pythonhosted.org/packages/89/da/75dfd804fc11e6612846758a23f13271b76d577e299592b4371a4ca4cd09/tomli-2.3.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a0e285d2649b78c0d9027570d4da3425bdb49830a6156121360b3f8511ea3441", size = 242052, upload-time = "2025-10-08T22:01:03.836Z" }, + { url = "https://files.pythonhosted.org/packages/70/8c/f48ac899f7b3ca7eb13af73bacbc93aec37f9c954df3c08ad96991c8c373/tomli-2.3.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:0a154a9ae14bfcf5d8917a59b51ffd5a3ac1fd149b71b47a3a104ca4edcfa845", size = 239555, upload-time = "2025-10-08T22:01:04.834Z" }, + { url = "https://files.pythonhosted.org/packages/ba/28/72f8afd73f1d0e7829bfc093f4cb98ce0a40ffc0cc997009ee1ed94ba705/tomli-2.3.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:74bf8464ff93e413514fefd2be591c3b0b23231a77f901db1eb30d6f712fc42c", size = 245128, upload-time = "2025-10-08T22:01:05.84Z" }, + { url = "https://files.pythonhosted.org/packages/60/83/59bff4996c2cf9f9387a0f5a3394629c7efa5ef16142076a23a90f1955fa/tomli-2.3.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:792262b94d5d0a466afb5bc63c7daa9d75520110971ee269152083270998316f", size = 242121, upload-time = "2025-10-08T22:01:11.332Z" }, + { url = "https://files.pythonhosted.org/packages/45/e5/7c5119ff39de8693d6baab6c0b6dcb556d192c165596e9fc231ea1052041/tomli-2.3.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:4f195fe57ecceac95a66a75ac24d9d5fbc98ef0962e09b2eddec5d39375aae52", size = 250070, upload-time = "2025-10-08T22:01:12.498Z" }, + { url = "https://files.pythonhosted.org/packages/45/12/ad5126d3a278f27e6701abde51d342aa78d06e27ce2bb596a01f7709a5a2/tomli-2.3.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:e31d432427dcbf4d86958c184b9bfd1e96b5b71f8eb17e6d02531f434fd335b8", size = 245859, upload-time = "2025-10-08T22:01:13.551Z" }, + { url = "https://files.pythonhosted.org/packages/fb/a1/4d6865da6a71c603cfe6ad0e6556c73c76548557a8d658f9e3b142df245f/tomli-2.3.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:7b0882799624980785240ab732537fcfc372601015c00f7fc367c55308c186f6", size = 250296, upload-time = "2025-10-08T22:01:14.614Z" }, + { url = "https://files.pythonhosted.org/packages/42/17/5e2c956f0144b812e7e107f94f1cc54af734eb17b5191c0bbfb72de5e93e/tomli-2.3.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c4665508bcbac83a31ff8ab08f424b665200c0e1e645d2bd9ab3d3e557b6185b", size = 240771, upload-time = "2025-10-08T22:01:20.106Z" }, + { url = "https://files.pythonhosted.org/packages/d5/f4/0fbd014909748706c01d16824eadb0307115f9562a15cbb012cd9b3512c5/tomli-2.3.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:4021923f97266babc6ccab9f5068642a0095faa0a51a246a6a02fccbb3514eaf", size = 248586, upload-time = "2025-10-08T22:01:21.164Z" }, + { url = "https://files.pythonhosted.org/packages/30/77/fed85e114bde5e81ecf9bc5da0cc69f2914b38f4708c80ae67d0c10180c5/tomli-2.3.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:a4ea38c40145a357d513bffad0ed869f13c1773716cf71ccaa83b0fa0cc4e42f", size = 244792, upload-time = "2025-10-08T22:01:22.417Z" }, + { url = "https://files.pythonhosted.org/packages/55/92/afed3d497f7c186dc71e6ee6d4fcb0acfa5f7d0a1a2878f8beae379ae0cc/tomli-2.3.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:ad805ea85eda330dbad64c7ea7a4556259665bdf9d2672f5dccc740eb9d3ca05", size = 248909, upload-time = "2025-10-08T22:01:23.859Z" }, + { url = "https://files.pythonhosted.org/packages/26/b6/d1eccb62f665e44359226811064596dd6a366ea1f985839c566cd61525ae/tomli-2.3.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c22a8bf253bacc0cf11f35ad9808b6cb75ada2631c2d97c971122583b129afbc", size = 241925, upload-time = "2025-10-08T22:01:29.066Z" }, + { url = "https://files.pythonhosted.org/packages/70/91/7cdab9a03e6d3d2bb11beae108da5bdc1c34bdeb06e21163482544ddcc90/tomli-2.3.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0eea8cc5c5e9f89c9b90c4896a8deefc74f518db5927d0e0e8d4a80953d774d0", size = 249045, upload-time = "2025-10-08T22:01:31.98Z" }, + { url = "https://files.pythonhosted.org/packages/15/1b/8c26874ed1f6e4f1fcfeb868db8a794cbe9f227299402db58cfcc858766c/tomli-2.3.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:b74a0e59ec5d15127acdabd75ea17726ac4c5178ae51b85bfe39c4f8a278e879", size = 245835, upload-time = "2025-10-08T22:01:32.989Z" }, + { url = "https://files.pythonhosted.org/packages/fd/42/8e3c6a9a4b1a1360c1a2a39f0b972cef2cc9ebd56025168c4137192a9321/tomli-2.3.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:b5870b50c9db823c595983571d1296a6ff3e1b88f734a4c8f6fc6188397de005", size = 253109, upload-time = "2025-10-08T22:01:34.052Z" }, + { url = "https://files.pythonhosted.org/packages/26/5a/4b546a0405b9cc0659b399f12b6adb750757baf04250b148d3c5059fc4eb/tomli-2.3.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:a56212bdcce682e56b0aaf79e869ba5d15a6163f88d5451cbde388d48b13f530", size = 268193, upload-time = "2025-10-08T22:01:39.712Z" }, + { url = "https://files.pythonhosted.org/packages/42/4f/2c12a72ae22cf7b59a7fe75b3465b7aba40ea9145d026ba41cb382075b0e/tomli-2.3.0-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c5f3ffd1e098dfc032d4d3af5c0ac64f6d286d98bc148698356847b80fa4de1b", size = 275488, upload-time = "2025-10-08T22:01:40.773Z" }, + { url = "https://files.pythonhosted.org/packages/92/04/a038d65dbe160c3aa5a624e93ad98111090f6804027d474ba9c37c8ae186/tomli-2.3.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:5e01decd096b1530d97d5d85cb4dff4af2d8347bd35686654a004f8dea20fc67", size = 272669, upload-time = "2025-10-08T22:01:41.824Z" }, + { url = "https://files.pythonhosted.org/packages/be/2f/8b7c60a9d1612a7cbc39ffcca4f21a73bf368a80fc25bccf8253e2563267/tomli-2.3.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:8a35dd0e643bb2610f156cca8db95d213a90015c11fee76c946aa62b7ae7e02f", size = 279709, upload-time = "2025-10-08T22:01:43.177Z" }, + { url = "https://files.pythonhosted.org/packages/77/b8/0135fadc89e73be292b473cb820b4f5a08197779206b33191e801feeae40/tomli-2.3.0-py3-none-any.whl", hash = "sha256:e95b1af3c5b07d9e643909b5abbec77cd9f1217e6d0bca72b0234736b9fb1f1b", size = 14408, upload-time = "2025-10-08T22:01:46.04Z" }, +] + +[[package]] +name = "typer" +version = "0.21.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "click", marker = "sys_platform == 'linux'" }, + { name = "rich", marker = "sys_platform == 'linux'" }, + { name = "shellingham", marker = "sys_platform == 'linux'" }, + { name = "typing-extensions", marker = "sys_platform == 'linux'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/36/bf/8825b5929afd84d0dabd606c67cd57b8388cb3ec385f7ef19c5cc2202069/typer-0.21.1.tar.gz", hash = "sha256:ea835607cd752343b6b2b7ce676893e5a0324082268b48f27aa058bdb7d2145d", size = 110371, upload-time = "2026-01-06T11:21:10.989Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/a0/1d/d9257dd49ff2ca23ea5f132edf1281a0c4f9de8a762b9ae399b670a59235/typer-0.21.1-py3-none-any.whl", hash = "sha256:7985e89081c636b88d172c2ee0cfe33c253160994d47bdfdc302defd7d1f1d01", size = 47381, upload-time = "2026-01-06T11:21:09.824Z" }, +] + [[package]] name = "typing-extensions" version = "4.15.0" @@ -850,20 +1086,20 @@ wheels = [ [[package]] name = "tzdata" -version = "2025.2" +version = "2025.3" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/95/32/1a225d6164441be760d75c2c42e2780dc0873fe382da3e98a2e1e48361e5/tzdata-2025.2.tar.gz", hash = "sha256:b60a638fcc0daffadf82fe0f57e53d06bdec2f36c4df66280ae79bce6bd6f2b9", size = 196380, upload-time = "2025-03-23T13:54:43.652Z" } +sdist = { url = "https://files.pythonhosted.org/packages/5e/a7/c202b344c5ca7daf398f3b8a477eeb205cf3b6f32e7ec3a6bac0629ca975/tzdata-2025.3.tar.gz", hash = "sha256:de39c2ca5dc7b0344f2eba86f49d614019d29f060fc4ebc8a417896a620b56a7", size = 196772, upload-time = "2025-12-13T17:45:35.667Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/5c/23/c7abc0ca0a1526a0774eca151daeb8de62ec457e77262b66b359c3c7679e/tzdata-2025.2-py2.py3-none-any.whl", hash = "sha256:1a403fada01ff9221ca8044d701868fa132215d84beb92242d9acd2147f667a8", size = 347839, upload-time = "2025-03-23T13:54:41.845Z" }, + { url = "https://files.pythonhosted.org/packages/c7/b0/003792df09decd6849a5e39c28b513c06e84436a54440380862b5aeff25d/tzdata-2025.3-py2.py3-none-any.whl", hash = "sha256:06a47e5700f3081aab02b2e513160914ff0694bce9947d6b76ebd6bf57cfc5d1", size = 348521, upload-time = "2025-12-13T17:45:33.889Z" }, ] [[package]] name = "urllib3" -version = "2.6.0" +version = "2.6.3" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/1c/43/554c2569b62f49350597348fc3ac70f786e3c32e7f19d266e19817812dd3/urllib3-2.6.0.tar.gz", hash = "sha256:cb9bcef5a4b345d5da5d145dc3e30834f58e8018828cbc724d30b4cb7d4d49f1", size = 432585, upload-time = "2025-12-05T15:08:47.885Z" } +sdist = { url = "https://files.pythonhosted.org/packages/c7/24/5f1b3bdffd70275f6661c76461e25f024d5a38a46f04aaca912426a2b1d3/urllib3-2.6.3.tar.gz", hash = "sha256:1b62b6884944a57dbe321509ab94fd4d3b307075e0c2eae991ac71ee15ad38ed", size = 435556, upload-time = "2026-01-07T16:24:43.925Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/56/1a/9ffe814d317c5224166b23e7c47f606d6e473712a2fad0f704ea9b99f246/urllib3-2.6.0-py3-none-any.whl", hash = "sha256:c90f7a39f716c572c4e3e58509581ebd83f9b59cced005b7db7ad2d22b0db99f", size = 131083, upload-time = "2025-12-05T15:08:45.983Z" }, + { url = "https://files.pythonhosted.org/packages/39/08/aaaad47bc4e9dc8c725e68f9d04865dbcb2052843ff09c97b08904852d84/urllib3-2.6.3-py3-none-any.whl", hash = "sha256:bf272323e553dfb2e87d9bfd225ca7b0f467b919d7bbd355436d3fd37cb0acd4", size = 131584, upload-time = "2026-01-07T16:24:42.685Z" }, ] [[package]] diff --git a/{{ cookiecutter.project_name }}/.github/workflows/workflow.yaml b/{{ cookiecutter.project_name }}/.github/workflows/workflow.yml similarity index 100% rename from {{ cookiecutter.project_name }}/.github/workflows/workflow.yaml rename to {{ cookiecutter.project_name }}/.github/workflows/workflow.yml diff --git a/{{ cookiecutter.project_name }}/.pre-commit-config.yaml b/{{ cookiecutter.project_name }}/.pre-commit-config.yaml new file mode 100644 index 0000000..bcb0570 --- /dev/null +++ b/{{ cookiecutter.project_name }}/.pre-commit-config.yaml @@ -0,0 +1,10 @@ +repos: + - repo: local + hooks: + - id: local-check + name: Makefile Validation + entry: make pipeline + language: system + pass_filenames: false + always_run: true + verbose: true diff --git a/{{ cookiecutter.project_name }}/Makefile b/{{ cookiecutter.project_name }}/Makefile index 61ab8a7..9cf36e4 100644 --- a/{{ cookiecutter.project_name }}/Makefile +++ b/{{ cookiecutter.project_name }}/Makefile @@ -47,7 +47,7 @@ check-dead-code: @echo "✅ Dead code check complete." tests: - @echo "Runing test per each backend..." + @echo "Running tests..." @uv run pytest $(SRC_PROJECT_TESTS)/ @echo "✅ Tests complete." diff --git a/{{ cookiecutter.project_name }}/pyproject.toml b/{{ cookiecutter.project_name }}/pyproject.toml index ac0f668..9a5eeb2 100644 --- a/{{ cookiecutter.project_name }}/pyproject.toml +++ b/{{ cookiecutter.project_name }}/pyproject.toml @@ -33,6 +33,10 @@ required-environments = [ "sys_platform == 'linux' and platform_machine == 'x86_64'" ] +[tool.uv.build-backend] +module-name = "{{ cookiecutter.project_module_name }}" +module-root = "" + [dependency-groups] pipeline = [ "bandit==1.9.2", @@ -58,10 +62,6 @@ documentation = [ "mike==2.1.3" ] -[tool.setuptools.packages.find] -include = ["{{ cookiecutter.project_module_name }}*"] -exclude = ["{{ cookiecutter.project_test_folder_name }}*", "docs*", "*.egg-info*"] - [tool.ruff] line-length = 88 indent-width = 4