Skip to content

strip-align-padding

An alignment group exists to give the reader's eye a column to drop down. With two or more members the column carries information, where each row reads as a row in a table. With exactly one member the column becomes a single cell, and padding it to a width that no sibling matches adds visual noise without payoff.

strips the pre-: padding from every :-alignment context that resolves to a single member, so a one-key dict, a one-arg signature, or a one-field dataclass reads as plain code instead of a one-row table.

The rule operates on the :-shaped contexts that

covers (dict literals, annotated assignments at any scope, function-signature annotations, Google-style docstring sections) plus the single-expression match-arm context that covers. Multi-member groups whose :s sit on distinct lines and open at a shared column pass through this rule untouched, since the colon-alignment surfaces own them. A run whose rows open at differing columns realizes no shared column, so its padding strips here the way a singleton's does. The =-alignment from and the import-keyword alignment from carry their own one-member fallbacks and don't need pruning here.

Beyond the pre-: gap, the rule settles the run after a colon to one space wherever that colon introduces a value, so a stray x: int reads as x: int and a missing space in x:int fills to one. A match-arm body keeps the spacing

gives it, and a docstring entry's description stays as written.

also clears the padding just inside a bracket delimiter, where no alignment rule ever lines anything up. A space run directly after an opening (, [, or {, or directly before its closer, lines up with nothing, so int(a ) settles to int(a) and [ 1, 2 ] to [1, 2]. Each side strips on its own, and only where the pad shares a line with the content beside it, so a closer on its own line keeps its indent. The braces of an f-string or t-string replacement field are not delimiters this rule touches, wherein a debug f"{ total = }" keeps the spaces it echoes into its output. On a [ 1, 2, ], drops the comma while this rule clears both pads.

Configuration

KeyTypeDefaultMeaning
enabledbooltrueToggles the rule on or off.

is the cleanup pass for the alignment rules above it, so its only facet is enabled. Turning it off leaves one-member alignment contexts as one-row tables (a one-key dict reading with the same padding a multi-key dict would carry), which is rarely what a project wants in practice.

The Canonical Case

A one-key dict literal drops its pre-: padding, reading as a plain key-value pair rather than a one-row table.

single = {"only_key": compute_value()}

paired = {
    "first"  : 1,
    "second" : 2,
}

nested = {
    "outer": {"inner": "value"},
}
python

More Examples

Interior padding strips only when it shares a line with the content it pads. A closing bracket on its own line carries leading indent rather than a stranded space, so the rule leaves it while the same-line collection beside it tightens.

A docstring Args: section with one entry strips the pre-: padding on that entry. A section with two or more entries keeps its padding for align_colons to align in a separate pass.

A single-parameter signature with extra padding before its : is the canonical singleton shape, so the rule strips that padding to zero. Multi-parameter signatures collapsed onto one line do the same, because every : shares a line and has no column to align against. Spread across multiple lines, they stay padded for align_colons.

A pre-collapsed one-arm match carries one space before its colon. The rule strips the gap, leaving the : flush against the pattern.

The braces of an f-string or t-string replacement field are not the delimiters this rule touches, so a debug f"{ total = }" keeps the spaces it echoes into its output, whereas a real set literal beside it still strips.

A multi-line single-parameter signature strips its pre-: padding, since the lone parameter and its : share a line with non-zero width. A multi-line multi-parameter signature qualifies two distinct-line members, so the rule defers to align_colons and the padding stays.

The run after the colon settles to one space by measuring against the value's parenthesis-aware start, so the wrapping ( stays where it is. A {"key": (1, 2)} reads as {"key": (1, 2)} with the tuple's parentheses untouched.

A space run directly after an opening (, [, or { or directly before its closer lines up with nothing, so the rule pulls the delimiter tight against its content wherever the pad appears.

Class fields, dict literals, and function parameters interleave singleton contexts with multi-item groups. Singletons strip their pre-: padding while multi-line multi-item groups stay padded for align_colons. A multi-item group squashed onto one line strips too, because same-line : have no column to align against.

An annotated assignment that survives its aligned group as a lone row keeps the pre-: padding that once lined up with a column now gone. A module-level _handlers : Dict[Text, Callable] = {} and a function-body timeout : int = 30 each shed that padding down to name:, since no

run claims the column.

An unannotated self yields a None that splits the parameter slice into runs. A method with one annotated parameter after self forms a singleton run that strips its pre-: padding, as does a keyword-only parameter introduced by *. Two annotated parameters land a size-two run on one line, which strips because same-line : have no column to align against.

The run after a colon that aligns with nothing settles to one space, whichever context carries the colon. A one-key dict value, a lone annotated parameter, and a function-body annotation each read as name: value, collapsing a padded payload: dict and inserting the missing space into result:int.

No Change

Every singleton context already carries zero pre-: padding. The rule recognizes each gap as empty and emits no edits, so the output equals the input byte-for-byte and the pipeline reports no change.