You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Kivy记事本PyInstaller打包exe触发RecursionError问题求助

基于Kivy的记事本PyInstaller打包递归深度溢出问题解决

我自主开发了一个基于Kivy的记事本项目,本地运行完全正常,但使用PyInstaller将其打包为.exe文件后,打开时出现maximum recursion depth exceeded错误。已尝试在.py文件和.spec文件中设置递归上限、调整Kivy日志配置等多种方案,问题仍未解决。

项目代码

from kivy.uix.screenmanager import ScreenManager, Screen
from kivy.uix.filechooser import FileChooserIconView
from kivy.core.window import Window
import datetime
from kivy.lang import Builder
from kivy.app import App
from kivy.config import Config
import time
import sys
sys.setrecursionlimit(100000)
# Set the show_cursor property to 0 to disable the red circle on right-click
Config.set('input', 'mouse', 'mouse,multitouch_on_demand')
import logging
# Disable Kivy logging
Config.set('kivy', 'log_level', 'error')
import os
os.environ['KIVY_NO_FILELOG'] = '1'  # eliminate file log
os.environ['KIVY_NO_CONSOLELOG'] = '1'  # eliminate console logcls

# Set the root logger's level to ERROR
logging.getLogger().setLevel(logging.ERROR)

My_notepad_kv_string="""

<MyNotepad>
    BoxLayout:
        name: 'my_notepad'
        orientation: 'vertical'
        TextInput: 
            id: text_input
            background_color:'#D9F59C'
            background_active:'iron_man_2.jpg'
            
        BoxLayout:
            orientation:'horizontal'
            size_hint: (1, None) 
            height:50
            Button:
                text: "save_note"
                font_size : '20sp'
                on_press: root.texter(text_input.text)
                bold: True
                background_color :'#808000'
                color: '#2ADFE8'

            Button:
                text: "Clear"
                font_size : '20sp'
                bold: True
                background_color :'#811322'
                color: '#2ADFE8'
                on_release: text_input.text = ""
                


"""

class MyNotepad(Screen):

    def texter(self, text):
        self.your_text = text
        if self.your_text == "quit":
            MY_NOTES.get_running_app().stop()
        elif self.your_text != "quit":
            current_time = datetime.datetime.now()
            milliseconds = int(current_time.timestamp() * 1000) % 1000
            filename = 'save_me_{}.txt'.format(
                current_time.strftime(
                    '%Y-%m-%d_%H-%M-%S-{}'.format(milliseconds)))
            with open(filename, 'w') as saver:
                saver.write(self.your_text)
            self.ids.text_input.text = ""



class MY_NOTES(App):

    def build(self):
        Builder.load_string(My_notepad_kv_string)
        self.icon = 'notepad_3.png'
        sm = ScreenManager()
        sm.add_widget(MyNotepad(name='my_notepad'))
        return sm


if __name__ == '__main__':
    MY_NOTES().run()

打包命令

  • 初始打包命令:PyInstaller --onefile -w --icon=notepad.ico My_notepad_S+.py
  • 修改.spec文件添加递归上限后执行:PyInstaller My_notepad_S+.spec

完整错误日志

Traceback (most recent call last):
  File "logging\__init__.py", line 1086, in emit
AttributeError: 'NoneType' object has no attribute 'write'

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "logging\__init__.py", line 1086, in emit
AttributeError: 'NoneType' object has no attribute 'write'

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "logging\__init__.py", line 1086, in emit
AttributeError: 'NoneType' object has no attribute 'write'

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "logging\__init__.py", line 1086, in emit
AttributeError: 'NoneType' object has no attribute 'write'
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
  File "kivy\logger.py", line 248, in emit
  File "kivy\logger.py", line 222, in _configure
  File "logging\__init__.py", line 1446, in info
  File "logging\__init__.py", line 1589, in _log
  File "logging\__init__.py", line 1599, in handle
  File "logging\__init__.py", line 1661, in callHandlers
  File "logging\__init__.py", line 952, in handle
  File "logging\__init__.py", line 1091, in emit
  File "logging\__init__.py", line 1004, in handleError
  File "kivy\logger.py", line 338, in write
  File "logging\__init__.py", line 1458, in warning
  File "logging\__init__.py", line 1589, in _log
  File "logging\__init__.py", line 1599, in handle
  File "logging\__init__.py", line 1661, in callHandlers
  File "logging\__init__.py", line 952, in handle
  File "logging\__init__.py", line 1091, in emit
  File "logging\__init__.py", line 1004, in handleError
  File "kivy\logger.py", line 338, in write
  File "logging\__init__.py", line 1458, in warning
  File "logging\__init__.py", line 1589, in _log
  File "logging\__init__.py", line 1599, in handle
  File "logging\__init__.py", line 1661, in callHandlers
  File "logging\__init__.py", line 952, in handle
  File "logging\__init__.py", line 1091, in emit
  File "logging\__init__.py", line 1004, in handleError
  File "kivy\logger.py", line 338, in write
  File "logging\__init__.py", line 1458, in warning
  File "logging\__init__.py", line 1589, in _log
  File "logging\__init__.py", line 1589, in _log
  File "logging\__init__.py", line 1599, in handle
  File "logging\__init__.py", line 1661, in callHandlers
  File "logging\__init__.py", line 952, in handle
  File "logging\__init__.py", line 1091, in emit
  File "logging\__init__.py", line 1004, in handleError
  File "kivy\logger.py", line 338, in write
  File "logging\__init__.py", line 1458, in warning
  File "logging\__init__.py", line 1589, in _log
  File "logging\__init__.py", line 1599, in handle
  File "logging\__init__.py", line 1661, in callHandlers
  File "logging\__init__.py", line 952, in handle
  File "logging\__init__.py", line 1091, in emit
  File "logging\__init__.py", line 1004, in handleError
  File "kivy\logger.py", line 338, in write
  File "logging\__init__.py", line 1458, in warning
  File "logging\__init__.py", line 1589, in _log
  File "logging\__init__.py", line 1599, in handle
  File "logging\__init__.py", line 1661, in callHandlers
  File "logging\__init__.py", line 952, in handle
  File "logging\__init__.py", line 1091, in emit
  File "logging\__init__.py", line 1004, in handleError
  File "kivy\logger.py", line 338, in write
  File "logging\__init__.py", line 1458, in warning
  File "logging\__init__.py", line 1589, in _log
  File "logging\__init__.py", line 1599, in handle
  File "logging\__init__.py", line 1661, in callHandlers
  File "logging\__init__.py", line 952, in handle
  File "logging\__init__.py", line 1091, in emit
  File "logging\__init__.py", line 1004, in handleError
  File "kivy\logger.py", line 338, in write
  File "logging\__init__.py", line 1458, in warning
  File "logging\__init__.py", line 1589, in _log
  File "logging\__init__.py", line 1599, in handle
  File "logging\__init__.py", line 1661, in callHandlers
  File "logging\__init__.py", line 952, in handle
  File "logging\__init__.py", line 1083, in emit
  File "logging\__init__.py", line 927, in format
  File "kivy\logger.py", line 291, in format
  File "copy.py", line 172, in deepcopy
  File "copy.py", line 264, in _reconstruct
RecursionError: maximum recursion depth exceeded

问题根源与解决方案

根源分析

递归溢出是日志系统循环调用导致的:使用-w参数打包会隐藏控制台,日志输出流变为None,日志输出时触发AttributeError;而日志系统在处理这个错误时又会生成新的日志,形成无限递归,最终耗尽递归深度。另外,代码中未打包的资源文件也可能触发错误日志,加剧问题。

解决步骤

1. 重构日志配置,彻底禁用无效输出

把日志相关配置移到代码最顶部,避免Kivy初始化时加载错误的日志设置:

import os
# 先设置Kivy环境变量,彻底禁用日志文件和控制台输出
os.environ['KIVY_NO_FILELOG'] = '1'
os.environ['KIVY_NO_CONSOLELOG'] = '1'
os.environ['KIVY_LOG_MODE'] = 'null'  # 直接关闭Kivy日志系统

import sys
sys.setrecursionlimit(100000)

from kivy.config import Config
Config.set('input', 'mouse', 'mouse,multitouch_on_demand')
Config.set('kivy', 'log_level', 'critical')  # 仅保留致命错误日志

import logging
# 重置Python标准日志,移除所有默认输出handler
logging.basicConfig(level=logging.CRITICAL)
for handler in logging.root.handlers[:]:
    logging.root.removeHandler(handler)

2. 处理未打包的资源文件

KV代码中TextInput的background_active:'iron_man_2.jpg'和App的icon='notepad_3.png',需要在打包时加入资源:

  • 方法一:移除KV中的background_active属性(如果不需要该效果)
  • 方法二:修改.spec文件,在datas中添加资源路径:
datas=[('iron_man_2.jpg', '.'), ('notepad_3.png', '.')],

3. 调整打包与.spec设置

  • 若仍有问题,先去掉-w参数打包,查看真实错误:
    PyInstaller --onefile --icon=notepad.ico My_notepad_S+.py
  • 在.spec文件开头添加递归上限:
import sys
sys.setrecursionlimit(100000)

4. 重新打包验证

修改完成后,重新生成.spec并执行PyInstaller My_notepad_S+.spec,打包后的.exe即可正常运行。


内容的提问来源于stack exchange,提问作者Dieharder_3

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.30 09:27:04