安装 OpenNFT 时无法导入 DistutilsOptionError
结论
问题出在 OpenNFT 的 setup.py:DistutilsOptionError 的导入路径写错了。缺少依赖、venv 损坏以及 pip 版本都不是这次报错的原因。
DistutilsOptionError 定义在 distutils.errors 中。将:
from distutils.core import DistutilsOptionError
改为:
from distutils.errors import DistutilsOptionError
然后从本地源码重新安装。
为什么升级 pip 和 setuptools 没有效果
错误发生在生成包元数据时:
Preparing metadata (setup.py) ... error
这个阶段,pip 正在执行 OpenNFT 的 setup.py,尚未开始安装依赖。报错是因为 setup.py 第 10 行使用了错误的导入路径:
from distutils.core import DistutilsOptionError
异常堆栈中出现了:
site-packages\setuptools\_distutils\core.py
这说明当前环境使用的是 setuptools 提供的 distutils 实现,并非 _distutils 安装不完整。无论使用 Python 自带的旧版 distutils,还是 setuptools._distutils,都应从 distutils.errors 导入 DistutilsOptionError。
可以在虚拟环境中运行以下命令验证:
python -c "from distutils.errors import DistutilsOptionError; print(DistutilsOptionError)"
如果命令能正常输出类名,说明该对象确实存在,OpenNFT 只是导入错了位置。
推荐解决方法
先激活已有的虚拟环境,再克隆源码:
git clone --recursive https://github.com/OpenNFT/OpenNFT.git
Set-Location OpenNFT
打开仓库根目录下的 setup.py,找到:
from distutils.core import DistutilsOptionError
修改为:
from distutils.errors import DistutilsOptionError
保存文件,然后在仓库根目录执行:
python -m pip install .
使用 python -m pip 可以确保调用当前虚拟环境中的 pip。
安装完成后,用下面的命令检查 OpenNFT 是否已安装到当前环境:
python -m pip show OpenNFT
用补丁方式修改
也可以在仓库根目录创建并应用下面的补丁,无需手动编辑文件:
--- a/setup.py
+++ b/setup.py
@@
-from distutils.core import DistutilsOptionError
+from distutils.errors import DistutilsOptionError
补丁只修改这一行,无需调整 pip、wheel 或其他依赖。
如果仍想直接通过 Git URL 安装
执行 pip install git+https://... 时,pip 会将仓库克隆到临时目录,并立即运行 setup.py。这样很难在安装前修改源码。在上游仓库修复这一行之前,直接安装存在该问题的 Git 版本仍可能失败。
可以选择以下方式处理:
- 克隆源码,修改
setup.py,再执行python -m pip install .。 - 如果 OpenNFT 后续的提交或发行版本已经修复导入路径,安装包含该修复的提交、分支或版本。
采用第二种方式前,应检查目标版本的 setup.py,确认其中已经改为:
from distutils.errors import DistutilsOptionError
注意事项
某个 OpenNFT 版本兼容 Python 3.7,不代表它也兼容所有最新版构建工具。Python 3.7 已结束官方维护,一些新版软件包也不再支持它。修复上述源码后,如果又遇到其他依赖错误,应使用 OpenNFT 安装文档指定的 Python 和依赖版本,不要继续无条件升级所有构建工具。
distutils 已被弃用,并从 Python 3.12 的标准库中移除。在 Python 3.7 中,这次问题可以通过修正导入路径解决。如果以后迁移到较新的 Python,还需确认所用 OpenNFT 版本是否已经改用 setuptools 等受支持的构建方式。
备注:内容仅供参考。
