Trying to deploy a Flask app on CherryPy server - python

I was trying to deploy my Flask app on CherryPy server. I liked its simplistic and minimalistic nature.
So I PIP'ed CherryPy like below
pip install CherryPy-15.0.0-py2.py3-none-any.whl
and wrote script like below -very common suggested by many sources
from cherrypy import wsgiserver
from hello import app
d = wsgiserver.WSGIPathInfoDispatcher({'/': app})
server = wsgiserver.CherryPyWSGIServer(('0.0.0.0', 80), d)
if __name__ == '__main__':
try:
server.start()
except KeyboardInterrupt:
server.stop()
To my surprise, I had imports errors. After a few googling around, I learned that I had to change my import lines to cheroot to make it work.
from cheroot.wsgi import Server
from cheroot.wsgi import PathInfoDispatcher
Now, my code is working fine.
However, I am a bit confused if this is the right way of using CherryPy WSGI server or if I pip'ed a wrong version of CherryPy. I am confused because Cheroot seems to be more than year old (dates all the way back to 2014), yet all the information I found around Flask on CherryPy WSGI server is using from cherrypy import wsgiserver, not from cheroot.wsgi import Server, even the latest postings.
This makes me unsure if I am doing the right thing or not.
Can someone please shed light on this confusion?

Cheroot (src) is a low-level HTTP and WSGI server, which used to be a part of CherryPy (src) once, but has been factored out into a separate repo a while back. So former cherrypy.wsgiserver has moved to cheroot.wsgi module.
It's completely replaceable and designed to allow developers to depend on Cheroot directly if they only use WSGI server, not requiring other parts of CherryPy.
So here's how you can use it in a version-agnostic way:
try:
from cheroot.wsgi import Server as WSGIServer, PathInfoDispatcher
except ImportError:
from cherrypy.wsgiserver import CherryPyWSGIServer as WSGIServer, WSGIPathInfoDispatcher as PathInfoDispatcher
from hello import app
d = PathInfoDispatcher({'/': app})
server = WSGIServer(('0.0.0.0', 80), d)
if __name__ == '__main__':
try:
server.start()
except KeyboardInterrupt:
server.stop()

Related

Using flask-socketio, how can I asynchornously emit multiple messages in one function?

I'm building a Flask web app using the flask-socketio module to implement websockets. It generally works fine, but when I try to emit multiple messages from the server to the client in a for loop, all the messages are actually sent at once - that is, as soon as all of them have been created.
I read that the solution might be to use an eventlet server capable of asynchronous task handling:
"The simplest deployment strategy is to have eventlet or gevent installed, and start the web server by calling socketio.run(app) as shown in examples above. This will run the application on the eventlet or gevent web servers, whichever is installed." (taken from the Flask-SocketIO docs)
Sadly, that doesn't solve the problem. I've never worked with websockets before, so I'm a bit lost. Here is a simplified version of my code:
from flask import Flask
from flask_socketio import SocketIO, emit
import eventlet
app = Flask(__name__)
socketio = SocketIO(app)
#socketio.on("connect")
def handle_connect():
print("server and client connected")
#socketio.on("text")
def text(question):
for _ in range(3):
answer = my_module.generate_answer(question)
emit("message", {"msg": answer})
socketio.run(app)
Just assume that my_module.generate_answer() generates a sentence based on some user input sent via the websocket. Each generation takes 5-10 seconds. That's also the reason why I want the answers to be sent via a WebSocket once they're generated - my frontend could already display the first answer while waiting for the next ones.
Thank you so much for your help!
You need to monkey patch at the very top of your file.
Your import statements should look like this:
import eventlet
eventlet.monkey_patch()
from flask import Flask
from flask_socketio import SocketIO, emit

Python Flask REST API on Windows Cherrypy

