使用setuptools打包Python3.6应用后出现ModuleNotFoundError求助
这种情况我遇到过好几次,核心问题大多是导入路径不匹配或者setuptools配置没对齐项目结构。咱们一步步排查:
1. 先确认你的项目结构是否正确
本地运行没问题是因为你在项目根目录,Python会把当前目录加入sys.path,但打包安装后,程序是从site-packages目录加载的,结构不对就会找不到模块。正确的结构应该是这样的:
sonicparanoid-project/ ├── setup.py └── sonicparanoid/ # 这是你的核心包目录 ├── __init__.py # 必须有,哪怕是空文件,Python3.6需要它识别为包 ├── sonicparanoid.py # 你的主程序 └── other_module.py # 其他需要导入的模块
如果你的结构是把主脚本直接放在项目根目录(比如和setup.py同级),那打包后肯定会出问题——因为安装后主脚本不在包目录里,自然找不到内部模块。
2. 修改主程序的导入方式
本地直接运行时,你可能用的是import other_module这种相对当前目录的导入,但打包后,主脚本属于sonicparanoid包的一部分,必须用包内相对导入或者绝对导入:
- 相对导入(推荐,更灵活):在
sonicparanoid.py里改成from . import other_module # 注意开头的点,代表当前包 - 绝对导入:
from sonicparanoid import other_module
别再用裸的import other_module了,这种导入只在本地运行时有效。
3. 检查setup.py的配置(重点!)
很多人踩坑是因为用了scripts参数而不是entry_points,或者entry_points配置错误。
正确的配置应该用console_scripts
把setup.py里的入口配置改成这样:
from setuptools import setup, find_packages setup( name="sonicparanoid", version="1.0.0", packages=find_packages(), # 自动识别你的sonicparanoid包 entry_points={ "console_scripts": [ "sonicparanoid = sonicparanoid.sonicparanoid:main", # 格式:命令名 = 包.模块:函数名 ] }, # 其他配置(author、description等)... )
这里的main是你sonicparanoid.py里的主函数——你需要把原来的脚本代码封装到一个main()函数里,然后在脚本末尾加:
if __name__ == "__main__": main()
为什么要用console_scripts?因为setuptools会自动生成一个适配不同系统的命令行脚本,并且帮你处理好Python路径问题,比直接用scripts=['sonicparanoid.py']靠谱多了。
别用scripts参数(除非你特别清楚后果)
如果之前用的是scripts,比如:
setup( ... scripts=["sonicparanoid.py"] )
这种方式只是把脚本复制到系统的bin目录,但不会处理导入路径,所以运行时脚本找不到包内模块是必然的。
4. 重新安装并测试
先卸载旧的安装包:
pip uninstall -y sonicparanoid
然后重新安装:
pip install . # 或者 python setup.py install
之后直接运行sonicparanoid命令,应该就能正常导入模块了。
5. 排查:打印sys.path确认路径
如果还是有问题,在sonicparanoid.py的最开头加两行代码:
import sys print("Current sys.path:", sys.path)
然后运行命令行工具,看看输出的路径里有没有你的sonicparanoid包所在的目录(一般是site-packages下的sonicparanoid目录)。如果没有,说明setuptools没正确安装你的包,检查setup.py里的packages参数是否正确(用find_packages()就没问题,手动写packages=["sonicparanoid"]也可以,但find_packages更省心)。
内容的提问来源于stack exchange,提问作者Salvatore Cosentino

