black icon indicating copy to clipboard operation
black copied to clipboard

Option to force "chop down" multiline (+ add magic comma) when line too long

Open ruro opened this issue 1 year ago • 2 comments

I'd say that this is somewhere between a bug report and a feature request. Consider the following piece of code:

def really_really_really_long_function_name(with_long_arguments, that_would_fit_on, one_line):
    another_really_really_long_function_name(with_long_arguments, that_would_fit_on, one_line)

    a_really_really_really_really_long_list = [with_long_arguments, that_would_fit_on, one_line]
    
    a_really_really_really_really_long_set = {with_long_arguments, that_would_fit_on, one_line}

    a_really_really_really_really_long_tuple = (with_long_arguments, that_would_fit_on, one_line)

    a_really_really_really_really_long_dict = {"a": with_long_arguments, "b": that_would_fit_on, "c": one_line}

Currently, black formats it as:

def really_really_really_long_function_name(
    with_long_arguments, that_would_fit_on, one_line
):
    another_really_really_long_function_name(
        with_long_arguments, that_would_fit_on, one_line
    )

    a_really_really_really_really_long_list = [
        with_long_arguments,
        that_would_fit_on,
        one_line,
    ]

    a_really_really_really_really_long_set = {
        with_long_arguments,
        that_would_fit_on,
        one_line,
    }

    a_really_really_really_really_long_tuple = (
        with_long_arguments,
        that_would_fit_on,
        one_line,
    )

    a_really_really_really_really_long_dict = {
        "a": with_long_arguments,
        "b": that_would_fit_on,
        "c": one_line,
    }

which is inconsistent between function calls/definitions and list/set/tuple/dict literals.

I know, that you can force that same "long" multiline syntax by adding a magic comma after the last parameter/argument, however that requires manual intervention and (imho) doesn't fit into the normally opinionated black semantics.

I understand that some people might prefer this behaviour, but I often use black to format old, poorly formatted codebases and in those cases I almost never want this "intermediate" multiline style. IMHO, either the arguments should be refactored so that they fit on the same line as the function name, or they should be "properly" split over multiple lines:

def really_really_really_long_function_name(
    with_long_arguments,
    that_would_fit_on,
    one_line,
):
    another_really_really_long_function_name(
        with_long_arguments,
        that_would_fit_on,
        one_line,
    )

I would like to request an option --force-magic-trailing-comma or --insert-magic-trailing-comma (name open to bike shedding) that would automatically add a trailing comma when black is forced to wrap parameter/argument lists and split them into proper "one argument per line" multilines.

ruro avatar Feb 13 '24 15:02 ruro

I did some exploratory hacking and was able to get the desired output with the following patch:

diff --git a/src/black/linegen.py b/src/black/linegen.py
index cc8e41d..dc5d196 100644
--- a/src/black/linegen.py
+++ b/src/black/linegen.py
@@ -1598,8 +1598,16 @@ def should_split_line(line: Line, opening_bracket: Leaf) -> bool:
 
     return max_priority == COMMA_PRIORITY and (
         (line.mode.magic_trailing_comma and trailing_comma)
-        # always explode imports
-        or opening_bracket.parent.type in {syms.atom, syms.import_from}
+        or opening_bracket.parent.type in {
+            # always explode simple expressions
+            syms.atom,
+            # always explode parameter lists (function definitions)
+            syms.parameters,
+            # always explode imports
+            syms.import_from,
+        }
+        # always explode argument lists (function calls)
+        or opening_bracket.next_sibling.type == syms.arglist
     )

Keep in mind that this patch is almost completely untested, and it uses the "chop down" rules unconditionally, instead of only when a cli option is provided. However, I thought that this might still be useful as a starting point for a proper PR or as a quick n' dirty way to apply the described formatting to large codebases.

ruro avatar Mar 06 '24 20:03 ruro

Related to #1657

cobaltt7 avatar Jun 05 '24 17:06 cobaltt7