-
-
Notifications
You must be signed in to change notification settings - Fork 310
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
logical_line
for call with f-string can result in invalid ast under Python 3.12
#1948
Comments
logical_line
with f-string can result in invalid astlogical_line
for call with f-string can result in invalid ast under Python 3.12
I think this may be a bug introduced in 43266a2. Simplifying the above reproducer:
key = 'foo'
val = 'bar'
print(f'{{"{key}": "{val}"}}'
def foo(logical_line):
print(logical_line) If we run this we get: ❯ flake8 test.py
key = 'xxx'
val = 'xxx'
print(f'x{x{key}xxxx{val}xx}') I think we want to get: ❯ flake8 test.py
key = 'xxx'
val = 'xxx'
print(f'xxxxxxxxxxxxxxxxxxxx') Right? |
We parse 'logical_line's in a couple of extensions. There is currently a potential bug in flake8 [1] that means these lines are not valid Python. While we wait on a fix, simply skip these lines. [1] PyCQA/flake8#1948 Change-Id: Ia0f2d729ee48f85afaa58ddb6e983e12d4f298a2 Signed-off-by: Stephen Finucane <[email protected]>
* Update hacking from branch 'master' to 634cb78484a9c58f067c2df8cba7f49458c82043 - Ignore SyntaxError exceptions We parse 'logical_line's in a couple of extensions. There is currently a potential bug in flake8 [1] that means these lines are not valid Python. While we wait on a fix, simply skip these lines. [1] PyCQA/flake8#1948 Change-Id: Ia0f2d729ee48f85afaa58ddb6e983e12d4f298a2 Signed-off-by: Stephen Finucane <[email protected]>
nope! the method is meant to redact string contents and not code |
Then we should have:
? |
ah yes I see the quirk. ugh. the FSTRING_MIDDLE token is misleading for curly braces -- should be an easy fix (pycodestyle will likely need the same fix) want to try a patch? |
To use a curly brace in an f-string, you must escape it. For example: >>> k = 1 >>> f'{{{k}' '{1' Saving this as a script and running the 'tokenize' module higlights something odd around our counting: ❯ python -m tokenize wow.py 0,0-0,0: ENCODING 'utf-8' 1,0-1,1: NAME 'k' 1,2-1,3: OP '=' 1,4-1,5: NUMBER '1' 1,5-1,6: NEWLINE '\n' 2,0-2,2: FSTRING_START "f'" 2,2-2,3: FSTRING_MIDDLE '{' # <-- here... 2,4-2,5: OP '{' # <-- and here 2,5-2,6: NAME 'k' 2,6-2,7: OP '}' 2,7-2,8: FSTRING_END "'" 2,8-2,9: NEWLINE '\n' 3,0-3,0: ENDMARKER '' The FSTRING_MIDDLE character we have is the escaped/post-parse single curly brace rather than the raw double curly brace, however, while our end index of this token accounts for the parsed form, the start index of the next token does not (put another way, it jumps from 3 -> 4). This triggers some existing, unrelated code that we need to bypass. Do just that. Signed-off-by: Stephen Finucane <[email protected]>
To use a curly brace in an f-string, you must escape it. For example: >>> k = 1 >>> f'{{{k}' '{1' Saving this as a script and running the 'tokenize' module higlights something odd around our counting: ❯ python -m tokenize wow.py 0,0-0,0: ENCODING 'utf-8' 1,0-1,1: NAME 'k' 1,2-1,3: OP '=' 1,4-1,5: NUMBER '1' 1,5-1,6: NEWLINE '\n' 2,0-2,2: FSTRING_START "f'" 2,2-2,3: FSTRING_MIDDLE '{' # <-- here... 2,4-2,5: OP '{' # <-- and here 2,5-2,6: NAME 'k' 2,6-2,7: OP '}' 2,7-2,8: FSTRING_END "'" 2,8-2,9: NEWLINE '\n' 3,0-3,0: ENDMARKER '' The FSTRING_MIDDLE character we have is the escaped/post-parse single curly brace rather than the raw double curly brace, however, while our end index of this token accounts for the parsed form, the start index of the next token does not (put another way, it jumps from 3 -> 4). This triggers some existing, unrelated code that we need to bypass. Do just that. Signed-off-by: Stephen Finucane <[email protected]> Closes: PyCQA#1948
To use a curly brace in an f-string, you must escape it. For example: >>> k = 1 >>> f'{{{k}' '{1' Saving this as a script and running the 'tokenize' module higlights something odd around our counting: ❯ python -m tokenize wow.py 0,0-0,0: ENCODING 'utf-8' 1,0-1,1: NAME 'k' 1,2-1,3: OP '=' 1,4-1,5: NUMBER '1' 1,5-1,6: NEWLINE '\n' 2,0-2,2: FSTRING_START "f'" 2,2-2,3: FSTRING_MIDDLE '{' # <-- here... 2,4-2,5: OP '{' # <-- and here 2,5-2,6: NAME 'k' 2,6-2,7: OP '}' 2,7-2,8: FSTRING_END "'" 2,8-2,9: NEWLINE '\n' 3,0-3,0: ENDMARKER '' The FSTRING_MIDDLE character we have is the escaped/post-parse single curly brace rather than the raw double curly brace, however, while our end index of this token accounts for the parsed form, the start index of the next token does not (put another way, it jumps from 3 -> 4). This triggers some existing, unrelated code that we need to bypass. Do just that. Signed-off-by: Stephen Finucane <[email protected]> Closes: PyCQA#1948
Done. Apologies in advance for the fuzzy wording: I have no idea what the below code is intended to account for: flake8/src/flake8/processor.py Lines 207 to 218 in 2a811cc
(and that's after |
To use a curly brace in an f-string, you must escape it. For example: >>> k = 1 >>> f'{{{k}' '{1' Saving this as a script and running the 'tokenize' module highlights something odd around the counting of tokens: ❯ python -m tokenize wow.py 0,0-0,0: ENCODING 'utf-8' 1,0-1,1: NAME 'k' 1,2-1,3: OP '=' 1,4-1,5: NUMBER '1' 1,5-1,6: NEWLINE '\n' 2,0-2,2: FSTRING_START "f'" 2,2-2,3: FSTRING_MIDDLE '{' # <-- here... 2,4-2,5: OP '{' # <-- and here 2,5-2,6: NAME 'k' 2,6-2,7: OP '}' 2,7-2,8: FSTRING_END "'" 2,8-2,9: NEWLINE '\n' 3,0-3,0: ENDMARKER '' The FSTRING_MIDDLE character we have is the escaped/post-parse single curly brace rather than the raw double curly brace, however, while our end index of this token accounts for the parsed form, the start index of the next token does not (put another way, it jumps from 3 -> 4). This triggers some existing, unrelated code that we need to bypass. Do just that. Signed-off-by: Stephen Finucane <[email protected]> Closes: PyCQA#1948
Not looking at where you blamed back to but a bunch of this was implemented to keep compat with pycodestyle. If you want reasoning it's likely in that project |
To use a curly brace in an f-string, you must escape it. For example: >>> k = 1 >>> f'{{{k}' '{1' Saving this as a script and running the 'tokenize' module highlights something odd around the counting of tokens: ❯ python -m tokenize wow.py 0,0-0,0: ENCODING 'utf-8' 1,0-1,1: NAME 'k' 1,2-1,3: OP '=' 1,4-1,5: NUMBER '1' 1,5-1,6: NEWLINE '\n' 2,0-2,2: FSTRING_START "f'" 2,2-2,3: FSTRING_MIDDLE '{' # <-- here... 2,4-2,5: OP '{' # <-- and here 2,5-2,6: NAME 'k' 2,6-2,7: OP '}' 2,7-2,8: FSTRING_END "'" 2,8-2,9: NEWLINE '\n' 3,0-3,0: ENDMARKER '' The FSTRING_MIDDLE character we have is the escaped/post-parse single curly brace rather than the raw double curly brace, however, while our end index of this token accounts for the parsed form, the start index of the next token does not (put another way, it jumps from 3 -> 4). This triggers some existing, unrelated code that we need to bypass. Do just that. Signed-off-by: Stephen Finucane <[email protected]> Closes: PyCQA#1948
To use a curly brace in an f-string, you must escape it. For example: >>> k = 1 >>> f'{{{k}' '{1' Saving this as a script and running the 'tokenize' module highlights something odd around the counting of tokens: ❯ python -m tokenize wow.py 0,0-0,0: ENCODING 'utf-8' 1,0-1,1: NAME 'k' 1,2-1,3: OP '=' 1,4-1,5: NUMBER '1' 1,5-1,6: NEWLINE '\n' 2,0-2,2: FSTRING_START "f'" 2,2-2,3: FSTRING_MIDDLE '{' # <-- here... 2,4-2,5: OP '{' # <-- and here 2,5-2,6: NAME 'k' 2,6-2,7: OP '}' 2,7-2,8: FSTRING_END "'" 2,8-2,9: NEWLINE '\n' 3,0-3,0: ENDMARKER '' The FSTRING_MIDDLE character we have is the escaped/post-parse single curly brace rather than the raw double curly brace, however, while our end index of this token accounts for the parsed form, the start index of the next token does not (put another way, it jumps from 3 -> 4). This triggers some existing, unrelated code that we need to bypass. Do just that. Signed-off-by: Stephen Finucane <[email protected]> Closes: PyCQA#1948
We disable the E203 (whitespace before ':') and E501 (line too long) linter rules since these conflict with ruff-format. We also rework a statement in 'keystoneauth1/tests/unit/test_session.py' since it's triggering a bug in flake8 [1] that is currently (at time of authoring) unresolved. [1] PyCQA/flake8#1948 Signed-off-by: Stephen Finucane <[email protected]> Change-Id: Ief5c1c57d1e72db9fc881063d4c7e1030e76da43
We disable the E203 (whitespace before ':') and E501 (line too long) linter rules since these conflict with ruff-format. We also rework a statement in 'keystoneauth1/tests/unit/test_session.py' since it's triggering a bug in flake8 [1] that is currently (at time of authoring) unresolved. [1] PyCQA/flake8#1948 Signed-off-by: Stephen Finucane <[email protected]> Change-Id: Ief5c1c57d1e72db9fc881063d4c7e1030e76da43
* Update keystoneauth from branch 'master' to e4132b5c82264f8c929d5edb82bf4ae1fb4de227 - Merge "Apply ruff, ruff-format" - Apply ruff, ruff-format We disable the E203 (whitespace before ':') and E501 (line too long) linter rules since these conflict with ruff-format. We also rework a statement in 'keystoneauth1/tests/unit/test_session.py' since it's triggering a bug in flake8 [1] that is currently (at time of authoring) unresolved. [1] PyCQA/flake8#1948 Signed-off-by: Stephen Finucane <[email protected]> Change-Id: Ief5c1c57d1e72db9fc881063d4c7e1030e76da43
how did you install flake8?
$ pip install flake8
unmodified output of
flake8 --bug-report
describe the problem
what I expected to happen
Some of the plugins in
hacking
use a combo ofast.parse
andlogical_line
to generate an AST for an individual line that is then fed into anast.NodeVisitor
subclass. These work just fine on Python 3.11 and earlier, but I've noticed they fail under specific circumstances on Python 3.12. I've included a minimal reproducer below. There's a chance I am "holding it wrong" but I'd like to confirm this first.sample code
test.py
checks.py
:tox.ini
:commands ran
If I comment out the
print
statement, I see different results for Python 3.12 compared Pythons 3.10 and 3.11. Under 3.12:Under 3.10 and 3.11:
additional information
The E999 error is associated with line 1 of the file, despite the error actually coming from a plugin. This led me on a wild goose chase as I tried to figure out why flake8 thought my file was invalid Python but Python itself did not. I suspect this might also be user error and I should be handling the potential exception from
ast.parse
in my plugin but again, I just wanted to confirm that this was expected practice.The text was updated successfully, but these errors were encountered: