2025, Nov 09 21:00
Black's Call Chain Rule: Why Long Python Call Chains Get Parentheses and Can't Stay Single-Line
Learn why the Black formatter wraps long Python call chains in parentheses, what rule enforces it, and why it can't be disabled, readability and diff benefits.
When Black reformats long chained calls, it often introduces a wrapping pair of parentheses and splits the chain across multiple lines. Developers expecting to keep a single-line chain or a different wrapping style wonder whether this can be prevented and which rule is responsible.
Example that triggers the behavior
Consider a long call chain. Before formatting it might look like this:
compute_heavy(alpha_input, beta_input...).next_step().next_step().next_step()After running Black, the code is wrapped and each call in the chain appears on its own line:
(
compute_heavy(alpha_input, beta_input...)
.next_step()
.next_step()
.next_step()
)What is happening and why
This pattern is handled as a Call Chain, as described in the documentation. Black breaks each call onto a separate line for consistent readability and cleaner diffs. Such splitting inevitably introduces newlines. Without an outer pair of parentheses, those newlines would require escaping on every line, which Black avoids. The parentheses are added to keep the chain valid without backslashes.
The rule and whether it can be disabled
The rule comes from Black’s handling of Call Chains. It is a deliberate choice aimed at consistency, and it is unlikely to change. In other words, there is no supported way to prevent Black from wrapping such chains in parentheses when it decides the split is needed.
Rewritten example with the same logic
If you want to see the same idea using different identifiers, here is a function chain that Black will treat the same way:
process_payload(arg_one, arg_two...).pipe().pipe().pipe()Black will reflow it into the following shape for readability and diffs, introducing an outer pair of parentheses to avoid line-continuation escapes:
(
process_payload(arg_one, arg_two...)
.pipe()
.pipe()
.pipe()
)Why you should care
Understanding this behavior prevents fighting the formatter. The split improves scanability and produces smaller diffs when individual segments of the chain change. It also eliminates the need for trailing backslashes after every line, which would be noisy and fragile.
You can have any color you like, as long as it’s black.
That captures the philosophy: a single, opinionated style applied consistently across a codebase.
Practical takeaway
If a long call chain needs multiple lines, Black will split it into one call per line and add parentheses around the group. This is by design under the Call Chain rule and is not intended to be overridden. Embrace the style and let the formatter handle readability and diffs for you.