1.. index::
2   single: assets
3   single: static asssets
4
5.. _assets_chapter:
6
7Static Assets
8=============
9
10An :term:`asset` is any file contained within a Python :term:`package` which is
11*not* a Python source code file.  For example, each of the following is an
12asset:
13
14- a GIF image file contained within a Python package or contained within any
15  subdirectory of a Python package.
16
17- a CSS file contained within a Python package or contained within any
18  subdirectory of a Python package.
19
20- a JavaScript source file contained within a Python package or contained
21  within any subdirectory of a Python package.
22
23- A directory within a package that does not have an ``__init__.py`` in it (if
24  it possessed an ``__init__.py`` it would *be* a package).
25
26- a :term:`Chameleon` or :term:`Mako` template file contained within a Python
27  package.
28
29The use of assets is quite common in most web development projects.  For
30example, when you create a :app:`Pyramid` application using one of the
31available scaffolds, as described in :ref:`creating_a_project`, the directory
32representing the application contains a Python :term:`package`. Within that
33Python package, there are directories full of files which are static assets.
34For example, there's a ``static`` directory which contains ``.css``, ``.js``,
35and ``.gif`` files.  These asset files are delivered when a user visits an
36application URL.
37
38.. index::
39   single: asset specifications
40
41.. _asset_specifications:
42
43Understanding Asset Specifications
44----------------------------------
45
46Let's imagine you've created a :app:`Pyramid` application that uses a
47:term:`Chameleon` ZPT template via the
48:func:`pyramid.renderers.render_to_response` API.  For example, the application
49might address the asset using the :term:`asset specification`
50``myapp:templates/some_template.pt`` using that API within a ``views.py`` file
51inside a ``myapp`` package:
52
53.. code-block:: python
54   :linenos:
55
56   from pyramid.renderers import render_to_response
57   render_to_response('myapp:templates/some_template.pt', {}, request)
58
59"Under the hood", when this API is called, :app:`Pyramid` attempts to make
60sense out of the string ``myapp:templates/some_template.pt`` provided by the
61developer.  This string is an :term:`asset specification`.  It is composed of
62two parts:
63
64- The *package name* (``myapp``)
65
66- The *asset name* (``templates/some_template.pt``), relative to the package
67  directory.
68
69The two parts are separated by a colon ``:`` character.
70
71:app:`Pyramid` uses the Python :term:`pkg_resources` API to resolve the package
72name and asset name to an absolute (operating system-specific) file name.  It
73eventually passes this resolved absolute filesystem path to the Chameleon
74templating engine, which then uses it to load, parse, and execute the template
75file.
76
77There is a second form of asset specification: a *relative* asset
78specification.  Instead of using an "absolute" asset specification which
79includes the package name, in certain circumstances you can omit the package
80name from the specification.  For example, you might be able to use
81``templates/mytemplate.pt`` instead of ``myapp:templates/some_template.pt``.
82Such asset specifications are usually relative to a "current package".  The
83"current package" is usually the package which contains the code that *uses*
84the asset specification.  :app:`Pyramid` APIs which accept relative asset
85specifications typically describe to what the asset is relative in their
86individual documentation.
87
88.. index::
89   single: add_static_view
90   pair: assets; serving
91
92.. _static_assets_section:
93
94Serving Static Assets
95---------------------
96
97:app:`Pyramid` makes it possible to serve up static asset files from a
98directory on a filesystem to an application user's browser.  Use the
99:meth:`pyramid.config.Configurator.add_static_view` to instruct :app:`Pyramid`
100to serve static assets, such as JavaScript and CSS files. This mechanism makes
101a directory of static files available at a name relative to the application
102root URL, e.g., ``/static``, or as an external URL.
103
104.. note::
105
106   :meth:`~pyramid.config.Configurator.add_static_view` cannot serve a single
107   file, nor can it serve a directory of static files directly relative to the
108   root URL of a :app:`Pyramid` application.  For these features, see
109   :ref:`advanced_static`.
110
111Here's an example of a use of
112:meth:`~pyramid.config.Configurator.add_static_view` that will serve files up
113from the ``/var/www/static`` directory of the computer which runs the
114:app:`Pyramid` application as URLs beneath the ``/static`` URL prefix.
115
116.. code-block:: python
117   :linenos:
118
119   # config is an instance of pyramid.config.Configurator
120   config.add_static_view(name='static', path='/var/www/static')
121
122The ``name`` represents a URL *prefix*.  In order for files that live in the
123``path`` directory to be served, a URL that requests one of them must begin
124with that prefix.  In the example above, ``name`` is ``static`` and ``path`` is
125``/var/www/static``.  In English this means that you wish to serve the files
126that live in ``/var/www/static`` as sub-URLs of the ``/static`` URL prefix.
127Therefore, the file ``/var/www/static/foo.css`` will be returned when the user
128visits your application's URL ``/static/foo.css``.
129
130A static directory named at ``path`` may contain subdirectories recursively,
131and any subdirectories may hold files; these will be resolved by the static
132view as you would expect.  The ``Content-Type`` header returned by the static
133view for each particular type of file is dependent upon its file extension.
134
135By default, all files made available via
136:meth:`~pyramid.config.Configurator.add_static_view` are accessible by
137completely anonymous users.  Simple authorization can be required, however. To
138protect a set of static files using a permission, in addition to passing the
139required ``name`` and ``path`` arguments, also pass the ``permission`` keyword
140argument to :meth:`~pyramid.config.Configurator.add_static_view`. The value of
141the ``permission`` argument represents the :term:`permission` that the user
142must have relative to the current :term:`context` when the static view is
143invoked.  A user will be required to possess this permission to view any of the
144files represented by ``path`` of the static view.  If your static assets must
145be protected by a more complex authorization scheme, see
146:ref:`advanced_static`.
147
148Here's another example that uses an :term:`asset specification` instead of an
149absolute path as the ``path`` argument.  To convince
150:meth:`~pyramid.config.Configurator.add_static_view` to serve files up under
151the ``/static`` URL from the ``a/b/c/static`` directory of the Python package
152named ``some_package``, we can use a fully qualified :term:`asset
153specification` as the ``path``:
154
155.. code-block:: python
156   :linenos:
157
158   # config is an instance of pyramid.config.Configurator
159   config.add_static_view(name='static', path='some_package:a/b/c/static')
160
161The ``path`` provided to :meth:`~pyramid.config.Configurator.add_static_view`
162may be a fully qualified :term:`asset specification` or an *absolute path*.
163
164Instead of representing a URL prefix, the ``name`` argument of a call to
165:meth:`~pyramid.config.Configurator.add_static_view` can alternately be a
166*URL*.  Each of the examples we've seen so far have shown usage of the ``name``
167argument as a URL prefix.  However, when ``name`` is a *URL*, static assets can
168be served from an external webserver.  In this mode, the ``name`` is used as
169the URL prefix when generating a URL using
170:meth:`pyramid.request.Request.static_url`.
171
172For example, :meth:`~pyramid.config.Configurator.add_static_view` may be fed a
173``name`` argument which is ``http://example.com/images``:
174
175.. code-block:: python
176   :linenos:
177
178   # config is an instance of pyramid.config.Configurator
179   config.add_static_view(name='http://example.com/images',
180                          path='mypackage:images')
181
182Because :meth:`~pyramid.config.Configurator.add_static_view` is provided with a
183``name`` argument that is the URL ``http://example.com/images``, subsequent
184calls to :meth:`~pyramid.request.Request.static_url` with paths that start with
185the ``path`` argument passed to
186:meth:`~pyramid.config.Configurator.add_static_view` will generate a URL
187something like ``http://example.com/images/logo.png``.  The external webserver
188listening on ``example.com`` must be itself configured to respond properly to
189such a request.  The :meth:`~pyramid.request.Request.static_url` API is
190discussed in more detail later in this chapter.
191
192.. index::
193   single: generating static asset urls
194   single: static asset urls
195   pair:   assets; generating urls
196
197.. _generating_static_asset_urls:
198
199Generating Static Asset URLs
200~~~~~~~~~~~~~~~~~~~~~~~~~~~~
201
202When an :meth:`~pyramid.config.Configurator.add_static_view` method is used to
203register a static asset directory, a special helper API named
204:meth:`pyramid.request.Request.static_url` can be used to generate the
205appropriate URL for an asset that lives in one of the directories named by the
206static registration ``path`` attribute.
207
208For example, let's assume you create a set of static declarations like so:
209
210.. code-block:: python
211   :linenos:
212
213   config.add_static_view(name='static1', path='mypackage:assets/1')
214   config.add_static_view(name='static2', path='mypackage:assets/2')
215
216These declarations create URL-accessible directories which have URLs that begin
217with ``/static1`` and ``/static2``, respectively.  The assets in the
218``assets/1`` directory of the ``mypackage`` package are consulted when a user
219visits a URL which begins with ``/static1``, and the assets in the ``assets/2``
220directory of the ``mypackage`` package are consulted when a user visits a URL
221which begins with ``/static2``.
222
223You needn't generate the URLs to static assets "by hand" in such a
224configuration.  Instead, use the :meth:`~pyramid.request.Request.static_url`
225API to generate them for you.  For example:
226
227.. code-block:: python
228   :linenos:
229
230   from pyramid.renderers import render_to_response
231
232   def my_view(request):
233       css_url = request.static_url('mypackage:assets/1/foo.css')
234       js_url = request.static_url('mypackage:assets/2/foo.js')
235       return render_to_response('templates/my_template.pt',
236                                 dict(css_url=css_url, js_url=js_url),
237                                 request=request)
238
239If the request "application URL" of the running system is
240``http://example.com``, the ``css_url`` generated above would be:
241``http://example.com/static1/foo.css``.  The ``js_url`` generated above would
242be ``http://example.com/static2/foo.js``.
243
244One benefit of using the :meth:`~pyramid.request.Request.static_url` function
245rather than constructing static URLs "by hand" is that if you need to change
246the ``name`` of a static URL declaration, the generated URLs will continue to
247resolve properly after the rename.
248
249URLs may also be generated by :meth:`~pyramid.request.Request.static_url` to
250static assets that live *outside* the :app:`Pyramid` application.  This will
251happen when the :meth:`~pyramid.config.Configurator.add_static_view` API
252associated with the path fed to :meth:`~pyramid.request.Request.static_url` is
253a *URL* instead of a view name.  For example, the ``name`` argument may be
254``http://example.com`` while the ``path`` given may be ``mypackage:images``:
255
256.. code-block:: python
257   :linenos:
258
259   config.add_static_view(name='http://example.com/images',
260                          path='mypackage:images')
261
262Under such a configuration, the URL generated by ``static_url`` for assets
263which begin with ``mypackage:images`` will be prefixed with
264``http://example.com/images``:
265
266.. code-block:: python
267   :linenos:
268
269   request.static_url('mypackage:images/logo.png')
270   # -> http://example.com/images/logo.png
271
272Using :meth:`~pyramid.request.Request.static_url` in conjunction with a
273:meth:`~pyramid.config.Configurator.add_static_view` makes it possible to put
274static media on a separate webserver during production (if the ``name``
275argument to :meth:`~pyramid.config.Configurator.add_static_view` is a URL),
276while keeping static media package-internal and served by the development
277webserver during development (if the ``name`` argument to
278:meth:`~pyramid.config.Configurator.add_static_view` is a URL prefix).
279
280For example, we may define a :ref:`custom setting <adding_a_custom_setting>`
281named ``media_location`` which we can set to an external URL in production when
282our assets are hosted on a CDN.
283
284.. code-block:: python
285   :linenos:
286
287   media_location = settings.get('media_location', 'static')
288
289   config = Configurator(settings=settings)
290   config.add_static_view(path='myapp:static', name=media_location)
291
292Now we can optionally define the setting in our ini file:
293
294.. code-block:: ini
295   :linenos:
296
297   # production.ini
298   [app:main]
299   use = egg:myapp#main
300
301   media_location = http://static.example.com/
302
303It is also possible to serve assets that live outside of the source by
304referring to an absolute path on the filesystem. There are two ways to
305accomplish this.
306
307First, :meth:`~pyramid.config.Configurator.add_static_view` supports taking an
308absolute path directly instead of an asset spec. This works as expected,
309looking in the file or folder of files and serving them up at some URL within
310your application or externally. Unfortunately, this technique has a drawback in
311that it is not possible to use the :meth:`~pyramid.request.Request.static_url`
312method to generate URLs, since it works based on an asset specification.
313
314.. versionadded:: 1.6
315
316The second approach, available in Pyramid 1.6+, uses the asset overriding APIs
317described in the :ref:`overriding_assets_section` section. It is then possible
318to configure a "dummy" package which then serves its file or folder from an
319absolute path.
320
321.. code-block:: python
322
323   config.add_static_view(path='myapp:static_images', name='static')
324   config.override_asset(to_override='myapp:static_images/',
325                         override_with='/abs/path/to/images/')
326
327From this configuration it is now possible to use
328:meth:`~pyramid.request.Request.static_url` to generate URLs to the data in the
329folder by doing something like
330``request.static_url('myapp:static_images/foo.png')``. While it is not
331necessary that the ``static_images`` file or folder actually exist in the
332``myapp`` package, it is important that the ``myapp`` portion points to a valid
333package. If the folder does exist, then the overriden folder is given priority,
334if the file's name exists in both locations.
335
336.. index::
337   single: Cache Busting
338
339.. _cache_busting:
340
341Cache Busting
342-------------
343
344.. versionadded:: 1.6
345
346In order to maximize performance of a web application, you generally want to
347limit the number of times a particular client requests the same static asset.
348Ideally a client would cache a particular static asset "forever", requiring it
349to be sent to the client a single time.  The HTTP protocol allows you to send
350headers with an HTTP response that can instruct a client to cache a particular
351asset for an amount of time.  As long as the client has a copy of the asset in
352its cache and that cache hasn't expired, the client will use the cached copy
353rather than request a new copy from the server.  The drawback to sending cache
354headers to the client for a static asset is that at some point the static asset
355may change, and then you'll want the client to load a new copy of the asset.
356Under normal circumstances you'd just need to wait for the client's cached copy
357to expire before they get the new version of the static resource.
358
359A commonly used workaround to this problem is a technique known as
360:term:`cache busting`.  Cache busting schemes generally involve generating a
361URL for a static asset that changes when the static asset changes.  This way
362headers can be sent along with the static asset instructing the client to cache
363the asset for a very long time.  When a static asset is changed, the URL used
364to refer to it in a web page also changes, so the client sees it as a new
365resource and requests the asset, regardless of any caching policy set for the
366resource's old URL.
367
368:app:`Pyramid` can be configured to produce cache busting URLs for static
369assets using :meth:`~pyramid.config.Configurator.add_cache_buster`:
370
371.. code-block:: python
372   :linenos:
373
374   import time
375   from pyramid.static import QueryStringConstantCacheBuster
376
377   # config is an instance of pyramid.config.Configurator
378   config.add_static_view(name='static', path='mypackage:folder/static/')
379   config.add_cache_buster(
380       'mypackage:folder/static/',
381       QueryStringConstantCacheBuster(str(int(time.time()))))
382
383Adding the cachebuster instructs :app:`Pyramid` to add the current time for
384a static asset to the query string in the asset's URL:
385
386.. code-block:: python
387   :linenos:
388
389   js_url = request.static_url('mypackage:folder/static/js/myapp.js')
390   # Returns: 'http://www.example.com/static/js/myapp.js?x=1445318121'
391
392When the web server restarts, the time constant will change and therefore so
393will its URL.
394
395.. note::
396
397   Cache busting is an inherently complex topic as it integrates the asset
398   pipeline and the web application. It is expected and desired that
399   application authors will write their own cache buster implementations
400   conforming to the properties of their own asset pipelines. See
401   :ref:`custom_cache_busters` for information on writing your own.
402
403Disabling the Cache Buster
404~~~~~~~~~~~~~~~~~~~~~~~~~~
405
406It can be useful in some situations (e.g., development) to globally disable all
407configured cache busters without changing calls to
408:meth:`~pyramid.config.Configurator.add_cache_buster`.  To do this set the
409``PYRAMID_PREVENT_CACHEBUST`` environment variable or the
410``pyramid.prevent_cachebust`` configuration value to a true value.
411
412.. _custom_cache_busters:
413
414Customizing the Cache Buster
415~~~~~~~~~~~~~~~~~~~~~~~~~~~~
416
417Calls to :meth:`~pyramid.config.Configurator.add_cache_buster` may use
418any object that implements the interface
419:class:`~pyramid.interfaces.ICacheBuster`.
420
421:app:`Pyramid` ships with a very simplistic
422:class:`~pyramid.static.QueryStringConstantCacheBuster`, which adds an
423arbitrary token you provide to the query string of the asset's URL. This
424is almost never what you want in production as it does not allow fine-grained
425busting of individual assets.
426
427In order to implement your own cache buster, you can write your own class from
428scratch which implements the :class:`~pyramid.interfaces.ICacheBuster`
429interface.  Alternatively you may choose to subclass one of the existing
430implementations.  One of the most likely scenarios is you'd want to change the
431way the asset token is generated.  To do this just subclass
432:class:`~pyramid.static.QueryStringCacheBuster` and define a
433``tokenize(pathspec)`` method. Here is an example which uses Git to get
434the hash of the current commit:
435
436.. code-block:: python
437   :linenos:
438
439   import os
440   import subprocess
441   from pyramid.static import QueryStringCacheBuster
442
443   class GitCacheBuster(QueryStringCacheBuster):
444       """
445       Assuming your code is installed as a Git checkout, as opposed to an egg
446       from an egg repository like PYPI, you can use this cachebuster to get
447       the current commit's SHA1 to use as the cache bust token.
448       """
449       def __init__(self, param='x', repo_path=None):
450           super(GitCacheBuster, self).__init__(param=param)
451           if repo_path is None:
452               repo_path = os.path.dirname(os.path.abspath(__file__))
453           self.sha1 = subprocess.check_output(
454               ['git', 'rev-parse', 'HEAD'],
455               cwd=repo_path).strip()
456
457       def tokenize(self, pathspec):
458           return self.sha1
459
460A simple cache buster that modifies the path segment can be constructed as
461well:
462
463.. code-block:: python
464   :linenos:
465
466   import posixpath
467
468   class PathConstantCacheBuster(object):
469       def __init__(self, token):
470           self.token = token
471
472       def __call__(self, request, subpath, kw):
473           base_subpath, ext = posixpath.splitext(subpath)
474           new_subpath = base_subpath + self.token + ext
475           return new_subpath, kw
476
477The caveat with this approach is that modifying the path segment
478changes the file name, and thus must match what is actually on the
479filesystem in order for :meth:`~pyramid.config.Configurator.add_static_view`
480to find the file. It's better to use the
481:class:`~pyramid.static.ManifestCacheBuster` for these situations, as
482described in the next section.
483
484.. _path_segment_cache_busters:
485
486Path Segments and Choosing a Cache Buster
487~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
488
489Many caching HTTP proxies will fail to cache a resource if the URL contains
490a query string.  Therefore, in general, you should prefer a cache busting
491strategy which modifies the path segment rather than methods which add a
492token to the query string.
493
494You will need to consider whether the :app:`Pyramid` application will be
495serving your static assets, whether you are using an external asset pipeline
496to handle rewriting urls internal to the css/javascript, and how fine-grained
497do you want the cache busting tokens to be.
498
499In many cases you will want to host the static assets on another web server
500or externally on a CDN. In these cases your :app:`Pyramid` application may not
501even have access to a copy of the static assets. In order to cache bust these
502assets you will need some information about them.
503
504If you are using an external asset pipeline to generate your static files you
505should consider using the :class:`~pyramid.static.ManifestCacheBuster`.
506This cache buster can load a standard JSON formatted file generated by your
507pipeline and use it to cache bust the assets. This has many performance
508advantages as :app:`Pyramid` does not need to look at the files to generate
509any cache busting tokens, but still supports fine-grained per-file tokens.
510
511Assuming an example ``manifest.json`` like:
512
513.. code-block:: json
514
515   {
516       "css/main.css": "css/main-678b7c80.css",
517       "images/background.png": "images/background-a8169106.png"
518   }
519
520The following code would set up a cachebuster:
521
522.. code-block:: python
523   :linenos:
524
525   from pyramid.static import ManifestCacheBuster
526
527   config.add_static_view(
528       name='http://mycdn.example.com/',
529       path='mypackage:static')
530
531   config.add_cache_buster(
532       'mypackage:static/',
533       ManifestCacheBuster('myapp:static/manifest.json'))
534
535It's important to note that the cache buster only handles generating
536cache-busted URLs for static assets. It does **NOT** provide any solutions for
537serving those assets. For example, if you generated a URL for
538``css/main-678b7c80.css`` then that URL needs to be valid either by
539configuring ``add_static_view`` properly to point to the location of the files
540or some other mechanism such as the files existing on your CDN or rewriting
541the incoming URL to remove the cache bust tokens.
542
543.. index::
544   single: static assets view
545
546CSS and JavaScript source and cache busting
547~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
548
549Often one needs to refer to images and other static assets inside CSS and
550JavaScript files. If cache busting is active, the final static asset URL is not
551available until the static assets have been assembled. These URLs cannot be
552handwritten. Below is an example of how to integrate the cache buster into
553the entire stack. Remember, it is just an example and should be modified to
554fit your specific tools.
555
556* First, process the files by using a precompiler which rewrites URLs to their
557  final cache-busted form. Then, you can use the
558  :class:`~pyramid.static.ManifestCacheBuster` to synchronize your asset
559  pipeline with :app:`Pyramid`, allowing the pipeline to have full control
560  over the final URLs of your assets.
561
562Now that you are able to generate static URLs within :app:`Pyramid`,
563you'll need to handle URLs that are out of our control. To do this you may
564use some of the following options to get started:
565
566* Configure your asset pipeline to rewrite URL references inline in
567  CSS and JavaScript. This is the best approach because then the files
568  may be hosted by :app:`Pyramid` or an external CDN without having to
569  change anything. They really are static.
570
571* Templatize JS and CSS, and call ``request.static_url()`` inside their
572  template code. While this approach may work in certain scenarios, it is not
573  recommended because your static assets will not really be static and are now
574  dependent on :app:`Pyramid` to be served correctly. See
575  :ref:`advanced_static` for more information on this approach.
576
577If your CSS and JavaScript assets use URLs to reference other assets it is
578recommended that you implement an external asset pipeline that can rewrite the
579generated static files with new URLs containing cache busting tokens. The
580machinery inside :app:`Pyramid` will not help with this step as it has very
581little knowledge of the asset types your application may use. The integration
582into :app:`Pyramid` is simply for linking those assets into your HTML and
583other dynamic content.
584
585.. _advanced_static:
586
587Advanced: Serving Static Assets Using a View Callable
588-----------------------------------------------------
589
590For more flexibility, static assets can be served by a :term:`view callable`
591which you register manually.  For example, if you're using :term:`URL
592dispatch`, you may want static assets to only be available as a fallback if no
593previous route matches.  Alternatively, you might like to serve a particular
594static asset manually, because its download requires authentication.
595
596Note that you cannot use the :meth:`~pyramid.request.Request.static_url` API to
597generate URLs against assets made accessible by registering a custom static
598view.
599
600Root-Relative Custom Static View (URL Dispatch Only)
601~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
602
603The :class:`pyramid.static.static_view` helper class generates a Pyramid view
604callable.  This view callable can serve static assets from a directory.  An
605instance of this class is actually used by the
606:meth:`~pyramid.config.Configurator.add_static_view` configuration method, so
607its behavior is almost exactly the same once it's configured.
608
609.. warning::
610
611   The following example *will not work* for applications that use
612   :term:`traversal`; it will only work if you use :term:`URL dispatch`
613   exclusively.  The root-relative route we'll be registering will always be
614   matched before traversal takes place, subverting any views registered via
615   ``add_view`` (at least those without a ``route_name``).  A
616   :class:`~pyramid.static.static_view` static view cannot be made
617   root-relative when you use traversal unless it's registered as a :term:`Not
618   Found View`.
619
620To serve files within a directory located on your filesystem at
621``/path/to/static/dir`` as the result of a "catchall" route hanging from the
622root that exists at the end of your routing table, create an instance of the
623:class:`~pyramid.static.static_view` class inside a ``static.py`` file in your
624application root as below.
625
626.. code-block:: python
627   :linenos:
628
629   from pyramid.static import static_view
630   static_view = static_view('/path/to/static/dir', use_subpath=True)
631
632.. note::
633
634   For better cross-system flexibility, use an :term:`asset specification` as
635   the argument to :class:`~pyramid.static.static_view` instead of a physical
636   absolute filesystem path, e.g., ``mypackage:static``, instead of
637   ``/path/to/mypackage/static``.
638
639Subsequently, you may wire the files that are served by this view up to be
640accessible as ``/<filename>`` using a configuration method in your
641application's startup code.
642
643.. code-block:: python
644   :linenos:
645
646   # .. every other add_route declaration should come
647   # before this one, as it will, by default, catch all requests
648
649   config.add_route('catchall_static', '/*subpath')
650   config.add_view('myapp.static.static_view', route_name='catchall_static')
651
652The special name ``*subpath`` above is used by the
653:class:`~pyramid.static.static_view` view callable to signify the path of the
654file relative to the directory you're serving.
655
656Registering a View Callable to Serve a "Static" Asset
657~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
658
659You can register a simple view callable to serve a single static asset.  To do
660so, do things "by hand".  First define the view callable.
661
662.. code-block:: python
663   :linenos:
664
665   import os
666   from pyramid.response import FileResponse
667
668   def favicon_view(request):
669       here = os.path.dirname(__file__)
670       icon = os.path.join(here, 'static', 'favicon.ico')
671       return FileResponse(icon, request=request)
672
673The above bit of code within ``favicon_view`` computes "here", which is a path
674relative to the Python file in which the function is defined.  It then creates
675a :class:`pyramid.response.FileResponse` using the file path as the response's
676``path`` argument and the request as the response's ``request`` argument.
677:class:`pyramid.response.FileResponse` will serve the file as quickly as
678possible when it's used this way.  It makes sure to set the right content
679length and content_type, too, based on the file extension of the file you pass.
680
681You might register such a view via configuration as a view callable that should
682be called as the result of a traversal:
683
684.. code-block:: python
685   :linenos:
686
687   config.add_view('myapp.views.favicon_view', name='favicon.ico')
688
689Or you might register it to be the view callable for a particular route:
690
691.. code-block:: python
692   :linenos:
693
694   config.add_route('favicon', '/favicon.ico')
695   config.add_view('myapp.views.favicon_view', route_name='favicon')
696
697Because this is a simple view callable, it can be protected with a
698:term:`permission` or can be configured to respond under different
699circumstances using :term:`view predicate` arguments.
700
701
702.. index::
703   pair: overriding; assets
704
705.. _overriding_assets_section:
706
707Overriding Assets
708-----------------
709
710It can often be useful to override specific assets from "outside" a given
711:app:`Pyramid` application.  For example, you may wish to reuse an existing
712:app:`Pyramid` application more or less unchanged.  However, some specific
713template file owned by the application might have inappropriate HTML, or some
714static asset (such as a logo file or some CSS file) might not be appropriate.
715You *could* just fork the application entirely, but it's often more convenient
716to just override the assets that are inappropriate and reuse the application
717"as is".  This is particularly true when you reuse some "core" application over
718and over again for some set of customers (such as a CMS application, or some
719bug tracking application), and you want to make arbitrary visual modifications
720to a particular application deployment without forking the underlying code.
721
722To this end, :app:`Pyramid` contains a feature that makes it possible to
723"override" one asset with one or more other assets.  In support of this
724feature, a :term:`Configurator` API exists named
725:meth:`pyramid.config.Configurator.override_asset`.  This API allows you to
726*override* the following kinds of assets defined in any Python package:
727
728- Individual template files.
729
730- A directory containing multiple template files.
731
732- Individual static files served up by an instance of the
733  ``pyramid.static.static_view`` helper class.
734
735- A directory of static files served up by an instance of the
736  ``pyramid.static.static_view`` helper class.
737
738- Any other asset (or set of assets) addressed by code that uses the setuptools
739  :term:`pkg_resources` API.
740
741.. index::
742   single: override_asset
743
744.. _override_asset:
745
746The ``override_asset`` API
747~~~~~~~~~~~~~~~~~~~~~~~~~~
748
749An individual call to :meth:`~pyramid.config.Configurator.override_asset` can
750override a single asset.  For example:
751
752.. code-block:: python
753   :linenos:
754
755   config.override_asset(
756       to_override='some.package:templates/mytemplate.pt',
757       override_with='another.package:othertemplates/anothertemplate.pt')
758
759The string value passed to both ``to_override`` and ``override_with`` sent to
760the ``override_asset`` API is called an :term:`asset specification`.  The colon
761separator in a specification separates the *package name* from the *asset
762name*.  The colon and the following asset name are optional.  If they are not
763specified, the override attempts to resolve every lookup into a package from
764the directory of another package.  For example:
765
766.. code-block:: python
767   :linenos:
768
769   config.override_asset(to_override='some.package',
770                         override_with='another.package')
771
772Individual subdirectories within a package can also be overridden:
773
774.. code-block:: python
775   :linenos:
776
777   config.override_asset(to_override='some.package:templates/',
778                         override_with='another.package:othertemplates/')
779
780If you wish to override a directory with another directory, you *must* make
781sure to attach the slash to the end of both the ``to_override`` specification
782and the ``override_with`` specification.  If you fail to attach a slash to the
783end of a specification that points to a directory, you will get unexpected
784results.
785
786You cannot override a directory specification with a file specification, and
787vice versa; a startup error will occur if you try.  You cannot override an
788asset with itself; a startup error will occur if you try.
789
790Only individual *package* assets may be overridden.  Overrides will not
791traverse through subpackages within an overridden package.  This means that if
792you want to override assets for both ``some.package:templates``, and
793``some.package.views:templates``, you will need to register two overrides.
794
795The package name in a specification may start with a dot, meaning that the
796package is relative to the package in which the configuration construction file
797resides (or the ``package`` argument to the
798:class:`~pyramid.config.Configurator` class construction). For example:
799
800.. code-block:: python
801   :linenos:
802
803   config.override_asset(to_override='.subpackage:templates/',
804                         override_with='another.package:templates/')
805
806Multiple calls to ``override_asset`` which name a shared ``to_override`` but a
807different ``override_with`` specification can be "stacked" to form a search
808path.  The first asset that exists in the search path will be used; if no asset
809exists in the override path, the original asset is used.
810
811Asset overrides can actually override assets other than templates and static
812files.  Any software which uses the
813:func:`pkg_resources.get_resource_filename`,
814:func:`pkg_resources.get_resource_stream`, or
815:func:`pkg_resources.get_resource_string` APIs will obtain an overridden file
816when an override is used.
817
818.. versionadded:: 1.6
819  As of Pyramid 1.6, it is also possible to override an asset by supplying an
820  absolute path to a file or directory. This may be useful if the assets are
821  not distributed as part of a Python package.
822
823Cache Busting and Asset Overrides
824~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
825
826Overriding static assets that are being hosted using
827:meth:`pyramid.config.Configurator.add_static_view` can affect your cache
828busting strategy when using any cache busters that are asset-aware such as
829:class:`pyramid.static.ManifestCacheBuster`. What sets asset-aware cache
830busters apart is that they have logic tied to specific assets. For example,
831a manifest is only generated for a specific set of pre-defined assets. Now,
832imagine you have overridden an asset defined in this manifest with a new,
833unknown version. By default, the cache buster will be invoked for an asset
834it has never seen before and will likely end up returning a cache busting
835token for the original asset rather than the asset that will actually end up
836being served! In order to get around this issue, it's possible to attach a
837different :class:`pyramid.interfaces.ICacheBuster` implementation to the
838new assets. This would cause the original assets to be served by their
839manifest, and the new assets served by their own cache buster. To do this,
840:meth:`pyramid.config.Configurator.add_cache_buster` supports an ``explicit``
841option. For example:
842
843.. code-block:: python
844   :linenos:
845
846   from pyramid.static import ManifestCacheBuster
847
848   # define a static view for myapp:static assets
849   config.add_static_view('static', 'myapp:static')
850
851   # setup a cache buster for your app based on the myapp:static assets
852   my_cb = ManifestCacheBuster('myapp:static/manifest.json')
853   config.add_cache_buster('myapp:static', my_cb)
854
855   # override an asset
856   config.override_asset(
857       to_override='myapp:static/background.png',
858       override_with='theme:static/background.png')
859
860   # override the cache buster for theme:static assets
861   theme_cb = ManifestCacheBuster('theme:static/manifest.json')
862   config.add_cache_buster('theme:static', theme_cb, explicit=True)
863
864In the above example there is a default cache buster, ``my_cb``, for all
865assets served from the ``myapp:static`` folder. This would also affect
866``theme:static/background.png`` when generating URLs via
867``request.static_url('myapp:static/background.png')``.
868
869The ``theme_cb`` is defined explicitly for any assets loaded from the
870``theme:static`` folder. Explicit cache busters have priority and thus
871``theme_cb`` would be invoked for
872``request.static_url('myapp:static/background.png')``, but ``my_cb`` would
873be used for any other assets like
874``request.static_url('myapp:static/favicon.ico')``.
875