python-development · git:20260812.4160717 · 2026-08-12 · sha256 a1160de36757fccb

python-development git:20260812.4160717B

Immutable. This exact content is served forever at /api/v1/blob/a1160de36757fccb.

---
name: python-development
description: Python development standards for code review and generation. Covers Python 3.14+ patterns including template strings (t-strings), deferred annotations, free-threading, type hints, async/await, testing with pytest, package management with uv, AWS Lambda/boto3 patterns, and Pydantic validation. Use when working with .py files, pyproject.toml, requirements.txt, Lambda functions, or when asking about Python best practices, code review, or generation.
---

# Python Development

Mandatory gates are owned by the [Python rule](file:///Users/Devesh_Padmanabhan/.cursor/agent-engineering-handbook/rules/200-python.mdc). This skill and its references own procedures and examples.

## Guiding Principle

Apply features only when they add clarity, correctness, performance, or security. Prefer simple, intentional solutions (DRY, KISS, YAGNI, Fail Fast).

## The Zen of Python (`import this`)

The canonical aphorisms by Tim Peters (PEP 20). When in doubt about which Python idiom to choose, re-read these. Quote verbatim; do not paraphrase in code reviews.

```text
The Zen of Python, by Tim Peters

Beautiful is better than ugly.
Explicit is better than implicit.
Simple is better than complex.
Complex is better than complicated.
Flat is better than nested.
Sparse is better than dense.
Readability counts.
Special cases aren't special enough to break the rules.
Although practicality beats purity.
Errors should never pass silently.
Unless explicitly silenced.
In the face of ambiguity, refuse the temptation to guess.
There should be one-- and preferably only one --obvious way to do it.
Although that way may not be obvious at first unless you're Dutch.
Now is better than never.
Although never is often better than *right* now.
If the implementation is hard to explain, it's a bad idea.
If the implementation is easy to explain, it may be a good idea.
Namespaces are one honking great idea -- let's do more of those!
```

> Run `python -c "import this"` in any Python REPL to see it.

For per-line operative readings (how to apply each in review), see the Zen section in `rules/200-python.mdc`.

## AI Assistant Guidelines

- **Avoid Over-Engineering**: Don't recommend boto3 client caching, async/await, or concurrency patterns unless explicitly requested or bottlenecks are evident
- **Keep It Simple**: Prefer stdlib over complex architectures
- **Respect Context**: Don't transform a 20-line script into a 200-line framework

## Non-negotiables

> [!IMPORTANT]
> New Python applications, services, scheduled jobs, CLI tools, and AWS Lambda functions target **Python ≥ 3.14**. Treat lower runtimes as a reject-in-review issue unless the code is a library / SDK with a stated compatibility commitment.

### NN-1: Python ≥ 3.14 for new applications, services, and Lambda functions

Use `requires-python = ">=3.14"` in `pyproject.toml`, Python 3.14 in CI, Python 3.14 Docker images, and Python 3.14 Lambda runtimes for new code.

Libraries published to PyPI or shipped to external customers MAY target a lower floor when there is a documented compatibility commitment. The acceptable lower floor is Python 3.11. The PR description must explain the audience, the 3.14 features being deferred, and the planned floor-bump date.

Reject in review:

- New application / service / Lambda with `requires-python = ">=3.11"` (or lower) and no library-audience justification
- Missing `requires-python` in `pyproject.toml`
- New code targeting Python 3.10 or below for any reason
- CI, Docker, or Lambda runtime config pinned below Python 3.14 for new app / service / Lambda code

### NN-2: Leading underscores mean non-public API

Do not prefix functions, methods, classes, variables, modules, or packages with `_` unless they are intentionally internal implementation details. Public behavior gets public names.

```python
# Public API, public name
def validate_order(order: Order) -> None:
    ...


# Internal helper, module-private name
def _normalize_order_id(raw_order_id: str) -> str:
    ...
```

Reject in review:

- `_process_data()`, `_validate_input()`, or `_build_payload()` called directly from other modules
- Public classes / modules named `_Client`, `_Service`, `_helpers`, or similar
- Double-underscore methods (`__method`) unless name-mangling is intentionally required
- Invented dunder names such as `__process__` or `__validate__`
- Leading underscore added merely because the function is small or "helper-ish"

## Standards Quick Reference

| Aspect | Standard |
|--------|----------|
| **Python Version** | ≥ 3.14 |
| **Shebang** | `#!/usr/bin/env -S uv run` |
| **Formatting** | 4-space indents, 120 char line length |
| **Linting** | `black`, `ruff`, `pylint` (≥9.0) |
| **Type Hints** | Strict typing required |
| **Docstrings** | Google-style |
| **Package Manager** | `uv` (preferred) |

## Documentation Contract

For new scripts, place the module-level docstring immediately below the shebang, with one blank line between them. The module docstring must explain the script's purpose, provide a short overview, include a numbered workflow when there are multiple steps, and include CLI usage examples when the file is meant to be run directly. AWS Lambda handlers and import-only modules do not need CLI usage examples.

```python
#!/usr/bin/env -S uv run
"""
Process user export files and publish normalized records.

This script reads a JSON export, validates each record, writes a cleaned
CSV file, and optionally uploads the result to object storage.

Workflow:
1. Parse command-line arguments.
2. Validate input file and output directory.
3. Load and validate JSON records.
4. Write normalized CSV output.
5. Upload the result when --upload is set.

Usage:
    python process_users.py --input users.json --output users.csv
    python process_users.py --input users.json --output users.csv --upload
"""
```

Every public function, class, and method must use Google-style docstrings. Put the description on a new line after the opening triple quotes, then document arguments, return value, raised exceptions, and examples when helpful.

```python
def load_users(input_path: Path) -> list[User]:
    """
    Load user records from a JSON file.

    Args:
        input_path (Path): Path to the JSON file containing user records.

    Returns:
        list[User]: Validated user records parsed from the input file.

    Raises:
        FileNotFoundError: If the input file does not exist.
        ValueError: If the file contains invalid JSON or invalid user records.

    Example:
        users = load_users(Path("users.json"))
    """
```

Inline comments are for complex logic, non-obvious tradeoffs, or external constraints. Do not comment obvious assignments or restate function names.

## Type Hints

Use built-in types instead of `typing` module:

```python
# Modern Python 3.14+
def process(items: list[str], config: dict[str, int] | None = None) -> tuple[str, int]:
    ...

# Avoid (old style)
from typing import List, Dict, Optional, Tuple
def process(items: List[str], config: Optional[Dict[str, int]] = None) -> Tuple[str, int]:
    ...
```

## Python 3.14 Features (Released Oct 2025)

### Template String Literals (PEP 750)

Safe custom string processing with t-strings:

```python
# SQL query with safe parameterization
query = t"SELECT * FROM users WHERE id = {user_id}"

# HTML generation with auto-escaping
html = t"<div>{user_input}</div>"

# Custom formatting
config = t"server={host}:{port}"
```

### Deferred Annotation Evaluation (PEP 649)

Annotations are no longer evaluated eagerly, improving startup performance:

```python
# Annotations stored in __annotate__ function
# Evaluated only when inspect.get_annotations() is called
def process(data: ComplexType) -> Result:
    """Annotations evaluated lazily, not at import time."""
    ...
```

### Free-Threading Support (PEP 779)

True parallelism without the GIL (experimental):

```python
# Enable with: python3.14t (free-threaded build)
# Performance penalty reduced to 5-10% for single-threaded code
import concurrent.futures

with concurrent.futures.ThreadPoolExecutor() as executor:
    results = executor.map(cpu_intensive_task, items)
```

### datetime Improvements

Direct parsing of date and time strings:

```python
from datetime import date, time

# Python 3.14+
d = date.fromisoformat("2025-10-07")
t = time.fromisoformat("14:30:00")
```

### UUID7 and UUID8 Support

Modern UUID versions with better properties:

```python
import uuid

# UUID7: Time-ordered, sortable (recommended for databases)
id = uuid.uuid7()

# UUID8: Custom format
id = uuid.uuid8(bytes16)
```

## Code Structure

```python
#!/usr/bin/env -S uv run
"""
Module purpose and overview.

Workflow:
1. Load configuration
2. Validate inputs
3. Process data
"""

# Standard library
import logging

# Third-party
import requests

# Local
from utils import helper


def helper_function() -> None:
    """Helper functions first."""
    pass


def main() -> int:
    """Main function last."""
    return 0


if __name__ == "__main__":
    sys.exit(main())
```

## Key Patterns

### Defensive Programming

```python
# Validate inputs early (fail-fast)
def process_user(user_id: str | None) -> User:
    if user_id is None:
        raise ValueError("user_id is required")
    # Continue processing...
```

### No Mutable Defaults

```python
# BAD
def foo(items: list[str] = []):
    ...

# GOOD
def foo(items: list[str] | None = None):
    items = items or []
    ...
```

### Error Handling

```python
# Re-raise with context at boundaries
try:
    data = load_database()
except Exception as e:
    raise RuntimeError(f"Failed to load database: {e}") from e
```

### Logging Setup

```python
import logging
import time

def setup_logger(name: str) -> logging.Logger:
    logger = logging.getLogger(name)
    logger.setLevel(logging.INFO)
    
    class UTCFormatter(logging.Formatter):
        converter = time.gmtime
    
    handler = logging.StreamHandler()
    handler.setFormatter(UTCFormatter("%(asctime)s - %(levelname)s - %(message)s"))
    logger.addHandler(handler)
    return logger

logger = setup_logger(__name__)
```

## Package Management (uv)

```bash
# Install uv
curl -LsSf https://astral.sh/uv/install.sh | sh

# Project setup
uv init my-project
uv add boto3 pydantic
uv add --dev pytest black ruff
uv sync

# Run script
uv run python main.py
```

## Pydantic Validation

```python
from pydantic import BaseModel, field_validator

class User(BaseModel):
    name: str
    age: int
    
    @field_validator("age")
    @classmethod
    def valid_age(cls, v: int) -> int:
        if v < 0 or v > 150:
            raise ValueError("Invalid age")
        return v
```

## Quick Checklist

- [ ] Shebang line with `uv`
- [ ] Type hints on all functions
- [ ] Google-style docstrings
- [ ] Imports grouped and sorted
- [ ] `if __name__ == "__main__":` guard
- [ ] Logging configured
- [ ] Input validation
- [ ] Specific exception handling
- [ ] `black` and `ruff` pass
- [ ] `pylint` score ≥ 9.0

## Detailed References

- **Code Quality Tools**: See [code quality tools](file:///Users/Devesh_Padmanabhan/.cursor/agent-engineering-handbook/skills/python-development/references/code-quality-tools.md) for Black, Ruff, mypy, and Pylint configuration
- **Package Management**: See [package management](file:///Users/Devesh_Padmanabhan/.cursor/agent-engineering-handbook/skills/python-development/references/package-management.md) for uv and dependency management
- **Standard Library**: See [standard library](file:///Users/Devesh_Padmanabhan/.cursor/agent-engineering-handbook/skills/python-development/references/standard-library.md)
- **Logging & Observability**: See [logging and observability](file:///Users/Devesh_Padmanabhan/.cursor/agent-engineering-handbook/skills/python-development/references/logging-observability.md)
- **Security & Validation**: See [security and validation](file:///Users/Devesh_Padmanabhan/.cursor/agent-engineering-handbook/skills/python-development/references/security-validation.md)
- **Error Handling**: See [error handling](file:///Users/Devesh_Padmanabhan/.cursor/agent-engineering-handbook/skills/python-development/references/error-handling.md)
- **Performance Optimization**: See [performance optimization](file:///Users/Devesh_Padmanabhan/.cursor/agent-engineering-handbook/skills/python-development/references/performance-optimization.md)
- **Troubleshooting & Debugging**: See [troubleshooting and debugging](file:///Users/Devesh_Padmanabhan/.cursor/agent-engineering-handbook/skills/python-development/references/troubleshooting-debugging.md)
- **Design Patterns**: See [design patterns](file:///Users/Devesh_Padmanabhan/.cursor/agent-engineering-handbook/skills/python-development/references/design-patterns.md)
- **CLI & User Experience**: See [CLI and user experience](file:///Users/Devesh_Padmanabhan/.cursor/agent-engineering-handbook/skills/python-development/references/cli-user-experience.md)
- **Modern Python Features**: See [modern Python](file:///Users/Devesh_Padmanabhan/.cursor/agent-engineering-handbook/skills/python-development/references/modern-python.md)
- **Async & Concurrency**: See [async and concurrency](file:///Users/Devesh_Padmanabhan/.cursor/agent-engineering-handbook/skills/python-development/references/async-concurrency.md)
- **Testing Patterns**: See [testing patterns](file:///Users/Devesh_Padmanabhan/.cursor/agent-engineering-handbook/skills/python-development/references/testing-patterns.md)
- **AWS Lambda**: See [AWS Lambda](file:///Users/Devesh_Padmanabhan/.cursor/agent-engineering-handbook/skills/python-development/references/aws-lambda.md)
- **AWS and Boto3**: See [AWS and Boto3](file:///Users/Devesh_Padmanabhan/.cursor/agent-engineering-handbook/skills/python-development/references/aws-boto3.md)