Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

Open
RuRo opened this issue Feb 13, 2024 · 1 comment
Open
Labels
T: enhancement New feature or request

Comments

@RuRo
Copy link

RuRo commented Feb 13, 2024

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 RuRo added the T: enhancement New feature or request label Feb 13, 2024
@RuRo
Copy link
Author

RuRo commented Mar 6, 2024

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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
T: enhancement New feature or request
Projects
None yet
Development

No branches or pull requests

1 participant