Skip to content

collection-layout

A dictionary, list, or set with five non-trivial entries on one line reads as a single chunky token, and the reader's eye flicks across to find the entry it wants. The same data on five separate lines reads as a column of entries, each one a unit.

expands multi-entry collections to the one-per-line shape whenever the entries cross the atomicity threshold, and it leaves short single-line collections alone when each entry is already small enough to skim.

The rule fires on dictionary, list, set, and tuple literals. A literal expands when any entry is non-atomic (a function call, a nested collection, a computed expression) or when the entry count exceeds max-atomics-per-line. Single-line collections of atomic literals (ints, floats, strings, single-name identifiers) inside the cap stay on one line. Pair with

for the dict-key alignment after the expansion, with for sibling sorting where ordering doesn't matter, and with for the trailing-comma sweep on the multi-line form.

A dict also expands once it holds more than max-inline-dict-entries entries, whatever its width, taking any enclosing collection with it. It mirrors

's max-inline-params, the same count-gate shape applied to parameters. The trigger is dict-only, since a list or set reads acceptably as a packed run while a dict's key-value pairs earn the vertical layout. Set the knob to false to leave width as the only dict gate.

A dict entry whose key: value width overflows the budget at the item-indent column breaks at : and hangs the value at item_indent + INDENT_STEP. The hang applies per-row, so a multi-item dict hangs only the rows that need it. A single-entry dict whose entry overflows enters the expand path and applies the same break. Tuples, lists, and sets stay out of the hang shape because their elements carry no : separator.

Configuration

KeyTypeDefaultMeaning
enabledbooltrueToggle the rule on or off
max-atomics-per-linepositive int | false8Keep short collections on one line when each entry is an atomic literal and the run fits the cap. Setting false removes the cap and packs each line by width alone
max-inline-dict-entriespositive int | false3Expand a dict once its entry count exceeds the cap, whatever its width. Setting false disables the count trigger and leaves width as the only dict gate

A short tuple inside a function-call argument list, like numpy.zeros((3, 4)), stays inline at the default cap. A dict literal with eight non-atomic entries expands regardless of length. A four-entry dict expands at the default max-inline-dict-entries of 3 even when it fits the line.

The Canonical Case

A dict literal with non-atomic entries expands to one entry per line, and the reader reads the entries as a column of key-value pairs.

python
short_dict = {"alpha": 1, "beta": 2, "gamma": 3}
long_dict = {
    "alpha": 1,
    "beta": 2,
    "gamma": 3,
    "delta": 4,
    "epsilon": 5,
    "zeta": 6,
    "eta": 7
}
single_entry_dict = {"default_action": "noop"}
collapsing_dict = {"alpha": 1, "beta": 2, "gamma": 3}

More Examples

Literals, names, attribute chains, and unary operands are all atomic and flow together across balanced lines. A non-atomic call expression in the middle breaks its surrounding run into two independent flow segments, each balancing on its own.

A nested matrix stays fully inline within the 88-character budget. When the outer list overflows, it expands row by row, each inner row checking fit at its own column and staying inline when it fits, producing the matrix-by-row layout rather than one cell per line.

A dict row whose key: value width overflows at the item-indent column breaks at : and hangs the value at item_indent + INDENT_STEP. Rows that fit stay on one line, and an already-multi-line nested value runs its own expansion without triggering the hang.

A dict carrying more entries than max-inline-dict-entries breaks to one entry per line even when it fits the line budget, while a dict at or under the cap stays inline and an already-expanded dict past the cap stays expanded.

A list stays inline within the 88-character budget and expands when it overflows. Inside the expanded form, atomic items flow across as few balanced lines as fit under code-line-length and the max_atomics_per_line cap. A multi-line list that fits collapses back inline.

Each nested collection runs its own layout decision at its own column. An expanding outer literal drags its inners along, whereas a pinned outer leaves each inner to its own pass. Dict-value nesting folds the key-text offset into the inner's column, so a long key can push its value past the budget even when the outer fits.

No Change

An inline literal that already fits and a multi-line literal whose inline form would overflow both round-trip with no edit. A dict already hanging an oversized entry's value at the post-: column also passes through unchanged.

No Change

List, dict, set, and generator comprehensions are not literals, so the rule leaves them inline and never expands them. The visitor returns no rewrite for these shapes and keeps descending through their bodies.