unused-future-annotations
FormattingProse removes from __future__ import annotations lines that no longer carry their weight on the target Python version.
Union[X, Y] and Optional[X] come from the typing module, were the canonical union shapes for years, and still read clearly today. On Python 3.10 and later, the PEP 604 pipe-union shapes (X | Y, X | None) read more directly and consume one fewer import, which over the course of a large codebase adds up to genuinely clearer type signatures.
The rule fires only on projects whose target-version is 3.10 or higher, where the pipe-union shapes are runtime-supported. Pre-3.10 projects and projects with target-version unset stay quiet, since recommending the pipe form on those projects would mislead. The lint is non-rewriting, so the diagnostic surfaces without touching the source.
The rule fires. Optional[X] reads as X | None in the diagnostic message.
| Key | Type | Default | Meaning |
|---|---|---|---|
enabled | bool | true | Toggle the rule on or off |
The target-version field from the top-level Configuration gates the lint per project.
A from typing import Optional followed by Optional[X] surfaces the X | None.
from typing import Optional
x: Optional[int] = None
from typing import Optional as Opt binds Opt to typing.Optional, so Opt[int] resolves through the alias and flags the same as the bare name.
A legacy Optional[int] nested as the value type of dict[str, Optional[int]] is flagged on the inner expression. The enclosing subscript, rather than the statement, is passed as the parent for the parenthesized range.
Parentheses wrapping a subscript, as in (Optional[int]), are folded into the
The rule emits no edits, so every pass leaves the source byte-for-byte identical. A mix of legacy Optional[int] and Union[int, str] int | None form all pass through as written.
After import typing, the typing.Optional[int] resolves through the attribute chain back to typing.Optional and flags identically to the bare Optional[int] form.
Modern | are never flagged. The walker inspects only Subscript shapes, so the binary BitOr expression backing int | None slips past entirely.
A typing import naming something other than Optional or Union is not flagged. The walker resolves List[int] to typing.List and falls through the suffix
Prose removes from __future__ import annotations lines that no longer carry their weight on the target Python version.
For per-line opt-outs, the Suppression chapter covers the # prose: ignore[legacy-union-syntax] directive.