How to run kivy and flask apps together?

前端 未结 2 1241
北恋
北恋 2021-01-14 07:48

I have a flask app serving as a server and I have a kivy app serving as a front end to a server. How can I run flask and then kivy app so they work together at the same time

相关标签:
2条回答
  • 2021-01-14 08:15

    I wanted Flask to run continuously. I tried the proposed solution to run them together as threads as suggested by @amanb. I found out Flask is blocking Kivy and vice versa no matter the timing or how arranged are the threads. The reason being the interpreter's GIL. Therefore I tried with processes and it seems it does the work.

    CODE

    #!/usr/bin/python2.7 python2.7
    # -*- coding: utf-8 -*-
    
    # kivy modules first, if not Kivy may cause problems
    import kivy
    from kivy.app import App
    from kivy.lang import Builder
    from kivy.uix.label import Label
    from kivy.uix.floatlayout import FloatLayout
    from kivy.uix.screenmanager import ScreenManager, Screen
    kivy.require('1.10.0')
    
    
    # common modules
    import sys
    import signal
    from multiprocessing import Process
    
    
    # Flask & similar modules
    from flask import Flask
    from flask_restful import reqparse, abort, Api, Resource
    import eventlet
    from eventlet import wsgi
    
    
    # async server setup
    app = Flask(__name__)
    api = Api(app)
    
    
    def start_Flask():
        print("Starting server...")
        # start an eventlet WSGI server on port 5000
        wsgi.server(eventlet.listen(('', 5000)), app)     
    
    
    def signal_handler(signal, frame):
        # for fetching CTRL+C and relatives
        print " CTRL + C detected, exiting ... "
        exit(1)
    
    
    # Kivy screen class
    class MainScreen(Screen):
        def __init__(self, **kwargs):
            self.name="MAIN SCREEN"
            super(Screen, self).__init__(**kwargs)
    
    
    # Kivy app class
    class Kivy(App):
        w_MessageBox10_1 = "MAIN SCREEN"
        w_MessageBox10_2 = "One golden glance of what should be"
        w_MessageBox30_2 = "CHORUS"
        w_MessageBox30_3 = "EXIT"
    
    
        # exit button action   
        def exit(self):
            print "exiting... one shaft of light will show the way..."
            p1.terminate()  # terminate Flask by pressing on cancel
            exit(1)
    
    
        # do magic button action
        def do_magic(self):
            # your code goes here or maybe not
            print "***** it's a kind of magic *************************"
    
    
        # Kivy UI builder file
        def build(self):
            sm = Builder.load_string("""
    
    ScreenManager
        MainScreen:
            size_hint: 1, .7
            auto_dismiss: False
            title: app.w_MessageBox10_1       
            title_align: "center"
    
            BoxLayout:
                orientation: "vertical"
                Label:
                    text: app.w_MessageBox10_2
                BoxLayout:
                    orientation: "horizontal"
                    spacing: 10
                    size_hint: 1, .5
                    Button:
                        text: app.w_MessageBox30_2  # DO MAGIC
                        on_press:
                            app.do_magic()
                    Button:
                        text: app.w_MessageBox30_3  # EXIT
                        on_press:
                            app.exit()
    
    
            """)
    
            return sm
    
    
    if __name__ == '__main__':    
    
        # #CTRL+C signal handler
        signal.signal(signal.SIGINT, signal_handler)
        signal.signal(signal.SIGTERM, signal_handler)
    
        global p1
        p1 = Process(target=start_Flask)    # assign Flask to a process
        p1.start()                          # run Flask as process
        Kivy().run()                        # run Kivy UI
    

    UPDATE To run Flask on demand by pressing a button in Kivy I use the script below.

    #!/usr/bin/python2.7 python2.7
    # -*- coding: utf-8 -*-
    
    # kivy modules first, if not Kivy may cause problems
    import kivy
    from kivy.app import App
    from kivy.lang import Builder
    from kivy.uix.label import Label
    from kivy.uix.floatlayout import FloatLayout
    from kivy.uix.screenmanager import ScreenManager, Screen
    kivy.require('1.10.0')
    
    # common modules
    import sys
    import os
    import time
    import signal
    from multiprocessing import Process
    
    # Flask modules
    from flask import Flask
    
    # wsgi (Web Server Gateway Interface) modules
    import eventlet
    from eventlet import wsgi
    
    # async server setup
    app = Flask(__name__)
    
    def signal_handler(signal, frame):
        print " CTRL + C detected, exiting ... "
        exit(0)
    
    
    # kivy gui classes ######################################################     
    class MainScreen(Screen):
        def __init__(self, **kwargs):
            self.name="MAIN SCREEN"
            super(Screen, self).__init__(**kwargs)
    
    class MainApp(App):
        MainScreenTitle = "MainScreen title"
        MainScreenLabel = "MainScreen label"
        MessageButtonEnter = "START"
        MessageButtonExit = "EXIT"
    
        def start_Flask(self):
            print("Starting Flask...")
            wsgi.server(eventlet.listen(('', 5000)), app)     # deploy as an eventlet WSGI server
    
        def stop(self):
            print "terminating Flask and exiting..."
            global p1
            p1.terminate()
            exit(1)
    
        def start(self):
            print "starting Flask as process..."
            global p1
            p1 = Process(target=self.start_Flask) # assign Flask to a process
            p1.daemon = True
            p1.start()  #launch Flask as separate process
    
        def build(self):
            sm = Builder.load_string("""
    
    ScreenManager
        MainScreen:
            size_hint: 1, .7
            auto_dismiss: False
            title: app.MainScreenTitle       
            title_align: "center"
    
            BoxLayout:
                orientation: "vertical"
                Label:
                    text: app.MainScreenLabel
                BoxLayout:
                    orientation: "horizontal"
                    spacing: 10
                    size_hint: 1, .5
                    Button:
                        text: app.MessageButtonEnter  # start app
                        on_press:
                            app.start()
                    Button:
                        text: app.MessageButtonExit  # exit app
                        on_press:
                            app.stop()
    
            """)
    
            return sm
    
    
    # main ################################################
    if __name__ == '__main__':
    
        #CTRL+C signal handler
        signal.signal(signal.SIGINT, signal_handler)
        signal.signal(signal.SIGTERM, signal_handler)
    
        MainApp().run()   # run Kivy app
    
    0 讨论(0)
  • 2021-01-14 08:21

    The development server in Flask is part of Werkzeug. It should only be used for development purposes as it cannot accommodate high loads as in production deployments. I suggest that you set-up an Apache server with mod_wsgi to run both apps together. This will also provide isolation & parallelism at the same time and is ideal for development,testing and production deployments.

    A solution with threading works but with a caveat: The Werkzeug server can run in a separate thread but the app reloader expects to run in the main thread. This means that your Flask app will not reload when you make any changes to the app. Take a look at this answer.

    The below code uses two separate threads to run each app. A 'Hello World' window appears for the Kivy app and at the same time it is possible to display a 'Hello World' message in the browser when the Flask app is run on http://localhost:5000/.

    import threading
    import kivy
    from kivy.app import App
    from flask import Flask
    import os
    from kivy.uix.label import Label
    
    kivy.require('1.10.0')
    new_environ = os.environ.copy()
    
    app = Flask(__name__)
    
    @app.route('/')
    def hello():
        return 'Hello World'
    def start_app():
        print("Starting Flask app...")
        app.run(port=5000, debug=False)     #specify separate port to run Flask app
    
    class MyApp(App):
    
        def build(self):
            return Label(text='Hello world')
    
    if __name__ == '__main__':
        if os.environ.get("WERKZEUG_RUN_MAIN") != 'true':
            threading.Thread(target=start_app).start()
        MyApp().run()
    
    0 讨论(0)
提交回复
热议问题