Bottle framework and OOP, using method instead of function

user1129665 picture user1129665 · Jan 4, 2012 · Viewed 13.8k times · Source

I've done some coding with Bottle. It's really simple and fits my needs. However, I got stick when I tried to wrap the application into a class :

import bottle
app = bottle

class App():
    def __init__(self,param):
        self.param   = param

    # Doesn't work
    @app.route("/1")
    def index1(self):
        return("I'm 1 | self.param = %s" % self.param)

    # Doesn't work
    @app.route("/2")
    def index2(self):
        return("I'm 2")

    # Works fine
    @app.route("/3")
    def index3():
        return("I'm 3")

Is it possible to use methods instead of functions in Bottle?

Answer

Ski picture Ski · Jan 4, 2012

Your code does not work because you are trying to route to non-bound methods. Non-bound methods do not have a reference to self, how could they, if instance of App has not been created?

If you want to route to class methods, you first have to initialize your class and then bottle.route() to methods on that object like so:

import bottle        

class App(object):
    def __init__(self,param):
        self.param   = param

    def index1(self):
        return("I'm 1 | self.param = %s" % self.param)

myapp = App(param='some param')
bottle.route("/1")(myapp.index1)

If you want to stick routes definitions near the handlers, you can do something like this:

def routeapp(obj):
    for kw in dir(app):
        attr = getattr(app, kw)
        if hasattr(attr, 'route'):
            bottle.route(attr.route)(attr)

class App(object):
    def __init__(self, config):
        self.config = config

    def index(self):
        pass
    index.route = '/index/'

app = App({'config':1})
routeapp(app)

Don't do the bottle.route() part in App.__init__(), because you won't be able to create two instances of App class.

If you like the syntax of decorators more than setting attribute index.route=, you can write a simple decorator:

def methodroute(route):
    def decorator(f):
        f.route = route
        return f
    return decorator

class App(object):
    @methodroute('/index/')
    def index(self):
        pass