The solution was to package YUI into a Zope product that consisted of a single .egg; when the package is included, the YUI source directory is available as a resource in the browser. The same solution applies, of course, to any set of static files that merely need to be traversable—CSS, images, static data, whatever. It's trivially simple, but I couldn't find any clear tutorials. Plus I'm on a plane and don't feel like reading. Here's how to wrap any directory into a Zope product.
Throughout this, I'll be using the YUI package I created as an example. Obviously, you'd replace all instances of "zenoss" and "yui" with names appropriate to your package.
easy_install PasteScript if you don't have it already), which can generate skeleton structures from several different templates. In this case, you simply need an egg. You can either create the simplest kind of egg, or you can make a namespace package (for example, "yui" vs. "zenoss.yui"). I recommend the latter, if only to avoid conflicts with others who might have had the same idea:
$ paster create -t basic_namespace zenoss.yui
(If you just want a simple egg, use the
basic_package template instead).
Enter the namespace ("zenoss") and the package ("yui") and any other information you care to. You'll be asked for the basic egg metadata—license, description, author, etc. All is optional, but if you're going to distribute your package you should definitely provide this stuff. Don't worry, you can do it later by modifying
When you're done, you'll have an egg structure in the directory you specified (in this case, "zenoss.yui").
zenoss.yui/zenoss/yui) and create the directory to hold your files:
$ cd zenoss.yui/zenoss/yui
$ mkdir src
Copy any files you want available as resources into that directory. There's no need to create a
yui directory inside the
src directory; the entire resource directory will be available at
/++resource++yui already (see below for a way to get rid of the
++resource++ cruft if so inclined), so if you created, for example,
src/myfile.js, you would use the URL
/++resource++yui/myfile.js to traverse to it.
Now edit the new file
zenoss.yui/MANIFEST.in (it'll be a sibling of
setup.py) and add the following line:
That tells setuptools to include every file underneath the directory
zenoss; otherwise, it's likely to ignore most of the files you've added.
src as a Zope resource directory. Edit the new file
zenoss.yui/zenoss/yui/configure.zcml and add the ZCML necessary to wire the directory into Zope's publisher:
setup.py is located. Build the egg:
$ python setup.py bdist_egg
That'll create an egg in
dist. Install that in whatever way you like, as long as it ends up in the Python path of your Zope environment—manually, with
easy_install, or by including it in a buildout recipe. Then, somewhere in the ZCML chain of your Zope application, include the package:
Now fire up Zope and try the URL
++resource++yui/anyfile.js against the root object, where
anyfile.js is some file directly under
src in your package. As I explained earlier, you should be able to get to anything in the
src directory by mirroring the filesystem path in the URL, replacing
I mentioned a technique for removing the necessity to include
++resource++ as part of the URL. You may not want to do this; I only did it because all my template files already referred to
/yui and I didn't feel like changing them. In the same package in your Zope application in which you included
zenoss.yui, create a file called
YUIShortcut.py (you can put it anywhere, of course, but this keeps things organized). If you're using Five:
from Products.Five.browser import BrowserView
If Zope 3:
from zope.publisher.browser import BrowserView
Then make a view that passes traversal off to the
def __getitem__(self, name):
Then wire it to the
/yui URL in
Now you should be able to hit /yui/myfile.js instead of /++resource++yui/myfile.js.