Search code examples
pythoncherrypy

Python CherryPy server, what does cherrypy.Application do?


I have here a Python program. It uses CherryPy to create a server.

# coding:utf-8

import os.path
import cherrypy

from app import application

def main():

try:                                   
    currentDir_s = os.path.dirname(os.path.abspath(__file__))
except:
    currentDir_s = os.path.dirname(os.path.abspath(sys.executable))
cherrypy.Application.currentDir_s = currentDir_s

configFileName_s = 'server.conf'
if os.path.exists(configFileName_s) == False:
    configFileName_s = None

cherrypy.engine.autoreload.unsubscribe()
cherrypy.engine.timeout_monitor.unsubscribe()

cherrypy.quickstart(application.Application_cl(), config=configFileName_s)

if __name__ == '__main__':
    main()

And in "server.conf" it configure the server:

[global]
tools.log_headers.on: True
tools.sessions.on:    False  
tools.encode.on:      True
tools.encode.encoding:"utf-8"

server.socket_port:   8080 
server.socket_timeout:60     

server.thread_pool:  10      
server.environment:  "production"
log.screen:          True    

[/]
tools.staticdir.root: cherrypy.Application.currentDir_s
tools.staticdir.on = True
tools.staticdir.dir = '.'

There is one thing, I don't understand, this line (line 13 in the python code):

cherrypy.Application.currentDir_s = currentDir_s

I searched in the internet about this, but I couldn't find anything. What does "cherrypy.Application" do? Why I have to do this assignment (cherrypy.Application.currentDir_s = currentDir_s)?


Solution

  • I searched the cherrypy source code and here is what I found. In _cptree.py module you will find the Application class. Below that, there is a Tree class which has mount method which we are used to binding applications with (e.g. cherrypy.tree.mount(Root(), "/", config=config))

    def mount(self, root, script_name="", config=None):
        ...
    

    When you look inside this method you will see the code below;

    def mount(self, root, script_name="", config=None):
        ...
        if isinstance(root, Application):
            app = root
            if script_name != "" and script_name != app.script_name:
                raise ValueError(
                    "Cannot specify a different script name and pass an "
                    "Application instance to cherrypy.mount")
            script_name = app.script_name
        else:
            app = Application(root, script_name)
    
            # If mounted at "", add favicon.ico
            if (script_name == "" and root is not None
                    and not hasattr(root, "favicon_ico")):
                favicon = os.path.join(os.getcwd(), os.path.dirname(__file__),
                                       "favicon.ico")
                root.favicon_ico = tools.staticfile.handler(favicon)
    
        if config:
            app.merge(config)
    
        self.apps[script_name] = app
    

    So, the code says that every object (application) you pass to the mount method is either Application instance or wrapped in an Application instance. So why is that so? When you check Application class above Tree class, you will see a __call__ method like below;

    def __call__(self, environ, start_response):
        return self.wsgiapp(environ, start_response)
    

    Yes you see it now, it is wsgi interface. Therefore, Application is a wsgi wrapper for your cherrypy applications. When you check the source code of cherrypy you may learn lots of things. I hope this answer help you.