.Kv file not found while compiling to single exe using pyinstaller

Viewed 243

i've coded a simple calculator app , here is my project files

enter image description here

it runs fine from the interpreter and also when i compiled it with pyInstaller to a directory ,

enter image description here

enter image description here

but when i compliled to a single file using pyinstaller --onefile -w --icon=icon.ico --add-data calc.kv;. main.py , it gets complied successfully , but when i run it , it gives me an error " kv file not found " .

enter image description here

here is my code

**MY Main Python File **

from kivy.app import App
from kivy.uix.widget import Widget
from kivy.properties import ObjectProperty
from kivy.lang import Builder 
from kivy.core.window import Window
import sys
import os 
Window.size = (450,600)

Builder.load_file("calc.kv")



class Root(Widget   ):
    def clear(self):
        self.ids.score.text = "0"
        self.ids.score.color = "000000"


    def button_press(self, button):
        prior = self.ids.score.text 
        if "Error" in prior:
            prior = ''
        elif prior == "0":
            self.ids.score.text = ''
            self.ids.score.text = f'{button}'
        else:
            self.ids.score.text = f'{prior}{button}'


    def add_sign(self):
        prior = self.ids.score.text
        if prior[-1] == "-" or prior[-1] == "+"  or prior[-1] == "/" or prior[-1] == "*":
            pass
        else:
            self.ids.score.text = f"{prior}+"



    def subtract_sign(self):
        prior = self.ids.score.text
        if prior[-1] == "-" or prior[-1] == "+"  or prior[-1] == "/" or prior[-1] == "*":
            pass
        else:
            self.ids.score.text = f"{prior}-"

    def multiply_sign(self):

        prior = self.ids.score.text
        if prior[-1] == "/" or prior[-1] == "+"  or prior[-1] == "-" or prior == "**" :
            pass
        elif "**"  in prior:
            pass
        else:
            self.ids.score.text = f"{prior}*"


    def divide_sign(self):
        prior = self.ids.score.text
        if prior[-1] == "-" or prior[-1] == "+"  or prior[-1] == "/" or prior[-1] == "*":
            pass
        else:
            self.ids.score.text = f"{prior}/"

    def dot(self):
        prior = self.ids.score.text
        num_list = prior.split("+")

        if "+" in prior and "." not in num_list[-1]:    
            prior = f'{prior}.'
            self.ids.score.text = prior         
        elif "." in prior:
            pass
        else:
            prior = f'{prior}.'
            self.ids.score.text = prior 



    def equals(self):

        try : 

            allowed = ["0","1","2","3","4","5","6","7","8","9","+","-","/","*","%","."]

            prior = self.ids.score.text
            prior = list(prior)
            for i in prior:
                if i not in allowed:
                    self.ids.score.text = "0"
                else:
                    answer = eval(self.ids.score.text)
                    self.ids.score.text = str(answer)
        except:
            self.ids.score.text = "Eroor"

    def remove(self):
        prior = self.ids.score.text
        prior = prior[:-1]
        self.ids.score.text = prior


    def pos_neg(self):
        prior = self.ids.score.text
        if "-" in prior[0]:
            self.ids.score.text = f'{prior.replace("-","")}'
        else:
            self.ids.score.text = f'-{prior}'
class Calculator(App):
    def build(self):
        self.icon = "icon.png"
        return Root()



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

**and here is my .kv file **

