Use this before writing Python code, creating Python scripts, modifying Python files, or when user asks to "write python", "create a python script", "implement in python". TRIGGER when starting any Python development task.
Use this before writing Python code, creating Python scripts, modifying Python files, or when user asks to "write python", "create a python script", "implement in python". TRIGGER when starting any Python development task.
Python Development with UV
Modern Python development using uv for package management, PEP 723 for single-file scripts, and best-in-class tooling.
Quick Start
Single-File Scripts (Default)
By default, create self-contained scripts using PEP 723 format:
#!/usr/bin/env -S uv run --script# /// script# dependencies = [# "typer",# "rich",# ]# ///"""
Script description and usage examples.
Usage:
uv run python3 script.py --help
uv run python3 script.py --option value
"""import sys
# ... rest of script
All tooling configuration is centralized in /tests/pyproject.toml.
Run from /tests directory:
cd tests
# Run tests
uv run pytest
uv run pytest -v # verbose# Type checking
uv run pyright
uv run pyright --stats
# Linting & formatting
uv run ruff check ../.opencode/skill
uv run ruff check --fix ../.opencode/skill
uv run ruff format ../.opencode/skill
Use structured docstrings with Args, Returns, and Raises sections:
defcalculate_total(items: list[dict], tax_rate: float = 0.0) -> float:
"""Calculate the total cost of items including tax.
Args:
items: List of item dictionaries with 'price' keys
tax_rate: Tax rate as decimal (e.g., 0.08 for 8%)
Returns:
Total cost including tax
Raises:
ValueError: If items is empty or tax_rate is negative
"""ifnot 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)
Best Practices
Use uv exclusively - Never run python3 or pip directly
Start with PEP 723 - Single-file scripts by default
Minimize dependencies - Try stdlib first
Test incrementally - Build and test feature by feature
Use type hints - Catch errors early with pyright
Format with ruff - Consistent code style
Follow exit codes - 0 for success, 1 for runtime errors, 2 for validation
Common Pitfalls
Mutable Default Arguments
Never use mutable objects (lists, dicts) as default argument values:
# BAD - The list persists across calls!defadd_item(item, items=[]):
items.append(item)
return items
add_item("a") # ['a']
add_item("b") # ['a', 'b'] - Unexpected!# GOOD - Use None and create inside functiondefadd_item(item, items=None):
if items isNone:
items = []
items.append(item)
return items
Bare Except Clauses
Never use bare except: - always catch specific exceptions:
# BAD - Catches everything including KeyboardInterrupttry:
do_something()
except:
pass# GOOD - Catch specific exceptionstry:
do_something()
except (ValueError, TypeError) as e:
print(f"Error: {e}", file=sys.stderr)
sys.exit(1)
Comparing with None
Use is / is not for None comparisons:
# BADif value == None:
...
# GOODif value isNone:
...
Security
Environment Variables
Store secrets in .env files, never in code:
# Load from .env filefrom dotenv import load_dotenv
import os
load_dotenv()
api_key = os.getenv("API_KEY")
ifnot api_key:
print("Error: API_KEY not set", file=sys.stderr)
sys.exit(1)
Required Practices
Never commit secrets - Add .env to .gitignore
Never log secrets - Don't print API keys, passwords, or tokens
Never hardcode - Use environment variables for all credentials
Validate early - Check for required env vars at startup