Rob Watts
Rob Watts

Reputation: 7146

KeyError with CherryPy WSGIServer serving static files

I'm trying to use CherryPy's WSGI server to serve static files, like in Using Flask with CherryPy to serve static files. Option 2 of the accepted answer there looks exactly like what I'd like to do, but I'm getting a KeyError when I try to use the static directory handler.

What I've tried:

>>>> import cherrypy
>>>> from cherrypy import wsgiserver
>>>> import os
>>>> static_handler = cherrypy.tools.staticdir.handler(section='/', dir=os.path.abspath('server_files')
>>>> d = wsgiserver.WSGIPathInfoDispatcher({'/': static_handler})
>>>> server = wsgiserver.CherryPyWSGIServer(('localhost', 12345), d)
>>>> server.start()

Then, when I try to access the server I'm getting a 500 response and the following error in the console:

KeyError('tools',)
Traceback (most recent call last):
  File "/Library/Python/2.7/site-packages/cherrypy/wsgiserver/wsgiserver2.py", line 1353, in communicate
    req.respond()
  File "/Library/Python/2.7/site-packages/cherrypy/wsgiserver/wsgiserver2.py", line 868, in respond
    self.server.gateway(self).respond()
  File "/Library/Python/2.7/site-packages/cherrypy/wsgiserver/wsgiserver2.py", line 2267, in respond
    response = self.req.server.wsgi_app(self.env, self.start_response)
  File "/Library/Python/2.7/site-packages/cherrypy/wsgiserver/wsgiserver2.py", line 2477, in __call__
    return app(environ, start_response)
  File "/Library/Python/2.7/site-packages/cherrypy/_cptools.py", line 175, in handle_func
    handled = self.callable(*args, **self._merged_args(kwargs))
  File "/Library/Python/2.7/site-packages/cherrypy/_cptools.py", line 102, in _merged_args
    tm = cherrypy.serving.request.toolmaps[self.namespace]
KeyError: 'tools'

This is displayed twice for each time I try to hit anything that the server should be able to display. When I hooked up a Flask app to the server the Flask app worked as expected, but the static file serving still gave the same error.

What do I need to do to get the staticdir.handler to work?

Upvotes: 1

Views: 771

Answers (1)

robashdown
robashdown

Reputation: 63

I've tried various ways of getting this to work and up until today was also hitting the KeyError you have been seeing (among other issues).

I finally managed to get CherryPy to serve static alongside a Django app by adapting the code from this gist (included below).

import os
import cherrypy
from cherrypy import wsgiserver

from my_wsgi_app import wsgi

PATH = os.path.abspath(os.path.join(os.path.dirname(__file__), 'public'))


class Root(object):
    pass

def make_static_config(static_dir_name):
    """
    All custom static configurations are set here, since most are common, it
    makes sense to generate them just once.
    """
    static_path = os.path.join('/', static_dir_name)
    path = os.path.join(PATH, static_dir_name)
    configuration = {static_path: {
        'tools.staticdir.on': True,
        'tools.staticdir.dir': path}
    }
    print configuration
    return cherrypy.tree.mount(Root(), '/', config=configuration)

# Assuming your app has media on diferent paths, like 'c', 'i' and 'j'
application = wsgiserver.WSGIPathInfoDispatcher({
    '/': wsgi.application,
    '/c': make_static_config('c'),
    '/j': make_static_config('j'),
    '/i': make_static_config('i')})

server = wsgiserver.CherryPyWSGIServer(('0.0.0.0', 8070), application,
                                       server_name='www.cherrypy.example')
try:
    server.start()
except KeyboardInterrupt:
    print "Terminating server..."
    server.stop()

Hopefully wrapping a Flask app will be fairly similar.

The key for me was using the cherrypy.tree.mount on a dummy class, rather than trying to use the staticdir.handler directly.

For the curious - I used the code in the gist to customise a version of django-cherrypy's runcpserver management command, although in hindsight it would probably have been easier to create a new command from scratch.

Good luck (and thanks to Alfredo Deza)!

Upvotes: 2

Related Questions