#: import  utils kivy.utils 
<Root>

    BoxLayout:
        orientation: "vertical"
        size: root.width,root.height

        TextInput:
            id: score
            text: "0"
            halign : "right"
            font_size: 65 
            size_hint: (1, .15)
            multiline: False
            
            
        GridLayout:
            size: root.width,root.height
            cols: 4
            rows: 5

            Button:
                size_hint: (0.2,0.2)
                font_size: 32
                text: "CE"
                color: utils.get_color_from_hex('000000')
                background_normal:''
                background_color: utils.get_color_from_hex('03fc84')
                on_press: root.clear()
            Button:
                id: clear
                size_hint: (0.2,0.2)
                font_size: 32
                text: "C"   
                color: utils.get_color_from_hex('000000')
                background_normal:''
                background_color: utils.get_color_from_hex('03fc84')
                on_press: root.clear()

            Button:
                
                size_hint: (0.2,0.2)
                font_size: 32
                text: u"\u00AB"
                color: utils.get_color_from_hex('000000')
                background_normal:''
                background_color: utils.get_color_from_hex('03fc84')
                on_press: root.remove()

            Button:
                size_hint: (0.2,0.2)
                font_size: 32
                text: "/"
                color: utils.get_color_from_hex('000000')
                background_normal:''
                background_color: utils.get_color_from_hex('03fc84')
                on_press: root.divide_sign()

            Button:
                size_hint: (0.2,0.2)
                font_size: 32
                text: "7"
                color: utils.get_color_from_hex('03fc84')
                background_normal:''
                background_color: utils.get_color_from_hex('000000')
                on_press: root.button_press(7)

            Button:
                size_hint: (0.2,0.2)
                font_size: 32
                text: "8"   
                color: utils.get_color_from_hex('03fc84')
                background_normal:''
                background_color: utils.get_color_from_hex('000000')
                on_press: root.button_press(8)

            Button:
                size_hint: (0.2,0.2)
                font_size: 32
                text: "9"
                color: utils.get_color_from_hex('03fc84')
                background_normal:''
                background_color: utils.get_color_from_hex('000000')
                on_press: root.button_press(9)

            Button:
                size_hint: (0.2,0.2)
                font_size: 32
                text: "X"
                color: utils.get_color_from_hex('000000')
                background_normal:''
                background_color: utils.get_color_from_hex('03fc84')
                on_press: root.multiply_sign()


            Button:
                size_hint: (0.2,0.2)
                font_size: 32
                text: "4"
                color: utils.get_color_from_hex('03fc84')
                background_normal:''
                background_color: utils.get_color_from_hex('000000')
                on_press: root.button_press(4)

            Button:
                size_hint: (0.2,0.2)
                font_size: 32
                text: "5"   
                color: utils.get_color_from_hex('03fc84')
                background_normal:''
                background_color: utils.get_color_from_hex('000000')                
                on_press: root.button_press(5)

            Button:
                size_hint: (0.2,0.2)
                font_size: 32
                text: "6"
                color: utils.get_color_from_hex('03fc84')
                background_normal:''
                background_color: utils.get_color_from_hex('000000')
                on_press: root.button_press(6)

            Button:
                size_hint: (0.2,0.2)
                font_size: 32
                text: "-"
                color: utils.get_color_from_hex('000000')
                background_normal:''
                background_color: utils.get_color_from_hex('03fc84')
                on_press: root.subtract_sign()


            Button:
                size_hint: (0.2,0.2)
                font_size: 32
                text: "1"
                color: utils.get_color_from_hex('03fc84')
                background_normal:''
                background_color: utils.get_color_from_hex('000000')
                on_press: root.button_press(1)

            Button:
                size_hint: (0.2,0.2)
                font_size: 32
                text: "2"   
                color: utils.get_color_from_hex('03fc84')
                background_normal:''
                background_color: utils.get_color_from_hex('000000')                
                on_press: root.button_press(2)

            Button:
                size_hint: (0.2,0.2)
                font_size: 32
                text: "3"
                color: utils.get_color_from_hex('03fc84')
                background_normal:''
                background_color: utils.get_color_from_hex('000000')
                on_press: root.button_press(3)

            Button:
                size_hint: (0.2,0.2)
                font_size: 32
                text: "+"
                color: utils.get_color_from_hex('000000')
                background_normal:''
                background_color: utils.get_color_from_hex('03fc84')
                on_press: root.add_sign()

            Button:
                size_hint: (0.2,0.2)
                font_size: 32
                text: "+/-"
                color: utils.get_color_from_hex('03fc84')
                background_normal:''
                background_color: utils.get_color_from_hex('000000')
                on_press: root.pos_neg()

            Button:
                size_hint: (0.2,0.2)
                font_size: 32
                text: "0"   
                color: utils.get_color_from_hex('03fc84')
                background_normal:''
                background_color: utils.get_color_from_hex('000000')
                on_press: root.button_press(0)
            Button:
                size_hint: (0.2,0.2)
                font_size: 32
                text: "."
                color: utils.get_color_from_hex('03fc84')
                background_normal:''
                background_color: utils.get_color_from_hex('000000')
                on_press: root.dot()

            Button:
                size_hint: (0.2,0.2)
                font_size: 32
                text: "="
                color: utils.get_color_from_hex('000000')
                background_normal:''
                background_color: utils.get_color_from_hex('03fc84')
                on_press: root.equals()


                

