Add syntax error when conversion flag does not immediately follow exclamation mark (#18706)

Closes #18671

Note that while this has, I believe, always been invalid syntax, it was
reported as a different syntax error until Python 3.12:

Python 3.11:

```pycon
>>> x = 1
>>> f"{x! s}"
  File "<stdin>", line 1
    f"{x! s}"
             ^
SyntaxError: f-string: invalid conversion character: expected 's', 'r', or 'a'
```

Python 3.12:

```pycon
>>> x = 1
>>> f"{x! s}"
  File "<stdin>", line 1
    f"{x! s}"
        ^^^
SyntaxError: f-string: conversion type must come right after the exclamanation mark
```
This commit is contained in:
Dylan 2025-06-16 11:44:42 -05:00 committed by GitHub
parent a842899862
commit c5b58187da
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
8 changed files with 219 additions and 38 deletions

View file

@ -0,0 +1,186 @@
---
source: crates/ruff_python_parser/tests/fixtures.rs
input_file: crates/ruff_python_parser/resources/inline/err/f_string_conversion_follows_exclamation.py
---
## AST
```
Module(
ModModule {
node_index: AtomicNodeIndex(..),
range: 0..30,
body: [
Expr(
StmtExpr {
node_index: AtomicNodeIndex(..),
range: 0..9,
value: FString(
ExprFString {
node_index: AtomicNodeIndex(..),
range: 0..9,
value: FStringValue {
inner: Single(
FString(
FString {
range: 0..9,
node_index: AtomicNodeIndex(..),
elements: [
Interpolation(
InterpolatedElement {
range: 2..8,
node_index: AtomicNodeIndex(..),
expression: Name(
ExprName {
node_index: AtomicNodeIndex(..),
range: 3..4,
id: Name("x"),
ctx: Load,
},
),
debug_text: None,
conversion: Str,
format_spec: None,
},
),
],
flags: FStringFlags {
quote_style: Double,
prefix: Regular,
triple_quoted: false,
},
},
),
),
},
},
),
},
),
Expr(
StmtExpr {
node_index: AtomicNodeIndex(..),
range: 10..19,
value: TString(
ExprTString {
node_index: AtomicNodeIndex(..),
range: 10..19,
value: TStringValue {
inner: Single(
TString(
TString {
range: 10..19,
node_index: AtomicNodeIndex(..),
elements: [
Interpolation(
InterpolatedElement {
range: 12..18,
node_index: AtomicNodeIndex(..),
expression: Name(
ExprName {
node_index: AtomicNodeIndex(..),
range: 13..14,
id: Name("x"),
ctx: Load,
},
),
debug_text: None,
conversion: Str,
format_spec: None,
},
),
],
flags: TStringFlags {
quote_style: Double,
prefix: Regular,
triple_quoted: false,
},
},
),
),
},
},
),
},
),
Expr(
StmtExpr {
node_index: AtomicNodeIndex(..),
range: 20..29,
value: FString(
ExprFString {
node_index: AtomicNodeIndex(..),
range: 20..29,
value: FStringValue {
inner: Single(
FString(
FString {
range: 20..29,
node_index: AtomicNodeIndex(..),
elements: [
Interpolation(
InterpolatedElement {
range: 22..28,
node_index: AtomicNodeIndex(..),
expression: Name(
ExprName {
node_index: AtomicNodeIndex(..),
range: 23..24,
id: Name("x"),
ctx: Load,
},
),
debug_text: None,
conversion: None,
format_spec: None,
},
),
],
flags: FStringFlags {
quote_style: Double,
prefix: Regular,
triple_quoted: false,
},
},
),
),
},
},
),
},
),
],
},
)
```
## Errors
|
1 | f"{x! s}"
| ^ Syntax Error: f-string: conversion type must come right after the exclamation mark
2 | t"{x! s}"
3 | f"{x! z}"
|
|
1 | f"{x! s}"
2 | t"{x! s}"
| ^ Syntax Error: t-string: conversion type must come right after the exclamation mark
3 | f"{x! z}"
|
|
1 | f"{x! s}"
2 | t"{x! s}"
3 | f"{x! z}"
| ^ Syntax Error: f-string: conversion type must come right after the exclamation mark
|
|
1 | f"{x! s}"
2 | t"{x! s}"
3 | f"{x! z}"
| ^ Syntax Error: f-string: invalid conversion character
|