I'm trying to create a python Flask REST web API. Since Flask development server is not suitable for production, I tried to use cherrypy application server.
Following is the Flask app I tried to expose via cherrypy
from flask import Flask,request
from flask_restful import Api,Resource, reqparse
app= Flask(__name__)
api = Api(app)
class Main (Resource):
def get(self):
return "Hello Flask"
if __name__ == '__main__':
api.add_resource(Main, "/testapp/")
app.run(debug=True)
Following is the cherrypy script I have created
try:
from cheroot.wsgi import Server as WSGIServer, PathInfoDispatcher
except ImportError:
from cherrypy.wsgiserver import CherryPyWSGIServer as WSGIServer, WSGIPathInfoDispatcher as PathInfoDispatcher
from stack import app
d = PathInfoDispatcher({'/': app})
server = WSGIServer(('127.0.0.1', 8080), d)
if __name__ == '__main__':
try:
server.start()
print("started")
except KeyboardInterrupt:
server.stop()
I have saved this script as "run.py" in my project directory. When I run this it doesn't show any error, which made me to thin this is correct.
But unfortunately I cant access this using the url
Theoretically, url for this API should be some thing like follow
http://127.0.0.1:8080/testapp/
But it throws 404 with the message
"The requested URL was not found on the server. If you entered the URL manually please check your spelling and try again."
What am I doing wrong ?
The
api.add_resource(Main, "/testapp/")
in your file stack.py is not executed if the file is included from your run.py
as the condition
if __name__ == '__main__':
...
is not true (in the context of stack.py).
Moving the call to api.add_resource(...) to a position outside the if-main-condition (so it is always executed) should solve the issue.

Importing CherryPy fails on openshift

I'm running a cherrypy based app on an openshift gear. Recently I've been getting a "503 service temporarily unavailable" error whenever I try to go to the site. Inspecting the logs, I see I'm getting an ImportError where I try to import CherryPy. This is strange - CherryPy is listed as a dependency in my requirements.txt and used to be imported just fine. I double checked to make sure I'm getting the right path to the openshift activate_this.py and it seems to be correct. I'm not quite sure where to look next; any help would be appreciated. Thanks!
The failed import is at line 14 of app.py:
import os
import files
virtenv = os.path.join(os.environ['OPENSHIFT_PYTHON_DIR'], 'virtenv')
virtualenv = os.path.join(virtenv, 'bin', 'activate_this.py')
conf = os.path.join(files.get_root(), "conf", "server.conf")
try:
execfile(virtualenv, dict(__file__=virtualenv))
print virtualenv
except IOError:
pass
import cherrypy
import wsgi
def mount():
def CORS():
cherrypy.response.headers["Access-Control-Allow-Origin"] = os.environ['OPENSHIFT_APP_DNS']
cherrypy.config.update({"tools.staticdir.root": files.get_root()})
cherrypy.tools.CORS = cherrypy.Tool('before_handler', CORS)
cherrypy.tree.mount(wsgi.application(), "/", conf)
def start():
cherrypy.engine.start()
def end():
cherrypy.engine.exit()
if __name__ == "__main__":
mount()
start()
UPDATE
I eventually saw (when pushing to the openshift repo using git bash CLI) that the dependency installation from requirements.txt was failing with some exceptions I haven't bothered to look into yet. It then goes on to try to install dependencies in setup.py, and that works just fine.
Regarding the port in use issue...I have no idea. I changed my startup from tree.mount and engine.start to quickstart, and everything worked when I pushed to openshift. Just for kicks (and because I need it to run my tests), I switched back to cherrypy.tree.mount, pushed it, and it worked just fine.
Go figure.
I use the app.py entry point for Openshift. Here are several examples on how I start my server using the pyramid framework on Openshift. I use waitress as the server but I have also used the cherrypy wsgi server. Just comment out the code you don't want.
app.py
#Openshift entry point
import os
from pyramid.paster import get_app
from pyramid.paster import get_appsettings
if __name__ == '__main__':
here = os.path.dirname(os.path.abspath(__file__))
if 'OPENSHIFT_APP_NAME' in os.environ: #are we on OPENSHIFT?
ip = os.environ['OPENSHIFT_PYTHON_IP']
port = int(os.environ['OPENSHIFT_PYTHON_PORT'])
config = os.path.join(here, 'production.ini')
else:
ip = '0.0.0.0' #localhost
port = 6543
config = os.path.join(here, 'development.ini')
app = get_app(config, 'main') #find 'main' method in __init__.py. That is our wsgi app
settings = get_appsettings(config, 'main') #don't really need this but is an example on how to get settings from the '.ini' files
# Waitress (remember to include the waitress server in "install_requires" in the setup.py)
from waitress import serve
print("Starting Waitress.")
serve(app, host=ip, port=port, threads=50)
# Cherrypy server (remember to include the cherrypy server in "install_requires" in the setup.py)
# from cherrypy import wsgiserver
# print("Starting Cherrypy Server on http://{0}:{1}".format(ip, port))
# server = wsgiserver.CherryPyWSGIServer((ip, port), app, server_name='Server')
# server.start()
#Simple Server
# from wsgiref.simple_server import make_server
# print("Starting Simple Server on http://{0}:{1}".format(ip, port))
# server = make_server(ip, port, app)
# server.serve_forever()
#Running 'production.ini' method manually. I find this method the least compatible with Openshift since you can't
#easily start/stop/restart your app with the 'rhc' commands. Mabye somebody can suggest a better way :)
# #Don't forget to set the Host IP in 'production.ini'. Use 8080 for the port for Openshift
# You will need to use the 'pre_build' action hook(pkill python) so it stops the existing running instance of the server on OS
# You also will have to set up another custom action hook so rhc app-restart, stop works.
# See Openshifts Origin User's Guide ( I have not tried this yet)
#Method #1
# print('Running pserve production.ini')
# os.system("pserve production.ini &")
#Method #2
#import subprocess
#subprocess.Popen(['pserve', 'production.ini &'])

