mirror of
https://github.com/astral-sh/ruff.git
synced 2025-09-30 22:01:47 +00:00
Implement template strings (#17851)
This PR implements template strings (t-strings) in the parser and formatter for Ruff. Minimal changes necessary to compile were made in other parts of the code (e.g. ty, the linter, etc.). These will be covered properly in follow-up PRs.
This commit is contained in:
parent
ad024f9a09
commit
9bbf4987e8
261 changed files with 18023 additions and 1802 deletions
|
@ -431,3 +431,16 @@ f"hellooooooooooooooooooooooo \
|
|||
worlddddddddddddddddddddddddddddddddd" + (aaaaaaaaaaaaaaaaaaaaaaaaaa + bbbbbbbbbbbbbbbbbbb)
|
||||
aaaaaaaaaaa = f"hellooooooooooooooooooooooo \
|
||||
worlddddddddddddddddddddddddddddddddd" + (aaaaaaaaaaaaaaaaaaaaaaaaaa + bbbbbbbbbbbbbbbbbbb)
|
||||
|
||||
# This t-string should be flattened
|
||||
xxxxxxxxxxxxxxxx = t"aaaaaaaaaaaaaaaaaaaaa {
|
||||
expression } bbbbbbbbbbbbbbbbbbbbbbbb" + (
|
||||
yyyyyyyyyyyyyy + zzzzzzzzzzz
|
||||
)
|
||||
|
||||
# This is not a multiline t-string, but the expression is too long so it should be
|
||||
# wrapped in parentheses.
|
||||
t"hellooooooooooooooooooooooo \
|
||||
worlddddddddddddddddddddddddddddddddd" + (aaaaaaaaaaaaaaaaaaaaaaaaaa + bbbbbbbbbbbbbbbbbbb)
|
||||
aaaaaaaaaaa = t"hellooooooooooooooooooooooo \
|
||||
worlddddddddddddddddddddddddddddddddd" + (aaaaaaaaaaaaaaaaaaaaaaaaaa + bbbbbbbbbbbbbbbbbbb)
|
||||
|
|
|
@ -100,6 +100,55 @@ f"{10 + len('bar')=}" f'no debug{10}' f"{10 + len('bar')=}"
|
|||
f"{10 + len('bar')=}" f'{10 + len("bar")=}'
|
||||
|
||||
|
||||
##############################################################################
|
||||
# T-strings
|
||||
##############################################################################
|
||||
|
||||
# Escape `{` and `}` when merging a t-string with a string
|
||||
"a {not_a_variable}" t"b {10}" "c"
|
||||
|
||||
# Join, and break expressions
|
||||
t"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa{
|
||||
expression
|
||||
}bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb" t"cccccccccccccccccccc {20999}" "more"
|
||||
|
||||
# Join, but don't break the expressions
|
||||
t"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa{expression}bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb" t"cccccccccccccccccccc {20999}" "more"
|
||||
|
||||
t"test{
|
||||
expression
|
||||
}flat" t"can be {
|
||||
joined
|
||||
} together"
|
||||
|
||||
aaaaaaaaaaa = t"test{
|
||||
expression
|
||||
}flat" t"cean beeeeeeee {
|
||||
joined
|
||||
} eeeeeeeeeeeeeeeeeeeeeeeeeeeee" # inline
|
||||
|
||||
|
||||
t"single quoted '{x}'" t'double quoted "{x}"' # Same number of quotes => use preferred quote style
|
||||
t"single quote ' {x}" t'double quoted "{x}"' # More double quotes => use single quotes
|
||||
t"single quoted '{x}'" t'double quote " {x}"' # More single quotes => use double quotes
|
||||
|
||||
# Different triple quoted strings
|
||||
t"{'''test'''}" t'{"""other"""}'
|
||||
|
||||
# Now with inner quotes
|
||||
t"{'''test ' '''}" t'{"""other " """}'
|
||||
t"{some_where_nested('''test ' ''')}" t'{"""other " """ + "more"}'
|
||||
t"{b'''test ' '''}" t'{b"""other " """}'
|
||||
t"{t'''test ' '''}" t'{t"""other " """}'
|
||||
|
||||
# debug expressions containing quotes
|
||||
t"{10 + len('bar')=}" t"{10 + len('bar')=}"
|
||||
t"{10 + len('bar')=}" t'no debug{10}' t"{10 + len('bar')=}"
|
||||
|
||||
# We can't safely merge this pre Python 3.12 without altering the debug expression.
|
||||
t"{10 + len('bar')=}" t'{10 + len("bar")=}'
|
||||
|
||||
|
||||
##############################################################################
|
||||
# Don't join raw strings
|
||||
##############################################################################
|
||||
|
@ -110,6 +159,9 @@ R"a" "normal"
|
|||
f"test" fr"test"
|
||||
f"test" fR"test"
|
||||
|
||||
t"test" tr"test"
|
||||
t"test" tR"test"
|
||||
|
||||
|
||||
##############################################################################
|
||||
# Don't join triple quoted strings
|
||||
|
@ -119,9 +171,22 @@ f"test" fR"test"
|
|||
|
||||
"single" f""""single"""
|
||||
|
||||
"single" t""""single"""
|
||||
|
||||
b"single" b"""triple"""
|
||||
|
||||
|
||||
##############################################################################
|
||||
# Don't join t-strings and f-strings
|
||||
##############################################################################
|
||||
|
||||
t"{interp}" f"{expr}"
|
||||
|
||||
f"{expr}" t"{interp}"
|
||||
|
||||
f"{expr}" "string" t"{interp}"
|
||||
|
||||
|
||||
##############################################################################
|
||||
# Join strings in with statements
|
||||
##############################################################################
|
||||
|
|
|
@ -293,6 +293,155 @@ aaaaa[aaaaaaaaaaa] = (
|
|||
)
|
||||
|
||||
|
||||
#############################################################
|
||||
# T-Strings
|
||||
#############################################################
|
||||
|
||||
# Flatten and join the t-string
|
||||
aaaaaaaaaaa = t"test{
|
||||
expression}flat" t"cean beeeeeeee {joined} eeeeeeeeeeeeeeeee" # inline
|
||||
|
||||
# Parenthesize the value and join it, inline the comment
|
||||
aaaaaaaaaaa = t"test{
|
||||
expression}flat" t"cean beeeeeeee {joined} eeeeeeeeeeeeeeeeeeeeeeeeeee" # inline
|
||||
|
||||
# Parenthesize the t-string and keep it multiline because it doesn't fit on a single line including the comment
|
||||
aaaaaaaaaaa = t"test{
|
||||
expression
|
||||
}flat" t"cean beeeeeeee {
|
||||
joined
|
||||
} eeeeeeeeeeeeeeeeeeeeeeeeeeeee" # inline
|
||||
|
||||
|
||||
# The target splits because of a magic trailing comma
|
||||
# The string is joined and not parenthesized because it just fits into the line length (including comment).
|
||||
a[
|
||||
aaaaaaa,
|
||||
b,
|
||||
] = t"ccccc{
|
||||
expression}ccccccccccc" t"cccccccccccccccccccccccccccccccccccccccccc" # comment
|
||||
|
||||
|
||||
# Same but starting with a joined string. They should both result in the same formatting.
|
||||
[
|
||||
aaaaaaa,
|
||||
b,
|
||||
] = t"ccccc{
|
||||
expression}ccccccccccccccccccccccccccccccccccccccccccccccccccccc" # comment
|
||||
|
||||
# The target splits because of the magic trailing comma
|
||||
# The string is **not** joined because it with the inlined comment exceeds the line length limit.
|
||||
a[
|
||||
aaaaaaa,
|
||||
b,
|
||||
] = t"ccccc{
|
||||
expression}cccccccccccccccccccc" t"cccccccccccccccccccccccccccccccccccccccccc" # comment
|
||||
|
||||
|
||||
# The target should be flat
|
||||
# The string should be joined because it fits into the line length
|
||||
a[
|
||||
aaaaaaa,
|
||||
b
|
||||
] = (
|
||||
t"ccccc{
|
||||
expression}ccccccccccc" "cccccccccccccccccccccccc" # comment
|
||||
)
|
||||
|
||||
# Same but starting with a joined string. They should both result in the same formatting.
|
||||
a[
|
||||
aaaaaaa,
|
||||
b
|
||||
] = t"ccccc{
|
||||
expression}ccccccccccccccccccccccccccccccccccc" # comment
|
||||
|
||||
# The target should be flat
|
||||
# The string gets parenthesized because it, with the inlined comment, exceeds the line length limit.
|
||||
a[
|
||||
aaaaaaa,
|
||||
b
|
||||
] = t"ccccc{
|
||||
expression}ccccccccccc" "ccccccccccccccccccccccccccccccccccccccccccc" # comment
|
||||
|
||||
|
||||
# Split an overlong target, but join the string if it fits
|
||||
a[
|
||||
aaaaaaa,
|
||||
b
|
||||
].bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb = (
|
||||
t"ccccc{
|
||||
expression}ccccccccccc" "cccccccccccccccccccccccccccccc" # comment
|
||||
)
|
||||
|
||||
# Split both if necessary and keep multiline
|
||||
a[
|
||||
aaaaaaa,
|
||||
b
|
||||
].bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb = (
|
||||
t"ccccc{
|
||||
expression}cccccccccccccccccccccccccccccccc" "ccccccccccccccccccccccccccccccc" # comment
|
||||
)
|
||||
|
||||
# Don't inline t-strings that contain expressions that are guaranteed to split, e.b. because of a magic trailing comma
|
||||
aaaaaaaaaaaaaaaaaa = t"testeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee{
|
||||
[a,]
|
||||
}" "moreeeeeeeeeeeeeeeeeeee" "test" # comment
|
||||
|
||||
aaaaaaaaaaaaaaaaaa = (
|
||||
t"testeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee{
|
||||
[a,]
|
||||
}" "moreeeeeeeeeeeeeeeeeeee" "test" # comment
|
||||
)
|
||||
|
||||
aaaaa[aaaaaaaaaaa] = t"testeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee{
|
||||
[a,]
|
||||
}" "moreeeeeeeeeeeeeeeeeeee" "test" # comment
|
||||
|
||||
aaaaa[aaaaaaaaaaa] = (t"testeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee{
|
||||
[a,]
|
||||
}" "moreeeeeeeeeeeeeeeeeeee" "test" # comment
|
||||
)
|
||||
|
||||
# Don't inline t-strings that contain commented expressions
|
||||
aaaaaaaaaaaaaaaaaa = (
|
||||
t"testeeeeeeeeeeeeeeeeeeeeeeeee{[
|
||||
a # comment
|
||||
]}" "moreeeeeeeeeeeeeeeeeetest" # comment
|
||||
)
|
||||
|
||||
aaaaa[aaaaaaaaaaa] = (
|
||||
t"testeeeeeeeeeeeeeeeeeeeeeeeee{[
|
||||
a # comment
|
||||
]}" "moreeeeeeeeeeeeeeeeeetest" # comment
|
||||
)
|
||||
|
||||
# Don't inline t-strings with multiline debug expressions:
|
||||
aaaaaaaaaaaaaaaaaa = (
|
||||
t"testeeeeeeeeeeeeeeeeeeeeeeeee{
|
||||
a=}" "moreeeeeeeeeeeeeeeeeetest" # comment
|
||||
)
|
||||
|
||||
aaaaaaaaaaaaaaaaaa = (
|
||||
t"testeeeeeeeeeeeeeeeeeeeeeeeee{a +
|
||||
b=}" "moreeeeeeeeeeeeeeeeeetest" # comment
|
||||
)
|
||||
|
||||
aaaaaaaaaaaaaaaaaa = (
|
||||
t"testeeeeeeeeeeeeeeeeeeeeeeeee{a
|
||||
=}" "moreeeeeeeeeeeeeeeeeetest" # comment
|
||||
)
|
||||
|
||||
aaaaa[aaaaaaaaaaa] = (
|
||||
t"testeeeeeeeeeeeeeeeeeeeeeeeee{
|
||||
a=}" "moreeeeeeeeeeeeeeeeeetest" # comment
|
||||
)
|
||||
|
||||
aaaaa[aaaaaaaaaaa] = (
|
||||
t"testeeeeeeeeeeeeeeeeeeeeeeeee{a
|
||||
=}" "moreeeeeeeeeeeeeeeeeetest" # comment
|
||||
)
|
||||
|
||||
|
||||
# Trailing last-part comments
|
||||
|
||||
a = (
|
||||
|
@ -374,4 +523,4 @@ self._attr_unique_id = (
|
|||
return (
|
||||
f"Exception in {call_back_name} when handling msg on "
|
||||
f"'{msg.topic}': '{msg.payload}'" # type: ignore[str-bytes-safe]
|
||||
)
|
||||
)
|
||||
|
|
1
crates/ruff_python_formatter/resources/test/fixtures/ruff/expression/tstring.options.json
vendored
Normal file
1
crates/ruff_python_formatter/resources/test/fixtures/ruff/expression/tstring.options.json
vendored
Normal file
|
@ -0,0 +1 @@
|
|||
[{"target_version": "3.14"}]
|
731
crates/ruff_python_formatter/resources/test/fixtures/ruff/expression/tstring.py
vendored
Normal file
731
crates/ruff_python_formatter/resources/test/fixtures/ruff/expression/tstring.py
vendored
Normal file
|
@ -0,0 +1,731 @@
|
|||
(
|
||||
t'{one}'
|
||||
t'{two}'
|
||||
)
|
||||
|
||||
|
||||
rt"Not-so-tricky \"quote"
|
||||
|
||||
# Regression test for tstrings dropping comments
|
||||
result_f = (
|
||||
'Traceback (most recent call last):\n'
|
||||
t' File "{__file__}", line {lineno_f+5}, in _check_recursive_traceback_display\n'
|
||||
' f()\n'
|
||||
t' File "{__file__}", line {lineno_f+1}, in f\n'
|
||||
' f()\n'
|
||||
t' File "{__file__}", line {lineno_f+1}, in f\n'
|
||||
' f()\n'
|
||||
t' File "{__file__}", line {lineno_f+1}, in f\n'
|
||||
' f()\n'
|
||||
# XXX: The following line changes depending on whether the tests
|
||||
# are run through the interactive interpreter or with -m
|
||||
# It also varies depending on the platform (stack size)
|
||||
# Fortunately, we don't care about exactness here, so we use regex
|
||||
r' \[Previous line repeated (\d+) more times\]' '\n'
|
||||
'RecursionError: maximum recursion depth exceeded\n'
|
||||
)
|
||||
|
||||
|
||||
# Regression for tstring dropping comments that were accidentally attached to
|
||||
# an expression inside a formatted value
|
||||
(
|
||||
t'{1}'
|
||||
# comment 1
|
||||
''
|
||||
)
|
||||
|
||||
(
|
||||
t'{1}' # comment 2
|
||||
t'{2}'
|
||||
)
|
||||
|
||||
(
|
||||
t'{1}'
|
||||
t'{2}' # comment 3
|
||||
)
|
||||
|
||||
(
|
||||
1, ( # comment 4
|
||||
t'{2}'
|
||||
)
|
||||
)
|
||||
|
||||
(
|
||||
(
|
||||
t'{1}'
|
||||
# comment 5
|
||||
),
|
||||
2
|
||||
)
|
||||
|
||||
# https://github.com/astral-sh/ruff/issues/6841
|
||||
x = t'''a{""}b'''
|
||||
y = t'''c{1}d"""e'''
|
||||
z = t'''a{""}b''' t'''c{1}d"""e'''
|
||||
|
||||
# T-String formatting test cases (Preview)
|
||||
|
||||
# Simple expression with a mix of debug expression and comments.
|
||||
x = t"{a}"
|
||||
x = t"{
|
||||
a = }"
|
||||
x = t"{ # comment 6
|
||||
a }"
|
||||
x = t"{ # comment 7
|
||||
a = }"
|
||||
|
||||
# Remove the parentheses as adding them doesn't make then fit within the line length limit.
|
||||
# This is similar to how we format it before t-string formatting.
|
||||
aaaaaaaaaaa = (
|
||||
t"asaaaaaaaaaaaaaaaa { aaaaaaaaaaaa + bbbbbbbbbbbb + ccccccccccccccc + dddddddd } cccccccccc"
|
||||
)
|
||||
# Here, we would use the best fit layout to put the t-string indented on the next line
|
||||
# similar to the next example.
|
||||
aaaaaaaaaaa = t"asaaaaaaaaaaaaaaaa { aaaaaaaaaaaa + bbbbbbbbbbbb + ccccccccccccccc } cccccccccc"
|
||||
aaaaaaaaaaa = (
|
||||
t"asaaaaaaaaaaaaaaaa { aaaaaaaaaaaa + bbbbbbbbbbbb + ccccccccccccccc } cccccccccc"
|
||||
)
|
||||
|
||||
# This should never add the optional parentheses because even after adding them, the
|
||||
# t-string exceeds the line length limit.
|
||||
x = t"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa { "bbbbbbbbbbbbbbbbbbbbbbbbbbbbb" } ccccccccccccccc"
|
||||
x = t"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa { "bbbbbbbbbbbbbbbbbbbbbbbbbbbbb" = } ccccccccccccccc"
|
||||
x = t"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa { # comment 8
|
||||
"bbbbbbbbbbbbbbbbbbbbbbbbbbbbb" } ccccccccccccccc"
|
||||
x = t"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa { # comment 9
|
||||
"bbbbbbbbbbbbbbbbbbbbbbbbbbbbb" = } ccccccccccccccc"
|
||||
x = t"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa { # comment 9
|
||||
'bbbbbbbbbbbbbbbbbbbbbbbbbbbbb' = } ccccccccccccccc"
|
||||
|
||||
# Multiple larger expressions which exceeds the line length limit. Here, we need to decide
|
||||
# whether to split at the first or second expression. This should work similarly to the
|
||||
# assignment statement formatting where we split from right to left in preview mode.
|
||||
x = t"aaaaaaaaaaaa { bbbbbbbbbbbbbb } cccccccccccccccccccc { ddddddddddddddd } eeeeeeeeeeeeee"
|
||||
|
||||
# The above example won't split but when we start introducing line breaks:
|
||||
x = t"aaaaaaaaaaaa {
|
||||
bbbbbbbbbbbbbb } cccccccccccccccccccc { ddddddddddddddd } eeeeeeeeeeeeee"
|
||||
x = t"aaaaaaaaaaaa { bbbbbbbbbbbbbb
|
||||
} cccccccccccccccccccc { ddddddddddddddd } eeeeeeeeeeeeee"
|
||||
x = t"aaaaaaaaaaaa { bbbbbbbbbbbbbb } cccccccccccccccccccc {
|
||||
ddddddddddddddd } eeeeeeeeeeeeee"
|
||||
x = t"aaaaaaaaaaaa { bbbbbbbbbbbbbb } cccccccccccccccccccc { ddddddddddddddd
|
||||
} eeeeeeeeeeeeee"
|
||||
|
||||
# But, in case comments are present, we would split at the expression containing the
|
||||
# comments:
|
||||
x = t"aaaaaaaaaaaa { bbbbbbbbbbbbbb # comment 10
|
||||
} cccccccccccccccccccc { ddddddddddddddd } eeeeeeeeeeeeee"
|
||||
x = t"aaaaaaaaaaaa { bbbbbbbbbbbbbb
|
||||
} cccccccccccccccccccc { # comment 11
|
||||
ddddddddddddddd } eeeeeeeeeeeeee"
|
||||
|
||||
# Here, the expression part itself starts with a curly brace so we need to add an extra
|
||||
# space between the opening curly brace and the expression.
|
||||
x = t"{ {'x': 1, 'y': 2} }"
|
||||
# Although the extra space isn't required before the ending curly brace, we add it for
|
||||
# consistency.
|
||||
x = t"{ {'x': 1, 'y': 2}}"
|
||||
x = t"{ {'x': 1, 'y': 2} = }"
|
||||
x = t"{ # comment 12
|
||||
{'x': 1, 'y': 2} }"
|
||||
x = t"{ # 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 = t"aaaaa { {'aaaaaa', 'bbbbbbb', 'ccccccccc'}!s} bbbbbb"
|
||||
x = t"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.
|
||||
xxxxxxx = t"{
|
||||
{'aaaaaaaaaaaaaaaaaaa', 'bbbbbbbbbbbbbbbbbbbbbb', 'ccccccccccccccccccccc'}
|
||||
}"
|
||||
# And, split the expression itself because it exceeds the line length.
|
||||
xxxxxxx = t"{
|
||||
{'aaaaaaaaaaaaaaaaaaaaaaaaa', 'bbbbbbbbbbbbbbbbbbbbbbbbbbb', 'cccccccccccccccccccccccccc'}
|
||||
}"
|
||||
|
||||
#############################################################################################
|
||||
# Quotes
|
||||
#############################################################################################
|
||||
t"foo 'bar' {x}"
|
||||
t"foo \"bar\" {x}"
|
||||
t'foo "bar" {x}'
|
||||
t'foo \'bar\' {x}'
|
||||
t"foo {"bar"}"
|
||||
|
||||
t"single quoted '{x}' double quoted \"{x}\"" # Same number of quotes => use preferred quote style
|
||||
t"single quote ' {x} double quoted \"{x}\"" # More double quotes => use single quotes
|
||||
t"single quoted '{x}' double quote \" {x}" # More single quotes => use double quotes
|
||||
|
||||
fr"single quotes ' {x}" # Keep double because `'` can't be escaped
|
||||
fr'double quotes " {x}' # Keep single because `"` can't be escaped
|
||||
fr'flip quotes {x}' # Use preferred quotes, because raw string contains now quotes.
|
||||
|
||||
# Here, the formatter will remove the escapes
|
||||
t"foo {'\'bar\''}"
|
||||
t"foo {'\"bar\"'}"
|
||||
|
||||
# Quotes inside the expressions have no impact on the quote selection of the outer string.
|
||||
# Required so that the following two examples result in the same formatting.
|
||||
t'foo {10 + len("bar")}'
|
||||
t"foo {10 + len('bar')}"
|
||||
|
||||
# Pre 312, preserve the outer quotes if the t-string contains quotes in the debug expression
|
||||
t'foo {10 + len("bar")=}'
|
||||
t'''foo {10 + len('''bar''')=}'''
|
||||
t'''foo {10 + len('bar')=}''' # Fine to change the quotes because it uses triple quotes
|
||||
|
||||
# Triple-quoted strings
|
||||
# It's ok to use the same quote char for the inner string if it's single-quoted.
|
||||
t"""test {'inner'}"""
|
||||
t"""test {"inner"}"""
|
||||
# But if the inner string is also triple-quoted then we should preserve the existing quotes.
|
||||
t"""test {'''inner'''}"""
|
||||
|
||||
# It's not okay to change the quote style if the inner string is triple quoted and contains a quote.
|
||||
t'{"""other " """}'
|
||||
t'{"""other " """ + "more"}'
|
||||
t'{b"""other " """}'
|
||||
t'{t"""other " """}'
|
||||
|
||||
t"""test {t'inner {'''inner inner'''}'}"""
|
||||
t"""test {t'''inner {"""inner inner"""}'''}"""
|
||||
|
||||
# Magic trailing comma
|
||||
#
|
||||
# The expression formatting will result in breaking it across multiple lines with a
|
||||
# trailing comma but as the expression isn't already broken, we will remove all the line
|
||||
# breaks which results in the trailing comma being present. This test case makes sure
|
||||
# that the trailing comma is removed as well.
|
||||
t"aaaaaaa {['aaaaaaaaaaaaaaa', 'bbbbbbbbbbbbb', 'ccccccccccccccccc', 'ddddddddddddddd', 'eeeeeeeeeeeeee']} aaaaaaa"
|
||||
|
||||
# And, if the trailing comma is already present, we still need to remove it.
|
||||
t"aaaaaaa {['aaaaaaaaaaaaaaa', 'bbbbbbbbbbbbb', 'ccccccccccccccccc', 'ddddddddddddddd', 'eeeeeeeeeeeeee',]} aaaaaaa"
|
||||
|
||||
# Keep this Multiline by breaking it at the square brackets.
|
||||
t"""aaaaaa {[
|
||||
xxxxxxxx,
|
||||
yyyyyyyy,
|
||||
]} ccc"""
|
||||
|
||||
# Add the magic trailing comma because the elements don't fit within the line length limit
|
||||
# when collapsed.
|
||||
t"aaaaaa {[
|
||||
xxxxxxxxxxxx,
|
||||
xxxxxxxxxxxx,
|
||||
xxxxxxxxxxxx,
|
||||
xxxxxxxxxxxx,
|
||||
xxxxxxxxxxxx,
|
||||
xxxxxxxxxxxx,
|
||||
yyyyyyyyyyyy
|
||||
]} ccccccc"
|
||||
|
||||
# Remove the parentheses because they aren't required
|
||||
xxxxxxxxxxxxxxx = (
|
||||
t"aaaaaaaaaaaaaaaa bbbbbbbbbbbbbbb {
|
||||
xxxxxxxxxxx # comment 14
|
||||
+ yyyyyyyyyy
|
||||
} dddddddddd"
|
||||
)
|
||||
|
||||
# Comments
|
||||
|
||||
# No comments should be dropped!
|
||||
t"{ # comment 15
|
||||
# comment 16
|
||||
foo # comment 17
|
||||
# comment 18
|
||||
}" # comment 19
|
||||
# comment 20
|
||||
|
||||
# Single-quoted t-strings with a format specificer can be multiline
|
||||
t"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
|
||||
t"""aaaaaaaaaaaaaaaa bbbbbbbbbbbbbbbbbb ccccccccccc {
|
||||
variable:.3f} ddddddddddddddd eeeeeeee"""
|
||||
|
||||
# But, we can break the ones which don't have a format specifier
|
||||
t"""fooooooooooooooooooo barrrrrrrrrrrrrrrrrrr {
|
||||
xxxxxxxxxxxxxxx:.3f} aaaaaaaaaaaaaaaaa { xxxxxxxxxxxxxxxxxxxx } bbbbbbbbbbbb"""
|
||||
|
||||
# Throw in a random comment in it but surprise, this is not a comment but just a text
|
||||
# which is part of the format specifier
|
||||
aaaaaaaaaaa = t"""asaaaaaaaaaaaaaaaa {
|
||||
aaaaaaaaaaaa + bbbbbbbbbbbb + ccccccccccccccc + dddddddd:.3f
|
||||
# comment
|
||||
} cccccccccc"""
|
||||
aaaaaaaaaaa = t"""asaaaaaaaaaaaaaaaa {
|
||||
aaaaaaaaaaaa + bbbbbbbbbbbb + ccccccccccccccc + dddddddd:.3f
|
||||
# comment} cccccccccc"""
|
||||
|
||||
# Conversion flags
|
||||
#
|
||||
# This is not a valid Python code because of the additional whitespace between the `!`
|
||||
# and conversion type. But, our parser isn't strict about this. This should probably be
|
||||
# removed once we have a strict parser.
|
||||
x = t"aaaaaaaaa { x ! r }"
|
||||
|
||||
# Even in the case of debug expressions, we only need to preserve the whitespace within
|
||||
# the expression part of the replacement field.
|
||||
x = t"aaaaaaaaa { x = ! r }"
|
||||
|
||||
# Combine conversion flags with format specifiers
|
||||
x = t"{x = ! s
|
||||
:>0
|
||||
|
||||
}"
|
||||
# This is interesting. There can be a comment after the format specifier but only if it's
|
||||
# on it's own line. Refer to https://github.com/astral-sh/ruff/pull/7787 for more details.
|
||||
# We'll format is as trailing comments.
|
||||
x = t"{x !s
|
||||
:>0
|
||||
# comment 21
|
||||
}"
|
||||
|
||||
x = t"""
|
||||
{ # comment 22
|
||||
x = :.0{y # comment 23
|
||||
}f}"""
|
||||
|
||||
# Here, the debug expression is in a nested t-string so we should start preserving
|
||||
# whitespaces from that point onwards. This means we should format the outer t-string.
|
||||
x = t"""{"foo " + # comment 24
|
||||
t"{ x =
|
||||
|
||||
}" # comment 25
|
||||
}
|
||||
"""
|
||||
|
||||
# Mix of various features.
|
||||
t"{ # comment 26
|
||||
foo # after foo
|
||||
:>{
|
||||
x # after x
|
||||
}
|
||||
# comment 27
|
||||
# comment 28
|
||||
} woah {x}"
|
||||
|
||||
# Assignment statement
|
||||
|
||||
# Even though this t-string has multiline expression, thus allowing us to break it at the
|
||||
# curly braces, the t-string fits on a single line if it's moved inside the parentheses.
|
||||
# We should prefer doing that instead.
|
||||
aaaaaaaaaaaaaaaaaa = t"testeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee{
|
||||
expression}moreeeeeeeeeeeeeeeee"
|
||||
|
||||
# Same as above
|
||||
xxxxxxx = t"{
|
||||
{'aaaaaaaaaaaaaaaaaaa', 'bbbbbbbbbbbbbbbbbbb', 'cccccccccccccccccccccccccc'}
|
||||
}"
|
||||
|
||||
# Similar to the previous example, but the t-string will exceed the line length limit,
|
||||
# we shouldn't add any parentheses here.
|
||||
xxxxxxx = t"{
|
||||
{'aaaaaaaaaaaaaaaaaaaaaaaaa', 'bbbbbbbbbbbbbbbbbbbbbbbbbbb', 'cccccccccccccccccccccccccc'}
|
||||
}"
|
||||
|
||||
# Same as above but with an inline comment. The t-string should be formatted inside the
|
||||
# parentheses and the comment should be part of the line inside the parentheses.
|
||||
aaaaaaaaaaaaaaaaaa = t"testeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee{
|
||||
expression}moreeeeeeeeeeeeeeeee" # comment
|
||||
|
||||
# Similar to the previous example but this time parenthesizing doesn't work because it
|
||||
# exceeds the line length. So, avoid parenthesizing this t-string.
|
||||
aaaaaaaaaaaaaaaaaa = t"testeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee{
|
||||
expression}moreeeeeeeeeeeeeeeee" # comment loooooooong
|
||||
|
||||
# Similar to the previous example but we start with the parenthesized layout. This should
|
||||
# remove the parentheses and format the t-string on a single line. This shows that the
|
||||
# final layout for the formatter is same for this and the previous case. The only
|
||||
# difference is that in the previous case the expression is already mulitline which means
|
||||
# the formatter can break it further at the curly braces.
|
||||
aaaaaaaaaaaaaaaaaa = (
|
||||
t"testeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee{expression}moreeeeeeeeeeeeeeeee" # comment loooooooong
|
||||
)
|
||||
|
||||
# The following t-strings are going to break because of the trailing comma so we should
|
||||
# avoid using the best fit layout and instead use the default layout.
|
||||
# left-to-right
|
||||
aaaa = t"aaaa {[
|
||||
1, 2,
|
||||
]} bbbb"
|
||||
# right-to-left
|
||||
aaaa, bbbb = t"aaaa {[
|
||||
1, 2,
|
||||
]} bbbb"
|
||||
|
||||
# Using the right-to-left assignment statement variant.
|
||||
aaaaaaaaaaaaaaaaaa, bbbbbbbbbbb = t"testeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee{
|
||||
expression}moreeeeeeeeeeeeeeeee" # comment
|
||||
|
||||
# Here, the t-string layout is flat but it exceeds the line length limit. This shouldn't
|
||||
# try the custom best fit layout because the t-string doesn't have any split points.
|
||||
aaaaaaaaaaaa["bbbbbbbbbbbbbbbb"] = (
|
||||
t"aaaaaaaaaaaaaaaaaaa {aaaaaaaaa + bbbbbbbbbbb + cccccccccccccc} ddddddddddddddddddd"
|
||||
)
|
||||
# Same as above but without the parentheses to test that it gets formatted to the same
|
||||
# layout as the previous example.
|
||||
aaaaaaaaaaaa["bbbbbbbbbbbbbbbb"] = t"aaaaaaaaaaaaaaaaaaa {aaaaaaaaa + bbbbbbbbbbb + cccccccccccccc} ddddddddddddddddddd"
|
||||
|
||||
# But, the following t-string does have a split point because of the multiline expression.
|
||||
aaaaaaaaaaaa["bbbbbbbbbbbbbbbb"] = (
|
||||
t"aaaaaaaaaaaaaaaaaaa {
|
||||
aaaaaaaaa + bbbbbbbbbbb + cccccccccccccc} ddddddddddddddddddd"
|
||||
)
|
||||
aaaaaaaaaaaa["bbbbbbbbbbbbbbbb"] = (
|
||||
t"aaaaaaaaaaaaaaaaaaa {
|
||||
aaaaaaaaaaaaaaaaaaaa + bbbbbbbbbbbbbbbbbbbbb + cccccccccccccccccccccc + dddddddddddddddddddddddddddd} ddddddddddddddddddd"
|
||||
)
|
||||
|
||||
# This is an implicitly concatenated t-string but it cannot be joined because otherwise
|
||||
# it'll exceed the line length limit. So, the two t-strings will be inside parentheses
|
||||
# instead and the inline comment should be outside the parentheses.
|
||||
a = t"test{
|
||||
expression
|
||||
}flat" t"can be {
|
||||
joined
|
||||
} togethereeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee" # inline
|
||||
|
||||
# Similar to the above example but this fits within the line length limit.
|
||||
a = t"test{
|
||||
expression
|
||||
}flat" t"can be {
|
||||
joined
|
||||
} togethereeeeeeeeeeeeeeeeeeeeeeeeeee" # inline
|
||||
|
||||
# The following test cases are adopted from implicit string concatenation but for a
|
||||
# single t-string instead.
|
||||
|
||||
# Don't inline t-strings that contain expressions that are guaranteed to split, e.g. because of a magic trailing comma
|
||||
aaaaaaaaaaaaaaaaaa = t"testeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee{
|
||||
[a,]
|
||||
}moreeeeeeeeeeeeeeeeeeee" # comment
|
||||
|
||||
aaaaaaaaaaaaaaaaaa = (
|
||||
t"testeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee{
|
||||
[a,]
|
||||
}moreeeeeeeeeeeeeeeeeeee" # comment
|
||||
)
|
||||
|
||||
aaaaa[aaaaaaaaaaa] = t"testeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee{
|
||||
[a,]
|
||||
}moreeeeeeeeeeeeeeeeeeee" # comment
|
||||
|
||||
aaaaa[aaaaaaaaaaa] = (t"testeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee{
|
||||
[a,]
|
||||
}moreeeeeeeeeeeeeeeeeeee" # comment
|
||||
)
|
||||
|
||||
# Don't inline t-strings that contain commented expressions
|
||||
aaaaaaaaaaaaaaaaaa = (
|
||||
t"testeeeeeeeeeeeeeeeeeeeeeeeee{[
|
||||
a # comment
|
||||
]}moreeeeeeeeeeeeeeeeeetest" # comment
|
||||
)
|
||||
|
||||
aaaaa[aaaaaaaaaaa] = (
|
||||
t"testeeeeeeeeeeeeeeeeeeeeeeeee{[
|
||||
a # comment
|
||||
]}moreeeeeeeeeeeeeeeeeetest" # comment
|
||||
)
|
||||
|
||||
# Don't inline t-strings with multiline debug expressions or format specifiers
|
||||
aaaaaaaaaaaaaaaaaa = (
|
||||
t"testeeeeeeeeeeeeeeeeeeeeeeeee{
|
||||
a=}moreeeeeeeeeeeeeeeeeetest" # comment
|
||||
)
|
||||
|
||||
aaaaaaaaaaaaaaaaaa = (
|
||||
t"testeeeeeeeeeeeeeeeeeeeeeeeee{a +
|
||||
b=}moreeeeeeeeeeeeeeeeeetest" # comment
|
||||
)
|
||||
|
||||
aaaaaaaaaaaaaaaaaa = (
|
||||
t"testeeeeeeeeeeeeeeeeeeeeeeeee{a
|
||||
=}moreeeeeeeeeeeeeeeeeetest" # comment
|
||||
)
|
||||
|
||||
aaaaa[aaaaaaaaaaa] = (
|
||||
t"testeeeeeeeeeeeeeeeeeeeeeeeee{
|
||||
a=}moreeeeeeeeeeeeeeeeeetest" # comment
|
||||
)
|
||||
|
||||
aaaaa[aaaaaaaaaaa] = (
|
||||
t"testeeeeeeeeeeeeeeeeeeeeeeeee{a
|
||||
=}moreeeeeeeeeeeeeeeeeetest" # comment
|
||||
)
|
||||
|
||||
# This is not a multiline t-string even though it has a newline after the format specifier.
|
||||
aaaaaaaaaaaaaaaaaa = t"testeeeeeeeeeeeeeeeeeeeeeeeee{
|
||||
a:.3f
|
||||
}moreeeeeeeeeeeeeeeeeetest" # comment
|
||||
|
||||
aaaaaaaaaaaaaaaaaa = (
|
||||
t"testeeeeeeeeeeeeeeeeeeeeeeeee{
|
||||
a:.3f
|
||||
}moreeeeeeeeeeeeeeeeeetest" # comment
|
||||
)
|
||||
|
||||
# The newline is only considered when it's a tripled-quoted t-string.
|
||||
aaaaaaaaaaaaaaaaaa = t"""testeeeeeeeeeeeeeeeeeeeeeeeee{
|
||||
a:.3f
|
||||
}moreeeeeeeeeeeeeeeeeetest""" # comment
|
||||
|
||||
aaaaaaaaaaaaaaaaaa = (
|
||||
t"""testeeeeeeeeeeeeeeeeeeeeeeeee{
|
||||
a:.3f
|
||||
}moreeeeeeeeeeeeeeeeeetest""" # comment
|
||||
)
|
||||
|
||||
# Remove the parentheses here
|
||||
aaaaaaaaaaaaaaaaaa = (
|
||||
t"testeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee{[a, b,
|
||||
# comment
|
||||
]}moee" # comment
|
||||
)
|
||||
# ... but not here because of the ownline comment
|
||||
aaaaaaaaaaaaaaaaaa = (
|
||||
t"testeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee{[a, b,
|
||||
]}moee"
|
||||
# comment
|
||||
)
|
||||
|
||||
# t-strings in other positions
|
||||
|
||||
if t"aaaaaaaaaaa {ttttteeeeeeeeest} more {
|
||||
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
|
||||
}": pass
|
||||
|
||||
if (
|
||||
t"aaaaaaaaaaa {ttttteeeeeeeeest} more {
|
||||
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
|
||||
}"
|
||||
): pass
|
||||
|
||||
if t"aaaaaaaaaaa {ttttteeeeeeeeest} more {
|
||||
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
|
||||
}": pass
|
||||
|
||||
if t"aaaaaaaaaaa {ttttteeeeeeeeest} more { # comment
|
||||
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
|
||||
}": pass
|
||||
|
||||
if t"aaaaaaaaaaa {[ttttteeeeeeeeest,]} more {
|
||||
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
|
||||
}":
|
||||
pass
|
||||
|
||||
if (
|
||||
t"aaaaaaaaaaa {[ttttteeeeeeeeest,]} more {
|
||||
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
|
||||
}"
|
||||
):
|
||||
pass
|
||||
|
||||
if t"aaaaaaaaaaa {[ttttteeeeeeeeest,]} more {
|
||||
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
|
||||
}":
|
||||
pass
|
||||
|
||||
# For loops
|
||||
for a in t"testeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee{
|
||||
expression}moreeeeeeeeeeeeeeeeeeee":
|
||||
pass
|
||||
|
||||
for a in t"testeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee{expression}moreeeeeeeeeeeeeeeeeeeeeeeeeeeeee":
|
||||
pass
|
||||
|
||||
for a in t"testeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee{
|
||||
expression}moreeeeeeeeeeeeeeeeeeeeeeeeeeeeee":
|
||||
pass
|
||||
|
||||
for a in (
|
||||
t"testeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee{expression}moreeeeeeeeeeeeeeeeeeeeeeeeeeeee"
|
||||
):
|
||||
pass
|
||||
|
||||
# With statements
|
||||
with t"testeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee{
|
||||
expression}moreeeeeeeeeeeeeeeeeeee":
|
||||
pass
|
||||
|
||||
with t"testeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee{expression}moreeeeeeeeeeeeeeeeeeeeeeeeeeeeee":
|
||||
pass
|
||||
|
||||
with t"testeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee{
|
||||
expression}moreeeeeeeeeeeeeeeeeeeeeeeeeeeeee":
|
||||
pass
|
||||
|
||||
with (
|
||||
t"testeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee{expression}moreeeeeeeeeeeeeeeeeeeeeeeeeeeee"
|
||||
):
|
||||
pass
|
||||
|
||||
# Assert statements
|
||||
assert t"aaaaaaaaa{
|
||||
expression}bbbbbbbbbbbb", t"cccccccccc{
|
||||
expression}dddddddddd"
|
||||
|
||||
assert t"aaaaaaaaa{expression}bbbbbbbbbbbb", t"cccccccccccccccc{
|
||||
expression}dddddddddddddddd"
|
||||
|
||||
assert t"aaaaaaaaa{expression}bbbbbbbbbbbb", t"cccccccccccccccc{expression}dddddddddddddddd"
|
||||
|
||||
assert t"aaaaaaaaaaaaaaaaaaaaaaaaaaa{
|
||||
expression}bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", t"ccccccc{expression}dddddddddd"
|
||||
|
||||
assert t"aaaaaaaaaaaaaaaaaaaaaaaaaaa{expression}bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", t"ccccccc{expression}dddddddddd"
|
||||
|
||||
assert t"aaaaaaaaaaaaaaaaaaaaaaaaaaa{
|
||||
expression}bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", t"ccccccccccccccccccccc {
|
||||
expression} dddddddddddddddddddddddddd"
|
||||
|
||||
assert t"aaaaaaaaaaaaaaaaaaaaaaaaaaa{expression}bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", t"cccccccccccccccccccccccccccccccc {expression} ddddddddddddddddddddddddddddddddddddd"
|
||||
|
||||
# t-strings as a single argument to a call expression to test whether it's huggable or not.
|
||||
call(t"{
|
||||
testeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee
|
||||
}")
|
||||
|
||||
call(t"{
|
||||
testeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee
|
||||
}")
|
||||
|
||||
call(t"{ # comment
|
||||
testeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee
|
||||
}")
|
||||
|
||||
call(t"""aaaaaaaaaaaaaaaa bbbbbbbbbb {testeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee}""")
|
||||
|
||||
call(t"""aaaaaaaaaaaaaaaa bbbbbbbbbb {testeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee
|
||||
}""")
|
||||
|
||||
call(t"""aaaaaaaaaaaaaaaa
|
||||
bbbbbbbbbb {testeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee
|
||||
}""")
|
||||
|
||||
call(t"""aaaaaaaaaaaaaaaa
|
||||
bbbbbbbbbb {testeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee # comment
|
||||
}""")
|
||||
|
||||
call(
|
||||
t"""aaaaaaaaaaaaaaaa
|
||||
bbbbbbbbbb {testeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee # comment
|
||||
}"""
|
||||
)
|
||||
|
||||
call(t"{
|
||||
aaaaaa
|
||||
+ '''test
|
||||
more'''
|
||||
}")
|
||||
|
||||
# Indentation
|
||||
|
||||
# What should be the indentation?
|
||||
# https://github.com/astral-sh/ruff/discussions/9785#discussioncomment-8470590
|
||||
if indent0:
|
||||
if indent1:
|
||||
if indent2:
|
||||
foo = t"""hello world
|
||||
hello {
|
||||
t"aaaaaaa {
|
||||
[
|
||||
'aaaaaaaaaaaaaaaaaaaaa',
|
||||
'bbbbbbbbbbbbbbbbbbbbb',
|
||||
'ccccccccccccccccccccc',
|
||||
'ddddddddddddddddddddd'
|
||||
]
|
||||
} bbbbbbbb" +
|
||||
[
|
||||
'aaaaaaaaaaaaaaaaaaaaa',
|
||||
'bbbbbbbbbbbbbbbbbbbbb',
|
||||
'ccccccccccccccccccccc',
|
||||
'ddddddddddddddddddddd'
|
||||
]
|
||||
} --------
|
||||
"""
|
||||
|
||||
|
||||
# Implicit concatenated t-string containing quotes
|
||||
_ = (
|
||||
'This string should change its quotes to double quotes'
|
||||
t'This string uses double quotes in an expression {"it's a quote"}'
|
||||
t'This t-string does not use any quotes.'
|
||||
)
|
||||
|
||||
# Regression test for https://github.com/astral-sh/ruff/issues/14487
|
||||
t"aaaaaaaaaaaaaaaaaaaaaaaaaa {10**27} bbbbbbbbbbbbbbbbbbbbbbbbbb ccccccccccccccccccccccccc"
|
||||
|
||||
# Regression test for https://github.com/astral-sh/ruff/issues/14778
|
||||
t"{'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' 'a' if True else ""}"
|
||||
t"{'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' 'a' if True else ""}"
|
||||
|
||||
# Quotes reuse
|
||||
t"{'a'}"
|
||||
|
||||
# 312+, it's okay to change the outer quotes even when there's a debug expression using the same quotes
|
||||
t'foo {10 + len("bar")=}'
|
||||
t'''foo {10 + len("""bar""")=}'''
|
||||
|
||||
# 312+, it's okay to change the quotes here without creating an invalid t-string
|
||||
t'{"""other " """}'
|
||||
t'{"""other " """ + "more"}'
|
||||
t'{b"""other " """}'
|
||||
t'{t"""other " """}'
|
||||
|
||||
|
||||
# Regression tests for https://github.com/astral-sh/ruff/issues/13935
|
||||
t'{1: hy "user"}'
|
||||
t'{1:hy "user"}'
|
||||
t'{1: abcd "{1}" }'
|
||||
t'{1: abcd "{'aa'}" }'
|
||||
t'{1=: "abcd {'aa'}}'
|
||||
t'{x:a{z:hy "user"}} \'\'\''
|
||||
|
||||
# Changing the outer quotes is fine because the format-spec is in a nested expression.
|
||||
t'{t'{z=:hy "user"}'} \'\'\''
|
||||
|
||||
|
||||
# We have to be careful about changing the quotes if the t-string has a debug expression because it is inserted verbatim.
|
||||
t'{1=: "abcd \'\'}' # Don't change the outer quotes, or it results in a syntax error
|
||||
t'{1=: abcd \'\'}' # Changing the quotes here is fine because the inner quotes aren't the opposite quotes
|
||||
t'{1=: abcd \"\"}' # Changing the quotes here is fine because the inner quotes are escaped
|
||||
# Don't change the quotes in the following cases:
|
||||
t'{x=:hy "user"} \'\'\''
|
||||
t'{x=:a{y:hy "user"}} \'\'\''
|
||||
t'{x=:a{y:{z:hy "user"}}} \'\'\''
|
||||
t'{x:a{y=:{z:hy "user"}}} \'\'\''
|
||||
|
||||
# This is fine because the debug expression and format spec are in a nested expression
|
||||
|
||||
t"""{1=: "this" is fine}"""
|
||||
t'''{1=: "this" is fine}''' # Change quotes to double quotes because they're preferred
|
||||
t'{1=: {'ab"cd"'}}' # It's okay if the quotes are in an expression part.
|
||||
|
||||
|
||||
# Regression tests for https://github.com/astral-sh/ruff/issues/15459
|
||||
print(t"{ {1, 2, 3} - {2} }")
|
||||
print(t"{ {1: 2}.keys() }")
|
||||
print(t"{({1, 2, 3}) - ({2})}")
|
||||
print(t"{1, 2, {3} }")
|
||||
print(t"{(1, 2, {3})}")
|
||||
|
||||
|
||||
# Regression tests for https://github.com/astral-sh/ruff/issues/15535
|
||||
print(t"{ {}, }") # A single item tuple gets parenthesized
|
||||
print(t"{ {}.values(), }")
|
||||
print(t"{ {}, 1 }") # A tuple with multiple elements doesn't get parenthesized
|
||||
print(t"{ # Tuple with multiple elements that doesn't fit on a single line gets parenthesized
|
||||
{}, 1,
|
||||
}")
|
||||
|
||||
|
||||
# Regression tests for https://github.com/astral-sh/ruff/issues/15536
|
||||
print(t"{ {}, 1, }")
|
Loading…
Add table
Add a link
Reference in a new issue