Skip to content

restated-types

restated-types reports the parenthesized type in a name (type): description docstring entry when the signature or the class body already annotates that member, anchoring the diagnostic on the type group rather than the whole entry and leaving the description it introduces as written. The docstring copy restates in prose what the annotation states in code, and only the annotation is checked, because a type checker reads it on every run whereas nothing reads the docstring type. The written copy can stay wrong for the life of the function as a result, and the tools that render a docstring render the signature beside it anyway, an editor hover and help() both printing the parameter list above the body.

An entry resolves against the definition whose body its docstring opens. A parameter-documenting section reads the enclosing function's parameters, the *args and **kwargs variadics included, because an entry name drops its star prefix before it resolves. An Attributes: section reads the class body's annotated fields. Google style spells the parameter heading several ways, so Args:, Arguments:, Parameters:, Keyword Args:, Keyword Arguments:, Other Args:, Other Arguments:, Other Params:, and Other Parameters: all document parameters alike.

No report is made where the docstring is the only place a type is written. A parameter with no annotation leaves the docstring type as the sole copy, which is the gap signature-annotations reports in the code instead. An entry naming no member of the set its section documents resolves against nothing, so a Returns: or Raises: entry that shares a parameter's name stays silent. A module docstring documents no signature and no class body, so every entry inside it stays unresolved.

Nothing here is rewritten, because deciding which of two disagreeing types is correct takes a reader rather than a formatter.

Configuration

KeyTypeDefaultMeaning
enabledbooltrueTurns the rule on or off.

The Canonical Case

dial annotates host: str and timeout: float, and its docstring's Args: entries restate the same types as (str) and (float). Both parenthesized types are reported, each diagnostic anchored on the type group rather than the whole entry, because a type checker reads the annotation on every run whereas nothing reads the docstring copy, so the description after it is left to say what the parameter is for.

def dial(host: str, timeout: float) -> Session:
    """
    Open a session against a remote.

    Args:
        host (str): The remote to dial.
        timeout (float): Seconds before the dial is abandoned.
    """
python

More Examples

relay annotates *args: int and **kwargs: str, and its Args: entries *args (int) and **kwargs (str) restate both types. Both entries are reported, because an entry name drops its * or ** prefix before it resolves against the signature's variadic parameters.

Remote annotates host: str in its class body, binds port = 8080 without an annotation, and declares no proxy, while its docstring's Attributes: section documents all three with types. Only host (str) is reported, because port has no annotation for the docstring copy to restate and proxy resolves against no member of the class body.

No Change

resolve annotates value: int and error: str, and its docstring names value (int) under Returns: and error (str) under Raises:, each sharing a parameter's name and type. Neither entry is reported, because only a parameter-documenting section resolves against the signature, and Returns: and Raises: are not among them.

No Change

dial(host, timeout) carries no annotation, and its docstring's Args: entries write host (str) and timeout (float). Neither entry is reported, because an unannotated parameter leaves the docstring as the only place its type is written, so there is no annotation to check the copy against.

For per-line opt-outs, the Suppression chapter covers the # prose: ignore[restated-types] directive.