Search code examples
pythonkivypyinstallerexe

Not able to add images and .kv file in exe file


When exe file of my app created by pyinstaller it is keep showing errors and now this is the last error i found

Traceback (most recent call last):
  File "TestAnalysis.py", line 1, in <module>
  File "<frozen importlib._bootstrap>", line 1027, in _find_and_load
  File "<frozen importlib._bootstrap>", line 1006, in _find_and_load_unlocked
  File "<frozen importlib._bootstrap>", line 688, in _load_unlocked
  File "PyInstaller\loader\pyimod02_importers.py", line 419, in exec_module
  File "kivy\__init__.py", line 319, in <module>
  File "<frozen importlib._bootstrap>", line 568, in module_from_spec
AttributeError: 'NoneType' object has no attribute 'loader'

I want to add all of the images and kivy file in exe file and it should be independent of any dependencies so that i can distribute

pyinstaller --onefile -w --add-data="thelab.kv:." --add-data="images (1).jpg:." --add-data="Screenshot (23).png:." --add-data="Screenshot (24).png:." --add-data="Screenshot (25).png:." --add-data="KivyAppData.db:." --add-data="AppIcon.ico:." --icon=AppIcon.ico --hidden-import plyer.platforms.win.filechooser --hidden-import kivy_deps.gstreamer --hidden-import kivy_deps.angle --hidden-import kivy.core.image.img_ffpyplayer --hidden-import kivy.core.text.text_pil TestAnalysis.py

This is the code i used for converting all files to exe file and all the files are in the same folder so absolute path should not be a probelem

from kivy.app import App
from kivy.lang import Builder
from kivy.uix.screenmanager import ScreenManager, Screen
from plyer import filechooser
import csv, sqlite3,random
from kivy.properties import StringProperty
from kivy.uix.gridlayout import GridLayout
from kivy.uix.button import Button
from kivy.uix.label import Label
import os, sys
from kivy.resources import resource_add_path

class StudentButton(Button): 
    pass
class MainScreen(Screen):
    s = []
    val = 0
    files = []  
    def file_chooser1(self):
        if App.get_running_app().s_0 == 'invalid input':
            App.get_running_app().s_0 = ''
        file = filechooser.open_file()
        self.files+=file
        App.get_running_app().s_0 += "".join(file).split("\\")[-1] + '\n'

    def Enter(self):
        App.get_running_app().review=""
        try:
            Student_Selection.getselfTL.clear_widgets()
        except:
            pass
        files=self.files
        Student_Selection.clear_widgets(self.val,children=None)
        try:
            if Student_Selection.student==[]:
                if files==[]:
                       App.get_running_app().s_0 ='invalid input'
                for file in files:
                    with open(file, "r") as opfile:
                        rows = csv.reader(opfile)
                        header = next(rows)
                        cnn = sqlite3.connect("KivyAppData.db")
                        cr = cnn.cursor() 
                        for data in rows:
                            Marks = file[:-4][-3:]
                            Name=""
                            splited_name=data[0].split()
                            for name in splited_name:
                                if name==splited_name[len(splited_name)-1]:
                                    Name+=""+name
                                else:
                                    Name+=name[0].upper()
                            if file == files[0]:
                                Student_Selection.student.append(Name)
                                cr.execute(f"drop table if exists {data[0]}")
                                cr.execute(f"create table {data[0]}{('Subjects', Marks)}")
                                column = [(header[number], data[number]) for number in range(1, len(data))]
                                cr.executemany(f'insert into {data[0]}("Subjects","{Marks}") values(?,?)',
column)
                            else:
                                cr.execute(f"alter table {data[0]} add {Marks}")
                                for number in range(1, len(data)):
                                    cr.execute(
                                        f"update {data[0]} set {Marks}=\'{data[number]}\' where Subjects=\'{header[number]}\'")
                        cnn.commit()
                        cnn.close()                     
            Student_Selection.studentfunc(self.val)
            if App.get_running_app().s_0 !='invalid input':
                App.get_running_app().sm.transition.direction='left'
                App.get_running_app().sm.current='tablescreen'
        except:
            App.get_running_app().s_0 ='invalid input'
        
class TableLabel(Label):
    pass

class TableScreen(Screen):
    def backfunc(self):
        App.get_running_app().s_0 = ''


class Student_Selection(GridLayout):
    student =  []
    getselfTL=0
    parent = None
    def __init__(self, **kwargs):
        super(Student_Selection, self).__init__(**kwargs)
        MainScreen.val = self
        self.cols = len(self.student)
        self.bind(minimum_height=self.setter('height'))

    def studentfunc(self):
        for i in self.student:
            self.add_widget(StudentButton(text=i, size_hint_y=None, height=35,on_release=self.Go_to_table))
    
    def Go_to_table(self,instance):
        Tablelayout.table(self.getselfTL, txt=instance.text)

