Search code examples
pythontypeerrorcherrypy

Unable to add more than one applications together in cherryPy


When I do this and try to access "/api" than cherryPy throws "TypeError: 'ApiStringGenerator' object is not callable" error

'''
Created on Jan 11, 2016

@author: ankurjat
'''
import cherrypy
import random
import string
import os

conf = {'/': {'tools.sessions.on': True,
              'tools.staticdir.root': os.path.abspath(os.getcwd())},
        '/static': {'tools.staticdir.on': True,
                    'tools.staticdir.dir': './resources'},
        '/api': {'request.dispatch':  cherrypy.dispatch.MethodDispatcher(),
                 'tools.sessions.on': True,
                 'tools.response_headers.on': True,
                 'tools.response_headers.headers': [('Content-Type', 'text/plain')]}
            }


class ApiStringGenerator(object):
    exposed = True

    @cherrypy.tools.accept(media='text/plain')
    def GET(self, length=8):
        value = cherrypy.session['mystring']
        return value

    def POST(self, length=8):
        value = ''.join(random.sample(string.hexdigits, int(length)))
        cherrypy.session['mystring'] = value
        return value

    def PUT(self, value):
        cherrypy.session['mystring'] = value

    def DELETE(self):
        cherrypy.session.pop('mystring', None)


class StringGenerator(object):
    @cherrypy.expose
    def index(self):
        return file('templates/index.html')


if __name__ == '__main__':
    cherrypy.tree.mount(ApiStringGenerator(), '/api', conf)
    cherrypy.tree.mount(StringGenerator(), '/', conf)

    cherrypy.engine.start()
    cherrypy.engine.block()

But when I change below lines

cherrypy.tree.mount(ApiStringGenerator(), '/api', conf)
cherrypy.tree.mount(StringGenerator(), '/', conf)

cherrypy.engine.start()
cherrypy.engine.block()

By the code

webapp = StringGenerator()
webapp.api = ApiStringGenerator()
cherrypy.quickstart(webapp, '/', conf)

Then no error and everything works fine. Please help.


Solution

  • The problem is that the configuration in cherrypy is relative to the mountpoint.

    So when you are configuring the MethodDispatcher in /api inside the mount point /api. You are activating the MethodDispatcher inside /api/api and the dispatcher that's gets used in /api it's the default one, hence trying to call the object because the object has the exposed attribute but it's not callable. Which is the behavior of the default dispatcher.

    If you want to do:

    cherrypy.tree.mount(ApiStringGenerator(), '/api', conf)
    

    The configuration needs to be relative to the /api:

     {'/': {'request.dispatch':  cherrypy.dispatch.MethodDispatcher(),
            'tools.sessions.on': True,
            'tools.response_headers.on': True,
            'tools.response_headers.headers': [('Content-Type',  'text/plain')]}}