python / python/cpython

Nested replacement fields switch f-string lexing out of format-spec mode

未关闭
#157,491 1 条评论 1 个 reaction 已指派 0 人 在 GitHub 查看

还没有人认领这个 Issue。

interpreter-core topic-parser type-bug
主要语言
Python
星标
77.2k
派生
35.9k
PR 合并指标
PR 指标待抓取

描述

Bug report

Summary

Closing a nested replacement field inside an f-string format specifier switches the lexer to middle-string mode even though the outer replacement field remains open. Braces that follow the nested field are then parsed as escaped literal content instead of expressions in the format specifier. The shared lexer path also affects t-strings and changes the diagnostic produced for a newline after a nested field.

Reproduction Code
class X:
    def __format__(self, spec):
        return repr(spec)


x = X()
y = "Y"
z = "Z"

print(f'{x:{{y}}}')
print(f'{x:{y}{{z}}}')
Actual Behavior
"{'Y'}"
'Y{z'}

The second f-string passes Y{z to X.__format__(). repr() returns 'Y{z', and the remaining } is appended as literal f-string content. The corresponding t-string, t'{x:{y}{{z}}}', records Y{z as its interpolation's format specifier and places the remaining } in the following literal string.

Expected Behavior

The second f-string should treat {{z}} as a nested replacement field whose expression is the set literal {z}. It should pass Y{'Z'} to X.__format__() and print:

"{'Y'}"
"Y{'Z'}"

The t-string interpolation should likewise record Y{'Z'} as its format specifier.

Root Cause

begin_ftstring_expr() increments replacement_depth when a replacement field starts. A nested replacement field within a format specifier therefore has a greater replacement depth than its enclosing field.

When the matching } is processed, _PyLexer_close_ftstring_expr() decrements replacement_depth and unconditionally selects FTSTRING_MODE_MIDDLE. After a nested field closes, the remaining non-zero replacement depth represents the still-open outer field, whose format specifier is still being scanned. Losing that state changes how _PyLexer_get_ftstring() handles subsequent braces and
newlines.

CPython versions tested on:

CPython main branch

Operating systems tested on:

Linux

Linked PRs
  • gh-157492

贡献指南

打开贡献指南

从这里开始

  1. 先读完整个 Issue,再读项目的贡献指南。
  2. 在 Issue 下留言说明你要接手 —— 这能避免两个人做同样的事。
  3. Fork 仓库,在一个分支上完成修改。
  4. 提交 Pull Request,并在描述里引用这个 Issue 编号。

调研方向

运行两个 f-string 示例,并将其输出与预期行为进行比较,包括相应的 t-string 情况。然后阅读 begin_ftstring_expr() 和 _PyLexer_close_ftstring_expr(),报告将它们确定为相关的 lexer 入口点;完成的标准是:外层格式说明符处于打开状态时,嵌套字段仍能得到正确处理。

由索引模型根据 Issue 内容生成。

评估

技术栈
python
领域
compilers
Issue 类型
缺陷
难度
4/5
预计耗时
3-5 天
活跃度
停滞
描述清晰度
描述清楚
新手友好度
35/100

把新 issue 发到你的邮箱

精选适合新手参与的 GitHub issue 摘要。