PyInstaller编译exe后导入Scipy触发FileNotFoundError求助
问题背景
将名为Sim_choix_modal.py的Python脚本通过PyInstaller编译为单文件.exe时,运行到import scipy环节出现以下报错:
Traceback (most recent call last):
File "Sim_choix_modal.py", line 15 in
File "", line 1007, in _find_and_load
File "", line 986, in find_and_load_unlocked
File "", line 680, in load_unlocked .py, line 67 in _delvewheel_init_patch_1_1_0
File "PyInstaller\loader\yimode03_importers.py", line 495, in exec_module
File "scipy_init.py, line 76 in
File "scipy_init
File "os.py", line 1111, in add_dll_directory
FileNotFoundError: [WinError 2] 系统找不到指定的文件: 'C:\Users\username~1\AppData\Local\Temp\_MEI155082\scipy.libs'
[17952] Failed to execute script 'Sim_choix_modal' due to unhandled exception!
编译命令为pyinstaller --onefile Sim_choix_modal.py,已尝试添加--add-data、hiddenimports及官方钩子方案均未解决。
可行解决方案
方案1:修改Spec文件并添加Runtime Hook
步骤1:生成Spec文件
如果还没有生成Spec文件,先执行以下命令生成:
pyinstaller --onefile Sim_choix_modal.py
会得到Sim_choix_modal.spec文件。
步骤2:创建Runtime Hook文件
新建名为hook-scipy.py的文件,内容如下:
import os import sys def _delvewheel_init_patch_1_1_0(): # 指向单文件模式下临时目录中的scipy.libs路径 libs_dir = os.path.join(sys._MEIPASS, 'scipy.libs') if os.path.exists(libs_dir): os.add_dll_directory(libs_dir) # 替换scipy初始化时的同名函数,修正路径判断 import scipy scipy._delvewheel_init_patch_1_1_0 = _delvewheel_init_patch_1_1_0
步骤3:编辑Spec文件
打开Sim_choix_modal.spec,修改以下部分:
- 在
datas列表中添加scipy.libs的路径(替换为你的虚拟环境实际路径):
datas = [ (r'C:\path\to\venv\Lib\site-packages\scipy.libs', 'scipy.libs'), ]
- 添加runtime_hooks参数:
a = Analysis( ['Sim_choix_modal.py'], pathex=[], binaries=[], datas=datas, # 上面配置的datas hiddenimports=['scipy._lib.messagestream'], hookspath=[], hooksconfig={}, runtime_hooks=['hook-scipy.py'], # 添加此行 excludes=[], win_no_prefer_redirects=False, win_private_assemblies=False, cipher=None, noarchive=False, )
步骤4:重新打包
执行以下命令用修改后的Spec文件打包:
pyinstaller Sim_choix_modal.spec
方案2:先测试One-Directory模式
如果单文件模式仍有问题,先尝试用多文件模式打包验证依赖是否正确:
pyinstaller Sim_choix_modal.py
进入生成的dist/Sim_choix_modal目录运行exe,如果能正常执行,说明是单文件模式下的路径适配问题,再回到方案1调整配置。
方案3:升级依赖版本
确保使用兼容的Scipy和PyInstaller版本,执行以下命令升级:
pip install --upgrade scipy pyinstaller
Scipy 1.10+和PyInstaller 5.10+对delvewheel打包的支持更完善,可能直接解决路径问题。
问题原因
Scipy从1.10版本开始使用delvewheel打包,依赖的DLL文件集中放在scipy.libs目录下。PyInstaller默认不会自动识别并包含该目录,且Scipy初始化时的_delvewheel_init_patch_1_1_0函数在单文件模式下无法正确定位临时目录中的scipy.libs,导致DLL路径添加失败。
内容的提问来源于stack exchange,提问作者P.Bryss

