diff --git a/.gitignore b/.gitignore index cdb335b..04fe619 100644 --- a/.gitignore +++ b/.gitignore @@ -10,8 +10,9 @@ __pycache__/ memory-bank/ **/memory-bank/** .clinerules* -.specstory/ -.history/ +.specstory +.history + # Distribution / packaging .Python diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index ab6dc38..e8e4833 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -51,6 +51,13 @@ repos: language: system pass_filenames: false types: [python] + - id: mdformat + name: mdformat + description: "Format markdown files" + entry: poe mdformat + language: system + pass_filenames: false + types: [markdown] - repo: https://github.com/codespell-project/codespell rev: v2.4.1 hooks: @@ -122,8 +129,3 @@ repos: hooks: - id: commitizen stages: [commit-msg] - - - repo: https://github.com/executablebooks/mdformat - rev: 0.7.22 - hooks: - - id: mdformat diff --git a/README.md b/README.md index 385dcb8..09a8fe7 100644 --- a/README.md +++ b/README.md @@ -24,22 +24,22 @@ Welcome to the Python Starting Project documentation! This project provides a co ## TL;DR: Quick Setup 1. Install uv: [https://docs.astral.sh/uv/getting-started/installation/](https://docs.astral.sh/uv/getting-started/installation/) -1. Clone the repository: - ```bash - git clone https://github.com/yourusername/python-starting-project.git - cd python-starting-project - ``` -1. Set up the environment: - ```bash - uv sync - uv venv - uv run pre-commit install - ``` -1. Run pre-commit checks: - ```bash - poe pre - ``` - This command checks for errors that the linter might have missed and will be run by Cursor automatically when it finishes processing your code. +2. Clone the repository: + ``` + git clone https://github.com/yourusername/python-starting-project.git + cd python-starting-project + ``` +3. Set up the environment: + ``` + uv sync + uv venv + uv run pre-commit install + ``` +4. Run pre-commit checks: + ``` + poe pre + ``` + This command checks for errors that the linter might have missed and will be run by Cursor automatically when it finishes processing your code. You're all set! Start developing with confidence. @@ -95,8 +95,8 @@ python-starting-project/ This project is designed to have a minimal learning curve. You only need to know a few commands for the entire development cycle: 1. **Install dependencies**: `uv sync` -1. **Set up pre-commit hooks**: `uv run pre-commit install` (once after cloning) -1. **Run pre-commit checks**: `poe pre` +2. **Set up pre-commit hooks**: `uv run pre-commit install` (once after cloning) +3. **Run pre-commit checks**: `poe pre` ## Documentation @@ -198,32 +198,32 @@ To enable the dynamic badges: 1. Create a GitHub Gist to store the badge data: - - Go to https://gist.github.com/ and create a new gist - - Create a file named `badges.json` (content doesn't matter, it will be overwritten) - - Make sure the Gist is **public** so the badge images can be accessed without authentication - - Note the Gist ID from the URL (the alphanumeric string after your username) + - Go to https://gist.github.com/ and create a new gist + - Create a file named `badges.json` (content doesn't matter, it will be overwritten) + - Make sure the Gist is **public** so the badge images can be accessed without authentication + - Note the Gist ID from the URL (the alphanumeric string after your username) -1. Create a Personal Access Token (PAT) with `gist` scope: +2. Create a Personal Access Token (PAT) with `gist` scope: - - Go to GitHub Settings → Developer settings → Personal access tokens → Tokens (classic) - - Generate a new token with the `gist` scope - - Copy the generated token + - Go to GitHub Settings → Developer settings → Personal access tokens → Tokens (classic) + - Generate a new token with the `gist` scope + - Copy the generated token -1. Add the following secrets to your repository: +3. Add the following secrets to your repository: - - Go to your repository → Settings → Secrets and variables → Actions - - Add `BADGES_GIST_ID` with your Gist ID value - - Add `BADGES_TOKEN` with your Personal Access Token + - Go to your repository → Settings → Secrets and variables → Actions + - Add `BADGES_GIST_ID` with your Gist ID value + - Add `BADGES_TOKEN` with your Personal Access Token -1. Enable badges in your repository: +4. Enable badges in your repository: - - Go to your repository → Settings → Secrets and variables → Actions - - Under "Variables", add `ENABLE_BADGES` with value `true` + - Go to your repository → Settings → Secrets and variables → Actions + - Under "Variables", add `ENABLE_BADGES` with value `true` -1. Update the badge URLs in your README.md: +5. Update the badge URLs in your README.md: - - Replace the URL in the badge markdown with your Gist URL - - Example: `![Badge](https://img.shields.io/dynamic/json?url=https://gist.githubusercontent.com/YOUR_USERNAME/YOUR_GIST_ID/raw/badges.json&query=$.badges[?(@.label%3D%3D%27pre-commit%27)].message&label=pre-commit&color=green)` + - Replace the URL in the badge markdown with your Gist URL + - Example: `![Badge](https://img.shields.io/dynamic/json?url=https://gist.githubusercontent.com/YOUR_USERNAME/YOUR_GIST_ID/raw/badges.json&query=$.badges[?(@.label%3D%3D%27pre-commit%27)].message&label=pre-commit&color=green)` The badges workflow is disabled by default to avoid unnecessary GitHub Actions usage. It will only run when the `ENABLE_BADGES` repository variable is set to `true`. @@ -232,7 +232,6 @@ The badges workflow is disabled by default to avoid unnecessary GitHub Actions u For Dependabot to work with the badges workflow, additional configuration has been added: 1. The `.github/dependabot.yml` file includes permissions for Dependabot to access the badge secrets. -1. A special workflow file `.github/workflows/dependabot-badges.yml` handles Dependabot PRs. ### Other Tools diff --git a/docs/architecture/configuration.md b/docs/architecture/configuration.md index 47cfcc7..9262f34 100644 --- a/docs/architecture/configuration.md +++ b/docs/architecture/configuration.md @@ -83,25 +83,24 @@ print(f"Debug mode: {settings.DEBUG}") ## Available Settings -| Setting | Type | Default | Description | -| ------- | ---- | ------- | ----------- | -| `APP_NAME` | `str` | "Python Starting Project" | The name of the application | -| `APP_VERSION` | `str` | "0.1.0" | The version of the application | -| `DEBUG` | `bool` | `False` | Enable or disable debug mode | -| `LOG_LEVEL` | `str` | "INFO" | The logging level | -| `LOG_FORMAT` | `str` | "%(asctime)s - %(name)s - %(levelname)s - %(message)s" | The log message format | -| `LOG_FILE` | `str` | "logs/app.log" | Path to the log file | -| `BASE_DIR` | `Path` | `Path(__file__)` | Base directory of the application | -| `LOG_DIR` | `Path` | `Path("logs")` | Directory for log files | -| `env_file_found` | `bool` | `False` | Indicates whether a .env file was found during initialization | +| Setting | Type | Default | Description | +| ---------------- | ------ | ------------------------------------------------------ | ------------------------------------------------------------- | +| `APP_NAME` | `str` | "Python Starting Project" | The name of the application | +| `APP_VERSION` | `str` | "0.1.0" | The version of the application | +| `DEBUG` | `bool` | `False` | Enable or disable debug mode | +| `LOG_LEVEL` | `str` | "INFO" | The logging level | +| `LOG_FORMAT` | `str` | "%(asctime)s - %(name)s - %(levelname)s - %(message)s" | The log message format | +| `LOG_FILE` | `str` | "logs/app.log" | Path to the log file | +| `BASE_DIR` | `Path` | `Path(__file__)` | Base directory of the application | +| `LOG_DIR` | `Path` | `Path("logs")` | Directory for log files | +| `env_file_found` | `bool` | `False` | Indicates whether a .env file was found during initialization | ## Adding New Settings To add new settings to your application: -1. Add the setting with its type annotation and default value to the `Settings` class in `src/utils/settings.py`: - ```python +# Add the setting with its type annotation and default value to the `Settings` class in `src/utils/settings.py`: class Settings(BaseSettings): # Existing settings... @@ -112,16 +111,14 @@ class Settings(BaseSettings): ) ``` -2. Add the setting to `.env.example` with a comment explaining its purpose: - ``` +# Add the setting to `.env.example` with a comment explaining its purpose: # New setting description NEW_SETTING=default value ``` -3. Use the setting in your code: - ```python +# Use the setting in your code: from utils.settings import settings print(f"New setting: {settings.NEW_SETTING}") diff --git a/docs/architecture/ide-setup.md b/docs/architecture/ide-setup.md index 3796248..aef0aa5 100644 --- a/docs/architecture/ide-setup.md +++ b/docs/architecture/ide-setup.md @@ -112,9 +112,9 @@ This configuration allows you to: ### Getting Started with VSCode 1. Install [Visual Studio Code](https://code.visualstudio.com/) -1. Open the project folder in VSCode -1. When prompted, install the recommended extensions -1. VSCode will automatically use the project's settings +2. Open the project folder in VSCode +3. When prompted, install the recommended extensions +4. VSCode will automatically use the project's settings ### Key VSCode Features @@ -137,28 +137,28 @@ The Source Control view can be accessed by: 1. **Changes View**: - - Shows all modified, added, and deleted files - - Provides a clear overview of what has changed in your project - - Allows you to stage individual files or all changes at once + - Shows all modified, added, and deleted files + - Provides a clear overview of what has changed in your project + - Allows you to stage individual files or all changes at once -1. **Diff Viewer**: +2. **Diff Viewer**: - - Click on any modified file to see a side-by-side comparison - - Clearly highlights what has been added, changed, or removed - - Makes reviewing AI-generated code changes much easier - - Allows you to accept or reject changes at a granular level + - Click on any modified file to see a side-by-side comparison + - Clearly highlights what has been added, changed, or removed + - Makes reviewing AI-generated code changes much easier + - Allows you to accept or reject changes at a granular level -1. **Commit Management**: +3. **Commit Management**: - - Write commit messages and commit changes directly from the editor - - View commit history and browse previous versions - - Create and switch between branches + - Write commit messages and commit changes directly from the editor + - View commit history and browse previous versions + - Create and switch between branches -1. **Integration with GitHub**: +4. **Integration with GitHub**: - - Push and pull changes to/from remote repositories - - Create and review pull requests - - Manage issues + - Push and pull changes to/from remote repositories + - Create and review pull requests + - Manage issues #### Best Practices for Source Control @@ -172,9 +172,9 @@ The Source Control view can be accessed by: When working with AI-generated code: 1. After the AI makes changes, open the Source Control panel to see all modified files -1. Click on each file to review the changes in the diff viewer -1. Verify that the changes match your expectations and make any necessary adjustments -1. Stage and commit the changes with a descriptive message +2. Click on each file to review the changes in the diff viewer +3. Verify that the changes match your expectations and make any necessary adjustments +4. Stage and commit the changes with a descriptive message This workflow ensures you maintain full control over your codebase while benefiting from AI assistance. @@ -268,10 +268,10 @@ class Settings(BaseSettings): # (1)! ``` 1. Uses Pydantic's BaseSettings for environment variable loading and validation -1. Default application name that can be overridden via environment variables -1. Default log level is INFO, can be changed to DEBUG for more verbose logging -1. Uses a factory function to create the logs directory path -1. Configuration for loading settings from .env file with UTF-8 encoding +2. Default application name that can be overridden via environment variables +3. Default log level is INFO, can be changed to DEBUG for more verbose logging +4. Uses a factory function to create the logs directory path +5. Configuration for loading settings from .env file with UTF-8 encoding #### 3. Advanced Code Block Features @@ -329,12 +329,12 @@ This renders the complete documentation for the settings and logging modules, in The project includes several custom tasks that can be run from either editor: 1. Open the Command Palette (`Ctrl+Shift+P` or `Cmd+Shift+P`) -1. Type "Tasks: Run Task" -1. Select one of the available tasks: - - Run Tests - - Build Documentation - - Lint Code - - Format Code +2. Type "Tasks: Run Task" +3. Select one of the available tasks: + - Run Tests + - Build Documentation + - Lint Code + - Format Code ## Keyboard Shortcuts @@ -354,21 +354,21 @@ Here are some useful keyboard shortcuts for working with Python in both editors: 1. **Use AI Suggestions Wisely** - - Review AI-generated code for correctness - - Understand suggested changes before applying - - Use AI as a tool, not a replacement for understanding + - Review AI-generated code for correctness + - Understand suggested changes before applying + - Use AI as a tool, not a replacement for understanding -1. **Documentation** +2. **Documentation** - - Let AI help generate initial documentation - - Review and enhance AI-generated content - - Keep documentation up-to-date with code changes + - Let AI help generate initial documentation + - Review and enhance AI-generated content + - Keep documentation up-to-date with code changes -1. **Code Quality** +3. **Code Quality** - - Use AI to maintain consistent code style - - Leverage AI for complex refactoring - - Run automated tests after AI-suggested changes + - Use AI to maintain consistent code style + - Leverage AI for complex refactoring + - Run automated tests after AI-suggested changes ## Additional Resources @@ -396,37 +396,37 @@ The project includes MCP configuration in the `.cursor/mcp.json` file: ```json { - "mcpServers": { - "sequential-thinking": { - "command": "npx", - "args": [ - "-y", - "@modelcontextprotocol/server-sequential-thinking" - ] - }, - "fetch": { - "command": "uvx", - "args": [ - "mcp-server-fetch" - ] - } + "mcpServers": { + "sequential-thinking": { + "command": "npx", + "args": [ + "-y", + "@modelcontextprotocol/server-sequential-thinking" + ] + }, + "fetch": { + "command": "uvx", + "args": [ + "mcp-server-fetch" + ] } + } } ``` This configuration enables two MCP servers: 1. **sequential-thinking**: Helps break down complex problems into manageable steps -1. **fetch**: Allows the AI to retrieve information from the internet +2. **fetch**: Allows the AI to retrieve information from the internet ### Using MCPs When working with AI tools that support MCP: 1. The AI will automatically use the appropriate MCP when needed -1. For long-running operations or multi-step processes, you may see the AI thinking through steps -1. When the AI is using an MCP and needs your input to continue, simply respond with "continue" -1. For fetch operations, the AI may retrieve information from the internet to provide more accurate responses +2. For long-running operations or multi-step processes, you may see the AI thinking through steps +3. When the AI is using an MCP and needs your input to continue, simply respond with "continue" +4. For fetch operations, the AI may retrieve information from the internet to provide more accurate responses ### Global MCP Rules @@ -447,12 +447,12 @@ For example: To ensure MCPs are enabled: 1. Make sure the `.cursor/mcp.json` file exists in your project -1. Install the required dependencies: - ```bash - npm install -g @modelcontextprotocol/server-sequential-thinking - pip install mcp-server-fetch - ``` -1. When working with AI tools, verify they have access to the MCP configuration +2. Install the required dependencies: + ```bash + npm install -g @modelcontextprotocol/server-sequential-thinking + pip install mcp-server-fetch + ``` +3. When working with AI tools, verify they have access to the MCP configuration ## AI-Enhanced Development with Cursor @@ -461,12 +461,12 @@ For developers interested in AI-assisted development, [Cursor](https://cursor.sh ### Getting Started with Cursor 1. Install [Cursor](https://cursor.sh) -1. Open the project folder in Cursor: - ```bash - cursor . - ``` -1. Cursor will automatically use the same settings and extensions as VSCode -1. Let Cursor's AI agent analyze your codebase +2. Open the project folder in Cursor: + ```bash + cursor . + ``` +3. Cursor will automatically use the same settings and extensions as VSCode +4. Let Cursor's AI agent analyze your codebase ### AI-Assisted Development Features @@ -495,8 +495,8 @@ Cursor provides several AI-powered features that significantly improve the devel Cursor has built-in support for Model Context Protocol (MCP), making it particularly powerful for complex development tasks. When using Cursor: 1. The AI automatically leverages MCPs when appropriate -1. You can see the AI's thought process through sequential thinking -1. For long-running operations, simply type "continue" when prompted -1. The fetch MCP allows the AI to retrieve up-to-date information from the internet +2. You can see the AI's thought process through sequential thinking +3. For long-running operations, simply type "continue" when prompted +4. The fetch MCP allows the AI to retrieve up-to-date information from the internet This integration makes Cursor especially valuable for tackling complex development challenges and staying current with the latest programming practices. diff --git a/docs/architecture/lazy-loading.md b/docs/architecture/lazy-loading.md index 739924b..f0b7965 100644 --- a/docs/architecture/lazy-loading.md +++ b/docs/architecture/lazy-loading.md @@ -29,19 +29,17 @@ uv run mkinit src --relative --lazy_loader_typed --recursive -w Here's an example of how lazy loading works: -1. Original import (without lazy loading): - ```python # In __init__.py +# Original import without lazy loading from .module1 import function1 from .module2 import function2 # When this module is imported, both module1 and module2 are loaded immediately. ``` -2. With lazy loading: - ```python +# with lazy loading # In __init__.py (generated by mkinit) import lazy_loader @@ -72,7 +70,7 @@ To ensure type checking works correctly with lazy loading, `mkinit` generates `. The lazy loading system generates two types of files: 1. `__init__.py`: Contains the lazy loading implementation -1. `__init__.pyi`: Contains type hints for static type checkers +2. `__init__.pyi`: Contains type hints for static type checkers These files are automatically generated and maintained by the pre-commit hooks. While you shouldn't need to edit them manually, Cursor's AI capabilities help by: diff --git a/docs/architecture/logging.md b/docs/architecture/logging.md index 5783ae8..891100a 100644 --- a/docs/architecture/logging.md +++ b/docs/architecture/logging.md @@ -35,17 +35,17 @@ logger.critical("Critical message") The logging system can be configured through the following settings: -| Setting | Type | Default | Description | -|---------|------|---------|-------------| -| `LOG_LEVEL` | `str` | "INFO" | The logging level | +| Setting | Type | Default | Description | +| ------------ | ----- | ------------------------------------------------------ | ---------------------- | +| `LOG_LEVEL` | `str` | "INFO" | The logging level | | `LOG_FORMAT` | `str` | "%(asctime)s - %(name)s - %(levelname)s - %(message)s" | The log message format | -| `LOG_FILE` | `str` | "logs/app.log" | Path to the log file | +| `LOG_FILE` | `str` | "logs/app.log" | Path to the log file | ## Customizing Logging To customize logging for your application: -1. Modify the log format, level, or handlers in `src/utils/logging.py`: +# Modify the log format, level, or handlers in `src/utils/logging.py`: ```python def setup_logging() -> None: @@ -57,7 +57,7 @@ def setup_logging() -> None: # ... ``` -2. Add custom log filters or formatters as needed: +# Add custom log filters or formatters as needed: ```python class CustomFilter(logging.Filter): @@ -69,7 +69,7 @@ class CustomFilter(logging.Filter): return True ``` -3. Configure component-specific loggers using the `get_logger` function: +# Configure component-specific loggers using the `get_logger` function: ```python # Get a logger for a specific component diff --git a/docs/development/pre-commit-hooks.md b/docs/development/pre-commit-hooks.md index 253bff6..c65875f 100644 --- a/docs/development/pre-commit-hooks.md +++ b/docs/development/pre-commit-hooks.md @@ -163,9 +163,9 @@ poe pre-commit This project uses GitHub Actions to run pre-commit hooks in CI/CD pipelines. The workflow is defined in `.github/workflows/pre-commit.yml` and: 1. Runs on every pull request and push to the main branch -1. Uses uv for dependency management following Astral's best practices -1. Installs all project dependencies -1. Runs all pre-commit hooks on all files +2. Uses uv for dependency management following Astral's best practices +3. Installs all project dependencies +4. Runs all pre-commit hooks on all files This ensures that all code meets quality standards before being merged. The workflow configuration: @@ -189,12 +189,12 @@ jobs: uses: astral-sh/setup-uv@v5 with: enable-cache: true - cache-dependency-glob: "pyproject.toml" + cache-dependency-glob: pyproject.toml - name: Set up Python uses: actions/setup-python@v5 with: - python-version-file: "pyproject.toml" + python-version-file: pyproject.toml - name: Install dependencies run: uv sync --all-extras --dev @@ -218,7 +218,7 @@ However, this is discouraged and should only be used in exceptional circumstance To add a new pre-commit hook: 1. Add the hook configuration to `.pre-commit-config.yaml` -1. Add any necessary dependencies to `pyproject.toml` under `[dependency-groups.dev]` -1. Add any tool-specific configuration to `pyproject.toml` -1. Run `uv sync` to install the new dependencies -1. Run `pre-commit install` to update the hooks +2. Add any necessary dependencies to `pyproject.toml` under `[dependency-groups.dev]` +3. Add any tool-specific configuration to `pyproject.toml` +4. Run `uv sync` to install the new dependencies +5. Run `pre-commit install` to update the hooks diff --git a/docs/development/simplified-workflow.md b/docs/development/simplified-workflow.md index 0a793f7..42ab8d9 100644 --- a/docs/development/simplified-workflow.md +++ b/docs/development/simplified-workflow.md @@ -23,12 +23,12 @@ git push When you run `git commit`, the pre-commit hooks automatically: 1. **Format your code** using Ruff -1. **Lint your code** to check for errors and style issues -1. **Check types** using Pyright -1. **Detect security issues** using Bandit -1. **Find dead code** using Vulture -1. **Verify docstring coverage** using Interrogate -1. **Measure code complexity** using Radon and Xenon +2. **Lint your code** to check for errors and style issues +3. **Check types** using Pyright +4. **Detect security issues** using Bandit +5. **Find dead code** using Vulture +6. **Verify docstring coverage** using Interrogate +7. **Measure code complexity** using Radon and Xenon If any of these checks fail, the commit is aborted, and you'll see error messages explaining what needs to be fixed. @@ -47,9 +47,9 @@ If any of these checks fail, the commit is aborted, and you'll see error message If your commit fails due to pre-commit hooks: 1. Read the error messages to understand what failed -1. Fix the issues in your code -1. Run `git add .` to stage the fixes -1. Try committing again with `git commit -m "Your message"` +2. Fix the issues in your code +3. Run `git add .` to stage the fixes +4. Try committing again with `git commit -m "Your message"` ### Skipping Pre-commit Hooks (Not Recommended) diff --git a/docs/development/workflow.md b/docs/development/workflow.md index 35c1e97..f4cb64f 100644 --- a/docs/development/workflow.md +++ b/docs/development/workflow.md @@ -17,19 +17,19 @@ Our development workflow is designed to: Before you begin development, ensure you have: 1. Forked and cloned the repository -1. Set up your development environment as described in [Getting Started](../getting-started.md) -1. Installed pre-commit hooks with `uv run pre-commit install` -1. Familiarized yourself with the [project structure](../getting-started.md) +2. Set up your development environment as described in [Getting Started](../getting-started.md) +3. Installed pre-commit hooks with `uv run pre-commit install` +4. Familiarized yourself with the [project structure](../getting-started.md) ## Development Workflow When making changes: 1. Follow the project's code style guidelines -1. Write tests for new functionality -1. Update documentation as needed -1. Keep commits small and focused -1. Use meaningful commit messages +2. Write tests for new functionality +3. Update documentation as needed +4. Keep commits small and focused +5. Use meaningful commit messages ### 3. Run Tests Locally @@ -45,18 +45,18 @@ poe pre Our CI pipeline automatically: 1. Runs tests on all PRs -1. Checks code quality -1. Verifies documentation builds -1. Ensures all pre-commit hooks pass +2. Checks code quality +3. Verifies documentation builds +4. Ensures all pre-commit hooks pass ## Release Process Releases are managed by maintainers and follow these steps: 1. Version bump according to [Semantic Versioning](https://semver.org/) -1. Changelog update -1. Tag creation -1. Release build and deployment +2. Changelog update +3. Tag creation +4. Release build and deployment ## Best Practices @@ -97,9 +97,9 @@ Releases are managed by maintainers and follow these steps: If pre-commit hooks fail: 1. Read the error message carefully -1. Fix the issues locally -1. Stage the changes -1. Try committing again +2. Fix the issues locally +3. Stage the changes +4. Try committing again If you need to bypass hooks temporarily: @@ -125,12 +125,12 @@ git push --force-with-lease origin your-branch # (7) ``` 1. Switch to the main branch -1. Pull the latest changes -1. Switch back to your feature branch -1. Rebase your branch on main -1. Stage resolved conflicts -1. Continue the rebase process -1. Force push with lease for safety +2. Pull the latest changes +3. Switch back to your feature branch +4. Rebase your branch on main +5. Stage resolved conflicts +6. Continue the rebase process +7. Force push with lease for safety ## Resources diff --git a/docs/getting-started.md b/docs/getting-started.md index 70b7cf1..9ce8c43 100644 --- a/docs/getting-started.md +++ b/docs/getting-started.md @@ -28,12 +28,12 @@ A comprehensive Python project template with built-in logging, configuration man - **Lazy loading** for improved import performance - **Comprehensive testing** with pytest - **Code quality tools**: - - Ruff for linting and formatting - - Pyright for static type checking - - Bandit for security checks - - Vulture for dead code detection - - Interrogate for docstring coverage - - Darglint for docstring validation + - Ruff for linting and formatting + - Pyright for static type checking + - Bandit for security checks + - Vulture for dead code detection + - Interrogate for docstring coverage + - Darglint for docstring validation - **GitHub Actions** for CI/CD with pre-commit checks - **Comprehensive badge system** with dynamic quality indicators - **Documentation** with MkDocs for beautiful, searchable documentation @@ -48,42 +48,21 @@ A comprehensive Python project template with built-in logging, configuration man ### Important: Do not skip these steps! -1. Clone the repository: - ```bash +# Clone the repository git clone https://github.com/yourusername/python-starting-project.git cd python-starting-project -``` -2. Install dependencies with uv: - -```bash +# Install dependencies uv sync -``` - -3. Install pre-commit hooks: -```bash +# Install pre-commit hooks: uv run pre-commit install -``` -4. Run pre-commit hooks to verify everything works: - -```bash -# Run all pre-commit hooks to check your setup +# Run pre-commit hooks to verify everything works: uv run poe pre ``` -5. Open the project in your preferred IDE: - -```bash -# For VSCode -code . - -# For Cursor -cursor . -``` - ## Project Structure The project follows a modular architecture with clear separation of concerns: @@ -200,17 +179,17 @@ The project is configured to work with both VSCode and Cursor: For the best development experience with VSCode: 1. Open the project in VSCode -1. Install recommended extensions when prompted -1. Use the integrated terminal for running commands -1. Use the built-in debugger for debugging +2. Install recommended extensions when prompted +3. Use the integrated terminal for running commands +4. Use the built-in debugger for debugging ### Cursor Integration Cursor provides all VSCode features plus AI-assisted development: 1. Open the project in Cursor -1. Cursor will automatically use the project's settings and extensions -1. Use AI features to help with code completion, refactoring, and documentation +2. Cursor will automatically use the project's settings and extensions +3. Use AI features to help with code completion, refactoring, and documentation ## Next Steps diff --git a/docs/technologies/code-analysis/bandit.md b/docs/technologies/code-analysis/bandit.md index af7d47f..3c470c1 100644 --- a/docs/technologies/code-analysis/bandit.md +++ b/docs/technologies/code-analysis/bandit.md @@ -36,9 +36,9 @@ uv pip install bandit In this project, Bandit is used to: 1. Identify potential security vulnerabilities in the codebase -1. Enforce security best practices -1. Prevent common security mistakes -1. Run as part of the pre-commit hooks and CI/CD pipeline +2. Enforce security best practices +3. Prevent common security mistakes +4. Run as part of the pre-commit hooks and CI/CD pipeline ## Configuration in This Project @@ -47,7 +47,7 @@ Bandit is configured in the `pyproject.toml` file: ```toml [tool.bandit] exclude_dirs = ["tests", ".venv", ".git"] -skips = ["B101"] # Skip assert statements warning +skips = ["B101"] # Skip assert statements warning ``` This configuration: @@ -126,6 +126,7 @@ open("sensitive.txt", "w").write("secret") # More secure import os + with open("sensitive.txt", "w") as f: os.chmod("sensitive.txt", 0o600) # Owner read/write only f.write("secret") @@ -139,6 +140,7 @@ password = "hardcoded_password" # Better approach import os + password = os.environ.get("PASSWORD") ``` @@ -147,20 +149,22 @@ password = os.environ.get("PASSWORD") ```python # Insecure import pickle + data = pickle.loads(user_input) # Arbitrary code execution risk # Better approach import json + data = json.loads(user_input) ``` ## Best Practices 1. **Run Bandit regularly**: Include Bandit in your pre-commit hooks and CI/CD pipeline. -1. **Address high-severity issues immediately**: High-severity issues with high confidence should be fixed as soon as possible. -1. **Review false positives**: Some issues flagged by Bandit may be false positives. Review them carefully and add skips only when necessary. -1. **Use context-specific configurations**: Different parts of your codebase may need different security checks. -1. **Keep Bandit updated**: Security tools should be kept up to date to catch the latest known vulnerabilities. +2. **Address high-severity issues immediately**: High-severity issues with high confidence should be fixed as soon as possible. +3. **Review false positives**: Some issues flagged by Bandit may be false positives. Review them carefully and add skips only when necessary. +4. **Use context-specific configurations**: Different parts of your codebase may need different security checks. +5. **Keep Bandit updated**: Security tools should be kept up to date to catch the latest known vulnerabilities. ## Troubleshooting @@ -171,16 +175,16 @@ data = json.loads(user_input) If you're getting too many false positives: 1. Review the issues to ensure they're actually false positives -1. Add specific skips for the relevant checks in `pyproject.toml` -1. Use inline skips for specific lines: `# nosec` or `# nosec B101` +2. Add specific skips for the relevant checks in `pyproject.toml` +3. Use inline skips for specific lines: `# nosec` or `# nosec B101` #### Integration with Other Tools If you're having issues integrating Bandit with other tools: 1. Ensure you're using compatible versions -1. Check that your configuration files are correctly formatted -1. Try running Bandit directly to isolate the issue +2. Check that your configuration files are correctly formatted +3. Try running Bandit directly to isolate the issue ## Resources diff --git a/docs/technologies/code-analysis/pyright.md b/docs/technologies/code-analysis/pyright.md index d592a2e..8e58856 100644 --- a/docs/technologies/code-analysis/pyright.md +++ b/docs/technologies/code-analysis/pyright.md @@ -31,9 +31,9 @@ uv pip install pyright In this project, Pyright is used to: 1. Verify type correctness of the codebase -1. Catch potential type errors before runtime -1. Enforce type safety standards -1. Provide type information for IDE features +2. Catch potential type errors before runtime +3. Enforce type safety standards +4. Provide type information for IDE features It's configured to run in strict mode, which enforces comprehensive type checking. @@ -114,6 +114,7 @@ is_active: bool = True def greet(name: str) -> str: return f"Hello, {name}!" + # Function with optional parameters def greet_optional(name: str, title: str | None = None) -> str: if title: @@ -140,11 +141,11 @@ class User: ## Best Practices 1. **Add type annotations to public APIs**: At minimum, annotate function parameters and return types for public functions and methods. -1. **Use type aliases for complex types**: Create type aliases for complex types to improve readability. -1. **Leverage Union types for flexibility**: Use Union types (e.g., `str | None`) for parameters that can accept multiple types. -1. **Use TypedDict for dictionary structures**: Define TypedDict classes for dictionaries with specific structures. -1. **Add Generic types for containers**: Use Generic types for collections to specify contained types. -1. **Gradually add types**: Start with the most critical parts of your codebase and gradually add types to the rest. +2. **Use type aliases for complex types**: Create type aliases for complex types to improve readability. +3. **Leverage Union types for flexibility**: Use Union types (e.g., `str | None`) for parameters that can accept multiple types. +4. **Use TypedDict for dictionary structures**: Define TypedDict classes for dictionaries with specific structures. +5. **Add Generic types for containers**: Use Generic types for collections to specify contained types. +6. **Gradually add types**: Start with the most critical parts of your codebase and gradually add types to the rest. ## Troubleshooting @@ -155,24 +156,24 @@ class User: If you get type errors from third-party libraries: 1. Check if type stubs are available: `uv pip install types-package-name` -1. Add the library to the exclude list in `pyproject.toml` -1. Use `# type: ignore` comments for specific imports +2. Add the library to the exclude list in `pyproject.toml` +3. Use `# type: ignore` comments for specific imports #### "Cannot find module" Errors If Pyright can't find a module: 1. Ensure the module is installed -1. Check your project structure -1. Add the module to the Python path in your configuration +2. Check your project structure +3. Add the module to the Python path in your configuration #### "Type is unknown" Errors If you get "type is unknown" errors: 1. Add type annotations to the relevant variables or functions -1. Use `Any` as a last resort for truly dynamic types -1. Configure specific "reportUnknown\*" settings in `pyproject.toml` +2. Use `Any` as a last resort for truly dynamic types +3. Configure specific "reportUnknown\*" settings in `pyproject.toml` ## Resources diff --git a/docs/technologies/code-analysis/shellcheck-py.md b/docs/technologies/code-analysis/shellcheck-py.md index 9c07253..0dd3295 100644 --- a/docs/technologies/code-analysis/shellcheck-py.md +++ b/docs/technologies/code-analysis/shellcheck-py.md @@ -33,20 +33,20 @@ uv pip install shellcheck-py In this project, Shellcheck-py is used to: 1. Validate shell scripts in the repository -1. Ensure shell scripts follow best practices -1. Prevent common shell scripting bugs -1. Run as part of the pre-commit hooks and CI/CD pipeline +2. Ensure shell scripts follow best practices +3. Prevent common shell scripting bugs +4. Run as part of the pre-commit hooks and CI/CD pipeline ## Configuration in This Project Shellcheck-py is configured in the `.pre-commit-config.yaml` file: ```yaml -- repo: https://github.com/shellcheck-py/shellcheck-py - rev: v0.9.0.5 - hooks: - - id: shellcheck - args: ["--severity=warning"] + - repo: https://github.com/shellcheck-py/shellcheck-py + rev: v0.9.0.5 + hooks: + - id: shellcheck + args: [--severity=warning] ``` This configuration: @@ -113,32 +113,32 @@ eval "command ${user_input@Q}" Shellcheck uses different severity levels for issues: 1. **Error**: Severe issues that are likely to cause incorrect behavior -1. **Warning**: Issues that may cause problems in certain situations -1. **Info**: Suggestions for better practices -1. **Style**: Style recommendations +2. **Warning**: Issues that may cause problems in certain situations +3. **Info**: Suggestions for better practices +4. **Style**: Style recommendations ## Common Error Codes -| Code | Description | -|---------|-------------------------------------------------------| -| SC1000s | Shell parser issues | -| SC2000s | Common shell script issues | -| SC2086 | Double quote to prevent globbing and word splitting | -| SC2046 | Quote to prevent word splitting/globbing | -| SC2164 | Use `cd ... || exit` in case cd fails | -| SC2016 | Single quotes don't expand variables | -| SC2034 | Variable appears unused | -| SC2155 | Declare and assign separately for better error handling | -| SC3000s | Shell-specific issues (bash, dash, ksh) | +| Code | Description | +| ------- | ------------------------------------------------------- | +| SC1000s | Shell parser issues | +| SC2000s | Common shell script issues | +| SC2086 | Double quote to prevent globbing and word splitting | +| SC2046 | Quote to prevent word splitting/globbing | +| SC2164 | Use \`cd ... | +| SC2016 | Single quotes don't expand variables | +| SC2034 | Variable appears unused | +| SC2155 | Declare and assign separately for better error handling | +| SC3000s | Shell-specific issues (bash, dash, ksh) | ## Best Practices 1. **Fix all errors**: Address all error-level issues before committing. -1. **Review warnings**: Most warnings should be fixed unless there's a good reason not to. -1. **Use shellcheck directives**: Use `# shellcheck disable=SC2086` for intentional exceptions. -1. **Document exceptions**: When disabling checks, add a comment explaining why. -1. **Run regularly**: Include shellcheck in your pre-commit hooks. -1. **Learn from issues**: Use shellcheck as a learning tool to improve your shell scripting skills. +2. **Review warnings**: Most warnings should be fixed unless there's a good reason not to. +3. **Use shellcheck directives**: Use `# shellcheck disable=SC2086` for intentional exceptions. +4. **Document exceptions**: When disabling checks, add a comment explaining why. +5. **Run regularly**: Include shellcheck in your pre-commit hooks. +6. **Learn from issues**: Use shellcheck as a learning tool to improve your shell scripting skills. ## Resources diff --git a/docs/technologies/code-analysis/vulture.md b/docs/technologies/code-analysis/vulture.md index d8c8bfc..bfa3f47 100644 --- a/docs/technologies/code-analysis/vulture.md +++ b/docs/technologies/code-analysis/vulture.md @@ -38,8 +38,8 @@ uv pip install vulture In this project, Vulture is used to: 1. Identify unused code in the codebase -1. Maintain code quality by removing dead code -1. Run as part of the pre-commit hooks and CI/CD pipeline +2. Maintain code quality by removing dead code +3. Run as part of the pre-commit hooks and CI/CD pipeline ## Configuration in This Project @@ -151,10 +151,10 @@ uv run vulture src --min-confidence 70 ## Best Practices 1. **Run Vulture regularly**: Include Vulture in your pre-commit hooks and CI/CD pipeline. -1. **Start with a high confidence threshold**: Begin with a high threshold (e.g., 90%) and gradually lower it as you clean up obvious dead code. -1. **Maintain a whitelist**: Keep a whitelist of false positives to avoid repeatedly flagging the same code. -1. **Verify before removing**: Always verify that code is truly unused before removing it, especially for public APIs. -1. **Consider dynamic usage**: Remember that code might be used dynamically (e.g., through introspection or imports in rarely-run code paths). +2. **Start with a high confidence threshold**: Begin with a high threshold (e.g., 90%) and gradually lower it as you clean up obvious dead code. +3. **Maintain a whitelist**: Keep a whitelist of false positives to avoid repeatedly flagging the same code. +4. **Verify before removing**: Always verify that code is truly unused before removing it, especially for public APIs. +5. **Consider dynamic usage**: Remember that code might be used dynamically (e.g., through introspection or imports in rarely-run code paths). ## Troubleshooting @@ -165,16 +165,16 @@ uv run vulture src --min-confidence 70 If you're getting too many false positives: 1. Increase the minimum confidence threshold -1. Add more entries to your whitelist -1. Use more specific exclude patterns +2. Add more entries to your whitelist +3. Use more specific exclude patterns #### Missing Dead Code If Vulture is missing dead code: 1. Ensure you're scanning all relevant directories -1. Lower the confidence threshold -1. Check if the code is being imported or used dynamically +2. Lower the confidence threshold +3. Check if the code is being imported or used dynamically ## Resources diff --git a/docs/technologies/code-quality/codespell.md b/docs/technologies/code-quality/codespell.md index ad8375f..b7ba3a0 100644 --- a/docs/technologies/code-quality/codespell.md +++ b/docs/technologies/code-quality/codespell.md @@ -31,8 +31,8 @@ uv pip install codespell In this project, Codespell is used to: 1. Check for spelling errors in all project files -1. Run automatically as a pre-commit hook -1. Ensure consistent spelling in documentation and code comments +2. Run automatically as a pre-commit hook +3. Ensure consistent spelling in documentation and code comments ## Configuration in This Project @@ -108,28 +108,28 @@ src/module.py:10: definitely -> definitely Here are some common misspellings that Codespell catches: | Common Typo | Correct Spelling | -|---------------|---------------| -| accommodate | accommodate | -| achieve | achieve | -| address | address | -| argument | argument | -| believe | believe | -| consensus | consensus | -| definitely | definitely | -| dependency | dependency | -| existence | existence | -| occurred | occurred | -| receive | receive | -| separate | separate | -| successful | successful | +| ----------- | ---------------- | +| accommodate | accommodate | +| achieve | achieve | +| address | address | +| argument | argument | +| believe | believe | +| consensus | consensus | +| definitely | definitely | +| dependency | dependency | +| existence | existence | +| occurred | occurred | +| receive | receive | +| separate | separate | +| successful | successful | ## Best Practices 1. **Run regularly**: Include Codespell in your pre-commit hooks -1. **Customize for your project**: Add project-specific terms to the ignore list -1. **Fix spelling errors promptly**: Correct spelling errors as soon as they're detected -1. **Use with other tools**: Combine with other linting tools for comprehensive code quality -1. **Update dictionaries**: Keep custom dictionaries updated with domain-specific terminology +2. **Customize for your project**: Add project-specific terms to the ignore list +3. **Fix spelling errors promptly**: Correct spelling errors as soon as they're detected +4. **Use with other tools**: Combine with other linting tools for comprehensive code quality +5. **Update dictionaries**: Keep custom dictionaries updated with domain-specific terminology ## Troubleshooting @@ -138,14 +138,14 @@ Here are some common misspellings that Codespell catches: If Codespell flags words that are actually correct: 1. Add them to the `ignore-words-list` in your configuration -1. Create a custom dictionary file with words to ignore +2. Create a custom dictionary file with words to ignore ### Performance Issues For large codebases: 1. Use the `skip` option to exclude large generated files or binary files -1. Run Codespell only on changed files during development +2. Run Codespell only on changed files during development ## Resources diff --git a/docs/technologies/code-quality/commitizen.md b/docs/technologies/code-quality/commitizen.md index 6450685..8099e08 100644 --- a/docs/technologies/code-quality/commitizen.md +++ b/docs/technologies/code-quality/commitizen.md @@ -32,9 +32,9 @@ uv pip install commitizen In this project, Commitizen is used to: 1. Standardize commit messages following the Conventional Commits specification -1. Enforce commit message format through pre-commit hooks -1. Facilitate automatic changelog generation -1. Support semantic versioning +2. Enforce commit message format through pre-commit hooks +3. Facilitate automatic changelog generation +4. Support semantic versioning ## Configuration in This Project @@ -64,11 +64,11 @@ uv run cz c This will guide you through a series of prompts: 1. Select the type of change (feat, fix, docs, etc.) -1. Enter the scope (optional) -1. Write a short description -1. Provide a longer description (optional) -1. Indicate breaking changes (optional) -1. Reference issues (optional) +2. Enter the scope (optional) +3. Write a short description +4. Provide a longer description (optional) +5. Indicate breaking changes (optional) +6. Reference issues (optional) ### Common Command-Line Options @@ -121,26 +121,26 @@ Update installation instructions to include the new uv package manager. ## Best Practices 1. **Be specific in your commit messages**: Clearly describe what changes were made and why. -1. **Use appropriate types**: Choose the correct type (feat, fix, docs, etc.) for your changes. -1. **Include scope when relevant**: Specify which part of the codebase was affected. -1. **Reference issues**: Link commits to related issues or pull requests. -1. **Keep descriptions concise**: Aim for 50-72 characters in the summary line. -1. **Use imperative mood**: Write "add feature" instead of "added feature" or "adds feature". +2. **Use appropriate types**: Choose the correct type (feat, fix, docs, etc.) for your changes. +3. **Include scope when relevant**: Specify which part of the codebase was affected. +4. **Reference issues**: Link commits to related issues or pull requests. +5. **Keep descriptions concise**: Aim for 50-72 characters in the summary line. +6. **Use imperative mood**: Write "add feature" instead of "added feature" or "adds feature". ## Commit Types -| Type | Description | -|------------|------------------------------------------------------| -| `feat` | A new feature | -| `fix` | A bug fix | -| `docs` | Documentation changes | -| `style` | Code style changes (formatting, missing semi-colons) | -| `refactor` | Code changes that neither fix bugs nor add features | -| `perf` | Performance improvements | -| `test` | Adding or correcting tests | -| `build` | Changes to build system or dependencies | -| `ci` | Changes to CI configuration | -| `chore` | Other changes that don't modify src or test files | +| Type | Description | +| ---------- | ---------------------------------------------------- | +| `feat` | A new feature | +| `fix` | A bug fix | +| `docs` | Documentation changes | +| `style` | Code style changes (formatting, missing semi-colons) | +| `refactor` | Code changes that neither fix bugs nor add features | +| `perf` | Performance improvements | +| `test` | Adding or correcting tests | +| `build` | Changes to build system or dependencies | +| `ci` | Changes to CI configuration | +| `chore` | Other changes that don't modify src or test files | ## Resources diff --git a/docs/technologies/code-quality/darglint.md b/docs/technologies/code-quality/darglint.md index bd3e918..f7fdb2b 100644 --- a/docs/technologies/code-quality/darglint.md +++ b/docs/technologies/code-quality/darglint.md @@ -32,9 +32,9 @@ uv pip install darglint In this project, Darglint is used to: 1. Ensure docstrings accurately document function parameters and return values -1. Maintain consistency between code and documentation -1. Run as part of the pre-commit hooks and CI/CD pipeline -1. Improve code quality and maintainability +2. Maintain consistency between code and documentation +3. Run as part of the pre-commit hooks and CI/CD pipeline +4. Improve code quality and maintainability ## Configuration in This Project @@ -115,29 +115,29 @@ def add_numbers(a: int, b: int) -> int: ## Error Codes -| Code | Description | -|--------|-------------------------------------------------------| -| DAR001 | Missing parameter in docstring | -| DAR002 | Excess parameter in docstring | -| DAR003 | Missing return in docstring | -| DAR004 | Excess return in docstring | -| DAR101 | Missing parameter description in docstring | -| DAR102 | Excess parameter description in docstring | -| DAR103 | Missing return description in docstring | -| DAR104 | Excess return description in docstring | -| DAR201 | Missing "Yields" in docstring for generator function | -| DAR202 | Excess "Yields" in docstring for non-generator function | -| DAR301 | Missing "Raises" in docstring for function that raises| +| Code | Description | +| ------ | ------------------------------------------------------------ | +| DAR001 | Missing parameter in docstring | +| DAR002 | Excess parameter in docstring | +| DAR003 | Missing return in docstring | +| DAR004 | Excess return in docstring | +| DAR101 | Missing parameter description in docstring | +| DAR102 | Excess parameter description in docstring | +| DAR103 | Missing return description in docstring | +| DAR104 | Excess return description in docstring | +| DAR201 | Missing "Yields" in docstring for generator function | +| DAR202 | Excess "Yields" in docstring for non-generator function | +| DAR301 | Missing "Raises" in docstring for function that raises | | DAR302 | Excess "Raises" in docstring for function that doesn't raise | ## Best Practices 1. **Keep docstrings up to date**: Update docstrings whenever you change function signatures. -1. **Be consistent with style**: Choose one docstring style (Google, Sphinx, or Numpy) and stick with it. -1. **Document all parameters**: Include descriptions for all function parameters. -1. **Document return values**: Always specify what your function returns. -1. **Document exceptions**: Use the "Raises" section to document exceptions your function might raise. -1. **Run Darglint regularly**: Include Darglint in your pre-commit hooks to catch issues early. +2. **Be consistent with style**: Choose one docstring style (Google, Sphinx, or Numpy) and stick with it. +3. **Document all parameters**: Include descriptions for all function parameters. +4. **Document return values**: Always specify what your function returns. +5. **Document exceptions**: Use the "Raises" section to document exceptions your function might raise. +6. **Run Darglint regularly**: Include Darglint in your pre-commit hooks to catch issues early. ## Resources diff --git a/docs/technologies/code-quality/flynt.md b/docs/technologies/code-quality/flynt.md index de43ce8..6a5a549 100644 --- a/docs/technologies/code-quality/flynt.md +++ b/docs/technologies/code-quality/flynt.md @@ -30,8 +30,8 @@ uv pip install flynt In this project, Flynt is used to: 1. Automatically convert old-style string formatting to f-strings -1. Maintain consistent string formatting across the codebase -1. Run as part of the pre-commit hooks and CI/CD pipeline +2. Maintain consistent string formatting across the codebase +3. Run as part of the pre-commit hooks and CI/CD pipeline ## Configuration in This Project @@ -118,9 +118,9 @@ greeting = f"Hello, {name}!" ## Best Practices 1. **Run Flynt regularly**: Include Flynt in your pre-commit hooks to ensure consistent string formatting. -1. **Use f-strings for new code**: Write new code using f-strings directly. -1. **Review conversions**: Some complex string formatting might need manual review after conversion. -1. **Combine with other formatting tools**: Use Flynt alongside tools like Ruff for comprehensive code formatting. +2. **Use f-strings for new code**: Write new code using f-strings directly. +3. **Review conversions**: Some complex string formatting might need manual review after conversion. +4. **Combine with other formatting tools**: Use Flynt alongside tools like Ruff for comprehensive code formatting. ## Resources diff --git a/docs/technologies/code-quality/interrogate.md b/docs/technologies/code-quality/interrogate.md index 4d1df39..ac75d95 100644 --- a/docs/technologies/code-quality/interrogate.md +++ b/docs/technologies/code-quality/interrogate.md @@ -33,9 +33,9 @@ uv pip install interrogate In this project, Interrogate is used to: 1. Ensure all modules, classes, methods, and functions have docstrings -1. Maintain a high level of documentation coverage -1. Run as part of the pre-commit hooks and CI/CD pipeline -1. Generate coverage reports for documentation quality assessment +2. Maintain a high level of documentation coverage +3. Run as part of the pre-commit hooks and CI/CD pipeline +4. Generate coverage reports for documentation quality assessment ## Configuration in This Project @@ -43,7 +43,7 @@ Interrogate is configured in the `pyproject.toml` file: ```toml linenums="1" [tool.interrogate] -ignore-init-method = true # (1) +ignore-init-method = true # (1) ignore-init-module = true ignore-magic = true ignore-semiprivate = true @@ -52,8 +52,8 @@ ignore-property-decorators = true ignore-module = true ignore-nested-functions = true ignore-nested-classes = true -fail-under = 95 # (2) -exclude = ["tests", "docs", "build", "dist"] # (3) +fail-under = 95 # (2) +exclude = ["tests", "docs", "build", "dist"] # (3) verbose = 1 quiet = false whitelist-regex = [] @@ -61,8 +61,8 @@ color = true ``` 1. Ignores special methods that typically don't need docstrings -1. Requires at least 95% docstring coverage to pass -1. Excludes test files, documentation, and build artifacts from analysis +2. Requires at least 95% docstring coverage to pass +3. Excludes test files, documentation, and build artifacts from analysis This configuration: @@ -78,9 +78,11 @@ This configuration: To run Interrogate on the project: === "Using poe tasks" + `bash linenums="1" # Run via poethepoet uv run poe docstring-check ` === "Using direct commands" + \`\`\`bash linenums="1" \# Run on the entire project uv run interrogate src/ @@ -138,25 +140,26 @@ Wrote badge to: ./interrogate_badge.svg Interrogate measures docstring coverage at different levels: 1. **Module-level**: Docstrings at the top of Python files -1. **Class-level**: Docstrings for class definitions -1. **Method/Function-level**: Docstrings for methods and functions -1. **Nested-level**: Docstrings for nested classes and functions (if configured) +2. **Class-level**: Docstrings for class definitions +3. **Method/Function-level**: Docstrings for methods and functions +4. **Nested-level**: Docstrings for nested classes and functions (if configured) ## Best Practices 1. **Write docstrings for all public APIs**: Ensure all public classes, methods, and functions have docstrings. -1. **Use a consistent docstring style**: Follow a standard format like Google, NumPy, or reStructuredText. -1. **Include examples in docstrings**: Add examples to show how to use the code. -1. **Document parameters and return values**: Clearly describe inputs and outputs. -1. **Set appropriate coverage thresholds**: Start with a reasonable threshold and gradually increase it. -1. **Run regularly**: Include Interrogate in your pre-commit hooks to maintain documentation quality. -1. **Add badges to README**: Display docstring coverage badges in your project README. +2. **Use a consistent docstring style**: Follow a standard format like Google, NumPy, or reStructuredText. +3. **Include examples in docstrings**: Add examples to show how to use the code. +4. **Document parameters and return values**: Clearly describe inputs and outputs. +5. **Set appropriate coverage thresholds**: Start with a reasonable threshold and gradually increase it. +6. **Run regularly**: Include Interrogate in your pre-commit hooks to maintain documentation quality. +7. **Add badges to README**: Display docstring coverage badges in your project README. ## Docstring Formats Interrogate works with any docstring format, including: === "Google Style" + \`\`\`python linenums="1" def function(param1, param2): """Summary line. # (1) @@ -181,6 +184,7 @@ def function(param1, param2): ```` === "NumPy Style" + \`\`\`python linenums="1" def function(param1, param2): """ @@ -206,6 +210,7 @@ Summary line. ```` === "reStructuredText Style" + \`\`\`python linenums="1" def function(param1, param2): """Summary line. diff --git a/docs/technologies/code-quality/mdformat.md b/docs/technologies/code-quality/mdformat.md index dafa8fb..fc63f07 100644 --- a/docs/technologies/code-quality/mdformat.md +++ b/docs/technologies/code-quality/mdformat.md @@ -32,9 +32,9 @@ uv pip install mdformat In this project, MDFormat is used to: 1. Ensure consistent formatting across all Markdown documentation -1. Automatically fix formatting issues in documentation files -1. Run as part of the pre-commit hooks and CI/CD pipeline -1. Maintain professional and readable documentation +2. Automatically fix formatting issues in documentation files +3. Run as part of the pre-commit hooks and CI/CD pipeline +4. Maintain professional and readable documentation ## Configuration in This Project @@ -117,20 +117,20 @@ This is a paragraph with extra spaces. MDFormat applies several formatting rules: 1. **Consistent headings**: Uses ATX-style headings (`#` syntax) -1. **List formatting**: Standardizes list markers (`-` for unordered lists) -1. **Whitespace**: Removes trailing whitespace and ensures consistent spacing -1. **Line breaks**: Normalizes line breaks -1. **List numbering**: Correctly numbers ordered lists (when enabled) -1. **Table formatting**: Aligns table columns (with extensions) -1. **Code blocks**: Ensures proper fencing for code blocks +2. **List formatting**: Standardizes list markers (`-` for unordered lists) +3. **Whitespace**: Removes trailing whitespace and ensures consistent spacing +4. **Line breaks**: Normalizes line breaks +5. **List numbering**: Correctly numbers ordered lists (when enabled) +6. **Table formatting**: Aligns table columns (with extensions) +7. **Code blocks**: Ensures proper fencing for code blocks ## Best Practices 1. **Run MDFormat regularly**: Include it in your pre-commit hooks to maintain consistent formatting. -1. **Format before committing**: Run MDFormat on documentation files before committing changes. -1. **Use with other Markdown tools**: Combine with Markdown linters for comprehensive documentation quality. -1. **Enable relevant extensions**: Use extensions that match your Markdown flavor (e.g., GitHub Flavored Markdown). -1. **Check formatting in CI**: Verify Markdown formatting as part of your CI pipeline. +2. **Format before committing**: Run MDFormat on documentation files before committing changes. +3. **Use with other Markdown tools**: Combine with Markdown linters for comprehensive documentation quality. +4. **Enable relevant extensions**: Use extensions that match your Markdown flavor (e.g., GitHub Flavored Markdown). +5. **Check formatting in CI**: Verify Markdown formatting as part of your CI pipeline. ## Resources diff --git a/docs/technologies/code-quality/mkinit.md b/docs/technologies/code-quality/mkinit.md index 2f92e9b..d1364ad 100644 --- a/docs/technologies/code-quality/mkinit.md +++ b/docs/technologies/code-quality/mkinit.md @@ -31,9 +31,9 @@ uv pip install mkinit In this project, Mkinit is used to: 1. Automatically generate and update `__init__.py` files -1. Ensure consistent package exports -1. Simplify the package structure for users -1. Run as part of the development workflow +2. Ensure consistent package exports +3. Simplify the package structure for users +4. Run as part of the development workflow ## Configuration in This Project @@ -97,13 +97,14 @@ Mkinit might generate an `__init__.py` like: """ Package: your_package """ + from __future__ import absolute_import, division, print_function, unicode_literals from your_package import subpackage -from your_package.module1 import (Function1, Class1) -from your_package.module2 import (Function2, Class2) +from your_package.module1 import Function1, Class1 +from your_package.module2 import Function2, Class2 -__all__ = ['subpackage', 'Function1', 'Class1', 'Function2', 'Class2'] +__all__ = ["subpackage", "Function1", "Class1", "Function2", "Class2"] ``` ### Using Static Imports @@ -115,22 +116,23 @@ You can also use Mkinit with static imports: """ Package: your_package """ + from __future__ import absolute_import, division, print_function, unicode_literals # from your_package import subpackage -from your_package.module1 import (Function1, Class1) -from your_package.module2 import (Function2, Class2) +from your_package.module1 import Function1, Class1 +from your_package.module2 import Function2, Class2 # ``` ## Best Practices 1. **Run Mkinit after adding new modules**: Update your `__init__.py` files whenever you add new modules or classes. -1. **Use with version control**: Always commit the generated `__init__.py` files to your repository. -1. **Consider explicit imports**: For better IDE support, use explicit imports rather than wildcard imports. -1. **Add custom imports**: You can add custom imports outside the autogenerated section. -1. **Document your package structure**: Use the generated `__init__.py` files as a reference for your package structure. +2. **Use with version control**: Always commit the generated `__init__.py` files to your repository. +3. **Consider explicit imports**: For better IDE support, use explicit imports rather than wildcard imports. +4. **Add custom imports**: You can add custom imports outside the autogenerated section. +5. **Document your package structure**: Use the generated `__init__.py` files as a reference for your package structure. ## Resources diff --git a/docs/technologies/code-quality/pyupgrade.md b/docs/technologies/code-quality/pyupgrade.md index 442a757..dedb94e 100644 --- a/docs/technologies/code-quality/pyupgrade.md +++ b/docs/technologies/code-quality/pyupgrade.md @@ -31,8 +31,8 @@ uv pip install pyupgrade In this project, Pyupgrade is used to: 1. Automatically upgrade Python syntax to Python 3.11+ -1. Maintain modern Python syntax across the codebase -1. Run as part of the pre-commit hooks and CI/CD pipeline +2. Maintain modern Python syntax across the codebase +3. Run as part of the pre-commit hooks and CI/CD pipeline ## Configuration in This Project @@ -116,6 +116,7 @@ Before: ```python from typing import List, Dict, Optional + names: List[str] = ["Alice", "Bob"] ages: Dict[str, int] = {"Alice": 30, "Bob": 25} maybe_name: Optional[str] = None @@ -132,9 +133,9 @@ maybe_name: str | None = None ## Best Practices 1. **Run Pyupgrade regularly**: Include Pyupgrade in your pre-commit hooks to ensure consistent syntax. -1. **Specify the correct Python version**: Use the appropriate `--pyXX-plus` flag for your project's minimum Python version. -1. **Combine with other tools**: Use Pyupgrade alongside tools like Ruff and Flynt for comprehensive code modernization. -1. **Review changes**: Some syntax upgrades might change behavior in subtle ways, so review changes carefully. +2. **Specify the correct Python version**: Use the appropriate `--pyXX-plus` flag for your project's minimum Python version. +3. **Combine with other tools**: Use Pyupgrade alongside tools like Ruff and Flynt for comprehensive code modernization. +4. **Review changes**: Some syntax upgrades might change behavior in subtle ways, so review changes carefully. ## Resources diff --git a/docs/technologies/code-quality/radon.md b/docs/technologies/code-quality/radon.md index 20d2085..b462c7b 100644 --- a/docs/technologies/code-quality/radon.md +++ b/docs/technologies/code-quality/radon.md @@ -33,9 +33,9 @@ uv pip install radon In this project, Radon is used to: 1. Identify overly complex functions and methods -1. Maintain reasonable complexity levels across the codebase -1. Run as part of the pre-commit hooks and CI/CD pipeline -1. Guide refactoring efforts to improve code maintainability +2. Maintain reasonable complexity levels across the codebase +3. Run as part of the pre-commit hooks and CI/CD pipeline +4. Guide refactoring efforts to improve code maintainability ## Configuration in This Project @@ -67,9 +67,11 @@ This configuration: To run Radon on the project: === "Using poe tasks" + `bash linenums="1" # Run via poethepoet uv run poe radon ` === "Using direct commands" + \`\`\`bash linenums="1" \# Run cyclomatic complexity analysis directly uv run radon cc src/ @@ -128,14 +130,14 @@ src/your_package/complex.py - C (65.32) Radon uses letter grades to rank complexity: -| Rank | Complexity | Risk | -|------|------------|-------------------------------------| -| A | 1-5 | Low - simple block | -| B | 6-10 | Low - well structured and stable | -| C | 11-20 | Moderate - slightly complex | -| D | 21-30 | More than moderate - more complex | -| E | 31-40 | High - complex, alarming | -| F | 41+ | Very high - error-prone, unstable | +| Rank | Complexity | Risk | +| ---- | ---------- | --------------------------------- | +| A | 1-5 | Low - simple block | +| B | 6-10 | Low - well structured and stable | +| C | 11-20 | Moderate - slightly complex | +| D | 21-30 | More than moderate - more complex | +| E | 31-40 | High - complex, alarming | +| F | 41+ | Very high - error-prone, unstable | ## Metrics Explained @@ -171,18 +173,19 @@ A composite metric based on cyclomatic complexity, lines of code, and Halstead v ## Best Practices 1. **Keep functions simple**: Aim for cyclomatic complexity below 10 (A-B rank). -1. **Refactor complex code**: Break down functions with high complexity. -1. **Write unit tests**: Complex functions need thorough testing. -1. **Set thresholds in CI**: Fail builds if complexity exceeds acceptable levels. -1. **Monitor trends**: Track complexity metrics over time to prevent degradation. -1. **Use with other tools**: Combine with tools like Ruff and Xenon for comprehensive quality checks. -1. **Focus on hotspots**: Prioritize refactoring the most complex parts of your codebase. +2. **Refactor complex code**: Break down functions with high complexity. +3. **Write unit tests**: Complex functions need thorough testing. +4. **Set thresholds in CI**: Fail builds if complexity exceeds acceptable levels. +5. **Monitor trends**: Track complexity metrics over time to prevent degradation. +6. **Use with other tools**: Combine with tools like Ruff and Xenon for comprehensive quality checks. +7. **Focus on hotspots**: Prioritize refactoring the most complex parts of your codebase. ## Refactoring Strategies When Radon identifies complex code, consider these refactoring strategies: === "Extract Method" + \`\`\`python linenums="1" \# Before refactoring def complex_function(data): @@ -215,6 +218,7 @@ def calculate_result(processed): ```` === "Replace Conditionals" + \`\`\`python linenums="1" \# Before refactoring (complex if/else chain) def get_discount(customer_type, order_total): diff --git a/docs/technologies/code-quality/ruff.md b/docs/technologies/code-quality/ruff.md index 8f0a6e6..611366d 100644 --- a/docs/technologies/code-quality/ruff.md +++ b/docs/technologies/code-quality/ruff.md @@ -33,10 +33,10 @@ uv pip install ruff In this project, Ruff is used for: 1. Linting Python code to catch errors and enforce style -1. Formatting code to maintain consistent style -1. Sorting imports -1. Automatically fixing common issues -1. Running as part of the pre-commit hooks and CI/CD pipeline +2. Formatting code to maintain consistent style +3. Sorting imports +4. Automatically fixing common issues +5. Running as part of the pre-commit hooks and CI/CD pipeline ## Configuration in This Project @@ -89,17 +89,17 @@ skip-magic-trailing-comma = false [tool.ruff.lint] extend-ignore = [ - "E203", # Not PEP8 compliant and black insert space around slice - "E501", # Line too long. Disable it to allow long lines of comments - "D401", # First line should be in imperative mood - "D203", # Removed incompatible rule (keep D211 instead) - "D213", # Removed incompatible rule (keep D212 instead) + "E203", # Not PEP8 compliant and black insert space around slice + "E501", # Line too long. Disable it to allow long lines of comments + "D401", # First line should be in imperative mood + "D203", # Removed incompatible rule (keep D211 instead) + "D213", # Removed incompatible rule (keep D212 instead) "COM812", # Removed rule that may conflict with formatter - "F811", # Redefined variable from import + "F811", # Redefined variable from import "ISC001", "BLE001", "PGH", - "C901", # Too complex + "C901", # Too complex "PLR", "TRY300", ] @@ -109,7 +109,11 @@ extend-select = [ [tool.ruff.lint.per-file-ignores] "__init__.py" = ["D104"] # Allow __init__.py stuff -"tests/**/*.py" = ["S101", "ARG001", "FBT001"] # Allow assert statements in tests, unused function arguments, and boolean positional arguments +"tests/**/*.py" = [ + "S101", + "ARG001", + "FBT001", +] # Allow assert statements in tests, unused function arguments, and boolean positional arguments ``` Ruff is also configured as poethepoet tasks: @@ -193,11 +197,11 @@ And many more. See the [Ruff documentation](https://docs.astral.sh/ruff/rules/) ## Best Practices 1. **Run Ruff before committing**: Use pre-commit hooks to run Ruff automatically. -1. **Use `--fix` for automatic fixes**: Let Ruff fix simple issues automatically. -1. **Customize rules for your project**: Adjust the rule set to match your project's needs. -1. **Use per-file ignores for special cases**: Some files may need different rules. -1. **Keep configuration in pyproject.toml**: Centralize all tool configurations in one file. -1. **Update Ruff regularly**: Newer versions often include performance improvements and new rules. +2. **Use `--fix` for automatic fixes**: Let Ruff fix simple issues automatically. +3. **Customize rules for your project**: Adjust the rule set to match your project's needs. +4. **Use per-file ignores for special cases**: Some files may need different rules. +5. **Keep configuration in pyproject.toml**: Centralize all tool configurations in one file. +6. **Update Ruff regularly**: Newer versions often include performance improvements and new rules. ## Troubleshooting @@ -208,25 +212,25 @@ And many more. See the [Ruff documentation](https://docs.astral.sh/ruff/rules/) If you're getting too many errors when first adding Ruff: 1. Start with a smaller rule set: `--select E,F,W` -1. Gradually add more rules as you fix issues -1. Use `--fix` to automatically fix simple issues -1. Add specific ignores for rules that don't apply to your project +2. Gradually add more rules as you fix issues +3. Use `--fix` to automatically fix simple issues +4. Add specific ignores for rules that don't apply to your project #### Conflicts with Other Tools If Ruff conflicts with other tools: 1. Consider replacing the other tools with Ruff -1. Adjust Ruff's configuration to match the other tools -1. Use per-file ignores to handle special cases +2. Adjust Ruff's configuration to match the other tools +3. Use per-file ignores to handle special cases #### Performance Issues If Ruff is running slowly (which is rare): 1. Exclude large directories that don't need linting -1. Use a more specific file selection -1. Update to the latest version of Ruff +2. Use a more specific file selection +3. Update to the latest version of Ruff ## Resources diff --git a/docs/technologies/code-quality/xenon.md b/docs/technologies/code-quality/xenon.md index a32b53b..6dbffa1 100644 --- a/docs/technologies/code-quality/xenon.md +++ b/docs/technologies/code-quality/xenon.md @@ -33,9 +33,9 @@ uv pip install xenon In this project, Xenon is used to: 1. Enforce maximum complexity thresholds -1. Prevent code quality degradation over time -1. Run as part of the pre-commit hooks and CI/CD pipeline -1. Ensure maintainable code across the codebase +2. Prevent code quality degradation over time +3. Run as part of the pre-commit hooks and CI/CD pipeline +4. Ensure maintainable code across the codebase ## Configuration in This Project @@ -60,9 +60,11 @@ This configuration: To run Xenon on the project: === "Using poe tasks" + `bash linenums="1" # Run via poethepoet uv run poe xenon ` === "Using direct commands" + `bash linenums="1" # Run directly with thresholds uv run xenon --max-absolute B --max-modules B --max-average A src/ ` ### Common Command-Line Options @@ -113,55 +115,55 @@ The following thresholds were exceeded: Xenon uses Radon's letter grades to rank complexity: -| Rank | Complexity | Risk | -|------|------------|-------------------------------------| -| A | 1-5 | Low - simple block | -| B | 6-10 | Low - well structured and stable | -| C | 11-20 | Moderate - slightly complex | -| D | 21-30 | More than moderate - more complex | -| E | 31-40 | High - complex, alarming | -| F | 41+ | Very high - error-prone, unstable | +| Rank | Complexity | Risk | +| ---- | ---------- | --------------------------------- | +| A | 1-5 | Low - simple block | +| B | 6-10 | Low - well structured and stable | +| C | 11-20 | Moderate - slightly complex | +| D | 21-30 | More than moderate - more complex | +| E | 31-40 | High - complex, alarming | +| F | 41+ | Very high - error-prone, unstable | ## Metrics Explained Xenon checks three different complexity metrics: 1. **Absolute Complexity**: The highest complexity of any single function or method in the codebase -1. **Module Complexity**: The highest average complexity of any module in the codebase -1. **Average Complexity**: The average complexity across all functions and methods in the codebase +2. **Module Complexity**: The highest average complexity of any module in the codebase +3. **Average Complexity**: The average complexity across all functions and methods in the codebase ## Best Practices 1. **Start with reasonable thresholds**: Begin with moderate thresholds (C or D) and gradually tighten them. -1. **Focus on absolute complexity first**: Prioritize fixing the most complex functions. -1. **Use with Radon**: Use Radon to identify specific complex functions that Xenon flags. -1. **Include in CI pipeline**: Make Xenon part of your continuous integration checks. -1. **Gradually improve thresholds**: As you refactor, gradually lower thresholds to prevent regression. -1. **Document exceptions**: If certain complex functions can't be simplified, document why. -1. **Balance strictness with practicality**: Very strict thresholds (all A's) might be impractical for some codebases. +2. **Focus on absolute complexity first**: Prioritize fixing the most complex functions. +3. **Use with Radon**: Use Radon to identify specific complex functions that Xenon flags. +4. **Include in CI pipeline**: Make Xenon part of your continuous integration checks. +5. **Gradually improve thresholds**: As you refactor, gradually lower thresholds to prevent regression. +6. **Document exceptions**: If certain complex functions can't be simplified, document why. +7. **Balance strictness with practicality**: Very strict thresholds (all A's) might be impractical for some codebases. ## Integration with CI/CD ### GitHub Actions Example ```yaml linenums="1" -- name: Check code complexity - run: | - uv pip install xenon - xenon --max-absolute B --max-modules B --max-average A src/ + - name: Check code complexity + run: | + uv pip install xenon + xenon --max-absolute B --max-modules B --max-average A src/ ``` ### Pre-commit Hook Example ```yaml linenums="1" -- repo: local - hooks: - - id: xenon - name: xenon - entry: xenon --max-absolute B --max-modules B --max-average A - language: python - types: [python] - additional_dependencies: [xenon] + - repo: local + hooks: + - id: xenon + name: xenon + entry: xenon --max-absolute B --max-modules B --max-average A + language: python + types: [python] + additional_dependencies: [xenon] ``` ## Troubleshooting @@ -173,16 +175,16 @@ Xenon checks three different complexity metrics: If Xenon consistently fails with your current thresholds: 1. Use Radon to identify the most complex parts of your code -1. Refactor those parts to reduce complexity -1. If refactoring isn't feasible, consider slightly relaxing thresholds +2. Refactor those parts to reduce complexity +3. If refactoring isn't feasible, consider slightly relaxing thresholds #### False Positives Some complex code might be unavoidably complex due to the problem domain: 1. Consider excluding specific files from analysis -1. Document why the complexity is necessary -1. Ensure complex code is well-tested and documented +2. Document why the complexity is necessary +3. Ensure complex code is well-tested and documented ## Resources diff --git a/docs/technologies/documentation/index.md b/docs/technologies/documentation/index.md index 5ce7ca2..05b5b6e 100644 --- a/docs/technologies/documentation/index.md +++ b/docs/technologies/documentation/index.md @@ -9,8 +9,8 @@ Documentation is a critical aspect of any software project. Good documentation h This project uses several tools to maintain high-quality documentation: 1. **MkDocs**: A fast, simple static site generator for building project documentation -1. **MkDocs Material**: A modern theme for MkDocs that provides a responsive and feature-rich documentation experience -1. **MkDocstrings**: A plugin for MkDocs that generates API documentation from Python docstrings +2. **MkDocs Material**: A modern theme for MkDocs that provides a responsive and feature-rich documentation experience +3. **MkDocstrings**: A plugin for MkDocs that generates API documentation from Python docstrings ## Documentation Structure @@ -39,12 +39,12 @@ The documentation for this project is organized as follows: ## Best Practices 1. **Document as you code**: Write documentation alongside your code, not as an afterthought -1. **Keep documentation up-to-date**: Update documentation when code changes -1. **Use consistent style**: Follow a consistent style throughout the documentation -1. **Include examples**: Provide examples to illustrate how to use the code -1. **Use admonitions for important information**: Highlight warnings, notes, and tips -1. **Test documentation**: Ensure code examples in documentation work as expected -1. **Get feedback**: Ask others to review your documentation for clarity and completeness +2. **Keep documentation up-to-date**: Update documentation when code changes +3. **Use consistent style**: Follow a consistent style throughout the documentation +4. **Include examples**: Provide examples to illustrate how to use the code +5. **Use admonitions for important information**: Highlight warnings, notes, and tips +6. **Test documentation**: Ensure code examples in documentation work as expected +7. **Get feedback**: Ask others to review your documentation for clarity and completeness ## Resources diff --git a/docs/technologies/documentation/mkdocs.md b/docs/technologies/documentation/mkdocs.md index eb08004..369db48 100644 --- a/docs/technologies/documentation/mkdocs.md +++ b/docs/technologies/documentation/mkdocs.md @@ -37,10 +37,10 @@ uv pip install mkdocs In this project, MkDocs is used to: 1. Generate the project documentation website -1. Provide a searchable interface for documentation -1. Organize documentation in a logical structure -1. Enable easy navigation between documentation sections -1. Facilitate documentation updates alongside code changes +2. Provide a searchable interface for documentation +3. Organize documentation in a logical structure +4. Enable easy navigation between documentation sections +5. Facilitate documentation updates alongside code changes ## Configuration in This Project @@ -86,20 +86,20 @@ nav: - Getting Started: getting-started.md - Overview: overview.md - Development: - - Workflow: development/workflow.md - - Pre-commit Hooks: development/pre-commit-hooks.md + - Workflow: development/workflow.md + - Pre-commit Hooks: development/pre-commit-hooks.md - Technologies: - - Package Management: - - UV: technologies/package-management/uv.md - - Code Quality: - - Ruff: technologies/code-quality/ruff.md + - Package Management: + - UV: technologies/package-management/uv.md + - Code Quality: + - Ruff: technologies/code-quality/ruff.md - API Reference: api/ ``` 1. Material theme provides a modern, responsive design -1. Adds copy buttons to all code blocks -1. MkDocstrings plugin generates API documentation from docstrings -1. Markdown extensions enhance the basic Markdown syntax +2. Adds copy buttons to all code blocks +3. MkDocstrings plugin generates API documentation from docstrings +4. Markdown extensions enhance the basic Markdown syntax ## Basic Usage @@ -120,6 +120,7 @@ my-project/ To preview the documentation locally: === "Using poe tasks" + \`\`\`bash linenums="1" \# Start the development server uv run poe docs-serve @@ -134,6 +135,7 @@ uv run poe docs-deploy ```` === "Using direct commands" + \`\`\`bash linenums="1" \# Start the development server uv run mkdocs serve @@ -174,12 +176,15 @@ This is a paragraph with **bold** and *italic* text. ### Code Blocks === "Basic Code Block" + ```` markdown linenums="1" ```python def hello_world(): print("Hello, world!") ``` ```` === "With Line Numbers" + ```` markdown linenums="1" ```python linenums="1" def hello_world(): print("Hello, world!") ``` ```` === "With Annotations" + \`\`\`\`markdown linenums="1" `python def hello_world(): # (1) print("Hello, world!") # (2) ` @@ -205,15 +210,15 @@ This is a paragraph with **bold** and *italic* text. ## Best Practices 1. **Organize documentation logically**: Structure your documentation in a way that makes sense for users. -1. **Keep documentation up-to-date**: Update documentation when code changes. -1. **Use descriptive page titles**: Make it easy for users to find what they're looking for. -1. **Include examples**: Provide code examples and use cases. -1. **Use admonitions for important information**: Highlight warnings, notes, and tips. -1. **Add screenshots when helpful**: Visual aids can improve understanding. -1. **Maintain a consistent style**: Use a consistent writing style throughout. -1. **Link related content**: Cross-reference related documentation. -1. **Test documentation**: Ensure code examples work and instructions are accurate. -1. **Get feedback**: Ask users for feedback on documentation clarity. +2. **Keep documentation up-to-date**: Update documentation when code changes. +3. **Use descriptive page titles**: Make it easy for users to find what they're looking for. +4. **Include examples**: Provide code examples and use cases. +5. **Use admonitions for important information**: Highlight warnings, notes, and tips. +6. **Add screenshots when helpful**: Visual aids can improve understanding. +7. **Maintain a consistent style**: Use a consistent writing style throughout. +8. **Link related content**: Cross-reference related documentation. +9. **Test documentation**: Ensure code examples work and instructions are accurate. +10. **Get feedback**: Ask users for feedback on documentation clarity. ## Advanced Features @@ -233,7 +238,7 @@ Configure in `mkdocs.yml`: ```yaml linenums="1" theme: - name: null + name: custom_dir: mkdocs/custom_theme/ ``` @@ -251,7 +256,7 @@ plugins: ``` 1. Minifies HTML output for faster loading -1. Adds last updated dates to pages based on git history +2. Adds last updated dates to pages based on git history ## Troubleshooting @@ -262,24 +267,24 @@ plugins: If navigation isn't updating: 1. Check the `nav` section in `mkdocs.yml` -1. Ensure file paths are correct -1. Restart the development server +2. Ensure file paths are correct +3. Restart the development server #### Build Errors If you encounter build errors: 1. Check for syntax errors in Markdown files -1. Verify that all linked files exist -1. Check for configuration errors in `mkdocs.yml` +2. Verify that all linked files exist +3. Check for configuration errors in `mkdocs.yml` #### Search Not Working If search isn't working: 1. Ensure the search plugin is enabled -1. Rebuild the documentation -1. Check for JavaScript errors in the browser console +2. Rebuild the documentation +3. Check for JavaScript errors in the browser console ## Resources diff --git a/docs/technologies/documentation/mkdocstrings.md b/docs/technologies/documentation/mkdocstrings.md index 0efd6d0..c150a13 100644 --- a/docs/technologies/documentation/mkdocstrings.md +++ b/docs/technologies/documentation/mkdocstrings.md @@ -34,10 +34,10 @@ uv pip install mkdocstrings[python] In this project, MkDocstrings is used to: 1. Generate comprehensive API documentation from Python docstrings -1. Maintain consistency between code and documentation -1. Provide detailed function, class, and module documentation -1. Reduce manual documentation effort -1. Ensure documentation stays up-to-date with code changes +2. Maintain consistency between code and documentation +3. Provide detailed function, class, and module documentation +4. Reduce manual documentation effort +5. Ensure documentation stays up-to-date with code changes ## Configuration in This Project @@ -61,9 +61,9 @@ plugins: ``` 1. Enables the MkDocstrings plugin -1. Configures the Python handler -1. Shows source code in documentation -1. Uses Google-style docstrings +2. Configures the Python handler +3. Shows source code in documentation +4. Uses Google-style docstrings ## Basic Usage @@ -91,10 +91,10 @@ def calculate_area(length: float, width: float) -> float: ``` 1. Function signature with type hints -1. Short description of the function -1. Documentation of parameters -1. Documentation of return value -1. Documentation of exceptions +2. Short description of the function +3. Documentation of parameters +4. Documentation of return value +5. Documentation of exceptions ### Referencing in Markdown @@ -111,6 +111,7 @@ Reference your code in Markdown files: ## Docstring Styles === "Google Style (Default)" + \`\`\`python linenums="1" def function(param1, param2): """Summary line. @@ -132,6 +133,7 @@ def function(param1, param2): ```` === "NumPy Style" + \`\`\`python linenums="1" def function(param1, param2): """Summary line. @@ -160,6 +162,7 @@ def function(param1, param2): ```` === "reStructuredText Style" + \`\`\`python linenums="1" def function(param1, param2): """Summary line. @@ -221,13 +224,13 @@ Customize the rendering of documentation: ## Best Practices 1. **Be consistent with docstring style**: Choose one style (Google, NumPy, or reStructuredText) and use it consistently. -1. **Document all public APIs**: Ensure all public functions, classes, and methods have docstrings. -1. **Include type hints**: Use type hints in your code to enhance documentation. -1. **Document parameters and return values**: Always document parameters, return values, and exceptions. -1. **Keep docstrings up-to-date**: Update docstrings when code changes. -1. **Use examples**: Include examples in docstrings for complex functions. -1. **Be concise but complete**: Provide enough information without being overly verbose. -1. **Use cross-references**: Link to related documentation when appropriate. +2. **Document all public APIs**: Ensure all public functions, classes, and methods have docstrings. +3. **Include type hints**: Use type hints in your code to enhance documentation. +4. **Document parameters and return values**: Always document parameters, return values, and exceptions. +5. **Keep docstrings up-to-date**: Update docstrings when code changes. +6. **Use examples**: Include examples in docstrings for complex functions. +7. **Be concise but complete**: Provide enough information without being overly verbose. +8. **Use cross-references**: Link to related documentation when appropriate. ## Integration with Type Hints @@ -236,8 +239,8 @@ MkDocstrings works well with type hints: ```python linenums="1" from typing import List, Dict, Optional -def process_data(data: List[Dict[str, str]], - filter_key: Optional[str] = None) -> Dict[str, int]: + +def process_data(data: List[Dict[str, str]], filter_key: Optional[str] = None) -> Dict[str, int]: """Process the input data. Args: @@ -250,8 +253,8 @@ def process_data(data: List[Dict[str, str]], ``` 1. Import type annotations from the typing module -1. Parameter with complex type annotation -1. Optional parameter with default value and return type annotation +2. Parameter with complex type annotation +3. Optional parameter with default value and return type annotation ## Troubleshooting @@ -262,24 +265,24 @@ def process_data(data: List[Dict[str, str]], If documentation is not appearing: 1. Check that the import path is correct -1. Verify that the module is importable from where MkDocs is run -1. Ensure the docstrings are properly formatted +2. Verify that the module is importable from where MkDocs is run +3. Ensure the docstrings are properly formatted #### Formatting Issues If docstrings aren't rendering correctly: 1. Check that the docstring style in the configuration matches your code -1. Verify indentation in docstrings -1. Ensure all sections are properly formatted +2. Verify indentation in docstrings +3. Ensure all sections are properly formatted #### Import Errors If you encounter import errors: 1. Make sure your package is installed in the environment where MkDocs runs -1. Check for circular imports -1. Consider using the `watch` option to monitor for changes +2. Check for circular imports +3. Consider using the `watch` option to monitor for changes ## Resources diff --git a/docs/technologies/index.md b/docs/technologies/index.md index e2639c2..9597fe1 100644 --- a/docs/technologies/index.md +++ b/docs/technologies/index.md @@ -60,12 +60,12 @@ This section provides documentation for the various technologies and tools used Each technology page follows a consistent structure: 1. **Overview** - A brief description of what the tool does and its key features -1. **Installation** - How to install the tool in this project -1. **How It's Used in This Project** - Specific ways the tool is utilized -1. **Configuration in This Project** - How the tool is configured -1. **Basic Usage** - Common commands and usage patterns -1. **Examples** - Practical examples of using the tool -1. **Best Practices** - Recommended approaches when using the tool -1. **Resources** - Links to official documentation and helpful resources +2. **Installation** - How to install the tool in this project +3. **How It's Used in This Project** - Specific ways the tool is utilized +4. **Configuration in This Project** - How the tool is configured +5. **Basic Usage** - Common commands and usage patterns +6. **Examples** - Practical examples of using the tool +7. **Best Practices** - Recommended approaches when using the tool +8. **Resources** - Links to official documentation and helpful resources For a more comprehensive understanding of how these technologies work together, see the [Development Workflow](../development/workflow.md) documentation. diff --git a/docs/technologies/package-management/hatchling.md b/docs/technologies/package-management/hatchling.md index 765bbed..bfbe4bf 100644 --- a/docs/technologies/package-management/hatchling.md +++ b/docs/technologies/package-management/hatchling.md @@ -55,9 +55,9 @@ version = "0.1.0" description = "Project description" readme = "README.md" requires-python = ">=3.11" -license = {text = "MIT"} +license = { text = "MIT" } authors = [ - {name = "Your Name", email = "your.email@example.com"}, + { name = "Your Name", email = "your.email@example.com" }, ] ``` @@ -66,14 +66,14 @@ authors = [ ```toml [project] dependencies = [ - "dependency1>=1.0.0", - "dependency2>=2.0.0", + "dependency1>=1.0.0", + "dependency2>=2.0.0", ] [project.optional-dependencies] dev = [ - "pytest>=7.0.0", - "black>=23.0.0", + "pytest>=7.0.0", + "black>=23.0.0", ] ``` @@ -95,8 +95,8 @@ plugin-name = "package.module:function" ```toml [tool.hatch.build] exclude = [ - "tests/", - "docs/", + "tests/", + "docs/", ] [tool.hatch.build.targets.wheel] @@ -106,9 +106,9 @@ packages = ["src"] ## Best Practices 1. **Use `src` directory structure**: This keeps your package code separate from project files. -1. **Specify Python version requirements**: Use `requires-python` to ensure compatibility. -1. **Include comprehensive metadata**: Provide complete project information for better PyPI presentation. -1. **Use dynamic versioning when appropriate**: Hatchling supports various versioning schemes. +2. **Specify Python version requirements**: Use `requires-python` to ensure compatibility. +3. **Include comprehensive metadata**: Provide complete project information for better PyPI presentation. +4. **Use dynamic versioning when appropriate**: Hatchling supports various versioning schemes. ## Troubleshooting @@ -131,8 +131,8 @@ uv run python -m build If the built package is missing files: 1. Check the `[tool.hatch.build.targets.wheel]` section -1. Ensure all necessary directories are included -1. Check for exclude patterns that might be too broad +2. Ensure all necessary directories are included +3. Check for exclude patterns that might be too broad ## Resources diff --git a/docs/technologies/package-management/uv.md b/docs/technologies/package-management/uv.md index a959d1d..fc6f3d7 100644 --- a/docs/technologies/package-management/uv.md +++ b/docs/technologies/package-management/uv.md @@ -31,10 +31,10 @@ uv --version In this project, UV is used to: 1. Manage project dependencies -1. Create and update virtual environments -1. Run Python scripts and commands in the project's environment -1. Execute development tools and test runners -1. Ensure reproducible builds with dependency pinning +2. Create and update virtual environments +3. Run Python scripts and commands in the project's environment +4. Execute development tools and test runners +5. Ensure reproducible builds with dependency pinning ## Configuration in This Project @@ -43,17 +43,17 @@ UV uses the standard `pyproject.toml` file for dependency management: ```toml [project] dependencies = [ - "pydantic>=2.0.0", - "pydantic-settings>=2.0.0", - "lazy-loader>=0.3", + "pydantic>=2.0.0", + "pydantic-settings>=2.0.0", + "lazy-loader>=0.3", ] [project.optional-dependencies] dev = [ - "pytest>=7.0.0", - "pytest-cov>=4.1.0", - "ruff>=0.1.0", - # Other development dependencies + "pytest>=7.0.0", + "pytest-cov>=4.1.0", + "ruff>=0.1.0", + # Other development dependencies ] ``` @@ -147,34 +147,34 @@ tests/test_module1.py .......................................... [100%] UV significantly outperforms traditional Python package managers: -| Operation | pip | pip-tools | UV | -|-----------|-----|-----------|-----| -| Fresh install (42 packages) | 12.5s | 10.2s | 1.2s | -| Dependency resolution | 8.3s | 5.1s | 0.3s | -| No-op reinstall | 2.1s | 1.8s | 0.1s | +| Operation | pip | pip-tools | UV | +| --------------------------- | ----- | --------- | ---- | +| Fresh install (42 packages) | 12.5s | 10.2s | 1.2s | +| Dependency resolution | 8.3s | 5.1s | 0.3s | +| No-op reinstall | 2.1s | 1.8s | 0.1s | ## Best Practices 1. **Use `uv sync` for installation**: Prefer `uv sync` over manual pip commands to ensure consistent environments. -1. **Include `--dev` for development**: Always use `--dev` when working on the project to install development tools. -1. **Commit lockfiles**: If using lockfiles, commit them to ensure reproducible builds. -1. **Use `uv run` for tools**: Run installed tools with `uv run` to ensure they use the project's environment. -1. **Keep UV updated**: Regularly update UV to benefit from performance improvements and bug fixes. -1. **Use virtual environments**: Always work within a virtual environment to isolate project dependencies. -1. **Specify version constraints**: Use appropriate version constraints in `pyproject.toml` to avoid unexpected updates. +2. **Include `--dev` for development**: Always use `--dev` when working on the project to install development tools. +3. **Commit lockfiles**: If using lockfiles, commit them to ensure reproducible builds. +4. **Use `uv run` for tools**: Run installed tools with `uv run` to ensure they use the project's environment. +5. **Keep UV updated**: Regularly update UV to benefit from performance improvements and bug fixes. +6. **Use virtual environments**: Always work within a virtual environment to isolate project dependencies. +7. **Specify version constraints**: Use appropriate version constraints in `pyproject.toml` to avoid unexpected updates. ## Common Commands -| Command | Description | -|---------|-------------| -| `uv sync` | Install dependencies from pyproject.toml | -| `uv sync --dev` | Install dependencies including development dependencies | -| `uv sync --upgrade` | Upgrade all dependencies to their latest versions | -| `uv add package` | Add a new dependency | -| `uv add --dev package` | Add a new development dependency | -| `uv run command` | Run a command in the project's environment | -| `uv pip install package` | Install a package (pip-compatible interface) | -| `uv venv` | Create a virtual environment | +| Command | Description | +| ------------------------ | ------------------------------------------------------- | +| `uv sync` | Install dependencies from pyproject.toml | +| `uv sync --dev` | Install dependencies including development dependencies | +| `uv sync --upgrade` | Upgrade all dependencies to their latest versions | +| `uv add package` | Add a new dependency | +| `uv add --dev package` | Add a new development dependency | +| `uv run command` | Run a command in the project's environment | +| `uv pip install package` | Install a package (pip-compatible interface) | +| `uv venv` | Create a virtual environment | ## Resources diff --git a/docs/technologies/project-structure/hatchling.md b/docs/technologies/project-structure/hatchling.md index 4a3b70e..8847496 100644 --- a/docs/technologies/project-structure/hatchling.md +++ b/docs/technologies/project-structure/hatchling.md @@ -34,10 +34,10 @@ uv pip install hatchling In this project, Hatchling is used to: 1. Define the project's build system -1. Manage package metadata -1. Handle version information -1. Configure package discovery and inclusion -1. Support the build and distribution process +2. Manage package metadata +3. Handle version information +4. Configure package discovery and inclusion +5. Support the build and distribution process ## Configuration in This Project @@ -54,12 +54,12 @@ version = "0.1.0" description = "Your package description" readme = "README.md" requires-python = ">=3.11" -license = {text = "MIT"} +license = { text = "MIT" } authors = [ - {name = "Your Name", email = "your.email@example.com"}, + { name = "Your Name", email = "your.email@example.com" }, ] dependencies = [ - # List of dependencies + # List of dependencies ] [tool.hatch.build.targets.wheel] @@ -120,12 +120,12 @@ packages = ["src/your_package"] ```toml [project.optional-dependencies] dev = [ - "pytest>=7.0.0", - "pytest-cov>=4.1.0", + "pytest>=7.0.0", + "pytest-cov>=4.1.0", ] docs = [ - "mkdocs>=1.4.0", - "mkdocs-material>=9.0.0", + "mkdocs>=1.4.0", + "mkdocs-material>=9.0.0", ] ``` @@ -134,21 +134,21 @@ docs = [ When you run `hatch build`, Hatchling performs these steps: 1. **Configuration Loading**: Reads the `pyproject.toml` file -1. **Version Resolution**: Determines the package version -1. **Metadata Preparation**: Prepares package metadata -1. **Source Processing**: Processes source files according to configuration -1. **Build Execution**: Creates the distribution packages (wheel, sdist) -1. **Artifact Generation**: Outputs the final distribution files +2. **Version Resolution**: Determines the package version +3. **Metadata Preparation**: Prepares package metadata +4. **Source Processing**: Processes source files according to configuration +5. **Build Execution**: Creates the distribution packages (wheel, sdist) +6. **Artifact Generation**: Outputs the final distribution files ## Best Practices 1. **Use src layout**: Place your package code in a `src` directory for cleaner separation. -1. **Specify Python version**: Always set the `requires-python` field to ensure compatibility. -1. **Include a README**: Provide a README.md file for PyPI display. -1. **Manage versions properly**: Use a single source of truth for version information. -1. **Define optional dependencies**: Group dependencies logically using optional-dependencies. -1. **Include license information**: Always specify license information in your project metadata. -1. **Use dynamic metadata**: Take advantage of Hatchling's dynamic metadata capabilities for complex projects. +2. **Specify Python version**: Always set the `requires-python` field to ensure compatibility. +3. **Include a README**: Provide a README.md file for PyPI display. +4. **Manage versions properly**: Use a single source of truth for version information. +5. **Define optional dependencies**: Group dependencies logically using optional-dependencies. +6. **Include license information**: Always specify license information in your project metadata. +7. **Use dynamic metadata**: Take advantage of Hatchling's dynamic metadata capabilities for complex projects. ## Advanced Features @@ -157,8 +157,8 @@ When you run `hatch build`, Hatchling performs these steps: ```toml [project] dependencies = [ - "importlib-metadata>=4.6; python_version < '3.10'", - "tomli>=2.0.0; python_version < '3.11'", + "importlib-metadata>=4.6; python_version < '3.10'", + "tomli>=2.0.0; python_version < '3.11'", ] ``` diff --git a/docs/technologies/project-structure/lazy-loader.md b/docs/technologies/project-structure/lazy-loader.md index 7233ff7..6ea31ed 100644 --- a/docs/technologies/project-structure/lazy-loader.md +++ b/docs/technologies/project-structure/lazy-loader.md @@ -33,9 +33,9 @@ uv pip install lazy-loader In this project, Lazy-Loader is used to: 1. Optimize import times for large dependencies -1. Reduce memory usage by only loading modules when needed -1. Maintain clean imports in the codebase -1. Improve application startup performance +2. Reduce memory usage by only loading modules when needed +3. Maintain clean imports in the codebase +4. Improve application startup performance ## Configuration in This Project @@ -46,10 +46,7 @@ Lazy-Loader is typically used in `__init__.py` files to lazily load submodules: from lazy_loader import lazy_loader # Set up lazy loading for submodules -__getattr__, __dir__, __all__ = lazy_loader.attach( - __name__, - ["module1", "module2", "module3"] -) +__getattr__, __dir__, __all__ = lazy_loader.attach(__name__, ["module1", "module2", "module3"]) ``` ## Basic Usage @@ -60,10 +57,7 @@ __getattr__, __dir__, __all__ = lazy_loader.attach( # In your package's __init__.py from lazy_loader import lazy_loader -__getattr__, __dir__, __all__ = lazy_loader.attach( - __name__, - ["heavy_module", "rarely_used_module"] -) +__getattr__, __dir__, __all__ = lazy_loader.attach(__name__, ["heavy_module", "rarely_used_module"]) ``` ### Lazy Loading with Explicit Exports @@ -77,7 +71,7 @@ __getattr__, __dir__, __all__ = lazy_loader.attach( { "heavy_module": ["Class1", "function1"], "rarely_used_module": ["Class2", "function2"], - } + }, ) ``` @@ -105,10 +99,7 @@ from lazy_loader import lazy_loader from .core import main_function, CoreClass # Set up lazy loading for heavier modules -__getattr__, __dir__, __all__ = lazy_loader.attach( - __name__, - ["heavy_module", "rarely_used_module"] -) +__getattr__, __dir__, __all__ = lazy_loader.attach(__name__, ["heavy_module", "rarely_used_module"]) # Add directly imported items to __all__ __all__ += ["main_function", "CoreClass"] @@ -131,20 +122,20 @@ result = your_package.heavy_module.heavy_function() Lazy loading can significantly improve startup time and memory usage: -| Scenario | Without Lazy Loading | With Lazy Loading | -|----------|----------------------|-------------------| -| Startup Time | 500ms | 150ms | -| Memory Usage | 100MB | 40MB | -| First Access | Immediate | Slight delay | +| Scenario | Without Lazy Loading | With Lazy Loading | +| ------------ | -------------------- | ----------------- | +| Startup Time | 500ms | 150ms | +| Memory Usage | 100MB | 40MB | +| First Access | Immediate | Slight delay | ## Best Practices 1. **Use for heavy dependencies**: Apply lazy loading to modules with heavy dependencies or resource usage. -1. **Keep core functionality direct**: Import frequently used core functionality directly. -1. **Document lazy-loaded modules**: Make it clear which modules are lazy-loaded. -1. **Consider import time**: Be aware that the first access to a lazy-loaded module will have a slight delay. -1. **Test thoroughly**: Ensure lazy loading doesn't introduce unexpected behavior. -1. **Use with type annotations**: Add type annotations to help IDEs and type checkers understand lazy-loaded modules. +2. **Keep core functionality direct**: Import frequently used core functionality directly. +3. **Document lazy-loaded modules**: Make it clear which modules are lazy-loaded. +4. **Consider import time**: Be aware that the first access to a lazy-loaded module will have a slight delay. +5. **Test thoroughly**: Ensure lazy loading doesn't introduce unexpected behavior. +6. **Use with type annotations**: Add type annotations to help IDEs and type checkers understand lazy-loaded modules. ## Advanced Usage @@ -159,10 +150,7 @@ if TYPE_CHECKING: from .heavy_module import HeavyClass, heavy_function # Set up lazy loading -__getattr__, __dir__, __all__ = lazy_loader.attach( - __name__, - ["heavy_module"] -) +__getattr__, __dir__, __all__ = lazy_loader.attach(__name__, ["heavy_module"]) ``` ### Selective Lazy Loading @@ -180,7 +168,7 @@ __getattr__, __dir__, __all__ = lazy_loader.attach( { "heavy_module": ["HeavyClass", "heavy_function"], "rarely_used_module": ["RarelyUsedClass"], - } + }, ) ``` diff --git a/docs/technologies/project-structure/mkinit.md b/docs/technologies/project-structure/mkinit.md index d2e0c0d..f84c6ab 100644 --- a/docs/technologies/project-structure/mkinit.md +++ b/docs/technologies/project-structure/mkinit.md @@ -41,9 +41,9 @@ Mkinit is configured as a poethepoet task in the `pyproject.toml` file: ```toml [tool.poe.tasks] -mkinit = {sequence = ["mkinit-src", "mkinit-tests"]} -mkinit-src = {cmd = "mkinit src --relative --lazy_loader_typed --black --recursive -w"} -mkinit-tests = {cmd = "mkinit tests --relative --lazy_loader_typed --black --recursive -w"} +mkinit = { sequence = ["mkinit-src", "mkinit-tests"] } +mkinit-src = { cmd = "mkinit src --relative --lazy_loader_typed --black --recursive -w" } +mkinit-tests = { cmd = "mkinit tests --relative --lazy_loader_typed --black --recursive -w" } ``` This configuration: @@ -106,9 +106,9 @@ Mkinit supports several command-line options: ## Best Practices 1. **Run mkinit after adding new modules**: Whenever you add a new module to the project, run mkinit to update the `__init__.py` files. -1. **Use version control**: Always commit `__init__.py` files to version control after generating them. -1. **Include in pre-commit hooks**: Consider adding mkinit to your pre-commit hooks to ensure `__init__.py` files are always up to date. -1. **Use with lazy loading**: Combine mkinit with lazy loading for optimal import performance. +2. **Use version control**: Always commit `__init__.py` files to version control after generating them. +3. **Include in pre-commit hooks**: Consider adding mkinit to your pre-commit hooks to ensure `__init__.py` files are always up to date. +4. **Use with lazy loading**: Combine mkinit with lazy loading for optimal import performance. ## Troubleshooting @@ -119,16 +119,16 @@ Mkinit supports several command-line options: If you encounter circular import errors: 1. Restructure your code to avoid circular dependencies -1. Use lazy loading to break circular dependencies -1. Use conditional imports inside functions +2. Use lazy loading to break circular dependencies +3. Use conditional imports inside functions #### Missing Exports If some exports are missing from the generated `__init__.py`: 1. Ensure the exports are properly defined in the module -1. Check that the module is in the correct directory -1. Run mkinit with the `--verbose` flag to see what's being processed +2. Check that the module is in the correct directory +3. Run mkinit with the `--verbose` flag to see what's being processed ## Resources diff --git a/docs/technologies/project-structure/pydantic-settings.md b/docs/technologies/project-structure/pydantic-settings.md index 92b741f..3d1cea8 100644 --- a/docs/technologies/project-structure/pydantic-settings.md +++ b/docs/technologies/project-structure/pydantic-settings.md @@ -34,9 +34,9 @@ uv pip install pydantic-settings In this project, Pydantic-Settings is used to: 1. Define and validate application configuration -1. Load settings from environment variables -1. Provide type-safe access to configuration values -1. Support different environments (development, testing, production) +2. Load settings from environment variables +3. Provide type-safe access to configuration values +4. Support different environments (development, testing, production) ## Configuration in This Project @@ -104,6 +104,7 @@ class Settings(BaseSettings): extra="ignore", ) + # Create a global settings instance settings = Settings() ``` @@ -115,11 +116,9 @@ settings = Settings() ```python from pydantic_settings import BaseSettings, SettingsConfigDict + class AppSettings(BaseSettings): - model_config = SettingsConfigDict( - env_file=".env", - env_prefix="APP_" - ) + model_config = SettingsConfigDict(env_file=".env", env_prefix="APP_") # Settings with types and default values debug: bool = False @@ -147,6 +146,7 @@ logger.info("Starting %s v%s", settings.APP_NAME, settings.APP_VERSION) ```python from pydantic_settings import BaseSettings + class Settings(BaseSettings): environment: str = "development" @@ -192,11 +192,11 @@ model_config = SettingsConfigDict( In the case where a value is specified for the same `Settings` field in multiple ways, the selected value is determined as follows (in descending order of priority): 1. If `cli_parse_args` is enabled, arguments passed in at the CLI -1. Arguments passed to the `Settings` class initializer -1. Environment variables -1. Variables loaded from a dotenv (`.env`) file -1. Variables loaded from the secrets directory -1. Default field values for the `Settings` model +2. Arguments passed to the `Settings` class initializer +3. Environment variables +4. Variables loaded from a dotenv (`.env`) file +5. Variables loaded from the secrets directory +6. Default field values for the `Settings` model This priority order ensures that values can be overridden in a predictable way, with more explicit sources (like CLI arguments and initializer arguments) taking precedence over less explicit ones (like environment variables and dotenv files). @@ -207,7 +207,7 @@ If you need to load multiple dotenv files, you can pass multiple file paths as a ```python model_config = SettingsConfigDict( # `.env.prod` takes priority over `.env` - env_file=('.env', '.env.prod') + env_file=(".env", ".env.prod") ) ``` @@ -220,10 +220,10 @@ This is useful for having a base configuration in one file and environment-speci ```python # Our settings support environment variables without a prefix # For example, with these environment variables: -APP_NAME="Environment App" -APP_VERSION="2.0.0" -DEBUG=true -LOG_LEVEL="DEBUG" +APP_NAME = "Environment App" +APP_VERSION = "2.0.0" +DEBUG = true +LOG_LEVEL = "DEBUG" # The settings would be: settings = Settings() @@ -239,6 +239,7 @@ assert settings.LOG_LEVEL == "DEBUG" from pydantic import BaseModel from pydantic_settings import BaseSettings + class DatabaseSettings(BaseModel): host: str = "localhost" port: int = 5432 @@ -246,6 +247,7 @@ class DatabaseSettings(BaseModel): password: str = "password" name: str = "database" + class AppSettings(BaseSettings): debug: bool = False database: DatabaseSettings = DatabaseSettings() @@ -254,12 +256,12 @@ class AppSettings(BaseSettings): ## Best Practices 1. **Use environment variables**: Store configuration in environment variables, especially for secrets. -1. **Provide defaults**: Set sensible default values for non-sensitive settings. -1. **Use validation**: Take advantage of Pydantic's validation to ensure settings are correct. -1. **Separate concerns**: Split settings into logical groups using nested models. -1. **Document settings**: Add docstrings to explain what each setting does. -1. **Use computed properties**: Add properties for derived values to keep settings DRY. -1. **Keep secrets secure**: Never hardcode sensitive information; use environment variables or secret management tools. +2. **Provide defaults**: Set sensible default values for non-sensitive settings. +3. **Use validation**: Take advantage of Pydantic's validation to ensure settings are correct. +4. **Separate concerns**: Split settings into logical groups using nested models. +5. **Document settings**: Add docstrings to explain what each setting does. +6. **Use computed properties**: Add properties for derived values to keep settings DRY. +7. **Keep secrets secure**: Never hardcode sensitive information; use environment variables or secret management tools. ## Advanced Features @@ -270,6 +272,7 @@ from pydantic import Field from pydantic_settings import BaseSettings from pathlib import Path + class Settings(BaseSettings): # Simple field with description APP_NAME: str = Field( @@ -295,13 +298,14 @@ class Settings(BaseSettings): Pydantic-Settings v2 provides integrated CLI support, making it easy to define CLI applications using Pydantic models. There are two primary use cases: 1. Using a CLI to override fields in Pydantic models -1. Using Pydantic models to define CLIs +2. Using Pydantic models to define CLIs To enable CLI parsing, set the `cli_parse_args` flag in the model configuration: ```python from pydantic_settings import BaseSettings, SettingsConfigDict + class Settings(BaseSettings): model_config = SettingsConfigDict(cli_parse_args=True) @@ -325,6 +329,7 @@ If the default order of priority doesn't match your needs, you can change it by from typing import Tuple, Type from pydantic_settings import BaseSettings, PydanticBaseSettingsSource + class Settings(BaseSettings): # Your settings fields here... diff --git a/docs/technologies/task-running/poethepoet.md b/docs/technologies/task-running/poethepoet.md index 0314fec..b845c45 100644 --- a/docs/technologies/task-running/poethepoet.md +++ b/docs/technologies/task-running/poethepoet.md @@ -33,11 +33,11 @@ uv pip install poethepoet In this project, Poethepoet is used to: 1. Define common development tasks -1. Run linters and formatters -1. Execute tests -1. Build documentation -1. Generate code -1. Provide a consistent interface for various tools +2. Run linters and formatters +3. Execute tests +4. Build documentation +5. Generate code +6. Provide a consistent interface for various tools ## Configuration in This Project @@ -46,12 +46,12 @@ Poethepoet is configured in the `pyproject.toml` file under the `[tool.poe.tasks ```toml [tool.poe.tasks] flynt = "flynt --aggressive --fail-on-change --quiet src tests" -lint = {sequence = ["pyupgrade", "flynt", "pyright", "ruff", "ruff-format"]} -mkdocs = {cmd = "mkdocs build"} -mkdocs-serve = {cmd = "mkdocs serve"} -mkinit = {sequence = ["mkinit-src", "mkinit-tests"]} -mkinit-src = {cmd = "mkinit src --relative --lazy_loader_typed --black --recursive -w"} -mkinit-tests = {cmd = "mkinit tests --relative --lazy_loader_typed --black --recursive -w"} +lint = { sequence = ["pyupgrade", "flynt", "pyright", "ruff", "ruff-format"] } +mkdocs = { cmd = "mkdocs build" } +mkdocs-serve = { cmd = "mkdocs serve" } +mkinit = { sequence = ["mkinit-src", "mkinit-tests"] } +mkinit-src = { cmd = "mkinit src --relative --lazy_loader_typed --black --recursive -w" } +mkinit-tests = { cmd = "mkinit tests --relative --lazy_loader_typed --black --recursive -w" } pre = "pre-commit run --all-files --show-diff-on-failure --verbose" pre-commit = "pre-commit run --all-files" pyright = "pyright" @@ -115,25 +115,25 @@ task-name = "command --with --options" ### Command Tasks with Options ```toml -task-name = {cmd = "command --with --options"} +task-name = { cmd = "command --with --options" } ``` ### Sequence Tasks ```toml -task-name = {sequence = ["task1", "task2", "task3"]} +task-name = { sequence = ["task1", "task2", "task3"] } ``` ### Script Tasks ```toml -task-name = {script = "python_module:function_name"} +task-name = { script = "python_module:function_name" } ``` ### Shell Tasks ```toml -task-name = {shell = "echo 'Running in a shell'"} +task-name = { shell = "echo 'Running in a shell'" } ``` ## Advanced Features @@ -143,7 +143,7 @@ task-name = {shell = "echo 'Running in a shell'"} You can define tasks that depend on other tasks: ```toml -lint = {sequence = ["pyupgrade", "flynt", "pyright", "ruff", "ruff-format"]} +lint = { sequence = ["pyupgrade", "flynt", "pyright", "ruff", "ruff-format"] } ``` ### Task Arguments @@ -159,16 +159,16 @@ poe ruff src/specific_module.py You can set environment variables for tasks: ```toml -task-name = {cmd = "command", env = {VAR1 = "value1", VAR2 = "value2"}} +task-name = { cmd = "command", env = { VAR1 = "value1", VAR2 = "value2" } } ``` ## Best Practices 1. **Group related tasks**: Use sequence tasks to group related operations. -1. **Use descriptive task names**: Choose names that clearly indicate what the task does. -1. **Document tasks**: Include comments in your pyproject.toml to explain complex tasks. -1. **Prefer poe over direct commands**: Use poe tasks to provide a consistent interface. -1. **Use task dependencies**: Break complex tasks into smaller, reusable tasks. +2. **Use descriptive task names**: Choose names that clearly indicate what the task does. +3. **Document tasks**: Include comments in your pyproject.toml to explain complex tasks. +4. **Prefer poe over direct commands**: Use poe tasks to provide a consistent interface. +5. **Use task dependencies**: Break complex tasks into smaller, reusable tasks. ## Troubleshooting @@ -179,24 +179,24 @@ task-name = {cmd = "command", env = {VAR1 = "value1", VAR2 = "value2"}} If you get a "task not found" error: 1. Check the spelling of the task name -1. Ensure the task is defined in pyproject.toml -1. Make sure you're running the command from the project root +2. Ensure the task is defined in pyproject.toml +3. Make sure you're running the command from the project root #### Task Fails with Error If a task fails with an error: 1. Check the error message for details -1. Run the command directly to see if it works outside of poe -1. Check for environment or path issues +2. Run the command directly to see if it works outside of poe +3. Check for environment or path issues #### Arguments Not Passed Correctly If arguments aren't being passed correctly: 1. Try quoting the arguments -1. Use `--` to separate poe arguments from task arguments -1. Check if the task is defined to accept arguments +2. Use `--` to separate poe arguments from task arguments +3. Check if the task is defined to accept arguments ## Resources diff --git a/docs/technologies/testing/pytest-asyncio.md b/docs/technologies/testing/pytest-asyncio.md index f4d683a..4d77fdf 100644 --- a/docs/technologies/testing/pytest-asyncio.md +++ b/docs/technologies/testing/pytest-asyncio.md @@ -33,9 +33,9 @@ uv pip install pytest-asyncio In this project, Pytest-asyncio is used to: 1. Test asynchronous functions and coroutines -1. Ensure proper handling of async resources -1. Validate async API behavior -1. Test concurrent operations +2. Ensure proper handling of async resources +3. Validate async API behavior +4. Test concurrent operations ## Configuration in This Project @@ -61,6 +61,7 @@ async def test_async_function(): result = await my_async_function() assert result == expected_value + # Using async fixtures @pytest.fixture async def async_resource(): @@ -68,6 +69,7 @@ async def async_resource(): yield resource await resource.close() + async def test_with_async_fixture(async_resource): result = await async_resource.operation() assert result == expected_value @@ -90,6 +92,7 @@ uv run pytest test_async_module.py ```python import pytest + @pytest.fixture async def api_client(): client = AsyncAPIClient() @@ -97,6 +100,7 @@ async def api_client(): yield client await client.disconnect() + async def test_api_get_data(api_client): data = await api_client.get_data("resource_id") assert "key" in data @@ -108,13 +112,10 @@ async def test_api_get_data(api_client): ```python import asyncio + async def test_concurrent_operations(): # Run multiple operations concurrently - results = await asyncio.gather( - operation1(), - operation2(), - operation3() - ) + results = await asyncio.gather(operation1(), operation2(), operation3()) # Check results assert results[0] == expected1 @@ -127,27 +128,27 @@ async def test_concurrent_operations(): Pytest-asyncio supports different modes for handling the asyncio event loop: 1. **`auto`**: Automatically detects async tests and fixtures -1. **`strict`**: Requires explicit marking of async tests with `@pytest.mark.asyncio` -1. **`legacy`**: Uses a single event loop for all tests (deprecated) +2. **`strict`**: Requires explicit marking of async tests with `@pytest.mark.asyncio` +3. **`legacy`**: Uses a single event loop for all tests (deprecated) ## Best Practices 1. **Use appropriate fixtures**: Create async fixtures for resource management. -1. **Clean up resources**: Always clean up async resources in fixture teardown. -1. **Test error handling**: Test both success and error paths in async code. -1. **Avoid mixing sync and async**: Keep synchronous and asynchronous code separate. -1. **Test timeouts**: Use `asyncio.wait_for()` to test timeout behavior. -1. **Test cancellation**: Verify that your async code handles cancellation correctly. -1. **Use `asyncio.gather`**: Test concurrent operations with `asyncio.gather`. +2. **Clean up resources**: Always clean up async resources in fixture teardown. +3. **Test error handling**: Test both success and error paths in async code. +4. **Avoid mixing sync and async**: Keep synchronous and asynchronous code separate. +5. **Test timeouts**: Use `asyncio.wait_for()` to test timeout behavior. +6. **Test cancellation**: Verify that your async code handles cancellation correctly. +7. **Use `asyncio.gather`**: Test concurrent operations with `asyncio.gather`. ## Common Issues and Solutions -| Issue | Solution | -|-------|----------| -| Event loop is closed | Use `asyncio_mode = "auto"` in pytest configuration | -| Fixture teardown not running | Ensure you're using `yield` instead of `return` in async fixtures | -| Test hangs indefinitely | Add timeouts to your async operations with `asyncio.wait_for()` | -| Mixing sync and async code | Use `asyncio.run()` or `loop.run_until_complete()` to call async from sync | +| Issue | Solution | +| ---------------------------- | -------------------------------------------------------------------------- | +| Event loop is closed | Use `asyncio_mode = "auto"` in pytest configuration | +| Fixture teardown not running | Ensure you're using `yield` instead of `return` in async fixtures | +| Test hangs indefinitely | Add timeouts to your async operations with `asyncio.wait_for()` | +| Mixing sync and async code | Use `asyncio.run()` or `loop.run_until_complete()` to call async from sync | ## Resources diff --git a/docs/technologies/testing/pytest-cov.md b/docs/technologies/testing/pytest-cov.md index 73e3912..3275b50 100644 --- a/docs/technologies/testing/pytest-cov.md +++ b/docs/technologies/testing/pytest-cov.md @@ -33,9 +33,9 @@ uv pip install pytest-cov In this project, Pytest-cov is used to: 1. Measure test coverage across the codebase -1. Generate coverage reports as part of the CI/CD pipeline -1. Identify areas of the code that need more testing -1. Enforce minimum coverage thresholds +2. Generate coverage reports as part of the CI/CD pipeline +3. Identify areas of the code that need more testing +4. Enforce minimum coverage thresholds ## Configuration in This Project @@ -115,19 +115,19 @@ The HTML report provides a detailed view of coverage, including: Pytest-cov supports different types of coverage measurement: 1. **Statement Coverage**: Measures which statements in your code have been executed -1. **Branch Coverage**: Measures which possible branches (if/else paths) have been taken -1. **Function Coverage**: Measures which functions have been called -1. **Line Coverage**: Measures which executable lines have been run +2. **Branch Coverage**: Measures which possible branches (if/else paths) have been taken +3. **Function Coverage**: Measures which functions have been called +4. **Line Coverage**: Measures which executable lines have been run ## Best Practices 1. **Aim for high coverage**: Strive for at least 80-90% code coverage. -1. **Focus on critical paths**: Ensure business-critical code has near 100% coverage. -1. **Don't just chase numbers**: High coverage doesn't guarantee good tests; focus on test quality too. -1. **Use branch coverage**: Enable branch coverage to catch untested conditional paths. -1. **Set minimum thresholds**: Use `--cov-fail-under` to enforce minimum coverage requirements. -1. **Review coverage reports regularly**: Identify and address areas with low coverage. -1. **Include coverage in CI**: Make coverage checks part of your continuous integration pipeline. +2. **Focus on critical paths**: Ensure business-critical code has near 100% coverage. +3. **Don't just chase numbers**: High coverage doesn't guarantee good tests; focus on test quality too. +4. **Use branch coverage**: Enable branch coverage to catch untested conditional paths. +5. **Set minimum thresholds**: Use `--cov-fail-under` to enforce minimum coverage requirements. +6. **Review coverage reports regularly**: Identify and address areas with low coverage. +7. **Include coverage in CI**: Make coverage checks part of your continuous integration pipeline. ## Resources diff --git a/docs/technologies/testing/pytest-xdist.md b/docs/technologies/testing/pytest-xdist.md index 1127966..69b0dee 100644 --- a/docs/technologies/testing/pytest-xdist.md +++ b/docs/technologies/testing/pytest-xdist.md @@ -33,9 +33,9 @@ uv pip install pytest-xdist In this project, Pytest-xdist is used to: 1. Speed up test execution by running tests in parallel -1. Ensure tests are properly isolated and don't interfere with each other -1. Optimize CI/CD pipeline performance -1. Reduce feedback time during development +2. Ensure tests are properly isolated and don't interfere with each other +3. Optimize CI/CD pipeline performance +4. Reduce feedback time during development ## Configuration in This Project @@ -84,10 +84,10 @@ uv run pytest -n auto --dist=loadmodule Pytest-xdist supports different distribution modes: 1. **`--dist=load`** (default): Distributes tests to available workers as they finish their previous tests -1. **`--dist=loadscope`**: Groups tests by module and class, ensuring related tests run on the same worker -1. **`--dist=loadfile`**: Groups tests by file, ensuring all tests from a file run on the same worker -1. **`--dist=loadgroup`**: Groups tests by the `xdist_group` marker -1. **`--dist=each`**: Runs the entire test suite on each worker with different parameters +2. **`--dist=loadscope`**: Groups tests by module and class, ensuring related tests run on the same worker +3. **`--dist=loadfile`**: Groups tests by file, ensuring all tests from a file run on the same worker +4. **`--dist=loadgroup`**: Groups tests by the `xdist_group` marker +5. **`--dist=each`**: Runs the entire test suite on each worker with different parameters ## Examples @@ -110,11 +110,13 @@ gw0 [250] / gw1 [250] / gw2 [250] / gw3 [250] # In your test file import pytest + @pytest.mark.xdist_group(name="database") def test_database_connection(): # Test database connection ... + @pytest.mark.xdist_group(name="api") def test_api_endpoint(): # Test API endpoint @@ -129,22 +131,22 @@ uv run pytest -n 4 --dist=loadgroup ## Best Practices 1. **Ensure test isolation**: Make sure tests don't depend on each other or shared state. -1. **Use appropriate distribution mode**: Choose the right `--dist` option based on your test dependencies. -1. **Consider test data**: Be careful with tests that access the same test data or database. -1. **Balance parallelism**: More workers isn't always better; find the optimal number for your system. -1. **Use markers for grouping**: Use `xdist_group` markers to control how tests are distributed. -1. **Monitor resource usage**: Watch CPU, memory, and I/O usage during parallel test execution. -1. **Combine with pytest-cov**: Use `--cov-append` when combining with coverage measurement. +2. **Use appropriate distribution mode**: Choose the right `--dist` option based on your test dependencies. +3. **Consider test data**: Be careful with tests that access the same test data or database. +4. **Balance parallelism**: More workers isn't always better; find the optimal number for your system. +5. **Use markers for grouping**: Use `xdist_group` markers to control how tests are distributed. +6. **Monitor resource usage**: Watch CPU, memory, and I/O usage during parallel test execution. +7. **Combine with pytest-cov**: Use `--cov-append` when combining with coverage measurement. ## Common Issues and Solutions -| Issue | Solution | -|-------|----------| +| Issue | Solution | +| --------------------------------- | ------------------------------------------------------------------ | | Tests interfering with each other | Use `--dist=loadscope` or `--dist=loadfile` to group related tests | -| Database conflicts | Use separate test databases or transactions for isolation | -| Inconsistent test failures | Add the `--reruns` option to retry flaky tests | -| High resource usage | Reduce the number of workers with `-n` option | -| Slow test initialization | Use session-scoped fixtures for expensive setup operations | +| Database conflicts | Use separate test databases or transactions for isolation | +| Inconsistent test failures | Add the `--reruns` option to retry flaky tests | +| High resource usage | Reduce the number of workers with `-n` option | +| Slow test initialization | Use session-scoped fixtures for expensive setup operations | ## Resources diff --git a/docs/technologies/testing/pytest.md b/docs/technologies/testing/pytest.md index 24e0c13..19c2e0b 100644 --- a/docs/technologies/testing/pytest.md +++ b/docs/technologies/testing/pytest.md @@ -33,10 +33,10 @@ uv pip install pytest pytest-cov pytest-asyncio pytest-xdist In this project, Pytest is used to: 1. Write and run unit tests -1. Measure code coverage -1. Test asynchronous code -1. Run tests in parallel -1. Generate coverage reports +2. Measure code coverage +3. Test asynchronous code +4. Run tests in parallel +5. Generate coverage reports ## Configuration in This Project @@ -109,6 +109,7 @@ uv run pytest --cov=src def test_addition(): assert 1 + 1 == 2 + def test_string_methods(): assert "hello".capitalize() == "Hello" ``` @@ -131,13 +132,16 @@ class TestMathFunctions: # test_example.py import pytest + @pytest.fixture def sample_data(): return {"name": "Test User", "age": 30} + def test_user_name(sample_data): assert sample_data["name"] == "Test User" + def test_user_age(sample_data): assert sample_data["age"] == 30 ``` @@ -148,9 +152,11 @@ def test_user_age(sample_data): # test_example.py import pytest + def divide(a, b): return a / b + def test_division_by_zero(): with pytest.raises(ZeroDivisionError): divide(1, 0) @@ -162,14 +168,18 @@ def test_division_by_zero(): # test_example.py import pytest -@pytest.mark.parametrize("input,expected", [ - (1, 1), - (2, 4), - (3, 9), - (4, 16), -]) + +@pytest.mark.parametrize( + "input,expected", + [ + (1, 1), + (2, 4), + (3, 9), + (4, 16), + ], +) def test_square(input, expected): - assert input ** 2 == expected + assert input**2 == expected ``` ### Async Tests @@ -178,6 +188,7 @@ def test_square(input, expected): # test_example.py import pytest + @pytest.mark.asyncio async def test_async_function(): result = await some_async_function() @@ -216,12 +227,12 @@ uv run pytest -n 4 # Use 4 CPU cores ## Best Practices 1. **Follow naming conventions**: Name test files with `test_` prefix and test functions with `test_` prefix. -1. **Use fixtures for setup and teardown**: Avoid duplicating setup code across tests. -1. **Keep tests independent**: Tests should not depend on the state from other tests. -1. **Test one thing per test**: Each test should verify a single behavior. -1. **Use parameterized tests**: Test multiple inputs with a single test function. -1. **Aim for high coverage**: Strive for at least 80% code coverage. -1. **Include both positive and negative tests**: Test both expected and error cases. +2. **Use fixtures for setup and teardown**: Avoid duplicating setup code across tests. +3. **Keep tests independent**: Tests should not depend on the state from other tests. +4. **Test one thing per test**: Each test should verify a single behavior. +5. **Use parameterized tests**: Test multiple inputs with a single test function. +6. **Aim for high coverage**: Strive for at least 80% code coverage. +7. **Include both positive and negative tests**: Test both expected and error cases. ## Troubleshooting @@ -232,25 +243,25 @@ uv run pytest -n 4 # Use 4 CPU cores If tests aren't being discovered: 1. Check that test files start with `test_` -1. Check that test functions start with `test_` -1. Check that test classes start with `Test` -1. Check the `testpaths` configuration +2. Check that test functions start with `test_` +3. Check that test classes start with `Test` +4. Check the `testpaths` configuration #### Fixture Errors If you're having issues with fixtures: 1. Check fixture scope (function, class, module, session) -1. Check for circular dependencies between fixtures -1. Ensure fixtures are accessible to the tests that need them +2. Check for circular dependencies between fixtures +3. Ensure fixtures are accessible to the tests that need them #### Coverage Issues If you're having issues with coverage: 1. Check that the source paths are correct -1. Ensure you're not excluding relevant files -1. Check for `.coveragerc` or configuration in `pyproject.toml` +2. Ensure you're not excluding relevant files +3. Check for `.coveragerc` or configuration in `pyproject.toml` ## Resources diff --git a/docs/technologies/version-control/git.md b/docs/technologies/version-control/git.md index 3438307..d720fdf 100644 --- a/docs/technologies/version-control/git.md +++ b/docs/technologies/version-control/git.md @@ -40,11 +40,11 @@ git --version In this project, Git is used to: 1. Track changes to source code and documentation -1. Manage feature development through branches -1. Facilitate code reviews through pull requests -1. Integrate with pre-commit hooks for quality control -1. Support the CI/CD pipeline -1. Maintain a complete history of project development +2. Manage feature development through branches +3. Facilitate code reviews through pull requests +4. Integrate with pre-commit hooks for quality control +5. Support the CI/CD pipeline +6. Maintain a complete history of project development ## Configuration in This Project @@ -159,37 +159,37 @@ git commit -m "feat: add new feature" This project follows a feature branch workflow: 1. **Main Branch**: The `main` branch contains stable, production-ready code -1. **Feature Branches**: New features are developed in dedicated branches -1. **Pull Requests**: Changes are reviewed through pull requests -1. **Merge Strategy**: Feature branches are merged into `main` after review -1. **Commit Messages**: Follows the Conventional Commits specification +2. **Feature Branches**: New features are developed in dedicated branches +3. **Pull Requests**: Changes are reviewed through pull requests +4. **Merge Strategy**: Feature branches are merged into `main` after review +5. **Commit Messages**: Follows the Conventional Commits specification ## Best Practices 1. **Write meaningful commit messages**: Follow the [Conventional Commits](https://www.conventionalcommits.org/) specification. -1. **Keep commits focused**: Each commit should represent a single logical change. -1. **Pull before pushing**: Always pull the latest changes before pushing to avoid conflicts. -1. **Use branches for features**: Develop new features in dedicated branches. -1. **Review code before merging**: Use pull requests for code review. -1. **Don't commit sensitive information**: Keep secrets, credentials, and personal data out of the repository. -1. **Use .gitignore**: Properly configure `.gitignore` to exclude unnecessary files. +2. **Keep commits focused**: Each commit should represent a single logical change. +3. **Pull before pushing**: Always pull the latest changes before pushing to avoid conflicts. +4. **Use branches for features**: Develop new features in dedicated branches. +5. **Review code before merging**: Use pull requests for code review. +6. **Don't commit sensitive information**: Keep secrets, credentials, and personal data out of the repository. +7. **Use .gitignore**: Properly configure `.gitignore` to exclude unnecessary files. ## Common Git Patterns ### Feature Branch Workflow 1. Create a feature branch from `main` -1. Develop the feature in the branch -1. Create a pull request for review -1. Merge the feature branch into `main` after approval +2. Develop the feature in the branch +3. Create a pull request for review +4. Merge the feature branch into `main` after approval ### Gitflow Workflow 1. `main` branch for production releases -1. `develop` branch for development -1. Feature branches for new features -1. Release branches for preparing releases -1. Hotfix branches for urgent fixes +2. `develop` branch for development +3. Feature branches for new features +4. Release branches for preparing releases +5. Hotfix branches for urgent fixes ## Resources diff --git a/docs/technologies/version-control/pre-commit.md b/docs/technologies/version-control/pre-commit.md index e124a04..e445110 100644 --- a/docs/technologies/version-control/pre-commit.md +++ b/docs/technologies/version-control/pre-commit.md @@ -40,10 +40,10 @@ uv run pre-commit install In this project, Pre-commit is used to: 1. Run code quality checks before each commit -1. Enforce consistent code style and formatting -1. Catch common issues early in the development process -1. Ensure documentation is properly formatted -1. Run security checks on the codebase +2. Enforce consistent code style and formatting +3. Catch common issues early in the development process +4. Ensure documentation is properly formatted +5. Run security checks on the codebase ## Configuration in This Project @@ -126,35 +126,35 @@ src/module.py:25:5: E501 Line too long (88 > 79 characters) Pre-commit supports different types of hooks: 1. **pre-commit**: Runs before committing -1. **pre-push**: Runs before pushing -1. **pre-merge-commit**: Runs before merge commits -1. **pre-rebase**: Runs before rebasing -1. **commit-msg**: Runs to validate commit messages -1. **prepare-commit-msg**: Runs to prepare commit messages +2. **pre-push**: Runs before pushing +3. **pre-merge-commit**: Runs before merge commits +4. **pre-rebase**: Runs before rebasing +5. **commit-msg**: Runs to validate commit messages +6. **prepare-commit-msg**: Runs to prepare commit messages ## Best Practices 1. **Run hooks on all files periodically**: Use `pre-commit run --all-files` to check the entire codebase. -1. **Keep hooks fast**: Ensure hooks run quickly to avoid disrupting the development workflow. -1. **Use auto-fixing hooks**: Prefer hooks that can automatically fix issues when possible. -1. **Update hooks regularly**: Keep hook versions updated to benefit from improvements and bug fixes. -1. **Include pre-commit in CI**: Run pre-commit in CI to ensure all contributors follow the same standards. -1. **Document custom hooks**: If you add custom hooks, document their purpose and requirements. -1. **Use local hooks for project-specific checks**: Add local hooks for checks specific to your project. +2. **Keep hooks fast**: Ensure hooks run quickly to avoid disrupting the development workflow. +3. **Use auto-fixing hooks**: Prefer hooks that can automatically fix issues when possible. +4. **Update hooks regularly**: Keep hook versions updated to benefit from improvements and bug fixes. +5. **Include pre-commit in CI**: Run pre-commit in CI to ensure all contributors follow the same standards. +6. **Document custom hooks**: If you add custom hooks, document their purpose and requirements. +7. **Use local hooks for project-specific checks**: Add local hooks for checks specific to your project. ## Common Hooks -| Hook | Purpose | -|------|---------| -| `ruff` | Python linter and formatter | -| `mypy` | Static type checking | -| `black` | Python code formatter | -| `isort` | Import sorter | -| `flake8` | Python style guide enforcement | -| `bandit` | Security linter | -| `prettier` | Multi-language formatter | -| `markdownlint` | Markdown linter | -| `shellcheck` | Shell script linter | +| Hook | Purpose | +| -------------- | ------------------------------ | +| `ruff` | Python linter and formatter | +| `mypy` | Static type checking | +| `black` | Python code formatter | +| `isort` | Import sorter | +| `flake8` | Python style guide enforcement | +| `bandit` | Security linter | +| `prettier` | Multi-language formatter | +| `markdownlint` | Markdown linter | +| `shellcheck` | Shell script linter | ## Troubleshooting diff --git a/pyproject.toml b/pyproject.toml index 2f1d405..ed7aaaf 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -31,6 +31,10 @@ package = true [dependency-groups] dev = [ "mdformat>=0.7.22", + "mdformat-config>=0.1.3", + "mdformat-web>=0.1.1", + "mdformat-tables>=0.4.1", + "mdformat-frontmatter>=0.4.1", "codespell>=2.4.1", "flynt>=1.0.2", "mkdocs>=1.6.1", @@ -56,11 +60,14 @@ dev = [ "pytest-xdist>=3.6.1", "shellcheck-py>=0.10.0.1", "logging>=0.4.9.6", + "mdformat-mkdocs>=4.1.2", + "mdformat-gfm>=0.4.1", ] [tool.poe.tasks] flynt = "flynt --aggressive --fail-on-change --quiet src tests" lint = {sequence = ["pyupgrade", "flynt", "pyright", "ruff-check", "ruff-format"]} +mdformat = {cmd = "mdformat --number docs"} mkdocs = {cmd = "mkdocs build --strict"} mkdocs-serve = {cmd = "mkdocs serve"} mkinit = {sequence = ["mkinit-src", "mkinit-tests"]} @@ -198,4 +205,4 @@ omit = ["src/utils/logging.py", "src/utils/settings.py", "*/__init__.py"] [tool.coverage.report] exclude_also = [ "def __repr__", -] \ No newline at end of file +] diff --git a/uv.lock b/uv.lock index ac80700..d41531b 100644 --- a/uv.lock +++ b/uv.lock @@ -79,6 +79,19 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/88/85/db74b9233e0aa27ec96891045c5e920a64dd5cbccd50f8e64e9460f48d35/bandit-1.8.3-py3-none-any.whl", hash = "sha256:28f04dc0d258e1dd0f99dee8eefa13d1cb5e3fde1a5ab0c523971f97b289bcd8", size = 129078 }, ] +[[package]] +name = "beautifulsoup4" +version = "4.13.3" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "soupsieve" }, + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/f0/3c/adaf39ce1fb4afdd21b611e3d530b183bb7759c9b673d60db0e347fd4439/beautifulsoup4-4.13.3.tar.gz", hash = "sha256:1bd32405dacc920b42b83ba01644747ed77456a65760e285fbc47633ceddaf8b", size = 619516 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/f9/49/6abb616eb3cbab6a7cca303dc02fdf3836de2e0b834bf966a7f5271a34d8/beautifulsoup4-4.13.3-py3-none-any.whl", hash = "sha256:99045d7d3f08f91f0d656bc9b7efbae189426cd913d830294a15eefa0ea4df16", size = 186015 }, +] + [[package]] name = "bracex" version = "2.5.post1" @@ -259,6 +272,20 @@ toml = [ { name = "tomli", marker = "python_full_version <= '3.11'" }, ] +[[package]] +name = "cssbeautifier" +version = "1.15.4" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "editorconfig" }, + { name = "jsbeautifier" }, + { name = "six" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/f7/01/fdf41c1e5f93d359681976ba10410a04b299d248e28ecce1d4e88588dde4/cssbeautifier-1.15.4.tar.gz", hash = "sha256:9bb08dc3f64c101a01677f128acf01905914cf406baf87434dcde05b74c0acf5", size = 25376 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/63/51/ef6c5628e46092f0a54c7cee69acc827adc6b6aab57b55d344fefbdf28f1/cssbeautifier-1.15.4-py3-none-any.whl", hash = "sha256:78c84d5e5378df7d08622bbd0477a1abdbd209680e95480bf22f12d5701efc98", size = 123667 }, +] + [[package]] name = "darglint" version = "1.8.1" @@ -286,6 +313,15 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/91/a1/cf2472db20f7ce4a6be1253a81cfdf85ad9c7885ffbed7047fb72c24cf87/distlib-0.3.9-py2.py3-none-any.whl", hash = "sha256:47f8c22fd27c27e25a65601af709b38e4f0a45ea4fc2e710f65755fa8caaaf87", size = 468973 }, ] +[[package]] +name = "editorconfig" +version = "0.17.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/b4/29/785595a0d8b30ab8d2486559cfba1d46487b8dcbd99f74960b6b4cca92a4/editorconfig-0.17.0.tar.gz", hash = "sha256:8739052279699840065d3a9f5c125d7d5a98daeefe53b0e5274261d77cb49aa2", size = 13369 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/af/e5/8dba39ea24ca3de0e954e668107692f4dfc13a85300a531fa9a39e83fde4/EditorConfig-0.17.0-py3-none-any.whl", hash = "sha256:fe491719c5f65959ec00b167d07740e7ffec9a3f362038c72b289330b9991dfc", size = 16276 }, +] + [[package]] name = "execnet" version = "2.1.1" @@ -409,6 +445,19 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/62/a1/3d680cbfd5f4b8f15abc1d571870c5fc3e594bb582bc3b64ea099db13e56/jinja2-3.1.6-py3-none-any.whl", hash = "sha256:85ece4451f492d0c13c5dd7c13a64681a86afae63a5f347908daf103ce6d2f67", size = 134899 }, ] +[[package]] +name = "jsbeautifier" +version = "1.15.4" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "editorconfig" }, + { name = "six" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/ea/98/d6cadf4d5a1c03b2136837a435682418c29fdeb66be137128544cecc5b7a/jsbeautifier-1.15.4.tar.gz", hash = "sha256:5bb18d9efb9331d825735fbc5360ee8f1aac5e52780042803943aa7f854f7592", size = 75257 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/2d/14/1c65fccf8413d5f5c6e8425f84675169654395098000d8bddc4e9d3390e1/jsbeautifier-1.15.4-py3-none-any.whl", hash = "sha256:72f65de312a3f10900d7685557f84cb61a9733c50dcc27271a39f5b0051bf528", size = 94707 }, +] + [[package]] name = "lazy-loader" version = "0.4" @@ -529,6 +578,104 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/f2/6f/94a7344f6d634fe3563bea8b33bccedee37f2726f7807e9a58440dc91627/mdformat-0.7.22-py3-none-any.whl", hash = "sha256:61122637c9e1d9be1329054f3fa216559f0d1f722b7919b060a8c2a4ae1850e5", size = 34447 }, ] +[[package]] +name = "mdformat-config" +version = "0.2.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "mdformat" }, + { name = "ruamel-yaml" }, + { name = "taplo" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/ed/c0/49baad1d5121b1b7f30b5166f668d70d2a16ce5d2c267ebe7f210f575b59/mdformat_config-0.2.1.tar.gz", hash = "sha256:753aa1179198c791e4791099a0e9b1684a649fbbcd52db7c4d2e911a4c2c69ae", size = 2829 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/4e/73/e989491953da2cb446253258d0f3694ea021c277ca0cfbefe0a79ca5eef1/mdformat_config-0.2.1-py3-none-any.whl", hash = "sha256:484a867c067366f85c9e4b91e36d8a92c80141490db59e481befe0ec8055f02d", size = 3473 }, +] + +[[package]] +name = "mdformat-frontmatter" +version = "2.0.8" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "mdformat" }, + { name = "mdit-py-plugins" }, + { name = "ruamel-yaml" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/71/aa/70876bec1e66f2b1ab26f31d226c09bf7b78d3d27f03c2642d1d69d1ae77/mdformat_frontmatter-2.0.8.tar.gz", hash = "sha256:c11190ae3f9c91ada78fbd820f5b221631b520484e0b644715aa0f6ed7f097ed", size = 3254 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/5d/51/b3da1292c32819c52a4e4242ad94c3c07189ca70d228b3909a58f1f3a819/mdformat_frontmatter-2.0.8-py3-none-any.whl", hash = "sha256:577396695af96ad66dff1ff781284ff3764a10be3ab8659f2ef842ab42264ebb", size = 3747 }, +] + +[[package]] +name = "mdformat-gfm" +version = "0.4.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "markdown-it-py" }, + { name = "mdformat" }, + { name = "mdformat-tables" }, + { name = "mdit-py-plugins" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/e5/db/873bad63b36e390a33bc0cf7222442010997d3ccf29a1889f24d28fdeddd/mdformat_gfm-0.4.1.tar.gz", hash = "sha256:e189e728e50cfb15746abc6b3178ca0e2bebbb7a8d3d98fbc9e24bc1a4c65564", size = 7528 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/09/ba/3d4c680a2582593b8ba568ab60b119d93542fa39d757d65aae3c4f357e29/mdformat_gfm-0.4.1-py3-none-any.whl", hash = "sha256:63c92cfa5102f55779d4e04b16a79a6a5171e658c6c479175c0955fb4ca78dde", size = 8750 }, +] + +[[package]] +name = "mdformat-mkdocs" +version = "4.1.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "mdformat" }, + { name = "mdformat-gfm" }, + { name = "mdit-py-plugins" }, + { name = "more-itertools" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/de/9a/9c855818820345c814d008f118e4dd35a7159a84bc74f78dbd8be62a5fd0/mdformat_mkdocs-4.1.2.tar.gz", hash = "sha256:85017aa4cd6bcff68ca1c11a232bceef33fa7bfa181996f9c5004876af960de6", size = 26422 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/62/30/bad67c7b47b3806b415fcc9fba607e6d369706e931afdfa3815cdfff7586/mdformat_mkdocs-4.1.2-py3-none-any.whl", hash = "sha256:330774b40d27dc34ac56d216617968a7889de6adfb8641c510fb11d43ca257cf", size = 28608 }, +] + +[[package]] +name = "mdformat-tables" +version = "1.0.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "mdformat" }, + { name = "wcwidth" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/64/fc/995ba209096bdebdeb8893d507c7b32b7e07d9a9f2cdc2ec07529947794b/mdformat_tables-1.0.0.tar.gz", hash = "sha256:a57db1ac17c4a125da794ef45539904bb8a9592e80557d525e1f169c96daa2c8", size = 6106 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/2a/37/d78e37d14323da3f607cd1af7daf262cb87fe614a245c15ad03bb03a2706/mdformat_tables-1.0.0-py3-none-any.whl", hash = "sha256:94cd86126141b2adc3b04c08d1441eb1272b36c39146bab078249a41c7240a9a", size = 5104 }, +] + +[[package]] +name = "mdformat-web" +version = "0.2.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "beautifulsoup4" }, + { name = "cssbeautifier" }, + { name = "jsbeautifier" }, + { name = "mdformat" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/ab/94/848d6f3db16cce2115921130e50bd0569afd63559abf6bb09e29992c1a26/mdformat_web-0.2.0.tar.gz", hash = "sha256:7bf3b76ce01c3af1e6706ffe430e2b5c173248934191053477813b9119b01b64", size = 2751 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/f7/68/575b4d9c8dbab694a0ba8e8a4a348e263e774bac4a9ceb250642bad15e2b/mdformat_web-0.2.0-py3-none-any.whl", hash = "sha256:5d896564acfbe6ad8715a97ef6cac49b44ae6a9f3521c97bcf882d0b0e2ff5e7", size = 3150 }, +] + +[[package]] +name = "mdit-py-plugins" +version = "0.4.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "markdown-it-py" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/19/03/a2ecab526543b152300717cf232bb4bb8605b6edb946c845016fa9c9c9fd/mdit_py_plugins-0.4.2.tar.gz", hash = "sha256:5f2cd1fdb606ddf152d37ec30e46101a60512bc0e5fa1a7002c36647b09e26b5", size = 43542 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/a7/f7/7782a043553ee469c1ff49cfa1cdace2d6bf99a1f333cf38676b3ddf30da/mdit_py_plugins-0.4.2-py3-none-any.whl", hash = "sha256:0c673c3f889399a33b95e88d2f0d111b4447bdfea7f237dab2d488f459835636", size = 55316 }, +] + [[package]] name = "mdurl" version = "0.1.2" @@ -686,6 +833,15 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/b2/3b/4e5fabaa924292216f23f095009f9e091b49018e18d653eedab2dd25885c/mkinit-1.1.0-py3-none-any.whl", hash = "sha256:b49dca93956c1e3ba2ae84fa31238745cf1d1aaa47ab53aeda5e22d375a3732a", size = 63103 }, ] +[[package]] +name = "more-itertools" +version = "10.6.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/88/3b/7fa1fe835e2e93fd6d7b52b2f95ae810cf5ba133e1845f726f5a992d62c2/more-itertools-10.6.0.tar.gz", hash = "sha256:2cd7fad1009c31cc9fb6a035108509e6547547a7a738374f10bd49a09eb3ee3b", size = 125009 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/23/62/0fe302c6d1be1c777cab0616e6302478251dfbf9055ad426f5d0def75c89/more_itertools-10.6.0-py3-none-any.whl", hash = "sha256:6eb054cb4b6db1473f6e15fcc676a08e4732548acd47c708f0e179c2c7c01e89", size = 63038 }, +] + [[package]] name = "nodeenv" version = "1.9.1" @@ -1031,6 +1187,12 @@ dev = [ { name = "interrogate" }, { name = "logging" }, { name = "mdformat" }, + { name = "mdformat-config" }, + { name = "mdformat-frontmatter" }, + { name = "mdformat-gfm" }, + { name = "mdformat-mkdocs" }, + { name = "mdformat-tables" }, + { name = "mdformat-web" }, { name = "mkdocs" }, { name = "mkdocs-include-markdown-plugin" }, { name = "mkdocs-material" }, @@ -1067,6 +1229,12 @@ dev = [ { name = "interrogate", specifier = ">=1.5.0" }, { name = "logging", specifier = ">=0.4.9.6" }, { name = "mdformat", specifier = ">=0.7.22" }, + { name = "mdformat-config", specifier = ">=0.1.3" }, + { name = "mdformat-frontmatter", specifier = ">=0.4.1" }, + { name = "mdformat-gfm", specifier = ">=0.4.1" }, + { name = "mdformat-mkdocs", specifier = ">=4.1.2" }, + { name = "mdformat-tables", specifier = ">=0.4.1" }, + { name = "mdformat-web", specifier = ">=0.1.1" }, { name = "mkdocs", specifier = ">=1.6.1" }, { name = "mkdocs-include-markdown-plugin", specifier = ">=7.1.5" }, { name = "mkdocs-material", specifier = ">=9.6.8" }, @@ -1199,6 +1367,53 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/19/71/39c7c0d87f8d4e6c020a393182060eaefeeae6c01dab6a84ec346f2567df/rich-13.9.4-py3-none-any.whl", hash = "sha256:6049d5e6ec054bf2779ab3358186963bac2ea89175919d699e378b99738c2a90", size = 242424 }, ] +[[package]] +name = "ruamel-yaml" +version = "0.18.10" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "ruamel-yaml-clib", marker = "python_full_version < '3.13' and platform_python_implementation == 'CPython'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/ea/46/f44d8be06b85bc7c4d8c95d658be2b68f27711f279bf9dd0612a5e4794f5/ruamel.yaml-0.18.10.tar.gz", hash = "sha256:20c86ab29ac2153f80a428e1254a8adf686d3383df04490514ca3b79a362db58", size = 143447 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/c2/36/dfc1ebc0081e6d39924a2cc53654497f967a084a436bb64402dfce4254d9/ruamel.yaml-0.18.10-py3-none-any.whl", hash = "sha256:30f22513ab2301b3d2b577adc121c6471f28734d3d9728581245f1e76468b4f1", size = 117729 }, +] + +[[package]] +name = "ruamel-yaml-clib" +version = "0.2.12" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/20/84/80203abff8ea4993a87d823a5f632e4d92831ef75d404c9fc78d0176d2b5/ruamel.yaml.clib-0.2.12.tar.gz", hash = "sha256:6c8fbb13ec503f99a91901ab46e0b07ae7941cd527393187039aec586fdfd36f", size = 225315 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/fb/8f/683c6ad562f558cbc4f7c029abcd9599148c51c54b5ef0f24f2638da9fbb/ruamel.yaml.clib-0.2.12-cp311-cp311-macosx_13_0_arm64.whl", hash = "sha256:4a6679521a58256a90b0d89e03992c15144c5f3858f40d7c18886023d7943db6", size = 132224 }, + { url = "https://files.pythonhosted.org/packages/3c/d2/b79b7d695e2f21da020bd44c782490578f300dd44f0a4c57a92575758a76/ruamel.yaml.clib-0.2.12-cp311-cp311-manylinux2014_aarch64.whl", hash = "sha256:d84318609196d6bd6da0edfa25cedfbabd8dbde5140a0a23af29ad4b8f91fb1e", size = 641480 }, + { url = "https://files.pythonhosted.org/packages/68/6e/264c50ce2a31473a9fdbf4fa66ca9b2b17c7455b31ef585462343818bd6c/ruamel.yaml.clib-0.2.12-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bb43a269eb827806502c7c8efb7ae7e9e9d0573257a46e8e952f4d4caba4f31e", size = 739068 }, + { url = "https://files.pythonhosted.org/packages/86/29/88c2567bc893c84d88b4c48027367c3562ae69121d568e8a3f3a8d363f4d/ruamel.yaml.clib-0.2.12-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:811ea1594b8a0fb466172c384267a4e5e367298af6b228931f273b111f17ef52", size = 703012 }, + { url = "https://files.pythonhosted.org/packages/11/46/879763c619b5470820f0cd6ca97d134771e502776bc2b844d2adb6e37753/ruamel.yaml.clib-0.2.12-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:cf12567a7b565cbf65d438dec6cfbe2917d3c1bdddfce84a9930b7d35ea59642", size = 704352 }, + { url = "https://files.pythonhosted.org/packages/02/80/ece7e6034256a4186bbe50dee28cd032d816974941a6abf6a9d65e4228a7/ruamel.yaml.clib-0.2.12-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:7dd5adc8b930b12c8fc5b99e2d535a09889941aa0d0bd06f4749e9a9397c71d2", size = 737344 }, + { url = "https://files.pythonhosted.org/packages/f0/ca/e4106ac7e80efbabdf4bf91d3d32fc424e41418458251712f5672eada9ce/ruamel.yaml.clib-0.2.12-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:1492a6051dab8d912fc2adeef0e8c72216b24d57bd896ea607cb90bb0c4981d3", size = 714498 }, + { url = "https://files.pythonhosted.org/packages/67/58/b1f60a1d591b771298ffa0428237afb092c7f29ae23bad93420b1eb10703/ruamel.yaml.clib-0.2.12-cp311-cp311-win32.whl", hash = "sha256:bd0a08f0bab19093c54e18a14a10b4322e1eacc5217056f3c063bd2f59853ce4", size = 100205 }, + { url = "https://files.pythonhosted.org/packages/b4/4f/b52f634c9548a9291a70dfce26ca7ebce388235c93588a1068028ea23fcc/ruamel.yaml.clib-0.2.12-cp311-cp311-win_amd64.whl", hash = "sha256:a274fb2cb086c7a3dea4322ec27f4cb5cc4b6298adb583ab0e211a4682f241eb", size = 118185 }, + { url = "https://files.pythonhosted.org/packages/48/41/e7a405afbdc26af961678474a55373e1b323605a4f5e2ddd4a80ea80f628/ruamel.yaml.clib-0.2.12-cp312-cp312-macosx_14_0_arm64.whl", hash = "sha256:20b0f8dc160ba83b6dcc0e256846e1a02d044e13f7ea74a3d1d56ede4e48c632", size = 133433 }, + { url = "https://files.pythonhosted.org/packages/ec/b0/b850385604334c2ce90e3ee1013bd911aedf058a934905863a6ea95e9eb4/ruamel.yaml.clib-0.2.12-cp312-cp312-manylinux2014_aarch64.whl", hash = "sha256:943f32bc9dedb3abff9879edc134901df92cfce2c3d5c9348f172f62eb2d771d", size = 647362 }, + { url = "https://files.pythonhosted.org/packages/44/d0/3f68a86e006448fb6c005aee66565b9eb89014a70c491d70c08de597f8e4/ruamel.yaml.clib-0.2.12-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:95c3829bb364fdb8e0332c9931ecf57d9be3519241323c5274bd82f709cebc0c", size = 754118 }, + { url = "https://files.pythonhosted.org/packages/52/a9/d39f3c5ada0a3bb2870d7db41901125dbe2434fa4f12ca8c5b83a42d7c53/ruamel.yaml.clib-0.2.12-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:749c16fcc4a2b09f28843cda5a193e0283e47454b63ec4b81eaa2242f50e4ccd", size = 706497 }, + { url = "https://files.pythonhosted.org/packages/b0/fa/097e38135dadd9ac25aecf2a54be17ddf6e4c23e43d538492a90ab3d71c6/ruamel.yaml.clib-0.2.12-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:bf165fef1f223beae7333275156ab2022cffe255dcc51c27f066b4370da81e31", size = 698042 }, + { url = "https://files.pythonhosted.org/packages/ec/d5/a659ca6f503b9379b930f13bc6b130c9f176469b73b9834296822a83a132/ruamel.yaml.clib-0.2.12-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:32621c177bbf782ca5a18ba4d7af0f1082a3f6e517ac2a18b3974d4edf349680", size = 745831 }, + { url = "https://files.pythonhosted.org/packages/db/5d/36619b61ffa2429eeaefaab4f3374666adf36ad8ac6330d855848d7d36fd/ruamel.yaml.clib-0.2.12-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:b82a7c94a498853aa0b272fd5bc67f29008da798d4f93a2f9f289feb8426a58d", size = 715692 }, + { url = "https://files.pythonhosted.org/packages/b1/82/85cb92f15a4231c89b95dfe08b09eb6adca929ef7df7e17ab59902b6f589/ruamel.yaml.clib-0.2.12-cp312-cp312-win32.whl", hash = "sha256:e8c4ebfcfd57177b572e2040777b8abc537cdef58a2120e830124946aa9b42c5", size = 98777 }, + { url = "https://files.pythonhosted.org/packages/d7/8f/c3654f6f1ddb75daf3922c3d8fc6005b1ab56671ad56ffb874d908bfa668/ruamel.yaml.clib-0.2.12-cp312-cp312-win_amd64.whl", hash = "sha256:0467c5965282c62203273b838ae77c0d29d7638c8a4e3a1c8bdd3602c10904e4", size = 115523 }, + { url = "https://files.pythonhosted.org/packages/29/00/4864119668d71a5fa45678f380b5923ff410701565821925c69780356ffa/ruamel.yaml.clib-0.2.12-cp313-cp313-macosx_14_0_arm64.whl", hash = "sha256:4c8c5d82f50bb53986a5e02d1b3092b03622c02c2eb78e29bec33fd9593bae1a", size = 132011 }, + { url = "https://files.pythonhosted.org/packages/7f/5e/212f473a93ae78c669ffa0cb051e3fee1139cb2d385d2ae1653d64281507/ruamel.yaml.clib-0.2.12-cp313-cp313-manylinux2014_aarch64.whl", hash = "sha256:e7e3736715fbf53e9be2a79eb4db68e4ed857017344d697e8b9749444ae57475", size = 642488 }, + { url = "https://files.pythonhosted.org/packages/1f/8f/ecfbe2123ade605c49ef769788f79c38ddb1c8fa81e01f4dbf5cf1a44b16/ruamel.yaml.clib-0.2.12-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0b7e75b4965e1d4690e93021adfcecccbca7d61c7bddd8e22406ef2ff20d74ef", size = 745066 }, + { url = "https://files.pythonhosted.org/packages/e2/a9/28f60726d29dfc01b8decdb385de4ced2ced9faeb37a847bd5cf26836815/ruamel.yaml.clib-0.2.12-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:96777d473c05ee3e5e3c3e999f5d23c6f4ec5b0c38c098b3a5229085f74236c6", size = 701785 }, + { url = "https://files.pythonhosted.org/packages/84/7e/8e7ec45920daa7f76046578e4f677a3215fe8f18ee30a9cb7627a19d9b4c/ruamel.yaml.clib-0.2.12-cp313-cp313-musllinux_1_1_i686.whl", hash = "sha256:3bc2a80e6420ca8b7d3590791e2dfc709c88ab9152c00eeb511c9875ce5778bf", size = 693017 }, + { url = "https://files.pythonhosted.org/packages/c5/b3/d650eaade4ca225f02a648321e1ab835b9d361c60d51150bac49063b83fa/ruamel.yaml.clib-0.2.12-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:e188d2699864c11c36cdfdada94d781fd5d6b0071cd9c427bceb08ad3d7c70e1", size = 741270 }, + { url = "https://files.pythonhosted.org/packages/87/b8/01c29b924dcbbed75cc45b30c30d565d763b9c4d540545a0eeecffb8f09c/ruamel.yaml.clib-0.2.12-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:4f6f3eac23941b32afccc23081e1f50612bdbe4e982012ef4f5797986828cd01", size = 709059 }, + { url = "https://files.pythonhosted.org/packages/30/8c/ed73f047a73638257aa9377ad356bea4d96125b305c34a28766f4445cc0f/ruamel.yaml.clib-0.2.12-cp313-cp313-win32.whl", hash = "sha256:6442cb36270b3afb1b4951f060eccca1ce49f3d087ca1ca4563a6eb479cb3de6", size = 98583 }, + { url = "https://files.pythonhosted.org/packages/b0/85/e8e751d8791564dd333d5d9a4eab0a7a115f7e349595417fd50ecae3395c/ruamel.yaml.clib-0.2.12-cp313-cp313-win_amd64.whl", hash = "sha256:e5b8daf27af0b90da7bb903a876477a9e6d7270be6146906b276605997c7e9a3", size = 115190 }, +] + [[package]] name = "ruff" version = "0.11.0" @@ -1254,6 +1469,15 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl", hash = "sha256:4721f391ed90541fddacab5acf947aa0d3dc7d27b2e1e8eda2be8970586c3274", size = 11050 }, ] +[[package]] +name = "soupsieve" +version = "2.6" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/d7/ce/fbaeed4f9fb8b2daa961f90591662df6a86c1abf25c548329a86920aedfb/soupsieve-2.6.tar.gz", hash = "sha256:e2e68417777af359ec65daac1057404a3c8a5455bb8abc36f1a9866ab1a51abb", size = 101569 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/d1/c2/fe97d779f3ef3b15f05c94a2f1e3d21732574ed441687474db9d342a7315/soupsieve-2.6-py3-none-any.whl", hash = "sha256:e72c4ff06e4fb6e4b5a9f0f55fe6e81514581fca1515028625d0f299c602ccc9", size = 36186 }, +] + [[package]] name = "stevedore" version = "5.4.1" @@ -1275,6 +1499,20 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/40/44/4a5f08c96eb108af5cb50b41f76142f0afa346dfa99d5296fe7202a11854/tabulate-0.9.0-py3-none-any.whl", hash = "sha256:024ca478df22e9340661486f85298cff5f6dcdba14f3813e8830015b9ed1948f", size = 35252 }, ] +[[package]] +name = "taplo" +version = "0.9.3" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/71/79/513513960377e1212a28446acb323cf77dfce162e825a822f035b02a422d/taplo-0.9.3.tar.gz", hash = "sha256:6b73b45b9adbd20189d8981ac9055d5465227c58bbe1b0646a7588a1a5c07a1a", size = 102556 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/61/42/a93c18ebb7cf3ee2a7a30dd2fda654aca458956c3b64bdfb9d82b2c42679/taplo-0.9.3-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:1c3db689406d538420c64aa779ac8694cf44c13a46e158d6df406de65980b9c7", size = 4248497 }, + { url = "https://files.pythonhosted.org/packages/82/d2/f5b6e4a4f474f9fe613b5b91012520c3f62e46748a6ce9fd61fc2fb52fa2/taplo-0.9.3-py3-none-macosx_11_0_arm64.whl", hash = "sha256:1e7782f33f97e7aa658d18788748bce5cf3ce440eeb419cf5861cf542740e610", size = 4044421 }, + { url = "https://files.pythonhosted.org/packages/7d/32/4ac46ff15bb9d060f50ad31fb3a80aa8ee1e6ca500104ca8569f6fbdee3d/taplo-0.9.3-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:29d4d7abfcc10bd536e5a43fe6ec2c1931507c1433e79df03ea22e1030611cb6", size = 4334420 }, + { url = "https://files.pythonhosted.org/packages/ef/cc/656aed22a59cf4c50dcaaa66aaa570d4a1412acdd8ea429120a6bb00f336/taplo-0.9.3-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:33f12648f273478d7330cb3529c82f48f388501e1122e0bea78bce5ff5972b8b", size = 4468935 }, + { url = "https://files.pythonhosted.org/packages/21/15/d8db1db6382b444122fa1a66fe5fe0dd5b04bfbe68c74bdb5345aec11eb2/taplo-0.9.3-py3-none-win32.whl", hash = "sha256:9ab7df76a3facc6d0dd2fe2dae3e8eb52fa458d31d27878d5eac14f5cbc0abac", size = 3482612 }, + { url = "https://files.pythonhosted.org/packages/42/3c/df6641d7e2e84a6dd4de3b3a4426db7f6a7270c05bbdeadd523645c9c45f/taplo-0.9.3-py3-none-win_amd64.whl", hash = "sha256:7d80b630b93fb43cee99d1e1ee07b616236dc5615efaf7cd51074b4cffc33bab", size = 3985843 }, +] + [[package]] name = "termcolor" version = "2.5.0"