DEBUG.WIKI
ZgoCloud:多地区部署,按需选节点;日本、美国、香港、德国
雨云;给项目一台云服务器
RackNerd;$21.99/年 · 1GB KVM

Black 格式化含中文变量的 Notebook 魔法语句失败,按 UTF-8 字节截前缀

Black 用 AST 字节位置切字符前缀时会损坏含中文变量的 Notebook 魔法语句,应采用偏移修复并检查原单元格内容。

Notebook 单元格里的 变量 = %env FOO 在 IPython 中有明确含义,Black 格式化时却可能生成 变量 = get_b"..." 一类残缺文本,再报无法解析。把变量名换成 ASCII 后恢复正常,是定位魔法语句占位处理的线索,不表示中文变量名本身不合法。

Black 先把魔法语句转换为 get_ipython() 调用,再暂时替换成可格式化的占位符。这里从 Python AST 得到的 col_offset 按 UTF-8 字节计数,旧代码却直接用它切 Python 字符串。两个中文字占六个字节,字节位置 9 对应的字符位置只有 5,截取时就会多留下 get_ 等转换代码。

Black 26.10.0 包含修复:先对行按 UTF-8 编码,按字节位置截取前缀,再解码回字符串。使用 Notebook 支持所需的 Jupyter extra,并核对编辑器或 pre-commit 实际调用的版本。

python -m pip install "black[jupyter]==26.10.0"
python -m black --version

可在独立目录构造一个最小 Notebook,避免先改真实笔记本中的变量名:

import json
from pathlib import Path

notebook = {
    "nbformat": 4, "nbformat_minor": 5,
    "metadata": {"language_info": {"name": "python"}},
    "cells": [{
        "cell_type": "code", "id": "unicode-magic", "metadata": {},
        "execution_count": None, "outputs": [],
        "source": ["变量 = %env FOO\n"],
    }],
}
Path("unicode-magic-check.ipynb").write_text(
    json.dumps(notebook, ensure_ascii=False), encoding="utf-8"
)
python -m black unicode-magic-check.ipynb
python -m black --check unicode-magic-check.ipynb

格式化命令应成功,第二次检查应不再要求修改。打开文件查看单元格源代码,确认 %env FOO 仍是原魔法语句、变量名完整,没有残留 get_ipython 占位内容;再在项目认可的内核中验证该单元格行为。

普通 Python 的 AST 不能直接解析 %env,所以不能把魔法语句原文拿给 ast.parse(),将其异常当作 Black 的复现。Notebook 文件名、语言元数据及 Jupyter 依赖也需要正确,单独把文件改名为 .py 会走另一条路径。

这个修复处理非 ASCII 前缀与 AST 字节偏移的对齐。未知自定义魔法、未安装 IPython 或普通 Python 语法错误,仍需分别处理;更新不会使任意 Notebook 语法都自动得到支持。