black icon indicating copy to clipboard operation
black copied to clipboard

Break long expressions at operators, not inside inner parentheses

Open mfripp opened this issue 1 year ago • 0 comments

Describe the style change

When a long expression includes parenthetical expressions or functions, it would be better to put parentheses around the whole expression and wrap before operators, rather than wrapping inside an arbitrary set of existing parentheses.

Examples in the current Black style

if this_very_long_variable_name != float(
    "inf"
) and other_very_long_variable_name == float("inf"):
    pass

test = this_very_long_variable_name * float(
    "inf"
) + other_very_long_variable_name * float("inf")

test = (this_very_long_variable_name * float("inf")) + (
    other_very_long_variable_name * float("inf")
)

Desired style

if (
    this_very_long_variable_name != float("inf") 
    and other_very_long_variable_name == float("inf")
):
    pass

test = (
    this_very_long_variable_name * float("inf") 
    + other_very_long_variable_name * float("inf")
)

test = (
    (this_very_long_variable_name * float("inf")) 
    + (other_very_long_variable_name * float("inf"))
)

Additional context

Fortunately, we already get this behavior for the dot operator, like this:

df = pd.DataFrame(
    {"a": [1, 2, 3, 4], "b": [2, 4, 6, 8], "c": [3, 6, 9, 12]}
).sort_values(axis=0, ascending=False, by=["a", "b", "c"]).set_index(
    "a"
).apply(lambda x: x**2)

# becomes 

df = (
    pd.DataFrame({'a': [1, 2, 3, 4], 'b': [2, 4, 6, 8], 'c': [3, 6, 9, 12]})
    .sort_values(axis=0, ascending=False, by=['a', 'b', 'c'])
    .set_index('a')
    .apply(lambda x: x**2)
)

# and 

x = "this is a long string with some {}, {} or {} in it.".format(
    "parameters", "arguments", "placeholders"
) + "this is a long string with some {}, {} or {} in it.".format(
    "parameters", "arguments", "placeholders"
) + "this is a long string with some {}, {} or {} in it.".format(
    "parameters", "arguments", "placeholders"
)

# becomes

x = (
    "this is a long string with some {}, {} or {} in it.".format(
        "parameters", "arguments", "placeholders"
    )
    + "this is a long string with some {}, {} or {} in it.".format(
        "parameters", "arguments", "placeholders"
    )
    + "this is a long string with some {}, {} or {} in it.".format(
        "parameters", "arguments", "placeholders"
    )
)

But for other operators (+, *, and, ==, etc.), we get breaks inside the existing inner parentheses instead of between operators. This is not good for readability.

mfripp avatar Nov 28 '23 17:11 mfripp