summaryrefslogtreecommitdiff
path: root/docs
diff options
context:
space:
mode:
Diffstat (limited to 'docs')
-rw-r--r--docs/api/authentication.rst10
-rw-r--r--docs/api/interfaces.rst4
-rw-r--r--docs/api/security.rst2
-rw-r--r--docs/conf.py2
-rw-r--r--docs/designdefense.rst22
-rw-r--r--docs/glossary.rst10
-rw-r--r--docs/index.rst4
-rw-r--r--docs/latexindex.rst6
-rw-r--r--docs/narr/advconfig.rst6
-rw-r--r--docs/narr/assets.rst397
-rw-r--r--docs/narr/csrf.rst2
-rw-r--r--docs/narr/declarative.rst220
-rw-r--r--docs/narr/extending.rst421
-rw-r--r--docs/narr/flash.rst14
-rw-r--r--docs/narr/hooks.rst668
-rw-r--r--docs/narr/i18n.rst5
-rw-r--r--docs/narr/introduction.rst2
-rw-r--r--docs/narr/project.rst10
-rw-r--r--docs/narr/renderers.rst1
-rw-r--r--docs/narr/resources.rst8
-rw-r--r--docs/narr/static.rst320
-rw-r--r--docs/narr/templates.rst2
-rw-r--r--docs/narr/urldispatch.rst44
-rw-r--r--docs/tutorials/cmf/actions.rst28
-rw-r--r--docs/tutorials/cmf/catalog.rst73
-rw-r--r--docs/tutorials/cmf/content.rst67
-rw-r--r--docs/tutorials/cmf/index.rst38
-rw-r--r--docs/tutorials/cmf/missing.rst22
-rw-r--r--docs/tutorials/cmf/skins.rst23
-rw-r--r--docs/tutorials/cmf/workflow.rst14
30 files changed, 1205 insertions, 1240 deletions
diff --git a/docs/api/authentication.rst b/docs/api/authentication.rst
index 54db77417..a6d4c1e18 100644
--- a/docs/api/authentication.rst
+++ b/docs/api/authentication.rst
@@ -3,6 +3,9 @@
:mod:`pyramid.authentication`
--------------------------------
+Authentication Policies
+~~~~~~~~~~~~~~~~~~~~~~~
+
.. automodule:: pyramid.authentication
.. autoclass:: AuthTktAuthenticationPolicy
@@ -11,3 +14,10 @@
.. autoclass:: RemoteUserAuthenticationPolicy
+Helper Classes
+~~~~~~~~~~~~~~
+
+ .. autoclass:: AuthTktCookieHelper
+
+
+
diff --git a/docs/api/interfaces.rst b/docs/api/interfaces.rst
index b3c14e5f7..3ce926230 100644
--- a/docs/api/interfaces.rst
+++ b/docs/api/interfaces.rst
@@ -35,3 +35,7 @@ Other Interfaces
.. autointerface:: ITemplateRenderer
+ .. autointerface:: IViewMapperFactory
+
+ .. autointerface:: IViewMapper
+
diff --git a/docs/api/security.rst b/docs/api/security.rst
index 4acf5fe4d..de249355d 100644
--- a/docs/api/security.rst
+++ b/docs/api/security.rst
@@ -10,6 +10,8 @@ Authentication API Functions
.. autofunction:: authenticated_userid
+.. autofunction:: unauthenticated_userid
+
.. autofunction:: effective_principals
.. autofunction:: forget
diff --git a/docs/conf.py b/docs/conf.py
index 7bcdf3a07..8c238cecd 100644
--- a/docs/conf.py
+++ b/docs/conf.py
@@ -76,7 +76,7 @@ copyright = '%s, Agendaless Consulting' % datetime.datetime.now().year
# other places throughout the built documents.
#
# The short X.Y version.
-version = '1.0a7'
+version = '1.0a8'
# The full version, including alpha/beta/rc tags.
release = version
diff --git a/docs/designdefense.rst b/docs/designdefense.rst
index b1e869a12..df14fb440 100644
--- a/docs/designdefense.rst
+++ b/docs/designdefense.rst
@@ -90,7 +90,7 @@ libraries, each built upon a specific low level stack that is incompatible
with the other. We'll also shrink the choice of credible Python web
frameworks down by at least one. We're also hoping to attract users from
other communities (such as Zope's and TurboGears') by providing the features
-they requre, while allowing enough flexibility to do things in a familiar
+they require, while allowing enough flexibility to do things in a familiar
fashion. Some overlap of functionality to achieve these goals is expected
and unavoidable, at least if we aim to prevent pointless duplication at
higher levels. If we've done our job well enough, the various audiences will
@@ -260,7 +260,7 @@ ZCA registry gives us, and we have long-ago borne the weight of understanding
what it does and how it works. The authors of :app:`Pyramid` understand the
ZCA deeply and can read code that uses it as easily as any other code.
-But we recognize that developers who my want to extend the framework are not
+But we recognize that developers who might want to extend the framework are not
as comfortable with the ZCA registry API as the original developers are with
it. So, for the purposes of being kind to third-party :app:`Pyramid`
framework developers in, we've drawn some lines in the sand.
@@ -895,9 +895,9 @@ Pyramid Applications are Extensible; I Don't Believe In Application Extensibilit
Any :app:`Pyramid` application written obeying certain constraints is
*extensible*. This feature is discussed in the :app:`Pyramid` documentation
-chapters named :ref:`extending_chapter` and :ref:`advconf_narr`. It is made
-possible by the use of the :term:`Zope Component Architecture` and within
-:app:`Pyramid`.
+chapters named :ref:`extending_chapter` and :ref:`advconfig_narr`. It is
+made possible by the use of the :term:`Zope Component Architecture` and
+within :app:`Pyramid`.
"Extensible", in this context, means:
@@ -1002,7 +1002,7 @@ understand the ZCA or he will need to develop his own similar extensibility
system.
Ultimately, any argument about whether the extensibility features lent to
-applications by :app:`Pyramid` are "good" or "bad" is somewhat pointless. You
+applications by :app:`Pyramid` are "good" or "bad" is mostly pointless. You
needn't take advantage of the extensibility features provided by a particular
:app:`Pyramid` application in order to affect a modification for a particular
set of its deployments. You can ignore the application's extensibility
@@ -1018,7 +1018,7 @@ Challenge
:app:`Pyramid` performs automatic authorization checks only at :term:`view`
execution time. Zope 3 wraps context objects with a `security proxy
-<http://wiki.zope.org/zope3/WhatAreSecurityProxies>`, which causes Zope 3 to
+<http://wiki.zope.org/zope3/WhatAreSecurityProxies>`_, which causes Zope 3 to
do also security checks during attribute access. I like this, because it
means:
@@ -1604,10 +1604,10 @@ If you can understand this hello world program, you can use Pyramid:
app = config.make_wsgi_app()
serve(app)
-Pyramid has ~ 650 of documentation (printed), covering topics from the very
-basic to the most advanced. *Nothing* is left undocumented, quite literally.
-It also has an *awesome*, very helpful community. Visit the #repoze and/or
-#pylons IRC channels on freenode.net and see.
+Pyramid has ~ 650 pages of documentation (printed), covering topics from the
+very basic to the most advanced. *Nothing* is left undocumented, quite
+literally. It also has an *awesome*, very helpful community. Visit the
+#repoze and/or #pylons IRC channels on freenode.net and see.
Hate Zope
+++++++++
diff --git a/docs/glossary.rst b/docs/glossary.rst
index ed96b8afe..4d0c53d60 100644
--- a/docs/glossary.rst
+++ b/docs/glossary.rst
@@ -54,7 +54,8 @@ Glossary
For example, the asset specification
``my.package:static/baz.css`` identifies the file named
``baz.css`` in the ``static`` subdirectory of the ``my.package``
- Python :term:`package`.
+ Python :term:`package`. See :ref:`asset_specifications` for more
+ info.
package
A directory on disk which contains an ``__init__.py`` file, making
@@ -849,6 +850,11 @@ Glossary
WSGI middleware which can display debuggable traceback information in
the browser when an exception is raised by a Pyramid application. See
http://pypi.python.org/pypi/WebError .
-
+ view mapper
+
+ A view mapper is a class which implements the
+ :class:`pyramid.interfaces.IViewMapperFactory` interface, which performs
+ view argument and return value mapping. This is a plug point for
+ extension builders, not normally used by "civilians".
diff --git a/docs/index.rst b/docs/index.rst
index 3830a83f9..d35eb2325 100644
--- a/docs/index.rst
+++ b/docs/index.rst
@@ -45,7 +45,7 @@ Narrative documentation in chapter form explaining how to use
narr/renderers
narr/templates
narr/resources
- narr/static
+ narr/assets
narr/webob
narr/sessions
narr/flash
@@ -61,7 +61,6 @@ Narrative documentation in chapter form explaining how to use
narr/advconfig
narr/declarative
narr/extending
- narr/assets
narr/router
narr/threadlocals
narr/zca
@@ -79,7 +78,6 @@ applications to various platforms.
tutorials/wiki/index.rst
tutorials/wiki2/index.rst
tutorials/bfg/index.rst
- tutorials/cmf/index.rst
tutorials/gae/index.rst
tutorials/modwsgi/index.rst
tutorials/zeo/index.rst
diff --git a/docs/latexindex.rst b/docs/latexindex.rst
index 2d4644416..058835937 100644
--- a/docs/latexindex.rst
+++ b/docs/latexindex.rst
@@ -38,7 +38,7 @@ Narrative Documentation
narr/renderers
narr/templates
narr/resources
- narr/static
+ narr/assets
narr/webob
narr/sessions
narr/flash
@@ -54,7 +54,6 @@ Narrative Documentation
narr/advconfig
narr/declarative
narr/extending
- narr/assets
narr/router
narr/startup
narr/threadlocals
@@ -126,7 +125,9 @@ ZCML Directive Reference
zcml/configure
zcml/default_permission
zcml/forbidden
+ zcml/handler
zcml/include
+ zcml/localenegotiator
zcml/notfound
zcml/remoteuserauthenticationpolicy
zcml/renderer
@@ -135,6 +136,7 @@ ZCML Directive Reference
zcml/scan
zcml/static
zcml/subscriber
+ zcml/translationdir
zcml/utility
zcml/view
diff --git a/docs/narr/advconfig.rst b/docs/narr/advconfig.rst
index e096ef863..f8b3ee191 100644
--- a/docs/narr/advconfig.rst
+++ b/docs/narr/advconfig.rst
@@ -118,6 +118,9 @@ Conflict detection happens for any kind of configuration: imperative
configuration, :term:`ZCML` configuration, or configuration that results from
the execution of a :term:`scan`.
+.. note:: If you use, ZCML, its conflict detection algorithm is described in
+ :ref:`zcml_conflict_detection`.
+
Manually Resolving Conflicts
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -335,6 +338,9 @@ Instead, use :meth:`pyramid.config.Configuration.include`:
Using ``include`` rather than calling the function directly will allow
:ref:`automatic_conflict_resolution` to work.
+.. note: See :ref:`the_include_tag` for a declarative alternative to
+ :meth:`pyramid.config.Configurator.include`.
+
.. _twophase_config:
Two-Phase Configuration
diff --git a/docs/narr/assets.rst b/docs/narr/assets.rst
index 1932e19ff..f73ff231a 100644
--- a/docs/narr/assets.rst
+++ b/docs/narr/assets.rst
@@ -1,74 +1,403 @@
.. index::
single: assets
+ single: static asssets
.. _assets_chapter:
-Assets
-======
+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
asset:
-- a :term:`Chameleon` template file contained within a Python package.
+- a GIF image file contained within a Python package or contained within any
+ subdirectory of a Python package.
-- a GIF image file contained within a Python package.
+- a CSS file contained within a Python package or contained within any
+ subdirectory of a Python package.
-- a CSS file contained within a Python package.
-
-- a JavaScript source file contained within a Python package.
+- 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 :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 "paster" templates, 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
-assets. For example, there is a ``templates`` directory which contains
-``.pt`` files, and a ``static`` directory which contains ``.css``, ``.js``,
-and ``.gif`` files.
+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.
-.. _understanding_assets:
+.. _asset_specifications:
-Understanding Assets
---------------------
+Understanding Asset Specifications
+----------------------------------
Let's imagine you've created a :app:`Pyramid` application that uses a
:term:`Chameleon` ZPT template via the
-:func:`pyramid.chameleon_zpt.render_template_to_response` API. For example,
-the application might address the asset named ``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:
.. ignore-next-block
.. code-block:: python
:linenos:
- from pyramid.chameleon_zpt import render_template_to_response
- render_template_to_response('templates/some_template.pt')
+ from pyramid.renderers import render_to_response
+ render_to_response('myapp:templates/some_template.pt', {}, request)
-"Under the hood", when this API is called, :app:`Pyramid` attempts
-to make sense out of the string ``templates/some_template.pt``
-provided by the developer. To do so, it first finds the "current"
-package. The "current" package is the Python package in which the
-``views.py`` module which contains this code lives. This would be the
-``myapp`` package, according to our example so far. By resolving the
-current package, :app:`Pyramid` has enough information to locate
-the actual template file. These are the elements it needs:
+"Under the hood", when this API is called, :app:`Pyramid` attempts to make
+sense out of the string ``myapp:templates/some_template.pt`` provided by the
+developer. This string is an :term:`asset specification`. It is composed of
+two parts:
- The *package name* (``myapp``)
-- The *asset name* (``templates/some_template.pt``)
+- The *asset name* (``templates/some_template.pt``), relative to the package
+ directory.
+
+The two parts are separated by the 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.
+
+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
+"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
+individual documentation.
+
+.. index::
+ single: add_static_view
+
+.. _static_assets_section:
+
+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.
+
+.. 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`.
+
+Here's an example of a use of
+:meth:`~pyramid.config.Configurator.add_static_view` that will serve files up
+from the ``/var/www/static`` directory of the computer which runs the
+:app:`Pyramid` application as URLs beneath the ``/static`` URL prefix.
+
+.. code-block:: python
+ :linenos:
+
+ # 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
+``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``.
+
+A static directory named at ``path`` may contain subdirectories recursively,
+and any subdirectories may hold files; these will be resolved by the static
+view as you would expect. The ``Content-Type`` header returned by the static
+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 resources 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
+:meth:`pyramid.config.Configurator.add_static_view` to serve files up under
+the ``/static`` URL from the ``a/b/c/static`` directory of the Python package
+named ``some_package``, we can use a fully qualified :term:`asset
+specification` as the ``path``:
+
+.. code-block:: python
+ :linenos:
+
+ # config is an instance of pyramid.config.Configurator
+ config.add_static_view(name='static', path='some_package:a/b/c/static')
+
+The ``path`` provided to :meth:`pyramid.config.Configurator.add_static_view`
+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 :func:`pyramid.url.static_url`.
+
+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:
+
+ # config is an instance of pyramid.config.Configurator
+ 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 :func:`pyramid.url.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.
+
+.. note::
+
+ The :ref:`static_directive` ZCML directive offers an declarative
+ equivalent to :meth:`pyramid.config.Configurator.add_static_view`. Use of
+ the :ref:`static_directive` ZCML directive is completely equivalent to
+ using imperative configuration for the same purpose.
+
+.. index::
+ single: generating static asset urls
+ single: static asset urls
+
+.. _generating_static_asset_urls:
+
+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.
+
+For example, let's assume you create a set of static declarations like so:
+
+.. code-block:: python
+ :linenos:
+
+ 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
+``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``.
+
+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:
+
+.. 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)
+ return render_template_to_response('templates/my_template.pt',
+ css_url = css_url,
+ js_url = js_url)
+
+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``.
+
+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.
+
+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``:
+
+.. code-block:: python
+ :linenos:
+
+ 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
+``http://example.com/images``:
+
+.. code-block:: python
+ :linenos:
+
+ static_url('mypackage:images/logo.png', request)
+ # -> http://example.com/images/logo.png
+
+Using :func:`pyramid.url.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
+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.
+
+.. index::
+ single: static assets view
+
+.. _advanced_static:
+
+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
+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.
+
+Root-Relative Custom Static View (URL Dispatch Only)
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+The :class:`pyramid.view.static` 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
+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`
+ 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.
+
+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.
+
+.. ignore-next-block
+.. code-block:: python
+ :linenos:
+
+ from pyramid.view import static
+ static_view = static('/path/to/static/dir')
+
+.. 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``.
+
+Subsequently, you may wire the files that are served by this view up to be
+accessible as ``/<filename>`` using a configuration method in your
+application's startup code.
+
+.. code-block:: python
+ :linenos:
+
+ # .. every other add_route and/or add_handler declaration should come
+ # before this one, as it will, by default, catch all requests
+
+ config.add_route('catchall_static', '/*subpath', 'myapp.static.static_view')
+
+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.
+
+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.
+
+.. code-block:: python
+ :linenos:
+
+ import os
+ from webob import Response
+
+ def favicon_view(request):
+ here = os.path.dirname(__file__)
+ icon = open(os.path.join(here, 'static', 'favicon.ico'))
+ return Response(content_type='image/x-icon', app_iter=icon)
+
+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.
+
+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:
+
+ config.add_view('myapp.views.favicon_view', name='favicon.ico')
+
+Or you might register it to be the view callable for a particular route:
+
+.. code-block:: python
+ :linenos:
+
+ config.add_route('favicon', '/favicon.ico',
+ view='myapp.views.favicon_view')
-:app:`Pyramid` uses the :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.
+Because this is a simple view callable, it can be protected with a
+:term:`permission` or can be configured to respond under different
+circumstances using :term:`view predicate` arguments.
-Package names often contain dots. For example, ``pyramid`` is a package.
-Asset names usually look a lot like relative UNIX file paths.
.. index::
pair: overriding; assets
diff --git a/docs/narr/csrf.rst b/docs/narr/csrf.rst
index 7586b0ed7..2f545fb4f 100644
--- a/docs/narr/csrf.rst
+++ b/docs/narr/csrf.rst
@@ -9,7 +9,7 @@ phenomenon whereby a user with an identity on your website might click on a
URL or button on another website which unwittingly redirects the user to your
application to perform some command that requires elevated privileges.
-You can avoid most of these attacks by making sure that a the correct *CSRF
+You can avoid most of these attacks by making sure that the correct *CSRF
token* has been set in an :app:`Pyramid` session object before performing any
actions in code which requires elevated privileges and is invoked via a form
post. To use CSRF token support, you must enable a :term:`session factory`
diff --git a/docs/narr/declarative.rst b/docs/narr/declarative.rst
index deccb6c48..f36e55b29 100644
--- a/docs/narr/declarative.rst
+++ b/docs/narr/declarative.rst
@@ -3,28 +3,27 @@
Declarative Configuration
=========================
-The mode of configuration most comprehensively detailed by examples in
-narrative chapters in this book is "imperative" configuration. This is the
-configuration mode in which a developer cedes the least amount of control to
-the framework; it's "imperative" because you express the configuration
-directly in Python code, and you have the full power of Python at your
-disposal as you issue configuration statements. However, another mode of
-configuration exists within :app:`Pyramid`, which often provides better
-extensibility and configuration conflict detection.
+The mode of configuration detailed in the majority of examples within this
+this book is "imperative" configuration. This is the configuration mode in
+which a developer cedes the least amount of control to the framework; it's
+"imperative" because you express the configuration directly in Python code,
+and you have the full power of Python at your disposal as you issue
+configuration statements. However, another mode of configuration exists
+within :app:`Pyramid` named :term:`ZCML` which often provides better
+opportunity for extensibility.
A complete listing of ZCML directives is available within
:ref:`zcml_directives`. This chapter provides an overview of how you might
get started with ZCML and highlights some common tasks performed when you use
-ZCML. You can get a better understanding of when it's appropriate to use
-ZCML from :ref:`extending_chapter`.
+ZCML.
.. index::
single: declarative configuration
.. _declarative_configuration:
-Declarative Configuration
--------------------------
+ZCML Configuration
+------------------
A :app:`Pyramid` application can be configured "declaratively", if so
desired. Declarative configuration relies on *declarations* made external to
@@ -48,9 +47,7 @@ In a file named ``helloworld.py``:
if __name__ == '__main__':
config = Configurator()
- config.begin()
config.load_zcml('configure.zcml')
- config.end()
app = config.make_wsgi_app()
serve(app, host='0.0.0.0')
@@ -83,9 +80,7 @@ the ``if __name__ == '__main__'`` section of ``helloworld.py``:
if __name__ == '__main__':
config = Configurator()
- config.begin()
config.add_view(hello_world)
- config.end()
app = config.make_wsgi_app()
serve(app, host='0.0.0.0')
@@ -99,9 +94,7 @@ it now reads as:
if __name__ == '__main__':
config = Configurator()
- config.begin()
config.load_zcml('configure.zcml')
- config.end()
app = config.make_wsgi_app()
serve(app, host='0.0.0.0')
@@ -163,6 +156,8 @@ configure your application; instead you need to use :term:`ZCML`.
.. index::
single: ZCML conflict detection
+.. _zcml_conflict_detection:
+
ZCML Conflict Detection
~~~~~~~~~~~~~~~~~~~~~~~
@@ -224,9 +219,7 @@ To do so, first, create a file named ``helloworld.py``:
if __name__ == '__main__':
config = Configurator()
- config.begin()
config.load_zcml('configure.zcml')
- config.end()
app = config.make_wsgi_app()
serve(app, host='0.0.0.0')
@@ -269,10 +262,8 @@ within the ``if __name__ == '__main__'`` section of ``helloworld.py``:
if __name__ == '__main__':
config = Configurator()
- config.begin()
config.add_view(hello_world)
config.add_view(goodbye_world, name='goodbye')
- config.end()
app = config.make_wsgi_app()
serve(app, host='0.0.0.0')
@@ -287,9 +278,7 @@ name='goodbye')``, so that it now reads as:
if __name__ == '__main__':
config = Configurator()
- config.begin()
config.load_zcml('configure.zcml')
- config.end()
app = config.make_wsgi_app()
serve(app, host='0.0.0.0')
@@ -345,6 +334,8 @@ contain other directives.
See also :ref:`configure_directive` and :ref:`word_on_xml_namespaces`.
+.. _the_include_tag:
+
The ``<include>`` Tag
~~~~~~~~~~~~~~~~~~~~~
@@ -478,6 +469,45 @@ declaratively. More information about this mode of configuration is
available in :ref:`declarative_configuration` and within
:ref:`zcml_reference`.
+.. index::
+ single: ZCML granularity
+
+ZCML Granularity
+~~~~~~~~~~~~~~~~
+
+It's extremely helpful to third party application "extenders" (aka
+"integrators") if the :term:`ZCML` that composes the configuration for an
+application is broken up into separate files which do very specific things.
+These more specific ZCML files can be reintegrated within the application's
+main ``configure.zcml`` via ``<include file="otherfile.zcml"/>``
+declarations. When ZCML files contain sets of specific declarations, an
+integrator can avoid including any ZCML he does not want by including only
+ZCML files which contain the declarations he needs. He is not forced to
+"accept everything" or "use nothing".
+
+For example, it's often useful to put all ``<route>`` declarations in a
+separate ZCML file, as ``<route>`` statements have a relative ordering that
+is extremely important to the application: if an extender wants to add a
+route to the "middle" of the routing table, he will always need to disuse all
+the routes and cut and paste the routing configuration into his own
+application. It's useful for the extender to be able to disuse just a
+*single* ZCML file in this case, accepting the remainder of the configuration
+from other :term:`ZCML` files in the original application.
+
+Granularizing ZCML is not strictly required. An extender can always disuse
+*all* your ZCML, choosing instead to copy and paste it into his own package,
+if necessary. However, doing so is considerate, and allows for the best
+reusability. Sometimes it's possible to include only certain ZCML files from
+an application that contain only the registrations you really need, omitting
+others. But sometimes it's not. For brute force purposes, when you're
+getting ``view`` or ``route`` registrations that you don't actually want in
+your overridden application, it's always appropriate to just *not include*
+any ZCML file from the overridden application. Instead, just cut and paste
+the entire contents of the ``configure.zcml`` (and any ZCML file included by
+the overridden application's ``configure.zcml``) into your own package and
+omit the ``<include package=""/>`` ZCML declaration in the overriding
+package's ``configure.zcml``.
+
.. _zcml_scanning:
Scanning via ZCML
@@ -503,9 +533,7 @@ file points to is scanned.
if __name__ == '__main__':
from pyramid.config import Configurator
config = Configurator()
- config.begin()
config.load_zcml('configure.zcml')
- config.end()
app = config.make_wsgi_app()
serve(app, host='0.0.0.0')
@@ -1266,9 +1294,143 @@ which we assume lives in a ``subscribers.py`` module within your application:
See also :ref:`subscriber_directive` and :ref:`events_chapter`.
+.. index::
+ single: not found view
+
+.. _notfound_zcml:
+
+Configuring a Not Found View via ZCML
+-------------------------------------
+
+If your application uses :term:`ZCML`, you can replace the Not Found view by
+placing something like the following ZCML in your ``configure.zcml`` file.
+
+.. code-block:: xml
+ :linenos:
+
+ <view
+ view="helloworld.views.notfound_view"
+ context="pyramid.exceptions.NotFound"
+ />
+
+Replace ``helloworld.views.notfound_view`` with the Python dotted name to the
+notfound view you want to use.
+
+See :ref:`changing_the_notfound_view` for more information.
+
+.. index::
+ single: forbidden view
-.. Todo
-.. ----
+.. _forbidden_zcml:
+
+Configuring a Forbidden View via ZCML
+-------------------------------------
+
+If your application uses :term:`ZCML`, you can replace the Forbidden view by
+placing something like the following ZCML in your ``configure.zcml`` file.
+
+.. code-block:: xml
+ :linenos:
+
+ <view
+ view="helloworld.views.notfound_view"
+ context="pyramid.exceptions.Forbidden"
+ />
+
+Replace ``helloworld.views.forbidden_view`` with the Python dotted name to
+the forbidden view you want to use.
+
+See :ref:`changing_the_forbidden_view` for more information.
+
+.. _changing_traverser_zcml:
+
+Configuring an Alternate Traverser via ZCML
+-------------------------------------------
+
+Use an ``adapter`` stanza in your application's ``configure.zcml`` to
+change the default traverser:
+
+.. code-block:: xml
+ :linenos:
+
+ <adapter
+ factory="myapp.traversal.Traverser"
+ provides="pyramid.interfaces.ITraverser"
+ for="*"
+ />
+
+Or to register a traverser for a specific resource type:
+
+.. code-block:: xml
+ :linenos:
+
+ <adapter
+ factory="myapp.traversal.Traverser"
+ provides="pyramid.interfaces.ITraverser"
+ for="myapp.resources.MyRoot"
+ />
+
+See :ref:`changing_the_traverser` for more information.
+
+.. index::
+ single: url generator
+
+.. _changing_resource_url_zcml:
+
+Changing ``resource_url`` URL Generation via ZCML
+-------------------------------------------------
+
+You can change how :func:`pyramid.url.resource_url` generates a URL for a
+specific type of resource by adding an adapter statement to your
+``configure.zcml``.
+
+.. code-block:: xml
+ :linenos:
+
+ <adapter
+ factory="myapp.traversal.URLGenerator"
+ provides="pyramid.interfaces.IContextURL"
+ for="myapp.resources.MyRoot *"
+ />
+
+See :ref:`changing_resource_url` for more information.
+
+.. _changing_request_factory_zcml:
+
+Changing the Request Factory via ZCML
+-------------------------------------
+
+A ``MyRequest`` class can be registered via ZCML as a request factory through
+the use of the ZCML ``utility`` directive. In the below, we assume it lives
+in a package named ``mypackage.mymodule``.
+
+.. code-block:: xml
+ :linenos:
+
+ <utility
+ component="mypackage.mymodule.MyRequest"
+ provides="pyramid.interfaces.IRequestFactory"
+ />
+
+See :ref:`changing_request_factory` for more information.
+
+.. _adding_renderer_globals_zcml:
+
+Changing the Renderer Globals Factory via ZCML
+----------------------------------------------
+
+A renderer globals factory can be registered via ZCML as a through the use of
+the ZCML ``utility`` directive. In the below, we assume a
+``renderers_globals_factory`` function lives in a package named
+``mypackage.mymodule``.
+
+.. code-block:: xml
+ :linenos:
+
+ <utility
+ component="mypackage.mymodule.renderer_globals_factory"
+ provides="pyramid.interfaces.IRendererGlobalsFactory"
+ />
-.. - hooks chapter still has topics for ZCML
+See :ref:`adding_renderer_globals` for more information.
diff --git a/docs/narr/extending.rst b/docs/narr/extending.rst
index 9802a01f6..524dcb2ac 100644
--- a/docs/narr/extending.rst
+++ b/docs/narr/extending.rst
@@ -3,11 +3,61 @@
Extending An Existing :app:`Pyramid` Application
===================================================
-If the developer of a :app:`Pyramid` application has obeyed certain
-constraints while building that application, a third party should be
-able to change its behavior without needing to modify its source code.
-The behavior of a :app:`Pyramid` application that obeys certain
-constraints can be *overridden* or *extended* without modification.
+If a :app:`Pyramid` developer has obeyed certain constraints while building
+an application, a third party should be able to change the application's
+behavior without needing to modify its source code. The behavior of a
+:app:`Pyramid` application that obeys certain constraints can be *overridden*
+or *extended* without modification.
+
+We'll define some jargon here for the benefit of identifying the parties
+involved in such an effort.
+
+Developer
+ The original application developer.
+
+Integrator
+ Another developer who wishes to reuse the application written by the
+ original application developer in an unanticipated context. He may also
+ wish to modify the original application without changing the original
+ application's source code.
+
+The Difference Between "Extensible" and "Pluggable" Applications
+----------------------------------------------------------------
+
+Other web frameworks, such as :term:`Django`, advertise that they allow
+developers to create "pluggable applications". They claim that if you create
+an application in a certain way, it will be integratable in a sensible,
+structured way into another arbitrarily-written application or project
+created by a third-party developer.
+
+:app:`Pyramid`, as a platform, does not claim to provide such a feature. The
+platform provides no guarantee that you can create an application and package
+it up such that an arbitrary integrator can use it as a subcomponent in a
+larger Pyramid application or project. Pyramid does not mandate the
+constraints necessary for such a pattern to work satisfactorily. Because
+Pyramid is not very "opinionated", developers are able to use wildly
+different patterns and technologies to build an application. A given Pyramid
+application may happen to be reusable by a particular third party integrator,
+because the integrator and the original developer may share similar base
+technology choices (such as the use of a particular relational database or
+ORM). But the same application may not be reusable by a different developer,
+because he has made different technology choices which are incompatible with
+the original developer's.
+
+As a result, the concept of a "pluggable application" is left to layers built
+above Pyramid, such as a "CMS" layer or "application server" layer. Such
+layers are apt to provide the necessary "opinions" (such as mandating a
+storage layer, a templating system, and a structured, well-documented pattern
+of registering that certain URLs map to certain bits of code) which makes the
+concept of a "pluggable application" possible. "Pluggable applications",
+thus, should not plug in to Pyramid itself but should instead plug into a
+system written atop Pyramid.
+
+Although it does not provide for "pluggable applications", Pyramid *does*
+provide a rich set of mechanisms which allows for the extension of a single
+existing application. Such features can be used by frameworks built using
+Pyramid as a base. All Pyramid applications may not be *pluggable*, but all
+Pyramid applications are *extensible*.
.. index::
single: extensible application
@@ -15,65 +65,65 @@ constraints can be *overridden* or *extended* without modification.
Rules for Building An Extensible Application
--------------------------------------------
-There's only one rule you need to obey if you want to build a
-maximally extensible :app:`Pyramid` application: you should not use
-any :term:`configuration decoration` or :term:`imperative
-configuration`. This means the application developer should avoid
-relying on :term:`configuration decoration` meant to be detected via
-a :term:`scan`, and you mustn't configure your :app:`Pyramid`
-application *imperatively* by using any code which configures the
-application through methods of the :term:`Configurator` (except for
-the :meth:`pyramid.config.Configurator.load_zcml` method).
-
-Instead, you must always use :term:`ZCML` for the equivalent
-purposes. :term:`ZCML` declarations that belong to an application can be
-"overridden" by integrators as necessary, but decorators and imperative code
-which perform the same tasks cannot. Use only :term:`ZCML` to configure your
-application if you'd like it to be extensible. See
+There is only one rule you need to obey if you want to build a maximally
+extensible :app:`Pyramid` application: as a developer, you should factor any
+overrideable :term:`imperative configuration` you've created into functions
+which can be used via :meth:`pyramid.config.Configurator.include` rather than
+inlined as calls to methods of a :term:`Configurator` within the ``main``
+function in your application's ``__init__.py``. For example, rather than:
+
+.. code-block:: python
+ :linenos:
+
+ from pyramid.config import Configurator
+
+ if __name__ == '__main__':
+ config = Configurator()
+ config.add_view('myapp.views.view1', name='view1')
+ config.add_view('myapp.views.view2', name='view2')
+
+You should do move the calls to ``add_view`` outside of the (non-reusable)
+``if __name__ == '__main__'`` block, and into a reusable function:
+
+.. code-block:: python
+ :linenos:
+
+ from pyramid.config import Configurator
+
+ if __name__ == '__main__':
+ config = Configurator()
+ config.include(add_views)
+
+ def add_views(config):
+ config.add_view('myapp.views.view1', name='view1')
+ config.add_view('myapp.views.view2', name='view2')
+
+Doing this allows an integrator to maximally reuse the configuration
+statements that relate to your application by allowing him to selectively
+include or disinclude the configuration functions you've created from an
+"override package".
+
+Alternately, you can use :term:`ZCML` for the purpose of making configuration
+extensible and overrideable. :term:`ZCML` declarations that belong to an
+application can be overridden and extended by integrators as necessary in a
+similar fashion. If you use only :term:`ZCML` to configure your application,
+it will automatically be maximally extensible without any manual effort. See
:ref:`declarative_chapter` for information about using ZCML.
Fundamental Plugpoints
~~~~~~~~~~~~~~~~~~~~~~
The fundamental "plug points" of an application developed using
-:app:`Pyramid` are *routes*, *views*, and *resources*. Routes are
-declarations made using the ZCML ``<route>`` directive. Views are
-declarations made using the ZCML ``<view>`` directive (or the
-``@view_config`` decorator). Resources are files that are accessed by
-:app:`Pyramid` using the :term:`pkg_resources` API such as static
-files and templates.
-
-.. index::
- single: ZCML granularity
-
-ZCML Granularity
-~~~~~~~~~~~~~~~~
-
-It's extremely helpful to third party application "extenders" (aka
-"integrators") if the :term:`ZCML` that composes the configuration for
-an application is broken up into separate files which do very specific
-things. These more specific ZCML files can be reintegrated within the
-application's main ``configure.zcml`` via ``<include
-file="otherfile.zcml"/>`` declarations. When ZCML files contain sets
-of specific declarations, an integrator can avoid including any ZCML
-he does not want by including only ZCML files which contain the
-declarations he needs. He is not forced to "accept everything" or
-"use nothing".
-
-For example, it's often useful to put all ``<route>`` declarations in
-a separate ZCML file, as ``<route>`` statements have a relative
-ordering that is extremely important to the application: if an
-extender wants to add a route to the "middle" of the routing table, he
-will always need to disuse all the routes and cut and paste the
-routing configuration into his own application. It's useful for the
-extender to be able to disuse just a *single* ZCML file in this case,
-accepting the remainder of the configuration from other :term:`ZCML`
-files in the original application.
-
-Granularizing ZCML is not strictly required. An extender can always
-disuse *all* your ZCML, choosing instead to copy and paste it into his
-own package, if necessary. However, doing so is considerate, and
-allows for the best reusability.
+:app:`Pyramid` are *routes*, *views*, and *assets*. Routes are declarations
+made using the :meth:`pyramid.config.Configurator.add_route` method (or the
+ZCML ``<route>`` directive). Views are declarations made using the
+:meth:`pyramid.config.Configurator.add_view` method (or the ZCML ``<view>``
+directive). Assets are files that are accessed by :app:`Pyramid` using the
+:term:`pkg_resources` API such as static files and templates via a
+:term:`asset specification`. Other directives and configurator methods also
+deal in routes, views, and assets. For example,
+:meth:`pyramid.config.Configurator.add_handler` adds a single route, and some
+number of views.
.. index::
single: extending an existing application
@@ -81,96 +131,88 @@ allows for the best reusability.
Extending an Existing Application
---------------------------------
-The steps for extending an existing application depend largely on
-whether the application does or does not use configuration decorators
-and/or imperative code.
+The steps for extending an existing application depend largely on whether the
+application does or does not use configuration decorators and/or imperative
+code.
+
+If The Application Has Configuration Decorations
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+You've inherited a :app:`Pyramid` application which you'd like to extend or
+override that uses :class:`pyramid.view.view_config` decorators or other
+:term:`configuration decoration` decorators.
-Extending an Application Which Possesses Configuration Decorators Or Which Does Configuration Imperatively
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+If you just want to *extend* the application, you can run a :term:`scan`
+against the application's package, then add additional configuration that
+registers more views or routes.
-If you've inherited a :app:`Pyramid` application which uses
-:class:`pyramid.view.view_config` decorators or which performs
-configuration imperatively, one of two things may be true:
+.. code-block:: python
+ :linenos:
+
+ if __name__ == '__main__':
+ config.scan('someotherpackage')
+ config.add_view('mypackage.views.myview', name='myview')
-- If you just want to *extend* the application, you can write
- additional ZCML that registers more views or routes, loading any
- existing ZCML and continuing to use any existing imperative
- configuration done by the original application.
+If you want to *override* configuration in the application, you *may* need to
+run :meth:`pyramid.config.Configurator.commit` after performing the scan of
+the original package, then add additional configuration that registers more
+views or routes which performs overrides.
-- If you want to *override* configuration in the application, you
- *may* need to change the source code of the original application.
+.. code-block:: python
+ :linenos:
- If the only source of trouble is the existence of
- :class:`pyramid.view.view_config` decorators, you can just prevent a
- :term:`scan` from happening (by omitting the ``<scan>`` declaration
- from ZCML or omitting any call to the
- :meth:`pyramid.config.Configurator.scan` method). This
- will cause the decorators to do nothing. At this point, you will
- need to convert all the configuration done in decorators into
- equivalent :term:`ZCML` and add that ZCML to a separate Python
- package as described in :ref:`extending_the_application`.
+ if __name__ == '__main__':
+ config.scan('someotherpackage')
+ config.commit()
+ config.add_view('mypackage.views.myview', name='myview'
- If the source of trouble is configuration done imperatively in a
- function called during application startup, you'll need to change
- the code: convert imperative configuration statements into
- equivalent :term:`ZCML` declarations.
+Once this is done, you should be able to extend or override the application
+like any other (see :ref:`extending_the_application`).
-Once this is done, you should be able to extend or override the
-application like any other (see :ref:`extending_the_application`).
+You can alternately just prevent a :term:`scan` from happening (by omitting
+any call to the :meth:`pyramid.config.Configurator.scan` method). This will
+cause the decorators attached to objects in the target application to do
+nothing. At this point, you will need to convert all the configuration done
+in decorators into equivalent imperative configuration or ZCML and add that
+configuration or ZCML to a separate Python package as described in
+:ref:`extending_the_application`.
.. _extending_the_application:
-Extending an Application Which Does Not Possess Configuration Decorators or Imperative Configuration
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-To extend or override the behavior of an existing application, you
-will need to write some :term:`ZCML`, and perhaps some implementations
-of the types of things you'd like to override (such as views), which
-are referred to within that ZCML.
-
-The general pattern for extending an existing application looks
-something like this:
-
-- Create a new Python package. The easiest way to do this is to
- create a new :app:`Pyramid` application using the "paster"
- template mechanism. See :ref:`creating_a_project` for more
- information.
-
-- Install the new package into the same Python environment as the
- original application (e.g. ``python setup.py develop`` or ``python
- setup.py install``).
-
-- Change the ``configure.zcml`` in the new package to include the
- original :app:`Pyramid` application's ``configure.zcml`` via an
- include statement, e.g. ``<include package="theoriginalapp"/>``.
- Alternately, if the original application writer anticipated
- overriding some things and not others, instead of including the
- "main" ``configure.zcml`` of the original application, include only
- specific ZCML files from the original application using the ``file``
- attribute of the ``<include>`` statement, e.g. ``<include
- package="theoriginalapp" file="views.zcml"/>``.
-
-- On a line in the new package's ``configure.zcml`` file that falls
- after (XML-ordering-wise) all the ``include`` statements of the original
- package ZCML, put an ``includeOverrides`` statement which identifies
- *another* ZCML file within the new package (for example
- ``<includeOverrides file="overrides.zcml"/>``.
-
-- Create an ``overrides.zcml`` file within the new package. The
- statements in the ``overrides.zcml`` file will override any ZCML
- statements made within the original application (such as view
- declarations).
-
-- Create Python files containing views and other overridden elements,
- such as templates and static resources as necessary, and wire these
- up using ZCML registrations within the ``overrides.zcml`` file.
- These registrations may extend or override the original view
- registrations. See :ref:`overriding_views`,
- :ref:`overriding_routes` and :ref:`overriding_resources`.
+Extending the Application
+~~~~~~~~~~~~~~~~~~~~~~~~~
+
+To extend or override the behavior of an existing application, you will need
+to create a new package which includes the configuration of the old package,
+and you'll perhaps need to create implementations of the types of things
+you'd like to override (such as views), which are referred to within the
+original package.
-- In the ``__init__.py`` of the new package, load the ``configure.zcml`` file
- of the new package using the
- :meth:`pyramid.config.Configurator.load_zcml` method.
+The general pattern for extending an existing application looks something
+like this:
+
+- Create a new Python package. The easiest way to do this is to create a new
+ :app:`Pyramid` application using the "paster" template mechanism. See
+ :ref:`creating_a_project` for more information.
+
+- In the new package, create Python files containing views and other
+ overridden elements, such as templates and static resources as necessary.
+
+- Install the new package into the same Python environment as the original
+ application (e.g. ``python setup.py develop`` or ``python setup.py
+ install``).
+
+- Change the ``main`` function in the new package's ``__init__py`` to include
+ the original :app:`Pyramid` application's configuration functions via
+ :meth:`pyramid.config.Configurator.include` statements or a :term:`scan`.
+
+- Wire the new views and assets created in the new package up using
+ imperative registrations within the ``main`` function of the
+ ``__init__.py`` file of the new application. These wiring should happen
+ *after* including the configuration functions of the old application.
+ These registrations will extend or override any registrations performed by
+ the original application. See :ref:`overriding_views`,
+ :ref:`overriding_routes` and :ref:`overriding_resources`.
.. index::
pair: overriding; views
@@ -180,26 +222,44 @@ something like this:
Overriding Views
~~~~~~~~~~~~~~~~~
-The ZCML ``<view>`` declarations you make which *override* application
-behavior will usually have the same ``context`` and ``name`` (and
-:term:`predicate` attributes, if used) as the original. These
-``<view>`` declarations will point at "new" view code. The new view
-code itself will usually be cut-n-paste copies of view callables from
-the original application with slight tweaks. For example:
+The :term:`view configuration` declarations you make which *override*
+application behavior will usually have the same :term:`view predicate`
+attributes as the original you wish to override. These ``<view>``
+declarations will point at "new" view code, in the override package you've
+created. The new view code itself will usually be cut-n-paste copies of view
+callables from the original application with slight tweaks.
+
+For example, if the original application has the following
+``configure_views`` configuration method:
+
+.. code-block:: python
+ :linenos:
+
+ def configure_views(config):
+ config.add_view('theoriginalapp.views.theview', name='theview')
-.. code-block:: xml
+You can override the first view configuration statement made by
+``configure_views`` within the override package, after loading the original
+configuration function:
+
+.. code-block:: python
:linenos:
- <view
- context="theoriginalapplication.resources.SomeResource"
- name="theview"
- view=".views.a_view_that_does_something_slightly_different"
- />
+ from pyramid.config import Configurator
+ from originalapp import configure_views
+
+ if __name == '__main__':
+ config = Configurator()
+ config.include(configure_views)
+ config.add_view('theoverrideapp.views.theview', name='theview')
+
+In this case, the ``theoriginalapp.views.theview`` view will never be
+executed. Instead, a new view, ``theoverrideapp.views.theview`` will be
+executed instead, when request circumstances dictate.
-A similar pattern can be used to *extend* the application with ``<view>``
-declarations. Just register a new view against some existing resource type
-(using ``context``) and make sure the URLs it implies are available on some
-other page rendering.
+A similar pattern can be used to *extend* the application with ``add_view``
+declarations. Just register a new view against some other set of predicates
+to make sure the URLs it implies are available on some other page rendering.
.. index::
pair: overriding; routes
@@ -209,48 +269,27 @@ other page rendering.
Overriding Routes
~~~~~~~~~~~~~~~~~
-Route setup is currently typically performed in a sequence of ordered
-ZCML ``<route>`` declarations. Because these declarations are ordered
-relative to each other, and because this ordering is typically
-important, you should retain the relative ordering of these
-declarations when performing an override. Typically, this means
-*copying* all the ``<route>`` declarations into an external ZCML file
-and changing them as necessary. Then disinclude any ZCML from the
-original application which contains the original declarations.
+Route setup is currently typically performed in a sequence of ordered calls
+to :meth:`pyramid.config.Configurator.add_route`. Because these calls are
+ordered relative to each other, and because this ordering is typically
+important, you should retain their relative ordering when performing an
+override. Typically, this means *copying* all the ``add_route`` statements
+into the override package's file and changing them as necessary. Then
+disinclude any ``add_route`` statements from the original application.
.. index::
pair: overriding; resources
.. _overriding_resources:
-Overriding Resources
-~~~~~~~~~~~~~~~~~~~~
-
-"Resource" files are static files on the filesystem that are
-accessible within a Python *package*. An entire chapter is devoted to
-resources: :ref:`resources_chapter`. Within this chapter is a section
-named :ref:`overriding_resources_section`. This section of that
-chapter describes in detail how to override package resources with
-other resources by using :term:`ZCML` ``<resource>`` declarations. Add
-such ``<resource>`` declarations to your override package's
-``configure.zcml`` to perform overrides.
-
-.. index::
- single: ZCML inclusion
-
-Dealing With ZCML Inclusions
-----------------------------
-
-Sometimes it's possible to include only certain ZCML files from an
-application that contain only the registrations you really need,
-omitting others. But sometimes it's not. For brute force purposes,
-when you're getting ``view`` or ``route`` registrations that you don't
-actually want in your overridden application, it's always appropriate
-to just *not include* any ZCML file from the overridden application.
-Instead, just cut and paste the entire contents of the
-``configure.zcml`` (and any ZCML file included by the overridden
-application's ``configure.zcml``) into your own package and omit the
-``<include package=""/>`` ZCML declaration in the overriding package's
-``configure.zcml``.
-
+Overriding Assets
+~~~~~~~~~~~~~~~~~
+Assets are files on the filesystem that are accessible within a Python
+*package*. An entire chapter is devoted to resources: :ref:`assets_chapter`.
+Within this chapter is a section named :ref:`overriding_assets_section`.
+This section of that chapter describes in detail how to override package
+resources with other resources by using the
+:meth:`pyramid.config.Configurator.override_asset` method. Add such
+``override_asset`` calls to your override package's ``__init__.py`` to
+perform overrides.
diff --git a/docs/narr/flash.rst b/docs/narr/flash.rst
index d41c2cdaf..037bfc416 100644
--- a/docs/narr/flash.rst
+++ b/docs/narr/flash.rst
@@ -38,7 +38,7 @@ provide is not modified in any way.
The ``queue`` argument allows you to choose a queue to which to append the
message you provide. This can be used to push different kinds of messages
-into flash storage for later display in different places on a page. You cam
+into flash storage for later display in different places on a page. You can
pass any name for your queue, but it must be a string. The default value is
the empty string, which chooses the default queue. Each queue is independent,
and can be popped by ``pop_flash`` or examined via ``peek_flash`` separately.
@@ -49,20 +49,22 @@ default flash message queue.
request.session.flash(msg, 'myappsqueue')
-The ``allow_duplicate`` argument, which defaults to ``True``. If this is
+The ``allow_duplicate`` argument defaults to ``True``. If this is
``False``, if you attempt to add a message to a queue which is already
present in the queue, it will not be added.
Using the ``session.pop_flash`` Method
--------------------------------------
-Once one or more messages has been added to a flash queue by the
+Once one or more messages have been added to a flash queue by the
``session.flash`` API, the ``session.pop_flash`` API can be used to pop that
queue and return it for use.
To pop a particular queue of messages from the flash object, use the session
object's ``pop_flash`` method.
+.. method:: pop_flash(queue='')
+
.. code-block:: python
:linenos:
@@ -85,14 +87,16 @@ been popped.
The object returned from ``pop_flash`` is a list.
-Using the ``session.pop_flash`` Method
---------------------------------------
+Using the ``session.peek_flash`` Method
+---------------------------------------
Once one or more messages has been added to a flash queue by the
``session.flash`` API, the ``session.peek_flash`` API can be used to "peek"
at that queue. Unlike ``session.pop_flash``, the queue is not popped from
flash storage.
+.. method:: peek_flash(queue='')
+
.. code-block:: python
:linenos:
diff --git a/docs/narr/hooks.rst b/docs/narr/hooks.rst
index 006f5d5cb..2917b5254 100644
--- a/docs/narr/hooks.rst
+++ b/docs/narr/hooks.rst
@@ -3,8 +3,8 @@
Using Hooks
===========
-"Hooks" can be used to influence the behavior of the :app:`Pyramid`
-framework in various ways.
+"Hooks" can be used to influence the behavior of the :app:`Pyramid` framework
+in various ways.
.. index::
single: not found view
@@ -14,61 +14,38 @@ framework in various ways.
Changing the Not Found View
---------------------------
-When :app:`Pyramid` can't map a URL to view code, it invokes a
-:term:`not found view`, which is a :term:`view callable`. A default
-notfound view exists. The default not found view can be overridden
-through application configuration. This override can be done via
-:term:`imperative configuration` or :term:`ZCML`.
+When :app:`Pyramid` can't map a URL to view code, it invokes a :term:`not
+found view`, which is a :term:`view callable`. A default notfound view
+exists. The default not found view can be overridden through application
+configuration.
-The :term:`not found view` callable is a view callable like any other.
-The :term:`view configuration` which causes it to be a "not found"
-view consists only of naming the :exc:`pyramid.exceptions.NotFound`
-class as the ``context`` of the view configuration.
+The :term:`not found view` callable is a view callable like any other. The
+:term:`view configuration` which causes it to be a "not found" view consists
+only of naming the :exc:`pyramid.exceptions.NotFound` class as the
+``context`` of the view configuration.
-.. topic:: Using Imperative Configuration
+If your application uses :term:`imperative configuration`, you can replace
+the Not Found view by using the :meth:`pyramid.config.Configurator.add_view`
+method to register an "exception view":
- If your application uses :term:`imperative configuration`, you can
- replace the Not Found view by using the
- :meth:`pyramid.config.Configurator.add_view` method to
- register an "exception view":
-
- .. code-block:: python
- :linenos:
-
- from pyramid.exceptions import NotFound
- from helloworld.views import notfound_view
- config.add_view(notfound_view, context=NotFound)
-
- Replace ``helloworld.views.notfound_view`` with a reference to the
- Python :term:`view callable` you want to use to represent the Not
- Found view.
-
-.. topic:: Using ZCML
-
- If your application uses :term:`ZCML`, you can replace the Not Found
- view by placing something like the following ZCML in your
- ``configure.zcml`` file.
-
- .. code-block:: xml
- :linenos:
+.. code-block:: python
+ :linenos:
- <view
- view="helloworld.views.notfound_view"
- context="pyramid.exceptions.NotFound"
- />
+ from pyramid.exceptions import NotFound
+ from helloworld.views import notfound_view
+ config.add_view(notfound_view, context=NotFound)
- Replace ``helloworld.views.notfound_view`` with the Python dotted name
- to the notfound view you want to use.
+Replace ``helloworld.views.notfound_view`` with a reference to the
+:term:`view callable` you want to use to represent the Not Found view.
-Like any other view, the notfound view must accept at least a
-``request`` parameter, or both ``context`` and ``request``. The
-``request`` is the current :term:`request` representing the denied
-action. The ``context`` (if used in the call signature) will be the
-instance of the :exc:`pyramid.exceptions.NotFound` exception that
-caused the view to be called.
+Like any other view, the notfound view must accept at least a ``request``
+parameter, or both ``context`` and ``request``. The ``request`` is the
+current :term:`request` representing the denied action. The ``context`` (if
+used in the call signature) will be the instance of the
+:exc:`pyramid.exceptions.NotFound` exception that caused the view to be
+called.
-Here's some sample code that implements a minimal NotFound view
-callable:
+Here's some sample code that implements a minimal NotFound view callable:
.. code-block:: python
:linenos:
@@ -93,6 +70,9 @@ callable:
:exc:`pyramid.exceptions.NotFound` exception instance. If available, the
resource context will still be available as ``request.context``.
+For information about how to configure a not found view via :term:`ZCML`, see
+:ref:`notfound_zcml`.
+
.. index::
single: forbidden view
@@ -101,59 +81,36 @@ callable:
Changing the Forbidden View
---------------------------
-When :app:`Pyramid` can't authorize execution of a view based on
-the :term:`authorization policy` in use, it invokes a :term:`forbidden
-view`. The default forbidden response has a 401 status code and is
-very plain, but the view which generates it can be overridden as
-necessary using either :term:`imperative configuration` or
-:term:`ZCML`.
-
-The :term:`forbidden view` callable is a view callable like any other.
-The :term:`view configuration` which causes it to be a "not found"
-view consists only of naming the :exc:`pyramid.exceptions.Forbidden`
-class as the ``context`` of the view configuration.
-
-.. topic:: Using Imperative Configuration
-
- If your application uses :term:`imperative configuration`, you can
- replace the Forbidden view by using the
- :meth:`pyramid.config.Configurator.add_view` method to
- register an "exception view":
-
- .. code-block:: python
- :linenos:
-
- from helloworld.views import forbidden_view
- from pyramid.exceptions import Forbidden
- config.add_view(forbidden_view, context=Forbidden)
-
- Replace ``helloworld.views.forbidden_view`` with a reference to the
- Python :term:`view callable` you want to use to represent the
- Forbidden view.
+When :app:`Pyramid` can't authorize execution of a view based on the
+:term:`authorization policy` in use, it invokes a :term:`forbidden view`.
+The default forbidden response has a 401 status code and is very plain, but
+the view which generates it can be overridden as necessary.
-.. topic:: Using ZCML
+The :term:`forbidden view` callable is a view callable like any other. The
+:term:`view configuration` which causes it to be a "not found" view consists
+only of naming the :exc:`pyramid.exceptions.Forbidden` class as the
+``context`` of the view configuration.
- If your application uses :term:`ZCML`, you can replace the
- Forbidden view by placing something like the following ZCML in your
- ``configure.zcml`` file.
+You can replace the forbidden view by using the
+:meth:`pyramid.config.Configurator.add_view` method to register an "exception
+view":
- .. code-block:: xml
- :linenos:
+.. code-block:: python
+ :linenos:
- <view
- view="helloworld.views.notfound_view"
- context="pyramid.exceptions.Forbidden"
- />
+ from helloworld.views import forbidden_view
+ from pyramid.exceptions import Forbidden
+ config.add_view(forbidden_view, context=Forbidden)
- Replace ``helloworld.views.forbidden_view`` with the Python
- dotted name to the forbidden view you want to use.
+Replace ``helloworld.views.forbidden_view`` with a reference to the Python
+:term:`view callable` you want to use to represent the Forbidden view.
-Like any other view, the forbidden view must accept at least a
-``request`` parameter, or both ``context`` and ``request``. The
-``context`` (available as ``request.context`` if you're using the
-request-only view argument pattern) is the context found by the router
-when the view invocation was denied. The ``request`` is the current
-:term:`request` representing the denied action.
+Like any other view, the forbidden view must accept at least a ``request``
+parameter, or both ``context`` and ``request``. The ``context`` (available
+as ``request.context`` if you're using the request-only view argument
+pattern) is the context found by the router when the view invocation was
+denied. The ``request`` is the current :term:`request` representing the
+denied action.
Here's some sample code that implements a minimal forbidden view:
@@ -161,10 +118,10 @@ Here's some sample code that implements a minimal forbidden view:
:linenos:
from pyramid.views import view_config
+ from pyramid.response import Response
- @view_config(renderer='templates/login_form.pt')
def forbidden_view(request):
- return {}
+ return Response('forbidden')
.. note:: When a forbidden view callable is invoked, it is passed a
:term:`request`. The ``exception`` attribute of the request will
@@ -181,164 +138,26 @@ Here's some sample code that implements a minimal forbidden view:
an alternate forbidden view. For example, it would make sense to
return a response with a ``403 Forbidden`` status code.
-.. index::
- single: traverser
-
-.. _changing_the_traverser:
-
-Changing the Traverser
-----------------------
-
-The default :term:`traversal` algorithm that :app:`Pyramid` uses is
-explained in :ref:`traversal_algorithm`. Though it is rarely
-necessary, this default algorithm can be swapped out selectively for a
-different traversal pattern via configuration.
-
-Use an ``adapter`` stanza in your application's ``configure.zcml`` to
-change the default traverser:
-
-.. code-block:: xml
- :linenos:
-
- <adapter
- factory="myapp.traversal.Traverser"
- provides="pyramid.interfaces.ITraverser"
- for="*"
- />
-
-In the example above, ``myapp.traversal.Traverser`` is assumed to be
-a class that implements the following interface:
-
-.. code-block:: python
- :linenos:
-
- class Traverser(object):
- def __init__(self, root):
- """ Accept the root object returned from the root factory """
-
- def __call__(self, request):
- """ Return a dictionary with (at least) the keys ``root``,
- ``context``, ``view_name``, ``subpath``, ``traversed``,
- ``virtual_root``, and ``virtual_root_path``. These values are
- typically the result of a resource tree traversal. ``root``
- is the physical root object, ``context`` will be a resource
- object, ``view_name`` will be the view name used (a Unicode
- name), ``subpath`` will be a sequence of Unicode names that
- followed the view name but were not traversed, ``traversed``
- will be a sequence of Unicode names that were traversed
- (including the virtual root path, if any) ``virtual_root``
- will be a resource object representing the virtual root (or the
- physical root if traversal was not performed), and
- ``virtual_root_path`` will be a sequence representing the
- virtual root path (a sequence of Unicode names) or None if
- traversal was not performed.
-
- Extra keys for special purpose functionality can be added as
- necessary.
-
- All values returned in the dictionary will be made available
- as attributes of the ``request`` object.
- """
-
-More than one traversal algorithm can be active at the same time. For
-instance, if your :term:`root factory` returns more than one type of
-object conditionally, you could claim that an alternate traverser
-adapter is ``for`` only one particular class or interface. When the
-root factory returned an object that implemented that class or
-interface, a custom traverser would be used. Otherwise, the default
-traverser would be used. For example:
-
-.. code-block:: xml
- :linenos:
-
- <adapter
- factory="myapp.traversal.Traverser"
- provides="pyramid.interfaces.ITraverser"
- for="myapp.resources.MyRoot"
- />
-
-If the above stanza was added to a ``configure.zcml`` file,
-:app:`Pyramid` would use the ``myapp.traversal.Traverser`` only
-when the application :term:`root factory` returned an instance of the
-``myapp.resources.MyRoot`` object. Otherwise it would use the default
-:app:`Pyramid` traverser to do traversal.
+For information about how to configure a forbidden view via :term:`ZCML`, see
+:ref:`forbidden_zcml`.
.. index::
- single: url generator
-
-Changing How :mod:`pyramid.url.resource_url` Generates a URL
-------------------------------------------------------------
-
-When you add a traverser as described in :ref:`changing_the_traverser`, it's
-often convenient to continue to use the :func:`pyramid.url.resource_url` API.
-However, since the way traversal is done will have been modified, the URLs it
-generates by default may be incorrect.
-
-If you've added a traverser, you can change how
-:func:`pyramid.url.resource_url` generates a URL for a specific type of
-resource by adding an adapter stanza for
-:class:`pyramid.interfaces.IContextURL` to your application's
-``configure.zcml``:
-
-.. code-block:: xml
- :linenos:
-
- <adapter
- factory="myapp.traversal.URLGenerator"
- provides="pyramid.interfaces.IContextURL"
- for="myapp.resources.MyRoot *"
- />
-
-In the above example, the ``myapp.traversal.URLGenerator`` class will
-be used to provide services to :func:`pyramid.url.resource_url` any
-time the :term:`context` passed to ``resource_url`` is of class
-``myapp.resources.MyRoot``. The asterisk following represents the type
-of interface that must be possessed by the :term:`request` (in this
-case, any interface, represented by asterisk).
-
-The API that must be implemented by a class that provides
-:class:`pyramid.interfaces.IContextURL` is as follows:
-
-.. code-block:: python
- :linenos:
-
- from zope.interface import Interface
-
- class IContextURL(Interface):
- """ An adapter which deals with URLs related to a context.
- """
- def __init__(self, context, request):
- """ Accept the context and request """
-
- def virtual_root(self):
- """ Return the virtual root object related to a request and the
- current context"""
-
- def __call__(self):
- """ Return a URL that points to the context """
-
-The default context URL generator is available for perusal as the
-class :class:`pyramid.traversal.TraversalContextURL` in the
-`traversal module
-<http://github.com/Pylons/pyramid/blob/master/pyramid/traversal.py>`_ of
-the :term:`Pylons` GitHub Pyramid repository.
+ single: request factory
.. _changing_the_request_factory:
Changing the Request Factory
----------------------------
-Whenever :app:`Pyramid` handles a :term:`WSGI` request, it creates
-a :term:`request` object based on the WSGI environment it has been
-passed. By default, an instance of the
-:class:`pyramid.request.Request` class is created to represent the
-request object.
+Whenever :app:`Pyramid` handles a :term:`WSGI` request, it creates a
+:term:`request` object based on the WSGI environment it has been passed. By
+default, an instance of the :class:`pyramid.request.Request` class is created
+to represent the request object.
-The class (aka "factory") that :app:`Pyramid` uses to create a
-request object instance can be changed by passing a
-``request_factory`` argument to the constructor of the
-:term:`configurator`. This argument can be either a callable or a
-:term:`dotted Python name` representing a callable.
+The class (aka "factory") that :app:`Pyramid` uses to create a request object
+instance can be changed by passing a ``request_factory`` argument to the
+constructor of the :term:`configurator`. This argument can be either a
+callable or a :term:`dotted Python name` representing a callable.
.. code-block:: python
:linenos:
@@ -350,24 +169,9 @@ request object instance can be changed by passing a
config = Configurator(request_factory=MyRequest)
-The same ``MyRequest`` class can alternately be registered via ZCML as
-a request factory through the use of the ZCML ``utility`` directive.
-In the below, we assume it lives in a package named
-``mypackage.mymodule``.
-
-.. code-block:: xml
- :linenos:
-
- <utility
- component="mypackage.mymodule.MyRequest"
- provides="pyramid.interfaces.IRequestFactory"
- />
-
-Lastly, if you're doing imperative configuration, and you'd rather do
-it after you've already constructed a :term:`configurator` it can also
-be registered via the
-:meth:`pyramid.config.Configurator.set_request_factory`
-method:
+If you're doing imperative configuration, and you'd rather do it after you've
+already constructed a :term:`configurator` it can also be registered via the
+:meth:`pyramid.config.Configurator.set_request_factory` method:
.. code-block:: python
:linenos:
@@ -381,26 +185,29 @@ method:
config = Configurator()
config.set_request_factory(MyRequest)
+To use ZCML for the same purpose, see :ref:`changing_request_factory_zcml`.
+
+.. index::
+ single: renderer globals
+
.. _adding_renderer_globals:
Adding Renderer Globals
-----------------------
-Whenever :app:`Pyramid` handles a request to perform a rendering
-(after a view with a ``renderer=`` configuration attribute is invoked,
-or when the any of the methods beginning with ``render`` within the
-:mod:`pyramid.renderers` module are called), *renderer globals* can
-be injected into the *system* values sent to the renderer. By
-default, no renderer globals are injected, and the "bare" system
-values (such as ``request``, ``context``, and ``renderer_name``) are
-the only values present in the system dictionary passed to every
-renderer.
-
-A callback that :app:`Pyramid` will call every time a renderer is
-invoked can be added by passing a ``renderer_globals_factory``
-argument to the constructor of the :term:`configurator`. This
-callback can either be a callable object or a :term:`dotted Python
-name` representing such a callable.
+Whenever :app:`Pyramid` handles a request to perform a rendering (after a
+view with a ``renderer=`` configuration attribute is invoked, or when the any
+of the methods beginning with ``render`` within the :mod:`pyramid.renderers`
+module are called), *renderer globals* can be injected into the *system*
+values sent to the renderer. By default, no renderer globals are injected,
+and the "bare" system values (such as ``request``, ``context``, and
+``renderer_name``) are the only values present in the system dictionary
+passed to every renderer.
+
+A callback that :app:`Pyramid` will call every time a renderer is invoked can
+be added by passing a ``renderer_globals_factory`` argument to the
+constructor of the :term:`configurator`. This callback can either be a
+callable object or a :term:`dotted Python name` representing such a callable.
.. code-block:: python
:linenos:
@@ -411,30 +218,15 @@ name` representing such a callable.
config = Configurator(
renderer_globals_factory=renderer_globals_factory)
-Such a callback must accept a single positional argument (notionally
-named ``system``) which will contain the original system values. It
-must return a dictionary of values that will be merged into the system
-dictionary. See :ref:`renderer_system_values` for discription of the
-values present in the system dictionary.
+Such a callback must accept a single positional argument (notionally named
+``system``) which will contain the original system values. It must return a
+dictionary of values that will be merged into the system dictionary. See
+:ref:`renderer_system_values` for discription of the values present in the
+system dictionary.
-A renderer globals factory can alternately be registered via ZCML as a
-through the use of the ZCML ``utility`` directive. In the below, we
-assume a ``renderers_globals_factory`` function lives in a package
-named ``mypackage.mymodule``.
-
-.. code-block:: xml
- :linenos:
-
- <utility
- component="mypackage.mymodule.renderer_globals_factory"
- provides="pyramid.interfaces.IRendererGlobalsFactory"
- />
-
-Lastly, if you're doing imperative configuration, and you'd rather do
-it after you've already constructed a :term:`configurator` it can also
-be registered via the
-:meth:`pyramid.config.Configurator.set_renderer_globals_factory`
-method:
+If you're doing imperative configuration, and you'd rather do it after you've
+already constructed a :term:`configurator` it can also be registered via the
+:meth:`pyramid.config.Configurator.set_renderer_globals_factory` method:
.. code-block:: python
:linenos:
@@ -450,6 +242,12 @@ method:
Another mechanism which allows event subscribers to add renderer global values
exists in :ref:`beforerender_event`.
+If you'd rather ZCML to register a renderer globals factory, see
+:ref:`adding_renderer_globals_zcml`.
+
+.. index::
+ single: before render event
+
.. _beforerender_event:
Using The Before Render Event
@@ -472,8 +270,8 @@ that can be used for this purpose. For example:
An object of this type is sent as an event just before a :term:`renderer` is
invoked (but *after* the application-level renderer globals factory added via
-:class:`pyramid.config.Configurator.set_renderer_globals_factory`, if
-any, has injected its own keys into the renderer globals dictionary).
+:class:`pyramid.config.Configurator.set_renderer_globals_factory`, if any,
+has injected its own keys into the renderer globals dictionary).
If a subscriber attempts to add a key that already exist in the renderer
globals dictionary, a :exc:`KeyError` is raised. This limitation is enforced
@@ -488,21 +286,24 @@ interface at :class:`pyramid.interfaces.IBeforeRender`.
Another mechanism which allows event subscribers more control when adding
renderer global values exists in :ref:`adding_renderer_globals`.
+.. index::
+ single: response callback
+
.. _using_response_callbacks:
Using Response Callbacks
------------------------
-Unlike many other web frameworks, :app:`Pyramid` does not eagerly
-create a global response object. Adding a :term:`response callback`
-allows an application to register an action to be performed against a
-response object once it is created, usually in order to mutate it.
+Unlike many other web frameworks, :app:`Pyramid` does not eagerly create a
+global response object. Adding a :term:`response callback` allows an
+application to register an action to be performed against a response object
+once it is created, usually in order to mutate it.
-The :meth:`pyramid.request.Request.add_response_callback` method is
-used to register a response callback.
+The :meth:`pyramid.request.Request.add_response_callback` method is used to
+register a response callback.
-A response callback is a callable which accepts two positional
-parameters: ``request`` and ``response``. For example:
+A response callback is a callable which accepts two positional parameters:
+``request`` and ``response``. For example:
.. code-block:: python
:linenos:
@@ -515,11 +316,11 @@ parameters: ``request`` and ``response``. For example:
No response callback is called if an unhandled exception happens in
application code, or if the response object returned by a :term:`view
-callable` is invalid. Response callbacks *are*, however, invoked when
-a :term:`exception view` is rendered successfully: in such a case, the
-:attr:`request.exception` attribute of the request when it enters a
-response callback will be an exception object instead of its default
-value of ``None``.
+callable` is invalid. Response callbacks *are*, however, invoked when a
+:term:`exception view` is rendered successfully: in such a case, the
+:attr:`request.exception` attribute of the request when it enters a response
+callback will be an exception object instead of its default value of
+``None``.
Response callbacks are called in the order they're added
(first-to-most-recently-added). All response callbacks are called *after*
@@ -532,18 +333,21 @@ response callback to happen as the result of *every* request, you must
re-register the callback into every new request (perhaps within a subscriber
of a :class:`pyramid.events.NewRequest` event).
+.. index::
+ single: finished callback
+
.. _using_finished_callbacks:
Using Finished Callbacks
------------------------
-A :term:`finished callback` is a function that will be called
-unconditionally by the :app:`Pyramid` :term:`router` at the very
-end of request processing. A finished callback can be used to perform
-an action at the end of a request unconditionally.
+A :term:`finished callback` is a function that will be called unconditionally
+by the :app:`Pyramid` :term:`router` at the very end of request processing.
+A finished callback can be used to perform an action at the end of a request
+unconditionally.
-The :meth:`pyramid.request.Request.add_finished_callback` method is
-used to register a finished callback.
+The :meth:`pyramid.request.Request.add_finished_callback` method is used to
+register a finished callback.
A finished callback is a callable which accepts a single positional
parameter: ``request``. For example:
@@ -563,25 +367,24 @@ parameter: ``request``. For example:
Finished callbacks are called in the order they're added ( first- to
most-recently- added). Finished callbacks (unlike a :term:`response
-callback`) are *always* called, even if an exception happens in
-application code that prevents a response from being generated.
-
-The set of finished callbacks associated with a request are called
-*very late* in the processing of that request; they are essentially
-the very last thing called by the :term:`router` before a request
-"ends". They are called after response processing has already occurred
-in a top-level ``finally:`` block within the router request processing
-code. As a result, mutations performed to the ``request`` provided to
-a finished callback will have no meaningful effect, because response
-processing will have already occurred, and the request's scope will
-expire almost immediately after all finished callbacks have been
-processed.
+callback`) are *always* called, even if an exception happens in application
+code that prevents a response from being generated.
+
+The set of finished callbacks associated with a request are called *very
+late* in the processing of that request; they are essentially the very last
+thing called by the :term:`router` before a request "ends". They are called
+after response processing has already occurred in a top-level ``finally:``
+block within the router request processing code. As a result, mutations
+performed to the ``request`` provided to a finished callback will have no
+meaningful effect, because response processing will have already occurred,
+and the request's scope will expire almost immediately after all finished
+callbacks have been processed.
It is often necessary to tell whether an exception occurred within
-:term:`view callable` code from within a finished callback: in such a
-case, the :attr:`request.exception` attribute of the request when it
-enters a response callback will be an exception object instead of its
-default value of ``None``.
+:term:`view callable` code from within a finished callback: in such a case,
+the :attr:`request.exception` attribute of the request when it enters a
+response callback will be an exception object instead of its default value of
+``None``.
Errors raised by finished callbacks are not handled specially. They
will be propagated to the caller of the :app:`Pyramid` router
@@ -592,28 +395,175 @@ finished callback to happen as the result of *every* request, you must
re-register the callback into every new request (perhaps within a subscriber
of a :class:`pyramid.events.NewRequest` event).
+.. index::
+ single: traverser
+
+.. _changing_the_traverser:
+
+Changing the Traverser
+----------------------
+
+The default :term:`traversal` algorithm that :app:`Pyramid` uses is explained
+in :ref:`traversal_algorithm`. Though it is rarely necessary, this default
+algorithm can be swapped out selectively for a different traversal pattern
+via configuration.
+
+.. code-block:: python
+ :linenos:
+
+ from pyramid.interfaces import ITraverser
+ from zope.interface import Interface
+ from myapp.traversal import Traverser
+
+ config.registry.registerAdapter(Traverser, (Interface,), ITraverser)
+
+In the example above, ``myapp.traversal.Traverser`` is assumed to be a class
+that implements the following interface:
+
+.. code-block:: python
+ :linenos:
+
+ class Traverser(object):
+ def __init__(self, root):
+ """ Accept the root object returned from the root factory """
+
+ def __call__(self, request):
+ """ Return a dictionary with (at least) the keys ``root``,
+ ``context``, ``view_name``, ``subpath``, ``traversed``,
+ ``virtual_root``, and ``virtual_root_path``. These values are
+ typically the result of a resource tree traversal. ``root``
+ is the physical root object, ``context`` will be a resource
+ object, ``view_name`` will be the view name used (a Unicode
+ name), ``subpath`` will be a sequence of Unicode names that
+ followed the view name but were not traversed, ``traversed``
+ will be a sequence of Unicode names that were traversed
+ (including the virtual root path, if any) ``virtual_root``
+ will be a resource object representing the virtual root (or the
+ physical root if traversal was not performed), and
+ ``virtual_root_path`` will be a sequence representing the
+ virtual root path (a sequence of Unicode names) or None if
+ traversal was not performed.
+
+ Extra keys for special purpose functionality can be added as
+ necessary.
+
+ All values returned in the dictionary will be made available
+ as attributes of the ``request`` object.
+ """
+
+More than one traversal algorithm can be active at the same time. For
+instance, if your :term:`root factory` returns more than one type of object
+conditionally, you could claim that an alternate traverser adapter is ``for``
+only one particular class or interface. When the root factory returned an
+object that implemented that class or interface, a custom traverser would be
+used. Otherwise, the default traverser would be used. For example:
+
+.. code-block:: python
+ :linenos:
+
+ from pyramid.interfaces import ITraverser
+ from zope.interface import Interface
+ from myapp.traversal import Traverser
+ from myapp.resources import MyRoot
+
+ config.registry.registerAdapter(Traverser, (MyRoot,), ITraverser)
+
+If the above stanza was added to a Pyramid ``__init__.py`` file's ``main``
+function, :app:`Pyramid` would use the ``myapp.traversal.Traverser`` only
+when the application :term:`root factory` returned an instance of the
+``myapp.resources.MyRoot`` object. Otherwise it would use the default
+:app:`Pyramid` traverser to do traversal.
+
+For information about how to configure an alternate traverser via
+:term:`ZCML`, see :ref:`changing_traverser_zcml`.
+
+.. index::
+ single: url generator
+
+.. _changing_resource_url:
+
+Changing How :mod:`pyramid.url.resource_url` Generates a URL
+------------------------------------------------------------
+
+When you add a traverser as described in :ref:`changing_the_traverser`, it's
+often convenient to continue to use the :func:`pyramid.url.resource_url` API.
+However, since the way traversal is done will have been modified, the URLs it
+generates by default may be incorrect.
+
+If you've added a traverser, you can change how
+:func:`pyramid.url.resource_url` generates a URL for a specific type of
+resource by adding a registerAdapter call for
+:class:`pyramid.interfaces.IContextURL` to your application:
+
+.. code-block:: python
+ :linenos:
+
+ from pyramid.interfaces import ITraverser
+ from zope.interface import Interface
+ from myapp.traversal import URLGenerator
+ from myapp.resources import MyRoot
+
+ config.registry.registerAdapter(URLGenerator, (MyRoot, Interface),
+ IContextURL)
+
+In the above example, the ``myapp.traversal.URLGenerator`` class will be used
+to provide services to :func:`pyramid.url.resource_url` any time the
+:term:`context` passed to ``resource_url`` is of class
+``myapp.resources.MyRoot``. The second argument in the ``(MyRoot,
+Interface)`` tuple represents the type of interface that must be possessed by
+the :term:`request` (in this case, any interface, represented by
+``zope.interface.Interface``).
+
+The API that must be implemented by a class that provides
+:class:`pyramid.interfaces.IContextURL` is as follows:
+
+.. code-block:: python
+ :linenos:
+
+ from zope.interface import Interface
+
+ class IContextURL(Interface):
+ """ An adapter which deals with URLs related to a context.
+ """
+ def __init__(self, context, request):
+ """ Accept the context and request """
+
+ def virtual_root(self):
+ """ Return the virtual root object related to a request and the
+ current context"""
+
+ def __call__(self):
+ """ Return a URL that points to the context """
+
+The default context URL generator is available for perusal as the class
+:class:`pyramid.traversal.TraversalContextURL` in the `traversal module
+<http://github.com/Pylons/pyramid/blob/master/pyramid/traversal.py>`_ of the
+:term:`Pylons` GitHub Pyramid repository.
+
+.. index::
+ single: configuration decorator
+
.. _registering_configuration_decorators:
Registering Configuration Decorators
------------------------------------
Decorators such as :class:`pyramid.view.view_config` don't change the
-behavior of the functions or classes they're decorating. Instead,
-when a :term:`scan` is performed, a modified version of the function
-or class is registered with :app:`Pyramid`.
-
-You may wish to have your own decorators that offer such
-behaviour. This is possible by using the :term:`Venusian` package in
-the same way that it is used by :app:`Pyramid`.
-
-By way of example, let's suppose you want to write a decorator that
-registers the function it wraps with a :term:`Zope Component
-Architecture` "utility" within the :term:`application registry`
-provided by :app:`Pyramid`. The application registry and the
-utility inside the registry is likely only to be available once your
-application's configuration is at least partially completed. A normal
-decorator would fail as it would be executed before the configuration
-had even begun.
+behavior of the functions or classes they're decorating. Instead, when a
+:term:`scan` is performed, a modified version of the function or class is
+registered with :app:`Pyramid`.
+
+You may wish to have your own decorators that offer such behaviour. This is
+possible by using the :term:`Venusian` package in the same way that it is
+used by :app:`Pyramid`.
+
+By way of example, let's suppose you want to write a decorator that registers
+the function it wraps with a :term:`Zope Component Architecture` "utility"
+within the :term:`application registry` provided by :app:`Pyramid`. The
+application registry and the utility inside the registry is likely only to be
+available once your application's configuration is at least partially
+completed. A normal decorator would fail as it would be executed before the
+configuration had even begun.
However, using :term:`Venusian`, the decorator could be written as
follows:
@@ -671,10 +621,8 @@ performed, enabling you to set up the utility in advance:
if __name__ == '__main__':
config = Configurator()
- config.begin()
config.registry.registerUtility(UtilityImplementation())
config.scan()
- config.end()
app = config.make_wsgi_app()
serve(app, host='0.0.0.0')
diff --git a/docs/narr/i18n.rst b/docs/narr/i18n.rst
index d8cc5cb1c..c2a5b8ce7 100644
--- a/docs/narr/i18n.rst
+++ b/docs/narr/i18n.rst
@@ -881,11 +881,8 @@ application startup. For example:
:linenos:
from pyramid.config import Configurator
- config.begin()
config.add_translation_dirs('my.application:locale/',
'another.application:locale/')
- # ...
- config.end()
A message catalog in a translation directory added via
:meth:`pyramid.config.Configurator.add_translation_dirs`
@@ -1020,9 +1017,7 @@ For example:
from pyramid.config import Configurator
config = Configurator()
- config.begin()
config.set_locale_negotiator(my_locale_negotiator)
- config.end()
.. note:: You can also add a custom locale negotiator via ZCML. See
:ref:`zcml_adding_a_locale_negotiator`
diff --git a/docs/narr/introduction.rst b/docs/narr/introduction.rst
index 3ade3726c..c61ef21d4 100644
--- a/docs/narr/introduction.rst
+++ b/docs/narr/introduction.rst
@@ -63,7 +63,7 @@ A Sense of Fun
Minimalism
:app:`Pyramid` provides only the very basics: *URL to code
- mapping*, *templating*, *security*, and *resources*. There is not
+ mapping*, *templating*, *security*, and *assets*. There is not
much more to the framework than these pieces: you are expected to
provide the rest.
diff --git a/docs/narr/project.rst b/docs/narr/project.rst
index 36f2d6975..5e84a4fa7 100644
--- a/docs/narr/project.rst
+++ b/docs/narr/project.rst
@@ -256,6 +256,8 @@ create`` -generated project. Within a project generated by the
single: IPython
single: paster pshell
+.. _interactive_shell:
+
The Interactive Shell
---------------------
@@ -908,6 +910,8 @@ example.
See :ref:`testing_chapter` for more information about writing :app:`Pyramid`
unit tests.
+.. _modifying_package_structure:
+
Modifying Package Structure
----------------------------
@@ -956,12 +960,14 @@ To this:
.. code-block:: python
:linenos:
- config.add_view('myproject.views.blogs.my_view',
+ config.add_view('myproject.views.blog.my_view',
renderer='myproject:templates/mytemplate.pt')
You can then continue to add files to the ``views`` directory, and refer to
views or handler classes/functions within those files via the dotted name
-passed as the first argument to ``add_view``. For example:
+passed as the first argument to ``add_view``. For example, if you added a
+file named ``anothermodule.py`` to the ``views`` subdirectory, and added a
+view callable named ``my_view`` to it:
.. code-block:: python
:linenos:
diff --git a/docs/narr/renderers.rst b/docs/narr/renderers.rst
index 3804fcf42..76e9562fa 100644
--- a/docs/narr/renderers.rst
+++ b/docs/narr/renderers.rst
@@ -22,6 +22,7 @@ response. For example:
from pyramid.response import Response
from pyramid.view import view_config
+ @view_config(renderer='json')
def hello_world(request):
return {'content':'Hello!'}
diff --git a/docs/narr/resources.rst b/docs/narr/resources.rst
index ac88afdfd..8cf2cead2 100644
--- a/docs/narr/resources.rst
+++ b/docs/narr/resources.rst
@@ -404,7 +404,7 @@ Obtaining the Lineage of a Resource
-----------------------------------
:func:`pyramid.location.lineage` returns a generator representing the
-:term:`lineage` of the :term:`location` aware:term:`resource` object.
+:term:`lineage` of the :term:`location` aware :term:`resource` object.
The :func:`~pyramid.location.lineage` function returns the resource it is
passed, then each parent of the resource, in order. For example, if the
@@ -533,7 +533,7 @@ declares that the blog entry implements an :term:`interface`.
implements(IBlogEntry)
def __init__(self, title, body, author):
self.title = title
- self.body = body
+ self.body = body
self.author = author
self.created = datetime.datetime.now()
@@ -568,7 +568,7 @@ To do so, use the :func:`zope.interface.directlyProvides` function:
class BlogEntry(object):
def __init__(self, title, body, author):
self.title = title
- self.body = body
+ self.body = body
self.author = author
self.created = datetime.datetime.now()
@@ -596,7 +596,7 @@ the :func:`zope.interface.alsoProvides` function:
class BlogEntry(object):
def __init__(self, title, body, author):
self.title = title
- self.body = body
+ self.body = body
self.author = author
self.created = datetime.datetime.now()
diff --git a/docs/narr/static.rst b/docs/narr/static.rst
deleted file mode 100644
index d4f6da76d..000000000
--- a/docs/narr/static.rst
+++ /dev/null
@@ -1,320 +0,0 @@
-Static Assets
-=============
-
-:app:`Pyramid` makes it possible to serve up static asset files from a
-directory on a filesystem. This chapter describes how to configure
-:app:`Pyramid` to do so.
-
-.. index::
- single: add_static_view
-
-.. _static_assets_section:
-
-Serving Static Assets
----------------------
-
-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.
-
-.. note:: `~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
-from the ``/var/www/static`` directory of the computer which runs the
-:app:`Pyramid` application as URLs beneath the ``/static`` URL prefix.
-
-.. code-block:: python
- :linenos:
-
- # 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
-``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``.
-
-A static directory named at ``path`` may contain subdirectories recursively,
-and any subdirectories may hold files; these will be resolved by the static
-view as you would expect. The ``Content-Type`` header returned by the static
-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 resources 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
-:meth:`pyramid.config.Configurator.add_static_view` to serve files up under
-the ``/static`` URL from the ``a/b/c/static`` directory of the Python package
-named ``some_package``, we can use a fully qualified :term:`asset
-specification` as the ``path``:
-
-.. code-block:: python
- :linenos:
-
- # config is an instance of pyramid.config.Configurator
- config.add_static_view(name='static', path='some_package:a/b/c/static')
-
-The ``path`` provided to :meth:`pyramid.config.Configurator.add_static_view`
-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 :func:`pyramid.url.static_url`.
-
-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:
-
- # config is an instance of pyramid.config.Configurator
- 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 :func:`pyramid.url.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.
-
-.. note::
-
- The :ref:`static_directive` ZCML directive offers an declarative
- equivalent to :meth:`pyramid.config.Configurator.add_static_view`. Use of
- the :ref:`static_directive` ZCML directive is completely equivalent to
- using imperative configuration for the same purpose.
-
-.. index::
- single: generating static asset urls
- single: static asset urls
-
-.. _generating_static_asset_urls:
-
-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.
-
-For example, let's assume you create a set of static declarations like so:
-
-.. code-block:: python
- :linenos:
-
- 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
-``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``.
-
-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:
-
-.. 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)
- return render_template_to_response('templates/my_template.pt',
- css_url = css_url,
- js_url = js_url)
-
-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``.
-
-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.
-
-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``:
-
-.. code-block:: python
- :linenos:
-
- 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
-``http://example.com/images``:
-
-.. code-block:: python
- :linenos:
-
- static_url('mypackage:images/logo.png', request)
- # -> http://example.com/images/logo.png
-
-Using :func:`pyramid.url.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
-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.
-
-.. index::
- single: static assets view
-
-.. _advanced_static:
-
-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
-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.
-
-Root-Relative Custom Static View (URL Dispatch Only)
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-The :class:`pyramid.view.static` 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
-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`
- 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.
-
-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.
-
-.. ignore-next-block
-.. code-block:: python
- :linenos:
-
- from pyramid.view import static
- static_view = static('/path/to/static/dir')
-
-.. 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``.
-
-Subsequently, you may wire the files that are served by this view up to be
-accessible as ``/<filename>`` using a configuration method in your
-application's startup code.
-
-.. code-block:: python
- :linenos:
-
- # .. every other add_route and/or add_handler declaration should come
- # before this one, as it will, by default, catch all requests
-
- config.add_route('catchall_static', '/*subpath', 'myapp.static.static_view')
-
-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.
-
-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.
-
-.. code-block:: python
- :linenos:
-
- import os
- from pyramid.view import view_config
- from webob import Response
-
- def favicon_view(request):
- here = os.path.dirname(__file__)
- icon = open(os.path.join(here, 'static', 'favicon.ico'))
- return Response(content_type='image/x-icon', app_iter=icon)
-
-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.
-
-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:
-
- config.add_view('myapp.views.favicon_view', name='favicon.ico')
-
-Or you might register it to be the view callable for a particular route:
-
-.. code-block:: python
- :linenos:
-
- config.add_route('favicon', '/favicon.ico',
- view='myapp.views.favicon_view')
-
-Because this is a simple view callable, it can be protected with a
-:term:`permission` or can be configured to respond under different
-circumstances using :term:`view predicate` arguments.
diff --git a/docs/narr/templates.rst b/docs/narr/templates.rst
index 437b823e9..7ef8e1923 100644
--- a/docs/narr/templates.rst
+++ b/docs/narr/templates.rst
@@ -628,7 +628,7 @@ application's configuration section, e.g.:
.. code-block:: ini
:linenos:
- [app:main]
+ [app:MyProject]
use = egg:MyProject#app
debug_templates = true
diff --git a/docs/narr/urldispatch.rst b/docs/narr/urldispatch.rst
index 76eca454d..0d28a0e96 100644
--- a/docs/narr/urldispatch.rst
+++ b/docs/narr/urldispatch.rst
@@ -533,12 +533,12 @@ neither predicates nor view configuration information.
callables. Use custom predicates when no set of predefined predicates does
what you need. Custom predicates can be combined with predefined
predicates as necessary. Each custom predicate callable should accept two
- arguments: ``context`` and ``request`` and should return either ``True`` or
+ arguments: ``info`` and ``request`` and should return either ``True`` or
``False`` after doing arbitrary evaluation of the context resource and/or
the request. If all callables return ``True``, the associated route will
be considered viable for a given request. If any custom predicate returns
- ``False``, route matching continues. Note that the value ``context`` will
- always be ``None`` when passed to a custom route predicate.
+ ``False``, route matching continues. See :ref:`custom_route_predicates`
+ for more information.
**View-Related Arguments**
@@ -1231,6 +1231,44 @@ which you started the application from. For example:
See :ref:`environment_chapter` for more information about how, and where to
set these values.
+.. index::
+ pair: routes; printing
+ single: paster proutes
+
+Displaying All Application Routes
+---------------------------------
+
+You can use the ``paster proutes`` command in a terminal window to print a
+summary of routes related to your application. Much like the ``paster
+pshell`` command (see :ref:`interactive shell`), the ``paster proutes``
+command accepts two arguments. The first argument to ``proutes`` is the path
+to your application's ``.ini`` file. The second is the ``app`` section name
+inside the ``.ini`` file which points to your application.
+
+For example:
+
+.. code-block:: text
+ :linenos:
+
+ [chrism@thinko MyProject]$ ../bin/paster proutes development.ini MyProject
+ Name Pattern View
+ ---- ------- ----
+ home / <function my_view>
+ home2 / <function my_view>
+ another /another None
+ static/ static/*subpath <static_view object>
+ catchall /*subpath <function static_view>
+
+``paster proutes`` generates a table. The table has three columns: a Name
+name column, a Pattern column, and a View column. The items listed in the
+Name column are route names, the items listen in the Pattern column are route
+patterns, and the items listed in the View column are representations of the
+view callable that will be invoked when a request matches the associated
+route pattern. The view column may show ``None`` if no associated view
+callable could be found. If no routes are configured within your
+application, nothing will be printed to the console when ``paster proutes``
+is executed.
+
References
----------
diff --git a/docs/tutorials/cmf/actions.rst b/docs/tutorials/cmf/actions.rst
deleted file mode 100644
index a6e33fa59..000000000
--- a/docs/tutorials/cmf/actions.rst
+++ /dev/null
@@ -1,28 +0,0 @@
-.. _actions_chapter:
-
-=======
-Actions
-=======
-
-In CMF, the "actions tool" along with "action providers" create an extensible
-mechanism to show links in the CMF management UI that invoke a particular
-behavior or which show a particular template.
-
-:app:`Pyramid` itself has no such concept, and no package provides a direct
-replacement. Actions are such a generic concept that it's simple to
-reimplement action-like navigation in a different way within any given
-application. For example, a module-scope global dictionary which has keys
-that are action names, and values which are tuples of (permission, link).
-Take that concept and expand on it, and you'll have some passable actions
-tool replacement within a single application.
-
-The `pyramid_viewgroup <https://github.com/Pylons/pyramid_viewgroup/>`_
-package provides some functionality for creating "view groups". Each view in
-a viewgroup can provide some snippet of HTML (e.g. a single "tab"), and
-individual views (tabs) within the group which cannot be displayed to the
-user due to the user's lack of permissions will be omitted from the rendered
-output.
-
-The :term:`repoze.lemonade` package provides "list item" support that
-may be used to construct action lists.
-
diff --git a/docs/tutorials/cmf/catalog.rst b/docs/tutorials/cmf/catalog.rst
deleted file mode 100644
index d5e9534ae..000000000
--- a/docs/tutorials/cmf/catalog.rst
+++ /dev/null
@@ -1,73 +0,0 @@
-.. _catalog_chapter:
-
-=======
-Catalog
-=======
-
-The main feature of the CMF catalog is that it filters search results
-from the Zope 2 "catalog" based on the requesting user's ability to
-view a particular cataloged object.
-
-:app:`Pyramid` itself has no cataloging facility, but an addon
-package named :term:`repoze.catalog` offers similar functionality.
-
-Creating an Allowed Index
--------------------------
-
-In CMF, a catalog index named ``getAllowedRolesAndUsers`` along with
-application indexing code allows for filtered search results. It's
-reasonably easy to reproduce this pattern using some custom code.
-
-Creating The ``allowed`` Index
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-Here's some code which creates an ``allowed`` index for use in a
-``repoze.catalog`` catalog::
-
- from pyramid.security import principals_allowed_by_permission
- from repoze.catalog.indexes.keyword import CatalogKeywordIndex
- from repoze.catalog.catalog import Catalog
-
- class Allowed:
- def __init__(self, permission):
- self.permission = permission
-
- def __call__(self, context, default):
- principals = principals_allowed_by_permission(context,
- self.permission)
- return principals
-
- def make_allowed_index(permission='View'):
- index = CatalogKeywordIndex(Allowed(permission))
- return index
-
- index = make_allowed_index()
- catalog = Catalog()
- catalog['allowed'] = index
-
-When you index an item, the allowed index will be populated with all
-the principal ids which have the 'View' permission.
-
-Using the ``allowed`` Index
-~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-Here's how you might use the ``allowed`` index within a query::
-
- from pyramid.security import effective_principals
- principals = effective_principals(request)
- catalog.searchResults(allowed={'operator':'or', 'query':principals})
-
-The above query will return all document ids that the current user has
-the 'View' permission against. Add other indexes to the query to get
-a useful result.
-
-See the `repoze.catalog package
-<http://svn.repoze.org/repoze.catalog/trunk>`_ for more information.
-
-
-
-
-
-
-
-
diff --git a/docs/tutorials/cmf/content.rst b/docs/tutorials/cmf/content.rst
deleted file mode 100644
index 85e5b5fbc..000000000
--- a/docs/tutorials/cmf/content.rst
+++ /dev/null
@@ -1,67 +0,0 @@
-.. _content_types_chapter:
-
-=============
-Content Types
-=============
-
-In CMF, a content type is defined as a bag of settings (the type
-information, controlled within the "types tool"), as well as factory
-code which generates an instance of that content. It is possible to
-construct and enumerate content types using APIs defined on the types
-tool.
-
-:app:`Pyramid` itself has no such concept, but an addon package named
-:term:`repoze.lemonade` has a barebones replacement.
-
-Factory Type Information
-------------------------
-
-A factory type information object in CMF allows you to associate a
-title, a description, an internationalization domain, an icon, an
-initial view name, a factory, and a number of security settings with a
-type name. Each type information object knows how to manufacture
-content objects that match its type.
-
-:app:`Pyramid` certainly enforces none of these concepts in any
-particular way, but :term:`repoze.lemonade` does.
-
-``repoze.lemonade`` Content
-+++++++++++++++++++++++++++
-
-:term:`repoze.lemonade` provides a reasonably handy directive and set
-of helper functions which allow you to:
-
-#. Associate a interface with a factory function, making it into a
- "content type".
-
-#. Enumerate all interfaces associated with factory functions.
-
-.. note:: Using this pattern is often plain silly, as it's usually
- just as easy to actually import a class implementation and
- create an instance directly using its constructor. But it
- can be useful in cases where you want to address some set of
- constructors uniformly without doing direct imports in the
- code which performs the construction, or if you need to make
- content construction uniform across a diverse set of model
- types, or if you need to enumerate some set of information
- about "content" types. It's left as an exercise to the
- reader to determine under which circumstances using this
- pattern is an appropriate thing to do. Hint: not very
- often, unless you're doing the indirection solely to aid
- content-agnostic unit tests or if you need to get an
- enumerated subset of content type information to aid in UI
- generation. That said, this *is* a tutorial about how to
- get CMF-like features in :app:`Pyramid`, so we'll assume
- the pattern is useful to readers.
-
-See the `repoze.lemonade package
-<http://svn.repoze.org/repoze.lemonade/trunk>`_ for more information,
-particularly its documentation for "content".
-
-
-
-
-
-
-
-
diff --git a/docs/tutorials/cmf/index.rst b/docs/tutorials/cmf/index.rst
deleted file mode 100644
index 26aa336a9..000000000
--- a/docs/tutorials/cmf/index.rst
+++ /dev/null
@@ -1,38 +0,0 @@
-Converting an Existing Zope/CMF Application to :app:`Pyramid`
-================================================================
-
-The Zope `Content Management Framework
-<http://www.zope.org/Products/CMF/>`_ (aka CMF) is a layer on top of
-:term:`Zope` 2 that provides facilities for creating content-driven
-websites. It's reasonably easy to convert a modern Zope/CMF
-application to :app:`Pyramid`.
-
-The main difference between CMF and :app:`Pyramid` is that :app:`Pyramid`
-does not advertise itself as a system into which you can plug arbitrary
-"packages" that extend a system-supplied management user interface. You
-*could* build a CMF-like layer on top of :app:`Pyramid` but none currently
-exists. For those sorts of high-extensibility, highly-regularized-UI
-systems, CMF is still the better choice.
-
-:app:`Pyramid` (and other more lightweight systems) is often a
-better choice when you're building the a user interface from scratch,
-which often happens when the paradigms of some CMF-provided user
-interface don't match the requirements of an application very closely.
-Even so, a good number of developers tend to use CMF even when they do
-start an application for which they need to build a UI from scratch,
-because CMF happens to provide other helpful services, such as types,
-skins, and workflow; this tutorial is for those sorts of developers
-and projects.
-
-.. toctree::
- :maxdepth: 2
-
- content.rst
- catalog.rst
- skins.rst
- actions.rst
- workflow.rst
- missing.rst
-
-
-
diff --git a/docs/tutorials/cmf/missing.rst b/docs/tutorials/cmf/missing.rst
deleted file mode 100644
index 964e0ab04..000000000
--- a/docs/tutorials/cmf/missing.rst
+++ /dev/null
@@ -1,22 +0,0 @@
-Missing Comparisons
-===================
-
-We currently don't have any comparative Pyramid-vs-CMF information
-about the following concepts within this tutorial:
-
-- Templates
-
-- Forms
-
-- Membership
-
-- Discussions
-
-- Syndication
-
-- Dublincore
-
-Please ask on the `Pylons-devel maillist
-<http://groups.google.com/group/pylons-devel>`_ or on the `#pylons IRC
-channel <http://irc.freenode.net#pylons>`_ about these topics.
-
diff --git a/docs/tutorials/cmf/skins.rst b/docs/tutorials/cmf/skins.rst
deleted file mode 100644
index 676a076b3..000000000
--- a/docs/tutorials/cmf/skins.rst
+++ /dev/null
@@ -1,23 +0,0 @@
-.. _skins_chapter:
-
-=====
-Skins
-=====
-
-In CMF, a "skin layer" is defined as a collection of templates and
-code (Python scripts, DTML methods, etc) that can be activated and
-deactivated within a particular setup. A collection of active "skin
-layers" grouped in a particular order forms a "skin". "Add-on" CMF
-products often provide skin layers that are activated within a
-particular skin to provide the site with additional features.
-
-To override static resources using a "search path" much like a set of
-skin layers, :app:`Pyramid` provides the concept of
-:term:`resource` overrides. See :ref:`overriding_resources_section`
-for more information about resource overrides.
-
-While there is no analogue to a skin layer search path for locating
-Python code (as opposed to resources), :term:`view` code combined with
-differing :term:`predicate` arguments can provide a good deal of
-the same sort of behavior.
-
diff --git a/docs/tutorials/cmf/workflow.rst b/docs/tutorials/cmf/workflow.rst
deleted file mode 100644
index cc70d771a..000000000
--- a/docs/tutorials/cmf/workflow.rst
+++ /dev/null
@@ -1,14 +0,0 @@
-.. _workflow_chapter:
-
-========
-Workflow
-========
-
-In CMF, the "workflow tool" allows developers to design state machines
-which imply transition between content states.
-
-:app:`Pyramid` itself has no such concept, but the
-:term:`repoze.workflow` package provides a simple state machine
-implementation that can act as a barebones workflow tool. See its
-documentation for more information.
-