Cas
Cas

Reputation: 2297

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.

Upvotes: 3

Views: 7981

Answers (3)

vy32
vy32

Reputation: 29707

Here is what I had to do in 2024:

server.py:

import cherrypy as cp
import bottle_app

app = bottle_app.app

cp.tree.graft(app, '/')
cp.server.start()

My Bottle app is in a file called bottle_app.py. This file has the import bottle statement, all of the @bottle.route statements, and this at the top:

app = bottle.default_app()

Upvotes: 0

Maks
Maks

Reputation: 1639

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"

Upvotes: 0

cyraxjoe
cyraxjoe

Reputation: 5741

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.

Upvotes: 10

Related Questions