Add f-string formatting to the docs (#15367)

Revive https://github.com/astral-sh/ruff/pull/15341 as it got removed
from the latest rebase in https://github.com/astral-sh/ruff/pull/15238.
This commit is contained in:
Dhruv Manilawala 2025-01-09 13:26:22 +05:30 committed by Micha Reiser
parent 29f6653318
commit f706c3fdf2
4 changed files with 119 additions and 18 deletions

View file

@ -19,7 +19,7 @@ filed in the issue tracker. If you've identified a new deviation, please [file a
When run over _non_-Black-formatted code, the formatter makes some different decisions than Black,
and so more deviations should be expected, especially around the treatment of end-of-line comments.
For details, see [Black compatibility](https://docs.astral.sh/ruff/formatter/#black-compatibility).
For details, see [Style Guide](https://docs.astral.sh/ruff/formatter/#style-guide).
## Getting started

View file

@ -28,7 +28,7 @@ to see a few differences on the margins, but the vast majority of your code shou
When run over _non_-Black-formatted code, the formatter makes some different decisions than Black,
and so more deviations should be expected, especially around the treatment of end-of-line comments.
See [_Black compatibility_](formatter.md#black-compatibility) for more.
See [_Style Guide_](formatter.md#style-guide) for more.
## How does Ruff's linter compare to Flake8?

View file

@ -33,7 +33,7 @@ adoption is minimally disruptive for the vast majority of projects.
Specifically, the formatter is intended to emit near-identical output when run over existing
Black-formatted code. When run over extensive Black-formatted projects like Django and Zulip, > 99.9%
of lines are formatted identically. (See: [_Black compatibility_](#black-compatibility).)
of lines are formatted identically. (See: [_Style Guide](#style-guide).)
Given this focus on Black compatibility, the formatter thus adheres to [Black's (stable) code style](https://black.readthedocs.io/en/stable/the_black_code_style/current_style.html),
which aims for "consistency, generality, readability and reducing git diffs". To give you a sense
@ -373,21 +373,10 @@ Meanwhile, `ruff format --check` exits with the following status codes:
- `2` if Ruff terminates abnormally due to invalid configuration, invalid CLI options, or an
internal error.
## Black compatibility
## Style Guide
The formatter is designed to be a drop-in replacement for [Black](https://github.com/psf/black).
Specifically, the formatter is intended to emit near-identical output when run over Black-formatted
code. When run over extensive Black-formatted projects like Django and Zulip, > 99.9% of lines
are formatted identically. When migrating an existing project from Black to Ruff, you should expect
to see a few differences on the margins, but the vast majority of your code should be unchanged.
When run over _non_-Black-formatted code, the formatter makes some different decisions than Black,
and so more deviations should be expected, especially around the treatment of end-of-line comments.
If you identify deviations in your project, spot-check them against the [known deviations](formatter/black.md),
as well as the [unintentional deviations](https://github.com/astral-sh/ruff/issues?q=is%3Aopen+is%3Aissue+label%3Aformatter)
filed in the issue tracker. If you've identified a new deviation, please [file an issue](https://github.com/astral-sh/ruff/issues/new).
This section documents the areas where the Ruff formatter goes beyond Black in terms of code style.
### Intentional deviations
@ -398,11 +387,120 @@ Black's code style, while others fall out of differences in the underlying imple
For a complete enumeration of these intentional deviations, see [_Known deviations_](formatter/black.md).
Unintentional deviations from Black are tracked in the [issue tracker](https://github.com/astral-sh/ruff/issues?q=is%3Aopen+is%3Aissue+label%3Aformatter).
If you've identified a new deviation, please [file an issue](https://github.com/astral-sh/ruff/issues/new).
### Preview style
Similar to [Black](https://black.readthedocs.io/en/stable/the_black_code_style/future_style.html#preview-style), Ruff implements formatting changes
Similar to [Black](https://black.readthedocs.io/en/stable/the_black_code_style/future_style.html#preview-style), Ruff implements formatting changes
under the [`preview`](https://docs.astral.sh/ruff/settings/#format_preview) flag, promoting them to stable through minor releases, in accordance with our [versioning policy](https://github.com/astral-sh/ruff/discussions/6998#discussioncomment-7016766).
### F-string formatting
_Stabilized in Ruff 0.9.0_
Unlike Black, Ruff formats the expression parts of f-strings which are the parts inside the curly
braces `{...}`. This is a [known deviation](formatter/black.md#f-strings) from Black.
Ruff employs several heuristics to determine how an f-string should be formatted which are detailed
below.
#### Quotes
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 or requires more backslash escapes than the original
expression. Specifically, Ruff will preserve the original quote style for the following cases:
When the target Python version is < 3.12 and a [self-documenting f-string] contains a string
literal with the [configured quote style]:
```python
# format.quote-style = "double"
f'{10 + len("hello")=}'
# This f-string cannot be formatted as follows when targeting Python < 3.12
f"{10 + len("hello")=}"
```
When the target Python version is < 3.12 and an f-string contains any triple-quoted string, byte
or f-string literal that contains the [configured quote style]:
```python
# format.quote-style = "double"
f'{"""nested " """}'`
# This f-string cannot be formatted as follows when targeting Python < 3.12
f"{'''nested " '''}``
```
For all target Python versions, when a [self-documenting f-string] contains an expression between
the curly braces (`{...}`) with a format specifier containing the [configured quote style]:
```python
# format.quote-style = "double"
f'{1=:"foo}'
# This f-string cannot be formatted as follows for all target Python versions
f"{1=:"foo}"
```
For nested f-strings, Ruff alternates quote styles, starting with the [configured quote style] for the
outermost f-string. For example, consider the following f-string:
```python
# format.quote-style = "double"
f"outer f-string {f"nested f-string {f"another nested f-string"} end"} end"
```
Ruff formats it as:
```python
f"outer f-string {f'nested f-string {f"another nested f-string"} end'} end"
```
#### Line breaks
Starting with Python 3.12 ([PEP 701](https://peps.python.org/pep-0701/)), the expression parts of an f-string can
span multiple lines. Ruff needs to decide when to introduce a line break in an f-string expression.
This depends on the semantic content of the expression parts of an f-string - for example,
introducing a line break in the middle of a natural-language sentence is undesirable. Since Ruff
doesn't have enough information to make that decision, it adopts a heuristic similar to [Prettier](https://prettier.io/docs/en/next/rationale.html#template-literals):
it will only split the expression parts of an f-string across multiple lines if there was already a line break
within any of the expression parts.
For example, the following code:
```python
f"this f-string has a multiline expression {
['red', 'green', 'blue', 'yellow',]} and does not fit within the line length"
```
... is formatted as:
```python
# The list expression is split across multiple lines because of the trailing comma
f"this f-string has a multiline expression {
[
'red',
'green',
'blue',
'yellow',
]
} and does not fit within the line length"
```
But, the following will not be split across multiple lines even though it exceeds the line length:
```python
f"this f-string has a multiline expression {['red', 'green', 'blue', 'yellow']} and does not fit within the line length"
```
If you want Ruff to split an f-string across multiple lines, ensure there's a linebreak somewhere within the
`{...}` parts of an f-string.
[self-documenting f-string]: https://realpython.com/python-f-strings/#self-documenting-expressions-for-debugging
[configured quote style]: settings.md/#format_quote-style
## Sorting imports
Currently, the Ruff formatter does not sort imports. In order to both sort imports and format,

View file

@ -253,6 +253,9 @@ f'test{inner + "nested_string"} including math {5 ** 3 + 10}'
f"test{inner + 'nested_string'} including math {5**3 + 10}"
```
For more details on the formatting style, refer to the [f-string
formatting](../formatter.md#f-string-formatting) section.
### Implicit concatenated strings
Ruff merges implicitly concatenated strings if the entire string fits on a single line:
@ -348,7 +351,7 @@ match some_variable:
) or last_condition:
pass
# Ruff
match some_variable:
case "short-guard" if other_condition: