summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMalthe Borch <mborch@gmail.com>2009-08-24 17:21:10 +0000
committerMalthe Borch <mborch@gmail.com>2009-08-24 17:21:10 +0000
commit241390d911639cb658bbbbbf1bf3d8c21e0c0270 (patch)
tree7ebcc33709c8c715debf9b94e5157a1464df260c
parent45b545c377945812a83d926d11f1635d279069a6 (diff)
downloadpyramid-241390d911639cb658bbbbbf1bf3d8c21e0c0270.tar.gz
pyramid-241390d911639cb658bbbbbf1bf3d8c21e0c0270.tar.bz2
pyramid-241390d911639cb658bbbbbf1bf3d8c21e0c0270.zip
Added ZCML directive to serve up static files from a directory.
-rw-r--r--CHANGES.txt3
-rw-r--r--docs/narr/MyProject/myproject/configure.zcml5
-rw-r--r--docs/narr/MyProject/myproject/views.py3
-rw-r--r--docs/narr/project.rst19
-rw-r--r--docs/narr/views.rst84
-rw-r--r--repoze/bfg/includes/meta.zcml6
-rw-r--r--repoze/bfg/paster_templates/starter/+package+/configure.zcml5
-rw-r--r--repoze/bfg/paster_templates/starter/+package+/views.py_tmpl3
-rw-r--r--repoze/bfg/tests/test_zcml.py70
-rw-r--r--repoze/bfg/zcml.py34
10 files changed, 177 insertions, 55 deletions
diff --git a/CHANGES.txt b/CHANGES.txt
index fca8c5f0d..50b9758f4 100644
--- a/CHANGES.txt
+++ b/CHANGES.txt
@@ -1,6 +1,9 @@
Next release
============
+- Added ``static`` ZCML directive which registers a route for a static
+ view that serves up files in a directory.
+
- "tests" module removed from the bfg_alchemy paster template; these
tests didn't work.
diff --git a/docs/narr/MyProject/myproject/configure.zcml b/docs/narr/MyProject/myproject/configure.zcml
index 89bf74525..aa98296c5 100644
--- a/docs/narr/MyProject/myproject/configure.zcml
+++ b/docs/narr/MyProject/myproject/configure.zcml
@@ -8,10 +8,9 @@
view=".views.my_view"
/>
- <view
- for=".models.MyModel"
- view=".views.static_view"
+ <static
name="static"
+ path="templates/static"
/>
</configure>
diff --git a/docs/narr/MyProject/myproject/views.py b/docs/narr/MyProject/myproject/views.py
index d4de33b6d..486019bd7 100644
--- a/docs/narr/MyProject/myproject/views.py
+++ b/docs/narr/MyProject/myproject/views.py
@@ -1,7 +1,4 @@
from repoze.bfg.chameleon_zpt import render_template_to_response
-from repoze.bfg.view import static
-
-static_view = static('templates/static')
def my_view(context, request):
return render_template_to_response('templates/mytemplate.pt',
diff --git a/docs/narr/project.rst b/docs/narr/project.rst
index e2fc69435..131a8ff48 100644
--- a/docs/narr/project.rst
+++ b/docs/narr/project.rst
@@ -565,10 +565,8 @@ registry`. It looks like so:
``.views.my_view`` could be replaced with
``myproject.views.my_view``.
-#. Lines 11-15 register a view named ``static``. This view
- declaration points at the ``static_view``, which is a view
- implementation that serves static files from the filesystem for the
- default application.
+#. Lines 11-14 register a static view, which will register a view
+ which serves up the files from the static directory in the package.
``views.py``
~~~~~~~~~~~~
@@ -582,13 +580,7 @@ in the model, and the response given back to a browser.
#. Lines 1-2 import required functions.
-#. Line 4 sets up a ``static_view`` which will be consulted when
- visitors visit ``/static/<something>``. This view will serve up
- CSS and images in our default application. This view is registered
- in ``configure.zcml`` as the ``static`` view name for the class
- ``MyModel`` (the root).
-
-#. Lines 6-9 provide the ``my_view`` that was registered as the view.
+#. Lines 3-6 provide the ``my_view`` that was registered as the view.
``configure.zcml`` said that the default URL for instances that are
of the class ``MyModel`` should run this ``my_view`` function.
@@ -622,11 +614,6 @@ in the model, and the response given back to a browser.
retrieve the template object without rendering it at all, for
additional control.
-.. note::
-
- For more information about the ``static`` view helper function see
- :ref:`static_resources_section`.
-
.. _modelspy_project_section:
``models.py``
diff --git a/docs/narr/views.rst b/docs/narr/views.rst
index b5db0ca63..795fa61a6 100644
--- a/docs/narr/views.rst
+++ b/docs/narr/views.rst
@@ -630,18 +630,66 @@ includes other response types for Unauthorized, etc.
.. _static_resources_section:
+Serving Static Resources Using a ZCML directive
+-----------------------------------------------
+
+Using the ``static`` ZCML directive is the preferred way to serve
+static resources (like JavaScript and CSS files) within
+:mod:`repoze.bfg`. This directive makes static files available at a
+name relative to the application root URL, e.g. ``/static``.
+
+You can either use a package-relative path to a directory or a path
+relative to the ZCML file (or an absolute path).
+
+.. code-block:: xml
+ :linenos:
+
+ <static
+ name="static"
+ path="some_package:static"
+ />
+
+ <static
+ name="static"
+ path="static"
+ />
+
+ <static
+ name="static"
+ path="/var/www/static"
+ />
+
+Now put your static files (JS, etc) on your filesystem in the
+directory represented as ``/path/to/static/dir``. After this is done,
+you should be able to view the static files in this directory via a
+browser at URLs prefixed with ``/static/``, for instance
+``/static/foo.js`` will return the file
+``/path/to/static/dir/foo.js``. The static directory may contain
+subdirectories recursively, and any subdirectories may hold files;
+these will be resolved by the static view as you would expect.
+
+.. note:: To ensure that model objects contained in the root don't
+ "shadow" your static view (model objects take precedence during
+ traversal), or to ensure that your root object's ``__getitem__`` is
+ never called when a static resource is requested, you can refer to
+ your static resources as registered above in URLs as,
+ e.g. ``/@@static/foo.js``. This is completely equivalent to
+ ``/static/foo.js``. See :ref:`traversal_chapter` for information
+ about "goggles" (``@@``).
+
Serving Static Resources Using a View
-------------------------------------
-Using the :mod:`repoze.bfg.view` ``static`` helper class is the
-preferred way to serve static resources (like JavaScript and CSS
-files) within :mod:`repoze.bfg`. This class creates a callable that
-is capable acting as a :mod:`repoze.bfg` view which serves static
-resources from a directory. For instance, to serve files within a
-directory located on your filesystem at ``/path/to/static/dir``
-mounted at the URL path ``/static`` in your application, create an
-instance of :mod:`repoze.bfg.view` 's ``static`` class inside a
-``static.py`` file in your application root as below.
+For more flexibility, static resources can be served by a view which
+you register manually. The :mod:`repoze.bfg.view` ``static`` helper
+class is the preferred way to go about this. This class creates a
+callable that is capable acting as a :mod:`repoze.bfg` view which
+serves static resources from a directory. For instance, to serve
+files within a directory located on your filesystem at
+``/path/to/static/dir`` mounted at the URL path ``/static`` in your
+application, create an instance of :mod:`repoze.bfg.view` 's
+``static`` class inside a ``static.py`` file in your application root
+as below.
.. code-block:: python
:linenos:
@@ -671,24 +719,6 @@ In this case, ``.models.Root`` refers to the class of which your
for ``/anything/static/foo.js`` too, as long as ``anything`` itself
is resolveable.
-Now put your static files (JS, etc) on your filesystem in the
-directory represented as ``/path/to/static/dir``. After this is done,
-you should be able to view the static files in this directory via a
-browser at URLs prefixed with ``/static/``, for instance
-``/static/foo.js`` will return the file
-``/path/to/static/dir/foo.js``. The static directory may contain
-subdirectories recursively, and any subdirectories may hold files;
-these will be resolved by the static view as you would expect.
-
-.. note:: To ensure that model objects contained in the root don't
- "shadow" your static view (model objects take precedence during
- traversal), or to ensure that your root object's ``__getitem__`` is
- never called when a static resource is requested, you can refer to
- your static resources as registered above in URLs as,
- e.g. ``/@@static/foo.js``. This is completely equivalent to
- ``/static/foo.js``. See :ref:`traversal_chapter` for information
- about "goggles" (``@@``).
-
Using Views to Handle Form Submissions (Unicode and Character Set Issues)
-------------------------------------------------------------------------
diff --git a/repoze/bfg/includes/meta.zcml b/repoze/bfg/includes/meta.zcml
index 89a540098..69e2eabc0 100644
--- a/repoze/bfg/includes/meta.zcml
+++ b/repoze/bfg/includes/meta.zcml
@@ -41,6 +41,12 @@
/>
<meta:directive
+ name="static"
+ schema="repoze.bfg.zcml.IStaticDirective"
+ handler="repoze.bfg.zcml.static"
+ />
+
+ <meta:directive
name="repozewho1authenticationpolicy"
schema="repoze.bfg.zcml.IRepozeWho1AuthenticationPolicyDirective"
handler="repoze.bfg.zcml.repozewho1authenticationpolicy"
diff --git a/repoze/bfg/paster_templates/starter/+package+/configure.zcml b/repoze/bfg/paster_templates/starter/+package+/configure.zcml
index 89bf74525..aa98296c5 100644
--- a/repoze/bfg/paster_templates/starter/+package+/configure.zcml
+++ b/repoze/bfg/paster_templates/starter/+package+/configure.zcml
@@ -8,10 +8,9 @@
view=".views.my_view"
/>
- <view
- for=".models.MyModel"
- view=".views.static_view"
+ <static
name="static"
+ path="templates/static"
/>
</configure>
diff --git a/repoze/bfg/paster_templates/starter/+package+/views.py_tmpl b/repoze/bfg/paster_templates/starter/+package+/views.py_tmpl
index 9c5fe7a67..d9f0df378 100644
--- a/repoze/bfg/paster_templates/starter/+package+/views.py_tmpl
+++ b/repoze/bfg/paster_templates/starter/+package+/views.py_tmpl
@@ -1,7 +1,4 @@
from repoze.bfg.chameleon_zpt import render_template_to_response
-from repoze.bfg.view import static
-
-static_view = static('templates/static')
def my_view(context, request):
return render_template_to_response('templates/mytemplate.pt',
diff --git a/repoze/bfg/tests/test_zcml.py b/repoze/bfg/tests/test_zcml.py
index 556f22983..d17babaf3 100644
--- a/repoze/bfg/tests/test_zcml.py
+++ b/repoze/bfg/tests/test_zcml.py
@@ -1037,6 +1037,76 @@ class TestRouteDirective(unittest.TestCase):
self.assertEqual(route_discriminator[3], 'GET')
self.assertEqual(route_args, ('path', 'name', None))
+class TestStaticDirective(unittest.TestCase):
+ def setUp(self):
+ cleanUp()
+ import os
+ here = os.path.dirname(__file__)
+ self.static_path = os.path.join(here, 'fixtures', 'static')
+
+ def tearDown(self):
+ cleanUp()
+
+ def _callFUT(self, *arg, **kw):
+ from repoze.bfg.zcml import static
+ return static(*arg, **kw)
+
+ def test_absolute(self):
+ from repoze.bfg.zcml import handler
+ from repoze.bfg.zcml import connect_route
+ from repoze.bfg.interfaces import IView
+ context = DummyContext()
+ self._callFUT(context, 'name', self.static_path)
+ actions = context.actions
+ self.assertEqual(len(actions), 2)
+
+ route_action = actions[0]
+ route_callable = route_action['callable']
+ route_discriminator = route_action['discriminator']
+ route_args = route_action['args']
+ self.assertEqual(route_callable, handler)
+ self.assertEqual(route_discriminator[:3], (
+ 'view', None, ''))
+ self.assertEqual(route_discriminator[4], IView)
+
+ route_action = actions[1]
+ route_callable = route_action['callable']
+ route_discriminator = route_action['discriminator']
+ route_args = route_action['args']
+ self.assertEqual(route_callable, connect_route)
+ self.assertEqual(route_discriminator, (
+ 'route', 'name', None, None))
+ self.assertEqual(route_args, (
+ 'name*subpath', 'name', None))
+
+ def test_package_relative(self):
+ from repoze.bfg.zcml import handler
+ from repoze.bfg.zcml import connect_route
+ from repoze.bfg.interfaces import IView
+ context = DummyContext()
+ self._callFUT(context, 'name', 'repoze.bfg.tests:fixtures/static')
+ actions = context.actions
+ self.assertEqual(len(actions), 2)
+
+ route_action = actions[0]
+ route_callable = route_action['callable']
+ route_discriminator = route_action['discriminator']
+ route_args = route_action['args']
+ self.assertEqual(route_callable, handler)
+ self.assertEqual(route_discriminator[:3], (
+ 'view', None, ''))
+ self.assertEqual(route_discriminator[4], IView)
+
+ route_action = actions[1]
+ route_callable = route_action['callable']
+ route_discriminator = route_action['discriminator']
+ route_args = route_action['args']
+ self.assertEqual(route_callable, connect_route)
+ self.assertEqual(route_discriminator, (
+ 'route', 'name', None, None))
+ self.assertEqual(route_args, (
+ 'name*subpath', 'name', None))
+
class TestResourceDirective(unittest.TestCase):
def setUp(self):
cleanUp()
diff --git a/repoze/bfg/zcml.py b/repoze/bfg/zcml.py
index 7c1a74ec2..e38fd3449 100644
--- a/repoze/bfg/zcml.py
+++ b/repoze/bfg/zcml.py
@@ -46,6 +46,7 @@ from repoze.bfg.security import ViewPermissionFactory
from repoze.bfg.secpols import registerBBBAuthn
+from repoze.bfg.view import static as static_view
import martian
@@ -338,6 +339,39 @@ def connect_route(path, name, factory):
mapper = getUtility(IRoutesMapper)
mapper.connect(path, name, factory)
+class IStaticDirective(Interface):
+ name = TextLine(
+ title=u"The URL prefix of the static view",
+ description=u"""
+ The directory will be served up for the route that starts with
+ this prefix.""",
+ required=True)
+
+ path = TextLine(
+ title=u'Path to the directory which contains resources',
+ description=u'May be package-relative by using a colon to '
+ 'seperate package name and path relative to the package directory.',
+ required=True)
+
+ cache_max_age = Int(
+ title=u"Cache maximum age",
+ required=False,
+ default=None)
+
+def static(_context, name, path, cache_max_age=3600):
+ """ Handle ``static`` ZCML directives
+ """
+
+ if ':' in path:
+ package_name, path = path.split(':')
+ else:
+ package_name = _context.resolve('.').__name__
+
+ view = static_view(
+ path, cache_max_age=cache_max_age, package_name=package_name)
+
+ route(_context, name, "%s*subpath" % name, view=view)
+
class IViewDirective(Interface):
for_ = GlobalObject(
title=u"The interface or class this view is for.",