psf / black

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

Black doesn't format expressions inside f-strings #567

Open mxr opened 5 years ago

mxr commented 5 years ago

Operating system: macOS 10.13.6 Python version: 3.7.0 Black version: 18.9b0 Does also happen on master: yes


Given this example

prefix = "foo"
print(f"{ prefix        }.bar")

I was expecting black to trim the whitespace inside the f-string braces, but black leaves the file as-is.

Is this a bug or expected?

zsol commented 5 years ago

This is an unfortunate side effect of how the AST encodes f-strings :( It would be awesome if black would understand expressions inside f-strings, but that's not the case today.

ambv commented 5 years ago

This is not handled currently because:

In particular, we cannot use newlines inside the braces and we probably should minimize the amount of whitespace compared to regular code.

janosh commented 4 years ago

The title makes this issue a little hard to find. Something like "black not formatting expressions inside f-strings" would make it easier.

ambv commented 4 years ago

This is a design problem. Should we enforce the same style for expressions in f-strings as we do outside of them? In particular, spaces around operators come to mind.

vpoulailleau commented 4 years ago

I came here to write the same kind of issue :wink: BTW, thanks so much for black, this is a great tool!

To my mind, yes the formatting should be the same inside and outside an f-string. But at least, PEP 8 should be respected: "Use your own judgment; however, never use more than one space, and always have the same amount of whitespace on both sides of a binary operator"

Especially when applied to:

x = f"{3  +      5}"
ericvsmith commented 4 years ago

Two points:

  1. I've tried on multiple occasions to make CPython use the grammar to parse f-strings, but it's complicated. Maybe the new PEG parser will help here, but I'm not optimistic. I really should write up a description of the problem someday. Basically it's a lexer problem, not a parser problem, but I'm not sure where the PEG parser draws the line. Now that PEP 617 has been accepted I'll dig into it deeper.

  2. With the "f-string debugging" feature (a name I do not love), whitespace becomes significant between the expression and before and after the equal sign, so you'd need to be aware of that. Hopefully if the first point is addressed you might get some help here.

    >>> f'{x=}'
    "x='foo'"
    >>> f'{x = }'
    "x = 'foo'"

I think the significant whitespace here is perhaps too clever, but it solved a design problem.

JelleZijlstra commented 2 years ago

We should really fix this at some point. Here are some thoughts in no particular order:

zsol commented 2 years ago

For what it's worth, I believe this would be close to trivial to implement on top of LibCST, which now parses f-strings inside the grammar, and so it provides a simple API to expose the parts of the f-string expression: https://libcst.readthedocs.io/en/latest/nodes.html#formatted-strings-f-strings

robwijnhoven commented 1 year ago

We have experienced an issue with black when splitting f-strings over multiple lines. Probably this is a similar to the issue mentioned above, but adding it here for completeness.

string = f"{variable1} some text here so that this line becomes way too long for my line-limit {variable2}."

Black now formats this into (ignoring spacing):

string = f"{variable1} some text here so that this line becomes way "
+ "too long for my line-limit {variable2}."

while it should be adding the "f-" to the second split line:

string = f"{variable1} some text here so that this line becomes way "
+ f"too long for my line-limit {variable2}."
JelleZijlstra commented 1 year ago

@robwijnhoven I don't believe that's how Black formatting has ever worked. If you can find a reproducible example, please report a separate bug.

lts20050703 commented 6 months ago

Was having basic python classes today, tried to use ternary if else in f string, print(f"{a} / {b} = {"Cannot divide by 0" if b == 0 else f"{a/b:.2f}"}") ended up with the following error error: cannot format C:\Users\lts20\Git\py\2023.11.08\Exer_1.py: Cannot parse: 16:22: print(f"{a} / {b} = {"Cannot divide by 0" if b == 0 else f"{a/b:.2f}"}") Is this intended?

hauntsaninja commented 6 months ago

That is only valid syntax on Python 3.12 or newer, support for that is tracked at https://github.com/psf/black/issues/3746

JelleZijlstra commented 1 month ago

Once #3822 is merged it should be much more tractable to fix this long-standing issue.