You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

基于Stanza的auto-py-to-exe GUI程序在Windows10下抛出异常

问题分析

打包无控制台的GUI程序时,Python的sys.stderr会被设置为None(无终端环境下无标准错误流),而Stanza的get_tqdm()函数在捕获get_ipython未定义的异常后,直接调用sys.stderr.isatty(),未先判断sys.stderr是否为None,因此触发AttributeError: 'NoneType' object has no attribute 'isatty'。


解决方案

方案1:修改Stanza源码修复逻辑

找到Python环境中stanza/models/common/utils.py文件,修改get_tqdm()函数的异常处理部分,增加sys.stderr的非空判断:

def get_tqdm():
    """
    Return a tqdm appropriate for the situation

    imports tqdm depending on if we're at a console, redir to a file, notebook, etc

    from @tcrimi at https://github.com/tqdm/tqdm/issues/506

    This replaces `import tqdm`, so for example, you do this:
      tqdm = utils.get_tqdm()
    then do this when you want a scroll bar or regular iterator depending on context:
      tqdm(list)

    If there is no tty, the returned tqdm will always be disabled
    unless disable=False is specifically set.
    """
    try:
        ipy_str = str(type(get_ipython()))
        if 'zmqshell' in ipy_str:
            from tqdm import tqdm_notebook as tqdm
            return tqdm
        if 'terminal' in ipy_str:
            from tqdm import tqdm
            return tqdm
    except:
        # 先检查sys.stderr是否存在,再调用isatty()
        if sys.stderr is not None and sys.stderr.isatty():
            from tqdm import tqdm
            return tqdm

    from tqdm import tqdm
    def hidden_tqdm(*args, **kwargs):
        if "disable" in kwargs:
            return tqdm(*args, **kwargs)
        kwargs["disable"] = True
        return tqdm(*args, **kwargs)

    return hidden_tqdm

修改完成后重新用auto-py-to-exe打包即可。

方案2:在脚本开头预处理标准流

在你的GUI脚本最顶部(导入Stanza之前)添加以下代码,用模拟流替换为空的标准输入/输出/错误流:

import sys

class DummyStream:
    def isatty(self):
        return False
    def write(self, msg):
        pass
    def flush(self):
        pass

# 处理无控制台时标准流为None的情况
if sys.stdin is None:
    sys.stdin = DummyStream()
if sys.stdout is None:
    sys.stdout = DummyStream()
if sys.stderr is None:
    sys.stderr = DummyStream()

# 之后再导入Stanza相关模块
from MFTE import tag_MD, tag_MD_parallel, tag_stanford, tag_stanford_stanza, do_counts
# ... 其余代码

这样get_tqdm()调用sys.stderr.isatty()时会返回False,直接进入禁用tqdm的分支,避免报错。

方案3:用PyInstaller钩子全局处理

创建hook-stanza.py文件,内容如下:

import sys

def pre_safe_import_module(api):
    # 预处理标准流,避免None
    class DummyStream:
        def isatty(self):
            return False
        def write(self, msg):
            pass
        def flush(self):
            pass
    if sys.stderr is None:
        sys.stderr = DummyStream()
    if sys.stdout is None:
        sys.stdout = DummyStream()
    if sys.stdin is None:
        sys.stdin = DummyStream()

# 确保Stanza的模型数据被打包
from PyInstaller.utils.hooks import collect_data_files
datas = collect_data_files('stanza')

在auto-py-to-exe的「Additional Files」中添加该钩子文件,或打包时通过--additional-hooks-dir=.参数指定钩子目录。

内容的提问来源于stack exchange,提问作者Shakir

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.29 12:47:17