mirror of
https://github.com/astral-sh/ruff.git
synced 2025-11-25 13:36:47 +00:00
Avoid multiline expression if format specifier is present (#11123)
## Summary
This PR fixes the bug where the formatter would format an f-string and
could potentially change the AST.
For a triple-quoted f-string, the element can't be formatted into
multiline if it has a format specifier because otherwise the newline
would be treated as part of the format specifier.
Given the following f-string:
```python
f"""aaaaaaaaaaaaaaaa bbbbbbbbbbbbbbbbbb ccccccccccc {
variable:.3f} ddddddddddddddd eeeeeeee"""
```
The formatter sees that the f-string is already multiline so it assumes
that it can contain line breaks i.e., broken into multiple lines. But,
in this specific case we can't format it as:
```python
f"""aaaaaaaaaaaaaaaa bbbbbbbbbbbbbbbbbb ccccccccccc {
variable:.3f
} ddddddddddddddd eeeeeeee"""
```
Because the format specifier string would become ".3f\n", which is not
the original string (`.3f`).
If the original source code already contained a newline, they'll be
preserved. For example:
```python
f"""aaaaaaaaaaaaaaaa bbbbbbbbbbbbbbbbbb ccccccccccc {
variable:.3f
} ddddddddddddddd eeeeeeee"""
```
The above will be formatted as:
```py
f"""aaaaaaaaaaaaaaaa bbbbbbbbbbbbbbbbbb ccccccccccc {variable:.3f
} ddddddddddddddd eeeeeeee"""
```
Note that the newline after `.3f` is part of the format specifier which
needs to be preserved.
The Python version is irrelevant in this case.
fixes: #10040
## Test Plan
Add some test cases to verify this behavior.
This commit is contained in:
parent
16a1f3cbcc
commit
77a72ecd38
7 changed files with 220 additions and 31 deletions
|
|
@ -129,6 +129,10 @@ x = f"{ # comment 12
|
|||
{'x': 1, 'y': 2} }"
|
||||
x = f"{ # comment 13
|
||||
{'x': 1, 'y': 2} = }"
|
||||
# But, if there's a format specifier or a conversion flag then we don't need to add
|
||||
# any whitespace at the end
|
||||
x = f"aaaaa { {'aaaaaa', 'bbbbbbb', 'ccccccccc'}!s} bbbbbb"
|
||||
x = f"aaaaa { {'aaaaaa', 'bbbbbbb', 'ccccccccc'}:.3f} bbbbbb"
|
||||
|
||||
# But, in this case, we would split the expression itself because it exceeds the line
|
||||
# length limit so we need not add the extra space.
|
||||
|
|
@ -207,6 +211,29 @@ f"{ # comment 15
|
|||
}" # comment 19
|
||||
# comment 20
|
||||
|
||||
# Single-quoted f-strings with a format specificer can be multiline
|
||||
f"aaaaaaaaaaaaaaaa bbbbbbbbbbbbbbbbbb ccccccccccc {
|
||||
variable:.3f} ddddddddddddddd eeeeeeee"
|
||||
|
||||
# But, if it's triple-quoted then we can't or the format specificer will have a
|
||||
# trailing newline
|
||||
f"""aaaaaaaaaaaaaaaa bbbbbbbbbbbbbbbbbb ccccccccccc {
|
||||
variable:.3f} ddddddddddddddd eeeeeeee"""
|
||||
|
||||
# But, we can break the ones which don't have a format specifier
|
||||
f"""fooooooooooooooooooo barrrrrrrrrrrrrrrrrrr {
|
||||
xxxxxxxxxxxxxxx:.3f} aaaaaaaaaaaaaaaaa { xxxxxxxxxxxxxxxxxxxx } bbbbbbbbbbbb"""
|
||||
|
||||
# Throw in a random comment in it but surpise, this is not a comment but just a text
|
||||
# which is part of the format specifier
|
||||
aaaaaaaaaaa = f"""asaaaaaaaaaaaaaaaa {
|
||||
aaaaaaaaaaaa + bbbbbbbbbbbb + ccccccccccccccc + dddddddd:.3f
|
||||
# comment
|
||||
} cccccccccc"""
|
||||
aaaaaaaaaaa = f"""asaaaaaaaaaaaaaaaa {
|
||||
aaaaaaaaaaaa + bbbbbbbbbbbb + ccccccccccccccc + dddddddd:.3f
|
||||
# comment} cccccccccc"""
|
||||
|
||||
# Conversion flags
|
||||
#
|
||||
# This is not a valid Python code because of the additional whitespace between the `!`
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue