F-String Formatting Style #9785
Replies: 3 comments 9 replies
-
I think it would be useful to also see how yapf (google/yapf#1136) and autopep8 (hhatto/autopep8#712) decide to implement this formalization. |
Beta Was this translation helpful? Give feedback.
-
Style decision: IndentationWhat should be the indentation level of the expression part of an f-string? The problem here is that the formatter can't push the For example: if indent0:
if indent1:
if indent2:
foo = f"""
# Heading
--------- {
[
"aaaaaaaaaaaaaaaaaaaaa",
"bbbbbbbbbbbbbbbbbbbbb",
"ccccccccccccccccccccc",
"ddddddddddddddddddddd"
]
} ----------
""" 1Should it be relative to the enclosing node? if indent0:
if indent1:
if indent2:
foo = f"""
# Heading
--------- {
[
"aaaaaaaaaaaaaaaaaaaaa",
"bbbbbbbbbbbbbbbbbbbbb",
"ccccccccccccccccccccc",
"ddddddddddddddddddddd",
]
} ----------
""" 2Should it be relative to the opening curly brace? This is problematic because the opening curly brace could be at a position which is not in multiples of 4 as there's text before it. if indent0:
if indent1:
if indent2:
foo = f"""
# heading
--------- {
[
"aaaaaaaaaaaaaaaaaaaaa",
"bbbbbbbbbbbbbbbbbbbbb",
"ccccccccccccccccccccc",
"ddddddddddddddddddddd",
]
} ----------
""" 3Should it be always be an absolute 4 space indent from line start? if indent0:
if indent1:
if indent2:
foo = f"""
# heading
--------- {
[
"aaaaaaaaaaaaaaaaaaaaa",
"bbbbbbbbbbbbbbbbbbbbb",
"ccccccccccccccccccccc",
"ddddddddddddddddddddd",
]
} ----------
""" Real world example: https://github.com/python-poetry/poetry/blob/f49f3ee838379c26790dda60893ff51ab431e975/tests/packages/test_locker.py#L1162-L1190 |
Beta Was this translation helpful? Give feedback.
-
Since this was brought up in psf/black#3822 (comment), here are my opinions, going over the examples in the OP:
However, it's hard for a formatter to decide on exact line breaks, so in Black I'd leave this up to users to do.
Self-documenting expressions section: You actually can't normalize whitespace in the format spec either, because that can affect behavior. See psf/black#4112 (comment). |
Beta Was this translation helpful? Give feedback.
-
This document provides examples to initiate a discussion on formatting f-strings, particularly the expression part, which can now be broken into multiple lines as of Python 3.12.
The main decision which needs to be taken is when to add line breaks within the replacement field of f-strings, especially when either or all of the following are present:
Another important one is regarding quotes. Now that we’re allowed to re-use the same quotation style in f-strings, should the same quote be used throughout the f-string?
Black's implementation: psf/black#3822
Ruff's implementation: #9642
Tagging some folks to initiate a conversation to keep the style compatible with Black @tusharsadhwani @ambv
Examples:
This can be best discussed with various examples:
1
A simple expression containing a comment right after the opening curly braces.
Possible formatting style:
2
Taking the example from above and adding a few additional comments:
And some more:
The code snippets in (2) illustrate the preferred style for formatting f-strings with comments.
3
When there are more than 1 replacement field and the f-string exceeds the line-length
Should we only break the expression from left to right?
Or, break it from right to left?
Or, both expressions?
And, should this be parenthesized?
4
When the expression is either a dictionary or set, then we need to surround the expression with an additional whitespace to not escape the curly brace. But, this is only to be done if the expression doesn’t fit on the line.
Here, we need to preserve the whitespace between the opening curly brace of the replacement field and the set otherwise it behaves as escaping the opening curly braces. The question is whether to add a whitespace before the closing curly braces for consistency?
5
When the expression is a collection exceeding the line-length
Should we break it twice? This means to break at both
{
and[
.Or, hug the parentheses as done in the preview style?
6
If the conversion flag is present, should it always be right after the expression or can it go to another line? I think it should be the former, even in the case the expression breaks into multiple lines like the example shown above. So,
Not breaking before the conversion flag:
But, if there’s a collection instead:
7
Should we break before the
:
token if format spec is present and the f-string breaks across multiple lines with expression? This would be a bit similar to formatting a slice expression.Should the above be formatted as the following? The downside here is that it’s difficult to notice the format specifier otherwise.
Or,
Note that whitespaces aren’t allowed in the format spec. Here, the line break is allowed because the newline character ends the format specifier. This creates an interesting code snippet which is valid during parsing and runtime:
Here, the
comment 2
is actually a valid comment. But, if it’s placed right after the format specifier, then it’s invalid and will be part of the format specifier as a string. This is because of #7787.8
Should we re-use the same quotes throughout the f-string?
f"first {f"second" + "third"} fourth"
Self-documenting expression
When self-documenting expressions are present in an f-string (
=
after an expression), then all whitespace needs to be preserved which means the formatter shouldn’t take any decisions at all. But, we can still normalize whitespace / format the conversion flag and format spec because that isn’t used in the string value. For example,We can format the above as:
Because both are equivalent. And, whitespace isn’t allowed in the format specifier otherwise it raises a
ValueError
with the message “Space not allowed in string format specifier”.Another question here is whether to preserve whitespace for nested f-strings when a self-documenting expression is present in the parent f-string. For example,
Here, the whitespace in the nested f-string is preserved in the output (
f”{x }”
) but if there’s a comment or newline, then we get unexpected output:Here, the newlines and comment after the nested f-string (
f”{x
) isn’t preserved in the output.With that, I think we should stop formatting the current f-string once we encounter a self-documenting expression.
Beta Was this translation helpful? Give feedback.
All reactions