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

Black should add parentheses to long values in dict literals #620

Closed
ThomasMarques opened this issue Nov 26, 2018 · 15 comments · Fixed by #3440
Closed

Black should add parentheses to long values in dict literals #620

ThomasMarques opened this issue Nov 26, 2018 · 15 comments · Fixed by #3440
Labels
F: parentheses Too many parentheses, not enough parentheses, and so on. S: accepted The changes in this design / enhancement issue have been accepted and can be implemented T: style What do we want Blackened code to look like?

Comments

@ThomasMarques
Copy link

ThomasMarques commented Nov 26, 2018

Operating system: Linux CentOS 7
Python version: 3.6.6
Black version: 18.9b0
Does also happen on master: Yes (Example on master)

I have this code (line length is greater than allowed)

my_dict = {
    'a key in my dict': deformation_rupture_mean * constraint_rupture_mean / 100.0
}

So Black wrap the line, but without indent :

my_dict = {
    "a key in my dict": deformation_rupture_mean
    * constraint_rupture_mean
    / 100.0
}

I find this indent not very readable.

If I add paranthesis, I get the code below, nice formatted in my opinion.

my_dict = {
    "a key in my dict": (
        deformation_rupture_mean * constraint_rupture_mean / 100.0
    )
}

Should not Black add paranthesis in this case?

@romaingz
Copy link

Going one step further we can observe that with even longer lines, black will propose the following formatting:

my_dict = {
    "a very very long key in my dict": (
        another_long_operand
        + deformation_rupture_mean * constraint_rupture_mean / 100.0
    )
}

Even if black did not add parenthesis, it would be nice if it added that little bit of extra indent.
It provides more readability in my opinion.

@jdufresne
Copy link
Contributor

I've found this issue shows up in Django projects that chain a lot of queryset methods together. For example, black was found to produce the following:

class MyView:
    def get_context_data(self, *args, **kwargs):
        context = {
            "filtered_users": User.objects.all()
            .archived()
            .filter(groups__in=get_groups())
        }

I think this would be more readable if the chained methods were indented.

@zsol zsol added T: enhancement New feature or request F: parentheses Too many parentheses, not enough parentheses, and so on. labels Feb 14, 2019
@zsol
Copy link
Collaborator

zsol commented Feb 14, 2019

Black should totally add parenthesis in all these cases

@zsol zsol changed the title Indent in dictionnary Black should add parenthesis to long values in dict literals Feb 14, 2019
@zsol zsol changed the title Black should add parenthesis to long values in dict literals Black should add parentheses to long values in dict literals Feb 14, 2019
@uhbif19
Copy link

uhbif19 commented Apr 10, 2019

There is probably similar problem with string lines in dictionary. Example:

REST_FRAMEWORK = {
    'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.LimitOffsetPagination',
    'PAGE_SIZE': 100,
}

When I set line-length = 79, black does not try to fix this line, while parenthesis could help to fit line-length restriction. In cases of more long lines, splitting string to more parts is required too.

@zsol Not sure if this should be separate issue, or just part of this one.

@ljades
Copy link

ljades commented Aug 12, 2019

Is there any update or fix planned for this issue? A lot of issues were created, closed and referenced to this one at this point. And manually fixing the lines still causes black to undo those fixes and violate its line-length rule.

@zsol
Copy link
Collaborator

zsol commented Aug 12, 2019

AFAIK nobody is actively working on this right now, but I'm happy to review a pr if you're interested in contributing

@and-semakin
Copy link

Another annoying case when black decreases readability is this.

Original code:

my_function(
    my_kwarg=1 if True else 2
)

Blackified code (at first glance it looks like function takes 3 args!):

my_function(
    my_kwarg=1
    if True
    else 2,
)

What I would expect it to look like:

my_function(
    my_kwarg=(
        1
        if True
        else 2,
    ),
)

It happens with black==19.3b0 when function call is indented enough so lines start to wrap.

@Holt59
Copy link

Holt59 commented Nov 28, 2019

This also happens without string literals or even complex operations. This simple example is not split on multiple lines by black:

a = {
    SomeLongEnumeration.SOME_LONG_ENUM_NAME: another_pkg.subpkg.another_enum.another_enum_name
}

@nourspace
Copy link

nourspace commented Sep 9, 2020

Another example

max_prediction_rank_to_save = self.metadata['additional_params'][
    'max_prediction_rank_to_save'
]

which would look better if parentheses were used

max_prediction_rank_to_save = (
    self.metadata['additional_params']['max_prediction_rank_to_save']
)

If there are too many keys, each could go on a separate line

