Black 报 "INTERNAL ERROR: Black produced code that is not equivalent to the source" 怎么排查
【免费下载链接】blackThe uncompromising Python code formatter项目地址: https://gitcode.com/GitHub_Trending/bl/black
当你用 Black 格式化某个 Python 文件时,如果终端出现下面这样的报错,说明 Black 拒绝了这次格式化:
error: cannot format test.py: INTERNAL ERROR: Black produced code that is not equivalent to the source. Please report a bug on https://github.com/psf/black/issues. This diff might be helpful: /tmp/blk_kjdr1oog.log Oh no! 💥 💔 💥 1 file would fail to reformat.这篇文章基于 Black 仓库中的文档和源码,说明这条报错的来龙去脉、错误信息里各部分分别是什么,以及按文档能走的排查与上报路径。
这条报错是怎么产生的
Black 默认运行在--safe模式下:格式化之后,它会把源码的 AST(抽象语法树)和格式化结果的 AST 逐行字符串化后对比,要求二者语义等价。这个安全检查是 Black 的默认行为,可以用--fast关闭、用--safe显式开启(见 The basics ---fast/--safe):
By default,Blackperforms an AST safety check after formatting your code. The
--fastflag turns off this check and the--safeflag explicitly enables it.
该检查的实现位于 src/black/init.py 的assert_equivalent函数:它先解析源文件和格式化结果的 AST,再把两者转成字符串比较。一旦不一致,就会把「源 AST 与结果 AST 的 diff」写进一个临时文件,然后抛出你看到的那条INTERNAL ERROR,并附上 Black 版本与 Python 运行时信息(_black_info()返回Black <版本> on Python (<实现>) <版本>)。
需要注意:AST 对比并不是「零容忍」。当前风格的说明文档 列出了三种被明确允许的 AST 差异,这些情况不会触发本错误:
- docstring 的前后空白清理与重新缩进;
del语句外层可选括号的处理(解释器层面语义等价);- 注释(包括 Python 3.8 起属于 AST 的 type comments)被移动位置。
所以报出INTERNAL ERROR时,差异已经超出了这些已知例外,属于 Black 自己应当避免的内部问题。
读懂报错信息里的三部分
对照上面的示例输出,错误消息包含三部分,排查时按这个顺序看:
- 出问题的文件:
cannot format test.py,指明是哪个文件没能通过安全检查。 - 版本信息:完整报错里带有
Black <版本> on Python (<实现>) <版本>(由_black_info()生成,见 src/black/init.py)。这是复现和上报 bug 的关键环境信息,记录你的 Black 版本和 Python 版本。 - 诊断 diff 文件:
This diff might be helpful: /tmp/blk_kjdr1oog.log中的路径(示例中的/tmp/blk_kjdr1oog.log是文档给出的示例结果,你的路径每次不同)指向源码 AST 与格式化结果 AST 的对比。查看这个文件能看出具体是哪一段代码在 AST 层面发生了变化。
另外可以确认:源文件没有被修改。FAQ「Is Black safe to use?」 明确写道:安全检查发现问题时会抛出错误,文件保持原样(an error is raised and the file is left untouched)。所以不需要回滚,直接处理即可。
用--check在 CI 中识别这类错误
如果你在 CI 或脚本里跑 Black,可以用--check让 Black 只检查不落盘,此时内部错误会以退出码 123 体现(见 The basics ---check):
- 退出码 0:没有任何文件需要变更;
- 退出码 1:有文件会被重新格式化;
- 退出码 123:发生了内部错误,即本文这类问题。
文档中的示例输出(注意其中的报错行即本文错误):
$ black test.py --check error: cannot format test.py: INTERNAL ERROR: Black produced code that is not equivalent to the source. Please report a bug on https://github.com/psf/black/issues. This diff might be helpful: /tmp/blk_kjdr1oog.log Oh no! 💥 💔 💥 1 file would fail to reformat. $ echo $? 123也就是说,脚本中用$?(或等价的退出码判断)拿到 123,就能确定是内部错误而不是普通的「需要重排」,可以据此在 CI 中单独告警。
官方给出的处理路径
这条错误消息本身就指明了 Black 认为正确的处理流程:把该问题作为 bug 上报,并附上那个 diff 文件。结合文档中已给出的事实,上报时值得包含的内容是:
- 出问题的源文件内容(或最小可复现代码);
- 报错中的 Black 版本与 Python 版本信息;
- 报错里给出的那个临时 diff 文件(
/tmp/blk_*.log形式,内容是源 AST 与结果 AST 的差异)。
错误消息中的上报地址是 GitHub 项目 issue 入口(见 docs/usage_and_configuration/the_basics.md 示例原文)。
可选项:--fast跳过安全检查
如果你只是想绕过这个检查继续拿到格式化结果,文档记录的开关是--fast:它关闭格式化后的 AST 安全检查。需要留意两点:
- 这个检查是 Black 的核心保障,风格文档 明确表示它是一项重要特性且没有放松的计划,所以
--fast只是跳过验证,并不表示差异无风险; - 跳过检查后,退出码 123 对应的这条内部错误不会在
--check流程中因等价性失败出现,是否适合在你的流程中使用需要自行权衡。
小结:排查动作清单
- 确认源文件未被改动,无需回滚(FAQ 明确文件在报错时保持原样)。
- 记下报错中的 Black 版本、Python 版本,并打开报错给出的
/tmp/blk_*.logdiff 文件,定位 AST 差异对应的代码段。 - 在 CI 中用
black --check配合退出码 123 监控这类内部错误。 - 按错误消息指引,把源文件、版本信息和 diff 文件作为 bug 报告附上。
- 仅在需要继续拿到格式化结果时考虑
--fast,并理解它只是关闭安全验证。
参考文档:The basics、FAQ、当前风格的 AST 检查说明,以及报错实现 src/black/init.py。
【免费下载链接】blackThe uncompromising Python code formatter项目地址: https://gitcode.com/GitHub_Trending/bl/black
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考