Skip to content

step-narration

A numbered-step comment inside a function body (# 1. ..., # Step 2: ...) is usually a signal that the function is doing too many things. Each numbered step wants to be its own helper with a name that captures what the step does, and the comment is standing in for that name.

surfaces own-line numbered-step comments as a lint, leaving the extract-to-helper decision to a future refactor pass.

Two shapes are recognized: the bare numeric-dot form # N. text and the Step-prefixed forms # Step N: text and # Step N. text (case-insensitive on the keyword). Inline comments at the end of a code line stay quiet, since they annotate the line rather than narrate a procedure. Pragma-style comments (# type: ignore, # noqa) stay quiet too, since they carry a different meaning. The lint fires at every scope (module-level, function body, class body, nested block) and never rewrites.

Configuration

KeyTypeDefaultMeaning
enabledbooltrueToggle the rule on or off

The Canonical Case

A module-level own-line numbered-step comment surfaces the lint.

python
# 1. normalize input
# 2. emit the result


def process(payload):
    return payload.strip()

More Examples

A numbered-step comment inside a class body is flagged the same way as one inside a function. The own-line filter passes and the enclosing scope plays no part in the match.

A run of numbered-step comments earns one diagnostic per matching comment, each range pinned to its own comment in turn. The mix of # 1., # 2., and # Step 3: shapes all match independently rather than collapsing into a single report.

A leading # 1. text comment matches the numeric-dot shape and earns a diagnostic recommending the step move into a named function. The digit followed by . and whitespace is the trigger.

No Change

A # fmt: off block carries the same suppression weight against lint diagnostics as it does against edits. A numbered-step comment sitting inside the block escapes the rule's emission path entirely.

No Change

An end-of-line comment that happens to match the numbered-step shape is excluded by the own-line filter. Only comments occupying their own line earn diagnostics, so a trailing # 1. rides alongside its statement untouched.

No Change

A pragma comment routed through ruff_python_trivia::is_pragma_comment is invisible to the rule, even when its body opens with a digit or mimics another tool's directive shape. Lines like # noqa: F401 and # type: ignore pass through silently.

No Change

A module carrying no numbered-step comments produces no diagnostics. The rule is lint-only, so any pass over clean source leaves the text unchanged and reports nothing.

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