Skip to content
Permalink

Comparing changes

This is a direct comparison between two commits made in this repository or its related repositories. View the default comparison for this range or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: astral-sh/ruff
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: 512aa0abf4393767e19fd1cd6b7026bb517f1aa1
Choose a base ref
..
head repository: astral-sh/ruff
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: 7d2f6ccfa51d492e860c1540a377eb0b99cbd979
Choose a head ref
Showing with 25 additions and 21 deletions.
  1. +25 −21 docs/formatter.md
46 changes: 25 additions & 21 deletions docs/formatter.md
Original file line number Diff line number Diff line change
@@ -232,45 +232,49 @@ _Stabilized in 2025 style with Ruff 0.9.0_
By default, Ruff formats f-string expressions. This is a [known deviation](formatter/black.md#f-strings)
from Black, which does not format f-strings.

Ruff utilizes multiple heuristics to determine how an f-string should be formatted which includes
what quote style to use for both outer and any nested f-strings, whether to break the f-string into
multiple lines, and when to skip formatting the f-string.
Ruff employs several heuristics to determine how an f-string should be formatted, including the
following considerations:

* The quote style for both outer and nested f-strings
* Whether to break the f-string into multiple lines
* When to skip formatting the f-string altogether

### Quotes

Ruff will use the configured quote style for the f-string expression unless it would result in
an invalid syntax as per the target Python version. In such cases, Ruff will avoid changing the
quote style. There are multiple cases where this could happen like when a self-documenting f-string
contains a string literal with the configured quote style, it's not possible to use the same quote
style for the f-string expression when the target version is less than 3.12.
Ruff will use the configured quote style for the f-string expression unless doing so would result in
invalid syntax for the target Python version. In such cases, Ruff will avoid changing the
quote style.

For example, if a self-documenting f-string contains a string literal with the configured quote
style, Ruff cannot use the same quote style for the f-string itself when targeting Python versions
earlier than 3.12:

```python
f'{10 + len("hello")=}'
# The above f-string cannot be formatted as below when the target version is less than 3.12
# This f-string cannot be formatted as follows when targeting Python < 3.12
f"{10 + len("hello")=}"
```

For nested f-strings, Ruff will use an alternating quote style starting with the configured quote
style for the outermost f-string expression. If this would result in an invalid syntax, Ruff will
avoid changing the quote style. For example, the following f-string expression:
For nested f-strings, Ruff alternates quote styles, starting with the configured style for the
outermost f-string. If this would result in an invalid syntax, Ruff avoids changing the quote style.
For example, consider the following f-string:

```python
f"outer f-string {f"nested f-string {f"another nested f-string"} end"} end"
```

... will be formatted as:
Ruff formats it as:

```python
f"outer f-string {f'nested f-string {f"another nested f-string"} end'} end"
```

### Line breaks

F-string expressions can be broken into multiple lines from Python 3.12 onwards ([PEP
701](https://peps.python.org/pep-0701/)). Ruff has chosen to follow a similar heuristic as
[Prettier](https://prettier.io/docs/en/next/rationale.html#template-literals) for when to
introduce a linebreak in an f-string expression: it will only split the f-string across multiple
lines if there was already a linebreak in the f-string expression.
Starting with Python 3.12 ([PEP 701](https://peps.python.org/pep-0701/)), f-string expressions can
span multiple lines. Ruff adopts a similar heuristic as [Prettier](https://prettier.io/docs/en/next/rationale.html#template-literals)
for when to introduce a line break in an f-string expression: it introduces line breaks only
if the original f-string expression already contains them.

For example, the following code:

@@ -279,7 +283,7 @@ f"this f-string has a multiline expression {
['red', 'green', 'blue', 'yellow',]} and does not fit within the line length"
```

... will be formatted as:
... is formatted as:

```python
# The list expression is split across multiple lines because of the trailing comma
@@ -293,8 +297,8 @@ f"this f-string has a multiline expression {
} and does not fit within the line length"
```

This means that if you want Ruff to split an f-string across multiple lines, you'll need to
ensure there's a linebreak within the `{...}` expression.
If you want Ruff to split an f-string across multiple lines, ensure there's a linebreak within the
`{...}` expression.

## Format suppression