I have been fighting PyInstaller for the past week trying to get my application to compile into a single executable.
I've tried several different implementations with the .spec file, and of the many methods I try, I can either get it to compile into a single executable that crashes immediately on launch, doesn't launch at all, or it runs, but is extremely slow. Nothing compared to that of when I run it out of PyCharm.
I'm unsure if the slow run speeds is because of the compiler or what, but it takes roughly 1-2 seconds for the execution task to run when I run it through PyCharm, however when it is ran from the executable it takes about 30-35 seconds and the application hangs.
My application essentially takes some text from TextInput boxes, grabs the text values from them, does some SQL querying and then submits proper information to update / add entry information into an access database.
My latest .spec file is as follows:
# -*- mode: python -*-
import pyodbc
from datetime import date
from kivy.app import App
from kivy.uix.button import Button
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.label import Label
from kivy.uix.popup import Popup
from kivy.uix.textinput import TextInput
from kivy.lang import Builder
from kivy.properties import BooleanProperty, ObjectProperty
from kivy.deps import sdl2, glew
block_cipher = None
a = Analysis(['DBInterfaceAssistant.py'],
pathex=['C:\\Python36-32'],
binaries=[],
datas=[],
hookspath=[],
runtime_hooks=[],
excludes=[],
win_no_prefer_redirects=False,
win_private_assemblies=False,
cipher=block_cipher)
pyz = PYZ(a.pure, a.zipped_data,
cipher=block_cipher)
exe = EXE(pyz,
a.scripts,
a.binaries,
a.zipfiles,
a.datas,
name='DBInterfaceAssistant',
debug=False,
strip=False,
upx=True,
runtime_tmpdir=None,
console=False )
The product of this is an application that doesn't launch, it attempts to load the application but crashes immediately.
---EDIT---
My Current build script is as follows:
# -*- mode: python -*-
import pyodbc
from datetime import date
from kivy.app import App
from kivy.uix.button import Button
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.label import Label
from kivy.uix.popup import Popup
from kivy.uix.textinput import TextInput
from kivy.lang import Builder
from kivy.properties import BooleanProperty, ObjectProperty
from kivy.deps import sdl2, glew
from kivy.tools.packaging.pyinstaller_hooks import get_deps_minimal, get_deps_all, hookspath, runtime_hooks
block_cipher = None
a = Analysis(['DBInterfaceAssistant.py'],
pathex=['C:\\Python36-32'],
binaries=[],
datas=[],
hookspath=hookspath(),
runtime_hooks=runtime_hooks(),
** get_deps_all())
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)],
name='DBInterfaceAssistant',
debug=False,
strip=False,
upx=True,
runtime_tmpdir=None,
console=False )
You may use the example from the Kivy docs:
from kivy.tools.packaging.pyinstaller_hooks import get_deps_minimal, get_deps_all, hookspath, runtime_hooks
a = Analysis(['examples-path\\demo\\touchtracer\\main.py'],
...
hookspath=hookspath(),
runtime_hooks=runtime_hooks(),
...
**get_deps_all())
coll = COLLECT(exe, Tree('examples-path\\demo\\touchtracer\\'),
a.binaries,
a.zipfiles,
a.datas,
*[Tree(p) for p in (sdl2.dep_bins + glew.dep_bins)],
strip=False,
upx=True,
name='touchtracer')
https://kivy.org/docs/guide/packaging-windows.html#overwrite-win-hook
Related
I'm trying to generating a .exe of my kivymd code. I have coded a really simple code, because i was trying to learn how to do this.
My code is as follows:
from kivymd.app import MDApp
from kivymd.uix.label import MDLabel
from kivymd.uix.screen import Screen
class Demo(MDApp):
def build(self):
self.screen = Screen()
self.l1 = MDLabel(
text = "My Label"
)
self.screen.add_widget(self.l1)
return self.screen
if __name__ == "__main__":
Demo().run()
Really simple.
So i'm using a .spec like this:
# -*- mode: python ; coding: utf-8 -*-
import os
from kivy_deps import sdl2, glew
block_cipher = None
from kivymd import hooks_path as kivymd_hooks_path
current_path = os.path.abspath('.')
icon_path = os.path.join(current_path, 'imagens', 'icone.ico')
a = Analysis(['main.py'],
pathex=[current_path],
binaries=[],
datas=[],
hiddenimports=[],
hookspath=[kivymd_hooks_path],
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)],
name='Eaton',
debug=False,
bootloader_ignore_signals=False,
strip=False,
upx=True,
upx_exclude=[],
runtime_tmpdir=None,
icon=icon_path,
console=False )
My code file name is main.py and my .spec is main.spec.
So my problem is, when I use the console=True, this code and .spec works fine and create a good .exe, but when I use console=False the aplication returns error.
If someone can help me I will be very thankful.
The problem I have is that after build the exe of an kivy app, when I try to get the main path of the main.py file which is c:..../desktop/statistic/dist/salida/salida.exe, the path python is printing in the function I use to check is c:..../desktop/statistic/dis.
The code I use to get the path of the main file is this:
application_path = os.path.dirname(os.path.abspath(__file__))
If I create an script in that folder and use this code it prints the correct path, dont understand why it changes after make the exe.
The spec file I'm using for the exe if needed:
# -*- mode: python ; coding: utf-8 -*-
from kivy.app import App
from kivy.uix.boxlayout import BoxLayout
from kivy.properties import ListProperty, StringProperty
from kivy.uix.button import Button
from kivy.uix.actionbar import ActionBar
from kivy.uix.label import Label
from kivy.uix.screenmanager import ScreenManager, Screen
from kivy.lang import Builder
from kivy.uix.checkbox import CheckBox
from kivy.uix.gridlayout import GridLayout
from kivy.uix.recycleview import RecycleView
from kivy.uix.stacklayout import StackLayout
from kivy.uix.filechooser import FileChooser
from kivy.uix.anchorlayout import AnchorLayout
from kivy.uix.popup import Popup
from kivy.uix.floatlayout import FloatLayout
from kivy.properties import ObjectProperty, StringProperty, BooleanProperty
from kivy.clock import Clock, mainthread
from kivy.uix.scrollview import ScrollView
from kivy_deps import sdl2, glew
import numpy as np
import pandas as pd
import threading
import os
import sys
import pkg_resources.py2_warn
import pkg_resources
block_cipher = None
a = Analysis(['C:\\Users\\adm\\Desktop\\StatisticAnalisis - copia\\main.py'],
pathex=['C:\\Users\\adm\\Desktop\\statistic'],
binaries=[],
datas=[],
hiddenimports=['pkg_resources.py2_warn','win32timezone'],
hookspath=[],
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,
[],
exclude_binaries=True,
name='salida',
debug=False,
bootloader_ignore_signals=False,
strip=False,
upx=True,
console=True )
coll = COLLECT(exe,Tree('C:\\Users\\adm\\Desktop\\StatisticAnalisis - copia'),
a.binaries,
a.zipfiles,
a.datas,
*[Tree(p) for p in (sdl2.dep_bins + glew.dep_bins)],
strip=False,
upx=True,
upx_exclude=[],
name='salida')
I am trying unsuccessfully to wrap up my kivy GUI application into a single executable with pyinstaller. Whey I run PyInstaller, it creates a single executable, but when I run it I get a "fatal error" saying "Failed to execute script myApp". I am using python 2.7 on windows. Here is my directory setup:
GUI_DEV\
-myApp_style.kv (this is my kivy file)
-myApp.py (this is my main script)
-ico.ico (this is my icon file)
-myImage.png (this is an image used by myApp.py)
rel\
-myApp.spec (this is the spec file I am using with pyinstaller)
Here is my myApp.py code:
import kivy
#kivy.require("1.9.0")
from kivy.core.window import Window
from kivy.app import App
from kivy.uix.gridlayout import GridLayout
from kivy.properties import ObjectProperty
from kivy.lang import Builder
import sys, os
def resourcePath():
if hasattr(sys, '_MEIPASS'):
return os.path.join(sys._MEIPASS)
return os.path.join(os.path.abspath("."))
Builder.load_file('myApp.kv')
class designerLayout(GridLayout):
part = "123"
def update(self):
self.part = value
self.id_test.text = "hello world: "+str(self.part)
return
def spinner_clicked(self, value):
self.part = value
self.id_test.text = "hello world: "+str(self.part)
class myApp(App):
def build(self):
Window.clearcolor = (1,1,1,1)
Window.size = (930,780)
return designerLayout()
if __name__ == '__main__':
kivy.resources.resource_add_path(resourcePath()) # add this line
calcApp = myApp()
calcApp = myApp()
calcApp.run()
Here is my myApp.spec file:
# -*- mode: python -*-
from kivy.deps import sdl2, glew
block_cipher = None
a = Analysis(['..\\myApp.py'],
pathex=['C:\\GUI_DEV\\rel\\MyHiddenImports'],
binaries=None,
datas=None,
hiddenimports=['MyHiddenImports'],
hookspath=[],
runtime_hooks=[],
excludes=[],
win_no_prefer_redirects=False,
win_private_assemblies=False,
cipher=block_cipher)
pyz = PYZ(a.pure, a.zipped_data,
cipher=block_cipher)
a.datas += [('myApp_style.kv', '../myApp_style.kv', 'DATA')]
exe = EXE(pyz, Tree('C:\\GUI_DEV\\','Data'),
a.scripts,
a.binaries,
a.zipfiles,
a.datas,
*[Tree(p) for p in (sdl2.dep_bins + glew.dep_bins)],
name='myApp',
debug=False,
strip=False,
upx=True,
console=False, icon='C:\\GUI_DEV\\ico.ico' )
I am then running the command:
python -m PyInstaller myApp.spec
from the GUI_DEV\rel directory.
Any ideas as to why this is not working? I am not getting any errors that point me to any specific problems.
I have been trying to package a Kivy app which runs perfectly from the .py file. I use the PyInstaller module to create the .exe file. The .exe file is created but it fails to open.
I have tried all I can, and I have gone through the Kivy documentation https://kivy.org/docs/guide/packaging-windows.html# .
I noticed that the .exe file worked when it is only kivy modules that are imported but wouldn't work when other libraries such as pandas are imported.
Any help would be appreciated.
from kivy.app import App
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.button import Button
from tkinter.filedialog import askopenfilename
from kivy.lang import Builder
from kivy.uix.label import Label
from kivy.config import Config
import pandas as pd
import sqlite3
from kivy.properties import StringProperty
Config.set('graphics', 'resizable', '0')
Config.set('graphics', 'width', '800')
Config.set('graphics', 'height', '450')
def databasesetup(sharepoint,exchange,onedrivefaculty,onedrivestudent):
def sharepoint(filename):
def exchangecleanup(file):
def OD4Bclean(filename):
class Container(BoxLayout):
Message = StringProperty()
def Selectfile(self):
def Selectfilecsv(self):
def Cleandata(self):
""" This function cleans all the uploaded files and returns the cleaned dataframes """
def CreateDatabase(self):
def downloadfiles(self):
class MainApp(App):
def build(self):
self.title = 'Technology Support App for Office 365 adoption'
return Container()
if __name__ == "__main__":
app = MainApp()
app.run()
the .spec file
from kivy.deps import sdl2, glew
# -*- mode: python -*-
block_cipher = None
a = Analysis(['main.py'],
pathex=['D:\\Users\\bodea\\Documents\\desktop kivy app\\main'],
binaries=[],
datas=[],
hiddenimports=[],
hookspath=[],
runtime_hooks=[],
excludes=[],
win_no_prefer_redirects=False,
win_private_assemblies=False,
cipher=block_cipher)
pyz = PYZ(a.pure, a.zipped_data,
cipher=block_cipher)
exe = EXE(pyz,
a.scripts,
exclude_binaries=True,
name='main',
debug=False,
strip=False,
upx=True,
console=True )
coll = COLLECT(exe,Tree('D:\\Users\\bodea\\Documents\\desktop kivy app\\main'),
a.binaries,
a.zipfiles,
a.datas,*[Tree(p) for p in (sdl2.dep_bins + glew.dep_bins)],
strip=False,
upx=True,
name='main')
"main.py"
from kivy.app import App
class WeatherApp(App):
pass
if __name__="__main__":
WeatherApp().run()
"weather.kv"
Label:
text: "hello world"
i am expecting a window with a black background and the words "hello world"
in the middle
For me I managed to solve
Editing the spec file like so:
# -*- mode: python ; coding: utf-8 -*-
from kivy_deps import sdl2, glew
block_cipher = None
a = Analysis(['hello.py'],
pathex=['C:\\Users\\<username>\\PycharmProjects\\<project_dir>'],
binaries=[],
datas=[],
hiddenimports=[],
hookspath=[],
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,
[],
exclude_binaries=True,
name='hello',
debug=False,
bootloader_ignore_signals=False,
strip=False,
upx=True,
console=True )
coll = COLLECT(exe,
Tree('C:\\Users\\<username>\\PycharmProjects\\<project_dir>'),
a.binaries,
a.zipfiles,
a.datas,
*[Tree(p) for p in (sdl2.dep_bins + glew.dep_bins)],
strip=False,
upx=True,
upx_exclude=[],
name='hello')
by copying the kivymd dir C:\Users<username>\Anaconda3\envs<project_name>\Lib\site-packages\kivymd to your dist folder
Roboto-Regular.ttfs Not Found - Windows 8.1
Currently, in the Kivy config file, the default fonts used for widgets displaying any text defaults to [‘Roboto’, ‘data/fonts/Roboto-Regular.ttf’, ‘data/fonts/Roboto-Italic.ttf’, ‘data/fonts/Roboto-Bold.ttf’, ‘data/fonts/Roboto-BoldItalic.ttf’].
The latest version of Roboto can be found at https://github.com/google/roboto/releases
There is a typo error and indentation problem in your app. After fixing the problems, your app should works as shown in the example below.
Replace:
if __name__="__main__":
with:
if __name__ == "__main__":
Example
main.py
from kivy.app import App
class WeatherApp(App):
pass
if __name__ == "__main__":
WeatherApp().run()
weather.kv
#:kivy 1.10.0
Label:
text: "hello world"
Output