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 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 legacy-union-syntax leaves the Optional/Union values in place because it is a display-only
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.
alphabetizereorders the statements first, thenalign-importssettles theaskeyword onto a shared column across the sorted run.Untyped module constants of varied widths widen onto a shared
=column underalign-equals, whilereassigned-constantsflagsRATE_LIMITalone, the one name rebound after its first write, and leaves the write-once neighbors silent. Thediagnostic range tracks the source offsets rather than the post-align statement positions.A function body assigns consecutive locals, some reused and some used once.
align-equalswidens the=column across the whole run, andsingle-use-variablesemits onediagnostic per once-usedbinding whose range tracks the source offset.Annotated class fields out of alphabetical order with varied name and default widths.
alphabetizereorders 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
matcharms return inline lists that overflow the line budget.collection-layoutexpands each list, andalign-match-caseleaves those arm bodies wrapped because expansion forces a multi-line statement the arm cannot collapse.Single-statement
matcharms return inline collection literals carrying a trailing comma.strip-trailing-commasremoves the comma andalign-match-casecollapses each body onto its pattern line, aligning the arm:column across the run.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.alphabetizesorts each kind in place,align-importsaligns theasandimportkeywords, andblank-linesinserts one blank at the bare-to-from boundary.Three bare imports arrive out of order, each reached through a single attribute.
alphabetizereorders the statements, andbare-importsflags every one, eachdiagnostic anchored to the import as written rather than to its post-reorder position.Three top-level class definitions out of alphabetical order with no spacing between them.
alphabetizereorders the declarations andblank-linessettles the canonical two-blank-line cushion between top-level definitions.Module constants above a
# fmt: offblock sort alphabetically and align their=column. The suppressed block stays verbatim because the directive bounds its ownscope , and the run boundary respects that bracket.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-largeblank-line gap before the first definition.unused-future-annotationsremoves the import andblank-linescollapses 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 theblank-line cushion before the first function.A module opens with
from __future__ import annotationsahead of aliased imports that need no future.unused-future-annotationsremoves the import, leaving a residualblank line , andalign-importsaligns theascolumn across the remaining run.A
from __future__ import annotationsprecedes step-narration comments in a function body.unused-future-annotationsremoves the import, andstep-narrationemits onediagnostic per offending comment whose range tracks the post-removal offset.A block of only
fromimports, external and local-package mixed.alphabetizekeeps external imports ahead of the localgroup ,blank-linesseparates the two with one blank and adds no leading bare group, andalign-importsaligns within each.A class with both annotated fields and methods declared out of order. The fields sort and align both
:and=as onegroup , the methods sort separately, andblank-linessettles a one-blank cushion between every member.A class
__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, andblank-linescushions each one.A multi-line
docstring opens on the triple-quote line and carries anArgs: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.docstring-framemoves the opener to its own line anddocstring-wrapreflows the prose to fit the docstring budget.An outer class and its nested helper class each carry out-of-order annotated fields.
alphabetizeand the alignment rules act independently within eachscope , giving the inner class its own:and=columns.import-layoutsplits a long import into repeated-prefix lines, andalign-importsleaves the run untouched because every line already opens with the samefrom ... 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 excludesalphabetize.Methods 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, andblank-linescushions the methods.Out-of-order methods, one holding a
matchwith single-statement return arms. The methods sort alphabetically,align-match-casecollapses each arm body onto its pattern line and aligns the:column, andblank-linescushions the methods.Out-of-order methods, one opening its body with a
try/exceptblock.alphabetizereorders the methods andblank-linescushions them, leaving the compound-statement body of the reordered method untouched.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, andblank-linescushions 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 noalignment 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 adjacentalignment groups where the shorterhost/portnames share one column and the longerfallback_host/retry_countnames share another.A module constant whose overflowing dict carries legacy union values, with
target-versionpinned to3.10. The dict expands, sorts, and aligns its:column, whilelegacy-union-syntaxleaves theOptional/Unionvalues in place because it is a display-onlylint that reports findings rather than rewriting them.A five-parameter signature with out-of-order typed parameters. The parameters regroup into required-then-optional alphabetical runs, expand to one per line, align the
annotation :column, and align the default=column across the optional run.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 onebinding each. The pre-match run aligns its=column, andalign-match-casecollapses each arm body onto its pattern line with the:column aligned.Bare, external
from, and local-package imports scrambled together, withmyappdeclared first-party.alphabetizeresolves them into the three canonical groups,blank-linesseparates each with one blank, andalign-importsaligns the keyword within eachgroup .A short inline dict with out-of-order keys that fits the line budget.
alphabetizereorders the keys in place and the dict stays inline, because the fitting width givescollection-layoutno 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 anddocstring-wrapreflows the body across multiple lines to fit the budget.Methods each carry a single-line
docstring with noblank line between them. The docstrings expand to multi-line form andblank-linesinserts the one-blank cushion between the methods.An already-expanded dict with out-of-order string keys and a trailing comma.
alphabetizesorts the keys,strip-trailing-commasdrops the final comma, andalign-colonsaligns the:column across the rows.Module-level functions out of order with no spacing between them.
alphabetizereorders the definitions andblank-linessettles the canonical two-blank-line cushion around each top-level function.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
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.