PyInstaller的这个打包寻找依赖的过程感觉不是很智能,对于常用的库比如PyQt等,他们的依赖文件都能被正常处理,从而pyInstaller打包出来的exe没有运行报错问题。
但如果是不常见的库比如弹窗样式组件pyqt_toast库,打包时总是报错:

图像 001.png

这个foreground.css文件是pyqt_toast库自身引入的文件(而不是我代码的依赖)

图像 002.png

通过查询PyInstaller的文档发现了相关说明:

The majority of Python packages use normal methods of importing their dependencies, and PyInstaller locates all their files without difficulty. But some packages make unusual uses of the Python import mechanism, or make clever changes to the import system at runtime. For this or other reasons, PyInstaller cannot reliably find all the needed files, or may include too many files. A hook can tell about additional source files or data files to import, or files not to import.

大多数 Python 包使用正常的导入方法 它们的依赖项,并且 PyInstaller 可以轻松找到它们的所有文件。 但是有些包不寻常地使用了 Python 导入机制, 或者在运行时对导入系统进行巧妙的更改。 由于这个或其他原因,PyInstaller 无法可靠地找到 所有需要的文件,或者可能包含太多文件。 Hook文件可以告诉要导入的其他源文件或数据文件,或不导入的文件

也即是这种相对路径导入的方式,PyInstaller无法识别。针对此种情况他们也给出了解决方案(https://pyinstaller.org/en/stable/hooks.html),即手动为三方库添加Hook文件来使得PyInstaller能够遍历到三方库的依赖。

为此这个问题的解决方案是在PyInstaller库的Hook目录下(pyinterpreter\Lib\site-packages\PyInstaller\hooks),新建一个Hook文件,命名规则:hook-第三方库名称.py
新建“hook-pyqt_toast.py”,然后写入以下代码,这样PyInstaller会识别pyqt_toast的依赖库在pyqt_toast下面(pyqt_toast的实际依赖样式文件在pyqt_toast\style,不用管,PyInstaller会自己遍历)

from PyInstaller.utils.hooks import collect_data_files

datas = collect_data_files("pyqt_toast")

图像 004.png

然后重新执行构建exe命令:pyinstaller -F 要构建的文件.py

可以从窗口看到构建时,自建的hook-pyqt_toast.py被正确加载(不正确加载会有提示)

图像 003.png

最后就是运行打包好的exe文件,不会再出现相同报错