max_prediction_rank_to_save = (
    self.metadata['additional_params']
    ['max_prediction_rank_to_save']
    ['another']
    ['looooooooooong_key']
)

@kmulka-medigo
Copy link

@zsol
Copy link
Collaborator

zsol commented Feb 4, 2021

To be clear this issue is about dictionary literals. The previous two comments are not examples relevant for this issue (they are about long subscript expressions)

@kmulka-medigo
Copy link

@zsol Ok, I've created a new issue here: #1965

@sodul
Copy link

sodul commented Apr 22, 2021

I see folks mentioning that parentheses should be added, but they are completely unecessary inside a dictionary since Python already knows the dictonary is not closed until the final }.

my_dict = {
    "a key in my dict": (
        deformation_rupture_mean * constraint_rupture_mean / 100.0
    )
}

Should just be:

my_dict = {
    "a key in my dict":
        deformation_rupture_mean * constraint_rupture_mean / 100.0,
}

And:

my_dict = {
    "a very very long key in my dict": (
        another_long_operand
        + deformation_rupture_mean * constraint_rupture_mean / 100.0
    ),
    "other": 42
}

Should be:

my_dict = {
    "a very very long key in my dict":
        another_long_operand
        + deformation_rupture_mean * constraint_rupture_mean / 100.0,
    "other": 42,
}

The indentation makes it really clear that the data belongs to the key without the need for the extra parentheses.

This issue is mentioned in #2063.

So far this is the single issue that prevents us from adopting Black for auto formatting our codebase since the longer lines break our other CI checks.

@ichard26 ichard26 added S: accepted The changes in this design / enhancement issue have been accepted and can be implemented T: style What do we want Blackened code to look like? and removed T: enhancement New feature or request labels May 30, 2021
@felix-hilden
Copy link
Collaborator

Another case would be fluent interfaces like in #2591.

@roganartu
Copy link

roganartu commented Mar 23, 2022

Another place I had this happen recently that I didn't see mentioned above but seems related was in a list.

Given this:

["foo", "bar", "baz" if some_really_long_variable else "some other long value"]

black will generate this:

[
    "foo",
    "bar",
    "baz"
    if some_really_long_variable
    else "some other long value",
]

Which is difficult to read, easy to miss in review, and easy to accidentally break by adding a comma in the wrong place in future. Manually adding parens results in black generating this, which is much clearer:

[
    "foo",
    "bar",
    (
        "baz"
        if some_really_long_variable
        else "some other long value"
    ),
]

toofar added a commit to qutebrowser/qutebrowser that referenced this issue Apr 30, 2022
Running darker over the pyqt reference renames (see previous commit)
worked pretty well. Unfortnately we ran into
psf/black#620 a lot with dicts with long
attributes. Things that used to be manually wrapped like:

    some_map = {
      quote_long_attribute_name:
        also_long_value,
    }

get turned into:

    some_map = {
      quote_long_attribute_name: also_long_value,
    }

which is quite often over 88 chars with Qt enum values in the map.
I've manually added aliases and such for the Qt enums and classes to
shorted the lines.

This is likely to conflict entirely with the enum scoped changes on the
qt6 branches.
toofar added a commit to qutebrowser/qutebrowser that referenced this issue Apr 30, 2022
Running darker over the pyqt reference renames (see previous commit)
worked pretty well. Unfortnately we ran into
psf/black#620 a lot with dicts with long
attributes. Things that used to be manually wrapped like:

    some_map = {
      quote_long_attribute_name:
        also_long_value,
    }

get turned into:

    some_map = {
      quote_long_attribute_name: also_long_value,
    }

which is quite often over 88 chars with Qt enum values in the map.
I've manually added aliases and such for the Qt enums and classes to
shorted the lines.

This is likely to conflict entirely with the enum scoped changes on the
qt6 branches.
toofar added a commit to qutebrowser/qutebrowser that referenced this issue Apr 30, 2022
Running darker over the pyqt reference renames (see previous commit)
worked pretty well. Unfortnately we ran into
psf/black#620 a lot with dicts with long
attributes. Things that used to be manually wrapped like:

    some_map = {
      quote_long_attribute_name:
        also_long_value,
    }

get turned into:

    some_map = {
      quote_long_attribute_name: also_long_value,
    }

which is quite often over 88 chars with Qt enum values in the map.
I've manually added aliases and such for the Qt enums and classes to
shorted the lines.

This is likely to conflict entirely with the enum scoped changes on the
qt6 branches.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
F: parentheses Too many parentheses, not enough parentheses, and so on. S: accepted The changes in this design / enhancement issue have been accepted and can be implemented T: style What do we want Blackened code to look like?
Projects
None yet
Development

Successfully merging a pull request may close this issue.