align-colons
AlignmentPads the space before : so consecutive dict entries, annotated assignments, signature annotations, and docstring entries share one column, with a docstring entry's parenthesized type in a column of its own.
strip-stranded-padding removes the padding before the : in every :-alignment group that has a single member, so a one-key dict, a one-parameter signature, or a one-field dataclass reads as plain code rather than a one-row table. An alignment group with two or more members gives the eye a column to drop down, whereas a group with exactly one member has no sibling for its padding to line up with, so the padding adds width and nothing else.
The rule reads the : contexts align-colons covers (dict literals, annotated assignments at any scope, function-signature annotations, Google-style docstring sections) plus the single-statement match-arm context align-match-case covers. A group of two or more members whose colons sit on separate lines and whose rows start at one shared indent passes through this rule unchanged, since the colon-alignment rules own it. A run whose rows start at differing indents resolves no shared column, so its padding is stripped here the way a single member's is. The = alignment of align-equals and the import-keyword alignment of align-imports handle their own one-member groups and need no stripping here.
Past the gap before the :, the rule settles the gap after a colon to one space wherever that colon introduces a value, so a stray x: int becomes x: int and x:int gains its missing space. A match-arm body keeps the spacing align-match-case writes, and a docstring entry's description stays as written.
strip-stranded-padding also removes the padding just inside a bracket delimiter, where no alignment rule ever lines anything up. A run of spaces directly after an opening (, [, or {, or directly before its closer, lines up with nothing, so int(a ) becomes int(a) and [ 1, 2 ] becomes [1, 2]. Each side is stripped on its own, and only where the padding 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 reads, so a debug f"{ total = }" keeps the spaces it echoes into its output. On [ 1, 2, ], strip-trailing-commas removes the comma while this rule removes both pads.
| Key | Type | Default | Meaning |
|---|---|---|---|
enabled | bool | true | Turns the rule on or off. |
strip-stranded-padding is the cleanup pass for the alignment rules above it, so its only facet is enabled. Turning it off leaves a one-member alignment group as a one-row table (a one-key dict carrying the same padding a multi-key dict would), which is rarely the layout a project chooses.
single = {"only_key" : compute_value()} carries one key, paired spreads two entries across separate lines, and nested carries a single "outer" entry whose value is the single-entry {"inner" : "value"}. strip-stranded-padding removes the padding before the : in single and in both levels of nested, so each reads as a plain key-value pair rather than a one-row table, whereas paired's entries keep their padding for align-colons.
single = {"only_key": compute_value()}
paired = {
"first" : 1,
"second" : 2,
}
nested = {
"outer": {"inner": "value"},
}
kept's closing ] sits on its own line, carrying ordinary indentation rather than the same-line space beside a bracket that strip-stranded-padding reads, and stripped = [ 1, 2 ] carries that same-line padding around its values. kept stays untouched, and stripped is written as [1, 2].
fetch's signature spans several lines but carries only timeout : float,, the lone parameter, whereas render's carries two parameters, template : str, and context : dict,, each on its own line. strip-stranded-padding removes the padding before timeout's :, writing timeout: float,, and leaves render's two parameters to align-colons, so their padding stays.
case "only" : icon = "wrench" is the only arm in its match, already collapsed onto one line with one space before its :. strip-stranded-padding removes that gap, leaving the : flush against "only".
fetch's docstring Args: section carries one entry, timeout : Maximum seconds to wait before giving up., whereas render's carries two, template and context. strip-stranded-padding removes the padding before timeout's :, writing timeout:, and leaves render's two entries to align-colons, so their padding stays.
fetch(timeout : float) carries a single parameter, the plainest singleton form, whereas store and render write several parameters on one line each. strip-stranded-padding removes the padding on every one of them, writing timeout: float for fetch and tightening each of store's and render's parameters too, because a same-line : has no column to align against.
f"{ value }" and f"{ total = }" place their braces around an f-string replacement field rather than the bracket delimiters strip-stranded-padding reads. Both keep their interior spaces, total = included, whereas padded = { 1, 2 } is a set literal, so the rule writes it as {1, 2}.
int(count ) pads only before its closing ), wrap( 1) pads only after its opening (, and items = [ 1, 2 ] and mapping = { "key": 1 } pad on both sides. strip-stranded-padding pulls each delimiter tight against its content wherever the pad sits, writing int(count), wrap(1), [1, 2], and {"key": 1}.
{"key": (1, 2)} pads its : with three spaces before the tuple (1, 2). strip-stranded-padding settles the gap to one space, measuring from the tuple's own opening ( so the parentheses stay exactly where they are, and writes {"key": (1, 2)}.
Solo.only_field, single_dict's one entry, and lone_param's x are each the only member in their group, so there is no sibling column for them to line up with. Their padding before the : is removed.
Pair's first and second, and paired_dict's two entries, each have a sibling on a separate line, so their padding stays for align-colons to use. two_params squashes first and second onto one line, and their padding is removed too, because a : sharing a line with another has no column to align against.
_handlers : Dict[Text, Callable] = {} sits at module scope and timeout : int = 30 sits inside configure, each the lone annotated assignment in its group, so align-colons sets no shared column for the padding before the :. strip-stranded-padding removes that padding down to name: at both scopes, because no other row remains to align with.
self carries no annotation in fetch, store, or render, so it never joins the run of annotated parameters strip-stranded-padding groups by :. fetch's timeout and store's keyword-only ttl each form a singleton run, and their padding before the : is removed. render's template and context form a two-member run on the same line, and their padding is removed too, because a same-line : has no column to align against.
A : that aligns with nothing appears in a one-key dict as "only": 1, in a signature as payload: dict, and in an annotation as result:int. Each is written with exactly one space after the :, so the dict and the signature lose their extra spaces and the annotation gains its missing one, every one ending up as plain name: value.
fetch's timeout, single's one entry, Solo.only_field, and render's docstring template entry are each a singleton context that already carries no padding before the :. strip-stranded-padding finds every gap already empty and emits no edit, so the output equals the input byte for byte and the pipeline reports no change.
_openers is assigned a dict with no space after any :, above CHECK_DELAY = 100. strip-stranded-padding writes a space after each :, which widens the _openers row by three columns.
align-equals leaves the two = unaligned, because it measures the row at the width it has once that edit is written, and padding _openers onto a shared column with CHECK_DELAY would take the row past the 40-column budget.
some_function( argument_one_here, argument_two_here ) carries a space just inside each parenthesis, and the row crosses the 66-column budget by exactly those two spaces. strip-stranded-padding removes them, and reflow-calls measures the argument list at the width that removal leaves, so the call stays on one row rather than exploding and joining back once the padding is gone.
One key of _hash_action carries a stranded space before its closing parenthesis, (False, False, False, True ), and strip-stranded-padding removes it. align-colons pads the run onto one : column, because it measures each row at the width it has once that removal is written, whereas the padded width would have read as a breach of the 40-column budget and the run would have skipped its column over a breach that never happens.
tagdefs writes two spaces after each key's :, and alphabetize-siblings moves "stderr" ahead of "stdout", the comment above "stdout" moving with it. The "stdout" value, last after the sort, stays on one row at exactly the 40-column budget, because reflow-collections measures a value from the plain ": " past its key rather than from the two spaces the source wrote, and the row is written back at that width, whereas the "stderr" value explodes.
self.loggerMap is assigned a dict with spaces just inside its braces, and m a dict with no space after any :. strip-stranded-padding removes the spaces from the first and writes a space after each : in the second, and reflow-collections measures each literal at the width those edits leave, so the first stays on its row and only the second, now past the 40-column budget, explodes.
_FORMATS lists FMT_BINARY and FMT_XML in the order alphabetize-siblings leaves them, so the last entry gains no separator, and align-colons pads FMT_XML onto a : column that puts its row exactly at the 45-column budget. The column stays, because reflow-collections measures that row at exactly the budget rather than past it, and the padding is not stripped back.
non_adjacent.append( (la, lb, 0) ) carries a space after append( and a space before its closing ), and the row crosses the 40-column budget by exactly those two spaces. strip-stranded-padding removes both, and reflow-collections measures the tuple at the width that removal leaves, so the tuple stays on its row, the first space narrowing the column the tuple starts at and the second narrowing the text trailing it.
paired lists three entries with uneven spacing before their :, and single lists one entry written "only_key" : 1. align-colons pads paired's : into one column one space past "second", and strip-stranded-padding removes the stray space in single, leaving "only_key": 1, because a lone entry forms no alignment group.
dirlist.extend([ ... ]) writes a space just inside each bracket of its list, and strip-stranded-padding reports both. reflow-collections explodes the list, rebuilding the bracket interior and carrying that padding away before the strip is written, and the first member call ends up alone on a row inside the exploded list with no padding ahead of it. The _os.path.expanduser(...) call is measured from that row and explodes, because at that column it crosses the 60-column budget, rather than being measured from the row the source wrote.
store writes ttl : int with a space before the :, and its one-line signature crosses the 40-column budget by exactly that space. strip-stranded-padding removes it, and reflow-signatures measures the signature at the width that removal leaves, so it stays on one line rather than exploding and joining back on a later pass.
The one Args: entry of fetch is written timeout : Maximum seconds to wait before giving up., with a space before its :, and its description runs past the 40-column docstring budget. strip-stranded-padding removes the space, because a lone entry has no sibling column to share, and wrap-docstrings breaks the description at the budget and hangs the continuation under the start of the text as the strip leaves it, one column narrower than the source, so both rules agree on where the continuation sits.
Pads the space before : so consecutive dict entries, annotated assignments, signature annotations, and docstring entries share one column, with a docstring entry's parenthesized type in a column of its own.
Pads the space before = so consecutive assignments, annotated parameter defaults, and an exploded call's keyword arguments share one column.
Pads the space before the import keyword across consecutive from imports, or before as across consecutive aliased imports, so the keywords share one column.
Folds each single-statement case arm onto one line and pads the space before its : so consecutive arms share one column.
Removes the trailing comma from a collection, signature, call, class base list, or type-parameter list, leaving tuples alone.