DEBUG.WIKI
晚安云;香港 CN2 ¥15/月
ZgoCloud:多地区部署,按需选节点;日本、美国、香港、德国
OnlineSIM:在线接收短信,虚拟号码租用

IPython 9.13.0 一导入就报 stdout 没有 isatty

IPython 9.13.0 的终端图形检测直接调用 stdout.isatty,可能让 Sphinx 等捕获输出环境在导入时失败。修正适配接口或采用已有防护的兼容版本。

Sphinx 构建文档或宿主程序接管标准输出后,import IPython 直接失败,错误是 AttributeError: 'DummyFile' object has no attribute 'isatty'。如果栈落在 IPython/core/kitty.py,检查输出对象是否只有 write()、flush(),没有终端检测接口。

IPython 9.13.0 会在导入时检查 Kitty 图形协议支持。Darwin、Linux 路径直接调用 sys.stdout.isatty(),所以并不需要真正绘图,也不需要打开 Notebook,就可能触发异常。输出可以写进去,不代表它实现了 IPython 此处读取的全部接口。

不要给非终端输出伪造一个终端身份

如果输出适配器由自己的程序维护,并且目标确实是文档捕获器、文件或日志收集器,可以让 isatty() 明确返回 False。下面只是最小接口示例,写入和刷新仍委托给现有目标:

class CapturedOutput:
    def __init__(self, target):
        self.target = target

    def write(self, text):
        return self.target.write(text)

    def flush(self):
        return self.target.flush()

    def isatty(self):
        return False

实际宿主若还有 encoding、fileno() 等要求,应在原适配器里分别处理,不能把这个片段当成完整的 TextIO 替代。也不要为绕过检测返回 True:非终端输出可能因此收到不适合的控制序列。

适配器来自 Sphinx 或其他依赖时,优先采用该组件受支持的更新或修复入口,不改它的私有对象。临时把 sys.stdout 换回 sys.__stdout__ 可能绕过捕获并丢失构建日志;sys.__stdout__ 在某些宿主里也可能是 None,并不是可靠的通用修复。

更新后仍用原来的捕获入口验收

IPython 9.17.1 的正式实现已先取 getattr(sys.stdout, "isatty", None),仅在对象可调用且返回 True 时继续终端检测。缺少这个方法的输出对象会被当作不支持此图形输出,而不再在这里直接抛属性错误。

项目能够使用该版本时,沿现有依赖管理方式更新 IPython,并核对文档构建或宿主程序实际使用的解释器。终端里升级成功,不代表构建工具调用的隔离环境或 Notebook 内核也已更新。这里确认的是 9.17.1 已有防护,不把它称作首次修复版本。

验收要回到原先替换 stdout 的那条完整构建或运行命令,检查导入、输出捕获和构建结果都正常。只在普通终端里运行一次 import IPython,没有覆盖原来的接口缺口。若适配器提供了 isatty(),但它自己抛出别的异常,缺失属性的防护也不能保证替它处理。

若新堆栈出现在另一个模块,或图形协议检测已经通过,应按当前错误继续查。这个问题限定于导入期间的终端能力检测,不等于所有 Sphinx 构建失败都需要改 stdout。