class Tablelayout(GridLayout):
    def __init__(self, **kwargs,):
        super(Tablelayout, self).__init__(**kwargs)
        Student_Selection.parent = self
        Student_Selection.getselfTL=self
        self.bind(minimum_height=self.setter('height'))
    def table(self,txt):
        cnn = sqlite3.connect("KivyAppData.db")
        cr = cnn.cursor() 
        cr.execute(f"select * from {txt}")
        names=[d[0] for d in cr.description]
        self.cols=len(names) #2
        rows=list(cr.fetchall())
        self.rows=len(rows)+1 #6
        review_1=""
        subject=""
        try:
            self.clear_widgets()
        except:
            pass
        for header in names:
            self.add_widget(TableLabel(text=header))
        self.max_subject=""
        self.max_mark="0/1"
        self.min_subject=""
        self.min_mark="1000000/1"
        for row in rows:
            increase=0
            decrease=0
            constant=0
            subject=row[0]
            review_increase=[
            f"The student's performance in {subject} has improved.",
            f"{subject} performance is showing a positive trend.",
            f"In the subject of {subject}, the student's performance has risen.",
            f"{subject} performance is on the rise, exhibiting improvement.",
            f"The student has demonstrated improvement in {subject} performance.",
            f"{subject} proficiency has grown, showcasing enhancement.",
            f"A positive trend is evident in {subject} performance.",
            f"The student's mastery of {subject} has advanced.",
            f"{subject} scores have elevated, indicating improvement.",
            f"With a surge, the student has excelled in {subject} performance."
            ]
            review_decrease=[
            f"The student's performance in {subject} has declined.",
            f"{subject} performance is exhibiting a negative trend.",
            f"In the subject of {subject}, the student's performance has decreased.",
            f"{subject} performance is on the decline, showing a decrease.",
            f"The student's performance in {subject} has taken a downturn.",
            f"{subject} proficiency has decreased, indicating a decline.",
            f"A negative trend is evident in {subject} performance.",
            f"The student's mastery of {subject} has regressed.",
            f"{subject} scores have dropped, signaling a decrease.",
            f"With a decline, the student's performance in {subject} has weakened."
            ]
            review_constant=[
            f"The student's performance in {subject} remains consistent.",
            f"{subject} performance is stable, showing a consistent level of achievement.",
            f"In the subject of {subject}, the student's performance is steady.",
            f"{subject} performance has demonstrated a consistent level of proficiency.",
            f"The student has maintained a stable performance in {subject}.",
            f"{subject} proficiency is consistent, indicating a sustained level of achievement.",
            f"The student's performance in {subject} shows reliability and consistency.",
            f"{subject} scores have remained constant, reflecting a consistent performance.",
            f"With a consistent effort, the student excels in {subject} performance.",
            f"The subject of {subject} exhibits a consistently high level of performance."
            ]
            for index in range(len(row)):
                content=row[index]
                self.add_widget(TableLabel(text=content))
                if content!=subject:
                    object_1=int(content.split("/")[0])
                    if object_1>int(self.max_mark.split("/")[0]):
                        self.max_mark=content
                        self.max_subject=subject
                    if object_1<int(self.min_mark.split("/")[0]):
                        self.min_mark=content
                        self.min_subject=subject
                    if content!=row[len(row)-1]:
                        object_2=int(row[index+1].split("/")[0])
                        if object_2>object_1:
                            increase+=1
                        elif object_2<object_1:
                            decrease+=1
                        else:
                            constant+=1
            review_max= [ 
            f"The student has excelled to the maximum in {self.max_subject}.",
            f"In {self.max_subject}, the student has achieved the highest possible level of proficiency.",
            f"{self.max_subject} performance has reached the pinnacle with the student achieving the maximum.",
            f"The student has attained the maximum score in {self.max_subject}.",
            f"{self.max_subject} mastery is showcased as the student attains the maximum level of achievement.",
            f"In {self.max_subject}, the student's achievement has soared to the maximum.",
            f"The maximum level of proficiency in {self.max_subject} has been reached by the student.",
            f"{self.max_subject} scores reflect the student's attainment of the highest possible level.",
            f"The student has achieved the maximum in the subject of {self.max_subject}.",
            f"With outstanding performance, the student has reached the maximum in {self.max_subject}."
            ]
            review_min=[
            f"The student has scored the lowest in {self.min_subject}.",
            f"In {self.min_subject}, the student has attained the minimum level of proficiency.",
            f"{self.min_subject} performance has reached the lowest point with the student achieving the minimum.",
            f"The student has received the minimum score in {self.min_subject}.",
            f"{self.min_subject} mastery is at the lowest as the student attains the minimum level of achievement.",
            f"In {subject}, the student's achievement has fallen to the lowest.",
            f"The minimum level of proficiency in {self.min_subject} has been reached by the student.",
            f"{self.min_subject} scores reflect the student's attainment of the lowest possible level.",
            f"The student has achieved the lowest marks in the subject of {self.min_subject}.",
            f"With minimal performance, the student has reached the lowest in {self.min_subject}."
            ]
            if increase>decrease and increase>constant:
                review_1+=random.choice(review_increase)+" "
            elif decrease>increase and decrease>constant:
                review_1+=random.choice(review_decrease)+" "
            else:
                review_1+=random.choice(review_constant)+" " 
        review_1+=random.choice(review_max)+" "+random.choice(review_min) 
        App.get_running_app().review=review_1
        cnn.commit()
        cnn.close() 

