--- name: python-dev description: "Python development guidance with code quality standards, error handling, testing practices, and environment management. Use when writing, reviewing, or modifying Python code (.py files) or Jupyter notebooks (.ipynb files)." --- # Python Development Rules ## Overview Python development guidance focused on code quality, error handling, testing, and environment management. Apply when working with Python code or Jupyter notebooks. ## When to Use This Skill Use this skill when: - Writing new Python code or modifying existing Python files - Creating or updating Jupyter notebooks - Setting up Python development environments - Writing or updating tests - Reviewing Python code for quality and best practices ## Code Quality ### Principles - **DRY (Don't Repeat Yourself)**: Avoid code duplication - **Composition over inheritance**: Prefer composition patterns - **Pure functions when possible**: Functions without side effects - **Simple solutions over clever ones**: Prioritize readability and maintainability - **Design for common use cases first**: Solve the primary problem before edge cases ### Style & Documentation - **Type hints required**: All functions must include type annotations - **snake_case naming**: Use snake_case for variables, functions, and modules - **Google-style docstrings**: Document functions, classes, and modules using Google-style docstrings - **Keep functions small**: Single responsibility principle - one function, one purpose - **Preserve existing comments**: Maintain and update existing code comments ### Example ```python def calculate_total(items: list[dict[str, float]], tax_rate: float = 0.08) -> float: """Calculate total cost including tax. Args: items: List of items with 'price' key tax_rate: Tax rate as decimal (default 0.08) Returns: Total cost including tax Raises: ValueError: If tax_rate is negative or items list is empty """ if not items: raise ValueError("Items list cannot be empty") if tax_rate < 0: raise ValueError("Tax rate cannot be negative") subtotal = sum(item['price'] for item in items) return subtotal * (1 + tax_rate) ``` ## Error Handling & Efficiency ### Error Handling - **Specific exception types**: Catch specific exceptions, not bare `except` - **Validate inputs early**: Check inputs at function entry - **No bare except**: Always specify exception types ### Efficiency Patterns - **f-strings**: Use f-strings for string formatting - **Comprehensions**: Prefer list/dict/set comprehensions over loops when appropriate - **Context managers**: Use `with` statements for resource management ### Example ```python def process_file(file_path: str) -> list[str]: """Process file and return lines. Args: file_path: Path to file Returns: List of non-empty lines Raises: FileNotFoundError: If file doesn't exist PermissionError: If file cannot be read """ if not file_path: raise ValueError("File path cannot be empty") try: with open(file_path, 'r', encoding='utf-8') as f: return [line.strip() for line in f if line.strip()] except FileNotFoundError: raise FileNotFoundError(f"File not found: {file_path}") except PermissionError: raise PermissionError(f"Permission denied: {file_path}") ``` ## Testing (Critical) ### Framework & Structure - **pytest only**: Use pytest exclusively (no unittest) - **Test location**: All tests in `./tests/` directory - **Test package**: Include `__init__.py` in tests directory - **TDD approach**: Write/update tests for all new/modified code - **All tests must pass**: Ensure all tests pass before task completion ### Test Structure Example ``` project/ ├── src/ │ └── my_module.py └── tests/ ├── __init__.py └── test_my_module.py ``` ### Example Test ```python # tests/test_calculations.py import pytest from src.calculations import calculate_total def test_calculate_total_basic(): """Test basic total calculation.""" items = [{'price': 10.0}, {'price': 20.0}] result = calculate_total(items, tax_rate=0.1) assert result == 33.0 def test_calculate_total_empty_list(): """Test error handling for empty list.""" with pytest.raises(ValueError, match="Items list cannot be empty"): calculate_total([]) def test_calculate_total_negative_tax(): """Test error handling for negative tax rate.""" items = [{'price': 10.0}] with pytest.raises(ValueError, match="Tax rate cannot be negative"): calculate_total(items, tax_rate=-0.1) ``` ## Environment Management ### Dependency Management - **Use uv**: Dependency management via [uv](https://github.com/astral-sh/uv) - **Virtual environments**: Use virtual environments (`venv`) or `uv` - **Check existing venv**: Always check for existing `.venv` in current or parent directories before creating new one - **Activate before use**: Activate `.venv` before installing packages or executing scripts ### Code Style - **Ruff**: Use Ruff for code style consistency and linting ### Environment Setup Example ```bash # Check for existing .venv if [ -d ".venv" ]; then source .venv/bin/activate elif [ -d "../.venv" ]; then source ../.venv/bin/activate else # Create new venv or use uv python3 -m venv .venv source .venv/bin/activate fi # Install dependencies pip install -r requirements.txt # Or with uv uv pip install -r requirements.txt ``` ### Python Script Execution - Always activate virtual environment before running Python scripts - Use `python3` explicitly when not in venv - Check for `requirements.txt` or `pyproject.toml` for dependencies ## Best Practices Summary 1. **Code Quality**: DRY, composition, pure functions, simple solutions 2. **Style**: Type hints, snake_case, Google docstrings, small functions 3. **Errors**: Specific exceptions, early validation, no bare except 4. **Efficiency**: f-strings, comprehensions, context managers 5. **Testing**: pytest only, TDD, tests in `./tests/`, all must pass 6. **Environment**: uv or venv, check existing `.venv`, activate before use, Ruff for style