SKILL.md
$27
Frozen dataclasses are immutable — no accidental mutation
**Discriminated unions with Literal:**
from dataclasses import dataclass
from typing import Literal
@dataclass
class Success:
status: Literal["success"] = "success"
data: str
@dataclass
class Failure:
status: Literal["error"] = "error"
error: Exception
RequestState = Success | Failure
def handle_state(state: RequestState) -> None:
match state:
case Success(data=data):
render(data)
case Failure(error=err):
show_error(err)
**NewType for domain primitives:**
from typing import NewType
UserId = NewType("UserId", str)
OrderId = NewType("OrderId", str)
def get_user(user_id: UserId) -> User:
# Type checker prevents passing OrderId here
...
**Protocol for structural typing:**
from typing import Protocol
class Readable(Protocol):
def read(self, n: int = -1) -> bytes: ...
def process_input(source: Readable) -> bytes:
# Accepts any object with a read() method — no inheritance required
return source.read()
## Python-Specific Error Handling
Chain exceptions with `from err` to preserve the original traceback:
try:
data = json.loads(raw)
except json.JSONDecodeError as err:
raise ValueError(f"invalid JSON payload: {err}") from err
## Structured Logging
Use a module-level logger with `%s` formatting (deferred string interpolation):
import logging
logger = logging.getLogger("myapp.widgets")
def create_widget(name: str) -> Widget:
logger.debug("creating widget: %s", name)
widget = Widget(name=name)
logger.debug("created widget id=%s", widget.id)
return widget
## Optional: ty
For fast type checking, consider [ty](https://docs.astral.sh/ty/) from Astral (creators of ruff and uv). Written in Rust, significantly faster than mypy or pyright.
uvx ty check # run directly, no install needed
uvx ty check src/ # check specific path
pyproject.toml
[tool.ty]
python-version = "3.12"