psf / black

The uncompromising Python code formatter
https://black.readthedocs.io/en/stable/
MIT License
38.63k stars 2.43k forks source link

Line too long: Attribute chain #510

Open decibyte opened 6 years ago

decibyte commented 6 years ago

Operating system: Ubuntu 18.04 Python version: 3.6.5 Black version: 18.6b4 (via pip) Does also happen on master: Yes

This might not be a bug, but then I'd like to get the (opinionated) explanation for this behavior.

Feeding this code into black:

# A long line example for black

def my_function(x, y, z):
    """Whatever"""

    if condition:
        if other_condition:
            result = "{} {} {}".format(
                x,
                y,
                z.and_then.something_very_deep.
                inside_the_complex.object_called_z.even_further,
            )
        else:
            result = "{} {} {}".format(
                x,
                y,
                (
                    z.and_then.something_very_deep.
                    inside_the_complex.object_called_z.even_further
                ),
            )
        return result

Gives me this:

# A long line example for black

def my_function(x, y, z):
    """Whatever"""

    if condition:
        if other_condition:
            result = "{} {} {}".format(
                x,
                y,
                z.and_then.something_very_deep.inside_the_complex.object_called_z.even_further,
            )
        else:
            result = "{} {} {}".format(
                x,
                y,
                (
                    z.and_then.something_very_deep.inside_the_complex.object_called_z.even_further
                ),
            )
        return result

What bothers me is that the long dotted paths are kept on a single line that's way too long. The two examples are basically the same, I just tried the second thing with parentheses, as I got the impression – while skimming existing issues – that this might be a way to force wrapping the line to respect the line length limit.

How do I get black to wrap these lines within the limit, if possible at all?

Anyway: Thanks for an extremely nice utility :)

jaraco commented 5 years ago

I'm seeing this issue also. Here's a more minimal example:

inflect feature/black $ cat > test.py
test_cases = {
    "blah blah blah blah blah blah blah blah blah blah blah":
        "bob loblaw bob loblaw bob loblaw bob loblaw bob loblaw ",
}
inflect feature/black $ rwt black -- -m black test.py
Collecting black
  Using cached https://files.pythonhosted.org/packages/2a/34/9938749f260a861cdd8427d63899e08f9a2a041159a26c2615b02828c973/black-18.9b0-py36-none-any.whl
Collecting attrs>=17.4.0 (from black)
  Using cached https://files.pythonhosted.org/packages/3a/e1/5f9023cc983f1a628a8c2fd051ad19e76ff7b142a0faf329336f9a62a514/attrs-18.2.0-py2.py3-none-any.whl
Collecting appdirs (from black)
  Using cached https://files.pythonhosted.org/packages/56/eb/810e700ed1349edde4cbdc1b2a21e28cdf115f9faf263f6bbf8447c1abf3/appdirs-1.4.3-py2.py3-none-any.whl
Collecting click>=6.5 (from black)
  Using cached https://files.pythonhosted.org/packages/fa/37/45185cb5abbc30d7257104c434fe0b07e5a195a6847506c074527aa599ec/Click-7.0-py2.py3-none-any.whl
Collecting toml>=0.9.4 (from black)
  Using cached https://files.pythonhosted.org/packages/a2/12/ced7105d2de62fa7c8fb5fce92cc4ce66b57c95fb875e9318dba7f8c5db0/toml-0.10.0-py2.py3-none-any.whl
Installing collected packages: attrs, appdirs, click, toml, black
Successfully installed appdirs-1.4.3 attrs-18.2.0 black-18.9b0 click-7.0 toml-0.10.0
reformatted test.py
All done! ✨ 🍰 ✨
1 file reformatted.
inflect feature/black $ cat test.py
test_cases = {
    "blah blah blah blah blah blah blah blah blah blah blah": "bob loblaw bob loblaw bob loblaw bob loblaw bob loblaw "
}

I tried it with parentheses, but that removes the trailing comma:

inflect feature/black $ cat test.py
test_cases = {
    "blah blah blah blah blah blah blah blah blah blah blah": (
        "bob loblaw bob loblaw bob loblaw bob loblaw bob loblaw "
    ),
}
inflect feature/black $ rwt -q black -- -m black test.py
reformatted test.py
All done! ✨ 🍰 ✨
1 file reformatted.
inflect feature/black $ cat test.py
test_cases = {
    "blah blah blah blah blah blah blah blah blah blah blah": (
        "bob loblaw bob loblaw bob loblaw bob loblaw bob loblaw "
    )
}

That latter part is perhaps another issue, maybe #493.

hugovk commented 5 years ago

I have a case where Black 19.3b0 removes a backslash and a newline to make the line over the limit:

Input

class Thing:
    def get(self):
        typ = 1
        if True:
            if True:
                if True:
                    for i in range(0, 10):
                        try:
                            abcd_efgh, ijklmno =\
                                AaaaBbbbbCccccc.DddddEeeeFffffffff_gg._hhhh_iiiiiii[
                                    typ
                                ]
                        except KeyError:
                            continue

Output

class Thing:
    def get(self):
        typ = 1
        if True:
            if True:
                if True:
                    for i in range(0, 10):
                        try:
                            abcd_efgh, ijklmno = AaaaBbbbbCccccc.DddddEeeeFffffffff_gg._hhhh_iiiiiii[
                                typ
                            ]
                        except KeyError:
                            continue

Diff

9,12c9,12
<                             abcd_efgh, ijklmno =\
<                                 AaaaBbbbbCccccc.DddddEeeeFffffffff_gg._hhhh_iiiiiii[
<                                     typ
<                                 ]
---
>                             abcd_efgh, ijklmno = AaaaBbbbbCccccc.DddddEeeeFffffffff_gg._hhhh_iiiiiii[
>                                 typ
>                             ]
> 

Bug or by design? Other than refactoring all those indents, any workarounds?

JelleZijlstra commented 5 years ago

Black generally removes backslashes, which is by design. You can perhaps work around this by putting parentheses around the unpacking assignment, which will enable Black to put the variables on separate lines. Perhaps we should automatically insert these parens.

ketozhang commented 1 year ago

@JelleZijlstra I think you meant to put parenthesis around the dot accessors

result = "{} {} {}".format(
    x,
    y,
    (
-        z.and_then.something_very_deep.inside_the_complex.object_called_z.even_further
    ),
)
result = "{} {} {}".format(
    x,
    y,
    (
+        (z.and_then.something_very_deep.inside_the_complex.object_called_z).even_further
    ),
)

After black

result = "{} {} {}".format(
    x,
    y,
    (
+        (
+            z.and_then.something_very_deep.inside_the_complex.object_called_z
+        ).even_further
    ),
)
Feuermurmel commented 1 year ago

Two small examples that lead to lines longer than the configured maximum (see playground link below):

a = (
    a123456789.a123456789.a123456789.a123456789.a12345678()
)

a123456789.a123456789().a123456789().a123456789().a123456789()

https://black.vercel.app/?version=stable&state=_Td6WFoAAATm1rRGAgAhARYAAAB0L-Wj4ADpAGFdAD2IimZxl1N_WlOfrjrv4T23UbUYHWg1zEHnpuDHXBotslGy88S7D9eXLeMmFf77Po8Vst34lz-hLkHRzCXCmdpba0t9DoDAVwqUUQZE2RVOMqwGvC1LjYo46a5aHQHyRwAAAAAA-0ZjDg0XK5YAAX3qAQAAANlyMa6xxGf7AgAAAAAEWVo=