Python setup.py配置pip包安装后置函数无法执行问题
问题诱因
- 核心原因:现代pip默认不触发自定义
install/develop命令逻辑。pip 10.0之后默认启用PEP 517构建隔离规则,安装sdist包时会先创建独立的临时构建环境,仅预装setuptools、wheel等基础构建工具,在临时环境中构建完安装产物后直接部署文件,全程不会调用你在cmdclass中注册的自定义安装类,钩子自然不会执行。 - 顶层导入依赖直接触发构建报错:你在
setup.py开头直接写了import requests,但默认PEP517构建环境里没有预装requests,构建阶段直接抛出ImportError,这类构建日志默认被pip折叠隐藏,你看不到报错,只会误以为钩子没触发。 - 自定义函数本身存在多处可导致执行中断的bug:
- 缺失必要导入:代码中用到的
os、Path没有对应导入语句,自定义打印函数p()未定义,执行时会直接抛错。 - 执行顺序错误:你在重写的
run方法里先调用temp()再执行父类的install.run(),此时install_requires中声明的requests等依赖还没安装,就算跳过了顶层导包的问题,temp里调用requests时也会报错;同时包的安装路径还未初始化完成,你要写入文件的目标目录大概率不存在,会触发路径不存在错误。
- 缺失必要导入:代码中用到的
修复方案
临时验证自定义钩子的方法
安装时加参数禁用默认PEP517流程,即可触发你写的自定义cmdclass逻辑:pip install 你的包路径 --no-build-isolation --no-use-pep517注意:这类重写
install命令的方案兼容性极差,不支持wheel格式安装,后续setuptools、pip版本升级后很可能彻底失效,生产环境不推荐长期使用。修复现有代码的bug
- 删掉
setup.py顶层的import requests语句,不要在构建阶段导入运行时依赖。 - 补全缺失的导入:在
setup.py开头加上import os、from pathlib import Path,把temp函数里未定义的p('failed to download data files')改成标准的print('failed to download data files')。 - 调整自定义命令的执行顺序,先完成标准安装流程、装完所有依赖,再执行后置逻辑,示例修改:
class PostDevelopCommand(develop): """Post-installation for development mode.""" def run(self): develop.run(self) # 先执行标准开发模式安装 temp() # 最后跑自定义逻辑 class PostInstallCommand(install): """Post-installation for installation mode.""" def run(self): install.run(self) # 先执行标准安装、装完所有依赖 temp() # 最后跑自定义逻辑 - 修改
temp函数的依赖导入逻辑,把import requests放到temp函数内部,等依赖装完再导入;或者直接用标准库urllib实现下载逻辑,彻底避免安装阶段的依赖问题。
- 删掉
长期兼容方案(推荐)
不要依赖安装钩子实现后置逻辑,这类逻辑本身违反Python包安装的规范,很容易在不同环境、不同pip版本下出问题。更稳妥的实现方式有两种:- 方案1:在包中增加一个初始化入口,通过
console_scripts注册为命令行工具,用户安装完成后手动执行一次初始化命令完成文件下载,兼容所有安装格式(wheel/sdist/可编辑安装)。 - 方案2:在包的顶层
__init__.py中增加首次运行检测逻辑,第一次被用户导入时判断目标资源文件是否存在,不存在就执行下载逻辑,下载完成后在包目录下生成标记文件避免重复执行。
- 方案1:在包中增加一个初始化入口,通过
额外规范提示:不要在安装流程中强制联网下载资源,很多企业内网、离线环境安装包时没有网络连接,这类逻辑会直接导致安装失败,优先选择把资源文件随包分发,或者给用户提供手动指定资源路径的配置项。
内容的提问来源于stack exchange,提问作者bobsmith76
相关产品推荐
相关产品推荐

