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?
Flask app:
from flask import Flask
app = Flask(__name__)
#app.route('/')
def hello():
return 'Hello'
if __name__ == "__main__":
app.run()
Kivy app:
from kivy.app import App
from kivy.builder import Builder
from kivy.uix.screenmanager import Screen, ScreenManager
kivy.require('1.10.0')
Builder.load_file('kivy.kv')
sm = ScreenManager()
class MainScreen(Screen)
pass
class OtherScreen(Screen)
pass
sm.add_widget(MainScreen(name='main'))
sm.add_widget(OtherScreen(name='other'))
class MyApp(App):
def build(self):
return sm
MyApp().run()
Update:
If someone is having problems implementing a webserver with apache, try docker, simpler and faster solution, in my opinion!
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
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()
Related
I'm working in simple kivy app for android that play sound every minute, i want to make it work in background even when I close app
from kivy.app import App
from kivy.uix.button import Button
from kivy.core.audio import SoundLoader
import time
class MyApp(App):
def build(self):
self.sound = SoundLoader.load('1.wav')
start_but = Button(text='start',
on_press = self.click
)
return start_but
def click(self, obj):
while True:
self.sound.play()
time.sleep(60)
if __name__ == '__main__':
MyApp().run()
I'm trying to create a small GUI with kivy. by clicking on the button named button it should launch the popup on another thread with a progress bar that evolves after 3 seconds. But kivy gives me an error saying "Cannot create graphics instruction outside the main Kivy thread"
how to solve this problem?
from kivy.app import App
from kivy.uix.label import Label
from kivy.uix.progressbar import ProgressBar
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.button import Button
from kivy.uix.popup import Popup
from kivy.lang import Builder
import time
import threading
Builder.load_string("""
<Interface>:
orientation: 'vertical'
Label:
text: "Test"
BoxLayout:
orientation: 'vertical'
Label
text: "phone Number"
TextInput:
id: variable
hint_text: ""
Thebutton:
user_input: variable.text
text: "Buttion"
on_release: self.do_action()
""")
class Interface(BoxLayout):
pass
class Thebutton(Button):
def bar_de_progress(self):
bdp = ProgressBar()
poo = Popup(title="Brute Forcing ...", content=bdp, size_hint=(0.5, 0.2))
poo.open()
time.sleep(1)
bdp.value = 25
def do_action(self, *args):
threading.Thread(target=self.bar_de_progress).start()
return
class MyApp(App, Thebutton):
def build(self):
return Interface()
if __name__ == "__main__":
MyApp().run()
Im a bit late but i just solve the same problem by changing the 2.1.0 kivy version to the 2.0.0 version.
I cannot replicate your error, but the general rule is don't do GUI operations on threads other than the main thread. Here is a modified version of your Thebutton class that does that:
class Thebutton(Button):
def bar_de_progress(self):
# this is run on the main thread
self.bdp = ProgressBar()
poo = Popup(title="Brute Forcing ...", content=self.bdp, size_hint=(0.5, 0.2))
poo.open()
threading.Thread(target=self.update_progress).start()
def update_progress(self):
# this is run on another thread
time.sleep(1)
self.bdp.value = 25
def do_action(self, *args):
self.bar_de_progress()
In a part of an app I am developing, I would like to able the user view the logger that python & kivy output to see any sort of warnings or issues that may have been caused.
I searched this and there way only one stackoverflow issue regarding this: so issue on redirecting python logging onto a kivy label
I tried the exact same code (the one checked as an answer) but all I got was a label that said WOO % and a timer as its last character.
I had an idea which was to access the log record that kivy writes to but practically it won't work because for how long should I access the file? Should I create a while True: read_file() loop and put it in another thread and run it forever? Ultimately, it was not a good ides.
If this is my code:
from kivy.lang import Builder
from kivy.app import App
class MainApp(App):
def __init__(self, **kwargs):
super(MainApp, self).__init__(**kwargs)
self.kv = Builder.load_string('''
#:kivy 2.0.0
TextInput:
# redirect (preferably copy) logger text here
id: logger_text
readonly: True
''')
def build(self):
return self.kv
if __name__ == '__main__':
MainApp().run()
How can I redirect (but preferably copy) this logger onto my text input?
You can use the concepts from the so question that you cited. Here is a modified version of that so answer employing your kivy code:
import logging
from kivy.lang import Builder
from kivy.logger import Logger
from kivy.app import App
from kivy.clock import Clock
class MyLabelHandler(logging.Handler):
def __init__(self, label, level=logging.NOTSET):
super(MyLabelHandler, self).__init__(level=level)
self.label = label
def emit(self, record):
"using the Clock module for thread safety with kivy's main loop"
def f(dt=None):
self.label.text += self.format(record) + '\n' #"use += to append..."
Clock.schedule_once(f)
class MainApp(App):
def __init__(self, **kwargs):
super(MainApp, self).__init__(**kwargs)
self.kv = Builder.load_string('''
FloatLayout: # added because `id` on root object has no effect
TextInput:
# redirect (preferably copy) logger text here
id: logger_text
readonly: True
''')
def build(self):
# use Kivy Logger
Logger.level = logging.INFO
Logger.addHandler(MyLabelHandler(self.kv.ids.logger_text, logging.INFO))
# send some logging from this app
Clock.schedule_interval(self.send_log, 2)
return self.kv
def send_log(self, dt):
# This is just to demonstrate some logging fom this App
Logger.info('MyApp: this is a test at ' + str(dt) + ' seconds')
logging.info('this is a python log')
if __name__ == '__main__':
MainApp().run()
Situation: Hello, I have a kivy application with buttons/icons which have bindings like changing page, saving/loading data with AWS or local storage, calling an API REST, etc...
Problem: Some of theses actions take some time and when I click multiple time on an icon that take time to do an action, my application crash on android.
Solution: Every time a binding is called, I disable the possibility of the user to interact with the application and I display a little "charging icon" on the menu.
Real problem: I don't know how to do it ! Is there a boolean userCanInteract or 2 functions like enable_user_interaction() disable_user_interaction() ?
I don't know a way to disable all user interaction with your app but you can disable your button like this:
Python file:
from kivy.app import App
from kivy.uix.widget import Widget
from kivy.properties import ObjectProperty
class Window(Widget):
button = ObjectProperty(None)
def disable_button(self):
self.button.disabled = True
self.button.text = "Disabled"
class GUI(App):
def build(self):
return Window()
if __name__ == "__main__":
GUI().run()
.kv file:
<Window>
button: button
Button:
id: button
text: "Enabled"
disabled: False
on_release: root.disable_button()
For the crashing part, i think using threading module can solve your problem. Every time you click a button for long tasks, create a new thread. Example:
Python:
from kivy.app import App
from kivy.uix.widget import Widget
from kivy.properties import ObjectProperty
import threading
from time import sleep
def do_something(app):
print("This function is doing something.")
sleep(1)
app.root.button.disabled = False
app.root.button.text = "Enabled"
class Window(Widget):
button = ObjectProperty(None)
def disable_button(self, app):
thread = threading.Thread(target=do_something, args=(app,))
self.button.disabled = True
self.button.text = "Disabled"
thread.start()
class GUI(App):
def build(self):
return Window()
if __name__ == "__main__":
GUI().run()
.kv file:
<Window>
button: button
Button:
id: button
text: "Enabled"
disabled: False
on_release: root.disable_button(app)
This way, your button will be disabled until the thread is done. When the thread ends, button will be enabled.
I have a problem deploying a Kivy application using RstDocument. It works fine on PC. I can deploy it if I use Label instead of RstDocument, but it stops in the latter case.
import kivy
from kivy.app import App
from kivy.uix.screenmanager import Screen
import configparser
class MainFrame(Screen):
def __init__(self, **kwargs):
super(MainFrame, self).__init__(**kwargs)
pass
def on_quit_button_click(self):
quit()
class BasicApp(App):
def build(self):
return MainFrame()
pass
if __name__ == '__main__':
BasicApp().run()
with the following basic.kv
<MainFrame>:
BoxLayout:
RstDocument:
#Label:
text: 'Hello *world*!'
Button:
text: 'Click to quit'
on_press: root.on_quit_button_click()
Nothing significant in logcat, just
WindowManager: finishDrawingWindow: Window{bf4383ed0 u0 Application Error: testrstdocument.testrstdocument} mDrawState=HAS_DRAWN
Buildozer.spec
I am able to run a Kivy App with rstDocument on an Acer Android tablet by adding docutils into buildozer's requirement.
requirements = kivy, configparser, docutils