Search code examples
pythonpython-3.xkivyexecexecv

How to restart kivy app after updating (exit old version & execute new version)


How can I have a kivy app restart after downloading a new version of itself?

I'm developing a python GUI app that uses the kivy framework, I just added an auto-update feature to my app that securely downloads, verifies, and extracts a newer version of itself. After these upgrade steps are complete, I present the user with a modal dialog asking them to click a button to restart the app to the newer version.

How can I get that button to actually close the window and execute the new kivy app?


Solution

  • In python, you can use os.execv() to exit the current process and replace it with another execution.

    The following commands demonstrate how to do this with kivy in Debian 10:

    sudo apt-get -y install python3 python3-pip python3-virtualenv python3-setuptools
    sudo dpkg -l | grep python
    
    python3 -m virtualenv --python=python3.7 /tmp/virtualenv/kivy_test
    /tmp/virtualenv/kivy_test/bin/python3 -m pip install --upgrade pip kivy
    /tmp/virtualenv/kivy_test/bin/python3 -m pip list
    source /tmp/virtualenv/kivy_test/bin/activate
    
    tmpDir=`mktemp -d`
    pushd "${tmpDir}"
    
    cat << EOF > helloWorldOne.py
    #!/usr/bin/env python3
    import kivy, os
    from kivy.app import App
    from kivy.uix.label import Label
    from kivy.clock import Clock
    
    class MyApp(App):
        def build(self):
            Clock.schedule_once( self.restart, 1 )
            return Label(text='Hello World One!')
    
        def restart(self, dt):
            os.execv( 'helloWorldTwo.py', ['helloWorldTwo.py'] )
    
    if __name__ == '__main__':
        MyApp().run()
    EOF
    
    cat << EOF > helloWorldTwo.py
    #!/usr/bin/env python3
    import kivy, os
    from kivy.app import App
    from kivy.uix.label import Label
    from kivy.clock import Clock
    
    class MyApp(App):
        def build(self):
            return Label(text='Hello World Two!')
    
    if __name__ == '__main__':
        MyApp().run()
    EOF
    
    chmod +x helloWorld*.py
    ./helloWorldOne.py
    
    popd
    

    When ./helloWorldOne.py is executed above, a window (the "old version") appears. After a 1 second delay, the restart() function is executed (which instead could be bound to a button)--which calls os.execv().

    The helloWorldOne.py app window is closed and replaced with the helloWorldTwo.py app window.