skills/python-rest-docstrings/SKILL.md
Write consistent Python docstrings using reST roles for cross-references. Use when writing or updating docstrings, documenting Python code, or when the user mentions docstrings, reST, Sphinx, or API documentation.
npx skillsauth add morzecrew/agent-skills python-rest-docstringsInstall 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.
Write consistent, high-signal docstrings using reST roles for cross-linking. Optimize for: fast scanning in IDE/tooltips, friendly references, minimal redundancy with type hints, and explaining why/behavior rather than restating types.
Conventions: Type aliases/constants → immediate string literal. Classes/functions → PEP 257 docstring. Attributes/TypedDict keys → trailing docstring. Cross-references → reST roles (e.g. :class:`Foo, :meth:`Bar.baz), not plain text. For @overload and :class:typing.Protocol, follow the dedicated sections below.
Docstring immediately after the assignment. One line when possible. Use double backticks for literals (e.g. "dict", None). Prefer meaning and effects over restating the type.
RowFactory = Literal["tuple", "dict"]
"""Row format for fetch methods: ``"tuple"`` for sequences, ``"dict"`` for column-keyed dicts."""
IsolationLevel = Literal["repeatable read", "serializable"]
"""Supported transaction isolation levels."""
First line: short noun phrase. Then: lifecycle, concurrency/transaction semantics, invariants. Don’t list every attribute. Use roles for references. Add exactly one blank line between the docstring and the class definition below the docstring.
@attrs.define(slots=True)
class PostgresClient:
"""Async Postgres client with connection pooling and context-bound transactions.
Must be :meth:`initialize`d with a DSN before use. Uses context variables to
share a single connection per logical request, so nested :meth:`transaction`
blocks reuse the same connection and use savepoints.
"""
typing.ProtocolFor :class:typing.Protocol interfaces:
:raises for protocols unless an exception is a required part of the contract (usually unknown for interfaces).@overload.from typing import Protocol, AsyncContextManager
class AppRuntimePort(Protocol):
"""Application runtime contract for transactional execution.
Implementations provide a transaction boundary for usecases. Nested
transactions may be supported via savepoints; callers should not assume a
specific strategy unless explicitly documented by the implementation.
"""
def transaction(self) -> AsyncContextManager[None]:
"""Return an async context manager that scopes a transaction.
The returned context manager starts a transaction on entry and commits or
rolls back on exit according to implementation policy.
"""
...
Brief summary + behavioral details. Use reST field lists for params/returns/raises when needed. Explain what it does, what it returns, and edge cases. Document errors only when meaningful (e.g. :raises SomeError: When ...). Add exactly one blank line between the docstring and the function definition below the docstring.
async def fetch_one(self, query: str, *args: Any) -> Mapping[str, Any] | None:
"""Execute a query and return a single row.
Returns ``None`` when no rows match.
:param query: SQL query text.
:param args: Query parameters.
:returns: A row mapping or ``None``.
"""
@overloadFor overloaded callables, docstrings should primarily reflect the semantic differences between overload variants, not just duplicate a shared description.
Many IDEs display the docstring of the selected overload signature. If an
overload stub lacks a docstring, callers may see no documentation at all.
Therefore, each @overload should have a docstring.
Rules:
@overload stub must have a docstring.from typing import overload, Literal, Self
@overload
def register(self, op: str, *, inplace: Literal[True]) -> None:
"""Register an operation factory and mutate the registry.
Does not return a value. Raises :exc:`CoreError` if the operation
is already registered.
"""
...
@overload
def register(self, op: str, *, inplace: Literal[False] = False) -> Self:
"""Register an operation factory and return a new registry.
Does not mutate the original instance. Raises :exc:`CoreError`
if the operation is already registered.
"""
...
def register(self, op: str, *, inplace: bool = False) -> Self | None:
"""Register an operation factory.
Dispatches to the appropriate overload behavior based on ``inplace``.
"""
Fallback (no meaningful semantic difference):
@overload
def normalize(value: int) -> int:
"""Normalize a numeric value without changing its meaning."""
...
@overload
def normalize(value: str) -> str:
"""Normalize a numeric value without changing its meaning."""
...
def normalize(value: int | str) -> int | str:
"""Normalize a value without changing its meaning."""
...
Trailing docstring when public or needing clarification. Omit or keep very short for private fields (only if subtle or critical).
min_size: int = 2
"""Minimum number of connections in the pool."""
_ctx_depth: ContextVar[int] = ...
"""Transaction nesting depth used to manage savepoints."""
Class docstring: what the dict represents and where it’s used. Key docstrings: behavior, defaults, interpretation. If a key is optional (e.g. total=False), note what happens when absent.
class TransactionOptions(TypedDict, total=False):
"""Options for :meth:`PostgresClient.transaction`."""
read_only: bool
"""If true, transaction is read-only."""
isolation: IsolationLevel
"""Transaction isolation level (e.g. ``"repeatable read"``, ``"serializable"``)."""
| Role | Use for |
|------|--------|
| :class:`MyClass | Classes |
| :meth:`MyClass.method | Methods |
| :func:`my_function | Functions |
| :attr:`MyClass.attr | Attributes/properties |
| :mod:`package.module | Modules |
| :data:`CONSTANT | Module-level data/constants |
| :exc:`SomeError | Exceptions |
Same-class: :meth:`initialize is fine. Cross-module: use fully-qualified names, e.g. :class:`pkg.mod.Foo.
Attribute — Bad (repeats type): """Timeout as an integer."""
Good: """Timeout in seconds for acquiring a connection from the pool."""
TypedDict — Bad (no role): """Options for PostgresClient.transaction."""
Good: """Options for :meth:`PostgresClient.transaction`."""
:meth:`... / :class:`....@overload? → Each overload stub must have a docstring; document semantic differences per signature.typing.Protocol? → Document contract/semantics; avoid :raises unless mandated.Type alias / constant:
Thing = ... → """What it represents and how callers should interpret it."""
Class:
One-line summary, then key behaviors, lifecycle, invariants, and :meth:`X.foo / :class:`Y references.
Function / method:
One-line summary, then details; :param name: Meaning. :returns: Meaning. :raises SomeError: When.
Field:
field: Type = default → """Meaning, units, constraints, or why it exists."""
Compatible with PEP 257, reST, and IDE tooltips. Keep roles even in Markdown-only contexts; they stay readable and beneficial.
testing
Write, polish, review, or align documentation pages to a consistent, production-grade standard using the altitude model (a deliberate high-level to low-level descent), Diátaxis-based page contracts, a shared consistency layer, and a ship rubric. Use when creating, revising, reviewing, or aligning documentation pages, or when deciding where new doc content belongs.
development
Write consistent Python docstrings in Google style with typed sections. Use when writing or updating docstrings, documenting Python code, or when the user mentions docstrings, Google style, Napoleon, or API documentation.
development
Maintain CHANGELOG.md in Keep a Changelog format by updating Unreleased and version sections with user-relevant changes.
development
Format git commit messages and Pull Request titles using Conventional Commits with a deterministic gitmoji prefix. Use when generating or suggesting commit messages, PR titles, or when the user says "commit this", "create PR", "write a commit", "prepare PR", or similar.