How do I run twisted with flask?

I want to be able to run twisted servers on multiple different directories (exp: /example1, /example2...etc), So I thought I'd use flask. Here is what I have so far:
from flask import Flask
from twisted.web.server import Site
from twisted.web.wsgi import WSGIResource
from twisted.internet import reactor
from twisted.web.proxy import ReverseProxyResource
from twisted.web.resource import Resource
app = Flask(__name__)
#app.route('/example1')
def index():
return 'My Twisted Flask'
flask_site = WSGIResource(reactor, reactor.getThreadPool(), app)
root = Resource()
root.putChild('my_flask', flask_site)
site_example = ReverseProxyResource('www.example.com', 80, ''.encode('utf-8'))
root.putChild('example1', site_example)
reactor.listenTCP(80, Site(root))
reactor.run()
The only problem is that it doesn't work, I'm not sure what I'm doing wrong. I appreciate any help, thanks!
My personal opinion: running Flask in Twisted's reactor isn't a good idea because Twisted's reactor is blocked when a request is processed by Flask.
I think you might be interested in Klein, which provided API similar to Flask, but works on Twisted out of the box: http://klein.readthedocs.io/en/latest/
Another option: I'd take a look into nginx as a reverse proxy for Flask applications instead of Twisted. nginx runs in a separate process and isn't blocked while a request is processed by Flask.
https://www.nginx.com/resources/admin-guide/reverse-proxy/
You can use twisted web, as documented on the Flask deploy documentation. Here's how I managed to run a server on my machine:
pip3 install twisted[tls]
export PYTHONPATH=${PYTHONPATH}:${PWD} # exports python path
twistd web -n --port tcp:5000 --wsgi path-to-your-app-root --logfile log.txt
Though I've had some issues with the server after it's up and running for my particular scenario, this might work for you

How to launch a Bottle application over a CherryPy standalone web server?

