-
Notifications
You must be signed in to change notification settings - Fork 1.1k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Fix curly brace escape handling in f-strings #7331
Conversation
Current dependencies on/for this PR:
This comment was auto-generated by Graphite. |
// valid here because it's a substring of a f-string. Even though | ||
// curly braces cannot be escaped, it's a valid syntax. | ||
// | ||
// Refer to point 3: https://peps.python.org/pep-0701/#rejected-ideas |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This section doesn't explain why it is valid. It only explains why it isn't an escape sequence. I assume it is valid because allows invalid escape sequences in general (Do we have a lint rule for that, does it need updating?)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I actually noticed this while I was working on https://github.com/astral-sh/ruff/pull/7327/files#diff-739ef20efc60adce8f2acfaeda1005a932c58536433cbb895b323d335fffdd63 where at the end of the test file, the following was mentioned:
# To be fixed
# Error: f-string: single '}' is not allowed at line 41 column 8
# f"\{{x}}"
So, then I started looking into it and realize that we don't parse this as a valid syntax. Python parses it as a valid syntax pre 3.12 as well although with 3.12 it produces a syntax warning:
$ python3.12-dev fstring.py
/Users/dhruv/playground/ruff/fstring.py:2: SyntaxWarning: invalid escape sequence '\{'
f"\{foo}"
(Do we have a lint rule for that, does it need updating?)
We do have W605
(tracking issue) but as we didn't parse the syntax before, we didn't raise any warning. Now, we have the ability to raise that warning and I think we should do it.
d184850
to
6c4f8c2
Compare
This will be used to extract the `leading` and `trailing` text for f-string debug expressions.
25fad0c
to
06ba358
Compare
6c4f8c2
to
44f3155
Compare
CodSpeed Performance ReportMerging #7331 will degrade performances by 9.55%Falling back to comparing Summary
Benchmarks breakdown
|
## Summary This PR fixes the escape handling of curly braces inside a f-string. There are 2 main changes: ### Lexer The lexer change was actually a bug. Instead of breaking as soon as we find a curly brace after the `\` character, we'll continue and let the next iteration handle it in the curly brace branch. This fixes the following case: ```python f"\{{foo}}" # ^ use the curly brace branch to handle this character instead of breaking ``` ### Parser We can encounter a `\` as the last character in a `FStringMiddle` token which is valid in this context[^1]. For example, ```python f"\{foo} \{bar:\}" # ^ ^^ ^ # The marked characters are part of 3 different `FStringMiddle` token ``` Here, the `FStringMiddle` token content will be `"\"` and `" \"` which is invalid in a regular string literal. However, it's valid here because it's a substring of a f-string. Even though curly braces cannot be escaped, it's a valid syntax. [^1]: Refer to point 3 in https://peps.python.org/pep-0701/#rejected-ideas ## Test Plan Verified that existing test cases are passing and add new test cases for the lexer and parser.
## Summary This PR fixes the escape handling of curly braces inside a f-string. There are 2 main changes: ### Lexer The lexer change was actually a bug. Instead of breaking as soon as we find a curly brace after the `\` character, we'll continue and let the next iteration handle it in the curly brace branch. This fixes the following case: ```python f"\{{foo}}" # ^ use the curly brace branch to handle this character instead of breaking ``` ### Parser We can encounter a `\` as the last character in a `FStringMiddle` token which is valid in this context[^1]. For example, ```python f"\{foo} \{bar:\}" # ^ ^^ ^ # The marked characters are part of 3 different `FStringMiddle` token ``` Here, the `FStringMiddle` token content will be `"\"` and `" \"` which is invalid in a regular string literal. However, it's valid here because it's a substring of a f-string. Even though curly braces cannot be escaped, it's a valid syntax. [^1]: Refer to point 3 in https://peps.python.org/pep-0701/#rejected-ideas ## Test Plan Verified that existing test cases are passing and add new test cases for the lexer and parser.
## Summary This PR fixes the escape handling of curly braces inside a f-string. There are 2 main changes: ### Lexer The lexer change was actually a bug. Instead of breaking as soon as we find a curly brace after the `\` character, we'll continue and let the next iteration handle it in the curly brace branch. This fixes the following case: ```python f"\{{foo}}" # ^ use the curly brace branch to handle this character instead of breaking ``` ### Parser We can encounter a `\` as the last character in a `FStringMiddle` token which is valid in this context[^1]. For example, ```python f"\{foo} \{bar:\}" # ^ ^^ ^ # The marked characters are part of 3 different `FStringMiddle` token ``` Here, the `FStringMiddle` token content will be `"\"` and `" \"` which is invalid in a regular string literal. However, it's valid here because it's a substring of a f-string. Even though curly braces cannot be escaped, it's a valid syntax. [^1]: Refer to point 3 in https://peps.python.org/pep-0701/#rejected-ideas ## Test Plan Verified that existing test cases are passing and add new test cases for the lexer and parser.
## Summary This PR fixes the escape handling of curly braces inside a f-string. There are 2 main changes: ### Lexer The lexer change was actually a bug. Instead of breaking as soon as we find a curly brace after the `\` character, we'll continue and let the next iteration handle it in the curly brace branch. This fixes the following case: ```python f"\{{foo}}" # ^ use the curly brace branch to handle this character instead of breaking ``` ### Parser We can encounter a `\` as the last character in a `FStringMiddle` token which is valid in this context[^1]. For example, ```python f"\{foo} \{bar:\}" # ^ ^^ ^ # The marked characters are part of 3 different `FStringMiddle` token ``` Here, the `FStringMiddle` token content will be `"\"` and `" \"` which is invalid in a regular string literal. However, it's valid here because it's a substring of a f-string. Even though curly braces cannot be escaped, it's a valid syntax. [^1]: Refer to point 3 in https://peps.python.org/pep-0701/#rejected-ideas ## Test Plan Verified that existing test cases are passing and add new test cases for the lexer and parser.
## Summary This PR fixes the escape handling of curly braces inside a f-string. There are 2 main changes: ### Lexer The lexer change was actually a bug. Instead of breaking as soon as we find a curly brace after the `\` character, we'll continue and let the next iteration handle it in the curly brace branch. This fixes the following case: ```python f"\{{foo}}" # ^ use the curly brace branch to handle this character instead of breaking ``` ### Parser We can encounter a `\` as the last character in a `FStringMiddle` token which is valid in this context[^1]. For example, ```python f"\{foo} \{bar:\}" # ^ ^^ ^ # The marked characters are part of 3 different `FStringMiddle` token ``` Here, the `FStringMiddle` token content will be `"\"` and `" \"` which is invalid in a regular string literal. However, it's valid here because it's a substring of a f-string. Even though curly braces cannot be escaped, it's a valid syntax. [^1]: Refer to point 3 in https://peps.python.org/pep-0701/#rejected-ideas ## Test Plan Verified that existing test cases are passing and add new test cases for the lexer and parser.
## Summary This PR fixes the escape handling of curly braces inside a f-string. There are 2 main changes: ### Lexer The lexer change was actually a bug. Instead of breaking as soon as we find a curly brace after the `\` character, we'll continue and let the next iteration handle it in the curly brace branch. This fixes the following case: ```python f"\{{foo}}" # ^ use the curly brace branch to handle this character instead of breaking ``` ### Parser We can encounter a `\` as the last character in a `FStringMiddle` token which is valid in this context[^1]. For example, ```python f"\{foo} \{bar:\}" # ^ ^^ ^ # The marked characters are part of 3 different `FStringMiddle` token ``` Here, the `FStringMiddle` token content will be `"\"` and `" \"` which is invalid in a regular string literal. However, it's valid here because it's a substring of a f-string. Even though curly braces cannot be escaped, it's a valid syntax. [^1]: Refer to point 3 in https://peps.python.org/pep-0701/#rejected-ideas ## Test Plan Verified that existing test cases are passing and add new test cases for the lexer and parser.
## Summary This PR fixes the escape handling of curly braces inside a f-string. There are 2 main changes: ### Lexer The lexer change was actually a bug. Instead of breaking as soon as we find a curly brace after the `\` character, we'll continue and let the next iteration handle it in the curly brace branch. This fixes the following case: ```python f"\{{foo}}" # ^ use the curly brace branch to handle this character instead of breaking ``` ### Parser We can encounter a `\` as the last character in a `FStringMiddle` token which is valid in this context[^1]. For example, ```python f"\{foo} \{bar:\}" # ^ ^^ ^ # The marked characters are part of 3 different `FStringMiddle` token ``` Here, the `FStringMiddle` token content will be `"\"` and `" \"` which is invalid in a regular string literal. However, it's valid here because it's a substring of a f-string. Even though curly braces cannot be escaped, it's a valid syntax. [^1]: Refer to point 3 in https://peps.python.org/pep-0701/#rejected-ideas ## Test Plan Verified that existing test cases are passing and add new test cases for the lexer and parser.
## Summary This PR fixes the escape handling of curly braces inside a f-string. There are 2 main changes: ### Lexer The lexer change was actually a bug. Instead of breaking as soon as we find a curly brace after the `\` character, we'll continue and let the next iteration handle it in the curly brace branch. This fixes the following case: ```python f"\{{foo}}" # ^ use the curly brace branch to handle this character instead of breaking ``` ### Parser We can encounter a `\` as the last character in a `FStringMiddle` token which is valid in this context[^1]. For example, ```python f"\{foo} \{bar:\}" # ^ ^^ ^ # The marked characters are part of 3 different `FStringMiddle` token ``` Here, the `FStringMiddle` token content will be `"\"` and `" \"` which is invalid in a regular string literal. However, it's valid here because it's a substring of a f-string. Even though curly braces cannot be escaped, it's a valid syntax. [^1]: Refer to point 3 in https://peps.python.org/pep-0701/#rejected-ideas ## Test Plan Verified that existing test cases are passing and add new test cases for the lexer and parser.
## Summary This PR fixes the escape handling of curly braces inside a f-string. There are 2 main changes: ### Lexer The lexer change was actually a bug. Instead of breaking as soon as we find a curly brace after the `\` character, we'll continue and let the next iteration handle it in the curly brace branch. This fixes the following case: ```python f"\{{foo}}" # ^ use the curly brace branch to handle this character instead of breaking ``` ### Parser We can encounter a `\` as the last character in a `FStringMiddle` token which is valid in this context[^1]. For example, ```python f"\{foo} \{bar:\}" # ^ ^^ ^ # The marked characters are part of 3 different `FStringMiddle` token ``` Here, the `FStringMiddle` token content will be `"\"` and `" \"` which is invalid in a regular string literal. However, it's valid here because it's a substring of a f-string. Even though curly braces cannot be escaped, it's a valid syntax. [^1]: Refer to point 3 in https://peps.python.org/pep-0701/#rejected-ideas ## Test Plan Verified that existing test cases are passing and add new test cases for the lexer and parser.
## Summary This PR fixes the escape handling of curly braces inside a f-string. There are 2 main changes: ### Lexer The lexer change was actually a bug. Instead of breaking as soon as we find a curly brace after the `\` character, we'll continue and let the next iteration handle it in the curly brace branch. This fixes the following case: ```python f"\{{foo}}" # ^ use the curly brace branch to handle this character instead of breaking ``` ### Parser We can encounter a `\` as the last character in a `FStringMiddle` token which is valid in this context[^1]. For example, ```python f"\{foo} \{bar:\}" # ^ ^^ ^ # The marked characters are part of 3 different `FStringMiddle` token ``` Here, the `FStringMiddle` token content will be `"\"` and `" \"` which is invalid in a regular string literal. However, it's valid here because it's a substring of a f-string. Even though curly braces cannot be escaped, it's a valid syntax. [^1]: Refer to point 3 in https://peps.python.org/pep-0701/#rejected-ideas ## Test Plan Verified that existing test cases are passing and add new test cases for the lexer and parser.
## Summary This PR fixes the escape handling of curly braces inside a f-string. There are 2 main changes: ### Lexer The lexer change was actually a bug. Instead of breaking as soon as we find a curly brace after the `\` character, we'll continue and let the next iteration handle it in the curly brace branch. This fixes the following case: ```python f"\{{foo}}" # ^ use the curly brace branch to handle this character instead of breaking ``` ### Parser We can encounter a `\` as the last character in a `FStringMiddle` token which is valid in this context[^1]. For example, ```python f"\{foo} \{bar:\}" # ^ ^^ ^ # The marked characters are part of 3 different `FStringMiddle` token ``` Here, the `FStringMiddle` token content will be `"\"` and `" \"` which is invalid in a regular string literal. However, it's valid here because it's a substring of a f-string. Even though curly braces cannot be escaped, it's a valid syntax. [^1]: Refer to point 3 in https://peps.python.org/pep-0701/#rejected-ideas ## Test Plan Verified that existing test cases are passing and add new test cases for the lexer and parser.
Summary
This PR fixes the escape handling of curly braces inside a f-string. There are 2
main changes:
Lexer
The lexer change was actually a bug. Instead of breaking as soon as we find a
curly brace after the
\
character, we'll continue and let the next iterationhandle it in the curly brace branch. This fixes the following case:
Parser
We can encounter a
\
as the last character in aFStringMiddle
token which isvalid in this context1. For example,
Here, the
FStringMiddle
token content will be"\"
and" \"
which is invalid ina regular string literal. However, it's valid here because it's a substring of a
f-string. Even though curly braces cannot be escaped, it's a valid syntax.
Test Plan
Verified that existing test cases are passing and add new test cases for the lexer and parser.
Footnotes
Refer to point 3 in https://peps.python.org/pep-0701/#rejected-ideas ↩