Python 3.12 彻底删除 distutils 导致 pip install 卡在 “Preparing metadata (setup.py)”:因无 pyproject.toml,pip 尝试包装 setup.py,但 distutils.cmd 等已不存在,包装失败且错误被静默;需升级 setuptools≥69.0、pip≥24.1、补 wheel,并迁移三处代码(LooseVersion→packaging.version、setup→setuptools、自定义命令→setuptools.command)。

Python 3.12 下的安装报错,大概率是 distutils 被彻底删除引发的连锁反应,不是环境没配好,而是旧构建逻辑已经失效。
为什么 pip install 会卡在 “Preparing metadata (setup.py)”
pip 检测到项目没有 pyproject.toml,就试图用兼容模式包装 setup.py;但 Python 3.12 已经删光 distutils,连 distutils.cmd 都不存在,包装直接失败。错误常被静默吞掉,只显示卡住或无限等待。
- 加
-v参数才能看到真实报错,比如:No module named 'distutils.cmd' - PyCharm 点 “Install package” 也走这条老路径,不自动启用 PEP 517
- Docker 构建时用
FROM python:3.12-slim,镜像里甚至没预装setuptools,第一步就崩
setuptools ≥69.0 是硬门槛,但光升级不够
setuptools 在构建时仍会 fallback 到 <code>distutils,升级后照样报错。而且仅运行 pip install --upgrade setuptools 不保险——它可能只更新了 pip 自带的副本,而没更新解释器内嵌的版本。
- 必须确认:运行
python -c "import setuptools; print(setuptools.__version__)"输出 ≥69.0 - 同时补上
wheel:python -m pip install wheel(否则无法生成 wheel 元数据) - 确保
pip --version ≥ 24.1,旧版 pip 内部构建链仍依赖distutils
旧项目迁移必须改三处代码,不能跳过
替换不是可选动作,漏一个都可能在导入、版本比较或自定义命令阶段静默失败。PyPI 上那个叫 distutils 的空包没用,它不提供任何实际类。
让 macOS 自动化像说话一样简单 —— 用代码控制你的 Mac,无需学习 AppleScript 系统要求 macOS 14+ (Sonoma) Python 3.9+ 需要开启:辅助功能 + 屏幕录制权限
-
from distutils.version import LooseVersion→ 改成from packaging.version import parse,然后用parse("1.2.3") > parse("1.2a1") -
from distutils.core import setup→ 改成from setuptools import setup,且项目根目录必须有pyproject.toml(哪怕只有最简[build-system]段) - 自定义命令类(如继承
distutils.command.build_ext)→ 改用setuptools.command.build_ext
AttributeError: module 'setuptools' has no attribute 'dist' 怎么办
这是 setuptools 70+ 移除 setuptools.dist 后的典型报错,常见于 PyCharm 内置打包工具或某些 legacy setup.py 直接访问该属性。它和 ModuleNotFoundError: No module named 'distutils' 是同一波清理的副产品。
- 不要降级 setuptools——60.x 版本反而更不稳定,容易 fallback 失败
- 检查项目里有没有手动调用
setuptools.dist.Distribution或类似写法,全部替换成setuptools.build_meta或标准 PEP 517 构建入口 - PyCharm 用户:进
Settings → Tools → Python Packaging,勾选 “Use setuptools for building packages”,并禁用 “Legacy setup.py installation”
最易被忽略的是:MANIFEST.in 行为在新版 setuptools 中已变更,include 规则默认不再递归匹配子目录,旧规则可能让打包遗漏文件——这点不会报错,但会导致运行时缺模块。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!










