diff options
| -rw-r--r-- | docs/api/interfaces.rst | 2 | ||||
| -rw-r--r-- | docs/api/static.rst | 7 | ||||
| -rw-r--r-- | docs/narr/assets.rst | 72 | ||||
| -rw-r--r-- | pyramid/config/views.py | 15 | ||||
| -rw-r--r-- | pyramid/interfaces.py | 14 | ||||
| -rw-r--r-- | pyramid/static.py | 41 |
6 files changed, 129 insertions, 22 deletions
diff --git a/docs/api/interfaces.rst b/docs/api/interfaces.rst index d8d935afd..a62976d8a 100644 --- a/docs/api/interfaces.rst +++ b/docs/api/interfaces.rst @@ -86,3 +86,5 @@ Other Interfaces .. autointerface:: IResourceURL :members: + .. autointerface:: ICacheBuster + :members: diff --git a/docs/api/static.rst b/docs/api/static.rst index c28473584..8ea2fff75 100644 --- a/docs/api/static.rst +++ b/docs/api/static.rst @@ -9,3 +9,10 @@ :members: :inherited-members: + .. autoclass:: PathSegmentCacheBuster + :members: + + .. autoclass:: QueryStringCacheBuster + :members: + + .. autofunction:: Md5AssetTokenGenerator diff --git a/docs/narr/assets.rst b/docs/narr/assets.rst index a2976de22..97d473761 100644 --- a/docs/narr/assets.rst +++ b/docs/narr/assets.rst @@ -315,7 +315,7 @@ requests a copy, regardless of any caching policy set for the resource's old URL. :app:`Pyramid` can be configured to produce cache busting URLs for static -assets by passing the optional argument, `cache_bust` to +assets by passing the optional argument, ``cachebuster`` to :meth:`~pyramid.config.Configurator.add_static_view`: .. code-block:: python @@ -323,27 +323,22 @@ assets by passing the optional argument, `cache_bust` to # config is an instance of pyramid.config.Configurator config.add_static_view(name='static', path='mypackage:folder/static', - cache_bust='md5') + cachebuster=True) -Supplying the `cache_bust` argument instructs :app:`Pyramid` to add a query -string to URLs generated for this static view which includes the md5 checksum -of the static file being served: +Setting the ``cachebuster`` argument instructs :app:`Pyramid` to use a cache +busting scheme which adds the md5 checksum for a static asset as a path segment +in the asset's URL: .. code-block:: python :linenos: js_url = request.static_url('mypackage:folder/static/js/myapp.js') - # Returns: 'http://www.example.com/static/js/myapp.js?md5=c9658b3c0a314a1ca21e5988e662a09e` + # Returns: 'http://www.example.com/static/c9658b3c0a314a1ca21e5988e662a09e/js/myapp.js` When the asset changes, so will its md5 checksum, and therefore so will its -URL. Supplying the `cache_bust` argument also causes the static view to set +URL. Supplying the ``cachebuster`` argument also causes the static view to set headers instructing clients to cache the asset for ten years, unless the -`max_cache_age` argument is also passed, in which case that value is used. - -.. note:: - - `md5` is currently the only possible value for the `cache_bust` argument to - :meth:`~pyramid.config.Configurator.add_static_view`. +``max_cache_age`` argument is also passed, in which case that value is used. .. note:: @@ -351,6 +346,57 @@ headers instructing clients to cache the asset for ten years, unless the restarting your application, you may still generate URLs with a stale md5 checksum. +Customizing the Cache Buster +~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Revisiting from the previous section: + +.. code-block:: python + :linenos: + + # config is an instance of pyramid.config.Configurator + config.add_static_view(name='static', path='mypackage:folder/static', + cachebuster=True) + +Setting ``cachebuster`` to ``True`` instructs :app:`Pyramid` to use a default +cache busting implementation that should work for many situations. The +``cachebuster`` may be set to any object that implements the interface, +:class:`~pyramid.interfaces.ICacheBuster`. The above configuration is exactly +equivalent to: + +.. code-block:: python + :linenos: + + from pyramid.static import ( + Md5AssetTokenGenerator, + PathSegmentCacheBuster) + + # config is an instance of pyramid.config.Configurator + cachebuster = PathSegmentCacheBuster(Md5AssetTokenGenerator()) + config.add_static_view(name='static', path='mypackage:folder/static', + cachebuster=cachebuster) + +:app:`Pyramid` includes two ready to use cache buster implementations: +:class:`~pyramid.static.PathSegmentCacheBuster`, which inserts an asset token +in the path portion of the asset's URL, and +:class:`~pyramid.static.QueryStringCacheBuster`, which adds an asset token to +the query string of the asset's URL. Both of these classes have constructors +which accept a token generator function as an argument, allowing for the way a +token is generated to be decoupled from the way it is inserted into a URL. +:app:`Pyramid` provides a single asset token generator, +:meth:`~pyramid.static.Md5AssetTokenGenerator`. + +In order to implement your own cache buster, see the +:class:`~pyramid.interfaces.ICacheBuster` interface and the existing +implementations in the :mod:`~pyramid.static` module. + +.. note:: + + Many HTTP caching proxy implementations will fail to cache any URL which + has a query string. For this reason, you should probably prefer + :class:`~pyramid.static.PathSegementCacheBuster` to + :class:`~pyramid.static.QueryStringCacheBuster`. + .. index:: single: static assets view diff --git a/pyramid/config/views.py b/pyramid/config/views.py index 00c5622e7..d74ecfadb 100644 --- a/pyramid/config/views.py +++ b/pyramid/config/views.py @@ -1788,11 +1788,16 @@ class ViewsConfiguratorMixin(object): particular Expires or Cache-Control headers are set in the response, unless ``cache_bust`` is specified. - The ``cache_bust`` keyword argument may be set to ``"md5"`` to cause - :meth:`~pyramid.request.Request.static_url` to generate URLs with an - additional query string which includes the md5 checksum for the static - asset. This argument modifies the default for ``cache_max_age``, - making it ten years. ``cache_max_age`` may still be explicitly + The ``cachebuster`` keyword argument may be set to cause + :meth:`~pyramid.request.Request.static_url` to use cache busting when + generating URLs. See :ref:`cache_busting` for general information + about cache busting. The value of the ``cachebuster`` argument may be + ``True``, in which case a default cache busting implementation is used. + The value of the ``cachebuster`` argument may also be an object which + implements :class:`~pyramid.interfaces.ICacheBuster`. See the + :mod:`~pyramid.static` module for some implementations. If the + ``cachebuster`` argument is provided, the default for ``cache_max_age`` + is modified to be ten years. ``cache_max_age`` may still be explicitly provided to override this default. The ``permission`` keyword argument is used to specify the diff --git a/pyramid/interfaces.py b/pyramid/interfaces.py index 822d1624c..f3d7b1798 100644 --- a/pyramid/interfaces.py +++ b/pyramid/interfaces.py @@ -1168,6 +1168,12 @@ class ICacheBuster(Interface): """ A container for functions which implement a cache busting policy for serving static assets. + + The implementations provided by :app:`Pyramid` use standard instance + methods for ``pregenerate`` and ``match``, while accepting an + implementation of ``token`` as an argument to their constructor. This + pattern allows for the decoupling of how a token is generated and how it is + inserted into a URL. For examples see the :mod:`~pyramid.static` module. """ def token(pathspec): """ @@ -1197,7 +1203,7 @@ class ICacheBuster(Interface): A function which modifies a subpath and/or keyword arguments from which a static asset URL will be computed during URL generation. The ``token`` argument is a token string computed by an instance of - :method:`~pyramid.interfaces.ICacheBuster.token` for a particular + :meth:`~pyramid.interfaces.ICacheBuster.token` for a particular asset. The ``subpath`` argument is a tuple of path elements that represent the portion of the asset URL which is used to find the asset. The ``kw`` argument is a dict of keywords that are to be passed @@ -1218,9 +1224,9 @@ class ICacheBuster(Interface): def match(subpath): """ - A function which performs the logical inverse of an - :method:`~pyramid.interfaces.ICacheBuster.pregenerate`, by taking a - subpath from a cache busted URL and removing the cachebust token, so + A function which performs the logical inverse of + :meth:`~pyramid.interfaces.ICacheBuster.pregenerate` by taking a + subpath from a cache busted URL and removing the cache bust token, so that :app:`Pyramid` can find the underlying asset. ``subpath`` is the subpath portion of the URL for an incoming request diff --git a/pyramid/static.py b/pyramid/static.py index 09743ac15..ab9d47aa5 100644 --- a/pyramid/static.py +++ b/pyramid/static.py @@ -166,6 +166,12 @@ def _generate_md5(spec): return md5.hexdigest() def Md5AssetTokenGenerator(): + """ + A factory method which returns a function that implements + :meth:`~pyramid.interfaces.ICacheBuster.token`. The function computes and + returns md5 checksums for static assets, caching them in memory for speedy + retrieval on subsequent calls. + """ token_cache = {} def generate_token(pathspec): @@ -189,7 +195,23 @@ def Md5AssetTokenGenerator(): return generate_token class PathSegmentCacheBuster(object): + """ + An implementation of :class:`~pyramid.interfaces.ICacheBuster` which + inserts a token for cache busting in the path portion of an asset URL. + + The ``token`` argument should be an implementation of + :meth:`~pyramid.interfaces.ICacheBuster.token`. For example, to use + this cache buster with an md5 token generator: + .. code-block:: python + :linenos: + + from pyramid.static import ( + Md5AssetTokenGenerator, + PathSegmentCacheBuster) + + cachebuster = PathSegmentCacheBuster(Md5AssetTokenGenerator()) + """ def __init__(self, token): self.token = token @@ -200,7 +222,26 @@ class PathSegmentCacheBuster(object): return subpath[1:] class QueryStringCacheBuster(object): + """ + An implementation of :class:`~pyramid.interfaces.ICacheBuster` which + adds a token for cache busting in the query string of an asset URL. + + The ``token`` argument should be an implementation of + :meth:`~pyramid.interfaces.ICacheBuster.token`. For example, to use + this cache buster with an md5 token generator: + + .. code-block:: python + :linenos: + from pyramid.static import ( + Md5AssetTokenGenerator, + PathSegmentCacheBuster) + + cachebuster = QueryStringCacheBuster(Md5AssetTokenGenerator()) + + The optional ``param`` argument determines the name of the parameter added + to the query string and defaults to ``'x'``. + """ def __init__(self, token, param='x'): self.param = param self.token = token |
