Rule Composition
The per-rule pages walk each rule's canonical case in isolation, but the real question for most projects is what happens when several rules apply to the same block. The composition fixtures answer that question. Each case here pairs a small Python source with the rule set it activates, and the before/after pair shows the combined effect of those rules running together in Pipeline Order.
The cases are the same crate/tests/fixtures/composition/ set the binary's integration tests run against, so the rendered output on this page is the canonical answer to what Prose does when these rules compose.
The Canonical Case
One module-level constant carries the full composition story. The right-hand dict starts in a state that puts five rules in motion:
- The literal overflows
code-line-lengthon a single line, so breaks it apart. - Entries arrive in authorship order rather than alphabetical, so sorts them.
- Keys and values both want vertical columns, so and compute the padding.
- Values use the legacy
Union[…]form, so rewrites them to the|operator.
The five rules fire in Pipeline Order against the same block, reparsing between each so every rule downstream measures against the rewritten source rather than the original.
A module constant whose overflowing dict carries legacy union values, with target-version pinned to 3.10. The dict expands, sorts, and aligns its : column, while leaves the Optional/Union values in place because it is a display-only lint that reports findings rather than rewriting them.
from typing import Optional, Union
PRIMARY = {
"alpha" : Optional[str],
"beta" : Union[int, str],
"delta_long" : Union[bool, None],
"gamma" : Optional[int]
}
SECONDARY = "fallback"
All Cases
A run of aliased module imports arrives out of alphabetical order. reorders the statements first, then settles the
askeyword onto a shared column across the sorted run.Untyped module constants of varied widths widen onto a shared
, while flags=column underRATE_LIMITalone, the one name rebound after its first write, and leaves the write-once neighbors silent. The diagnostic range tracks the source offsets rather than the post-align statement positions.A function body assigns consecutive locals, some reused and some used once.
widens the=column across the whole run, and emits one diagnostic per once-used binding whose range tracks the source offset.Annotated class fields out of alphabetical order with varied name and default widths.
reorders them, then both the type-annotation:column and the default=column align across the sorted run.Single-statement
matcharms each return a long inline dict. Each dict expands one entry per line, its keys sort alphabetically, and the:column aligns within each arm, while the bodiless wildcard arm collapses back onto its pattern line.Single-statement
expands each list, and leaves those arm bodies wrapped because expansion forces a multi-line statement the arm cannot collapse.matcharms return inline lists that overflow the line budget.Single-statement
matcharms return inline collection literals carrying a trailing comma. removes the comma and collapses each body onto its pattern line, aligning the arm:column across the run.
shifts thatHEADER_VALIDATORSfits inline at its unaligned=, but=rightward to clear the longer_VALID_HEADER_VALUE_RE_BYTE. reserves the shifted column, so the dict stays expanded from the first pass rather than collapsing and re-exploding on the next.A function opens with single-target assignments and guards on a multi-line
BoolOp. The assignment run aligns its=column, and theBoolOp's comparison operators right-align in their own independent column below.A mixed run of bare imports and
fromimports, each kind out of order. sorts each kind in place, aligns theasandimportkeywords, and inserts one blank at the bare-to-from boundary.Three bare imports arrive out of order, each reached through a single attribute.
reorders the statements, and flags every one, each diagnostic anchored to the import as written rather than to its post-reorder position.A one-line call carrying a multi-entry dict argument settles to the canonical shape in one forward pass, where
explodes the dict, re-indents it to the keyword column, sorts the entries, and forms the:column. The dict entries land at the keyword's item-indent plus a step and the}at the keyword column.- explodes a crowded call to keyword form, sorts the keywords, and aligns their
=on one column, all in the sameformatpass. - runs ahead of , so a crowded call to a module function explodes to keyword form and then its keywords alphabetize in the same pass. The signature holds its source order, since positional parameters never reorder.
Three top-level class definitions out of alphabetical order with no spacing between them. reorders the declarations and settles the canonical two-blank-line cushion between top-level definitions.
A multi-line subscript assignment target condenses onto one line under
, then aligns its=with the single-line assignments around it under . Condensing first lets the target join the alignment run rather than sitting outside it with an operator stranded across a break.A multi-line tuple key condenses onto one line under
, then joins its single-line siblings so orders the keys and settles the:one space past the widest. The condensed key reads as the single clean member the later rules fold into their run rather than one stranded across a break.Module constants above a
# fmt: offblock sort alphabetically and align their=column. The suppressed block stays verbatim because the directive bounds its own scope, and the run boundary respects that bracket.A free-floating comment block, set off by a blank line above and below, sits between the module constants and a def-run that
reorders. lifts the constants into the leading band over its own pass while the detached block stays with the definitions, so the comment survives the reorder rather than being dropped.A long inline dict with out-of-order keys. The full dict cycle expands the dict, sorts the keys, and aligns the
:column across the wider rows, leaving the much shorter"zeta"row outside the shared column.A module opens with
from __future__ import annotationsahead of a constant and an over-large blank-line gap before the first definition. removes the import and collapses the gap down to the canonical two-line cushion between the constant and thedef.A module top carries
from __future__ import annotations, out-of-order aliased imports, and irregular spacing. The subset removes the unused future, sorts the imports, aligns theascolumn, and normalizes the blank-line cushion before the first function.A module opens with
from __future__ import annotationsahead of aliased imports that need no future. removes the import, leaving a residual blank line, and aligns theascolumn across the remaining run.A
removes the import, and emits one diagnostic per offending comment whose range tracks the post-removal offset.from __future__ import annotationsprecedes step-narration comments in a function body.The same call and dict as the canonical case, but with
'sexplodeknob cleared. leaves the multi-entry dict inline rather than exploding it, so finds no multi-line block to re-indent and the dict rides its keyword line whole. The freeze reaches the dict argument the canonical shape would otherwise expand to its own column.An exploded signature carrying a trailing
removes the comma and recognizes the bare emission as canonical, so a second pass leaves the output byte-identical.,strips to a shape both rules accept.A block of only
aligns within each.fromimports, external and local-package mixed. keeps external imports ahead of the local group, separates the two with one blank and adds no leading bare group, andA class with both annotated fields and methods declared out of order. The fields sort and align both
:and=as one group, the methods sort separately, and settles a one-blank cushion between every member.- resolves a callee defined below the call against the completed module bindings, so the crowded forward call explodes to keyword form and its keywords sort in the same pass that lifts the callee above its caller, leaving the file settled on the first run.
Aligning the
looks ahead to that aligned prefix and splits the names against it, so the run then aligns with every row inside the cap rather than one member overflowing.importkeyword to the widerapps.registry.longpathprefix would carryapps.io's names pastimport-line-length.With
sorts the imports as one flat block, adds no section dividers, and still aligns thegroup-imports = false,importkeyword across thefromlines.A class
cushions each one.__init__opens with a run of self-attribute assignments followed by out-of-order methods. The self-assigns align their=column inside__init__, the later methods sort alphabetically, andA multi-line docstring opens on the triple-quote line and carries an
Args:section. The opener and closer move to their own lines, the Args entries align their:column, and the prose paragraph wraps to the docstring budget.A multi-line docstring opens on the triple-quote line and carries a single overlong prose line. moves the opener to its own line and reflows the prose to fit the docstring budget.
An outer class and its nested helper class each carry out-of-order annotated fields. and the alignment rules act independently within each scope, giving the inner class its own
:and=columns.The keyword
spaces itsKWsits at the budget before=from the tightKW={...}toKW = {...}. accounts for the two columns that spacing adds, so the value expands once and holds rather than collapsing inline and exploding on the next pass.- splits a long import into repeated-prefix lines, and leaves the run untouched because every line already opens with the same
from ... importprefix. Single-statement
.matcharms return long inline dicts that overflow once on their arm line. Each dict expands and aligns its:column, but the keys keep source order because the rule set excludesMethods carry multi-line docstrings with opener and closer sharing prose lines, and no spacing between methods. The opener and closer move to their own lines, the prose reflows, and cushions the methods.
Out-of-order methods, one holding a
cushions the methods.matchwith single-statement return arms. The methods sort alphabetically, collapses each arm body onto its pattern line and aligns the:column, andOut-of-order methods, one opening its body with a
try/exceptblock. reorders the methods and cushions them, leaving the compound-statement body of the reordered method untouched.One signature loses its redundant
while flags its unannotated parameter, the two rules acting on the same-> Nonetodefin a single pass.Out-of-order methods carry a mix of single-line and multi-line docstrings. The methods reorder, single-line docstrings expand to multi-line form, multi-line openers and closers move to their own lines, and
cushions each.Two dicts in one scope, one multi-entry and one single-entry. The multi-row dict aligns its
:column, while the single-row dict has its pre-:padding stripped because a lone entry forms no alignment group.An overflowing single-line dict whose entries each carry a single-key nested dict. The outer dict expands and sorts, and after expansion each nested single-key dict stays inline as its own one-row group while the outer
:column aligns.Args entries with old-style continuations indented to
body_indent + 4rather than under the description.align_colonsshifts every colon to the longest-name column, anddocstring_wrapreflows the continuations into the post-align hanging-column shape.Class fields annotated with
OptionalandUnion. The:and=columns align, but the run splits into two adjacent alignment groups where the shorterhost/portnames share one column and the longerfallback_host/retry_countnames share another.The nested
partitions the row out unpadded the way an over-"b"value fits inline, yet padding its:to the wider"aaaaaaaaaaaaa"column would carry the row pastcode-line-length.max-shiftoutlier breaks off, and with the lone remaining key no column survives, so the dict stays unaligned within the cap rather than padding past it.A module constant whose overflowing dict carries legacy union values, with
target-versionpinned to3.10. The dict expands, sorts, and aligns its:column, while leaves theOptional/Unionvalues in place because it is a display-only lint that reports findings rather than rewriting them.- and agree on where the own-line comment belongs. The comment forward-attaches to
MAX_WORKERS, so banding hoists the pair aboveconfigureon the first pass rather than relocating the block only after a second format settles the blank-line texture. Out-of-order class methods each carry a run of body assignments. The methods sort and gain blank-line cushions, and each method's
=column aligns independently within its own body.A function opens with single-target assignments ahead of a
matchwhose arms return one binding each. The pre-match run aligns its=column, and collapses each arm body onto its pattern line with the:column aligned.An out-of-order single-line class stub sandwiched between block-bodied classes reorders into place, and
settles the canonical two-blank-line cushion on both sides of the stub, so and reach a fixed point in one pass rather than trading the gap back and forth.Bare, external
from, and local-package imports scrambled together, withmyappdeclared first-party. resolves them into the three canonical groups, separates each with one blank, and aligns the keyword within each group.A short inline dict with out-of-order keys that fits the line budget. reorders the keys in place and the dict stays inline, because the fitting width gives
no reason to expand.A typed signature and an
Args:section whose names diverge by design.align_colonstreats the two as independent groups with separate columns, anddocstring_wrapwraps the Args descriptions at the Args hanging column rather than the signature's.A single-line docstring whose content would exceed the docstring budget once expanded. The docstring expands to multi-line form and reflows the body across multiple lines to fit the budget.
Methods each carry a single-line docstring with no blank line between them. The docstrings expand to multi-line form and inserts the one-blank cushion between the methods.
A single-line docstring in plain double quotes canonicalizes to
"""under , then drops it to the multi-line shape. The reframe runs first, so the requoted one-liner expands in the same pass.A dict handed to a call as its only argument hugs the call paren, its entries one per line at the call's item-indent and the
}closing against the call. leaves the single-argument call inline rather than exploding it, so the dict opens on the call line itself.An already-expanded dict with out-of-order string keys and a trailing comma. sorts the keys, drops the final comma, and aligns the
:column across the rows.Module-level functions out of order with no spacing between them. reorders the definitions and settles the canonical two-blank-line cushion around each top-level function.
A one-line call carrying an over-wide tuple argument settles in one forward pass, where
explodes the tuple, re-indents it to the keyword column, and orders the keywords with aligning their=. The tuple elements land at the keyword's item-indent plus a step and the)at the keyword column, the same seating alistordictargument takes.A five-parameter typed signature holds its source order, since the parameters never reorder. It expands to one per line, aligns the annotation
:column, and aligns the default=column across the optional run.An overflowing single-line dict whose values are
OptionalandUnionexpressions. The dict expands, sorts its keys, and aligns the:column, leaving the legacy union values on the right untouched.An expanded signature with typed parameters of varying widths and defaults. The
:and=columns align, but the run splits into two adjacent groups where the narrowhost/portshare one column and the widertimeout_seconds/retriesshare another.
How Composition Resolves
Each case's pipeline runs the listed rules in canonical order, reparsing between rules. A rule downstream of another sees the rewritten source from the upstream rule, not the original source. The cases here cover the common interaction shapes.
Layout Before Alignment
running upstream of commits the per-line shape against which the alignment columns are computed.Reorder Before Align
running upstream of settles the entry order, meaning the alignment math measures against the final column positions rather than the source ones.Docstring Discipline Before Wrap
and running upstream of settle the quote placement before the body rewrap measures budgets.Module Reorder Around a Block Marker
's module-level branch reorders the assigns above and below a# fmt: off block while the bracketed lines stay verbatim. The suppression directive bounds its own scope, so and fire freely on every assign outside the bracket and the run boundary respects the marker.Module constants above a # fmt: off block sort alphabetically and align their = column. The suppressed block stays verbatim because the directive bounds its own scope, and the run boundary respects that bracket.
bar_baz = 3
foo = 2
zebra = 1
# fmt: off
matrix = [[0.7, 0.1, 0.1],
[0.1, 0.7, 0.1],
[0.1, 0.1, 0.7]]
# fmt: on
For the per-rule canonical case, click any rule chip above. For the deterministic order the pipeline runs in, see the Pipeline Order reference. For the runner that drives the composition, see the Pipeline primitive. For the full rule catalog, see the Rules.