Unable to build kivy image loaded .py file into exe using auto-py-to-exe

2024/10/10 22:20:50

I have a simple kivy file in which i want to cover the entire canvas with an image bgi.jpg

MainWidget:    
<MainWidget>:canvas.before:Rectangle:size:self.sizesource:'bgi.jpg'

and the .py file code is

from kivy.app import App
from kivy.uix.widget import Widget
class MainWidget(Widget):pass
class TestApp(App):pass
TestApp().run()

I tried to build this code into .exe file using auot-py-to-exe. i added both kivy file and the image file as a additional file and tried to build into exe but the executable file is crashing with the error as shown below

Traceback (most recent call last):File "kivy\lang\builder.py", line 925, in _build_canvasFile "kivy\graphics\instructions.pyx", line 380, in kivy.graphics.instructions.VertexInstruction.source.__set__File "kivy\graphics\context_instructions.pyx", line 431, in kivy.graphics.context_instructions.BindTexture.source.__set__File "kivy\core\image\__init__.py", line 561, in __init__File "kivy\core\image\__init__.py", line 754, in _set_filenameFile "kivy\core\image\__init__.py", line 460, in loadFile "kivy\core\image\__init__.py", line 223, in __init__File "kivy\core\image\img_sdl2.py", line 47, in load
Exception: SDL2: Unable to load imageDuring handling of the above exception, another exception occurred:Traceback (most recent call last):File "Main.py", line 9, in <module>File "kivy\app.py", line 954, in runFile "kivy\app.py", line 923, in _run_prepareFile "kivy\app.py", line 696, in load_kvFile "kivy\lang\builder.py", line 305, in load_fileFile "kivy\lang\builder.py", line 405, in load_stringFile "kivy\uix\widget.py", line 470, in apply_class_lang_rulesFile "kivy\lang\builder.py", line 540, in applyFile "kivy\lang\builder.py", line 595, in _apply_ruleFile "kivy\lang\builder.py", line 928, in _build_canvaskivy.lang.builder.BuilderException: Parser: File "C:\Users\User\Documents\Python scripts\Python class\Kivy projects\exe test\Main with image\test.kv", line 6:...4:        Rectangle:5:            size:self.size>>    6:            source:'bgi.jpg'7:    Label:8:        id:lbl...Exception: SDL2: Unable to load imageFile "kivy\lang\builder.py", line 925, in _build_canvasFile "kivy\graphics\instructions.pyx", line 380, in kivy.graphics.instructions.VertexInstruction.source.__set__File "kivy\graphics\context_instructions.pyx", line 431, in kivy.graphics.context_instructions.BindTexture.source.__set__File "kivy\core\image\__init__.py", line 561, in __init__File "kivy\core\image\__init__.py", line 754, in _set_filenameFile "kivy\core\image\__init__.py", line 460, in loadFile "kivy\core\image\__init__.py", line 223, in __init__File "kivy\core\image\img_sdl2.py", line 47, in load

I am fairly new to both kivy,python and pyinstaller, so i have no idea what is wrong or should image files be added in a different method

Answer

auto-py-to-exe is not able to create exe file from Kivy project. It's a GUI for PyInstaller with limitations which won't allow you make required modifications to generate proper exe file.

In general you should follow the Kivy documentation: https://kivy.org/doc/stable/guide/packaging-windows.html and use pure PyInstaller .

But in my opinion the amount of provided informations/scenarios may be overwhelming, so here is my tutorial:

  1. Add following lines to your main python script (usually main.py), on top of file:

     import os, sysif sys.__stdout__ is None or sys.__stderr__ is None:os.environ['KIVY_NO_CONSOLELOG'] = '1'from kivy.resources import resource_add_path, resource_findif hasattr(sys, '_MEIPASS'):resource_add_path(os.path.join(sys._MEIPASS))
    
  2. Download PyInstaller package

     pip install pyinstaller
    

    Currently latest PyInstaller version is 5.7.0, you can specify it if you want to:

     pip install pyinstaller==5.7.0
    
  3. Create PyInstaller spec file

     pyi-makespec --noconsole --onefile --name "main" --add-data="*.kv;." --add-data="*.jpg;." "main.py"
    

    Notes:

         - noconsole will remove console window- onefile will create all-in-one exe file- name specify spec and final exe file name- add-data will include specified file/files into exe. You can use wildcards here like *.jpg- last param is your main Python script file name
    

    pyi-makespec will create following "main.spec" file:

     # -*- mode: python ; coding: utf-8 -*-block_cipher = Nonea = Analysis(['main.py'],pathex=[],binaries=[],datas=[('*.kv', '.'), ('*.jpg', '.')],hiddenimports=[],hookspath=[],hooksconfig={},runtime_hooks=[],excludes=[],win_no_prefer_redirects=False,win_private_assemblies=False,cipher=block_cipher,noarchive=False,)pyz = PYZ(a.pure, a.zipped_data, cipher=block_cipher)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,disable_windowed_traceback=False,argv_emulation=False,target_arch=None,codesign_identity=None,entitlements_file=None,)
    

    PyInstaller spec file is in fact Python script. You have to modify it to be able to build proper exe for Kivy based project. If you decide for example to enable console, you don't have to generate new spec file using pyi-makespec command. Just modify already generated spec file, which contain all parameters you passed to pyi-makespec first time. It's easy to match pyi-makespec arguments within "main.spec" file content. For instance if you want to enable console, then you have to change "console=False," to "console=True,". If you want to add another file to exe, like "image.png", just change "datas=[('.kv', '.'), ('.jpg', '.')]," to "datas=[('.kv', '.'), ('.jpg', '.'), ('image.png', '.')],". If you want to change final exe name from "main.exe" to "my_app.exe" just change "name='main'," to "name='my_app',".

    But if you want to create one-folder with binaries instead of all-in-one exe file, you have to use pyi-makespec command again, and remove "--onefile" argument. The spec file for onefile and onefolder is slightly different.

  4. Add Kivy specific lines to "main.spec" file

    Compared to original spec file two lines are added:

     from kivy_deps import sdl2, glew, gstreamer  # Kivy imports*[Tree(p) for p in (sdl2.dep_bins + glew.dep_bins)],  # Kivy binaries
    

    Here is modified "main.spec" file:

     # -*- mode: python ; coding: utf-8 -*-from kivy_deps import sdl2, glew, gstreamer  # Kivy importsblock_cipher = Nonea = Analysis(['main.py'],pathex=[],binaries=[],datas=[('*.kv', '.'), ('*.jpg', '.')],hiddenimports=[],hookspath=[],hooksconfig={},runtime_hooks=[],excludes=[],win_no_prefer_redirects=False,win_private_assemblies=False,cipher=block_cipher,noarchive=False,)pyz = PYZ(a.pure, a.zipped_data, cipher=block_cipher)exe = EXE(pyz,a.scripts,a.binaries,a.zipfiles,a.datas,*[Tree(p) for p in (sdl2.dep_bins + glew.dep_bins)],  # Kivy binaries excluding gstreamer.dep_bins[],name='main',debug=False,bootloader_ignore_signals=False,strip=False,upx=True,upx_exclude=[],runtime_tmpdir=None,console=False,disable_windowed_traceback=False,argv_emulation=False,target_arch=None,codesign_identity=None,entitlements_file=None,)
    

    Please keep in mind, that "Kivy binaries" line is added under "a.datas," line. It's new line, and it have to be placed here.

    If your app will use video content played by gstreamer, you will have to modify line:

     *[Tree(p) for p in (sdl2.dep_bins + glew.dep_bins)],
    

    to

     *[Tree(p) for p in (sdl2.dep_bins + glew.dep_bins + gstreamer.dep_bins)],
    

    In result your exe file size may be bigger. You can read about different scenarios on https://kivy.org/doc/stable/guide/packaging-windows.html

  5. Create exe file

     pyinstaller --clean "main.spec"
    

    It will create "build" and "dist" folders. First one is a temporary folder used by PyInstaller to collect required files. Within second one you will find your generated exe file (main.exe).

    If you remove "--clean" argument next build attempts will be faster, because PyInstaller will not collect required packages again. But if you for example uninstall some packages using "pip uninstall" because you decide to not use it anymore in your project, the exe size will not decrease, as long previously collected dependencies will be still stored in your exe file. To execute collect step again just keep "--clean" argument.

That's all. auto-py-to-exe is not able to include required lines into spec file, as it hides generated spec file from users's eyes.

Produced exe file is standalone. There is no need to install Python or any Python package on end user PC to run such exe file.

Python interpreter with all dependencies are included into this exe. When exe is started all content is silently unpacked to temporary folder, and folder is removed when app is closed properly.

https://en.xdnf.cn/q/118402.html

Related Q&A

Pandas Panel is deprecated,

This code snippet is from one of my script which works fine in current panda version (0.23) but Panel is deprecated and will be removed in a future version.panel = pd.Panel(dict(df1=dataframe1,df2=data…

Python - Why is this data being written to file incorrectly?

Only the first result is being written to a csv, with one letter of the url per row. This is instead of all urls being written, one per row.What am I not doing right in the last section of this code t…

How does Python interpreter look for types? [duplicate]

This question already has answers here:How does Python interpreter work in dynamic typing?(3 answers)Closed 10 months ago.If I write something like:>>> a = float()how does Python interpreter …

title() method in python writing functions when word like arent

using functiondef make_cap(sentence):return sentence.title()tryining outmake_cap("hello world") Hello World# it workd but when I have world like "arent" and isnt". how to write…

Creating a C++ Qt Gui for a Python logic

I was presented with a Python logic for which I need to create a GUI. I want to use Qt for that purpose and ideally I would like to program it in C++, without using the Qt Creator.What are recommended …

Pythons BaseHTTPServer returns junky responses

I use Pythons BaseHTTPServer and implement the following very simple BaseHTTPRequestHandler:class WorkerHandler(BaseHTTPRequestHandler):def do_GET(self):self.wfile.write({"status" : "rea…

Why is matplotlib failing on import matplotlib.pyplot as plt

I installed matplotlib using conda:conda install matplotlibThe following code failed:#!/usr/bin/env python import matplotlib import matplotlib.pyplot as pltWith this error message:"ImportError: N…

Setting cell color of matplotlib table and save as a figure?

Im following this code a link! to save a table as the image, and I have some feature like check value in a cell then set color for a cell, but I added some code stylemap, it doesnt workimport pandas a…

Errno 111 Connection refused - Python Mininet API hosts client/server no connection?

I am new to Mininet and I am trying to find a way to use a script in python to execute a few tests using Mininet. More precisely I want to build topology and send a few xmlrpc request from one host t…

Finding the Corners of the an array of coordinates

I have a 2D array of Coordinates in Numpy.My goal is to attempt to find the corners (as if it were a square). So the :Top left: smallest x, highest y Top right: largest x, largest y bottom left: smalle…