Operating system: MacOS
Python version: Python 3.6.5
Black version: 18.6b4
Does also happen on master: Yes
Python file contents:
class Foo():
def save(self):
for x in y:
for aaaaaaaaaaaaa, bbbbbbbbbbbbbbb, ccccccccccc, dddddddddddddd, eeee in self.ffffffffffffff['xxxxxxxxxxxxx']:
pass
pyproject.toml contents:
[tool.black]
line-length = 100
py36 = true
exclude = '''
/(
# Defaults
\.git
| \.hg
| \.mypy_cache
| \.tox
| \.venv
| _build
| buck-out
| build
| dist
# Futurepump
| node_modules
| bower_components
)/
'''
Command:
# Assuming loading settings from pyproject.toml
black test.py
Result:
error: cannot format test.py: INTERNAL ERROR: Black produced different code on the second pass of the formatter. Please report a bug on https://github.com/ambv/black/issues. This diff might be helpful: /var/folders/w5/jmchwlbx6sdgtbb6bgxhj23m0000gp/T/blk_b8ei2xz0.log
All done! 馃挜 馃挃 馃挜
1 file failed to reformat.
Thanks for reporting, this is definitely a bug. We'll fix it.
In the meanwhile, you can wrap your inner for loop's variables in parenthesis as a workaround to unblock yourself:
class Foo():
def save(self):
for x in y:
for (aaaaaaaaaaaaa, bbbbbbbbbbbbbbb, ccccccccccc, dddddddddddddd, eeee) in self.ffffffffffffff['xxxxxxxxxxxxx']:
pass
Thank you for the confirmation @zsol, and for the remedial suggestion 馃憤
Hi @zsol , I'm able to reproduce the issue, mind if I take a crack at it or is someone already working on this?
Nobody's actively working on it AFAIK, go for it!
@B-Souty any luck? need help?
@zsol Sorry I missed your message last weekend, I had a quick look at the code but didn't have a chance to work on it since my initial comment. I will take a closer look tonight. I must admit this issue is quite a step-up compared to any of my previous contribution on Github, any pointers are welcome 馃槂
The example code you gave gets formatted to (toml contents not relevant):
class Foo:
def save(self):
for x in y:
for (
aaaaaaaaaaaaa,
bbbbbbbbbbbbbbb,
ccccccccccc,
dddddddddddddd,
eeee,
) in self.ffffffffffffff[
'xxxxxxxxxxxxx'
]:
pass
But then in assert_stable, (or if we run the formatter with --fast on the new code), the second version gets formatted to:
class Foo:
def save(self):
for x in y:
for (
aaaaaaaaaaaaa,
bbbbbbbbbbbbbbb,
ccccccccccc,
dddddddddddddd,
eeee,
) in self.ffffffffffffff['xxxxxxxxxxxxx']:
pass
So I think its an order of operations problem, where the formatter decides to split the line
for aaaaaaaaaaaaa, bbbbbbbbbbbbbbb, ccccccccccc, dddddddddddddd, eeee in self.ffffffffffffff['xxxxxxxxxxxxx']:
but it does so starting from the rhs, so the square brackets get split turning the expression first into:
for aaaaaaaaaaaaa, bbbbbbbbbbbbbbb, ccccccccccc, dddddddddddddd, eeee in self.ffffffffffffff[
'xxxxxxxxxxxxx'
]:
And only then does it realize that the unpacked variables should be parenthesized (by normalize_invisible_parens?) and split up, which makes the first split unnecessary.
But I couldn't figure out how to follow the flow in __attrs_post_init__, sorry. Hopefully this is helpful.
Hey @arl-o it did help, I saw the function you mentioned in the debugger.
Unfortunately, I'm not much closer from fixing this issue than last week. I should have checked the project more closely before getting involved, this is way out of my league. If someone wants to grab it, please go ahead, you'll probably go much faster than I would.
I'll address this for the next release. I agree this is an ugly case where two heuristics are conflicting.
FWIW this is a duplicate of #267.