1 Answers

I believe you already read the official documentation, otherwise you wouldnt be able to go that far because when i tried to execute your code i was thrown off with an Error that no valid Window provider was found. However since i had some similar issues in the past i was curious. I think most of your problems are linked to the fact that your .kv file is named different than your App class. To solve the issue:

1. Match the .py and .kv names

Rename your main python file to calc.py and your main class inside from Calculator to CalcApp. Furthermore, comment or delte your line Builder.load_file("calc.kv").

2. Set up & activate a virtual environment

Generally it is a good idea to build projects based on a virtual environment to be clean and independent of other projects.

python -m venv venv  # to build
venv\Scripts\activate  # to activate

Next, install your dependencies.

pip install kivy pyinstaller

Optionally you can create a requirements.txt file to make it easier for others to catch up on your required dependencies via python -m pip freeze > requirements.txt

3. Build the project once

This is mainly to create a .spec template we can work with

python -m PyInstaller --onefile --add-data calc.kv;. calc.py

4. Modify the .spec file

We need to add the Window providers manually, as described in the official documentation mentioned above. Add the following to your .spec file:

from kivy_deps import sdl2_glew  # at the top
---
exe = EXE(pyz, Tree("."),  # scans the current folder
               a.scripts,
               a.binaries,
               a.zipfiles,
               a.datas,
               *[Tree(p) for p in (sdl2.dep_bins + glew.dep_bins)],  # adds paths for sdl2 and glew
               ..

5. Rebuild with .spec file

Before that, delete the existing build & dist folders - i just discovered that otherwise you might find yourself in an endless loop.

python -m PyiInstaller calc.spec

Thats it, you should have a single .exe file with no additional .kv files in that folder; Otherwise - you could just use your old strategy and copy the calc.kv by hand, which is less of a "blackbox". Here are also the slightly modified .py, .kv and .spec files:

calc.py

from kivy.app import App
from kivy.uix.widget import Widget
from kivy.properties import ObjectProperty
from kivy.lang import Builder 
from kivy.core.window import Window
import sys
import os 

# Builder.load_file("calc.kv")
Window.size = (450, 600)

class Root(Widget):
    def clear(self):
        self.ids.score.text = "0"
        self.ids.score.color = "000000"


    def button_press(self, button):
        prior = self.ids.score.text 
        if "Error" in prior:
            prior = ''
        elif prior == "0":
            self.ids.score.text = ''
            self.ids.score.text = f'{button}'
        else:
            self.ids.score.text = f'{prior}{button}'


    def add_sign(self):
        prior = self.ids.score.text
        if prior[-1] == "-" or prior[-1] == "+"  or prior[-1] == "/" or prior[-1] == "*":
            pass
        else:
            self.ids.score.text = f"{prior}+"



    def subtract_sign(self):
        prior = self.ids.score.text
        if prior[-1] == "-" or prior[-1] == "+"  or prior[-1] == "/" or prior[-1] == "*":
            pass
        else:
            self.ids.score.text = f"{prior}-"

    def multiply_sign(self):

        prior = self.ids.score.text
        if prior[-1] == "/" or prior[-1] == "+"  or prior[-1] == "-" or prior == "**" :
            pass
        elif "**"  in prior:
            pass
        else:
            self.ids.score.text = f"{prior}*"


    def divide_sign(self):
        prior = self.ids.score.text
        if prior[-1] == "-" or prior[-1] == "+"  or prior[-1] == "/" or prior[-1] == "*":
            pass
        else:
            self.ids.score.text = f"{prior}/"

    def dot(self):
        prior = self.ids.score.text
        num_list = prior.split("+")

        if "+" in prior and "." not in num_list[-1]:    
            prior = f'{prior}.'
            self.ids.score.text = prior         
        elif "." in prior:
            pass
        else:
            prior = f'{prior}.'
            self.ids.score.text = prior 



    def equals(self):

        try : 

            allowed = ["0","1","2","3","4","5","6","7","8","9","+","-","/","*","%","."]

            prior = self.ids.score.text
            prior = list(prior)
            for i in prior:
                if i not in allowed:
                    self.ids.score.text = "0"
                else:
                    answer = eval(self.ids.score.text)
                    self.ids.score.text = str(answer)
        except:
            self.ids.score.text = "Eroor"

    def remove(self):
        prior = self.ids.score.text
        prior = prior[:-1]
        self.ids.score.text = prior


    def pos_neg(self):
        prior = self.ids.score.text
        if "-" in prior[0]:
            self.ids.score.text = f'{prior.replace("-","")}'
        else:
            self.ids.score.text = f'-{prior}'

class CalcApp(App):
    def build(self):
        self.icon = "icon.png"
        return Root()



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

calc.kv

#: import  utils kivy.utils 
<Root>

    BoxLayout:
        orientation: "vertical"
        size: root.width,root.height

        TextInput:
            id: score
            text: "0"
            halign : "right"
            font_size: 65 
            size_hint: (1, .15)
            multiline: False
            
            
        GridLayout:
            size: root.width,root.height
            cols: 4
            rows: 5

            Button:
                size_hint: (0.2,0.2)
                font_size: 32
                text: "CE"
                color: utils.get_color_from_hex('000000')
                background_normal:''
                background_color: utils.get_color_from_hex('03fc84')
                on_press: root.clear()
            Button:
                id: clear
                size_hint: (0.2,0.2)
                font_size: 32
                text: "C"   
                color: utils.get_color_from_hex('000000')
                background_normal:''
                background_color: utils.get_color_from_hex('03fc84')
                on_press: root.clear()

            Button:
                
                size_hint: (0.2,0.2)
                font_size: 32
                text: u"\u00AB"
                color: utils.get_color_from_hex('000000')
                background_normal:''
                background_color: utils.get_color_from_hex('03fc84')
                on_press: root.remove()

            Button:
                size_hint: (0.2,0.2)
                font_size: 32
                text: "/"
                color: utils.get_color_from_hex('000000')
                background_normal:''
                background_color: utils.get_color_from_hex('03fc84')
                on_press: root.divide_sign()

            Button:
                size_hint: (0.2,0.2)
                font_size: 32
                text: "7"
                color: utils.get_color_from_hex('03fc84')
                background_normal:''
                background_color: utils.get_color_from_hex('000000')
                on_press: root.button_press(7)

            Button:
                size_hint: (0.2,0.2)
                font_size: 32
                text: "8"   
                color: utils.get_color_from_hex('03fc84')
                background_normal:''
                background_color: utils.get_color_from_hex('000000')
                on_press: root.button_press(8)

            Button:
                size_hint: (0.2,0.2)
                font_size: 32
                text: "9"
                color: utils.get_color_from_hex('03fc84')
                background_normal:''
                background_color: utils.get_color_from_hex('000000')
                on_press: root.button_press(9)

            Button:
                size_hint: (0.2,0.2)
                font_size: 32
                text: "X"
                color: utils.get_color_from_hex('000000')
                background_normal:''
                background_color: utils.get_color_from_hex('03fc84')
                on_press: root.multiply_sign()


            Button:
                size_hint: (0.2,0.2)
                font_size: 32
                text: "4"
                color: utils.get_color_from_hex('03fc84')
                background_normal:''
                background_color: utils.get_color_from_hex('000000')
                on_press: root.button_press(4)

            Button:
                size_hint: (0.2,0.2)
                font_size: 32
                text: "5"   
                color: utils.get_color_from_hex('03fc84')
                background_normal:''
                background_color: utils.get_color_from_hex('000000')                
                on_press: root.button_press(5)

            Button:
                size_hint: (0.2,0.2)
                font_size: 32
                text: "6"
                color: utils.get_color_from_hex('03fc84')
                background_normal:''
                background_color: utils.get_color_from_hex('000000')
                on_press: root.button_press(6)

            Button:
                size_hint: (0.2,0.2)
                font_size: 32
                text: "-"
                color: utils.get_color_from_hex('000000')
                background_normal:''
                background_color: utils.get_color_from_hex('03fc84')
                on_press: root.subtract_sign()


            Button:
                size_hint: (0.2,0.2)
                font_size: 32
                text: "1"
                color: utils.get_color_from_hex('03fc84')
                background_normal:''
                background_color: utils.get_color_from_hex('000000')
                on_press: root.button_press(1)

            Button:
                size_hint: (0.2,0.2)
                font_size: 32
                text: "2"   
                color: utils.get_color_from_hex('03fc84')
                background_normal:''
                background_color: utils.get_color_from_hex('000000')                
                on_press: root.button_press(2)

            Button:
                size_hint: (0.2,0.2)
                font_size: 32
                text: "3"
                color: utils.get_color_from_hex('03fc84')
                background_normal:''
                background_color: utils.get_color_from_hex('000000')
                on_press: root.button_press(3)

            Button:
                size_hint: (0.2,0.2)
                font_size: 32
                text: "+"
                color: utils.get_color_from_hex('000000')
                background_normal:''
                background_color: utils.get_color_from_hex('03fc84')
                on_press: root.add_sign()

            Button:
                size_hint: (0.2,0.2)
                font_size: 32
                text: "+/-"
                color: utils.get_color_from_hex('03fc84')
                background_normal:''
                background_color: utils.get_color_from_hex('000000')
                on_press: root.pos_neg()

            Button:
                size_hint: (0.2,0.2)
                font_size: 32
                text: "0"   
                color: utils.get_color_from_hex('03fc84')
                background_normal:''
                background_color: utils.get_color_from_hex('000000')
                on_press: root.button_press(0)
            Button:
                size_hint: (0.2,0.2)
                font_size: 32
                text: "."
                color: utils.get_color_from_hex('03fc84')
                background_normal:''
                background_color: utils.get_color_from_hex('000000')
                on_press: root.dot()

            Button:
                size_hint: (0.2,0.2)
                font_size: 32
                text: "="
                color: utils.get_color_from_hex('000000')
                background_normal:''
                background_color: utils.get_color_from_hex('03fc84')
                on_press: root.equals()

calc.spec

# -*- mode: python ; coding: utf-8 -*-
from kivy_deps import sdl2, glew

block_cipher = None


a = Analysis(['calc.py'],
             pathex=[],
             binaries=[],
             datas=[('calc.kv', '.')],
             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, Tree("."),
          a.scripts,
          a.binaries,
          a.zipfiles,
          a.datas, 
          *[Tree(p) for p in (sdl2.dep_bins + glew.dep_bins)], 
          [],
          name='calc',
          debug=False,
          bootloader_ignore_signals=False,
          strip=False,
          upx=True,
          upx_exclude=[],
          runtime_tmpdir=None,
          console=True,
          disable_windowed_traceback=False,
          target_arch=None,
          codesign_identity=None,
          entitlements_file=None )
Related