From d868fff7597c5a05acd1f5c024fc45dde9880413 Mon Sep 17 00:00:00 2001 From: Chris McDonough Date: Mon, 13 Jun 2011 06:17:00 -0400 Subject: - Remove IResponder abstraction in favor of more general IResponse abstraction. - It is now possible to return an arbitrary object from a Pyramid view callable even if a renderer is not used, as long as a suitable adapter to ``pyramid.interfaces.IResponse`` is registered for the type of the returned object. See the section in the Hooks chapter of the documentation entitled "Changing How Pyramid Treats View Responses". - The Pyramid router now, by default, expects response objects returned from view callables to implement the ``pyramid.interfaces.IResponse`` interface. Unlike the Pyramid 1.0 version of this interface, objects which implement IResponse now must define a ``__call__`` method that accepts ``environ`` and ``start_response``, and which returns an ``app_iter`` iterable, among other things. Previously, it was possible to return any object which had the three WebOb ``app_iter``, ``headerlist``, and ``status`` attributes as a response, so this is a backwards incompatibility. It is possible to get backwards compatibility back by registering an adapter to IResponse from the type of object you're now returning from view callables. See the section in the Hooks chapter of the documentation entitled "Changing How Pyramid Treats View Responses". - The ``pyramid.interfaces.IResponse`` interface is now much more extensive. Previously it defined only ``app_iter``, ``status`` and ``headerlist``; now it is basically intended to directly mirror the ``webob.Response`` API, which has many methods and attributes. - Documentation changes to support above. --- docs/narr/assets.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'docs/narr/assets.rst') diff --git a/docs/narr/assets.rst b/docs/narr/assets.rst index 8d0e7058c..0d50b0106 100644 --- a/docs/narr/assets.rst +++ b/docs/narr/assets.rst @@ -358,7 +358,7 @@ do so, do things "by hand". First define the view callable. :linenos: import os - from webob import Response + from pyramid.response import Response def favicon_view(request): here = os.path.dirname(__file__) -- cgit v1.2.3 From 56d0fe4a9f97daa4d5fd0c28ea83c6ef32856b3d Mon Sep 17 00:00:00 2001 From: Chris McDonough Date: Thu, 14 Jul 2011 01:13:27 -0400 Subject: - New API class: ``pyramid.static.static_view``. This supersedes the deprecated ``pyramid.view.static`` class. ``pyramid.satic.static_view`` by default serves up documents as the result of the request's ``path_info``, attribute rather than it's ``subpath`` attribute (the inverse was true of ``pyramid.view.static``, and still is). ``pyramid.static.static_view`` exposes a ``use_subpath`` flag for use when you don't want the static view to behave like the older deprecated version. - The ``pyramid.view.static`` class has been deprecated in favor of the newer ``pyramid.static.static_view`` class. A deprecation warning is raised when it is used. You should replace it with a reference to ``pyramid.static.static_view`` with the ``use_subpath=True`` argument. --- docs/narr/assets.rst | 29 +++++++++++++++-------------- 1 file changed, 15 insertions(+), 14 deletions(-) (limited to 'docs/narr/assets.rst') diff --git a/docs/narr/assets.rst b/docs/narr/assets.rst index 0d50b0106..d57687477 100644 --- a/docs/narr/assets.rst +++ b/docs/narr/assets.rst @@ -299,7 +299,7 @@ URLs against assets made accessible by registering a custom static view. Root-Relative Custom Static View (URL Dispatch Only) ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -The :class:`pyramid.view.static` helper class generates a Pyramid view +The :class:`pyramid.static.static_view` helper class generates a Pyramid view callable. This view callable can serve static assets from a directory. An instance of this class is actually used by the :meth:`~pyramid.config.Configurator.add_static_view` configuration method, so @@ -310,26 +310,27 @@ its behavior is almost exactly the same once it's configured. exclusively. The root-relative route we'll be registering will always be matched before traversal takes place, subverting any views registered via ``add_view`` (at least those without a ``route_name``). A - :class:`~pyramid.view.static` static view cannot be made root-relative when - you use traversal. + :class:`~pyramid.static.static_view` static view cannot be made + root-relative when you use traversal unless it's registered as a + :term:`NotFound view`. To serve files within a directory located on your filesystem at ``/path/to/static/dir`` as the result of a "catchall" route hanging from the root that exists at the end of your routing table, create an instance of the -:class:`~pyramid.view.static` class inside a ``static.py`` file in your -application root as below. +:class:`~pyramid.static.static_view` class inside a ``static.py`` file in +your application root as below. .. ignore-next-block .. code-block:: python :linenos: - from pyramid.view import static - static_view = static('/path/to/static/dir') + from pyramid.static import static + static_view = static_view('/path/to/static/dir', use_subpath=True) .. note:: For better cross-system flexibility, use an :term:`asset - specification` as the argument to :class:`~pyramid.view.static` instead of - a physical absolute filesystem path, e.g. ``mypackage:static`` instead of - ``/path/to/mypackage/static``. + specification` as the argument to :class:`~pyramid.static.static_view` + instead of a physical absolute filesystem path, e.g. ``mypackage:static`` + instead of ``/path/to/mypackage/static``. Subsequently, you may wire the files that are served by this view up to be accessible as ``/`` using a configuration method in your @@ -345,8 +346,8 @@ application's startup code. config.add_view('myapp.static.static_view', route_name='catchall_static') The special name ``*subpath`` above is used by the -:class:`~pyramid.view.static` view callable to signify the path of the file -relative to the directory you're serving. +:class:`~pyramid.static.static_view` view callable to signify the path of the +file relative to the directory you're serving. Registering A View Callable to Serve a "Static" Asset ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -425,10 +426,10 @@ feature, a :term:`Configurator` API exists named - A directory containing multiple Chameleon templates. - Individual static files served up by an instance of the - ``pyramid.view.static`` helper class. + ``pyramid.static.static_view`` helper class. - A directory of static files served up by an instance of the - ``pyramid.view.static`` helper class. + ``pyramid.static.static_view`` helper class. - Any other asset (or set of assets) addressed by code that uses the setuptools :term:`pkg_resources` API. -- cgit v1.2.3 From c515d77de5b2f62727251ebc32d1292e67811771 Mon Sep 17 00:00:00 2001 From: Chris McDonough Date: Fri, 15 Jul 2011 10:13:07 -0400 Subject: - get_root2 -> prepare - change prepare return value to a dict, and return the registry, request, etc - various docs and changelog entries. --- docs/narr/assets.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'docs/narr/assets.rst') diff --git a/docs/narr/assets.rst b/docs/narr/assets.rst index d57687477..f35f6dd7d 100644 --- a/docs/narr/assets.rst +++ b/docs/narr/assets.rst @@ -312,7 +312,7 @@ its behavior is almost exactly the same once it's configured. ``add_view`` (at least those without a ``route_name``). A :class:`~pyramid.static.static_view` static view cannot be made root-relative when you use traversal unless it's registered as a - :term:`NotFound view`. + :term:`Not Found view`. To serve files within a directory located on your filesystem at ``/path/to/static/dir`` as the result of a "catchall" route hanging from the -- cgit v1.2.3 From 6ce1e0cf1a141767ee0aca70786c15dd993347c5 Mon Sep 17 00:00:00 2001 From: Chris McDonough Date: Wed, 20 Jul 2011 06:10:38 -0400 Subject: add more index markers --- docs/narr/assets.rst | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'docs/narr/assets.rst') diff --git a/docs/narr/assets.rst b/docs/narr/assets.rst index f35f6dd7d..e609a3eab 100644 --- a/docs/narr/assets.rst +++ b/docs/narr/assets.rst @@ -35,6 +35,9 @@ static assets. For example, there's a ``static`` directory which contains ``.css``, ``.js``, and ``.gif`` files. These asset files are delivered when a user visits an application URL. +.. index:: + single: asset specifications + .. _asset_specifications: Understanding Asset Specifications @@ -85,6 +88,7 @@ individual documentation. .. index:: single: add_static_view + pair: assets; serving .. _static_assets_section: @@ -186,6 +190,7 @@ discussed in more detail later in this chapter. .. index:: single: generating static asset urls single: static asset urls + pair: assets; generating urls .. _generating_static_asset_urls: -- cgit v1.2.3 From fb90f0166728af40142ed9a31039d26ca3f97c73 Mon Sep 17 00:00:00 2001 From: Chris McDonough Date: Sun, 14 Aug 2011 04:58:34 -0400 Subject: - The ``route_url``, ``route_path``, ``resource_url``, ``static_url``, and ``current_route_url`` functions in the ``pyramid.url`` package now delegate to a method on the request they've been passed, instead of the other way around. The pyramid.request.Request object now inherits from a mixin named pyramid.url.URLMethodsMixin to make this possible, and all url/path generation logic is embedded in this mixin. - Narrative and API documentation which used the ``route_url``, ``route_path``, ``resource_url``, ``static_url``, and ``current_route_url`` functions in the ``pyramid.url`` package have now been changed to use eponymous methods of the request instead. --- docs/narr/assets.rst | 60 +++++++++++++++++++++++++++------------------------- 1 file changed, 31 insertions(+), 29 deletions(-) (limited to 'docs/narr/assets.rst') diff --git a/docs/narr/assets.rst b/docs/narr/assets.rst index e609a3eab..c8508f1b5 100644 --- a/docs/narr/assets.rst +++ b/docs/narr/assets.rst @@ -165,7 +165,8 @@ Instead of representing a URL prefix, the ``name`` argument of a call to *URL*. Each of examples we've seen so far have shown usage of the ``name`` argument as a URL prefix. However, when ``name`` is a *URL*, static assets can be served from an external webserver. In this mode, the ``name`` is used -as the URL prefix when generating a URL using :func:`pyramid.url.static_url`. +as the URL prefix when generating a URL using +:meth:`pyramid.request.Request.static_url`. For example, :meth:`~pyramid.config.Configurator.add_static_view` may be fed a ``name`` argument which is ``http://example.com/images``: @@ -179,13 +180,13 @@ be fed a ``name`` argument which is ``http://example.com/images``: Because :meth:`~pyramid.config.Configurator.add_static_view` is provided with a ``name`` argument that is the URL ``http://example.com/images``, subsequent -calls to :func:`~pyramid.url.static_url` with paths that start with the -``path`` argument passed to +calls to :meth:`~pyramid.request.Request.static_url` with paths that start +with the ``path`` argument passed to :meth:`~pyramid.config.Configurator.add_static_view` will generate a URL something like ``http://example.com/images/logo.png``. The external webserver listening on ``example.com`` must be itself configured to respond -properly to such a request. The :func:`~pyramid.url.static_url` API is -discussed in more detail later in this chapter. +properly to such a request. The :meth:`~pyramid.request.Request.static_url` +API is discussed in more detail later in this chapter. .. index:: single: generating static asset urls @@ -199,9 +200,9 @@ Generating Static Asset URLs When a :meth:`~pyramid.config.Configurator.add_static_view` method is used to register a static asset directory, a special helper API named -:func:`pyramid.url.static_url` can be used to generate the appropriate URL -for an asset that lives in one of the directories named by the static -registration ``path`` attribute. +:meth:`pyramid.request.Request.static_url` can be used to generate the +appropriate URL for an asset that lives in one of the directories named by +the static registration ``path`` attribute. For example, let's assume you create a set of static declarations like so: @@ -219,18 +220,17 @@ visits a URL which begins with ``/static1``, and the assets in the visits a URL which begins with ``/static2``. You needn't generate the URLs to static assets "by hand" in such a -configuration. Instead, use the :func:`~pyramid.url.static_url` API to -generate them for you. For example: +configuration. Instead, use the :meth:`~pyramid.request.Request.static_url` +API to generate them for you. For example: .. code-block:: python :linenos: - from pyramid.url import static_url from pyramid.chameleon_zpt import render_template_to_response def my_view(request): - css_url = static_url('mypackage:assets/1/foo.css', request) - js_url = static_url('mypackage:assets/2/foo.js', request) + css_url = request.static_url('mypackage:assets/1/foo.css') + js_url = request.static_url('mypackage:assets/2/foo.js') return render_template_to_response('templates/my_template.pt', css_url = css_url, js_url = js_url) @@ -240,17 +240,18 @@ If the request "application URL" of the running system is ``http://example.com/static1/foo.css``. The ``js_url`` generated above would be ``http://example.com/static2/foo.js``. -One benefit of using the :func:`~pyramid.url.static_url` function rather than -constructing static URLs "by hand" is that if you need to change the ``name`` -of a static URL declaration, the generated URLs will continue to resolve -properly after the rename. +One benefit of using the :meth:`~pyramid.request.Request.static_url` function +rather than constructing static URLs "by hand" is that if you need to change +the ``name`` of a static URL declaration, the generated URLs will continue to +resolve properly after the rename. -URLs may also be generated by :func:`~pyramid.url.static_url` to static assets -that live *outside* the :app:`Pyramid` application. This will happen when -the :meth:`~pyramid.config.Configurator.add_static_view` API associated with -the path fed to :func:`~pyramid.url.static_url` is a *URL* instead of a view -name. For example, the ``name`` argument may be ``http://example.com`` while -the the ``path`` given may be ``mypackage:images``: +URLs may also be generated by :meth:`~pyramid.request.Request.static_url` to +static assets that live *outside* the :app:`Pyramid` application. This will +happen when the :meth:`~pyramid.config.Configurator.add_static_view` API +associated with the path fed to :meth:`~pyramid.request.Request.static_url` +is a *URL* instead of a view name. For example, the ``name`` argument may be +``http://example.com`` while the the ``path`` given may be +``mypackage:images``: .. code-block:: python :linenos: @@ -265,14 +266,14 @@ assets which begin with ``mypackage:images`` will be prefixed with .. code-block:: python :linenos: - static_url('mypackage:images/logo.png', request) + request.static_url('mypackage:images/logo.png') # -> http://example.com/images/logo.png -Using :func:`~pyramid.url.static_url` in conjunction with a +Using :meth:`~pyramid.request.Request.static_url` in conjunction with a :meth:`~pyramid.configuration.Configurator.add_static_view` makes it possible to put static media on a separate webserver during production (if the -``name`` argument to :meth:`~pyramid.config.Configurator.add_static_view` is a -URL), while keeping static media package-internal and served by the +``name`` argument to :meth:`~pyramid.config.Configurator.add_static_view` is +a URL), while keeping static media package-internal and served by the development webserver during development (if the ``name`` argument to :meth:`~pyramid.config.Configurator.add_static_view` is a URL prefix). To create such a circumstance, we suggest using the @@ -298,8 +299,9 @@ dispatch`, you may want static assets to only be available as a fallback if no previous route matches. Alternately, you might like to serve a particular static asset manually, because its download requires authentication. -Note that you cannot use the :func:`~pyramid.url.static_url` API to generate -URLs against assets made accessible by registering a custom static view. +Note that you cannot use the :meth:`~pyramid.request.Request.static_url` API +to generate URLs against assets made accessible by registering a custom +static view. Root-Relative Custom Static View (URL Dispatch Only) ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -- cgit v1.2.3 From 55ce9d632f828d285360c1abee9f56042243cac9 Mon Sep 17 00:00:00 2001 From: Chris McDonough Date: Sun, 28 Aug 2011 22:15:48 -0400 Subject: clean up inappropriate discussions of ZCML --- docs/narr/assets.rst | 3 --- 1 file changed, 3 deletions(-) (limited to 'docs/narr/assets.rst') diff --git a/docs/narr/assets.rst b/docs/narr/assets.rst index c8508f1b5..93b03fbc9 100644 --- a/docs/narr/assets.rst +++ b/docs/narr/assets.rst @@ -441,9 +441,6 @@ feature, a :term:`Configurator` API exists named - Any other asset (or set of assets) addressed by code that uses the setuptools :term:`pkg_resources` API. -.. note:: The :term:`ZCML` directive named ``asset`` serves the same purpose - as the :meth:`~pyramid.config.Configurator.override_asset` method. - .. index:: single: override_asset -- cgit v1.2.3 From 012b9762cd0b114b6afbf2d6356554b51706804a Mon Sep 17 00:00:00 2001 From: michr Date: Fri, 23 Sep 2011 18:48:28 -0700 Subject: fixed up all the warning dealing ..note and ..warn added a hide toc for glossary to prevent warnings --- docs/narr/assets.rst | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'docs/narr/assets.rst') diff --git a/docs/narr/assets.rst b/docs/narr/assets.rst index 93b03fbc9..cd76f7b60 100644 --- a/docs/narr/assets.rst +++ b/docs/narr/assets.rst @@ -102,7 +102,9 @@ directory on a filesystem to an application user's browser. Use the mechanism makes a directory of static files available at a name relative to the application root URL, e.g. ``/static`` or as an external URL. -.. note:: :meth:`~pyramid.config.Configurator.add_static_view` cannot serve a +.. note:: + + :meth:`~pyramid.config.Configurator.add_static_view` cannot serve a single file, nor can it serve a directory of static files directly relative to the root URL of a :app:`Pyramid` application. For these features, see :ref:`advanced_static`. @@ -312,7 +314,9 @@ instance of this class is actually used by the :meth:`~pyramid.config.Configurator.add_static_view` configuration method, so its behavior is almost exactly the same once it's configured. -.. warning:: The following example *will not work* for applications that use +.. warning:: + + The following example *will not work* for applications that use :term:`traversal`, it will only work if you use :term:`URL dispatch` exclusively. The root-relative route we'll be registering will always be matched before traversal takes place, subverting any views registered via -- cgit v1.2.3 From b1e795e320a505f9ed737a5f1466261508cfc33b Mon Sep 17 00:00:00 2001 From: Casey Duncan Date: Sat, 1 Oct 2011 15:03:48 -0600 Subject: Fix incorrect import in static view example --- docs/narr/assets.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'docs/narr/assets.rst') diff --git a/docs/narr/assets.rst b/docs/narr/assets.rst index cd76f7b60..4f80d33c7 100644 --- a/docs/narr/assets.rst +++ b/docs/narr/assets.rst @@ -335,7 +335,7 @@ your application root as below. .. code-block:: python :linenos: - from pyramid.static import static + from pyramid.static import static_view static_view = static_view('/path/to/static/dir', use_subpath=True) .. note:: For better cross-system flexibility, use an :term:`asset -- cgit v1.2.3 From f4216ebb4097af71fc9477cd097360e08117d265 Mon Sep 17 00:00:00 2001 From: Marius Gedminas Date: Tue, 21 Feb 2012 21:46:48 +0200 Subject: Fix favicon_view example: open the file in binary mode. Without this fix Python 3 users might get Unicode errors, and Windows users might get data corruption. --- docs/narr/assets.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'docs/narr/assets.rst') diff --git a/docs/narr/assets.rst b/docs/narr/assets.rst index 4f80d33c7..2cc870619 100644 --- a/docs/narr/assets.rst +++ b/docs/narr/assets.rst @@ -374,7 +374,7 @@ do so, do things "by hand". First define the view callable. def favicon_view(request): here = os.path.dirname(__file__) - icon = open(os.path.join(here, 'static', 'favicon.ico')) + icon = open(os.path.join(here, 'static', 'favicon.ico'), 'rb') return Response(content_type='image/x-icon', app_iter=icon) The above bit of code within ``favicon_view`` computes "here", which is a -- cgit v1.2.3 From c2e82a7505bd0cac9304b31c4e84fbafe521e0e1 Mon Sep 17 00:00:00 2001 From: Chris McDonough Date: Wed, 22 Feb 2012 20:22:27 -0500 Subject: allow user to pass content type and encoding, change favicon example to use FileResponse --- docs/narr/assets.rst | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) (limited to 'docs/narr/assets.rst') diff --git a/docs/narr/assets.rst b/docs/narr/assets.rst index 2cc870619..bad666066 100644 --- a/docs/narr/assets.rst +++ b/docs/narr/assets.rst @@ -370,19 +370,22 @@ do so, do things "by hand". First define the view callable. :linenos: import os - from pyramid.response import Response + from pyramid.response import FileResponse def favicon_view(request): here = os.path.dirname(__file__) - icon = open(os.path.join(here, 'static', 'favicon.ico'), 'rb') - return Response(content_type='image/x-icon', app_iter=icon) + icon = os.path.join(here, 'static', 'favicon.ico') + return FileResponse(icon, request=request) The above bit of code within ``favicon_view`` computes "here", which is a path relative to the Python file in which the function is defined. It then uses the Python ``open`` function to obtain a file handle to a file within -"here" named ``static``, and returns a response using the open the file -handle as the response's ``app_iter``. It makes sure to set the right -content_type too. +"here" named ``static``, and returns a :class:`pyramid.response.Fileresponse` +using the file path as the response's ``path`` argument and the request as +the response's ``request`` argument. :class:`pyramid.response.FileResponse` +will serve the file as quickly as possible when it's used this way. It makes +sure to set the right content length and content_type too based on the file +extension of the file you pass. You might register such a view via configuration as a view callable that should be called as the result of a traversal: -- cgit v1.2.3 From a1317263c3a4dafd366d3a272c37a3ed8ac3613a Mon Sep 17 00:00:00 2001 From: Chris McDonough Date: Wed, 22 Feb 2012 20:23:26 -0500 Subject: fix --- docs/narr/assets.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'docs/narr/assets.rst') diff --git a/docs/narr/assets.rst b/docs/narr/assets.rst index bad666066..22b38c929 100644 --- a/docs/narr/assets.rst +++ b/docs/narr/assets.rst @@ -380,7 +380,7 @@ do so, do things "by hand". First define the view callable. The above bit of code within ``favicon_view`` computes "here", which is a path relative to the Python file in which the function is defined. It then uses the Python ``open`` function to obtain a file handle to a file within -"here" named ``static``, and returns a :class:`pyramid.response.Fileresponse` +"here" named ``static``, and returns a :class:`pyramid.response.FileResponse` using the file path as the response's ``path`` argument and the request as the response's ``request`` argument. :class:`pyramid.response.FileResponse` will serve the file as quickly as possible when it's used this way. It makes -- cgit v1.2.3 From 3b9e5f1df23e42eabfc41e8726c27a7227230b61 Mon Sep 17 00:00:00 2001 From: Chris McDonough Date: Thu, 23 Feb 2012 20:42:57 -0500 Subject: fix --- docs/narr/assets.rst | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) (limited to 'docs/narr/assets.rst') diff --git a/docs/narr/assets.rst b/docs/narr/assets.rst index 22b38c929..e8e915297 100644 --- a/docs/narr/assets.rst +++ b/docs/narr/assets.rst @@ -379,13 +379,12 @@ do so, do things "by hand". First define the view callable. The above bit of code within ``favicon_view`` computes "here", which is a path relative to the Python file in which the function is defined. It then -uses the Python ``open`` function to obtain a file handle to a file within -"here" named ``static``, and returns a :class:`pyramid.response.FileResponse` -using the file path as the response's ``path`` argument and the request as -the response's ``request`` argument. :class:`pyramid.response.FileResponse` -will serve the file as quickly as possible when it's used this way. It makes -sure to set the right content length and content_type too based on the file -extension of the file you pass. +creates a :class:`pyramid.response.FileResponse` using the file path as the +response's ``path`` argument and the request as the response's ``request`` +argument. :class:`pyramid.response.FileResponse` will serve the file as +quickly as possible when it's used this way. It makes sure to set the right +content length and content_type too based on the file extension of the file +you pass. You might register such a view via configuration as a view callable that should be called as the result of a traversal: -- cgit v1.2.3 From 08c2217e7f831379016e1ddee0b5d51eeca53878 Mon Sep 17 00:00:00 2001 From: Tshepang Lekhonkhobe Date: Tue, 1 Jan 2013 23:56:02 +0200 Subject: eliminate repeated "the" words --- docs/narr/assets.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'docs/narr/assets.rst') diff --git a/docs/narr/assets.rst b/docs/narr/assets.rst index e8e915297..7b620548d 100644 --- a/docs/narr/assets.rst +++ b/docs/narr/assets.rst @@ -252,7 +252,7 @@ static assets that live *outside* the :app:`Pyramid` application. This will happen when the :meth:`~pyramid.config.Configurator.add_static_view` API associated with the path fed to :meth:`~pyramid.request.Request.static_url` is a *URL* instead of a view name. For example, the ``name`` argument may be -``http://example.com`` while the the ``path`` given may be +``http://example.com`` while the ``path`` given may be ``mypackage:images``: .. code-block:: python -- cgit v1.2.3 From 2f4bdefd18073c418ae95fe9e5a8c7b2a9d1130e Mon Sep 17 00:00:00 2001 From: Tshepang Lekhonkhobe Date: Sat, 9 Mar 2013 03:06:17 +0200 Subject: capitalize; add term role --- docs/narr/assets.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'docs/narr/assets.rst') diff --git a/docs/narr/assets.rst b/docs/narr/assets.rst index 7b620548d..deaf0ce08 100644 --- a/docs/narr/assets.rst +++ b/docs/narr/assets.rst @@ -323,7 +323,7 @@ its behavior is almost exactly the same once it's configured. ``add_view`` (at least those without a ``route_name``). A :class:`~pyramid.static.static_view` static view cannot be made root-relative when you use traversal unless it's registered as a - :term:`Not Found view`. + :term:`Not Found View`. To serve files within a directory located on your filesystem at ``/path/to/static/dir`` as the result of a "catchall" route hanging from the -- cgit v1.2.3 From 1ad8de2b9032b5a452b75274b8f908645c732e57 Mon Sep 17 00:00:00 2001 From: Tshepang Lekhonkhobe Date: Fri, 22 Mar 2013 17:24:32 +0200 Subject: remove unused ignore-next-block directive --- docs/narr/assets.rst | 6 ------ 1 file changed, 6 deletions(-) (limited to 'docs/narr/assets.rst') diff --git a/docs/narr/assets.rst b/docs/narr/assets.rst index deaf0ce08..99bcb187f 100644 --- a/docs/narr/assets.rst +++ b/docs/narr/assets.rst @@ -50,7 +50,6 @@ application might address the asset using the :term:`asset specification` ``myapp:templates/some_template.pt`` using that API within a ``views.py`` file inside a ``myapp`` package: -.. ignore-next-block .. code-block:: python :linenos: @@ -331,7 +330,6 @@ root that exists at the end of your routing table, create an instance of the :class:`~pyramid.static.static_view` class inside a ``static.py`` file in your application root as below. -.. ignore-next-block .. code-block:: python :linenos: @@ -458,7 +456,6 @@ The ``override_asset`` API An individual call to :meth:`~pyramid.config.Configurator.override_asset` can override a single asset. For example: -.. ignore-next-block .. code-block:: python :linenos: @@ -473,7 +470,6 @@ colon separator in a specification separates the *package name* from the are not specified, the override attempts to resolve every lookup into a package from the directory of another package. For example: -.. ignore-next-block .. code-block:: python :linenos: @@ -482,7 +478,6 @@ package from the directory of another package. For example: Individual subdirectories within a package can also be overridden: -.. ignore-next-block .. code-block:: python :linenos: @@ -511,7 +506,6 @@ construction file resides (or the ``package`` argument to the :class:`~pyramid.config.Configurator` class construction). For example: -.. ignore-next-block .. code-block:: python :linenos: -- cgit v1.2.3 From f8afd1638456fc89bc3d17858f309686b40a40a4 Mon Sep 17 00:00:00 2001 From: thapar Date: Wed, 3 Apr 2013 02:05:36 -0300 Subject: minor typo correction 'prepresents'-->'represents' --- docs/narr/assets.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'docs/narr/assets.rst') diff --git a/docs/narr/assets.rst b/docs/narr/assets.rst index 99bcb187f..09a2b83f2 100644 --- a/docs/narr/assets.rst +++ b/docs/narr/assets.rst @@ -119,7 +119,7 @@ from the ``/var/www/static`` directory of the computer which runs the # config is an instance of pyramid.config.Configurator config.add_static_view(name='static', path='/var/www/static') -The ``name`` prepresents a URL *prefix*. In order for files that live in the +The ``name`` represents a URL *prefix*. In order for files that live in the ``path`` directory to be served, a URL that requests one of them must begin with that prefix. In the example above, ``name`` is ``static``, and ``path`` is ``/var/www/static``. In English, this means that you wish to serve the -- cgit v1.2.3 From f5eb753eebbda6fa55ccc5108fcc325931a17f85 Mon Sep 17 00:00:00 2001 From: Tshepang Lekhonkhobe Date: Fri, 5 Apr 2013 22:56:48 +0200 Subject: fix some cross-references --- docs/narr/assets.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'docs/narr/assets.rst') diff --git a/docs/narr/assets.rst b/docs/narr/assets.rst index 09a2b83f2..26b3e3a92 100644 --- a/docs/narr/assets.rst +++ b/docs/narr/assets.rst @@ -271,7 +271,7 @@ assets which begin with ``mypackage:images`` will be prefixed with # -> http://example.com/images/logo.png Using :meth:`~pyramid.request.Request.static_url` in conjunction with a -:meth:`~pyramid.configuration.Configurator.add_static_view` makes it possible +:meth:`~pyramid.config.Configurator.add_static_view` makes it possible to put static media on a separate webserver during production (if the ``name`` argument to :meth:`~pyramid.config.Configurator.add_static_view` is a URL), while keeping static media package-internal and served by the -- cgit v1.2.3 From ac681bc83778443bcb70b9c1ea370368044614fb Mon Sep 17 00:00:00 2001 From: Michael Merickel Date: Thu, 5 Sep 2013 23:56:46 -0500 Subject: remove chameleon refs from asset specs --- docs/narr/assets.rst | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) (limited to 'docs/narr/assets.rst') diff --git a/docs/narr/assets.rst b/docs/narr/assets.rst index 26b3e3a92..b0a8d18b0 100644 --- a/docs/narr/assets.rst +++ b/docs/narr/assets.rst @@ -227,14 +227,14 @@ API to generate them for you. For example: .. code-block:: python :linenos: - from pyramid.chameleon_zpt import render_template_to_response + from pyramid.renderers import render_to_response def my_view(request): css_url = request.static_url('mypackage:assets/1/foo.css') js_url = request.static_url('mypackage:assets/2/foo.js') - return render_template_to_response('templates/my_template.pt', - css_url = css_url, - js_url = js_url) + return render_to_response('templates/my_template.pt', + dict(css_url=css_url, js_url=js_url), + request=request) If the request "application URL" of the running system is ``http://example.com``, the ``css_url`` generated above would be: @@ -336,7 +336,9 @@ your application root as below. from pyramid.static import static_view static_view = static_view('/path/to/static/dir', use_subpath=True) -.. note:: For better cross-system flexibility, use an :term:`asset +.. note:: + + For better cross-system flexibility, use an :term:`asset specification` as the argument to :class:`~pyramid.static.static_view` instead of a physical absolute filesystem path, e.g. ``mypackage:static`` instead of ``/path/to/mypackage/static``. @@ -432,9 +434,9 @@ feature, a :term:`Configurator` API exists named :meth:`pyramid.config.Configurator.override_asset`. This API allows you to *override* the following kinds of assets defined in any Python package: -- Individual :term:`Chameleon` templates. +- Individual template files. -- A directory containing multiple Chameleon templates. +- A directory containing multiple template files. - Individual static files served up by an instance of the ``pyramid.static.static_view`` helper class. @@ -460,8 +462,8 @@ can override a single asset. For example: :linenos: config.override_asset( - to_override='some.package:templates/mytemplate.pt', - override_with='another.package:othertemplates/anothertemplate.pt') + to_override='some.package:templates/mytemplate.pt', + override_with='another.package:othertemplates/anothertemplate.pt') The string value passed to both ``to_override`` and ``override_with`` sent to the ``override_asset`` API is called an :term:`asset specification`. The -- cgit v1.2.3 From 407b335ed9954c042377fd2e060c36edcd07cf60 Mon Sep 17 00:00:00 2001 From: Michael Merickel Date: Thu, 27 Feb 2014 23:45:24 -0500 Subject: add support for using an absolute path to override an asset fixes #1229 --- docs/narr/assets.rst | 3 +++ 1 file changed, 3 insertions(+) (limited to 'docs/narr/assets.rst') diff --git a/docs/narr/assets.rst b/docs/narr/assets.rst index b0a8d18b0..fec55ce7c 100644 --- a/docs/narr/assets.rst +++ b/docs/narr/assets.rst @@ -526,3 +526,6 @@ files. Any software which uses the :func:`pkg_resources.get_resource_string` APIs will obtain an overridden file when an override is used. +As of Pyramid 1.6, it is also possible to override an asset by supplying an +absolute path to a file or directory. This may be useful if the assets are +not distributed as part of a Python package. -- cgit v1.2.3 From a8eb53fb79981e1b6fb93af3c80a6bdbae7f9d8f Mon Sep 17 00:00:00 2001 From: Chris Rossi Date: Mon, 14 Jul 2014 11:13:28 -0400 Subject: Narrative scifi. --- docs/narr/assets.rst | 65 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 65 insertions(+) (limited to 'docs/narr/assets.rst') diff --git a/docs/narr/assets.rst b/docs/narr/assets.rst index b0a8d18b0..a2976de22 100644 --- a/docs/narr/assets.rst +++ b/docs/narr/assets.rst @@ -286,6 +286,71 @@ the application is being run in development or in production (use a different suggestion for a pattern; any setting name other than ``media_location`` could be used. +.. _cache_busting: + +Cache Busting +------------- + +In order to maximize performance of a web application, you generally want to +limit the number of times a particular client requests the same static asset. +Ideally a client would cache a particular static asset "forever", requiring +it to be sent to the client a single time. The HTTP protocol allows you to +send headers with an HTTP response that can instruct a client to cache a +particular asset for an amount of time. As long as the client has a copy of +the asset in its cache and that cache hasn't expired, the client will use the +cached copy rather than request a new copy from the server. The drawback to +sending cache headers to the client for a static asset is that at some point +the static asset may change, and then you'll want the client to load a new copy +of the asset. Under normal circumstances you'd just need to wait for the +client's cached copy to expire before they get the new version of the static +resource. + +A commonly used workaround to this problem is a technique known as "cache +busting". Cache busting schemes generally involve generating a URL for a +static asset that changes when the static asset changes. This way headers can +be sent along with the static asset instructing the client to cache the asset +for a very long time. When a static asset is changed, the URL used to refer to +it in a web page also changes, so the client sees it as a new resource and +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 +:meth:`~pyramid.config.Configurator.add_static_view`: + +.. code-block:: python + :linenos: + + # config is an instance of pyramid.config.Configurator + config.add_static_view(name='static', path='mypackage:folder/static', + cache_bust='md5') + +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: + +.. 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` + +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 +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`. + +.. note:: + + md5 checksums are cached in RAM so if you change a static resource without + restarting your application, you may still generate URLs with a stale md5 + checksum. + .. index:: single: static assets view -- cgit v1.2.3 From f729a1e7f1efc27a6df1ae0eaca7fdffdd86ec2f Mon Sep 17 00:00:00 2001 From: Chris Rossi Date: Thu, 17 Jul 2014 16:04:28 -0400 Subject: Write the documentation. --- docs/narr/assets.rst | 72 ++++++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 59 insertions(+), 13 deletions(-) (limited to 'docs/narr/assets.rst') 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 -- cgit v1.2.3 From 002da7991f4433e5fd5a07489038a6bd2720a526 Mon Sep 17 00:00:00 2001 From: Chris Rossi Date: Thu, 17 Jul 2014 16:10:52 -0400 Subject: Add index entry. --- docs/narr/assets.rst | 3 +++ 1 file changed, 3 insertions(+) (limited to 'docs/narr/assets.rst') diff --git a/docs/narr/assets.rst b/docs/narr/assets.rst index 97d473761..642211f5b 100644 --- a/docs/narr/assets.rst +++ b/docs/narr/assets.rst @@ -286,6 +286,9 @@ the application is being run in development or in production (use a different suggestion for a pattern; any setting name other than ``media_location`` could be used. +.. index:: + single: Cache Busting + .. _cache_busting: Cache Busting -- cgit v1.2.3 From aa96dda157d39c57c0d2fe8399db0b2175fa83d2 Mon Sep 17 00:00:00 2001 From: Chris Rossi Date: Fri, 18 Jul 2014 17:18:56 -0400 Subject: Take mcdonc's advice. This should be easier for users to understand. --- docs/narr/assets.rst | 41 +++++++++++++++++++++++++++-------------- 1 file changed, 27 insertions(+), 14 deletions(-) (limited to 'docs/narr/assets.rst') diff --git a/docs/narr/assets.rst b/docs/narr/assets.rst index 642211f5b..7987d03a6 100644 --- a/docs/narr/assets.rst +++ b/docs/narr/assets.rst @@ -370,28 +370,18 @@ equivalent to: .. code-block:: python :linenos: - from pyramid.static import ( - Md5AssetTokenGenerator, - PathSegmentCacheBuster) + from pyramid.static import PathSegmentCacheBuster # config is an instance of pyramid.config.Configurator - cachebuster = PathSegmentCacheBuster(Md5AssetTokenGenerator()) config.add_static_view(name='static', path='mypackage:folder/static', - cachebuster=cachebuster) + cachebuster=PathSegmentCacheBuster()) :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. +the query string of the asset's URL. Both of these classes generate md5 +checksums as asset tokens. .. note:: @@ -400,6 +390,29 @@ implementations in the :mod:`~pyramid.static` module. :class:`~pyramid.static.PathSegementCacheBuster` to :class:`~pyramid.static.QueryStringCacheBuster`. +In order to implement your own cache buster, you can write your own class from +scratch which implements the :class:`~pyramid.interfaces.ICacheBuster` +interface. Alternatively you may choose to subclass one of the existing +implementations. One of the most likely scenarios is you'd want to change the +way the asset token is generated. To do this just subclass an existing +implementation and replace the :meth:`~pyramid.interfaces.ICacheBuster.token` +method. Here is an example which just uses a global setting for the asset +token: + +.. code-block:: python + :linenos: + + from pyramid.static import PathSegmentCacheBuster + + class MyCacheBuster(PathSegmentCacheBuster): + + def __init__(self, config): + # config is an instance of pyramid.config.Configurator + self._token = config.registry.settings['myapp.cachebust_token'] + + def token(self, pathspec): + return self._token + .. index:: single: static assets view -- cgit v1.2.3 From 6596304446f8369dfbcf264d143fe85d75832dba Mon Sep 17 00:00:00 2001 From: Chris Rossi Date: Mon, 21 Jul 2014 16:46:35 -0400 Subject: Add 'prevent_cachebuster' setting. --- docs/narr/assets.rst | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) (limited to 'docs/narr/assets.rst') diff --git a/docs/narr/assets.rst b/docs/narr/assets.rst index 7987d03a6..fea3fae48 100644 --- a/docs/narr/assets.rst +++ b/docs/narr/assets.rst @@ -349,6 +349,15 @@ 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. +Disabling the Cache Buster +~~~~~~~~~~~~~~~~~~~~~~~~~~ + +It can be useful in some situations (e.g. development) to globally disable all +configured cache busters without changing calls to +:meth:`~pyramid.config.Configurator.add_static_view`. To do this set the +``PYRAMID_PREVENT_CACHEBUSTER`` environment variable or the +``pyramid.prevent_cachebuster`` configuration value to a true value. + Customizing the Cache Buster ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -387,7 +396,7 @@ checksums as asset tokens. 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.PathSegmentCacheBuster` to :class:`~pyramid.static.QueryStringCacheBuster`. In order to implement your own cache buster, you can write your own class from -- cgit v1.2.3 From 15b979413c700fbc289328b25aaa4ba1c4cbdda9 Mon Sep 17 00:00:00 2001 From: Chris Rossi Date: Thu, 24 Jul 2014 17:13:08 -0400 Subject: cachebuster -> cachebust --- docs/narr/assets.rst | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) (limited to 'docs/narr/assets.rst') diff --git a/docs/narr/assets.rst b/docs/narr/assets.rst index fea3fae48..7fb0ec40b 100644 --- a/docs/narr/assets.rst +++ b/docs/narr/assets.rst @@ -318,7 +318,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, ``cachebuster`` to +assets by passing the optional argument, ``cachebust`` to :meth:`~pyramid.config.Configurator.add_static_view`: .. code-block:: python @@ -326,9 +326,9 @@ assets by passing the optional argument, ``cachebuster`` to # config is an instance of pyramid.config.Configurator config.add_static_view(name='static', path='mypackage:folder/static', - cachebuster=True) + cachebust=True) -Setting the ``cachebuster`` argument instructs :app:`Pyramid` to use a cache +Setting the ``cachebust`` 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: @@ -339,7 +339,7 @@ in the asset's URL: # 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 ``cachebuster`` argument also causes the static view to set +URL. Supplying the ``cachebust`` 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. @@ -355,8 +355,8 @@ Disabling the Cache Buster It can be useful in some situations (e.g. development) to globally disable all configured cache busters without changing calls to :meth:`~pyramid.config.Configurator.add_static_view`. To do this set the -``PYRAMID_PREVENT_CACHEBUSTER`` environment variable or the -``pyramid.prevent_cachebuster`` configuration value to a true value. +``PYRAMID_PREVENT_CACHEBUST`` environment variable or the +``pyramid.prevent_cachebust`` configuration value to a true value. Customizing the Cache Buster ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -368,11 +368,11 @@ Revisiting from the previous section: # config is an instance of pyramid.config.Configurator config.add_static_view(name='static', path='mypackage:folder/static', - cachebuster=True) + cachebust=True) -Setting ``cachebuster`` to ``True`` instructs :app:`Pyramid` to use a default +Setting ``cachebust`` 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, +``cachebust`` may be set to any object that implements the interface, :class:`~pyramid.interfaces.ICacheBuster`. The above configuration is exactly equivalent to: @@ -383,7 +383,7 @@ equivalent to: # config is an instance of pyramid.config.Configurator config.add_static_view(name='static', path='mypackage:folder/static', - cachebuster=PathSegmentCacheBuster()) + cachebust=PathSegmentCacheBuster()) :app:`Pyramid` includes two ready to use cache buster implementations: :class:`~pyramid.static.PathSegmentCacheBuster`, which inserts an asset token -- cgit v1.2.3 From f674a8f691d260d44e0f76e3afecfb15484c45b9 Mon Sep 17 00:00:00 2001 From: Chris Rossi Date: Mon, 28 Jul 2014 17:26:11 -0400 Subject: Mo' features, mo' problems. --- docs/narr/assets.rst | 87 +++++++++++++++++++++++++++++++++++++--------------- 1 file changed, 62 insertions(+), 25 deletions(-) (limited to 'docs/narr/assets.rst') diff --git a/docs/narr/assets.rst b/docs/narr/assets.rst index 7fb0ec40b..33677988d 100644 --- a/docs/narr/assets.rst +++ b/docs/narr/assets.rst @@ -379,25 +379,19 @@ equivalent to: .. code-block:: python :linenos: - from pyramid.static import PathSegmentCacheBuster + from pyramid.static import PathSegmentMd5CacheBuster # config is an instance of pyramid.config.Configurator config.add_static_view(name='static', path='mypackage:folder/static', - cachebust=PathSegmentCacheBuster()) + cachebust=PathSegmentMd5CacheBuster()) -: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 generate md5 -checksums as asset tokens. - -.. 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.PathSegmentCacheBuster` to - :class:`~pyramid.static.QueryStringCacheBuster`. +:app:`Pyramid` includes a handful of ready to use cache buster implementations: +:class:`~pyramid.static.PathSegmentMd5CacheBuster`, which inserts an md5 +checksum token in the path portion of the asset's URL, +:class:`~pyramid.static.QueryStringMd5CacheBuster`, which adds an md5 checksum +token to the query string of the asset's URL, and +:class:`~pyramid.static.QueryStringConstantCacheBuster`, which adds an +arbitrary token you provide to the query string of the asset's URL. In order to implement your own cache buster, you can write your own class from scratch which implements the :class:`~pyramid.interfaces.ICacheBuster` @@ -405,22 +399,65 @@ interface. Alternatively you may choose to subclass one of the existing implementations. One of the most likely scenarios is you'd want to change the way the asset token is generated. To do this just subclass an existing implementation and replace the :meth:`~pyramid.interfaces.ICacheBuster.token` -method. Here is an example which just uses a global setting for the asset -token: +method. Here is an example which just uses Git to get the hash of the +currently checked out code: .. code-block:: python :linenos: - - from pyramid.static import PathSegmentCacheBuster - class MyCacheBuster(PathSegmentCacheBuster): - - def __init__(self, config): - # config is an instance of pyramid.config.Configurator - self._token = config.registry.settings['myapp.cachebust_token'] + import os + import subprocess + from pyramid.static import PathSegmentMd5CacheBuster + + class GitCacheBuster(PathSegmentMd5CacheBuster): + """ + Assuming your code is installed as a Git checkout, as opposed to as an + egg from an egg repository like PYPI, you can use this cachebuster to + get the current commit's SHA1 to use as the cache bust token. + """ + def __init__(self): + here = os.path.dirname(os.path.abspath(__file__)) + self.sha1 = subprocess.check_output( + ['git', 'rev-parse', 'HEAD'], + cwd=here).strip() def token(self, pathspec): - return self._token + return self.sha1 + +Choosing a Cache Buster +~~~~~~~~~~~~~~~~~~~~~~~ + +The default cache buster implementation, +:class:`~pyramid.static.PathSegmentMd5CacheBuster`, works very well assuming +that you're using :app:`Pyramid` to serve your static assets. The md5 checksum +is fine grained enough that browsers should only request new versions of +specific assets that have changed. Many caching HTTP proxies will fail to +cache a resource if the URL contains a query string. In general, therefore, +you should prefer a cache busting strategy which modifies the path segment to +a strategy which adds a query string. + +It is possible, however, that your static assets are being served by another +web server or externally on a CDN. In these cases modifying the path segment +for a static asset URL would cause the external service to fail to find the +asset, causing your customer to get a 404. In these cases you would need to +fall back to a cache buster which adds a query string. It is even possible +that there isn't a copy of your static assets available to the :app:`Pyramid` +application, so a cache busting implementation that generates md5 checksums +would fail since it can't access the assets. In such a case, +:class:`~pyramid.static.QueryStringConstantCacheBuster` is a reasonable +fallback. The following code would set up a cachebuster that just uses the +time at start up as a cachebust token: + +.. code-block:: python + :linenos: + + import time + from pyramid.static import QueryStringConstantCacheBuster + + config.add_static_view( + name='http://mycdn.example.com/', + path='mypackage:static', + cachebust=QueryStringConstantCacheBuster(str(time.time()))) .. index:: single: static assets view -- cgit v1.2.3 From 6b88bdf7680151345debec0c8651f164a149a53a Mon Sep 17 00:00:00 2001 From: Chris McDonough Date: Mon, 28 Jul 2014 21:06:34 -0400 Subject: add versionadded notes --- docs/narr/assets.rst | 2 ++ 1 file changed, 2 insertions(+) (limited to 'docs/narr/assets.rst') diff --git a/docs/narr/assets.rst b/docs/narr/assets.rst index 33677988d..95863848b 100644 --- a/docs/narr/assets.rst +++ b/docs/narr/assets.rst @@ -294,6 +294,8 @@ could be used. Cache Busting ------------- +.. versionadded:: 1.6 + In order to maximize performance of a web application, you generally want to limit the number of times a particular client requests the same static asset. Ideally a client would cache a particular static asset "forever", requiring -- cgit v1.2.3 From b542a4d723e5e994f693884618878186b94fa51c Mon Sep 17 00:00:00 2001 From: Michael Merickel Date: Mon, 17 Nov 2014 01:10:11 -0600 Subject: improve the docs for absolute path overrides --- docs/narr/assets.rst | 65 ++++++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 56 insertions(+), 9 deletions(-) (limited to 'docs/narr/assets.rst') diff --git a/docs/narr/assets.rst b/docs/narr/assets.rst index 74708ff3e..fc908c2b4 100644 --- a/docs/narr/assets.rst +++ b/docs/narr/assets.rst @@ -276,15 +276,62 @@ to put static media on a separate webserver during production (if the ``name`` argument to :meth:`~pyramid.config.Configurator.add_static_view` is a URL), while keeping static media package-internal and served by the development webserver during development (if the ``name`` argument to -:meth:`~pyramid.config.Configurator.add_static_view` is a URL prefix). To -create such a circumstance, we suggest using the -:attr:`pyramid.registry.Registry.settings` API in conjunction with a setting -in the application ``.ini`` file named ``media_location``. Then set the -value of ``media_location`` to either a prefix or a URL depending on whether -the application is being run in development or in production (use a different -``.ini`` file for production than you do for development). This is just a -suggestion for a pattern; any setting name other than ``media_location`` -could be used. +:meth:`~pyramid.config.Configurator.add_static_view` is a URL prefix). + +For example, we may define a :ref:`custom setting ` +named ``media_location`` which we can set to an external URL in production +when our assets are hosted on a CDN. + +.. code-block:: python + :linenos: + + media_location = settings.get('media_location', 'static') + + config = Configurator(settings=settings) + config.add_static_view(path='myapp:static', name=media_location) + +Now we can optionally define the setting in our ini file: + +.. code-block:: ini + :linenos: + + # production.ini + [app:main] + use = egg:myapp#main + + media_location = http://static.example.com/ + +It is also possible to serve assets that live outside of the source by +referring to an absolute path on the filesystem. There are two ways to +accomplish this. + +First, :meth:`~pyramid.config.Configurator.add_static_view` +supports taking an absolute path directly instead of an asset spec. This works +as expected, looking in the file or folder of files and serving them up at +some URL within your application or externally. Unfortunately, this technique +has a drawback that it is not possible to use the +:meth:`~pyramid.request.Request.static_url` method to generate URLs, since it +works based on an asset spec. + +The second approach, available in Pyramid 1.6+, uses the asset overriding +APIs described in the :ref:`overriding_assets_section` section. It is then +possible to configure a "dummy" package which then serves its file or folder +from an absolute path. + +.. code-block:: python + + config.add_static_view(path='myapp:static_images', name='static') + config.override_asset(to_override='myapp:static_images/', + override_with='/abs/path/to/images/') + +From this configuration it is now possible to use +:meth:`~pyramid.request.Request.static_url` to generate URLs to the data +in the folder by doing something like +``request.static_url('myapp:static_images/foo.png')``. While it is not +necessary that the ``static_images`` file or folder actually exist in the +``myapp`` package, it is important that the ``myapp`` portion points to a +valid package. If the folder does exist then the overriden folder is given +priority if the file's name exists in both locations. .. index:: single: Cache Busting -- cgit v1.2.3 From 780889f18d17b86fc12625166a245c7f9947cbe6 Mon Sep 17 00:00:00 2001 From: Michael Merickel Date: Tue, 17 Feb 2015 01:05:04 -0600 Subject: remove the token from the ICacheBuster api This exposes the QueryStringCacheBuster and PathSegmentCacheBuster public APIs alongside the md5-variants. These should be more cleanly subclassed by people wishing to extend their implementations. --- docs/narr/assets.rst | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) (limited to 'docs/narr/assets.rst') diff --git a/docs/narr/assets.rst b/docs/narr/assets.rst index fc908c2b4..d6bc8cbb8 100644 --- a/docs/narr/assets.rst +++ b/docs/narr/assets.rst @@ -446,19 +446,20 @@ In order to implement your own cache buster, you can write your own class from scratch which implements the :class:`~pyramid.interfaces.ICacheBuster` interface. Alternatively you may choose to subclass one of the existing implementations. One of the most likely scenarios is you'd want to change the -way the asset token is generated. To do this just subclass an existing -implementation and replace the :meth:`~pyramid.interfaces.ICacheBuster.token` -method. Here is an example which just uses Git to get the hash of the -currently checked out code: +way the asset token is generated. To do this just subclass either +:class:`~pyramid.static.PathSegmentCacheBuster` or +:class:`~pyramid.static.QueryStringCacheBuster` and define a +``tokenize(pathspec)`` method. Here is an example which just uses Git to get +the hash of the currently checked out code: .. code-block:: python :linenos: import os import subprocess - from pyramid.static import PathSegmentMd5CacheBuster + from pyramid.static import PathSegmentCacheBuster - class GitCacheBuster(PathSegmentMd5CacheBuster): + class GitCacheBuster(PathSegmentCacheBuster): """ Assuming your code is installed as a Git checkout, as opposed to as an egg from an egg repository like PYPI, you can use this cachebuster to @@ -470,7 +471,7 @@ currently checked out code: ['git', 'rev-parse', 'HEAD'], cwd=here).strip() - def token(self, pathspec): + def tokenize(self, pathspec): return self.sha1 Choosing a Cache Buster -- cgit v1.2.3 From f866fa68ffcac3e200e4d530f8c157e5848e60b0 Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Sat, 6 Jun 2015 15:02:47 -0700 Subject: cherry pick 1.6-branch to master --- docs/narr/assets.rst | 87 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 87 insertions(+) (limited to 'docs/narr/assets.rst') diff --git a/docs/narr/assets.rst b/docs/narr/assets.rst index d6bc8cbb8..fc02b3f7d 100644 --- a/docs/narr/assets.rst +++ b/docs/narr/assets.rst @@ -512,6 +512,93 @@ time at start up as a cachebust token: .. index:: single: static assets view +CSS and JavaScript source and cache busting +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Often one needs to refer to images and other static assets inside CSS and +JavaScript files. If cache busting is active, the final static asset URL is +not available until the static assets have been assembled. These URLs cannot +be handwritten. Thus, when having static asset references in CSS and +JavaScript, one needs to perform one of the following tasks. + +* Process the files by using a precompiler which rewrites URLs to their final + cache busted form. + +* Templatize JS and CSS, and call ``request.static_url()`` inside their + template code. + +* Pass static URL references to CSS and JavaScript via other means. + +Below are some simple approaches for CSS and JS programming which consider +asset cache busting. These approaches do not require additional tools or +packages. + +Relative cache busted URLs in CSS ++++++++++++++++++++++++++++++++++ + +Consider a CSS file ``/static/theme/css/site.css`` which contains the +following CSS code. + +.. code-block:: css + + body { + background: url(/static/theme/img/background.jpg); + } + +Any changes to ``background.jpg`` would not appear to the visitor because the +URL path is not cache busted as it is. Instead we would have to construct an +URL to the background image with the default ``PathSegmentCacheBuster`` cache +busting mechanism:: + + https://site/static/1eeb262c717/theme/img/background.jpg + +Every time the image is updated, the URL would need to be changed. It is not +practical to write this non-human readable URL into a CSS file. + +However, the CSS file itself is cache busted and is located under the path for +static assets. This lets us use relative references in our CSS to cache bust +the image. + +.. code-block:: css + + body { + background: url(../img/background.jpg); + } + +The browser would interpret this as having the CSS file hash in URL:: + + https://site/static/ab234b262c71/theme/css/../img/background.jpg + +The downside of this approach is that if the background image changes, one +needs to bump the CSS file. The CSS file hash change signals the caches that +the relative URL to the image in the CSS has been changed. When updating CSS +and related image assets, updates usually happen hand in hand, so this does +not add extra effort to theming workflow. + +Passing cache busted URLs to JavaScript ++++++++++++++++++++++++++++++++++++++++ + +For JavaScript, one can pass static asset URLs as function arguments or +globals. The globals can be generated in page template code, having access to +the ``request.static_url()`` function. + +Below is a simple example of passing a cached busted image URL in the Jinja2 +template language. Put the following code into the ```` section of the +relevant page. + +.. code-block:: html + + + +Then in your main ``site.js`` file put the following code. + +.. code-block:: javascript + + var image = new Image(window.assets.backgroundImage); + .. _advanced_static: Advanced: Serving Static Assets Using a View Callable -- cgit v1.2.3 From d229631e690021222143b72c47fc9a9706a92467 Mon Sep 17 00:00:00 2001 From: David Beitey Date: Thu, 23 Jul 2015 14:00:27 +1000 Subject: Use correct cache argument in cache busting doco Minor correction; it's ``cache_max_age`` rather than ``max_cache_age``. --- docs/narr/assets.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'docs/narr/assets.rst') diff --git a/docs/narr/assets.rst b/docs/narr/assets.rst index fc02b3f7d..1beabe8de 100644 --- a/docs/narr/assets.rst +++ b/docs/narr/assets.rst @@ -390,7 +390,7 @@ in the asset's URL: When the asset changes, so will its md5 checksum, and therefore so will its URL. Supplying the ``cachebust`` 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. +``cache_max_age`` argument is also passed, in which case that value is used. .. note:: -- cgit v1.2.3 From 4a6aac80123afac25cb2c8a86269159e2735a11f Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Tue, 13 Oct 2015 15:43:47 -0700 Subject: minor grammar, add rst directives for versionadded/changed, rewrap 79 cols --- docs/narr/assets.rst | 430 +++++++++++++++++++++++++-------------------------- 1 file changed, 213 insertions(+), 217 deletions(-) (limited to 'docs/narr/assets.rst') diff --git a/docs/narr/assets.rst b/docs/narr/assets.rst index 1beabe8de..4c0013298 100644 --- a/docs/narr/assets.rst +++ b/docs/narr/assets.rst @@ -7,8 +7,8 @@ Static Assets ============= -An :term:`asset` is any file contained within a Python :term:`package` which -is *not* a Python source code file. For example, each of the following is an +An :term:`asset` is any file contained within a Python :term:`package` which is +*not* a Python source code file. For example, each of the following is an asset: - a GIF image file contained within a Python package or contained within any @@ -20,20 +20,20 @@ asset: - a JavaScript source file contained within a Python package or contained within any subdirectory of a Python package. -- A directory within a package that does not have an ``__init__.py`` - in it (if it possessed an ``__init__.py`` it would *be* a package). +- A directory within a package that does not have an ``__init__.py`` in it (if + it possessed an ``__init__.py`` it would *be* a package). - a :term:`Chameleon` or :term:`Mako` template file contained within a Python package. The use of assets is quite common in most web development projects. For example, when you create a :app:`Pyramid` application using one of the -available scaffolds, as described in :ref:`creating_a_project`, the -directory representing the application contains a Python :term:`package`. -Within that Python package, there are directories full of files which are -static assets. For example, there's a ``static`` directory which contains -``.css``, ``.js``, and ``.gif`` files. These asset files are delivered when -a user visits an application URL. +available scaffolds, as described in :ref:`creating_a_project`, the directory +representing the application contains a Python :term:`package`. Within that +Python package, there are directories full of files which are static assets. +For example, there's a ``static`` directory which contains ``.css``, ``.js``, +and ``.gif`` files. These asset files are delivered when a user visits an +application URL. .. index:: single: asset specifications @@ -45,10 +45,10 @@ Understanding Asset Specifications Let's imagine you've created a :app:`Pyramid` application that uses a :term:`Chameleon` ZPT template via the -:func:`pyramid.renderers.render_to_response` API. For example, the -application might address the asset using the :term:`asset specification` -``myapp:templates/some_template.pt`` using that API within a ``views.py`` -file inside a ``myapp`` package: +:func:`pyramid.renderers.render_to_response` API. For example, the application +might address the asset using the :term:`asset specification` +``myapp:templates/some_template.pt`` using that API within a ``views.py`` file +inside a ``myapp`` package: .. code-block:: python :linenos: @@ -66,23 +66,23 @@ two parts: - The *asset name* (``templates/some_template.pt``), relative to the package directory. -The two parts are separated by the colon character. +The two parts are separated by a colon ``:`` character. -:app:`Pyramid` uses the Python :term:`pkg_resources` API to resolve the -package name and asset name to an absolute (operating-system-specific) file -name. It eventually passes this resolved absolute filesystem path to the -Chameleon templating engine, which then uses it to load, parse, and execute -the template file. +:app:`Pyramid` uses the Python :term:`pkg_resources` API to resolve the package +name and asset name to an absolute (operating system-specific) file name. It +eventually passes this resolved absolute filesystem path to the Chameleon +templating engine, which then uses it to load, parse, and execute the template +file. There is a second form of asset specification: a *relative* asset specification. Instead of using an "absolute" asset specification which includes the package name, in certain circumstances you can omit the package name from the specification. For example, you might be able to use ``templates/mytemplate.pt`` instead of ``myapp:templates/some_template.pt``. -Such asset specifications are usually relative to a "current package." The +Such asset specifications are usually relative to a "current package". The "current package" is usually the package which contains the code that *uses* the asset specification. :app:`Pyramid` APIs which accept relative asset -specifications typically describe what the asset is relative to in their +specifications typically describe to what the asset is relative in their individual documentation. .. index:: @@ -96,17 +96,17 @@ Serving Static Assets :app:`Pyramid` makes it possible to serve up static asset files from a directory on a filesystem to an application user's browser. Use the -:meth:`pyramid.config.Configurator.add_static_view` to instruct -:app:`Pyramid` to serve static assets such as JavaScript and CSS files. This -mechanism makes a directory of static files available at a name relative to -the application root URL, e.g. ``/static`` or as an external URL. +:meth:`pyramid.config.Configurator.add_static_view` to instruct :app:`Pyramid` +to serve static assets, such as JavaScript and CSS files. This mechanism makes +a directory of static files available at a name relative to the application +root URL, e.g., ``/static``, or as an external URL. .. note:: - :meth:`~pyramid.config.Configurator.add_static_view` cannot serve a - single file, nor can it serve a directory of static files directly - relative to the root URL of a :app:`Pyramid` application. For these - features, see :ref:`advanced_static`. + :meth:`~pyramid.config.Configurator.add_static_view` cannot serve a single + file, nor can it serve a directory of static files directly relative to the + root URL of a :app:`Pyramid` application. For these features, see + :ref:`advanced_static`. Here's an example of a use of :meth:`~pyramid.config.Configurator.add_static_view` that will serve files up @@ -121,11 +121,11 @@ from the ``/var/www/static`` directory of the computer which runs the The ``name`` represents a URL *prefix*. In order for files that live in the ``path`` directory to be served, a URL that requests one of them must begin -with that prefix. In the example above, ``name`` is ``static``, and ``path`` -is ``/var/www/static``. In English, this means that you wish to serve the -files that live in ``/var/www/static`` as sub-URLs of the ``/static`` URL -prefix. Therefore, the file ``/var/www/static/foo.css`` will be returned -when the user visits your application's URL ``/static/foo.css``. +with that prefix. In the example above, ``name`` is ``static`` and ``path`` is +``/var/www/static``. In English this means that you wish to serve the files +that live in ``/var/www/static`` as sub-URLs of the ``/static`` URL prefix. +Therefore, the file ``/var/www/static/foo.css`` will be returned when the user +visits your application's URL ``/static/foo.css``. A static directory named at ``path`` may contain subdirectories recursively, and any subdirectories may hold files; these will be resolved by the static @@ -134,16 +134,16 @@ view for each particular type of file is dependent upon its file extension. By default, all files made available via :meth:`~pyramid.config.Configurator.add_static_view` are accessible by -completely anonymous users. Simple authorization can be required, however. -To protect a set of static files using a permission, in addition to passing -the required ``name`` and ``path`` arguments, also pass the ``permission`` -keyword argument to :meth:`~pyramid.config.Configurator.add_static_view`. -The value of the ``permission`` argument represents the :term:`permission` -that the user must have relative to the current :term:`context` when the -static view is invoked. A user will be required to possess this permission -to view any of the files represented by ``path`` of the static view. If your -static assets must be protected by a more complex authorization scheme, -see :ref:`advanced_static`. +completely anonymous users. Simple authorization can be required, however. To +protect a set of static files using a permission, in addition to passing the +required ``name`` and ``path`` arguments, also pass the ``permission`` keyword +argument to :meth:`~pyramid.config.Configurator.add_static_view`. The value of +the ``permission`` argument represents the :term:`permission` that the user +must have relative to the current :term:`context` when the static view is +invoked. A user will be required to possess this permission to view any of the +files represented by ``path`` of the static view. If your static assets must +be protected by a more complex authorization scheme, see +:ref:`advanced_static`. Here's another example that uses an :term:`asset specification` instead of an absolute path as the ``path`` argument. To convince @@ -163,14 +163,14 @@ may be a fully qualified :term:`asset specification` or an *absolute path*. Instead of representing a URL prefix, the ``name`` argument of a call to :meth:`~pyramid.config.Configurator.add_static_view` can alternately be a -*URL*. Each of examples we've seen so far have shown usage of the ``name`` -argument as a URL prefix. However, when ``name`` is a *URL*, static assets -can be served from an external webserver. In this mode, the ``name`` is used -as the URL prefix when generating a URL using +*URL*. Each of the examples we've seen so far have shown usage of the ``name`` +argument as a URL prefix. However, when ``name`` is a *URL*, static assets can +be served from an external webserver. In this mode, the ``name`` is used as +the URL prefix when generating a URL using :meth:`pyramid.request.Request.static_url`. -For example, :meth:`~pyramid.config.Configurator.add_static_view` may -be fed a ``name`` argument which is ``http://example.com/images``: +For example, :meth:`~pyramid.config.Configurator.add_static_view` may be fed a +``name`` argument which is ``http://example.com/images``: .. code-block:: python :linenos: @@ -179,15 +179,15 @@ be fed a ``name`` argument which is ``http://example.com/images``: config.add_static_view(name='http://example.com/images', path='mypackage:images') -Because :meth:`~pyramid.config.Configurator.add_static_view` is provided with -a ``name`` argument that is the URL ``http://example.com/images``, subsequent -calls to :meth:`~pyramid.request.Request.static_url` with paths that start -with the ``path`` argument passed to +Because :meth:`~pyramid.config.Configurator.add_static_view` is provided with a +``name`` argument that is the URL ``http://example.com/images``, subsequent +calls to :meth:`~pyramid.request.Request.static_url` with paths that start with +the ``path`` argument passed to :meth:`~pyramid.config.Configurator.add_static_view` will generate a URL -something like ``http://example.com/images/logo.png``. The external -webserver listening on ``example.com`` must be itself configured to respond -properly to such a request. The :meth:`~pyramid.request.Request.static_url` -API is discussed in more detail later in this chapter. +something like ``http://example.com/images/logo.png``. The external webserver +listening on ``example.com`` must be itself configured to respond properly to +such a request. The :meth:`~pyramid.request.Request.static_url` API is +discussed in more detail later in this chapter. .. index:: single: generating static asset urls @@ -199,11 +199,11 @@ API is discussed in more detail later in this chapter. Generating Static Asset URLs ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -When a :meth:`~pyramid.config.Configurator.add_static_view` method is used to +When an :meth:`~pyramid.config.Configurator.add_static_view` method is used to register a static asset directory, a special helper API named :meth:`pyramid.request.Request.static_url` can be used to generate the -appropriate URL for an asset that lives in one of the directories named by -the static registration ``path`` attribute. +appropriate URL for an asset that lives in one of the directories named by the +static registration ``path`` attribute. For example, let's assume you create a set of static declarations like so: @@ -213,12 +213,12 @@ For example, let's assume you create a set of static declarations like so: config.add_static_view(name='static1', path='mypackage:assets/1') config.add_static_view(name='static2', path='mypackage:assets/2') -These declarations create URL-accessible directories which have URLs that -begin with ``/static1`` and ``/static2``, respectively. The assets in the +These declarations create URL-accessible directories which have URLs that begin +with ``/static1`` and ``/static2``, respectively. The assets in the ``assets/1`` directory of the ``mypackage`` package are consulted when a user -visits a URL which begins with ``/static1``, and the assets in the -``assets/2`` directory of the ``mypackage`` package are consulted when a user -visits a URL which begins with ``/static2``. +visits a URL which begins with ``/static1``, and the assets in the ``assets/2`` +directory of the ``mypackage`` package are consulted when a user visits a URL +which begins with ``/static2``. You needn't generate the URLs to static assets "by hand" in such a configuration. Instead, use the :meth:`~pyramid.request.Request.static_url` @@ -238,8 +238,8 @@ API to generate them for you. For example: If the request "application URL" of the running system is ``http://example.com``, the ``css_url`` generated above would be: -``http://example.com/static1/foo.css``. The ``js_url`` generated -above would be ``http://example.com/static2/foo.js``. +``http://example.com/static1/foo.css``. The ``js_url`` generated above would +be ``http://example.com/static2/foo.js``. One benefit of using the :meth:`~pyramid.request.Request.static_url` function rather than constructing static URLs "by hand" is that if you need to change @@ -249,10 +249,9 @@ resolve properly after the rename. URLs may also be generated by :meth:`~pyramid.request.Request.static_url` to static assets that live *outside* the :app:`Pyramid` application. This will happen when the :meth:`~pyramid.config.Configurator.add_static_view` API -associated with the path fed to :meth:`~pyramid.request.Request.static_url` -is a *URL* instead of a view name. For example, the ``name`` argument may be -``http://example.com`` while the ``path`` given may be -``mypackage:images``: +associated with the path fed to :meth:`~pyramid.request.Request.static_url` is +a *URL* instead of a view name. For example, the ``name`` argument may be +``http://example.com`` while the ``path`` given may be ``mypackage:images``: .. code-block:: python :linenos: @@ -260,8 +259,8 @@ is a *URL* instead of a view name. For example, the ``name`` argument may be config.add_static_view(name='http://example.com/images', path='mypackage:images') -Under such a configuration, the URL generated by ``static_url`` for -assets which begin with ``mypackage:images`` will be prefixed with +Under such a configuration, the URL generated by ``static_url`` for assets +which begin with ``mypackage:images`` will be prefixed with ``http://example.com/images``: .. code-block:: python @@ -271,16 +270,16 @@ assets which begin with ``mypackage:images`` will be prefixed with # -> http://example.com/images/logo.png Using :meth:`~pyramid.request.Request.static_url` in conjunction with a -:meth:`~pyramid.config.Configurator.add_static_view` makes it possible -to put static media on a separate webserver during production (if the -``name`` argument to :meth:`~pyramid.config.Configurator.add_static_view` is -a URL), while keeping static media package-internal and served by the -development webserver during development (if the ``name`` argument to +:meth:`~pyramid.config.Configurator.add_static_view` makes it possible to put +static media on a separate webserver during production (if the ``name`` +argument to :meth:`~pyramid.config.Configurator.add_static_view` is a URL), +while keeping static media package-internal and served by the development +webserver during development (if the ``name`` argument to :meth:`~pyramid.config.Configurator.add_static_view` is a URL prefix). For example, we may define a :ref:`custom setting ` -named ``media_location`` which we can set to an external URL in production -when our assets are hosted on a CDN. +named ``media_location`` which we can set to an external URL in production when +our assets are hosted on a CDN. .. code-block:: python :linenos: @@ -305,18 +304,19 @@ It is also possible to serve assets that live outside of the source by referring to an absolute path on the filesystem. There are two ways to accomplish this. -First, :meth:`~pyramid.config.Configurator.add_static_view` -supports taking an absolute path directly instead of an asset spec. This works -as expected, looking in the file or folder of files and serving them up at -some URL within your application or externally. Unfortunately, this technique -has a drawback that it is not possible to use the -:meth:`~pyramid.request.Request.static_url` method to generate URLs, since it -works based on an asset spec. +First, :meth:`~pyramid.config.Configurator.add_static_view` supports taking an +absolute path directly instead of an asset spec. This works as expected, +looking in the file or folder of files and serving them up at some URL within +your application or externally. Unfortunately, this technique has a drawback in +that it is not possible to use the :meth:`~pyramid.request.Request.static_url` +method to generate URLs, since it works based on an asset specification. -The second approach, available in Pyramid 1.6+, uses the asset overriding -APIs described in the :ref:`overriding_assets_section` section. It is then -possible to configure a "dummy" package which then serves its file or folder -from an absolute path. +.. versionadded:: 1.6 + +The second approach, available in Pyramid 1.6+, uses the asset overriding APIs +described in the :ref:`overriding_assets_section` section. It is then possible +to configure a "dummy" package which then serves its file or folder from an +absolute path. .. code-block:: python @@ -325,13 +325,13 @@ from an absolute path. override_with='/abs/path/to/images/') From this configuration it is now possible to use -:meth:`~pyramid.request.Request.static_url` to generate URLs to the data -in the folder by doing something like +:meth:`~pyramid.request.Request.static_url` to generate URLs to the data in the +folder by doing something like ``request.static_url('myapp:static_images/foo.png')``. While it is not necessary that the ``static_images`` file or folder actually exist in the -``myapp`` package, it is important that the ``myapp`` portion points to a -valid package. If the folder does exist then the overriden folder is given -priority if the file's name exists in both locations. +``myapp`` package, it is important that the ``myapp`` portion points to a valid +package. If the folder does exist, then the overriden folder is given priority, +if the file's name exists in both locations. .. index:: single: Cache Busting @@ -343,31 +343,30 @@ Cache Busting .. versionadded:: 1.6 -In order to maximize performance of a web application, you generally want to +In order to maximize performance of a web application, you generally want to limit the number of times a particular client requests the same static asset. -Ideally a client would cache a particular static asset "forever", requiring -it to be sent to the client a single time. The HTTP protocol allows you to -send headers with an HTTP response that can instruct a client to cache a -particular asset for an amount of time. As long as the client has a copy of -the asset in its cache and that cache hasn't expired, the client will use the -cached copy rather than request a new copy from the server. The drawback to -sending cache headers to the client for a static asset is that at some point -the static asset may change, and then you'll want the client to load a new copy -of the asset. Under normal circumstances you'd just need to wait for the -client's cached copy to expire before they get the new version of the static -resource. - -A commonly used workaround to this problem is a technique known as "cache -busting". Cache busting schemes generally involve generating a URL for a +Ideally a client would cache a particular static asset "forever", requiring it +to be sent to the client a single time. The HTTP protocol allows you to send +headers with an HTTP response that can instruct a client to cache a particular +asset for an amount of time. As long as the client has a copy of the asset in +its cache and that cache hasn't expired, the client will use the cached copy +rather than request a new copy from the server. The drawback to sending cache +headers to the client for a static asset is that at some point the static asset +may change, and then you'll want the client to load a new copy of the asset. +Under normal circumstances you'd just need to wait for the client's cached copy +to expire before they get the new version of the static resource. + +A commonly used workaround to this problem is a technique known as "cache +busting". Cache busting schemes generally involve generating a URL for a static asset that changes when the static asset changes. This way headers can be sent along with the static asset instructing the client to cache the asset for a very long time. When a static asset is changed, the URL used to refer to -it in a web page also changes, so the client sees it as a new resource and -requests a copy, regardless of any caching policy set for the resource's old +it in a web page also changes, so the client sees it as a new resource and +requests the asset, 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, ``cachebust`` to +:app:`Pyramid` can be configured to produce cache busting URLs for static +assets by passing the optional argument, ``cachebust`` to :meth:`~pyramid.config.Configurator.add_static_view`: .. code-block:: python @@ -377,7 +376,7 @@ assets by passing the optional argument, ``cachebust`` to config.add_static_view(name='static', path='mypackage:folder/static', cachebust=True) -Setting the ``cachebust`` argument instructs :app:`Pyramid` to use a cache +Setting the ``cachebust`` 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: @@ -385,7 +384,7 @@ in the asset's URL: :linenos: js_url = request.static_url('mypackage:folder/static/js/myapp.js') - # Returns: 'http://www.example.com/static/c9658b3c0a314a1ca21e5988e662a09e/js/myapp.js` + # 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 ``cachebust`` argument also causes the static view to set @@ -394,17 +393,17 @@ headers instructing clients to cache the asset for ten years, unless the .. note:: - md5 checksums are cached in RAM so if you change a static resource without + md5 checksums are cached in RAM, so if you change a static resource without restarting your application, you may still generate URLs with a stale md5 - checksum. + checksum. Disabling the Cache Buster ~~~~~~~~~~~~~~~~~~~~~~~~~~ -It can be useful in some situations (e.g. development) to globally disable all +It can be useful in some situations (e.g., development) to globally disable all configured cache busters without changing calls to -:meth:`~pyramid.config.Configurator.add_static_view`. To do this set the -``PYRAMID_PREVENT_CACHEBUST`` environment variable or the +:meth:`~pyramid.config.Configurator.add_static_view`. To do this set the +``PYRAMID_PREVENT_CACHEBUST`` environment variable or the ``pyramid.prevent_cachebust`` configuration value to a true value. Customizing the Cache Buster @@ -420,8 +419,8 @@ Revisiting from the previous section: cachebust=True) Setting ``cachebust`` to ``True`` instructs :app:`Pyramid` to use a default -cache busting implementation that should work for many situations. The -``cachebust`` may be set to any object that implements the interface, +cache busting implementation that should work for many situations. The +``cachebust`` may be set to any object that implements the interface :class:`~pyramid.interfaces.ICacheBuster`. The above configuration is exactly equivalent to: @@ -440,7 +439,7 @@ checksum token in the path portion of the asset's URL, :class:`~pyramid.static.QueryStringMd5CacheBuster`, which adds an md5 checksum token to the query string of the asset's URL, and :class:`~pyramid.static.QueryStringConstantCacheBuster`, which adds an -arbitrary token you provide to the query string of the asset's URL. +arbitrary token you provide to the query string of the asset's URL. In order to implement your own cache buster, you can write your own class from scratch which implements the :class:`~pyramid.interfaces.ICacheBuster` @@ -461,9 +460,9 @@ the hash of the currently checked out code: class GitCacheBuster(PathSegmentCacheBuster): """ - Assuming your code is installed as a Git checkout, as opposed to as an - egg from an egg repository like PYPI, you can use this cachebuster to - get the current commit's SHA1 to use as the cache bust token. + Assuming your code is installed as a Git checkout, as opposed to an egg + from an egg repository like PYPI, you can use this cachebuster to get + the current commit's SHA1 to use as the cache bust token. """ def __init__(self): here = os.path.dirname(os.path.abspath(__file__)) @@ -477,25 +476,25 @@ the hash of the currently checked out code: Choosing a Cache Buster ~~~~~~~~~~~~~~~~~~~~~~~ -The default cache buster implementation, -:class:`~pyramid.static.PathSegmentMd5CacheBuster`, works very well assuming +The default cache buster implementation, +:class:`~pyramid.static.PathSegmentMd5CacheBuster`, works very well assuming that you're using :app:`Pyramid` to serve your static assets. The md5 checksum -is fine grained enough that browsers should only request new versions of -specific assets that have changed. Many caching HTTP proxies will fail to -cache a resource if the URL contains a query string. In general, therefore, -you should prefer a cache busting strategy which modifies the path segment to -a strategy which adds a query string. +is fine grained enough that browsers should only request new versions of +specific assets that have changed. Many caching HTTP proxies will fail to +cache a resource if the URL contains a query string. In general, therefore, +you should prefer a cache busting strategy which modifies the path segment to a +strategy which adds a query string. It is possible, however, that your static assets are being served by another web server or externally on a CDN. In these cases modifying the path segment for a static asset URL would cause the external service to fail to find the -asset, causing your customer to get a 404. In these cases you would need to -fall back to a cache buster which adds a query string. It is even possible +asset, causing your customer to get a 404. In these cases you would need to +fall back to a cache buster which adds a query string. It is even possible that there isn't a copy of your static assets available to the :app:`Pyramid` application, so a cache busting implementation that generates md5 checksums -would fail since it can't access the assets. In such a case, -:class:`~pyramid.static.QueryStringConstantCacheBuster` is a reasonable -fallback. The following code would set up a cachebuster that just uses the +would fail since it can't access the assets. In such a case, +:class:`~pyramid.static.QueryStringConstantCacheBuster` is a reasonable +fallback. The following code would set up a cachebuster that just uses the time at start up as a cachebust token: .. code-block:: python @@ -516,10 +515,10 @@ CSS and JavaScript source and cache busting ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Often one needs to refer to images and other static assets inside CSS and -JavaScript files. If cache busting is active, the final static asset URL is -not available until the static assets have been assembled. These URLs cannot -be handwritten. Thus, when having static asset references in CSS and -JavaScript, one needs to perform one of the following tasks. +JavaScript files. If cache busting is active, the final static asset URL is not +available until the static assets have been assembled. These URLs cannot be +handwritten. Thus, when having static asset references in CSS and JavaScript, +one needs to perform one of the following tasks. * Process the files by using a precompiler which rewrites URLs to their final cache busted form. @@ -536,8 +535,8 @@ packages. Relative cache busted URLs in CSS +++++++++++++++++++++++++++++++++ -Consider a CSS file ``/static/theme/css/site.css`` which contains the -following CSS code. +Consider a CSS file ``/static/theme/css/site.css`` which contains the following +CSS code. .. code-block:: css @@ -572,8 +571,8 @@ The browser would interpret this as having the CSS file hash in URL:: The downside of this approach is that if the background image changes, one needs to bump the CSS file. The CSS file hash change signals the caches that the relative URL to the image in the CSS has been changed. When updating CSS -and related image assets, updates usually happen hand in hand, so this does -not add extra effort to theming workflow. +and related image assets, updates usually happen hand in hand, so this does not +add extra effort to theming workflow. Passing cache busted URLs to JavaScript +++++++++++++++++++++++++++++++++++++++ @@ -593,7 +592,7 @@ relevant page. "{{ '/theme/img/background.jpg'|static_url() }}"; -Then in your main ``site.js`` file put the following code. +Then in your main ``site.js`` file, put the following code. .. code-block:: javascript @@ -606,13 +605,13 @@ Advanced: Serving Static Assets Using a View Callable For more flexibility, static assets can be served by a :term:`view callable` which you register manually. For example, if you're using :term:`URL -dispatch`, you may want static assets to only be available as a fallback if -no previous route matches. Alternately, you might like to serve a particular +dispatch`, you may want static assets to only be available as a fallback if no +previous route matches. Alternatively, you might like to serve a particular static asset manually, because its download requires authentication. -Note that you cannot use the :meth:`~pyramid.request.Request.static_url` API -to generate URLs against assets made accessible by registering a custom -static view. +Note that you cannot use the :meth:`~pyramid.request.Request.static_url` API to +generate URLs against assets made accessible by registering a custom static +view. Root-Relative Custom Static View (URL Dispatch Only) ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -626,19 +625,19 @@ its behavior is almost exactly the same once it's configured. .. warning:: The following example *will not work* for applications that use - :term:`traversal`, it will only work if you use :term:`URL dispatch` + :term:`traversal`; it will only work if you use :term:`URL dispatch` exclusively. The root-relative route we'll be registering will always be matched before traversal takes place, subverting any views registered via ``add_view`` (at least those without a ``route_name``). A :class:`~pyramid.static.static_view` static view cannot be made - root-relative when you use traversal unless it's registered as a - :term:`Not Found View`. + root-relative when you use traversal unless it's registered as a :term:`Not + Found View`. To serve files within a directory located on your filesystem at ``/path/to/static/dir`` as the result of a "catchall" route hanging from the root that exists at the end of your routing table, create an instance of the -:class:`~pyramid.static.static_view` class inside a ``static.py`` file in -your application root as below. +:class:`~pyramid.static.static_view` class inside a ``static.py`` file in your +application root as below. .. code-block:: python :linenos: @@ -648,10 +647,10 @@ your application root as below. .. note:: - For better cross-system flexibility, use an :term:`asset - specification` as the argument to :class:`~pyramid.static.static_view` - instead of a physical absolute filesystem path, e.g. ``mypackage:static`` - instead of ``/path/to/mypackage/static``. + For better cross-system flexibility, use an :term:`asset specification` as + the argument to :class:`~pyramid.static.static_view` instead of a physical + absolute filesystem path, e.g., ``mypackage:static``, instead of + ``/path/to/mypackage/static``. Subsequently, you may wire the files that are served by this view up to be accessible as ``/`` using a configuration method in your @@ -670,11 +669,11 @@ The special name ``*subpath`` above is used by the :class:`~pyramid.static.static_view` view callable to signify the path of the file relative to the directory you're serving. -Registering A View Callable to Serve a "Static" Asset +Registering a View Callable to Serve a "Static" Asset ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -You can register a simple view callable to serve a single static asset. To -do so, do things "by hand". First define the view callable. +You can register a simple view callable to serve a single static asset. To do +so, do things "by hand". First define the view callable. .. code-block:: python :linenos: @@ -687,17 +686,16 @@ do so, do things "by hand". First define the view callable. icon = os.path.join(here, 'static', 'favicon.ico') return FileResponse(icon, request=request) -The above bit of code within ``favicon_view`` computes "here", which is a -path relative to the Python file in which the function is defined. It then -creates a :class:`pyramid.response.FileResponse` using the file path as the -response's ``path`` argument and the request as the response's ``request`` -argument. :class:`pyramid.response.FileResponse` will serve the file as -quickly as possible when it's used this way. It makes sure to set the right -content length and content_type too based on the file extension of the file -you pass. +The above bit of code within ``favicon_view`` computes "here", which is a path +relative to the Python file in which the function is defined. It then creates +a :class:`pyramid.response.FileResponse` using the file path as the response's +``path`` argument and the request as the response's ``request`` argument. +:class:`pyramid.response.FileResponse` will serve the file as quickly as +possible when it's used this way. It makes sure to set the right content +length and content_type, too, based on the file extension of the file you pass. -You might register such a view via configuration as a view callable that -should be called as the result of a traversal: +You might register such a view via configuration as a view callable that should +be called as the result of a traversal: .. code-block:: python :linenos: @@ -730,13 +728,12 @@ It can often be useful to override specific assets from "outside" a given :app:`Pyramid` application more or less unchanged. However, some specific template file owned by the application might have inappropriate HTML, or some static asset (such as a logo file or some CSS file) might not be appropriate. -You *could* just fork the application entirely, but it's often more -convenient to just override the assets that are inappropriate and reuse the -application "as is". This is particularly true when you reuse some "core" -application over and over again for some set of customers (such as a CMS -application, or some bug tracking application), and you want to make -arbitrary visual modifications to a particular application deployment without -forking the underlying code. +You *could* just fork the application entirely, but it's often more convenient +to just override the assets that are inappropriate and reuse the application +"as is". This is particularly true when you reuse some "core" application over +and over again for some set of customers (such as a CMS application, or some +bug tracking application), and you want to make arbitrary visual modifications +to a particular application deployment without forking the underlying code. To this end, :app:`Pyramid` contains a feature that makes it possible to "override" one asset with one or more other assets. In support of this @@ -754,8 +751,8 @@ feature, a :term:`Configurator` API exists named - A directory of static files served up by an instance of the ``pyramid.static.static_view`` helper class. -- Any other asset (or set of assets) addressed by code that uses the - setuptools :term:`pkg_resources` API. +- Any other asset (or set of assets) addressed by code that uses the setuptools + :term:`pkg_resources` API. .. index:: single: override_asset @@ -765,8 +762,8 @@ feature, a :term:`Configurator` API exists named The ``override_asset`` API ~~~~~~~~~~~~~~~~~~~~~~~~~~ -An individual call to :meth:`~pyramid.config.Configurator.override_asset` -can override a single asset. For example: +An individual call to :meth:`~pyramid.config.Configurator.override_asset` can +override a single asset. For example: .. code-block:: python :linenos: @@ -776,11 +773,11 @@ can override a single asset. For example: override_with='another.package:othertemplates/anothertemplate.pt') The string value passed to both ``to_override`` and ``override_with`` sent to -the ``override_asset`` API is called an :term:`asset specification`. The -colon separator in a specification separates the *package name* from the -*asset name*. The colon and the following asset name are optional. If they -are not specified, the override attempts to resolve every lookup into a -package from the directory of another package. For example: +the ``override_asset`` API is called an :term:`asset specification`. The colon +separator in a specification separates the *package name* from the *asset +name*. The colon and the following asset name are optional. If they are not +specified, the override attempts to resolve every lookup into a package from +the directory of another package. For example: .. code-block:: python :linenos: @@ -796,27 +793,25 @@ Individual subdirectories within a package can also be overridden: config.override_asset(to_override='some.package:templates/', override_with='another.package:othertemplates/') - -If you wish to override a directory with another directory, you *must* -make sure to attach the slash to the end of both the ``to_override`` -specification and the ``override_with`` specification. If you fail to -attach a slash to the end of a specification that points to a directory, -you will get unexpected results. +If you wish to override a directory with another directory, you *must* make +sure to attach the slash to the end of both the ``to_override`` specification +and the ``override_with`` specification. If you fail to attach a slash to the +end of a specification that points to a directory, you will get unexpected +results. You cannot override a directory specification with a file specification, and -vice versa: a startup error will occur if you try. You cannot override an -asset with itself: a startup error will occur if you try. +vice versa; a startup error will occur if you try. You cannot override an +asset with itself; a startup error will occur if you try. Only individual *package* assets may be overridden. Overrides will not -traverse through subpackages within an overridden package. This means that -if you want to override assets for both ``some.package:templates``, and +traverse through subpackages within an overridden package. This means that if +you want to override assets for both ``some.package:templates``, and ``some.package.views:templates``, you will need to register two overrides. -The package name in a specification may start with a dot, meaning that -the package is relative to the package in which the configuration -construction file resides (or the ``package`` argument to the -:class:`~pyramid.config.Configurator` class construction). -For example: +The package name in a specification may start with a dot, meaning that the +package is relative to the package in which the configuration construction file +resides (or the ``package`` argument to the +:class:`~pyramid.config.Configurator` class construction). For example: .. code-block:: python :linenos: @@ -824,18 +819,19 @@ For example: config.override_asset(to_override='.subpackage:templates/', override_with='another.package:templates/') -Multiple calls to ``override_asset`` which name a shared ``to_override`` but -a different ``override_with`` specification can be "stacked" to form a search -path. The first asset that exists in the search path will be used; if no -asset exists in the override path, the original asset is used. +Multiple calls to ``override_asset`` which name a shared ``to_override`` but a +different ``override_with`` specification can be "stacked" to form a search +path. The first asset that exists in the search path will be used; if no asset +exists in the override path, the original asset is used. Asset overrides can actually override assets other than templates and static files. Any software which uses the :func:`pkg_resources.get_resource_filename`, -:func:`pkg_resources.get_resource_stream` or +:func:`pkg_resources.get_resource_stream`, or :func:`pkg_resources.get_resource_string` APIs will obtain an overridden file when an override is used. -As of Pyramid 1.6, it is also possible to override an asset by supplying an -absolute path to a file or directory. This may be useful if the assets are -not distributed as part of a Python package. +.. versionadded:: 1.6 + As of Pyramid 1.6, it is also possible to override an asset by supplying an + absolute path to a file or directory. This may be useful if the assets are + not distributed as part of a Python package. -- cgit v1.2.3 From ba9c42c7594aec80a819b774fb2cf0635cf3aa5a Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Fri, 16 Oct 2015 00:08:13 -0700 Subject: strip trailing whitespace --- docs/narr/assets.rst | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) (limited to 'docs/narr/assets.rst') diff --git a/docs/narr/assets.rst b/docs/narr/assets.rst index 4c0013298..020794062 100644 --- a/docs/narr/assets.rst +++ b/docs/narr/assets.rst @@ -30,7 +30,7 @@ The use of assets is quite common in most web development projects. For example, when you create a :app:`Pyramid` application using one of the available scaffolds, as described in :ref:`creating_a_project`, the directory representing the application contains a Python :term:`package`. Within that -Python package, there are directories full of files which are static assets. +Python package, there are directories full of files which are static assets. For example, there's a ``static`` directory which contains ``.css``, ``.js``, and ``.gif`` files. These asset files are delivered when a user visits an application URL. @@ -123,7 +123,7 @@ The ``name`` represents a URL *prefix*. In order for files that live in the ``path`` directory to be served, a URL that requests one of them must begin with that prefix. In the example above, ``name`` is ``static`` and ``path`` is ``/var/www/static``. In English this means that you wish to serve the files -that live in ``/var/www/static`` as sub-URLs of the ``/static`` URL prefix. +that live in ``/var/www/static`` as sub-URLs of the ``/static`` URL prefix. Therefore, the file ``/var/www/static/foo.css`` will be returned when the user visits your application's URL ``/static/foo.css``. @@ -176,7 +176,7 @@ For example, :meth:`~pyramid.config.Configurator.add_static_view` may be fed a :linenos: # config is an instance of pyramid.config.Configurator - config.add_static_view(name='http://example.com/images', + config.add_static_view(name='http://example.com/images', path='mypackage:images') Because :meth:`~pyramid.config.Configurator.add_static_view` is provided with a @@ -256,7 +256,7 @@ a *URL* instead of a view name. For example, the ``name`` argument may be .. code-block:: python :linenos: - config.add_static_view(name='http://example.com/images', + config.add_static_view(name='http://example.com/images', path='mypackage:images') Under such a configuration, the URL generated by ``static_url`` for assets @@ -391,7 +391,7 @@ URL. Supplying the ``cachebust`` argument also causes the static view to set headers instructing clients to cache the asset for ten years, unless the ``cache_max_age`` argument is also passed, in which case that value is used. -.. note:: +.. note:: md5 checksums are cached in RAM, so if you change a static resource without restarting your application, you may still generate URLs with a stale md5 @@ -472,7 +472,7 @@ the hash of the currently checked out code: def tokenize(self, pathspec): return self.sha1 - + Choosing a Cache Buster ~~~~~~~~~~~~~~~~~~~~~~~ @@ -504,7 +504,7 @@ time at start up as a cachebust token: from pyramid.static import QueryStringConstantCacheBuster config.add_static_view( - name='http://mycdn.example.com/', + name='http://mycdn.example.com/', path='mypackage:static', cachebust=QueryStringConstantCacheBuster(str(time.time()))) -- cgit v1.2.3 From 02011f1f5d3fae6eac0209b5faccc06079dd1b41 Mon Sep 17 00:00:00 2001 From: Michael Merickel Date: Tue, 20 Oct 2015 00:32:14 -0500 Subject: first cut at removing default cache busters --- docs/narr/assets.rst | 80 +++++++++++++++++++++++----------------------------- 1 file changed, 35 insertions(+), 45 deletions(-) (limited to 'docs/narr/assets.rst') diff --git a/docs/narr/assets.rst b/docs/narr/assets.rst index 020794062..397e0258d 100644 --- a/docs/narr/assets.rst +++ b/docs/narr/assets.rst @@ -372,30 +372,38 @@ assets by passing the optional argument, ``cachebust`` to .. code-block:: python :linenos: + import time + from pyramid.static import QueryStringConstantCacheBuster + # config is an instance of pyramid.config.Configurator - config.add_static_view(name='static', path='mypackage:folder/static', - cachebust=True) + config.add_static_view( + name='static', path='mypackage:folder/static', + cachebust=QueryStringConstantCacheBuster(str(int(time.time()))), + ) Setting the ``cachebust`` 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: +busting scheme which adds the curent time for a static asset to the query +string 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/c9658b3c0a314a1ca21e5988e662a09e/js/myapp.js' + # Returns: 'http://www.example.com/static/js/myapp.js?x=1445318121' -When the asset changes, so will its md5 checksum, and therefore so will its -URL. Supplying the ``cachebust`` argument also causes the static view to set -headers instructing clients to cache the asset for ten years, unless the -``cache_max_age`` argument is also passed, in which case that value is used. +When the web server restarts, the time constant will change and therefore so +will its URL. Supplying the ``cachebust`` argument also causes the static +view to set headers instructing clients to cache the asset for ten years, +unless the ``cache_max_age`` argument is also passed, in which case that +value is used. -.. note:: +.. warning:: - md5 checksums are cached in RAM, so if you change a static resource without - restarting your application, you may still generate URLs with a stale md5 - checksum. + Cache busting is an inherently complex topic as it integrates the asset + pipeline and the web application. It is expected and desired that + application authors will write their own cache buster implementations + conforming to the properties of their own asset pipelines. See + :ref:`custom_cache_busters` for information on writing your own. Disabling the Cache Buster ~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -406,40 +414,21 @@ configured cache busters without changing calls to ``PYRAMID_PREVENT_CACHEBUST`` environment variable or the ``pyramid.prevent_cachebust`` configuration value to a true value. +.. _custom_cache_busters: + Customizing the Cache Buster ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -Revisiting from the previous section: - -.. code-block:: python - :linenos: +The ``cachebust`` option to +:meth:`~pyramid.config.Configurator.add_static_view` may be set to any object +that implements the interface :class:`~pyramid.interfaces.ICacheBuster`. - # config is an instance of pyramid.config.Configurator - config.add_static_view(name='static', path='mypackage:folder/static', - cachebust=True) - -Setting ``cachebust`` to ``True`` instructs :app:`Pyramid` to use a default -cache busting implementation that should work for many situations. The -``cachebust`` 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 PathSegmentMd5CacheBuster - - # config is an instance of pyramid.config.Configurator - config.add_static_view(name='static', path='mypackage:folder/static', - cachebust=PathSegmentMd5CacheBuster()) - -:app:`Pyramid` includes a handful of ready to use cache buster implementations: -:class:`~pyramid.static.PathSegmentMd5CacheBuster`, which inserts an md5 -checksum token in the path portion of the asset's URL, -:class:`~pyramid.static.QueryStringMd5CacheBuster`, which adds an md5 checksum -token to the query string of the asset's URL, and +:app:`Pyramid` ships with a very simplistic :class:`~pyramid.static.QueryStringConstantCacheBuster`, which adds an -arbitrary token you provide to the query string of the asset's URL. +arbitrary token you provide to the query string of the asset's URL. This +is almost never what you want in production as it does not allow fine-grained +busting of individual assets. + In order to implement your own cache buster, you can write your own class from scratch which implements the :class:`~pyramid.interfaces.ICacheBuster` @@ -456,15 +445,16 @@ the hash of the currently checked out code: import os import subprocess - from pyramid.static import PathSegmentCacheBuster + from pyramid.static import QueryStringCacheBuster - class GitCacheBuster(PathSegmentCacheBuster): + class GitCacheBuster(QueryStringCacheBuster): """ Assuming your code is installed as a Git checkout, as opposed to an egg from an egg repository like PYPI, you can use this cachebuster to get the current commit's SHA1 to use as the cache bust token. """ - def __init__(self): + def __init__(self, param='x'): + super(GitCacheBuster, self).__init__(param=param) here = os.path.dirname(os.path.abspath(__file__)) self.sha1 = subprocess.check_output( ['git', 'rev-parse', 'HEAD'], -- cgit v1.2.3 From 31f3d86d3bf5db3c4aa5085c7b7a4d6396f29931 Mon Sep 17 00:00:00 2001 From: Michael Merickel Date: Thu, 12 Nov 2015 00:55:38 -0600 Subject: complete cache buster docs using manifest example --- docs/narr/assets.rst | 183 ++++++++++++++++++++++----------------------------- 1 file changed, 77 insertions(+), 106 deletions(-) (limited to 'docs/narr/assets.rst') diff --git a/docs/narr/assets.rst b/docs/narr/assets.rst index 397e0258d..d36fa49c0 100644 --- a/docs/narr/assets.rst +++ b/docs/narr/assets.rst @@ -356,14 +356,14 @@ may change, and then you'll want the client to load a new copy of the asset. Under normal circumstances you'd just need to wait for the client's cached copy to expire before they get the new version of the static resource. -A commonly used workaround to this problem is a technique known as "cache -busting". Cache busting schemes generally involve generating a URL for a -static asset that changes when the static asset changes. This way headers can -be sent along with the static asset instructing the client to cache the asset -for a very long time. When a static asset is changed, the URL used to refer to -it in a web page also changes, so the client sees it as a new resource and -requests the asset, regardless of any caching policy set for the resource's old -URL. +A commonly used workaround to this problem is a technique known as +:term:`cache busting`. Cache busting schemes generally involve generating a +URL for a static asset that changes when the static asset changes. This way +headers can be sent along with the static asset instructing the client to cache +the asset for a very long time. When a static asset is changed, the URL used +to refer to it in a web page also changes, so the client sees it as a new +resource and requests the asset, 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, ``cachebust`` to @@ -397,7 +397,7 @@ view to set headers instructing clients to cache the asset for ten years, unless the ``cache_max_age`` argument is also passed, in which case that value is used. -.. warning:: +.. note:: Cache busting is an inherently complex topic as it integrates the asset pipeline and the web application. It is expected and desired that @@ -429,16 +429,14 @@ arbitrary token you provide to the query string of the asset's URL. This is almost never what you want in production as it does not allow fine-grained busting of individual assets. - In order to implement your own cache buster, you can write your own class from scratch which implements the :class:`~pyramid.interfaces.ICacheBuster` interface. Alternatively you may choose to subclass one of the existing implementations. One of the most likely scenarios is you'd want to change the -way the asset token is generated. To do this just subclass either -:class:`~pyramid.static.PathSegmentCacheBuster` or +way the asset token is generated. To do this just subclass :class:`~pyramid.static.QueryStringCacheBuster` and define a -``tokenize(pathspec)`` method. Here is an example which just uses Git to get -the hash of the currently checked out code: +``tokenize(pathspec)`` method. Here is an example which uses Git to get +the hash of the current commit: .. code-block:: python :linenos: @@ -466,26 +464,60 @@ the hash of the currently checked out code: Choosing a Cache Buster ~~~~~~~~~~~~~~~~~~~~~~~ -The default cache buster implementation, -:class:`~pyramid.static.PathSegmentMd5CacheBuster`, works very well assuming -that you're using :app:`Pyramid` to serve your static assets. The md5 checksum -is fine grained enough that browsers should only request new versions of -specific assets that have changed. Many caching HTTP proxies will fail to -cache a resource if the URL contains a query string. In general, therefore, -you should prefer a cache busting strategy which modifies the path segment to a -strategy which adds a query string. - -It is possible, however, that your static assets are being served by another -web server or externally on a CDN. In these cases modifying the path segment -for a static asset URL would cause the external service to fail to find the -asset, causing your customer to get a 404. In these cases you would need to -fall back to a cache buster which adds a query string. It is even possible -that there isn't a copy of your static assets available to the :app:`Pyramid` -application, so a cache busting implementation that generates md5 checksums -would fail since it can't access the assets. In such a case, -:class:`~pyramid.static.QueryStringConstantCacheBuster` is a reasonable -fallback. The following code would set up a cachebuster that just uses the -time at start up as a cachebust token: +Many caching HTTP proxies will fail to cache a resource if the URL contains +a query string. Therefore, in general, you should prefer a cache busting +strategy which modifies the path segment rather than methods which add a +token to the query string. + +You will need to consider whether the :app:`Pyramid` application will be +serving your static assets, whether you are using an external asset pipeline +to handle rewriting urls internal to the css/javascript, and how fine-grained +do you want the cache busting tokens to be. + +In many cases you will want to host the static assets on another web server +or externally on a CDN. In these cases your :app:`Pyramid` application may not +even have access to a copy of the static assets. In order to cache bust these +assets you will need some information about them. + +If you are using an external asset pipeline to generate your static files you +should consider using the :class:`~pyramid.static.ManifestCacheBuster`. +This cache buster can load a standard JSON formatted file generated by your +pipeline and use it to cache bust the assets. This has many performance +advantages as :app:`Pyramid` does not need to look at the files to generate +any cache busting tokens, but still supports fine-grained per-file tokens. + +Assuming an example ``manifest.json`` like: + +.. code-block:: json + + { + "css/main.css": "css/main-678b7c80.css", + "images/background.png": "images/background-a8169106.png" + } + +The following code would set up a cachebuster: + +.. code-block:: python + :linenos: + + from pyramid.path import AssetResolver + from pyramid.static import ManifestCacheBuster + + resolver = AssetResolver() + manifest = resolver.resolve('myapp:static/manifest.json') + config.add_static_view( + name='http://mycdn.example.com/', + path='mypackage:static', + cachebust=ManifestCacheBuster(manifest.abspath())) + +A simpler approach is to use the +:class:`~pyramid.static.QueryStringConstantCacheBuster` to generate a global +token that will bust all of the assets at once. The advantage of this strategy +is that it is simple and by using the query string there doesn't need to be +any shared information between your application and the static assets. + +The following code would set up a cachebuster that just uses the time at +start up as a cachebust token: .. code-block:: python :linenos: @@ -496,7 +528,7 @@ time at start up as a cachebust token: config.add_static_view( name='http://mycdn.example.com/', path='mypackage:static', - cachebust=QueryStringConstantCacheBuster(str(time.time()))) + cachebust=QueryStringConstantCacheBuster(str(int(time.time())))) .. index:: single: static assets view @@ -508,85 +540,24 @@ Often one needs to refer to images and other static assets inside CSS and JavaScript files. If cache busting is active, the final static asset URL is not available until the static assets have been assembled. These URLs cannot be handwritten. Thus, when having static asset references in CSS and JavaScript, -one needs to perform one of the following tasks. +one needs to perform one of the following tasks: * Process the files by using a precompiler which rewrites URLs to their final - cache busted form. + cache busted form. Then, you can use the + :class:`~pyramid.static.ManifestCacheBuster` to synchronize your asset + pipeline with :app:`Pyramid`, allowing the pipeline to have full control + over the final URLs of your assets. * Templatize JS and CSS, and call ``request.static_url()`` inside their template code. * Pass static URL references to CSS and JavaScript via other means. -Below are some simple approaches for CSS and JS programming which consider -asset cache busting. These approaches do not require additional tools or -packages. - -Relative cache busted URLs in CSS -+++++++++++++++++++++++++++++++++ - -Consider a CSS file ``/static/theme/css/site.css`` which contains the following -CSS code. - -.. code-block:: css - - body { - background: url(/static/theme/img/background.jpg); - } - -Any changes to ``background.jpg`` would not appear to the visitor because the -URL path is not cache busted as it is. Instead we would have to construct an -URL to the background image with the default ``PathSegmentCacheBuster`` cache -busting mechanism:: - - https://site/static/1eeb262c717/theme/img/background.jpg - -Every time the image is updated, the URL would need to be changed. It is not -practical to write this non-human readable URL into a CSS file. - -However, the CSS file itself is cache busted and is located under the path for -static assets. This lets us use relative references in our CSS to cache bust -the image. - -.. code-block:: css - - body { - background: url(../img/background.jpg); - } - -The browser would interpret this as having the CSS file hash in URL:: - - https://site/static/ab234b262c71/theme/css/../img/background.jpg - -The downside of this approach is that if the background image changes, one -needs to bump the CSS file. The CSS file hash change signals the caches that -the relative URL to the image in the CSS has been changed. When updating CSS -and related image assets, updates usually happen hand in hand, so this does not -add extra effort to theming workflow. - -Passing cache busted URLs to JavaScript -+++++++++++++++++++++++++++++++++++++++ - -For JavaScript, one can pass static asset URLs as function arguments or -globals. The globals can be generated in page template code, having access to -the ``request.static_url()`` function. - -Below is a simple example of passing a cached busted image URL in the Jinja2 -template language. Put the following code into the ```` section of the -relevant page. - -.. code-block:: html - - - -Then in your main ``site.js`` file, put the following code. - -.. code-block:: javascript - - var image = new Image(window.assets.backgroundImage); +If your CSS and JavaScript assets use URLs to reference other assets it is +recommended that you implement an external asset pipeline that can rewrite the +generated static files with new URLs containing cache busting tokens. The +machinery inside :app:`Pyramid` will not help with this step as it has very +little knowledge of the asset types your application may use. .. _advanced_static: -- cgit v1.2.3 From 6f4e97603c2562914567a85bf18187299c3b543b Mon Sep 17 00:00:00 2001 From: Michael Merickel Date: Thu, 12 Nov 2015 20:04:28 -0600 Subject: Revert "fix/remove-default-cachebusters" This reverts commit 7410250313f893e5952bb2697324a4d4e3d47d22. This reverts commit cbec33b898efffbfa6acaf91cae45ec0daed4d7a. This reverts commit 345ca3052c395545b90fef9104a16eed5ab051a5, reversing changes made to 47162533af84bb8d26db6d1c9ba1e63d70e9070f. --- docs/narr/assets.rst | 257 +++++++++++++++++++++++++++++---------------------- 1 file changed, 148 insertions(+), 109 deletions(-) (limited to 'docs/narr/assets.rst') diff --git a/docs/narr/assets.rst b/docs/narr/assets.rst index d36fa49c0..020794062 100644 --- a/docs/narr/assets.rst +++ b/docs/narr/assets.rst @@ -356,14 +356,14 @@ may change, and then you'll want the client to load a new copy of the asset. Under normal circumstances you'd just need to wait for the client's cached copy to expire before they get the new version of the static resource. -A commonly used workaround to this problem is a technique known as -:term:`cache busting`. Cache busting schemes generally involve generating a -URL for a static asset that changes when the static asset changes. This way -headers can be sent along with the static asset instructing the client to cache -the asset for a very long time. When a static asset is changed, the URL used -to refer to it in a web page also changes, so the client sees it as a new -resource and requests the asset, regardless of any caching policy set for the -resource's old URL. +A commonly used workaround to this problem is a technique known as "cache +busting". Cache busting schemes generally involve generating a URL for a +static asset that changes when the static asset changes. This way headers can +be sent along with the static asset instructing the client to cache the asset +for a very long time. When a static asset is changed, the URL used to refer to +it in a web page also changes, so the client sees it as a new resource and +requests the asset, 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, ``cachebust`` to @@ -372,38 +372,30 @@ assets by passing the optional argument, ``cachebust`` to .. code-block:: python :linenos: - import time - from pyramid.static import QueryStringConstantCacheBuster - # config is an instance of pyramid.config.Configurator - config.add_static_view( - name='static', path='mypackage:folder/static', - cachebust=QueryStringConstantCacheBuster(str(int(time.time()))), - ) + config.add_static_view(name='static', path='mypackage:folder/static', + cachebust=True) Setting the ``cachebust`` argument instructs :app:`Pyramid` to use a cache -busting scheme which adds the curent time for a static asset to the query -string in the asset's URL: +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?x=1445318121' + # Returns: 'http://www.example.com/static/c9658b3c0a314a1ca21e5988e662a09e/js/myapp.js' -When the web server restarts, the time constant will change and therefore so -will its URL. Supplying the ``cachebust`` argument also causes the static -view to set headers instructing clients to cache the asset for ten years, -unless the ``cache_max_age`` argument is also passed, in which case that -value is used. +When the asset changes, so will its md5 checksum, and therefore so will its +URL. Supplying the ``cachebust`` argument also causes the static view to set +headers instructing clients to cache the asset for ten years, unless the +``cache_max_age`` argument is also passed, in which case that value is used. .. note:: - Cache busting is an inherently complex topic as it integrates the asset - pipeline and the web application. It is expected and desired that - application authors will write their own cache buster implementations - conforming to the properties of their own asset pipelines. See - :ref:`custom_cache_busters` for information on writing your own. + md5 checksums are cached in RAM, so if you change a static resource without + restarting your application, you may still generate URLs with a stale md5 + checksum. Disabling the Cache Buster ~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -414,45 +406,65 @@ configured cache busters without changing calls to ``PYRAMID_PREVENT_CACHEBUST`` environment variable or the ``pyramid.prevent_cachebust`` configuration value to a true value. -.. _custom_cache_busters: - Customizing the Cache Buster ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -The ``cachebust`` option to -:meth:`~pyramid.config.Configurator.add_static_view` may be set to any object -that implements the interface :class:`~pyramid.interfaces.ICacheBuster`. +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', + cachebust=True) + +Setting ``cachebust`` to ``True`` instructs :app:`Pyramid` to use a default +cache busting implementation that should work for many situations. The +``cachebust`` 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: -:app:`Pyramid` ships with a very simplistic + from pyramid.static import PathSegmentMd5CacheBuster + + # config is an instance of pyramid.config.Configurator + config.add_static_view(name='static', path='mypackage:folder/static', + cachebust=PathSegmentMd5CacheBuster()) + +:app:`Pyramid` includes a handful of ready to use cache buster implementations: +:class:`~pyramid.static.PathSegmentMd5CacheBuster`, which inserts an md5 +checksum token in the path portion of the asset's URL, +:class:`~pyramid.static.QueryStringMd5CacheBuster`, which adds an md5 checksum +token to the query string of the asset's URL, and :class:`~pyramid.static.QueryStringConstantCacheBuster`, which adds an -arbitrary token you provide to the query string of the asset's URL. This -is almost never what you want in production as it does not allow fine-grained -busting of individual assets. +arbitrary token you provide to the query string of the asset's URL. In order to implement your own cache buster, you can write your own class from scratch which implements the :class:`~pyramid.interfaces.ICacheBuster` interface. Alternatively you may choose to subclass one of the existing implementations. One of the most likely scenarios is you'd want to change the -way the asset token is generated. To do this just subclass +way the asset token is generated. To do this just subclass either +:class:`~pyramid.static.PathSegmentCacheBuster` or :class:`~pyramid.static.QueryStringCacheBuster` and define a -``tokenize(pathspec)`` method. Here is an example which uses Git to get -the hash of the current commit: +``tokenize(pathspec)`` method. Here is an example which just uses Git to get +the hash of the currently checked out code: .. code-block:: python :linenos: import os import subprocess - from pyramid.static import QueryStringCacheBuster + from pyramid.static import PathSegmentCacheBuster - class GitCacheBuster(QueryStringCacheBuster): + class GitCacheBuster(PathSegmentCacheBuster): """ Assuming your code is installed as a Git checkout, as opposed to an egg from an egg repository like PYPI, you can use this cachebuster to get the current commit's SHA1 to use as the cache bust token. """ - def __init__(self, param='x'): - super(GitCacheBuster, self).__init__(param=param) + def __init__(self): here = os.path.dirname(os.path.abspath(__file__)) self.sha1 = subprocess.check_output( ['git', 'rev-parse', 'HEAD'], @@ -464,60 +476,26 @@ the hash of the current commit: Choosing a Cache Buster ~~~~~~~~~~~~~~~~~~~~~~~ -Many caching HTTP proxies will fail to cache a resource if the URL contains -a query string. Therefore, in general, you should prefer a cache busting -strategy which modifies the path segment rather than methods which add a -token to the query string. - -You will need to consider whether the :app:`Pyramid` application will be -serving your static assets, whether you are using an external asset pipeline -to handle rewriting urls internal to the css/javascript, and how fine-grained -do you want the cache busting tokens to be. - -In many cases you will want to host the static assets on another web server -or externally on a CDN. In these cases your :app:`Pyramid` application may not -even have access to a copy of the static assets. In order to cache bust these -assets you will need some information about them. - -If you are using an external asset pipeline to generate your static files you -should consider using the :class:`~pyramid.static.ManifestCacheBuster`. -This cache buster can load a standard JSON formatted file generated by your -pipeline and use it to cache bust the assets. This has many performance -advantages as :app:`Pyramid` does not need to look at the files to generate -any cache busting tokens, but still supports fine-grained per-file tokens. - -Assuming an example ``manifest.json`` like: - -.. code-block:: json - - { - "css/main.css": "css/main-678b7c80.css", - "images/background.png": "images/background-a8169106.png" - } - -The following code would set up a cachebuster: - -.. code-block:: python - :linenos: - - from pyramid.path import AssetResolver - from pyramid.static import ManifestCacheBuster - - resolver = AssetResolver() - manifest = resolver.resolve('myapp:static/manifest.json') - config.add_static_view( - name='http://mycdn.example.com/', - path='mypackage:static', - cachebust=ManifestCacheBuster(manifest.abspath())) - -A simpler approach is to use the -:class:`~pyramid.static.QueryStringConstantCacheBuster` to generate a global -token that will bust all of the assets at once. The advantage of this strategy -is that it is simple and by using the query string there doesn't need to be -any shared information between your application and the static assets. - -The following code would set up a cachebuster that just uses the time at -start up as a cachebust token: +The default cache buster implementation, +:class:`~pyramid.static.PathSegmentMd5CacheBuster`, works very well assuming +that you're using :app:`Pyramid` to serve your static assets. The md5 checksum +is fine grained enough that browsers should only request new versions of +specific assets that have changed. Many caching HTTP proxies will fail to +cache a resource if the URL contains a query string. In general, therefore, +you should prefer a cache busting strategy which modifies the path segment to a +strategy which adds a query string. + +It is possible, however, that your static assets are being served by another +web server or externally on a CDN. In these cases modifying the path segment +for a static asset URL would cause the external service to fail to find the +asset, causing your customer to get a 404. In these cases you would need to +fall back to a cache buster which adds a query string. It is even possible +that there isn't a copy of your static assets available to the :app:`Pyramid` +application, so a cache busting implementation that generates md5 checksums +would fail since it can't access the assets. In such a case, +:class:`~pyramid.static.QueryStringConstantCacheBuster` is a reasonable +fallback. The following code would set up a cachebuster that just uses the +time at start up as a cachebust token: .. code-block:: python :linenos: @@ -528,7 +506,7 @@ start up as a cachebust token: config.add_static_view( name='http://mycdn.example.com/', path='mypackage:static', - cachebust=QueryStringConstantCacheBuster(str(int(time.time())))) + cachebust=QueryStringConstantCacheBuster(str(time.time()))) .. index:: single: static assets view @@ -540,24 +518,85 @@ Often one needs to refer to images and other static assets inside CSS and JavaScript files. If cache busting is active, the final static asset URL is not available until the static assets have been assembled. These URLs cannot be handwritten. Thus, when having static asset references in CSS and JavaScript, -one needs to perform one of the following tasks: +one needs to perform one of the following tasks. * Process the files by using a precompiler which rewrites URLs to their final - cache busted form. Then, you can use the - :class:`~pyramid.static.ManifestCacheBuster` to synchronize your asset - pipeline with :app:`Pyramid`, allowing the pipeline to have full control - over the final URLs of your assets. + cache busted form. * Templatize JS and CSS, and call ``request.static_url()`` inside their template code. * Pass static URL references to CSS and JavaScript via other means. -If your CSS and JavaScript assets use URLs to reference other assets it is -recommended that you implement an external asset pipeline that can rewrite the -generated static files with new URLs containing cache busting tokens. The -machinery inside :app:`Pyramid` will not help with this step as it has very -little knowledge of the asset types your application may use. +Below are some simple approaches for CSS and JS programming which consider +asset cache busting. These approaches do not require additional tools or +packages. + +Relative cache busted URLs in CSS ++++++++++++++++++++++++++++++++++ + +Consider a CSS file ``/static/theme/css/site.css`` which contains the following +CSS code. + +.. code-block:: css + + body { + background: url(/static/theme/img/background.jpg); + } + +Any changes to ``background.jpg`` would not appear to the visitor because the +URL path is not cache busted as it is. Instead we would have to construct an +URL to the background image with the default ``PathSegmentCacheBuster`` cache +busting mechanism:: + + https://site/static/1eeb262c717/theme/img/background.jpg + +Every time the image is updated, the URL would need to be changed. It is not +practical to write this non-human readable URL into a CSS file. + +However, the CSS file itself is cache busted and is located under the path for +static assets. This lets us use relative references in our CSS to cache bust +the image. + +.. code-block:: css + + body { + background: url(../img/background.jpg); + } + +The browser would interpret this as having the CSS file hash in URL:: + + https://site/static/ab234b262c71/theme/css/../img/background.jpg + +The downside of this approach is that if the background image changes, one +needs to bump the CSS file. The CSS file hash change signals the caches that +the relative URL to the image in the CSS has been changed. When updating CSS +and related image assets, updates usually happen hand in hand, so this does not +add extra effort to theming workflow. + +Passing cache busted URLs to JavaScript ++++++++++++++++++++++++++++++++++++++++ + +For JavaScript, one can pass static asset URLs as function arguments or +globals. The globals can be generated in page template code, having access to +the ``request.static_url()`` function. + +Below is a simple example of passing a cached busted image URL in the Jinja2 +template language. Put the following code into the ```` section of the +relevant page. + +.. code-block:: html + + + +Then in your main ``site.js`` file, put the following code. + +.. code-block:: javascript + + var image = new Image(window.assets.backgroundImage); .. _advanced_static: -- cgit v1.2.3 From 3a41196208c7fd78cfb177bb5105c6a702436b78 Mon Sep 17 00:00:00 2001 From: Michael Merickel Date: Tue, 20 Oct 2015 00:32:14 -0500 Subject: update cache buster prose and add ManifestCacheBuster redux of #2013 --- docs/narr/assets.rst | 257 ++++++++++++++++++++++----------------------------- 1 file changed, 109 insertions(+), 148 deletions(-) (limited to 'docs/narr/assets.rst') diff --git a/docs/narr/assets.rst b/docs/narr/assets.rst index 020794062..d36fa49c0 100644 --- a/docs/narr/assets.rst +++ b/docs/narr/assets.rst @@ -356,14 +356,14 @@ may change, and then you'll want the client to load a new copy of the asset. Under normal circumstances you'd just need to wait for the client's cached copy to expire before they get the new version of the static resource. -A commonly used workaround to this problem is a technique known as "cache -busting". Cache busting schemes generally involve generating a URL for a -static asset that changes when the static asset changes. This way headers can -be sent along with the static asset instructing the client to cache the asset -for a very long time. When a static asset is changed, the URL used to refer to -it in a web page also changes, so the client sees it as a new resource and -requests the asset, regardless of any caching policy set for the resource's old -URL. +A commonly used workaround to this problem is a technique known as +:term:`cache busting`. Cache busting schemes generally involve generating a +URL for a static asset that changes when the static asset changes. This way +headers can be sent along with the static asset instructing the client to cache +the asset for a very long time. When a static asset is changed, the URL used +to refer to it in a web page also changes, so the client sees it as a new +resource and requests the asset, 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, ``cachebust`` to @@ -372,30 +372,38 @@ assets by passing the optional argument, ``cachebust`` to .. code-block:: python :linenos: + import time + from pyramid.static import QueryStringConstantCacheBuster + # config is an instance of pyramid.config.Configurator - config.add_static_view(name='static', path='mypackage:folder/static', - cachebust=True) + config.add_static_view( + name='static', path='mypackage:folder/static', + cachebust=QueryStringConstantCacheBuster(str(int(time.time()))), + ) Setting the ``cachebust`` 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: +busting scheme which adds the curent time for a static asset to the query +string 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/c9658b3c0a314a1ca21e5988e662a09e/js/myapp.js' + # Returns: 'http://www.example.com/static/js/myapp.js?x=1445318121' -When the asset changes, so will its md5 checksum, and therefore so will its -URL. Supplying the ``cachebust`` argument also causes the static view to set -headers instructing clients to cache the asset for ten years, unless the -``cache_max_age`` argument is also passed, in which case that value is used. +When the web server restarts, the time constant will change and therefore so +will its URL. Supplying the ``cachebust`` argument also causes the static +view to set headers instructing clients to cache the asset for ten years, +unless the ``cache_max_age`` argument is also passed, in which case that +value is used. .. note:: - md5 checksums are cached in RAM, so if you change a static resource without - restarting your application, you may still generate URLs with a stale md5 - checksum. + Cache busting is an inherently complex topic as it integrates the asset + pipeline and the web application. It is expected and desired that + application authors will write their own cache buster implementations + conforming to the properties of their own asset pipelines. See + :ref:`custom_cache_busters` for information on writing your own. Disabling the Cache Buster ~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -406,65 +414,45 @@ configured cache busters without changing calls to ``PYRAMID_PREVENT_CACHEBUST`` environment variable or the ``pyramid.prevent_cachebust`` configuration value to a true value. +.. _custom_cache_busters: + 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', - cachebust=True) - -Setting ``cachebust`` to ``True`` instructs :app:`Pyramid` to use a default -cache busting implementation that should work for many situations. The -``cachebust`` 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: +The ``cachebust`` option to +:meth:`~pyramid.config.Configurator.add_static_view` may be set to any object +that implements the interface :class:`~pyramid.interfaces.ICacheBuster`. - from pyramid.static import PathSegmentMd5CacheBuster - - # config is an instance of pyramid.config.Configurator - config.add_static_view(name='static', path='mypackage:folder/static', - cachebust=PathSegmentMd5CacheBuster()) - -:app:`Pyramid` includes a handful of ready to use cache buster implementations: -:class:`~pyramid.static.PathSegmentMd5CacheBuster`, which inserts an md5 -checksum token in the path portion of the asset's URL, -:class:`~pyramid.static.QueryStringMd5CacheBuster`, which adds an md5 checksum -token to the query string of the asset's URL, and +:app:`Pyramid` ships with a very simplistic :class:`~pyramid.static.QueryStringConstantCacheBuster`, which adds an -arbitrary token you provide to the query string of the asset's URL. +arbitrary token you provide to the query string of the asset's URL. This +is almost never what you want in production as it does not allow fine-grained +busting of individual assets. In order to implement your own cache buster, you can write your own class from scratch which implements the :class:`~pyramid.interfaces.ICacheBuster` interface. Alternatively you may choose to subclass one of the existing implementations. One of the most likely scenarios is you'd want to change the -way the asset token is generated. To do this just subclass either -:class:`~pyramid.static.PathSegmentCacheBuster` or +way the asset token is generated. To do this just subclass :class:`~pyramid.static.QueryStringCacheBuster` and define a -``tokenize(pathspec)`` method. Here is an example which just uses Git to get -the hash of the currently checked out code: +``tokenize(pathspec)`` method. Here is an example which uses Git to get +the hash of the current commit: .. code-block:: python :linenos: import os import subprocess - from pyramid.static import PathSegmentCacheBuster + from pyramid.static import QueryStringCacheBuster - class GitCacheBuster(PathSegmentCacheBuster): + class GitCacheBuster(QueryStringCacheBuster): """ Assuming your code is installed as a Git checkout, as opposed to an egg from an egg repository like PYPI, you can use this cachebuster to get the current commit's SHA1 to use as the cache bust token. """ - def __init__(self): + def __init__(self, param='x'): + super(GitCacheBuster, self).__init__(param=param) here = os.path.dirname(os.path.abspath(__file__)) self.sha1 = subprocess.check_output( ['git', 'rev-parse', 'HEAD'], @@ -476,26 +464,60 @@ the hash of the currently checked out code: Choosing a Cache Buster ~~~~~~~~~~~~~~~~~~~~~~~ -The default cache buster implementation, -:class:`~pyramid.static.PathSegmentMd5CacheBuster`, works very well assuming -that you're using :app:`Pyramid` to serve your static assets. The md5 checksum -is fine grained enough that browsers should only request new versions of -specific assets that have changed. Many caching HTTP proxies will fail to -cache a resource if the URL contains a query string. In general, therefore, -you should prefer a cache busting strategy which modifies the path segment to a -strategy which adds a query string. - -It is possible, however, that your static assets are being served by another -web server or externally on a CDN. In these cases modifying the path segment -for a static asset URL would cause the external service to fail to find the -asset, causing your customer to get a 404. In these cases you would need to -fall back to a cache buster which adds a query string. It is even possible -that there isn't a copy of your static assets available to the :app:`Pyramid` -application, so a cache busting implementation that generates md5 checksums -would fail since it can't access the assets. In such a case, -:class:`~pyramid.static.QueryStringConstantCacheBuster` is a reasonable -fallback. The following code would set up a cachebuster that just uses the -time at start up as a cachebust token: +Many caching HTTP proxies will fail to cache a resource if the URL contains +a query string. Therefore, in general, you should prefer a cache busting +strategy which modifies the path segment rather than methods which add a +token to the query string. + +You will need to consider whether the :app:`Pyramid` application will be +serving your static assets, whether you are using an external asset pipeline +to handle rewriting urls internal to the css/javascript, and how fine-grained +do you want the cache busting tokens to be. + +In many cases you will want to host the static assets on another web server +or externally on a CDN. In these cases your :app:`Pyramid` application may not +even have access to a copy of the static assets. In order to cache bust these +assets you will need some information about them. + +If you are using an external asset pipeline to generate your static files you +should consider using the :class:`~pyramid.static.ManifestCacheBuster`. +This cache buster can load a standard JSON formatted file generated by your +pipeline and use it to cache bust the assets. This has many performance +advantages as :app:`Pyramid` does not need to look at the files to generate +any cache busting tokens, but still supports fine-grained per-file tokens. + +Assuming an example ``manifest.json`` like: + +.. code-block:: json + + { + "css/main.css": "css/main-678b7c80.css", + "images/background.png": "images/background-a8169106.png" + } + +The following code would set up a cachebuster: + +.. code-block:: python + :linenos: + + from pyramid.path import AssetResolver + from pyramid.static import ManifestCacheBuster + + resolver = AssetResolver() + manifest = resolver.resolve('myapp:static/manifest.json') + config.add_static_view( + name='http://mycdn.example.com/', + path='mypackage:static', + cachebust=ManifestCacheBuster(manifest.abspath())) + +A simpler approach is to use the +:class:`~pyramid.static.QueryStringConstantCacheBuster` to generate a global +token that will bust all of the assets at once. The advantage of this strategy +is that it is simple and by using the query string there doesn't need to be +any shared information between your application and the static assets. + +The following code would set up a cachebuster that just uses the time at +start up as a cachebust token: .. code-block:: python :linenos: @@ -506,7 +528,7 @@ time at start up as a cachebust token: config.add_static_view( name='http://mycdn.example.com/', path='mypackage:static', - cachebust=QueryStringConstantCacheBuster(str(time.time()))) + cachebust=QueryStringConstantCacheBuster(str(int(time.time())))) .. index:: single: static assets view @@ -518,85 +540,24 @@ Often one needs to refer to images and other static assets inside CSS and JavaScript files. If cache busting is active, the final static asset URL is not available until the static assets have been assembled. These URLs cannot be handwritten. Thus, when having static asset references in CSS and JavaScript, -one needs to perform one of the following tasks. +one needs to perform one of the following tasks: * Process the files by using a precompiler which rewrites URLs to their final - cache busted form. + cache busted form. Then, you can use the + :class:`~pyramid.static.ManifestCacheBuster` to synchronize your asset + pipeline with :app:`Pyramid`, allowing the pipeline to have full control + over the final URLs of your assets. * Templatize JS and CSS, and call ``request.static_url()`` inside their template code. * Pass static URL references to CSS and JavaScript via other means. -Below are some simple approaches for CSS and JS programming which consider -asset cache busting. These approaches do not require additional tools or -packages. - -Relative cache busted URLs in CSS -+++++++++++++++++++++++++++++++++ - -Consider a CSS file ``/static/theme/css/site.css`` which contains the following -CSS code. - -.. code-block:: css - - body { - background: url(/static/theme/img/background.jpg); - } - -Any changes to ``background.jpg`` would not appear to the visitor because the -URL path is not cache busted as it is. Instead we would have to construct an -URL to the background image with the default ``PathSegmentCacheBuster`` cache -busting mechanism:: - - https://site/static/1eeb262c717/theme/img/background.jpg - -Every time the image is updated, the URL would need to be changed. It is not -practical to write this non-human readable URL into a CSS file. - -However, the CSS file itself is cache busted and is located under the path for -static assets. This lets us use relative references in our CSS to cache bust -the image. - -.. code-block:: css - - body { - background: url(../img/background.jpg); - } - -The browser would interpret this as having the CSS file hash in URL:: - - https://site/static/ab234b262c71/theme/css/../img/background.jpg - -The downside of this approach is that if the background image changes, one -needs to bump the CSS file. The CSS file hash change signals the caches that -the relative URL to the image in the CSS has been changed. When updating CSS -and related image assets, updates usually happen hand in hand, so this does not -add extra effort to theming workflow. - -Passing cache busted URLs to JavaScript -+++++++++++++++++++++++++++++++++++++++ - -For JavaScript, one can pass static asset URLs as function arguments or -globals. The globals can be generated in page template code, having access to -the ``request.static_url()`` function. - -Below is a simple example of passing a cached busted image URL in the Jinja2 -template language. Put the following code into the ```` section of the -relevant page. - -.. code-block:: html - - - -Then in your main ``site.js`` file, put the following code. - -.. code-block:: javascript - - var image = new Image(window.assets.backgroundImage); +If your CSS and JavaScript assets use URLs to reference other assets it is +recommended that you implement an external asset pipeline that can rewrite the +generated static files with new URLs containing cache busting tokens. The +machinery inside :app:`Pyramid` will not help with this step as it has very +little knowledge of the asset types your application may use. .. _advanced_static: -- cgit v1.2.3 From 104870609e23edd1dba4d64869a068e883767552 Mon Sep 17 00:00:00 2001 From: Michael Merickel Date: Sun, 15 Nov 2015 21:59:56 -0600 Subject: update docs to use asset specs with ManifestCacheBuster --- docs/narr/assets.rst | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) (limited to 'docs/narr/assets.rst') diff --git a/docs/narr/assets.rst b/docs/narr/assets.rst index d36fa49c0..0f819570c 100644 --- a/docs/narr/assets.rst +++ b/docs/narr/assets.rst @@ -500,15 +500,12 @@ The following code would set up a cachebuster: .. code-block:: python :linenos: - from pyramid.path import AssetResolver from pyramid.static import ManifestCacheBuster - resolver = AssetResolver() - manifest = resolver.resolve('myapp:static/manifest.json') config.add_static_view( name='http://mycdn.example.com/', path='mypackage:static', - cachebust=ManifestCacheBuster(manifest.abspath())) + cachebust=ManifestCacheBuster('myapp:static/manifest.json')) A simpler approach is to use the :class:`~pyramid.static.QueryStringConstantCacheBuster` to generate a global -- cgit v1.2.3 From eedef93f0c4c52ea11320bcd49386262fa7293a1 Mon Sep 17 00:00:00 2001 From: Michael Merickel Date: Tue, 8 Dec 2015 11:12:38 -0600 Subject: update the cache busting narrative to use add_cache_buster --- docs/narr/assets.rst | 103 +++++++++++++++++++++++++++++++++++---------------- 1 file changed, 72 insertions(+), 31 deletions(-) (limited to 'docs/narr/assets.rst') diff --git a/docs/narr/assets.rst b/docs/narr/assets.rst index 0f819570c..8b41f9b8a 100644 --- a/docs/narr/assets.rst +++ b/docs/narr/assets.rst @@ -366,8 +366,7 @@ resource and requests the asset, 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, ``cachebust`` to -:meth:`~pyramid.config.Configurator.add_static_view`: +assets using :meth:`~pyramid.config.Configurator.add_cache_buster`: .. code-block:: python :linenos: @@ -376,14 +375,18 @@ assets by passing the optional argument, ``cachebust`` to from pyramid.static import QueryStringConstantCacheBuster # config is an instance of pyramid.config.Configurator - config.add_static_view( - name='static', path='mypackage:folder/static', - cachebust=QueryStringConstantCacheBuster(str(int(time.time()))), - ) + config.add_static_view(name='static', path='mypackage:folder/static/') + config.add_cache_buster( + 'mypackage:folder/static/', + QueryStringConstantCacheBuster(str(int(time.time())))) + +.. note:: + The trailing slash on the ``add_cache_buster`` call is important to + indicate that it is overriding every asset in the folder and not just a + file named ``static``. -Setting the ``cachebust`` argument instructs :app:`Pyramid` to use a cache -busting scheme which adds the curent time for a static asset to the query -string in the asset's URL: +Adding the cachebuster instructs :app:`Pyramid` to add the current time for +a static asset to the query string in the asset's URL: .. code-block:: python :linenos: @@ -392,10 +395,7 @@ string in the asset's URL: # Returns: 'http://www.example.com/static/js/myapp.js?x=1445318121' When the web server restarts, the time constant will change and therefore so -will its URL. Supplying the ``cachebust`` argument also causes the static -view to set headers instructing clients to cache the asset for ten years, -unless the ``cache_max_age`` argument is also passed, in which case that -value is used. +will its URL. .. note:: @@ -410,7 +410,7 @@ Disabling the Cache Buster It can be useful in some situations (e.g., development) to globally disable all configured cache busters without changing calls to -:meth:`~pyramid.config.Configurator.add_static_view`. To do this set the +:meth:`~pyramid.config.Configurator.add_cache_buster`. To do this set the ``PYRAMID_PREVENT_CACHEBUST`` environment variable or the ``pyramid.prevent_cachebust`` configuration value to a true value. @@ -419,9 +419,9 @@ configured cache busters without changing calls to Customizing the Cache Buster ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -The ``cachebust`` option to -:meth:`~pyramid.config.Configurator.add_static_view` may be set to any object -that implements the interface :class:`~pyramid.interfaces.ICacheBuster`. +Calls to :meth:`~pyramid.config.Configurator.add_cache_buster` may use +any object that implements the interface +:class:`~pyramid.interfaces.ICacheBuster`. :app:`Pyramid` ships with a very simplistic :class:`~pyramid.static.QueryStringConstantCacheBuster`, which adds an @@ -461,8 +461,30 @@ the hash of the current commit: def tokenize(self, pathspec): return self.sha1 -Choosing a Cache Buster -~~~~~~~~~~~~~~~~~~~~~~~ +A simple cache buster that modifies the path segment can be constructed as +well: + +.. code-block:: python + :linenos: + + import posixpath + + def cache_buster(spec, subpath, kw): + base_subpath, ext = posixpath.splitext(subpath) + new_subpath = base_subpath + '-asdf' + ext + return new_subpath, kw + +The caveat with this approach is that modifying the path segment +changes the file name, and thus must match what is actually on the +filesystem in order for :meth:`~pyramid.config.Configurator.add_static_view` +to find the file. It's better to use the +:class:`~pyramid.static.ManifestCacheBuster` for these situations, as +described in the next section. + +.. _path_segment_cache_busters: + +Path Segments and Choosing a Cache Buster +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Many caching HTTP proxies will fail to cache a resource if the URL contains a query string. Therefore, in general, you should prefer a cache busting @@ -504,8 +526,11 @@ The following code would set up a cachebuster: config.add_static_view( name='http://mycdn.example.com/', - path='mypackage:static', - cachebust=ManifestCacheBuster('myapp:static/manifest.json')) + path='mypackage:static') + + config.add_cache_buster( + 'mypackage:static/', + ManifestCacheBuster('myapp:static/manifest.json')) A simpler approach is to use the :class:`~pyramid.static.QueryStringConstantCacheBuster` to generate a global @@ -524,8 +549,11 @@ start up as a cachebust token: config.add_static_view( name='http://mycdn.example.com/', - path='mypackage:static', - cachebust=QueryStringConstantCacheBuster(str(int(time.time())))) + path='mypackage:static') + + config.add_cache_buster( + 'mypackage:static/', + QueryStringConstantCacheBuster(str(int(time.time())))) .. index:: single: static assets view @@ -536,25 +564,38 @@ CSS and JavaScript source and cache busting Often one needs to refer to images and other static assets inside CSS and JavaScript files. If cache busting is active, the final static asset URL is not available until the static assets have been assembled. These URLs cannot be -handwritten. Thus, when having static asset references in CSS and JavaScript, -one needs to perform one of the following tasks: +handwritten. Below is an example of how to integrate the cache buster into +the entire stack. Remember, it is just an example and should be modified to +fit your specific tools. -* Process the files by using a precompiler which rewrites URLs to their final - cache busted form. Then, you can use the +* First, process the files by using a precompiler which rewrites URLs to their + final cache-busted form. Then, you can use the :class:`~pyramid.static.ManifestCacheBuster` to synchronize your asset pipeline with :app:`Pyramid`, allowing the pipeline to have full control over the final URLs of your assets. -* Templatize JS and CSS, and call ``request.static_url()`` inside their - template code. +Now that you are able to generate static URLs within :app:`Pyramid`, +you'll need to handle URLs that are out of our control. To do this you may +use some of the following options to get started: -* Pass static URL references to CSS and JavaScript via other means. +* Configure your asset pipeline to rewrite URL references inline in + CSS and JavaScript. This is the best approach because then the files + may be hosted by :app:`Pyramid` or an external CDN without haven't to + change anything. They really are static. + +* Templatize JS and CSS, and call ``request.static_url()`` inside their + template code. While this approach may work in certain scenarios, it is not + recommended because your static assets will not really be static and are now + dependent on :app:`Pyramid` to be served correctly. See + :ref:`advanced static` for more information on this approach. If your CSS and JavaScript assets use URLs to reference other assets it is recommended that you implement an external asset pipeline that can rewrite the generated static files with new URLs containing cache busting tokens. The machinery inside :app:`Pyramid` will not help with this step as it has very -little knowledge of the asset types your application may use. +little knowledge of the asset types your application may use. The integration +into :app:`Pyramid` is simply for linking those assets into your HTML and +other dynamic content. .. _advanced_static: -- cgit v1.2.3 From 3175c990bc02805b729594996f6360b81f5f0ebc Mon Sep 17 00:00:00 2001 From: Michael Merickel Date: Wed, 9 Dec 2015 23:01:35 -0600 Subject: fix broken ref in docs --- docs/narr/assets.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'docs/narr/assets.rst') diff --git a/docs/narr/assets.rst b/docs/narr/assets.rst index 8b41f9b8a..0e3f6af11 100644 --- a/docs/narr/assets.rst +++ b/docs/narr/assets.rst @@ -587,7 +587,7 @@ use some of the following options to get started: template code. While this approach may work in certain scenarios, it is not recommended because your static assets will not really be static and are now dependent on :app:`Pyramid` to be served correctly. See - :ref:`advanced static` for more information on this approach. + :ref:`advanced_static` for more information on this approach. If your CSS and JavaScript assets use URLs to reference other assets it is recommended that you implement an external asset pipeline that can rewrite the -- cgit v1.2.3 From 313ff3c28fbd3b784e4c87daf8ae8a4cf713262b Mon Sep 17 00:00:00 2001 From: Michael Merickel Date: Wed, 16 Dec 2015 21:30:56 -0600 Subject: update docs to support explicit asset overrides --- docs/narr/assets.rst | 100 +++++++++++++++++++++++++++++++++------------------ 1 file changed, 65 insertions(+), 35 deletions(-) (limited to 'docs/narr/assets.rst') diff --git a/docs/narr/assets.rst b/docs/narr/assets.rst index 0e3f6af11..b28e6b5b3 100644 --- a/docs/narr/assets.rst +++ b/docs/narr/assets.rst @@ -380,11 +380,6 @@ assets using :meth:`~pyramid.config.Configurator.add_cache_buster`: 'mypackage:folder/static/', QueryStringConstantCacheBuster(str(int(time.time())))) -.. note:: - The trailing slash on the ``add_cache_buster`` call is important to - indicate that it is overriding every asset in the folder and not just a - file named ``static``. - Adding the cachebuster instructs :app:`Pyramid` to add the current time for a static asset to the query string in the asset's URL: @@ -451,12 +446,13 @@ the hash of the current commit: from an egg repository like PYPI, you can use this cachebuster to get the current commit's SHA1 to use as the cache bust token. """ - def __init__(self, param='x'): + def __init__(self, param='x', repo_path=None): super(GitCacheBuster, self).__init__(param=param) - here = os.path.dirname(os.path.abspath(__file__)) + if repo_path is None: + repo_path = os.path.dirname(os.path.abspath(__file__)) self.sha1 = subprocess.check_output( ['git', 'rev-parse', 'HEAD'], - cwd=here).strip() + cwd=repo_path).strip() def tokenize(self, pathspec): return self.sha1 @@ -469,10 +465,14 @@ well: import posixpath - def cache_buster(spec, subpath, kw): - base_subpath, ext = posixpath.splitext(subpath) - new_subpath = base_subpath + '-asdf' + ext - return new_subpath, kw + class PathConstantCacheBuster(object): + def __init__(self, token): + self.token = token + + def __call__(self, request, subpath, kw): + base_subpath, ext = posixpath.splitext(subpath) + new_subpath = base_subpath + self.token + ext + return new_subpath, kw The caveat with this approach is that modifying the path segment changes the file name, and thus must match what is actually on the @@ -532,29 +532,6 @@ The following code would set up a cachebuster: 'mypackage:static/', ManifestCacheBuster('myapp:static/manifest.json')) -A simpler approach is to use the -:class:`~pyramid.static.QueryStringConstantCacheBuster` to generate a global -token that will bust all of the assets at once. The advantage of this strategy -is that it is simple and by using the query string there doesn't need to be -any shared information between your application and the static assets. - -The following code would set up a cachebuster that just uses the time at -start up as a cachebust token: - -.. code-block:: python - :linenos: - - import time - from pyramid.static import QueryStringConstantCacheBuster - - config.add_static_view( - name='http://mycdn.example.com/', - path='mypackage:static') - - config.add_cache_buster( - 'mypackage:static/', - QueryStringConstantCacheBuster(str(int(time.time())))) - .. index:: single: static assets view @@ -834,3 +811,56 @@ when an override is used. As of Pyramid 1.6, it is also possible to override an asset by supplying an absolute path to a file or directory. This may be useful if the assets are not distributed as part of a Python package. + +Cache Busting and Asset Overrides +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Overriding static assets that are being hosted using +:meth:`pyramid.config.Configurator.add_static_view` can affect your cache +busting strategy when using any cache busters that are asset-aware such as +:class:`pyramid.static.ManifestCacheBuster`. What sets asset-aware cache +busters apart is that they have logic tied to specific assets. For example, +a manifest is only generated for a specific set of pre-defined assets. Now, +imagine you have overridden an asset defined in this manifest with a new, +unknown version. By default, the cache buster will be invoked for an asset +it has never seen before and will likely end up returning a cache busting +token for the original asset rather than the asset that will actually end up +being served! In order to get around this issue it's possible to attach a +different :class:`pyramid.interfaces.ICacheBuster` implementation to the +new assets. This would cause the original assets to be served by their +manifest, and the new assets served by their own cache buster. To do this, +:meth:`pyramid.config.Configurator.add_cache_buster` supports an ``explicit`` +option. For example: + +.. code-block:: python + :linenos: + + from pyramid.static import ManifestCacheBuster + + # define a static view for myapp:static assets + config.add_static_view('static', 'myapp:static') + + # setup a cache buster for your app based on the myapp:static assets + my_cb = ManifestCacheBuster('myapp:static/manifest.json') + config.add_cache_buster('myapp:static', my_cb) + + # override an asset + config.override_asset( + to_override='myapp:static/background.png', + override_with='theme:static/background.png') + + # override the cache buster for theme:static assets + theme_cb = ManifestCacheBuster('theme:static/manifest.json') + config.add_cache_buster('theme:static', theme_cb, explicit=True) + +In the above example there is a default cache buster, ``my_cb`` for all assets +served from the ``myapp:static`` folder. This would also affect +``theme:static/background.png`` when generating URLs via +``request.static_url('myapp:static/background.png')``. + +The ``theme_cb`` is defined explicitly for any assets loaded from the +``theme:static`` folder. Explicit cache busters have priority and thus +``theme_cb`` would be invoked for +``request.static_url('myapp:static/background.png')`` but ``my_cb`` would be +used for any other assets like +``request.static_url('myapp:static/favicon.ico')``. -- cgit v1.2.3 From 897d1deeab710233565f97d216e4d112b2a466e3 Mon Sep 17 00:00:00 2001 From: Michael Merickel Date: Thu, 17 Dec 2015 20:52:19 -0600 Subject: grammar updates from stevepiercy --- docs/narr/assets.rst | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'docs/narr/assets.rst') diff --git a/docs/narr/assets.rst b/docs/narr/assets.rst index b28e6b5b3..054c58247 100644 --- a/docs/narr/assets.rst +++ b/docs/narr/assets.rst @@ -557,7 +557,7 @@ use some of the following options to get started: * Configure your asset pipeline to rewrite URL references inline in CSS and JavaScript. This is the best approach because then the files - may be hosted by :app:`Pyramid` or an external CDN without haven't to + may be hosted by :app:`Pyramid` or an external CDN without having to change anything. They really are static. * Templatize JS and CSS, and call ``request.static_url()`` inside their @@ -825,7 +825,7 @@ imagine you have overridden an asset defined in this manifest with a new, unknown version. By default, the cache buster will be invoked for an asset it has never seen before and will likely end up returning a cache busting token for the original asset rather than the asset that will actually end up -being served! In order to get around this issue it's possible to attach a +being served! In order to get around this issue, it's possible to attach a different :class:`pyramid.interfaces.ICacheBuster` implementation to the new assets. This would cause the original assets to be served by their manifest, and the new assets served by their own cache buster. To do this, @@ -853,14 +853,14 @@ option. For example: theme_cb = ManifestCacheBuster('theme:static/manifest.json') config.add_cache_buster('theme:static', theme_cb, explicit=True) -In the above example there is a default cache buster, ``my_cb`` for all assets -served from the ``myapp:static`` folder. This would also affect +In the above example there is a default cache buster, ``my_cb``, for all +assets served from the ``myapp:static`` folder. This would also affect ``theme:static/background.png`` when generating URLs via ``request.static_url('myapp:static/background.png')``. The ``theme_cb`` is defined explicitly for any assets loaded from the ``theme:static`` folder. Explicit cache busters have priority and thus ``theme_cb`` would be invoked for -``request.static_url('myapp:static/background.png')`` but ``my_cb`` would be -used for any other assets like +``request.static_url('myapp:static/background.png')``, but ``my_cb`` would +be used for any other assets like ``request.static_url('myapp:static/favicon.ico')``. -- cgit v1.2.3 From 2901e968390f70b4bfa777dd4348dc9d3eb6210c Mon Sep 17 00:00:00 2001 From: Michael Merickel Date: Sun, 3 Jan 2016 00:22:44 -0600 Subject: add a note about serving cache busted assets --- docs/narr/assets.rst | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'docs/narr/assets.rst') diff --git a/docs/narr/assets.rst b/docs/narr/assets.rst index 054c58247..58f547fc9 100644 --- a/docs/narr/assets.rst +++ b/docs/narr/assets.rst @@ -532,6 +532,14 @@ The following code would set up a cachebuster: 'mypackage:static/', ManifestCacheBuster('myapp:static/manifest.json')) +It's important to note that the cache buster only handles generating +cache-busted URLs for static assets. It does **NOT** provide any solutions for +serving those assets. For example, if you generated a URL for +``css/main-678b7c80.css`` then that URL needs to be valid either by +configuring ``add_static_view`` properly to point to the location of the files +or some other mechanism such as the files existing on your CDN or rewriting +the incoming URL to remove the cache bust tokens. + .. index:: single: static assets view -- cgit v1.2.3