I have a python web app developed using the bottle framework. My bottle app is web API that provide methods that return JSon data, so no static content is needed. I am trying to deploy it to production using a CherryPy server which is supposed to be robust for production applications.
My web_api.py file (my bottle app) looks something like this:
from bottle import Bottle, request
app = Bottle()
#app.get('/stuff')
def do_stuff():
'''
Method that does stuff.
'''
stuff = {'data': 'some data'}
# Return the environment info as Json data
return stuff
I have a server.py file to launch the Bottle app over the CherryPy server that looks like this:
from my_package.web_api import app
from cherrypy.wsgiserver import CherryPyWSGIServer
server = CherryPyWSGIServer(
('0.0.0.0', 80),
app,
server_name='My_App',
numthreads=30)
server.start()
so when I run my server using this command:
python server.py
My server is successfully started and start listening in port 80 as expected. However once I start my web server I cannot stop it any more. I have tried Ctrl + C which works with the development server but has no effect here. Am I starting the server the right way? How do I stop it once it is running? Is this the correct way to launch a Bottle app over CherryPy?
BTW, I am running python 2.7 in Windows 8.
Your code is correct, you just need to add a try/catch statement:
from my_package.web_api import app
from cherrypy.wsgiserver import CherryPyWSGIServer
server = CherryPyWSGIServer(
('0.0.0.0', 80),
app,
server_name='My_App',
numthreads=30)
try:
server.start()
except KeyboardInterrupt:
server.stop()
You might wanna also consider to do some logging with wsgi-request-logger or something similar.
This are three alternative ways on hosting a WSGI application within cherrypy:
import cherrypy as cp
from cherrypy.wsgiserver import CherryPyWSGIServer
from cherrypy.process.servers import ServerAdapter
from bottle import Bottle
app = Bottle()
#app.get('/stuff')
def do_stuff():
'''
Method that does stuff.
'''
stuff = {'data': 'some dataX'}
return stuff
def run_decoupled(app, host='0.0.0.0', port=8080, **config):
server = CherryPyWSGIServer((host, port), app, **config)
try:
server.start()
except KeyboardInterrupt:
server.stop()
def run_in_cp_tree(app, host='0.0.0.0', port=8080, **config):
cp.tree.graft(app, '/')
cp.config.update(config)
cp.config.update({
'server.socket_port': port,
'server.socket_host': host
})
cp.engine.signals.subscribe() # optional
cp.engine.start()
cp.engine.block()
def run_with_adapter(app, host='0.0.0.0', port=8080, config=None, **kwargs):
cp.server.unsubscribe()
bind_addr = (host, port)
cp.server = ServerAdapter(cp.engine,
CherryPyWSGIServer(bind_addr, app, **kwargs),
bind_addr).subscribe()
if config:
cp.config.update(config)
cp.engine.signals.subscribe() # optional
cp.engine.start()
cp.engine.block()
The run_in_cp_tree and run_with_adapter functions are using the cherrypy engine, which enables the use of plugins to have off-the-shelf auto-reload, pidfile, daemonization, signal management and some more goodies, along with the possibility to create one of your own.
Notice that you can also use the WSGIPathInfoDispatcher to attach multiple wsgi applications on the CherryPyWSGIServer.
Trying to connect any WSGI server to my BottlePy app here in 2019 turned out to be rather tricky(to a noobie like me).
I tried connecting several ones, spent most off my time with CherryPy, which has changed his syntax.
The simpliest to me turned out to be waitress https://waitress.readthedocs.io/en/latest/usage.html
After i figured out how to use it on waitress i got it in cherrypy also. So:
CherryPy http://docs.cherrypy.org/en/latest/advanced.html?highlight=WSGi#host-a-foreign-wsgi-application-in-cherrypy
1)add after imports
import cherrypy as cp
app = bottle.Bottle()
2) change in routes "#bottle" to "#app"
3)add this as main function
cp.tree.graft(app, '/')
cp.server.start()
Waitress
1)add after imports
import waitress
app = bottle.Bottle()
2)add this as main function
waitress.serve(app, listen='*:44100')
3) change in routes "#bottle" to "#app"

Categories