class TestAnalysis(App):
    review=StringProperty("")
    s_0=StringProperty("")
    sm = ScreenManager()
    def build(self):
        self.icon="AppIcon.Ico"
        if getattr(sys, 'frozen', False):
            resource_add_path(sys._MEIPASS)
        Builder.load_file("thelab.kv")
        self.sm.add_widget(MainScreen(name="mainscreen"))
        self.sm.add_widget(TableScreen(name="tablescreen"))
        return self.sm

if __name__=="__main__":
    TestAnalysis().run()
#:import rgba kivy.utils.get_color_from_hex
<RoundedButton@Button>:
    background_color:(0,0,0,0)
    background_normal:''
    color:rgba('#fd6a02') if self.state =='normal' else rgba('ffffff')
    canvas.before:
        Color:  
            rgba:rgba('#fd6a02') 
        Line:
            rounded_rectangle:(self.pos[0],self.pos[1],self.size[0],self.size[1],15)
            width:1.2 
<StudentButton>:
    background_color:(0,0,0,0) if self.state=='normal' else (0,0,0,.3)
    background_normal:''

<RoundedButton1@Button>:
    background_color:(0,0,0,0)
    background_normal:''
    color:rgba('#ffffff')
    canvas.before:
        Color:  
            rgba:rgba('#fd6a02') if self.state =='normal' else rgba('0000ff')
        RoundedRectangle:
            size:self.size
            pos:self.pos
            radius:[15]

<TableLabel>:   
    size_hint:None,None
    width:140
    height:40

<MainScreen>:
    GridLayout:
        cols:2
        rows:1
        canvas.before:
            Rectangle:
                pos: self.pos
                size:self.size
                source: 'images (1).jpg'
        GridLayout:
            cols:2
            rows:1
            spacing:"5dp"
            size_hint:.5,1
            GridLayout:
                cols:1
                rows:3
                size_hint:None,1
                width:"400dp"
                spacing:10
                Label:
                    text:"Test\nAnalysis"
                    font_name:"Impact"
                    font_size:"100dp"
                    size_hint:1,.5
                GridLayout:
                    cols:2
                    rows:1
                    size_hint:1,.05
                    RoundedButton:
                        text:"Submit File"
                        size_hint:None,1
                        width:"100dp"
                        on_release:root.file_chooser1()
                    ScrollView:
                        size_hint:.7,1
                        canvas.before:
                            Color:
                                rgba:rgba('#80808080')
                            Rectangle:
                                size:self.size
                                pos:self.pos
                        Label:
                            text:app.s_0
                            font_name:"Georgia"
                            size_hint_y:None
                            height:self.texture_size[1]
                            text_size:self.width,None
                            color:rgba('#ffffff')
                            padding:[0,0,dp(100),0]
                AnchorLayout:
                    anchor_x:"center"
                    anchor_y:"top"
                    size_hint:1,.4
                    RoundedButton1:
                        text:"Enter"
                        size_hint_y:None
                        height:40
                        size_hint_x:None
                        width:150
                        on_release:root.Enter()
            ScrollView:
                size_hint:.5,1
                canvas.before:
                    Color:
                        rgba:(0,0,0,.7)
                    Rectangle:
                        size: self.size
                        pos: self.pos
                GridLayout:
                    cols:1
                    rows:7
                    do_scroll:True
                    size_hint:None,None
                    height:self.minimum_height
                    width:self.minimum_width
                    Label:
                        text:"The format of csv file must be like this:"
                        font_size:20
                        size_hint:None,None
                        size:self.texture_size
                    Image:
                        source:"Screenshot (23).png"
                        size_hint:None,None
                        size:400,400
                        allow_stretch:True
                    Label:
                        text:"Here s1,s2... are subjects and\nstudent0,student1... are name of student and\nmarks must be given in this format given marks/full marks"
                        font_size:20
                        size_hint:None,None
                        size:self.texture_size
                    Label:
                        text:"\nHere is sample input where two csv files are given\nuser is free to give any no. of files just press sumbit button that many times\nremember the last 3 letters of file is the name of examination"
                        font_size:20
                        size_hint:None,None
                        size:self.texture_size
                    Image:
                        source:"Screenshot (24).png"
                        size_hint:None,None
                        size:300,300
                        allow_stretch:True
                    Label:
                        text:"This is the ouput:"
                        font_size:20
                        size_hint:None,None
                        size:self.texture_size
                    Image:
                        source:"Screenshot (25).png"
                        size_hint:None,None
                        size:600,600
                        allow_stretch:True             
