4

I'm having a devil of a time getting CherryPy to serve the necessary css file for the page returned.

My directory structure:

Application
     ab.py              (CherryPy application)
     ab.config          (CherryPy config file)
     html\              (html template folder)
        ab.html         (html template file)
     css\               (css folder)
         ab.css         (css file)

The link statement in ab.html:

  <link href="/css/ab.css" rel="stylesheet" type="text/css" />

And finally, ab.config

 [/]
 tools.staticdir.root = "/"

 [/css/ab.css]
 tools.staticfile.on = True
 tools.staticfile.filename = "/css/ab.css"

My template is loaded and rendered to the browser as I expected, but no styling is applied. If I change the template to use a relative address (../css/ab.css) and open the template as a file in the browser, the styling is applied.

It took me a while to get the configuration file to a point where CherryPy did not complain about bad paths when starting the application. At this point it starts, renders, and returns fine but simply doesn't appear to serve the css file to the browser.

Any help greatly appreciated.

Update based on kind suggestions from fumanchu:

Preferring to use staticdir, and now understanding that the root refers to the filesystem absolute path, I now have this in the config file:

 [/]
 tools.staticdir.root = "c:/users/myaccount/documents/clientname/application"

 [/css]
 tools.staticdir.on = True
 tools.staticdir.dir = "css"

In my HTML I have this style sheet link:

<link href="/css/ab.css" rel="stylesheet" type="text/css" />

And I'm starting CherryPy with this:

 cherrypy.quickstart(ABRoot(), '/', 'ab.config')

In this configuration, I still don't get styling on my web page. When I check the page source and click on the /css/ab.css link directly, I get

 NotFound: (404, "The path '/css/ab.css' was not found.")

(Note: I'm developing on a windows machine).

Larry Lustig
  • 49,320
  • 14
  • 110
  • 160
  • Without changing to a relative URL, can you view source on the page as it's being served and click on the "/css/ab.css" address in the source? – asthasr Sep 12 '11 at 03:44
  • I can, and I receive an exception from one of my CherryPy handlers which indicates that the request for /css/ab.css is being subject to the dispatch mechanism rather than being served as a static file. – Larry Lustig Sep 12 '11 at 10:45
  • Oops, result from the handler is with the relative path. With /css/ab.css I get "NotFound: (404, "The path '/css/ab.css' was not found.")". – Larry Lustig Sep 12 '11 at 10:52

4 Answers4

12

Change it quickly! The static handlers take paths that are absolute to your filesystem. By setting tools.staticdir.root = "/" you are saying "serve any file from my hard drive".

Whew. Now that the panic is over, let's analyze in more detail. First of all, staticdir and staticfile are different tools, and don't interact (so you're only really at risk above if there's more config you're not showing us, like tools.staticdir.on = True). If you want to stick with staticfile, you need to provide tools.staticfile.root, not tools.staticdir.root. If you'd rather expose whole directories, then replace staticfile with staticdir throughout.

Second, let's fix that .root setting. It should be the path to your "Application" folder (that is, the folder that contains 'ab.py' etc).

Third, the staticdir and staticfile tools determine a disk path with a simple os.path.join(root, dir) (or root, filename), so if you're supplying a root, your .dir or .filename shouldn't start with a slash:

>>> import os
>>> os.path.join('/path/to/Application', '/css/ab.css')
'/css/ab.css'
>>> os.path.join('/path/to/Application', 'css/ab.css')
'/path/to/Application/css/ab.css'

Given all that, try this config:

[/]
tools.staticfile.root = "/path/to/Application"

[/css/ab.css]
tools.staticfile.on = True
tools.staticfile.filename = "css/ab.css"
fumanchu
  • 14,419
  • 6
  • 31
  • 36
  • Thanks fumanchu. Application is only on my laptop, so that hole is plugged. I had no idea that static handlers would work relative to my filesystem and not the root of the application. I'm on another project today, but will work on this tonight and get back to you. Thanks again. – Larry Lustig Sep 12 '11 at 16:23
  • Updated the question with my current, still-failing, configuration based on your comments and the page here: http://www.cherrypy.org/wiki/StaticContent. Still can't figure out how to get it to work. – Larry Lustig Sep 13 '11 at 03:30
  • If you're using a recent version of CherryPy, all the builtin tools have a "debug" mode that should help you isolate the problem very quickly. Turn it on in your config with `tools.staticdir.debug = True` (and make sure you are sending log messages somewhere). – fumanchu Sep 13 '11 at 17:39
  • Using CP 3.2 on Python 2.7 so I'll try the debug tools tonight or tomorrow. Thanks. – Larry Lustig Sep 13 '11 at 17:41
  • Okay, got it! (Probably had it last night, but I left some orphaned code in my main application file that was overriding the config file). Enormous thanks. – Larry Lustig Sep 14 '11 at 02:53
1

This works for me:

static_handler = cherrypy.tools.staticdir.handler(section="/", dir=settings.STATIC_ROOT)
cherrypy.tree.mount(static_handler, '/static')

or in your case:

css_handler = cherrypy.tools.staticdir.handler(section="/", dir='path/to/css')
cherrypy.tree.mount(css_handler, '/css')
Shaung
  • 508
  • 4
  • 11
  • I've tried that. In place of path/to/css I've tried both the path with respect to the application directory ('/css') and also a complete path from the root of c:/. I placed the handler creation and mounting code at the beginning of my ab.py file and removed the reference to the configuration file. Same results. – Larry Lustig Sep 12 '11 at 10:56
0

I tried for hours to get the "official" cherrypy method to work, always with a 404 result. But this solution from google groups worked like a charm, so I'm reposting it here, where more people will find it.

For whatever reason, cherrypy's internal wrapper doesn't work, but this will render any files in a given folder public.

class StaticServer(object):
    """For testing - serves static files out of a given root.
    """

    def __init__(self, rootDir):
        self.rootDir = rootDir
        if not os.path.isabs(self.rootDir):
            self.rootDir = os.path.abspath(rootDir)

    @cherrypy.expose
    def default(self, *args):
        file = os.path.join(self.rootDir, *args)
        return cherrypy.lib.static.serve_file(file)

Usage:
class Root(object):
    static = StaticServer(r'./static')

Then if you put a file in your <root>/static - it will work.

Source: https://groups.google.com/forum/#!topic/cherrypy-users/5h5Ysp8z67E

Marc Maxmeister
  • 4,191
  • 4
  • 40
  • 54
0

Following dict worked for me (same can be specified in the config files as well):

conf = {      
         '/':{'tools.staticdir.root':'/Users/Desktop/Automation/CherryPy/ExecReport/html_code'
                 },
            '/images': {
                'tools.staticdir.on': True,
                'tools.staticdir.dir': 'images'},
            '/css': {
                'tools.staticdir.on': True,
                'tools.staticdir.dir': 'css'}
            }
cherrypy.quickstart(SampleApp(), '/', conf)

We can define root at directory once and then we can provide relative directories.

Manish
  • 21
  • 4