使用PyInstaller打包Kivy应用运行时出现AttributeError: 'NoneType'无load_module属性
问题根因定位
这个报错本质是PyInstaller打包后的运行环境中,kivy初始化时尝试调用导入器的load_module方法失败,导入器返回了空值,通常和kivy的核心依赖导入顺序、Config配置预加载的冲突、或者PyInstaller对kivy自带的导入钩子支持异常有关。
排查步骤
- 第一步:先验证Config.read()调用的影响
你提到代码开头在导入kivy前调用了Config.read(),这是最可能的触发点:你需要确认你调用的是不是kivy的Config?如果是from kivy.config import Config之后再读配置,那没问题,但如果你是在导入任何kivy模块之前,自己写了Config读取逻辑改了sys.path、或者修改了导入相关的环境变量,会直接干扰kivy初始化时的模块加载逻辑。你可以先临时注释掉代码开头所有Config.read相关的逻辑,打包测试看是否还报错,先排除这个变量。 - 第二步:检查.spec文件的缺失配置
你现有的.spec里只加了sdl2、glew、gstreamer的依赖bin,但是漏了kivy核心的导入钩子配置,需要在.spec开头加上kivy的钩子路径,自动加载所有kivy需要的隐藏导入,避免手动漏加。 - 第三步:验证虚拟环境的依赖一致性
你直接在虚拟环境运行正常不代表打包时调用的PyInstaller和依赖是对的,需要确认你执行打包命令时的虚拟环境是激活状态,执行pip list检查kivy、pyinstaller、kivy_deps系列包的版本和你之前成功打包的版本是否一致,尤其是如果近期升级了PyInstaller到5.0以上版本,对kivy的钩子支持有变化,你可以降级到PyInstaller 4.10版本测试,这个版本是kivy官方验证过兼容性最高的打包版本。 - 第四步:检查导入路径冲突
你打包时加了很多--add-data的路径,如果你在代码开头修改了sys.path把当前目录或者其他打包后的目录加到了最前面,会覆盖PyInstaller自带的导入器路径,导致kivy找不到自己的模块,你可以在GUI.py的最开头打印sys.path,运行exe时查看输出的sys.path和本地运行的差异,排查是否有路径冲突。
快速解决方案
可以直接用以下标准kivy打包配置修改你的.spec文件,90%以上的这类导入报错都能解决:
- 替换你的.spec文件开头部分为:
# -*- mode: python ; coding: utf-8 -*- from kivy_deps import sdl2, glew, gstreamer from kivy.tools.packaging.pyinstaller_hooks import get_deps_all, hookspath, runtime_hooks import sys import os sys.path.insert(0, os.path.abspath('../GUI_T3')) # 把你的源码目录加到路径里
- 补全Analysis部分的钩子和隐藏导入配置:
a = Analysis( ['../GUI_T3/GUI.py'], pathex=[], binaries=[], datas=[ ('../GUI_T3/GUI.ini', '.'), ('../GUI_T3/navigator.ini', '.'), ('../GUI_T3/static', './static'), ('../GUI_T3/library', './library'), ('../GUI_T3/layouts', './layouts'), ('../../fpga/register_map/pico_regs.json', '.') ], hiddenimports=get_deps_all()['hiddenimports'] + ['kivy_deps.sdl2', 'kivy_deps.glew', 'kivy_deps.gstreamer'], hookspath=hookspath(), hooksconfig={}, runtime_hooks=runtime_hooks(), excludes=[], noarchive=False, )
- COLLECT部分保持你现有的添加sdl2、glew、gstreamer的Tree的逻辑即可,修改完后重新用spec打包测试。
内容的提问来源于stack exchange,提问作者mnikley
相关产品推荐
相关产品推荐