<TableScreen>:
    GridLayout:
        cols:1
        rows:2
        canvas.before:
            Rectangle:
                pos: self.pos
                size: self.size
                source: 'images (1).jpg'
        AnchorLayout:
            size_hint:1,.1
            anchor_x:"left"
            anchor_y:"top"
            RoundedButton:
                text:"Back"
                size_hint_y:None
                height:"40dp"
                size_hint_x:None
                width:"100dp"
                on_release:
                    root.backfunc()
                    root.manager.transition.direction='right'
                    root.manager.current='mainscreen'
        GridLayout:
            size_hint:1,.9
            cols:2
            rows:1
            spacing:3
            GridLayout:
                rows:2
                size_hint:.4,1
                Label:
                    text:"STUDENTS"
                    size_hint_y:.05
                    font_name:"Georgia"
                    color:rgba('#ffffff')
                    canvas.before:
                        Color:
                            rgba:(1,1,1,.1)
                        Rectangle:
                            size: self.size
                            pos: self.pos
                ScrollView:
                    size_hint:1,.7
                    canvas.before:
                        Color:
                            rgba:(1,1,1,.1)
                        Rectangle:
                            size:self.size
                            pos:self.pos
                    Student_Selection:
                        cols:1
                        size_hint_y:None
                        spacing:3
            GridLayout:
                cols:1
                rows:2
                ScrollView:
                    size_hint:1,.5
                    canvas.before:
                        Color:
                            rgba:(1,1,1,.1)
                        Rectangle:
                            size:self.size
                            pos:self.pos
                    Tablelayout:
                        size_hint:None,None
                        height:self.minimum_height
                        width:self.minimum_width
                ScrollView:
                    size_hint:1,.5
                    canvas.before:
                        Color:
                            rgba:(1,1,1,.1)
                        Rectangle:
                            size:self.size
                            pos:self.pos
                    Label:
                        text:app.review
                        font_name:"Georgia"
                        size_hint_y:None
                        height:self.texture_size[1]
                        text_size:self.width,None
                        color:rgba('#ffffff')
# -*- mode: python ; coding: utf-8 -*-


a = Analysis(
    ['TestAnalysis.py'],
    pathex=[],
    binaries=[],
    datas=[('thelab.kv', '.'), ('images (1).jpg', '.'), ('Screenshot (23).png', '.'), ('Screenshot (24).png', '.'), ('Screenshot (25).png', '.'), ('KivyAppData.db', '.'), ('AppIcon.ico', '.')],
    hiddenimports=['plyer.platforms.win.filechooser', 'kivy_deps.gstreamer', 'kivy_deps.angle', 'kivy.core.image.img_ffpyplayer', 'kivy.core.text.text_pil'],
    hookspath=[],
    hooksconfig={},
    runtime_hooks=[],
    excludes=[],
    noarchive=False,
)
pyz = PYZ(a.pure)

exe = EXE(
    pyz,
    a.scripts,
    a.binaries,
    a.datas,
    [],
    name='TestAnalysis',
    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,
    icon=['AppIcon.ico'],
)


Solution

  • Just added this code

    if __name__=="__main__":
        #from this line 
        if hasattr(sys, '_MEIPASS'): 
           resource_add_path(os.path.join(sys._MEIPASS))
        #to this
        TestAnalysis().run()
    

    and modified the pyinstaller code(just removed all the kivy related code) and removed gatattr condition block from build function in App class

    pyinstaller --onefile -w --add-data="thelab.kv:." --add-data="images (1).jpg:." --add-data="Screenshot (23).png:." --add-data="Screenshot (24).png:." --add-data="Screenshot (25).png:." --add-data="KivyAppData.db:." --add-data="AppIcon.ico:." --icon=AppIcon.ico --hidden-import plyer.platforms.win.filechooser TestAnalysis.py

    and then I am able to successfully convert files to one exe file I have not modified anything in spec file