hhatto / autopep8

A tool that automatically formats Python code to conform to the PEP 8 style guide.
https://pypi.org/project/autopep8/
MIT License
4.56k stars 288 forks source link

Inserting newlines into triple-quoted f-strings on Python 3.12 #744

Closed rix0rrr closed 4 months ago

rix0rrr commented 5 months ago

autopep8 seems to be adding newlines to what looks like an expression (but isn't!) inside triple-quoted f-strings.

It does not make the same mistake for triple-quoted non-f-strings, nor for regular-quoted f-strings.

I was originally confused myself, because the {{ ... }} below could be interpreted as a { ... } placeholder containing a literal dict expression, but the PEP seems to say that {{ should always be interpreted as a literal {... which make the characters that follow definitely not a valid expression and so not eligible for newline insertion.

Python Code

txt = f"""\
    color_dict = {{'black': 'black', 'blue': 'blue', 'brown': 'brown', 'gray': 'gray', 'green': 'green', 'orange': 'orange', 'pink': 'pink', 'purple': 'purple', 'red': 'red', 'white': 'white', 'yellow': 'yellow'}}
"""

txt2 = """\
    color_dict = {{'black': 'black', 'blue': 'blue', 'brown': 'brown', 'gray': 'gray', 'green': 'green', 'orange': 'orange', 'pink': 'pink', 'purple': 'purple', 'red': 'red', 'white': 'white', 'yellow': 'yellow'}}
"""

txt3 = "\
    color_dict = {{'black': 'black', 'blue': 'blue', 'brown': 'brown', 'gray': 'gray', 'green': 'green', 'orange': 'orange', 'pink': 'pink', 'purple': 'purple', 'red': 'red', 'white': 'white', 'yellow': 'yellow'}}\
"

No special configuration.

Command Line

$ autopep8 -i example.py
$ git diff
@@ -1,5 +1,6 @@
 txt = f"""\
-    color_dict = {{'black': 'black', 'blue': 'blue', 'brown': 'brown', 'gray': 'gray', 'green': 'green', 'orange': 'orange', 'pink': 'pink', 'purpl>
+    color_dict = {{'black': 'black', 'blue': 'blue', 'brown': 'brown', 'gray': 'gray', 'green': 'green',
+        'orange': 'orange', 'pink': 'pink', 'purple': 'purple', 'red': 'red', 'white': 'white', 'yellow': 'yellow'}}
 """

It added a newline inside the first triple-quoted f-string literal, but not inside the other ones.

Your Environment

Additional proof

Proof that the reformatting changes the meaning of the string:

txt = f"""\
    color_dict = {{'black': 'black', 'blue': 'blue', 'brown': 'brown', 'gray': 'gray', 'green': 'green', 'orange': 'orange', 'pink': 'pink', 'purple': 'purple', 'red': 'red', 'white': 'white', 'yellow': 'yellow'}}
"""

txt2 = """\
    color_dict = {{'black': 'black', 'blue': 'blue', 'brown': 'brown', 'gray': 'gray', 'green': 'green', 'orange': 'orange', 'pink': 'pink', 'purple': 'purple', 'red': 'red', 'white': 'white', 'yellow': 'yellow'}}
"""

txt3 = f"\
    color_dict = {{'black': 'black', 'blue': 'blue', 'brown': 'brown', 'gray': 'gray', 'green': 'green', 'orange': 'orange', 'pink': 'pink', 'purple': 'purple', 'red': 'red', 'white': 'white', 'yellow': 'yellow'}}\n\
"

#------------------------------------------------------------
# The rest is for mechanical proof

reference = "    color_dict = {'black': 'black', 'blue': 'blue', 'brown': 'brown', 'gray': 'gray', 'green': 'green', 'orange': 'orange', 'pink': 'pink', 'purple': 'purple', 'red': 'red', 'white': 'white', 'yellow': 'yellow'}\n"

# Normalize txt2 for the comparison below
txt2 = txt2.replace('{{', '{').replace('}}', '}')

equal = [x == reference for x in [txt, txt2, txt3]]
print(equal)
assert all(equal)
$ python3 example.py
[True, True, True]

$ autopep8 -i example.py

$ python3 example.py
[False, True, True]
Traceback (most recent call last):
  File "example.py", line 24, in <module>
    assert all(equal)
AssertionError
hhatto commented 4 months ago

fixed in v2.2.0

https://pypi.org/project/autopep8/2.2.0/