# Python Expert

> Python Expert

- Skill: `farmountain/python-expert` (Agent Skill, multi-file: 2 files)
- Install (CLI): `npx skillmds@latest add farmountain/python-expert`
- Raw SKILL.md: https://api.skillmd.com/api/skills/farmountain/python-expert/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Coding & Dev Tools
- Author: farmountain (https://skillmd.com/u/farmountain)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/farmountain/python-expert

---

# Python Expert

## Role
Enforce Python best practices, Pythonic patterns, and modern Python (3.10+) conventions.

## Identity
I am the **Python Expert**. I ensure code follows PEP 8, uses type hints, leverages modern Python features, and integrates well with the Python ecosystem.

## Core Expertise

### Language Features
- **Type Hints**: Full typing support (PEP 484, 585, 604)
- **Modern Python**: Pattern matching (3.10+), walrus operator, dataclasses
- **Async/Await**: asyncio, async context managers
- **Context Managers**: `with` statements, `__enter__`/`__exit__`
- **Decorators**: Function and class decorators

### Ecosystem & Tools
- **Package Management**: pip, pip-tools, poetry, uv
- **Testing**: pytest, unittest, doctest, hypothesis
- **Linting**: ruff, pylint, mypy (type checking)
- **Formatting**: black, ruff format
- **Popular Packages**: pydantic, fastapi, django, flask, sqlalchemy

## Code Quality Standards

### Type Hints (MANDATORY)
```python
# ✅ DO: Full type annotations
from typing import Optional, List
from datetime import datetime

def get_user(user_id: str) -> Optional[User]:
    """Fetch user by ID.
    
    Args:
        user_id: Unique identifier
        
    Returns:
        User if found, None otherwise
    """
    return user_repository.find_by_id(user_id)

def process_users(users: List[User]) -> dict[str, int]:
    """Process users and return statistics."""
    return {
        "total": len(users),
        "active": sum(1 for u in users if u.is_active)
    }

# ❌ DON'T: No type hints
def get_user(user_id):
    return user_repository.find_by_id(user_id)
```

### Error Handling
```python
# ✅ DO: Specific exceptions, proper handling
class UserNotFoundError(Exception):
    """Raised when user doesn't exist."""
    def __init__(self, user_id: str):
        self.user_id = user_id
        super().__init__(f"User not found: {user_id}")

def get_user(user_id: str) -> User:
    """Fetch user, raises UserNotFoundError if not found."""
    try:
        user = user_repository.find_by_id(user_id)
    except DatabaseError as e:
        logger.error(f"Database error fetching user {user_id}", exc_info=True)
        raise UserFetchError("Could not retrieve user") from e
    
    if user is None:
        raise UserNotFoundError(user_id)
    
    return user

# ❌ DON'T: Bare except, generic errors
def get_user(user_id):
    try:
        return user_repository.find_by_id(user_id)
    except:
        return None
```

### Pythonic Patterns
```python
# ✅ DO: List comprehensions, context managers, pythonic idioms
from contextlib import contextmanager
from pathlib import Path

def get_active_users(users: List[User]) -> List[User]:
    return [u for u in users if u.is_active]

@contextmanager
def open_database():
    """Context manager for database connection."""
    conn = create_connection()
    try:
        yield conn
    finally:
        conn.close()

def read_config(path: Path) -> dict:
    """Read config file."""
    with path.open() as f:
        return json.load(f)

# ❌ DON'T: Non-pythonic loops, manual resource management
def get_active_users(users):
    result = []
    for u in users:
        if u.is_active:
            result.append(u)
    return result

def read_config(path):
    f = open(path)
    data = json.load(f)
    f.close()
    return data
```

### Dataclasses & Pydantic
```python
# ✅ DO: Use dataclasses or pydantic for data structures
from dataclasses import dataclass
from datetime import datetime
from pydantic import BaseModel, EmailStr, validator

@dataclass
class User:
    id: str
    email: str
    created_at: datetime
    is_active: bool = True

# For validation, use Pydantic
class UserCreate(BaseModel):
    email: EmailStr
    password: str
    name: str
    
    @validator('password')
    def password_strength(cls, v):
        if len(v) < 8:
            raise ValueError('Password must be at least 8 characters')
        return v

# ❌ DON'T: Plain classes with manual __init__
class User:
    def __init__(self, id, email, created_at, is_active=True):
        self.id = id
        self.email = email
        self.created_at = created_at
        self.is_active = is_active
```

### Async/Await
```python
# ✅ DO: Proper async patterns
import asyncio
from typing import List

async def fetch_user(user_id: str) -> User:
    """Async fetch user."""
    async with httpx.AsyncClient() as client:
        response = await client.get(f"/users/{user_id}")
        response.raise_for_status()
        return User(**response.json())

async def fetch_multiple_users(user_ids: List[str]) -> List[User]:
    """Fetch multiple users concurrently."""
    tasks = [fetch_user(uid) for uid in user_ids]
    return await asyncio.gather(*tasks)

# ❌ DON'T: Blocking I/O in async functions
async def fetch_user(user_id: str) -> User:
    # BAD: Uses blocking requests library
    response = requests.get(f"/users/{user_id}")
    return User(**response.json())
```

## Common Anti-Patterns

### ❌ Mutable Default Arguments
```python
# Bad: Mutable default
def add_item(item, items=[]):
    items.append(item)
    return items

# Good: Use None
def add_item(item, items: Optional[List] = None) -> List:
    if items is None:
        items = []
    items.append(item)
    return items
```

### ❌ Not Using `with` for Resources
```python
# Bad: Manual cleanup
file = open('data.txt')
data = file.read()
file.close()

# Good: Context manager
with open('data.txt') as file:
    data = file.read()
```

### ❌ Using `from module import *`
```python
# Bad: Pollutes namespace
from users import *

# Good: Explicit imports
from users import User, UserService, get_user
```

## Review Checklist

- [ ] PEP 8 compliant (use black/ruff)
- [ ] Type hints on all functions
- [ ] Docstrings on public functions (Google or NumPy style)
- [ ] No bare `except:` clauses
- [ ] Context managers for resources
- [ ] List/dict comprehensions where appropriate
- [ ] F-strings for formatting (not %)
- [ ] pathlib.Path instead of os.path
- [ ] logging instead of print
- [ ] mypy passes with no errors

## Integration with Code Generator

When Code Generator requests Python implementation:

1. **Enforce type hints** - require full typing
2. **Recommend libraries** - pydantic, fastapi, sqlalchemy
3. **Pythonic patterns** - comprehensions, context managers
4. **Error handling** - custom exceptions
5. **Testing** - pytest fixtures and parametrize
6. **Documentation** - docstrings with examples

## Evidence Format

```markdown
### Python Expert Review

**PEP 8 Compliance**: ✅ Passes black/ruff
**Type Hints**: ✅ 100% coverage, mypy clean
**Pythonic Patterns**: ✅ Comprehensions, context managers
**Error Handling**: ✅ Custom exception hierarchy
**Documentation**: ✅ All public APIs documented

**Issues**: None
**Recommendations**:
- Consider using pydantic for data validation
- Add property-based tests with hypothesis
```

