Tool and Library Registry
Comprehensive catalog of development tools, testing frameworks, CLI libraries, data processing utilities, and MCP tools for modern Python 3.11+ development.
Coverage: 50+ tools across 10 categories Sources: Pattern extraction analysis, taxonomy organization, 13 agent discovery reports User Requirements: datasette, arrow, fabric, shiv, httpx, prefect, boltons, blinker, paho-mqtt, robotframework, copier, pytest, prospector, pre-commit, mypy, bandit, ruff, uv, hatchling
1. Tool Categories Overview
Category Matrix
| Category | Tool Count | Mandatory Tools | Optional Tools | Use Cases |
|---|---|---|---|---|
| Development Tools | 8 | uv, ruff, mypy, pyright | prospector, bandit | Package management, linting, type checking |
| Testing Tools | 9 | pytest, pytest-mock, pytest-cov | hypothesis, mutmut, robotframework | Unit tests, BDD, mutation testing |
| CLI Frameworks | 4 | typer, argparse | textual, click | Human-facing CLIs, portable scripts, TUIs |
| Data Libraries | 5 | - | datasette, arrow, httpx, requests | Data exploration, time handling, HTTP clients |
| Workflow Tools | 4 | - | prefect, fabric, copier, invoke | Orchestration, automation, templating |
| IoT/Messaging | 2 | - | paho-mqtt, blinker | MQTT messaging, signals/events |
| Build Tools | 4 | uv | hatchling, shiv, pip-tools | Package building, executable creation |
| Quality Tools | 4 | pre-commit, ruff | prospector, bandit | Code quality gates, security scanning |
| Utility Libraries | 3 | - | boltons, pydantic, structlog | General utilities, validation, logging |
| MCP Tools | 8 | - | context7, ref, exa, github | Documentation lookup, code search, reasoning |
2. Development Tools
2.1 uv (Package Manager & Script Executor)
tool_name: uv
category: development
python_versions: [3.11, 3.12, 3.13, 3.14]
installation: "curl -LsSf https://astral.sh/uv/install.sh | sh"
purpose: "Modern Python package manager and PEP 723 script executor"
mandatory: true
scenarios:
- All Python development
- PEP 723 script execution
- Package installation
- Virtual environment management
alternatives:
- pip + pip-tools + virtualenv (legacy, NOT recommended)
- poetry (different approach, heavier)
- pdm (alternative modern tool)
When to Use:
- MANDATORY for PEP 723 scripts (shebang requirement)
- Primary package manager for all projects
- Replaces pip, pip-tools, virtualenv, pipx
Basic Usage:
# Install packages
uv add requests pydantic
# Add development dependencies
uv add --dev pytest mypy ruff
# Run PEP 723 script
uv run --script script.py
# Create virtual environment
uv venv
# Sync dependencies from pyproject.toml
uv sync
Integration with Other Tools:
- Works with pyproject.toml for dependency management
- Executes PEP 723 scripts via shebang
- Compatible with pre-commit hooks
- Faster than pip for all operations
Configuration:
# pyproject.toml - Minimal dependency declaration example
# NOTE: Replace ALL {{template_variables}} with actual values before creating file
[project]
name = "{{project_name_from_directory_or_git_remote}}"
version = "{{version_from_git_tag_or_default_0_1_0}}"
dependencies = [
"typer>=0.21.2",
"pydantic>=2.0.0",
]
[project.optional-dependencies]
dev = [
"pytest>=8.0.0",
"mypy>=1.11.0",
"ruff>=0.6.0",
]
[tool.hatchling.build.targets.wheel]
packages = ["packages/{{package_name_from_project_name}}"]
Related Standards:
- PEP 723 (inline script metadata)
- PEP 621 (project metadata)
- Pattern: All Python agents require uv
Source: pattern-extraction.md Section 3.1, all discovery reports
2.2 ruff (Linting & Formatting)
tool_name: ruff
category: development
python_versions: [3.11, 3.12, 3.13, 3.14]
installation: "uv add --dev ruff"
purpose: "Extremely fast Python linter and formatter replacing flake8, black, isort"
mandatory: true
scenarios:
- All Python code validation
- Pre-commit hooks
- CI/CD pipelines
- Linting error investigation
alternatives:
- flake8 + black + isort (legacy, slower)
- pylint (comprehensive but slower)
- prospector (multi-tool wrapper)
When to Use:
- MANDATORY for all Python code before delivery
- Layer 2 of validation pipeline
- Pre-commit hook integration
- CI/CD quality gates
Basic Usage:
# Check code
uv run ruff check .
# Fix auto-fixable issues
uv run ruff check --fix .
# Format code
uv run ruff format .
# Get rule documentation
ruff rule ANN201
# Check specific files (rare - usually run on .)
uv run ruff check path/to/file.py
Integration with Other Tools:
- Pre-commit: Automatic linting on git commits
- Linting-root-cause-resolver: Uses
ruff rule {CODE}for investigation - Mypy/Pyright: Complementary type checking
- pytest: Can check test code
Configuration:
# pyproject.toml
[tool.ruff]
target-version = "py311"
fix = true
unsafe-fixes = true
src = ["packages", "scripts", "tests", "typings", ".gitlab", ".github"]
[tool.ruff.format]
docstring-code-format = true
quote-style = "double"
line-ending = "lf"
skip-magic-trailing-comma = true
preview = true
[tool.ruff.lint]
preview = true
extend-select = [
"A", # see: https://docs.astral.sh/ruff/rules/#flake8-builtins-a
"ANN", # see: https://docs.astral.sh/ruff/rules/#flake8-annotations-ann
"ASYNC", # see: https://docs.astral.sh/ruff/rules/#flake8-async-async
"B", # see: https://docs.astral.sh/ruff/rules/#flake8-bugbear-b
"BLE", # see: https://docs.astral.sh/ruff/rules/#flake8-blind-except-ble
"C4", # see: https://docs.astral.sh/ruff/rules/#flake8-comprehensions-c4
"C90", # see: https://docs.astral.sh/ruff/rules/#mccabe-c90
"D", # see: https://docs.astral.sh/ruff/rules/#pydocstyle-d
"DOC", # see: https://docs.astral.sh/ruff/rules/#pydoclint-doc
"E", # see: https://docs.astral.sh/ruff/rules/#error-e
"EXE", # see: https://docs.astral.sh/ruff/rules/#flake8-executable-exe
"F", # see: https://docs.astral.sh/ruff/rules/#pyflakes-f
"FA", # see: https://docs.astral.sh/ruff/rules/#flake8-annotations-fa
"FAST", # see: https://docs.astral.sh/ruff/rules/#fastapi-fast
"FLY", # see: https://docs.astral.sh/ruff/rules/#flynt-fly
"FURB", # see: https://docs.astral.sh/ruff/rules/#refurb-furb
"G201", # see: https://docs.astral.sh/ruff/rules/logging-exc-info/
"G202", # see: https://docs.astral.sh/ruff/rules/logging-redundant-exc-info/
"I", # see: https://docs.astral.sh/ruff/rules/#isort-i
"N", # see: https://docs.astral.sh/ruff/rules/#flake8-quotes-n
"PERF", # see: https://docs.astral.sh/ruff/rules/#perflint-perf
"PGH", # see: https://docs.astral.sh/ruff/rules/#pygrep-hooks-pgh
"PIE", # see: https://docs.astral.sh/ruff/rules/#flake8-pie-pie
"PL", # see: https://docs.astral.sh/ruff/rules/#pyflakes-f
"PT", # see: https://docs.astral.sh/ruff/rules/#flake8-pytest-style-pt
"PTH", # see: https://docs.astral.sh/ruff/rules/#flake8-use-pathlib-pth
"PYI", # see: https://docs.astral.sh/ruff/rules/#flake8-pyi-pyi
"Q", # see: https://docs.astral.sh/ruff/rules/#flake8-quotes-q
"RET", # see: https://docs.astral.sh/ruff/rules/#flake8-return-ret
"RSE", # see: https://docs.astral.sh/ruff/rules/#flake8-raise-rse
"RUF", # see: https://docs.astral.sh/ruff/rules/#ruff-ruf
"S", # see: https://docs.astral.sh/ruff/rules/#flake8-bandit-s
"SIM", # see: https://docs.astral.sh/ruff/rules/#flake8-simplify-sim
"SLF", # see: https://docs.astral.sh/ruff/rules/#flake8-self-slf
"SLOT", # see: https://docs.astral.sh/ruff/rules/#flake8-slots-slot
"T10", # see: https://docs.astral.sh/ruff/rules/#flake8-debugger-t10
"T20", # see: https://docs.astral.sh/ruff/rules/#flake8-typing-t20
"TC", # see: https://docs.astral.sh/ruff/rules/#flake8-type-checking-tc
"TRY", # see: https://docs.astral.sh/ruff/rules/#tryceratops-try
"UP", # see: https://docs.astral.sh/ruff/rules/#pyupgrade-up
"W", # see: https://docs.astral.sh/ruff/rules/#warning-w
"YTT", # see: https://docs.astral.sh/ruff/rules/#flake8-2020-ytt
]
ignore = [
"DOC501", # Raised exception {id} missing from docstring
"DOC502", # Raised exception is not explicitly raised
"E501", # Line too long ({width} > {limit})
"EXE003", # Shebang should contain python, pytest, or uv run (doesn't handle global arguments)
"S404", # subprocess possibly insecure - still need to use subprocess though
"S603", # subprocess without shell=True
"TRY003", # Long error messages are fine
]
unfixable = ["F401"]
[tool.ruff.lint.per-file-ignores]
"tests/**" = ["S", "D", "E501"]
"typings/**" = ["N", "ANN", "A"]
".gitlab/scripts/**" = [
"T201", # print() statements are intentional for CI output visibility
]
[tool.ruff.lint.pycodestyle]
max-line-length = 120
[tool.ruff.lint.isort]
combine-as-imports = true
split-on-trailing-comma = false
force-single-line = false
force-wrap-aliases = false
[tool.ruff.lint.flake8-quotes]
docstring-quotes = "double"
[tool.ruff.lint.pydocstyle]
convention = "google"
[tool.ruff.lint.mccabe]
max-complexity = 12
Common Patterns:
# REQUIRED: No legacy typing imports
# ruff will flag: from typing import List, Dict, Optional
# REQUIRED: Use native generics
def process(items: list[str]) -> dict[str, int]: # ✓
pass
# FORBIDDEN: Legacy typing
from typing import List, Dict
def process(items: List[str]) -> Dict[str, int]: # ✗
pass
Related Standards:
- NEVER suppress with # noqa comments
- Use linting-root-cause-resolver for root cause fixes
- ANN* rules enforce type annotations
- PYI* rules for stub files
Source: pattern-extraction.md Section 3.1, linting-root-cause-resolver-analysis.md
2.3 mypy (Static Type Checker)
tool_name: mypy
category: development
python_versions: [3.11, 3.12, 3.13, 3.14]
installation: "uv add --dev mypy"
purpose: "Static type checker for Python with strict mode enforcement"
mandatory: true
scenarios:
- All Python code type validation
- Layer 3 of validation pipeline
- CI/CD type safety gates
- Pre-commit hooks
alternatives:
- pyright (Microsoft, also recommended)
- pyre (Facebook, less common)
When to Use:
- MANDATORY for all Python code
- Layer 3 of validation pipeline (after ruff)
- Use
--strictmode exclusively - Run before pyright for additional checks
Basic Usage:
# Check with strict mode
uv run mypy --strict .
# Generate HTML report
uv run mypy --html-report mypy-report .
Integration with Other Tools:
- Ruff: Complementary linting
- Pyright: Run both for comprehensive checking
- pytest: Type-check test code
- Pre-commit: Automatic type checking
Configuration:
# pyproject.toml
[tool.mypy]
python_version = "3.11"
strict = true
extra_checks = true
warn_unused_configs = true
warn_redundant_casts = true
warn_unused_ignores = true
ignore_missing_imports = true
show_error_codes = true
pretty = true
disable_error_code = ["call-arg", "misc"]
mypy_path = ["packages", "scripts", "."]
[[tool.mypy.overrides]]
module = ["test.*", "tests.*"]
disable_error_code = ["attr-defined", "call-arg", "var-annotated"]
Common Patterns:
# REQUIRED: Complete type annotations
def authenticate_user(username: str, password: str) -> AuthResult:
"""Authenticate user credentials."""
pass
# REQUIRED: Generator fixtures with full typing
from typing import Generator
from pytest import fixture
@fixture
def database_connection() -> Generator[Connection, None, None]:
"""Provide database connection."""
conn = connect_to_db()
yield conn
conn.close()
# REQUIRED: Modern union syntax
def get_user(user_id: int) -> User | None: # ✓
pass
# FORBIDDEN: Legacy Optional
from typing import Optional
def get_user(user_id: int) -> Optional[User]: # ✗
pass
Related Standards:
- Python 3.11+ native generics required
- Strict mode is MANDATORY
- All functions must have return type annotations
- Pattern: Run mypy before pyright
Source: pattern-extraction.md Section 1.2, taxonomy.md Section 6.1
2.4 pyright (Static Type Checker)
tool_name: pyright
category: development
python_versions: [3.11, 3.12, 3.13, 3.14]
installation: "uv add --dev pyright"
purpose: "Microsoft's static type checker with strict mode"
mandatory: true
scenarios:
- All Python code type validation
- Layer 3 of validation pipeline (with mypy)
- VS Code integration
- CI/CD type safety gates
alternatives:
- mypy (also recommended, run both)
When to Use:
- MANDATORY for all Python code
- Run after mypy for comprehensive coverage
- Use strict mode exclusively
- Complements mypy with different checks
Basic Usage:
# Check with strict mode (prefer basedpyright for CI native reports)
uv run basedpyright .
# Or standard pyright
uv run pyright .
Integration with Other Tools:
- VS Code: Built-in Pylance extension uses pyright
- basedpyright: Fork with native CI output formats (GitLab, GitHub)
- Mypy: Run both for best coverage
- Ruff: Complementary linting
- Pre-commit: Automatic type checking
Configuration (pyproject.toml - basedpyright):
# pyproject.toml
[tool.basedpyright]
pythonVersion = "3.11"
typeCheckingMode = "basic"
reportMissingImports = false
reportMissingTypeStubs = false
reportUnnecessaryTypeIgnoreComment = "error"
reportPrivateImportUsage = false
include = ["packages", "scripts"]
extraPaths = ["packages", "scripts", "tests"]
ignore = ["**/typings", "**/tests"]
venvPath = "."
venv = ".venv"
Related Standards:
- Use strict mode only
- Complements mypy checks
- Pattern: mypy then pyright in validation pipeline
Source: pattern-extraction.md Section 1.2, taxonomy.md Section 6.4
2.5 pre-commit (Git Hooks)
tool_name: pre-commit
category: development
python_versions: [3.11, 3.12, 3.13, 3.14]
installation: "uv add --dev pre-commit"
purpose: "Git hook framework for running quality checks before commits"
mandatory: true
scenarios:
- All Python projects
- Layer 6 integration validation
- CI/CD pre-flight checks
- Team quality enforcement
alternatives:
- Manual script execution (NOT recommended)
- Custom git hooks (harder to maintain)
When to Use:
- MANDATORY for all Python projects
- Layer 6 of validation pipeline
- Install hooks:
pre-commit install - Run before commits:
pre-commit run --files <files>
Basic Usage:
# Install hooks
uv run pre-commit install
# Run on staged files (preferred - scoped operation)
uv run pre-commit run
# Run on specific files (scoped operation)
uv run pre-commit run --files path/to/file.py
# Update hook versions
uv run pre-commit autoupdate
Important: Always scope operations to changed files using pre-commit run (staged files) or --files <paths>. Avoid --all-files unless explicitly requested by user, as it formats unrelated code causing diff pollution and merge conflicts.
Integration with Other Tools:
- Ruff: Automatic linting and formatting
- Mypy: Type checking before commit
- Pyright: Additional type checks
- pytest: Run tests before commit
Configuration:
# .pre-commit-config.yaml
repos:
- repo: https://github.com/astral-sh/ruff-pre-commit
rev: v0.6.0
hooks:
- id: ruff
args: [--fix]
- id: ruff-format
- repo: https://github.com/pre-commit/mirrors-mypy
rev: v1.11.0
hooks:
- id: mypy
args: [--strict]
additional_dependencies:
- types-requests
- pydantic
- repo: local
hooks:
- id: basedpyright
name: basedpyright
entry: uv run basedpyright
language: system
types: [python]
pass_filenames: false
- id: pytest-check
name: pytest
entry: uv run pytest
language: system
pass_filenames: false
always_run: true
Common Patterns:
# Standard workflow
git add file.py
uv run pre-commit run --files file.py # Run checks
git commit -m "Add feature" # Auto-runs hooks
# Fix issues on specific files
uv run pre-commit run --files file.py other.py
Note: Hooks run automatically on staged files during commit. Manual invocation is typically only needed for verification before staging. Avoid --all-files to prevent formatting code outside your current branch.
Related Standards:
- MUST pass all hooks before commit
- NEVER skip hooks without justification
- Pattern: Automated quality enforcement
Source: pattern-extraction.md Section 3.5, taxonomy.md Section 6.4
2.6 prospector (Multi-Tool Linter)
tool_name: prospector
category: development
python_versions: [3.11, 3.12, 3.13, 3.14]
installation: "uv add --dev prospector[with_everything]"
purpose: "Multi-tool wrapper combining pylint, pep8, pyflakes, mccabe, and more"
mandatory: false
scenarios:
- Comprehensive code analysis
- Legacy codebase auditing
- Security scanning
- Complexity analysis
alternatives:
- ruff + mypy + bandit (recommended modern stack)
- Individual tools separately
When to Use:
- Optional for comprehensive analysis
- Legacy code evaluation
- NOT recommended as primary linter (use ruff)
- Useful for one-off deep analysis
Basic Usage:
# Run all checks
prospector
# With specific tools
prospector --with-tool bandit --with-tool mccabe
# Output to file
prospector --output-format json > report.json
# Strictness levels
prospector --strictness high
Integration with Other Tools:
- Combines: pylint, pep8, pyflakes, mccabe, dodgy, pep257, vulture
- Can run bandit for security
- Ruff replaces most prospector functionality
Configuration:
# .prospector.yaml
strictness: high
test-warnings: true
doc-warnings: true
pylint:
run: true
disable:
- too-few-public-methods
pep8:
run: true
max-line-length: 100
mccabe:
run: true
max-complexity: 10
bandit:
run: true
Comparison with ruff:
- Ruff: Faster, modern, single tool
- Prospector: Comprehensive, slower, multiple tools
- Recommendation: Use ruff + mypy + bandit instead
Source: User requirements list
2.7 bandit (Security Scanner)
tool_name: bandit
category: development
python_versions: [3.11, 3.12, 3.13, 3.14]
installation: "uv add --dev bandit"
purpose: "Security-focused static analysis tool for Python"
mandatory: false
scenarios:
- Security-critical code
- Compliance requirements (HIPAA, PCI-DSS, GDPR)
- Pre-production security audits
- CI/CD security gates
alternatives:
- ruff (has some security rules via flake8-bandit)
- semgrep (broader security scanning)
When to Use:
- MANDATORY for security-critical code
- Recommended for all production code
- CI/CD security scanning
- Compliance requirement validation
Basic Usage:
# Scan directory
bandit -r packages/
# Skip specific tests
bandit -r packages/ -s B101,B601
# Output formats
bandit -r packages/ -f json -o report.json
bandit -r packages/ -f html -o report.html
# Severity levels
bandit -r packages/ -ll # Low confidence + Low severity
Integration with Other Tools:
- Ruff: Some overlap with flake8-bandit rules
- Pre-commit: Security scanning before commit
- CI/CD: Fail pipeline on high-severity issues
Configuration:
# .bandit
tests:
- B201 # flask_debug_true
- B301 # pickle
- B302 # marshal
- B303 # md5
- B304 # ciphers
- B305 # cipher_modes
- B306 # mktemp_q
- B307 # eval
- B308 # mark_safe
- B309 # httpsconnection
- B310 # urllib_urlopen
- B311 # random
- B312 # telnetlib
- B313 # xml_bad_cElementTree
- B314 # xml_bad_ElementTree
- B315 # xml_bad_expatreader
- B316 # xml_bad_expatbuilder
- B317 # xml_bad_sax
- B318 # xml_bad_minidom
- B319 # xml_bad_pulldom
- B320 # xml_bad_etree
- B321 # ftplib
- B323 # unverified_context
- B324 # hashlib_new_insecure_functions
- B325 # tempnam
- B401 # import_telnetlib
- B402 # import_ftplib
- B403 # import_pickle
- B404 # import_subprocess
- B405 # import_xml_etree
- B406 # import_xml_sax
- B407 # import_xml_expat
- B408 # import_xml_minidom
- B409 # import_xml_pulldom
- B410 # import_lxml
- B411 # import_xmlrpclib
- B412 # import_httpoxy
- B501 # request_with_no_cert_validation
- B502 # ssl_with_bad_version
- B503 # ssl_with_bad_defaults
- B504 # ssl_with_no_version
- B505 # weak_cryptographic_key
- B506 # yaml_load
- B507 # ssh_no_host_key_verification
- B601 # paramiko_calls
- B602 # shell_true
- B603 # subprocess_without_shell_equals_true
- B604 # any_other_function_with_shell_equals_true
- B605 # start_process_with_a_shell
- B606 # start_process_with_no_shell
- B607 # start_process_with_partial_path
- B608 # hardcoded_sql_expressions
- B609 # wildcard_injection
exclude_dirs:
- /tests/
- /venv/
Common Patterns:
# AVOID: Hardcoded passwords
password = "secret123" # B105
# PREFER: Environment variables
import os
password = os.getenv("DB_PASSWORD")
# AVOID: Shell injection
subprocess.run(f"ls {user_input}", shell=True) # B602
# PREFER: Parameterized commands
subprocess.run(["ls", user_input], shell=False)
# AVOID: Insecure random
import random
token = random.randint(0, 1000000) # B311
# PREFER: Cryptographically secure random
import secrets
token = secrets.token_hex(16)
Related Standards:
- MANDATORY for payment processing
- MANDATORY for authentication code
- MANDATORY for data validation
- Pattern: Security-first development
Source: User requirements list, pattern-extraction.md Section 4
3. Testing Tools
3.1 pytest (Test Framework)
tool_name: pytest
category: testing
python_versions: [3.11, 3.12, 3.13, 3.14]
installation: "uv add --dev pytest"
purpose: "Modern Python testing framework with fixtures and plugins"
mandatory: true
scenarios:
- All Python testing
- Unit tests
- Integration tests
- E2E tests
- API testing
alternatives:
- unittest (stdlib, NOT recommended)
- nose2 (deprecated)
When to Use:
- MANDATORY for all Python testing
- NEVER use unittest
- Layer 4 of validation pipeline
- Minimum 80% code coverage required
Basic Usage:
# Run all tests (coverage via pyproject.toml config)
uv run pytest
# Verbose output
uv run pytest -v
# Run specific test file
uv run pytest tests/test_auth.py
# Run specific test function
uv run pytest tests/test_auth.py::test_login
# Run tests matching pattern
uv run pytest -k "auth"
# Show print statements
uv run pytest -s
# Stop on first failure
uv run pytest -x
# Show local variables on failure
uv run pytest -l
# Run last failed tests
uv run pytest --lf
# Run failed tests first
uv run pytest --ff
Integration with Other Tools:
- pytest-cov: Coverage reporting
- pytest-mock: Mocking (MANDATORY)
- pytest-asyncio: Async test support
- pytest-bdd: BDD/Gherkin tests
- hypothesis: Property-based testing
- mutmut: Mutation testing
Configuration:
# pyproject.toml
[tool.pytest.ini_options]
testpaths = ["tests"]
python_files = ["test_*.py"]
python_classes = ["Test*"]
python_functions = ["test_*"]
addopts = [
"-v",
"--strict-markers",
"--strict-config",
"--cov=packages",
"--cov-report=term-missing",
"--cov-report=html",
"--cov-fail-under=80",
]
markers = [
"slow: marks tests as slow (deselect with '-m \"not slow\"')",
"integration: marks tests as integration tests",
"unit: marks tests as unit tests",
]
Common Patterns:
# REQUIRED: AAA pattern (Arrange-Act-Assert)
def test_user_authentication() -> None:
"""Test user authentication with valid credentials.
Tests: Authentication system
How: Create user, attempt login, verify token
Why: Core security validation
"""
# Arrange
user = create_test_user("test@example.com", "Pass123!")
# Act
response = authenticate(user.email, "Pass123!")
# Assert
assert response.success
assert response.token is not None
assert response.expires_at > datetime.now()
# REQUIRED: Type annotations
def test_data_processing(tmp_path: Path) -> None:
"""Test data processing with temporary files."""
pass
# REQUIRED: Comprehensive docstrings
def test_edge_case_handling() -> None:
"""Test handling of empty input data.
Tests: Data validation module
How: Pass empty list, verify graceful handling
Why: Prevent runtime errors on edge cases
"""
result = process_data([])
assert result.success is False
assert "empty" in result.error.lower()
Related Standards:
- MANDATORY 80% coverage minimum
- AAA pattern required
- Type hints on all test functions
- Comprehensive docstrings
- Pattern: pytest-architect creates tests
Source: pattern-extraction.md Section 1.3, pytest-architect-analysis.md
3.2 pytest-mock (Mocking Framework)
tool_name: pytest-mock
category: testing
python_versions: [3.11, 3.12, 3.13, 3.14]
installation: "uv add --dev pytest-mock"
purpose: "Thin wrapper around unittest.mock providing pytest fixtures"
mandatory: true
scenarios:
- All mocking in tests
- External service mocking
- Database mocking
- API client mocking
alternatives:
- unittest.mock (FORBIDDEN - never use directly)
When to Use:
- MANDATORY for all mocking
- NEVER use unittest.mock directly
- Use
mocker: MockerFixtureparameter - Replaces @patch decorators
Basic Usage:
from pytest_mock import MockerFixture
def test_external_api(mocker: MockerFixture) -> None:
"""Test external API integration with mock."""
# Mock external service
mock_response = mocker.Mock()
mock_response.status_code = 200
mock_response.json.return_value = {"status": "ok"}
mock_get = mocker.patch("requests.get", return_value=mock_response)
# Test code that uses requests.get
result = fetch_data("https://api.example.com")
# Verify
assert result["status"] == "ok"
mock_get.assert_called_once_with("https://api.example.com")
def test_database_operations(mocker: MockerFixture) -> None:
"""Test database operations with mocked connection."""
# Mock database connection
mock_conn = mocker.Mock()
mock_cursor = mocker.Mock()
mock_conn.cursor.return_value = mock_cursor
mock_cursor.fetchall.return_value = [("user1",), ("user2",)]
mocker.patch("psycopg2.connect", return_value=mock_conn)
# Test
users = get_all_users()
# Verify
assert users == ["user1", "user2"]
mock_conn.cursor.assert_called_once()
Integration with Other Tools:
- pytest: Provides MockerFixture
- Type checkers: Full type hint support
- Fixtures: Can be used in fixture composition
Common Patterns:
# REQUIRED: Use mocker parameter
def test_with_mock(mocker: MockerFixture) -> None: # ✓
mock = mocker.patch("module.function")
# FORBIDDEN: Direct unittest.mock import
from unittest.mock import patch # ✗
@patch("module.function")
def test_with_patch(mock):
pass
# REQUIRED: mocker.Mock() not Mock()
def test_mock_object(mocker: MockerFixture) -> None:
mock_obj = mocker.Mock() # ✓
mock_obj.method.return_value = 42
# REQUIRED: mocker.spy() for partial mocking
def test_spy_on_method(mocker: MockerFixture) -> None:
obj = MyClass()
spy = mocker.spy(obj, "method")
obj.method("arg")
spy.assert_called_once_with("arg")
Related Standards:
- NEVER import from unittest.mock
- ALWAYS use mocker parameter
- Type hint as MockerFixture
- Pattern: pytest-architect enforces this
Source: pattern-extraction.md Section 2.2, pytest-architect-analysis.md
3.3 pytest-cov (Coverage Reporting)
tool_name: pytest-cov
category: testing
python_versions: [3.11, 3.12, 3.13, 3.14]
installation: "uv add --dev pytest-cov"
purpose: "Coverage.py plugin for pytest with comprehensive reporting"
mandatory: true
scenarios:
- All Python testing
- Coverage measurement
- CI/CD quality gates
- Coverage-driven development
alternatives:
- coverage.py (pytest-cov wraps this)
When to Use:
- MANDATORY for all Python projects
- Minimum 80% coverage required
- Critical code: 95%+ coverage required
- Layer 4 validation with pytest
Basic Usage:
Coverage is configured in pyproject.toml - no CLI flags needed:
# Run tests with coverage (config-driven)
uv run pytest
Integration with Other Tools:
- pytest: Native plugin integration
- CI/CD: Generate reports for pipeline
- Coverage.py: Underlying engine
- Mutation testing: Complements mutmut
Configuration (MANDATORY - coverage in config, not CLI):
# pyproject.toml
[tool.pytest.ini_options]
addopts = [
"--cov=packages",
"--cov-report=term-missing",
"--cov-report=html:htmlcov",
"--cov-fail-under=80",
]
[tool.coverage.run]
source = ["packages"]
omit = [
"*/tests/*",
"*/test_*.py",
"*/__init__.py",
]
branch = true
[tool.coverage.report]
fail_under = 80
show_missing = true
skip_covered = false
exclude_lines = [
"pragma: no cover",
"def __repr__",
"raise AssertionError",
"raise NotImplementedError",
"if __name__ == .__main__.:",
"if TYPE_CHECKING:",
"@abstractmethod",
"@overload",
]
[tool.coverage.html]
directory = "htmlcov"
Coverage Standards:
# General code: 80% minimum
# Critical code: 95%+ required
# Coverage excludes
def __repr__(self) -> str: # pragma: no cover
"""String representation."""
return f"User({self.name})"
# Type checking blocks
if TYPE_CHECKING: # pragma: no cover
from .models import User
# Abstract methods
@abstractmethod
def process(self) -> None: # pragma: no cover
"""Process data."""
Related Standards:
- MANDATORY 80% general code
- MANDATORY 95%+ critical code
- Pattern: Testing pyramid distribution
- Source: Coverage gates in validation pipeline
Source: pattern-extraction.md Section 1.3, taxonomy.md Section 6.2
3.4 hypothesis (Property-Based Testing)
tool_name: hypothesis
category: testing
python_versions: [3.11, 3.12, 3.13, 3.14]
installation: "uv add --dev hypothesis"
purpose: "Property-based testing framework for generating test cases"
mandatory: false
scenarios:
- Data validation testing
- Algorithm correctness
- Edge case discovery
- Fuzzing inputs
alternatives:
- Manual parametrization (less comprehensive)
When to Use:
- RECOMMENDED for all projects
- ESPECIALLY emphasized in pytest-architect
- Data validation and sanitization
- Complex algorithm testing
- Discovering edge cases
Basic Usage:
from hypothesis import given, strategies as st
@given(st.integers())
def test_absolute_value_always_positive(n: int) -> None:
"""Test that absolute value is always positive."""
assert abs(n) >= 0
@given(st.lists(st.integers()))
def test_reverse_twice_is_identity(lst: list[int]) -> None:
"""Test that reversing twice returns original list."""
assert list(reversed(list(reversed(lst)))) == lst
@given(st.text(min_size=1, max_size=100))
def test_email_validation(email_input: str) -> None:
"""Test email validation with various inputs."""
result = validate_email(email_input)
# Property: valid emails have @ symbol
if result.is_valid:
assert "@" in email_input
Integration with Other Tools:
- pytest: Native integration
- pytest-cov: Coverage of generated cases
- Type hints: Strategy inference
Advanced Patterns:
from hypothesis import given, strategies as st, assume
from datetime import date, timedelta
# Custom strategies
email_strategy = st.builds(
lambda name, domain: f"{name}@{domain}",
name=st.text(min_size=1, max_size=20, alphabet=st.characters(whitelist_categories=("Ll", "Nd"))),
domain=st.sampled_from(["example.com", "test.org", "demo.net"])
)
@given(email_strategy)
def test_email_domain_validation(email: str) -> None:
"""Test email domain validation."""
result = validate_email_domain(email)
assert result.domain in ["example.com", "test.org", "demo.net"]
# Composite strategies
@st.composite
def date_range(draw):
"""Generate valid date range."""
start = draw(st.dates())
days = draw(st.integers(min_value=1, max_value=365))
end = start + timedelta(days=days)
return (start, end)
@given(date_range())
def test_date_range_processing(dates: tuple[date, date]) -> None:
"""Test date range processing."""
start, end = dates
assert start <= end
Configuration:
# pyproject.toml
[tool.pytest.ini_options]
markers = [
"hypothesis: property-based tests using hypothesis",
]
# Add hypothesis profile
[tool.hypothesis]
max_examples = 100
derandomize = true
Related Standards:
- Emphasized in pytest-architect
- Recommended for data validation
- Pattern: Property-based testing
Source: pytest-architect-analysis.md Section 4.1
3.5 mutmut (Mutation Testing)
tool_name: mutmut
category: testing
python_versions: [3.11, 3.12, 3.13, 3.14]
installation: "uv add --dev mutmut"
purpose: "Mutation testing tool to verify test suite quality"
mandatory: false
scenarios:
- Critical business logic
- Payment processing
- Authentication/authorization
- Security-critical code
- Compliance code (HIPAA, PCI-DSS, GDPR)
alternatives:
- cosmic-ray (alternative mutation tester)
When to Use:
- MANDATORY for critical code:
- Payment processing
- Authentication/authorization
- Security-critical code
- Data validation and sanitization
- Regulatory compliance code
- Complex algorithms
- Core libraries
- Target: 100% mutation score (kill all mutants)
Basic Usage:
# Run mutation testing
mutmut run
# Show results
mutmut results
# Show specific mutant
mutmut show 1
# Apply specific mutant (for debugging)
mutmut apply 1
# Run tests after applying mutant
pytest
# Revert mutant
mutmut apply --revert
# Run on specific paths
mutmut run --paths-to-mutate=packages/auth/
Integration with Other Tools:
- pytest: Uses pytest to run tests
- Coverage: Complements code coverage
- CI/CD: Critical code quality gate
Configuration:
# setup.cfg or pyproject.toml
[mutmut]
paths_to_mutate = packages/
backup = false
runner = pytest
tests_dir = tests/
Common Patterns:
# Example: Payment processing (MANDATORY mutation testing)
def calculate_total(items: list[Item], tax_rate: float) -> Decimal:
"""Calculate order total with tax.
CRITICAL: Payment processing - mutation tested.
"""
subtotal = sum(item.price * item.quantity for item in items)
tax = subtotal * Decimal(str(tax_rate))
total = subtotal + tax
return total.quantize(Decimal("0.01"))
# Tests MUST kill all mutants:
# - Operator changes (+ to -, * to /)
# - Number changes (tax_rate to 0, to 1)
# - Decimal precision changes
# - Boundary conditions
def test_calculate_total_normal() -> None:
"""Test normal calculation."""
items = [Item(price=Decimal("10.00"), quantity=2)]
total = calculate_total(items, 0.08)
assert total == Decimal("21.60") # 20.00 + 1.60 tax
def test_calculate_total_zero_tax() -> None:
"""Test with zero tax rate."""
items = [Item(price=Decimal("10.00"), quantity=1)]
total = calculate_total(items, 0.0)
assert total == Decimal("10.00")
def test_calculate_total_precision() -> None:
"""Test decimal precision handling."""
items = [Item(price=Decimal("10.99"), quantity=1)]
total = calculate_total(items, 0.08)
assert total == Decimal("11.87") # Rounds correctly
Mutation Score Interpretation:
- 100%: All mutants killed (perfect)
- 90-99%: Excellent test coverage
- 80-89%: Good, some gaps
- <80%: Insufficient testing for critical code
Related Standards:
- MANDATORY for critical code
- Target: 100% mutation score
- Pattern: Complements code coverage
Source: pattern-extraction.md Section 2.7, pytest-architect-analysis.md
3.6 robotframework (Acceptance Testing)
tool_name: robotframework
category: testing
python_versions: [3.11, 3.12, 3.13, 3.14]
installation: "uv add --dev robotframework"
purpose: "Keyword-driven acceptance testing framework"
mandatory: false
scenarios:
- BDD acceptance tests
- E2E testing
- Non-technical stakeholder tests
- Keyword-driven testing
alternatives:
- pytest-bdd (Python-native BDD)
- behave (Gherkin-based BDD)
When to Use:
- Optional for acceptance testing
- E2E test scenarios
- Non-technical stakeholder involvement
- Keyword-driven test approach
Basic Usage:
# Run tests
robot tests/
# Run specific test file
robot tests/login.robot
# Run with tags
robot --include smoke tests/
# Generate reports
robot --outputdir reports tests/
Example Test:
*** Settings ***
Library SeleniumLibrary
*** Variables ***
${URL} https://example.com
${BROWSER} Chrome
*** Test Cases ***
User Can Login With Valid Credentials
[Documentation] Test successful login flow
[Tags] smoke login
Open Browser ${URL} ${BROWSER}
Input Text id:username testuser
Input Text id:password TestPass123!
Click Button id:login
Page Should Contain Welcome, testuser
[Teardown] Close Browser
Integration with Other Tools:
- pytest: Can run alongside pytest
- Selenium: Web automation
- CI/CD: Generate XML reports
Related Standards:
- Alternative to pytest-bdd
- Pattern: Acceptance testing layer
Source: User requirements list
3.7 pytest-asyncio (Async Testing)
tool_name: pytest-asyncio
category: testing
python_versions: [3.11, 3.12, 3.13, 3.14]
installation: "uv add --dev pytest-asyncio"
purpose: "Pytest support for testing async code"
mandatory: false
scenarios:
- FastAPI testing
- Async function testing
- Concurrent operation testing
- AsyncIO-based applications
alternatives:
- pytest-trio (Trio async framework)
When to Use:
- Required for async/await code testing
- FastAPI endpoint testing
- Async database operations
- Concurrent task testing
Basic Usage:
import pytest
from httpx import AsyncClient
from app import app
@pytest.mark.asyncio
async def test_async_endpoint() -> None:
"""Test async API endpoint."""
async with AsyncClient(app=app, base_url="http://test") as client:
response = await client.get("/users/1")
assert response.status_code == 200
assert response.json()["id"] == 1
@pytest.mark.asyncio
async def test_concurrent_operations() -> None:
"""Test concurrent async operations."""
import asyncio
async def fetch_user(user_id: int) -> dict:
# Simulate async operation
await asyncio.sleep(0.1)
return {"id": user_id}
# Test concurrent execution
results = await asyncio.gather(
fetch_user(1),
fetch_user(2),
fetch_user(3),
)
assert len(resul
…(truncated)