如何将Kivy应用打包为无控制台EXE?出现日志递归错误
Kivy应用PyInstaller无控制台打包报错问题
问题背景
使用Python 3.8和Kivy 2.2.1开发的小型应用,执行pyinstaller main.py打包后可正常运行,但会显示控制台窗口;添加--windowed、-w或--noconsole参数打包后,程序启动报错,错误信息如下:
Traceback (most recent call last): File "logging\__init__.py", line 1084, in emit AttributeError: 'NoneType' object has no attribute 'write' 在处理上述异常期间,又发生了新的异常: Traceback (most recent call last): File "logging\__init__.py", line 1084, in emit AttributeError: 'NoneType' object has no attribute 'write' 重复出现多次相同错误后,最终出现: File "logging\__init__.py", line 1002, in handleError File "kivy\logger.py", line 390, in write File "logging\__init__.py", line 1454, in warning File "logging\__init__.py", line 1585, in _log File "logging\__init__.py", line 1595, in handle File "logging\__init__.py", line 1657, in callHandlers File "logging\__init__.py", line 950, in handle File "logging\__init__.py", line 1081, in emit File "logging\__init__.py", line 925, in format File "kivy\logger.py", line 540, in format File "kivy\logger.py", line 424, in __init__ File "logging\__init__.py", line 318, in __init__ File "ntpath.py", line 216, in basename File "ntpath.py", line 186, in split File "ntpath.py", line 35, in _get_bothseps RecursionError: maximum recursion depth exceeded while calling a Python object
错误原因
Kivy默认日志系统依赖控制台的标准输出/错误流(sys.stdout/sys.stderr)。当使用--windowed等无控制台参数打包时,PyInstaller会将标准流设置为None,日志模块尝试向None对象写入内容触发AttributeError;而Kivy的日志处理逻辑在捕获该错误时,又会尝试输出新的日志,最终引发无限递归,触发RecursionError。
解决方法
方法1:修改Kivy日志配置,改用文件日志
在应用入口文件main.py最开头添加日志配置,移除控制台日志处理器,改用文件记录日志:
import logging import sys from kivy.logger import Logger # 移除所有控制台日志处理器 for handler in Logger.handlers[:]: if isinstance(handler, logging.StreamHandler): Logger.removeHandler(handler) # 添加文件日志处理器,日志写入app.log file_handler = logging.FileHandler('app.log', encoding='utf-8') log_formatter = logging.Formatter('%(asctime)s [%(levelname)s] %(name)s: %(message)s') file_handler.setFormatter(log_formatter) Logger.addHandler(file_handler) Logger.setLevel(logging.INFO) # 可选:重定向sys.stdout和sys.stderr到文件,避免其他依赖标准流的代码报错 sys.stdout = open('stdout.log', 'w', encoding='utf-8') sys.stderr = open('stderr.log', 'w', encoding='utf-8')
方法2:补充PyInstaller缺失的Kivy依赖
打包时指定Kivy的依赖模块,确保PyInstaller正确识别所有必要组件:
pyinstaller --windowed --hidden-import=kivy.deps.sdl2 --hidden-import=kivy.deps.glew --hidden-import=kivy.deps.angle main.py
方法3:修改PyInstaller spec文件,重定向标准流
- 先生成spec文件:
pyinstaller --windowed main.py - 打开生成的
main.spec文件,在EXE配置块中添加stdout和stderr参数,将标准流重定向到日志文件:exe = EXE(pyz, a.scripts, a.binaries, a.zipfiles, a.datas, [], name='main', debug=False, bootloader_ignore_signals=False, strip=False, upx=True, upx_exclude=[], runtime_tmpdir=None, console=False, stdout='app_stdout.log', stderr='app_stderr.log' ) - 使用spec文件重新打包:
pyinstaller main.spec
内容的提问来源于stack exchange,提问作者Shehara Winod
相关产品推荐
相关产品推荐

