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

False positive E202 and E251 inside f-string (Python 3.12) #1201

Closed
AndrewUshakov opened this issue Oct 6, 2023 · 10 comments
Closed

False positive E202 and E251 inside f-string (Python 3.12) #1201

AndrewUshakov opened this issue Oct 6, 2023 · 10 comments

Comments

@AndrewUshakov
Copy link

Hi!

For the code below:

a = 10
print(f'{a = }')

the pycodestyle.py version 2.11.0 generates 3 false positive errors:

tst.py:2:11: E251 unexpected spaces around keyword / parameter equals
tst.py:2:13: E202 whitespace before '}'
tst.py:2:13: E251 unexpected spaces around keyword / parameter equals

P.S. Python 3.12.0 (tags/v3.12.0:0fb18b0, Oct 2 2023, 13:03:39) [MSC v.1935 64 bit (AMD64)] on win32

Thank you in advance.

Andrew

@asottile
Copy link
Member

asottile commented Oct 7, 2023

I believe the intended syntax for this is f'{a=}' which does not produce errors

@asottile asottile closed this as completed Oct 7, 2023
@AndrewUshakov
Copy link
Author

Hi!

In the proposal python/cpython#80998, where discussed syntax was suggested, you can find example of the f-string with spaces around the = symbol.

In the section https://docs.python.org/3/reference/lexical_analysis.html#f-strings you can also find example of the f-string with more spaces than in my example:

>f"{ foo = }" # preserves whitespace

One of the new features In the Python 3.12 is: "More flexible f-string parsing , allowing many things previously disallowed (PEP 701)." In the PEP701 documentation the special section "Handling of f-string debug expressions" exists. The fragment of this section is below:

f-string debug expressions preserve whitespace in the expression, including spaces after the { and the = characters. This means that the raw string contents of the expression part of the f-string must be kept intact and not just the associated tokens.

As I understand, it means that:

f'{ foo = }'

is equivalent to

f' foo = {foo}'

and only expression itself without surrounding spaces need to be validated against PEP8.

Additionally, in the PEP701 documentation you can find examples of "usual" f-strings with spaces after { and before }. Your script generates E201 and E202 for such strings, while real warnings should look like "spaces after { and before } will disappear at the output". And, of course, E251 message is confusing, because meaning of = character is different here.

Best regards,
Andrew

@asottile
Copy link
Member

asottile commented Oct 7, 2023

yes but all of the canonical examples do not have spaces

@AndrewUshakov
Copy link
Author

By the way, I found one case (agree, very special) where the space after the { is required. Consider the valid Python 3.12 code below, which uses "usual" f-string:

a = 999
print(f'{ {a, 2, 3}}')
print(f'{{a, 2, 3}}')

which prints:

{2, 3, 999}
{a, 2, 3}

Process finished with exit code 0

Do you agree, that it is not PEP8 error/warning?

@asottile
Copy link
Member

asottile commented Oct 9, 2023

use parentheses

@AndrewUshakov
Copy link
Author

Result of

print(f'{({a, 2, 3})=}')

looks ugly:

({a, 2, 3})={2, 3, 999}

@asottile
Copy link
Member

asottile commented Oct 9, 2023

it looks ugly either way. nobody would write code like that

@AndrewUshakov
Copy link
Author

Ok. The last question. Will you accept pull request?

P.S. Yes, I understand, that patch will not be trivial, because in the function extraneous_whitespace tokens are unavailable.

@asottile
Copy link
Member

asottile commented Oct 9, 2023

no. I consider the current behavior to be correct. you can use noqa for your strawman cases

@yous
Copy link

yous commented Oct 26, 2023

The spaces around = in f-strings change the output.

foo = 42
print(f"{foo=}")
# foo=42
print(f"{foo =}")
# foo =42
print(f"{foo= }")
# foo= 42
print(f"(foo = }")
# foo = 42

What will be the effective way to produce foo = 42 without writing the variable name twice in the code? (i.e. f"foo = {foo}")

Generally E251 errors won't affect the behavior of the code, but this one forces to change the behavior.

@PyCQA PyCQA locked as resolved and limited conversation to collaborators Oct 26, 2023
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants