skills/python-best-practices/SKILL.md
Use when reading or writing Python files (.py, pyproject.toml, requirements.txt).
npx skillsauth add awfixers-stuff/opencode-config python-best-practicesInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
Follows type-first, functional, and error handling patterns from CLAUDE.md. This skill covers language-specific idioms only.
Use Python's type system to prevent invalid states at type-check time.
Frozen dataclasses for immutable domain models:
from dataclasses import dataclass
from datetime import datetime
@dataclass(frozen=True)
class User:
id: str
email: str
name: str
created_at: datetime
# 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()
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
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
For fast type checking, consider 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"
When to choose:
ty — fastest, good for CI and large codebases (early stage, rapidly evolving)pyright — most complete type inference, VS Code integrationmypy — mature, extensive plugin ecosystemdevelopment
Use when starting dev servers, watchers, tilt, or any process expected to outlive the conversation. Provides zmx session management patterns for long-lived processes.
development
Zig testing skill for writing and running tests. Use when using zig build test, writing comptime tests, using test filters, working with test allocators to detect leaks, or using Zig's built-in fuzz testing (0.14+). Activates on queries about Zig tests, zig test, zig build test, comptime testing, test allocators, Zig fuzz testing, or detecting memory leaks in Zig tests.
development
Zig debugging skill. Use when debugging Zig programs with GDB or LLDB, interpreting Zig runtime panics, using std.debug.print for tracing, configuring debug builds, or debugging Zig programs in VS Code. Activates on queries about debugging Zig, Zig panics, zig gdb, zig lldb, std.debug.print, Zig stack traces, or Zig error return traces.
tools
Zig cross-compilation skill. Use when cross-compiling Zig programs to different targets, using Zig's built-in cross-compilation for embedded, WASM, Windows, ARM, or using zig cc to cross-compile C code without a system cross-toolchain. Activates on queries about Zig cross-compilation, zig target triples, zig cc cross-compile, Zig embedded targets, or Zig WASM.