alphabetize
OrderingAlphabetizes import siblings, dict-key blocks, and class-body members.
A reader opening a module wants its shape to declare itself: what it draws on, what it defines, and the values that fall out of those definitions. When constants sit wherever they were typed, that shape blurs, a configuration value buried between two functions reading no differently from a table derived from them.
gathers module-level constants into two bands, a leading band directly below the imports and a trailing band beneath the definitions, so a module reads top to bottom as its imports, its leading constants, its definitions, then the constants derived from them.| Band | Holds |
|---|---|
| Leading | a constant whose value reaches only imports, builtins, literals, or fellow leading constants |
| Trailing | a constant that names a function or class defined later in the module |
The rule relocates a constant into its band, the move that makes the banding a structural concern rather than an alphabetizing one. Each band sorts within its dependency tier by (tier, subcategory, name), clustering the type aliases ahead of the SCREAMING_CASE constants and those ahead of the remaining module state, so like kinds sit together and a constant another constant reads stays above its reader. The tiering and soundness analysis it rests on lives in the shared tiering primitive that
A constant that reads another band member climbs an evaluation tier, and each tier opens its own blank-separated sub-band, so a module's derived values read apart from the primitives they build on. A tier holding a single constant is the exception, folding tight below the tier above and aligning with it through
rather than standing alone across a blank line, the way a one-element collection stays inline. Themax-tiers facet caps how many tiers open their own sub-band, and group-subcategories gates the subcategory clustering.Only an evaluation-time reference binds the order, a right-hand side, a decorator, a default argument, a base class, or a non-deferred annotation. A constant a function reads only inside its body still joins the leading band, because the body does not run at import time. A constant the rule cannot place safely (a reassigned name, a value naming an unresolved reference, or a line a suppression directive or a # prose: keep marker covers) pins where the author left it, and a reference graph that forms a cycle leaves every constant in place.
The rule bands a constant only when its value is inert, holding an effectful value in place. An inert value merely reads names and builds a result (a literal, a name, an attribute or subscript read, a display or operator expression over these, or a lambda, whose body does not run at binding), so relocating it changes nothing a later statement observes. An effectful value carries a call, a comprehension, or an await somewhere in its expression tree, so evaluating it runs code beyond reading names, and moving it reorders that work against the statements around it. RANDOM_SEED = 42 still hoists into the leading band, whereas wide_trainer = L.Trainer(**trainer_kwargs) holds its place, because a module runs top to bottom and a seeded run draws its random numbers in that order. A .py module and a notebook cell carry the same reach, since evaluation order is observable in both.
An own-line comment above a member travels with it wherever the rule seats it, a constant, an import, and a definition alike, so a note stays attached to whatever it describes. A comment on the line directly below a member, held off the next one by a blank line, documents the member above it instead and travels the other way, trailing that member's code where the line has room and climbing onto the line above it where it does not. A run touching both members reads as the description of the one beneath it. A decorative banner (# --- Configuration ---), a suppression directive, a tool pragma (# type: ignore, # noqa), and a comment opening at another indent than the member below it are the exceptions, each holding the slot the author gave it and pinning the member beneath it, and a band never crosses a banner into the section above it. Inside a notebook the cell boundary bounds the carry too, so a comment closing one cell stays where the author typed it while the member in the next cell bands without it.
A member's relocation and the spacing around it settle in the same run, so the file reaches its final shape the first time it is formatted rather than advancing one structural gap per invocation. Running prose format again reads that output and rewrites nothing.
Two comment blocks separated by a blank line lead a band that opens a tier blank, so the assembly re-emits on every pass. The lower block forward-attaches to ATTEMPT_MS and the blank above it survives the hoist, leaving the two blocks distinct however often the file is formatted.
As written
import os
def load(path):
return os.stat(path)
# the retry envelope the loader reads
# per-attempt ceiling, in milliseconds
ATTEMPT_MS = 250
RETRY_LIMIT = 3
TOTAL_BUDGET_MS = ATTEMPT_MS
MAX_ATTEMPTS = RETRY_LIMIT
Run 1Rewritten
import os
# the retry envelope the loader reads
# per-attempt ceiling, in milliseconds
ATTEMPT_MS = 250
RETRY_LIMIT = 3
MAX_ATTEMPTS = RETRY_LIMIT
TOTAL_BUDGET_MS = ATTEMPT_MS
def load(path):
return os.stat(path)
Run 2No change
This run reads the previous output and rewrites nothing, so the file has reached its fixed point and every later run leaves it exactly as it stands.
Pair with
to sort the names within each import section and the definition runs, with to partition the imports the leading band seats below, and with to flag aSCREAMING_CASE name whose reassignment pins it out of a band.| Key | Type | Default | Meaning |
|---|---|---|---|
enabled | bool | true | Toggles the rule on or off. |
group-subcategories | bool | true | Clusters each band by subcategory, the type aliases first, then the SCREAMING_CASE constants, then the remaining module state, before sorting by name within each. false sorts by tier and name alone. |
max-tiers | positive int | false | 2 | Caps how many evaluation tiers open their own blank-separated sub-band, merging every deeper tier into the last. 1 holds the band tight and false opens one sub-band per tier. |
The facets above tune the band without switching it off. group-subcategories clusters each band by subcategory, dropping to a plain (tier, name) sort when false. max-tiers caps how many evaluation tiers open their own sub-band, defaulting to 2 so a band reads as its base plus one derived sub-band, with 1 holding it tight and false opening one per tier. Turned off entirely with band-constants = false, the constants stay in place among their neighbors. The imports.first-party list under [imports] (see the configuration reference) decides which imports the leading band seats below, since a first-party package's imports group with the local-package section.
A module-level constant whose value reaches only imports, builtins, and literals lands in a leading band directly below the imports, while one that names a later definition pools into a trailing band beneath the definitions. Here TIMEOUT lifts above build into the leading band and SESSION, which names build, drains to the trailing band, so the module reads as its imports, its leading constants, its definitions, then the constants derived from them.
import logging
TIMEOUT = 30
def build(spec):
return logging.getLogger(spec)
SESSION = build
A comment leading the band's first constant heads the whole band rather than documenting the one constant beneath it, so it holds the head as ALPHA_DECAY sorts past MAX_INT instead of being stranded mid-band.
The blank line under the comment binds it to DEFAULT_EPSILON above rather than to MAX_INT below, so packing the band carries the comment onto its own constant's line as a trailing note rather than stranding it over whichever constant sorts in beneath it.
A free-standing prose comment sits between _Norm and fft, and __all__ still reaches the leading band. The comment forward-attaches to the definition it heads and travels down with it, so whatever sits between two members leaves the hoist intact.
A constant whose value touches only literals lands in the leading band directly below the imports, hoisting above a function that reads it inside its body, because a body reference defers to call time and constrains no order.
A constant naming a module-level function pools into the trailing band beneath the definitions, never rising above the make it names, because evaluating its right-hand side reaches that definition at once.
A constant naming a function that reaches a class through a default argument pools beneath both the function and the class, since the eval-time surface threads CONFIG past build and the Widget its default names.
Banding binds the own-line prose comment to TTL_SECONDS and hoists the pair into the leading band above render, the blank line the author wrote between them preserved so the comment reaches the top with the constant it describes.
A derived tier holding a single constant folds tight below the tier above rather than opening a blank sub-band, staying available to
.REGISTRY reaches the build_default definition, so it pools into the trailing band beneath the definitions, carrying the own-line prose comment bound to it down as well.
A band mixing type aliases, SCREAMING_CASE constants, and lowercase module state clusters each kind together, the aliases first, then the constants, then the state, alphabetized within each group.
max-tiers = false opens a blank sub-band at every evaluation tier, each holding two or more constants.
A three-tier dependency chain reorders within each tier without crossing tier boundaries. PI and RADIUS lead as tier 0, and the derived DIAMETER and AREA fold into one sub-band beneath a blank line under the default max-tiers.
A module-level run terminates at a # fmt: off block. Assigns above the block sort within their run, the suppression directive bounds its own verbatim scope, and no run forms across the bracket.
Handler names Seconds, so it climbs into the derived tier, and the subcategory clustering holds within each tier, the aliases Seconds and Handler leading their tiers ahead of the constants MAX and TIMEOUT across the blank line the tier split opens.
The lowercase opener names an object that already exists, so it bands as an alias, while the PascalCase Config builds a dict and bands as module state. The value settles the sub-band, leaving the target's casing out of it.
Any Call on a binding's right-hand side skips the entire run. The call could carry observable side effects, so reordering would risk running them out of source order. Source order survives intact.
Alphabetizes import siblings, dict-key blocks, and class-body members.
Partitions a module's imports into __future__, bare, external from, and local-package sections.
Normalizes blank-line counts to canonical values between thematically adjacent statements.
Aligns the = separator across consecutive single-target assignments, annotated function-parameter defaults, and an exploded call's keyword arguments.
Surfaces a module-level constant whose name is not SCREAMING_CASE.
Surfaces a module-level constant reassigned despite its UPPER_SNAKE_CASE casing.