概述

自从转 Go 之后,好久没写 Python 了。最近在 Ubuntu 24.04 中使用 pipx 安装了一个工具之后,运行报依赖错误。把上下文喂给 DeepSeek 之后,最终解决了问题。

我让 DeepSeek 回顾问答的上下文,整理了一篇文章出来——不过相比上一篇,这次我人工介入修改的内容多得多。


问题提出

最近需要扣一个图,把我的证件照背景颜色换一换。搜了一下,在 Github 上找到一个高 star 的项目 rembg 的图片背景去除工具,用 pipx install rembg 安装后运行时,却遇到了 ModuleNotFoundError: No module named 'onnxruntime' 的错误。这明显是包依赖问题。奇怪了,看起来 pipx 没有 pip 那么聪明?

为什么用 pipx 而不是 pip?

在 Ubuntu 24.04 中,系统默认安装了 Python 3.12,所以我就不用费心去自己通过源码安装。但为了避免污染全局环境,官方不推荐使用 pip,而是 pipx 来管理命令行工具。原因如下:

  • 系统 Python 的自我保护: Ubuntu 的系统工具(如 apt)依赖 Python 环境,直接使用 pip 安装全局包可能导致依赖冲突,甚至破坏系统功能。
  • 隔离性需求: pipx 会为每个包创建独立的虚拟环境,避免包之间的依赖冲突。例如,安装 rembg 时,其依赖的 numpy 版本不会影响其他工具。
  • 命令行工具的天然适配: pipx 会自动将包的可执行文件链接到 ~/.local/bin,无需手动配置环境变量,适合管理 rembg 这类 CLI 工具。

现象

安装 rembg 看似成功,但运行时直接报错:

$ rembg i input.png output.png
Traceback (most recent call last):
  File "/root/.local/bin/rembg", line 5, in <module>
    from rembg.cli import main
  File "/root/.local/share/pipx/venvs/rembg/lib/python3.12/site-packages/rembg/__init__.py", line 5, in <module>
    from .bg import remove
  File "/root/.local/share/pipx/venvs/rembg/lib/python3.12/site-packages/rembg/bg.py", line 7, in <module>
    import onnxruntime as ort
ModuleNotFoundError: No module named 'onnxruntime'

关键信息: rembg 运行时找不到 onnxruntime 模块。


解决方案

找 DeepSeek 问,说实话,DeepSeek 对问题的原因的解释并不能让我满意,它给出的解决方法也有好几条。经过 7 轮问答,我最终挑选了一个可行的方案。

被验证不可行的方案

  1. 强制重装 rembg

尝试卸载后强制重装,但问题依旧:

pipx uninstall rembg
pipx install rembg --force
  1. 全局安装 onnxruntime

直接运行 pipx install onnxruntime,这个方法可以,但是依赖又不止这一个,一个个安装挺麻烦的。此外 pipx install 会为 onnxruntime 创建新虚拟环境,而非注入到 rembg 的环境,推荐用 pipx inject 的模式。


关键操作: pipx inject vs pipx install

1. pipx inject 的作用

  • 精准注入依赖: 将指定包安装到某个应用的虚拟环境中。
  • 解决依赖隔离问题: 例如,为 rembg 单独安装 onnxruntime:
pipx inject rembg onnxruntime

最终解决方案: 自动化脚本

  1. 自动捕获缺失依赖: 从错误日志中提取 ModuleNotFoundError 提示的模块名。
  2. 循环安装与重试: 直到命令成功或达到最大重试次数。
#!/bin/bash
# auto_fix_pipx_deps_loop_fixed.sh

# 配置参数
PACKAGE="rembg"  # 替换为你的包名
COMMAND="rembg"  # 替换为需要执行的命令
MAX_RETRY=20     # 最大重试次数,防止无限循环

# 临时日志文件
LOG="/tmp/pipx_error.log"

# 初始化计数器
retry_count=0
success=0

while [ $retry_count -lt $MAX_RETRY ] && [ $success -eq 0 ]; do
    # 清理旧日志
    rm -f "$LOG"

    # 运行命令并捕获输出,同时记录原始退出状态码
    echo "尝试运行命令 (第 $((retry_count+1)) 次)..."
    $COMMAND 2>&1 | tee "$LOG"
    original_exit_code=${PIPESTATUS[0]}  # 获取原命令的退出状态码

    # 检查命令是否成功
    if [ $original_exit_code -eq 0 ]; then
        echo "命令执行成功!"
        success=1
        break
    else
        echo "命令执行失败,退出码: $original_exit_code"
    fi

    # 提取缺失的模块名(去重)
    MISSING_MODULES=$(grep -o "ModuleNotFoundError: No module named '[^']*'" "$LOG" | awk -F"'" '{print $2}' | sort | uniq)

    if [ ! -z "$MISSING_MODULES" ]; then
        echo "检测到缺失依赖: $MISSING_MODULES"
        for MODULE in $MISSING_MODULES; do
            echo "正在安装: $MODULE"
            pipx inject "$PACKAGE" "$MODULE"
            if [ $? -ne 0 ]; then
                echo "安装依赖 $MODULE 失败,请手动处理。"
                exit 1
            fi
        done
    else
        echo "未检测到缺失的 Python 依赖。请检查以下可能原因:"
        echo "1. 系统级依赖未安装(如 libgomp1)"
        echo "2. 动态导入的依赖未在代码中显式声明"
        echo "3. 其他运行时错误(查看日志: $LOG)"
        break
    fi

    # 增加重试计数
    retry_count=$((retry_count+1))
done

# 最终状态检查
if [ $success -eq 0 ]; then
    echo "已达到最大重试次数 ($MAX_RETRY),问题仍未解决。请手动检查日志: $LOG"
    exit 1
else
    exit 0
fi

脚本运行效果

执行效果类似于这样子的:

尝试运行命令 (第 1 次)...
Traceback (most recent call last):
  File "/root/.local/bin/rembg", line 5, in <module>
    from rembg.cli import main
ModuleNotFoundError: No module named 'onnxruntime'
检测到缺失依赖: onnxruntime
正在安装: onnxruntime
  injected package onnxruntime into venv rembg

尝试运行命令 (第 2 次)...
Traceback (most recent call last):
  File "/root/.local/bin/rembg", line 5, in <module>
    from rembg.cli import main
  File "/root/.local/share/pipx/venvs/rembg/lib/python3.12/site-packages/rembg/cli.py", line 4, in <module>
    from .commands import command_functions
  File "/root/.local/share/pipx/venvs/rembg/lib/python3.12/site-packages/rembg/commands/__init__.py", line 7, in <module>
    from .s_command import s_command
  File "/root/.local/share/pipx/venvs/rembg/lib/python3.12/site-packages/rembg/commands/s_command.py", line 6, in <module>
    import aiohttp
ModuleNotFoundError: No module named 'aiohttp'
命令执行失败,退出码: 1
检测到缺失依赖: aiohttp
正在安装: aiohttp
  injected package aiohttp into venv rembg

......

安装过程中会出现一些失败的情况,一般都是超时等网络问题。解决网络错误之后再跑这个脚本就行了


本文章采用 知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议 进行许可。

原作者: amc,欢迎转载,但请注明出处。

原文标题: 《AI 写文章系列——Ubuntu 24.04 pipx install 解决 ModuleNotFoundError 问题》

发布日期: 2025-03-29

原文链接: https://cloud.tencent.com/developer/article/2508854

CC BY-NC-SA 4.0 DEED.png


amc
927 声望229 粉丝

微电子学毕业,硬件开发转行软件工程师,混迹嵌入式和云计算多年