summaryrefslogtreecommitdiff
path: root/docs
diff options
context:
space:
mode:
Diffstat (limited to 'docs')
-rw-r--r--docs/api/static.rst8
-rw-r--r--docs/glossary.rst4
-rw-r--r--docs/index.rst153
-rw-r--r--docs/narr/advconfig.rst133
-rw-r--r--docs/narr/assets.rst257
-rw-r--r--docs/narr/commandline.rst2
-rw-r--r--docs/narr/extconfig.rst265
-rw-r--r--docs/narr/extending.rst194
-rw-r--r--docs/narr/hooks.rst644
-rw-r--r--docs/narr/hybrid.rst539
-rw-r--r--docs/narr/introspector.rst123
-rw-r--r--docs/narr/scaffolding.rst100
-rw-r--r--docs/narr/security.rst438
-rw-r--r--docs/narr/subrequest.rst156
-rw-r--r--docs/narr/tb_introspector.pngbin95962 -> 181225 bytes
-rw-r--r--docs/tutorials/wiki2/basiclayout.rst2
16 files changed, 1417 insertions, 1601 deletions
diff --git a/docs/api/static.rst b/docs/api/static.rst
index b6b279139..f3727e197 100644
--- a/docs/api/static.rst
+++ b/docs/api/static.rst
@@ -9,17 +9,11 @@
:members:
:inherited-members:
- .. autoclass:: PathSegmentCacheBuster
+ .. autoclass:: ManifestCacheBuster
:members:
.. autoclass:: QueryStringCacheBuster
:members:
- .. autoclass:: PathSegmentMd5CacheBuster
- :members:
-
- .. autoclass:: QueryStringMd5CacheBuster
- :members:
-
.. autoclass:: QueryStringConstantCacheBuster
:members:
diff --git a/docs/glossary.rst b/docs/glossary.rst
index 9c0ea8598..b4bb36421 100644
--- a/docs/glossary.rst
+++ b/docs/glossary.rst
@@ -1089,3 +1089,7 @@ Glossary
data in a Redis database. See
https://pypi.python.org/pypi/pyramid_redis_sessions for more information.
+ cache busting
+ A technique used when serving a cacheable static asset in order to force
+ a client to query the new version of the asset. See :ref:`cache_busting`
+ for more information.
diff --git a/docs/index.rst b/docs/index.rst
index 0ee3557bf..e792b9905 100644
--- a/docs/index.rst
+++ b/docs/index.rst
@@ -4,10 +4,9 @@
The Pyramid Web Framework
=========================
-:app:`Pyramid` is a small, fast, down-to-earth Python web framework. It
-is developed as part of the `Pylons Project
-<http://docs.pylonsproject.org/>`_. It is licensed under a `BSD-like license
-<http://repoze.org/license.html>`_.
+:app:`Pyramid` is a small, fast, down-to-earth Python web framework. It is
+developed as part of the `Pylons Project <http://docs.pylonsproject.org/>`_.
+It is licensed under a `BSD-like license <http://repoze.org/license.html>`_.
Here is one of the simplest :app:`Pyramid` applications you can make:
@@ -15,30 +14,17 @@ Here is one of the simplest :app:`Pyramid` applications you can make:
After you install :app:`Pyramid` and run this application, when you visit
`<http://localhost:8080/hello/world>`_ in a browser, you will see the text
-``Hello, world!``
+``Hello, world!`` See :ref:`firstapp_chapter` for a full explanation of how
+this application works.
-See :ref:`firstapp_chapter` for a full explanation of how this application
-works. Read the :ref:`html_narrative_documentation` to understand how
-:app:`Pyramid` is designed to scale from simple applications like this to
-very large web applications. To just dive in headfirst, read the
-:doc:`quick_tour`.
-
-Front Matter
-============
-
-.. toctree::
- :maxdepth: 1
-
- copyright.rst
- conventions.rst
.. _html_getting_started:
Getting Started
===============
-If you are new to Pyramid, we have a few resources that can help you get
-up to speed right away.
+If you are new to Pyramid, we have a few resources that can help you get up to
+speed right away.
.. toctree::
:hidden:
@@ -46,26 +32,69 @@ up to speed right away.
quick_tour
quick_tutorial/index
-* :doc:`quick_tour` goes through the major features in Pyramid, covering
- a little about a lot.
+* :doc:`quick_tour` gives an overview of the major features in Pyramid,
+ covering a little about a lot.
-* :doc:`quick_tutorial/index` does the same, but in a tutorial format:
- deeper treatment of each topic and with working code.
+* :doc:`quick_tutorial/index` is similar to the Quick Tour, but in a tutorial
+ format, with somewhat deeper treatment of each topic and with working code.
-* To see a minimal Pyramid web application, check out
- :ref:`firstapp_chapter`.
+* Like learning by example? Visit the official :ref:`html_tutorials` as well as
+ the community-contributed :ref:`Pyramid tutorials
+ <tutorials:pyramid-tutorials>`, which include a :ref:`Todo List Application
+ in One File <tutorials:single-file-tutorial>`.
-* For help getting Pyramid set up, try
- :ref:`installing_chapter`.
+* For help getting Pyramid set up, try :ref:`installing_chapter`.
-* Like learning by example? Visit the official
- :doc:`wiki tutorial <../tutorials/wiki2/index>` as well as the
- community-contributed
- :ref:`Pyramid tutorials <tutorials:pyramid-tutorials>`, which include
- a :ref:`single file tasks tutorial <tutorials:single-file-tutorial>`.
+* Need help? See :ref:`Support and Development <support-and-development>`.
-* Need help? See :ref:`Support and
- Development <support-and-development>`.
+
+.. _html_tutorials:
+
+Tutorials
+=========
+
+Official tutorials explaining how to use :app:`Pyramid` to build various types
+of applications, and how to deploy :app:`Pyramid` applications to various
+platforms.
+
+.. toctree::
+ :maxdepth: 1
+
+ tutorials/wiki2/index.rst
+ tutorials/wiki/index.rst
+ tutorials/modwsgi/index.rst
+
+
+.. _support-and-development:
+
+Support and Development
+=======================
+
+The `Pylons Project web site <http://pylonsproject.org/>`_ is the main online
+source of :app:`Pyramid` support and development information.
+
+To report bugs, use the `issue tracker
+<https://github.com/Pylons/pyramid/issues>`_.
+
+If you've got questions that aren't answered by this documentation, contact the
+`Pylons-discuss maillist <http://groups.google.com/group/pylons-discuss>`_ or
+join the `#pyramid IRC channel <irc://irc.freenode.net/#pyramid>`_.
+
+Browse and check out tagged and trunk versions of :app:`Pyramid` via the
+`Pyramid GitHub repository <https://github.com/Pylons/pyramid/>`_. To check out
+the trunk via ``git``, use either command:
+
+.. code-block:: text
+
+ # If you have SSH keys configured on GitHub:
+ git clone git@github.com:Pylons/pyramid.git
+
+ # Otherwise, HTTPS will work, using your GitHub login:
+ git clone https://github.com/Pylons/pyramid.git
+
+To find out how to become a contributor to :app:`Pyramid`, please see the
+`contributor's section of the documentation
+<http://docs.pylonsproject.org/en/latest/#contributing>`_.
.. _html_narrative_documentation:
@@ -73,8 +102,7 @@ up to speed right away.
Narrative Documentation
=======================
-Narrative documentation in chapter form explaining how to use
-:app:`Pyramid`.
+Narrative documentation in chapter form explaining how to use :app:`Pyramid`.
.. toctree::
:maxdepth: 2
@@ -119,26 +147,12 @@ Narrative documentation in chapter form explaining how to use
narr/threadlocals
narr/zca
-.. _html_tutorials:
-
-Tutorials
-=========
-
-Tutorials explaining how to use :app:`Pyramid` to build various types of
-applications, and how to deploy :app:`Pyramid` applications to various
-platforms.
-
-.. toctree::
- :maxdepth: 2
-
- tutorials/wiki2/index.rst
- tutorials/wiki/index.rst
- tutorials/modwsgi/index.rst
API Documentation
=================
-Comprehensive reference material for every public API exposed by :app:`Pyramid`:
+Comprehensive reference material for every public API exposed by
+:app:`Pyramid`:
.. toctree::
:maxdepth: 1
@@ -147,6 +161,7 @@ Comprehensive reference material for every public API exposed by :app:`Pyramid`:
api/index
api/*
+
Change History
==============
@@ -162,6 +177,7 @@ Change History
whatsnew-1.0
changes
+
Design Documents
================
@@ -170,33 +186,24 @@ Design Documents
designdefense
-.. _support-and-development:
-Support and Development
-=======================
+Copyright, Trademarks, and Attributions
+=======================================
-The `Pylons Project web site <http://pylonsproject.org/>`_ is the main online
-source of :app:`Pyramid` support and development information.
+.. toctree::
+ :maxdepth: 1
-To report bugs, use the `issue tracker
-<https://github.com/Pylons/pyramid/issues>`_.
+ copyright
-If you've got questions that aren't answered by this documentation,
-contact the `Pylons-discuss maillist
-<http://groups.google.com/group/pylons-discuss>`_ or join the `#pyramid
-IRC channel <irc://irc.freenode.net/#pyramid>`_.
-Browse and check out tagged and trunk versions of :app:`Pyramid` via
-the `Pyramid GitHub repository <https://github.com/Pylons/pyramid/>`_.
-To check out the trunk via ``git``, use this command:
+Typographical Conventions
+=========================
-.. code-block:: text
+.. toctree::
+ :maxdepth: 1
- git clone git@github.com:Pylons/pyramid.git
+ conventions
-To find out how to become a contributor to :app:`Pyramid`, please see the
-`contributor's section of the documentation
-<http://docs.pylonsproject.org/en/latest/#contributing>`_.
Index and Glossary
==================
diff --git a/docs/narr/advconfig.rst b/docs/narr/advconfig.rst
index 9ceaaa495..ba9bd1352 100644
--- a/docs/narr/advconfig.rst
+++ b/docs/narr/advconfig.rst
@@ -6,12 +6,11 @@
Advanced Configuration
======================
-To support application extensibility, the :app:`Pyramid`
-:term:`Configurator`, by default, detects configuration conflicts and allows
-you to include configuration imperatively from other packages or modules. It
-also, by default, performs configuration in two separate phases. This allows
-you to ignore relative configuration statement ordering in some
-circumstances.
+To support application extensibility, the :app:`Pyramid` :term:`Configurator`
+by default detects configuration conflicts and allows you to include
+configuration imperatively from other packages or modules. It also by default
+performs configuration in two separate phases. This allows you to ignore
+relative configuration statement ordering in some circumstances.
.. index::
pair: configuration; conflict detection
@@ -70,11 +69,11 @@ try to add another view to the configuration with the same set of
server = make_server('0.0.0.0', 8080, app)
server.serve_forever()
-The application now has two conflicting view configuration statements. When
-we try to start it again, it won't start. Instead, we'll receive a traceback
-that ends something like this:
+The application now has two conflicting view configuration statements. When we
+try to start it again, it won't start. Instead we'll receive a traceback that
+ends something like this:
-.. code-block:: guess
+.. code-block:: text
:linenos:
Traceback (most recent call last):
@@ -94,19 +93,19 @@ that ends something like this:
This traceback is trying to tell us:
-- We've got conflicting information for a set of view configuration
- statements (The ``For:`` line).
+- We've got conflicting information for a set of view configuration statements
+ (The ``For:`` line).
- There are two statements which conflict, shown beneath the ``For:`` line:
``config.add_view(hello_world. 'hello')`` on line 14 of ``app.py``, and
``config.add_view(goodbye_world, 'hello')`` on line 17 of ``app.py``.
-These two configuration statements are in conflict because we've tried to
-tell the system that the set of :term:`predicate` values for both view
+These two configuration statements are in conflict because we've tried to tell
+the system that the set of :term:`predicate` values for both view
configurations are exactly the same. Both the ``hello_world`` and
``goodbye_world`` views are configured to respond under the same set of
-circumstances. This circumstance: the :term:`view name` (represented by the
-``name=`` predicate) is ``hello``.
+circumstances. This circumstance, the :term:`view name` represented by the
+``name=`` predicate, is ``hello``.
This presents an ambiguity that :app:`Pyramid` cannot resolve. Rather than
allowing the circumstance to go unreported, by default Pyramid raises a
@@ -138,8 +137,7 @@ made by your application. Use the detail provided in the
modify your configuration code accordingly.
If you're getting a conflict while trying to extend an existing application,
-and that application has a function which performs configuration like this
-one:
+and that application has a function which performs configuration like this one:
.. code-block:: python
:linenos:
@@ -147,8 +145,8 @@ one:
def add_routes(config):
config.add_route(...)
-Don't call this function directly with ``config`` as an argument. Instead,
-use :meth:`pyramid.config.Configurator.include`:
+Don't call this function directly with ``config`` as an argument. Instead, use
+:meth:`pyramid.config.Configurator.include`:
.. code-block:: python
:linenos:
@@ -156,9 +154,9 @@ use :meth:`pyramid.config.Configurator.include`:
config.include(add_routes)
Using :meth:`~pyramid.config.Configurator.include` instead of calling the
-function directly provides a modicum of automated conflict resolution, with
-the configuration statements you define in the calling code overriding those
-of the included function.
+function directly provides a modicum of automated conflict resolution, with the
+configuration statements you define in the calling code overriding those of the
+included function.
.. seealso::
@@ -169,10 +167,10 @@ Using ``config.commit()``
+++++++++++++++++++++++++
You can manually commit a configuration by using the
-:meth:`~pyramid.config.Configurator.commit` method between configuration
-calls. For example, we prevent conflicts from occurring in the application
-we examined previously as the result of adding a ``commit``. Here's the
-application that generates conflicts:
+:meth:`~pyramid.config.Configurator.commit` method between configuration calls.
+For example, we prevent conflicts from occurring in the application we examined
+previously as the result of adding a ``commit``. Here's the application that
+generates conflicts:
.. code-block:: python
:linenos:
@@ -199,11 +197,12 @@ application that generates conflicts:
server = make_server('0.0.0.0', 8080, app)
server.serve_forever()
-We can prevent the two ``add_view`` calls from conflicting by issuing a call
-to :meth:`~pyramid.config.Configurator.commit` between them:
+We can prevent the two ``add_view`` calls from conflicting by issuing a call to
+:meth:`~pyramid.config.Configurator.commit` between them:
.. code-block:: python
:linenos:
+ :emphasize-lines: 16
from wsgiref.simple_server import make_server
from pyramid.config import Configurator
@@ -230,21 +229,20 @@ to :meth:`~pyramid.config.Configurator.commit` between them:
server.serve_forever()
In the above example we've issued a call to
-:meth:`~pyramid.config.Configurator.commit` between the two ``add_view``
-calls. :meth:`~pyramid.config.Configurator.commit` will execute any pending
+:meth:`~pyramid.config.Configurator.commit` between the two ``add_view`` calls.
+:meth:`~pyramid.config.Configurator.commit` will execute any pending
configuration statements.
Calling :meth:`~pyramid.config.Configurator.commit` is safe at any time. It
-executes all pending configuration actions and leaves the configuration
-action list "clean".
+executes all pending configuration actions and leaves the configuration action
+list "clean".
-Note that :meth:`~pyramid.config.Configurator.commit` has no effect when
-you're using an *autocommitting* configurator (see
-:ref:`autocommitting_configurator`).
+Note that :meth:`~pyramid.config.Configurator.commit` has no effect when you're
+using an *autocommitting* configurator (see :ref:`autocommitting_configurator`).
.. _autocommitting_configurator:
-Using An Autocommitting Configurator
+Using an Autocommitting Configurator
++++++++++++++++++++++++++++++++++++
You can also use a heavy hammer to circumvent conflict detection by using a
@@ -278,17 +276,17 @@ Automatic Conflict Resolution
If your code uses the :meth:`~pyramid.config.Configurator.include` method to
include external configuration, some conflicts are automatically resolved.
Configuration statements that are made as the result of an "include" will be
-overridden by configuration statements that happen within the caller of
-the "include" method.
+overridden by configuration statements that happen within the caller of the
+"include" method.
-Automatic conflict resolution supports this goal: if a user wants to reuse a
+Automatic conflict resolution supports this goal. If a user wants to reuse a
Pyramid application, and they want to customize the configuration of this
application without hacking its code "from outside", they can "include" a
configuration function from the package and override only some of its
configuration statements within the code that does the include. No conflicts
will be generated by configuration statements within the code that does the
-including, even if configuration statements in the included code would
-conflict if it was moved "up" to the calling code.
+including, even if configuration statements in the included code would conflict
+if it was moved "up" to the calling code.
Methods Which Provide Conflict Detection
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -312,9 +310,9 @@ These are the methods of the configurator which provide conflict detection:
:meth:`~pyramid.config.Configurator.add_resource_url_adapter`,
and :meth:`~pyramid.config.Configurator.add_response_adapter`.
-:meth:`~pyramid.config.Configurator.add_static_view` also indirectly
-provides conflict detection, because it's implemented in terms of the
-conflict-aware ``add_route`` and ``add_view`` methods.
+:meth:`~pyramid.config.Configurator.add_static_view` also indirectly provides
+conflict detection, because it's implemented in terms of the conflict-aware
+``add_route`` and ``add_view`` methods.
.. index::
pair: configuration; including from external sources
@@ -324,10 +322,10 @@ conflict-aware ``add_route`` and ``add_view`` methods.
Including Configuration from External Sources
---------------------------------------------
-Some application programmers will factor their configuration code in such a
-way that it is easy to reuse and override configuration statements. For
-example, such a developer might factor out a function used to add routes to
-his application:
+Some application programmers will factor their configuration code in such a way
+that it is easy to reuse and override configuration statements. For example,
+such a developer might factor out a function used to add routes to their
+application:
.. code-block:: python
:linenos:
@@ -335,8 +333,8 @@ his application:
def add_routes(config):
config.add_route(...)
-Rather than calling this function directly with ``config`` as an argument.
-Instead, use :meth:`pyramid.config.Configurator.include`:
+Rather than calling this function directly with ``config`` as an argument,
+instead use :meth:`pyramid.config.Configurator.include`:
.. code-block:: python
:linenos:
@@ -363,21 +361,21 @@ the special name ``includeme``, which should perform configuration (like the
:meth:`~pyramid.config.Configurator.include` can also accept a :term:`dotted
Python name` to a function or a module.
-.. note: See :ref:`the_include_tag` for a declarative alternative to
- the :meth:`~pyramid.config.Configurator.include` method.
+.. note:: See :ref:`the_include_tag` for a declarative alternative to the
+ :meth:`~pyramid.config.Configurator.include` method.
.. _twophase_config:
Two-Phase Configuration
-----------------------
-When a non-autocommitting :term:`Configurator` is used to do configuration
-(the default), configuration execution happens in two phases. In the first
-phase, "eager" configuration actions (actions that must happen before all
-others, such as registering a renderer) are executed, and *discriminators*
-are computed for each of the actions that depend on the result of the eager
-actions. In the second phase, the discriminators of all actions are compared
-to do conflict detection.
+When a non-autocommitting :term:`Configurator` is used to do configuration (the
+default), configuration execution happens in two phases. In the first phase,
+"eager" configuration actions (actions that must happen before all others, such
+as registering a renderer) are executed, and *discriminators* are computed for
+each of the actions that depend on the result of the eager actions. In the
+second phase, the discriminators of all actions are compared to do conflict
+detection.
Due to this, for configuration methods that have no internal ordering
constraints, execution order of configuration method calls is not important.
@@ -401,15 +399,14 @@ Has the same result as:
config.add_view('some.view', renderer='path_to_custom/renderer.rn')
Even though the view statement depends on the registration of a custom
-renderer, due to two-phase configuration, the order in which the
-configuration statements are issued is not important. ``add_view`` will be
-able to find the ``.rn`` renderer even if ``add_renderer`` is called after
-``add_view``.
+renderer, due to two-phase configuration, the order in which the configuration
+statements are issued is not important. ``add_view`` will be able to find the
+``.rn`` renderer even if ``add_renderer`` is called after ``add_view``.
The same is untrue when you use an *autocommitting* configurator (see
:ref:`autocommitting_configurator`). When an autocommitting configurator is
-used, two-phase configuration is disabled, and configuration statements must
-be ordered in dependency order.
+used, two-phase configuration is disabled, and configuration statements must be
+ordered in dependency order.
Some configuration methods, such as
:meth:`~pyramid.config.Configurator.add_route` have internal ordering
@@ -420,7 +417,7 @@ added in configuration execution order.
More Information
----------------
-For more information, see the article, `"A Whirlwind Tour of Advanced
+For more information, see the article `"A Whirlwind Tour of Advanced
Configuration Tactics"
-<http://docs.pylonsproject.org/projects/pyramid_cookbook/en/latest/configuration/whirlwind_tour.html>`_,
+<http://docs.pylonsproject.org/projects/pyramid_cookbook/en/latest/configuration/whirlwind_tour.html>`_
in the Pyramid Cookbook.
diff --git a/docs/narr/assets.rst b/docs/narr/assets.rst
index 020794062..d36fa49c0 100644
--- a/docs/narr/assets.rst
+++ b/docs/narr/assets.rst
@@ -356,14 +356,14 @@ may change, and then you'll want the client to load a new copy of the asset.
Under normal circumstances you'd just need to wait for the client's cached copy
to expire before they get the new version of the static resource.
-A commonly used workaround to this problem is a technique known as "cache
-busting". Cache busting schemes generally involve generating a URL for a
-static asset that changes when the static asset changes. This way headers can
-be sent along with the static asset instructing the client to cache the asset
-for a very long time. When a static asset is changed, the URL used to refer to
-it in a web page also changes, so the client sees it as a new resource and
-requests the asset, regardless of any caching policy set for the resource's old
-URL.
+A commonly used workaround to this problem is a technique known as
+:term:`cache busting`. Cache busting schemes generally involve generating a
+URL for a static asset that changes when the static asset changes. This way
+headers can be sent along with the static asset instructing the client to cache
+the asset for a very long time. When a static asset is changed, the URL used
+to refer to it in a web page also changes, so the client sees it as a new
+resource and requests the asset, regardless of any caching policy set for the
+resource's old URL.
:app:`Pyramid` can be configured to produce cache busting URLs for static
assets by passing the optional argument, ``cachebust`` to
@@ -372,30 +372,38 @@ assets by passing the optional argument, ``cachebust`` to
.. code-block:: python
:linenos:
+ import time
+ from pyramid.static import QueryStringConstantCacheBuster
+
# config is an instance of pyramid.config.Configurator
- config.add_static_view(name='static', path='mypackage:folder/static',
- cachebust=True)
+ config.add_static_view(
+ name='static', path='mypackage:folder/static',
+ cachebust=QueryStringConstantCacheBuster(str(int(time.time()))),
+ )
Setting the ``cachebust`` argument instructs :app:`Pyramid` to use a cache
-busting scheme which adds the md5 checksum for a static asset as a path segment
-in the asset's URL:
+busting scheme which adds the curent time for a static asset to the query
+string in the asset's URL:
.. code-block:: python
:linenos:
js_url = request.static_url('mypackage:folder/static/js/myapp.js')
- # Returns: 'http://www.example.com/static/c9658b3c0a314a1ca21e5988e662a09e/js/myapp.js'
+ # Returns: 'http://www.example.com/static/js/myapp.js?x=1445318121'
-When the asset changes, so will its md5 checksum, and therefore so will its
-URL. Supplying the ``cachebust`` argument also causes the static view to set
-headers instructing clients to cache the asset for ten years, unless the
-``cache_max_age`` argument is also passed, in which case that value is used.
+When the web server restarts, the time constant will change and therefore so
+will its URL. Supplying the ``cachebust`` argument also causes the static
+view to set headers instructing clients to cache the asset for ten years,
+unless the ``cache_max_age`` argument is also passed, in which case that
+value is used.
.. note::
- md5 checksums are cached in RAM, so if you change a static resource without
- restarting your application, you may still generate URLs with a stale md5
- checksum.
+ Cache busting is an inherently complex topic as it integrates the asset
+ pipeline and the web application. It is expected and desired that
+ application authors will write their own cache buster implementations
+ conforming to the properties of their own asset pipelines. See
+ :ref:`custom_cache_busters` for information on writing your own.
Disabling the Cache Buster
~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -406,65 +414,45 @@ configured cache busters without changing calls to
``PYRAMID_PREVENT_CACHEBUST`` environment variable or the
``pyramid.prevent_cachebust`` configuration value to a true value.
+.. _custom_cache_busters:
+
Customizing the Cache Buster
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-Revisiting from the previous section:
-
-.. code-block:: python
- :linenos:
-
- # config is an instance of pyramid.config.Configurator
- config.add_static_view(name='static', path='mypackage:folder/static',
- cachebust=True)
-
-Setting ``cachebust`` to ``True`` instructs :app:`Pyramid` to use a default
-cache busting implementation that should work for many situations. The
-``cachebust`` may be set to any object that implements the interface
-:class:`~pyramid.interfaces.ICacheBuster`. The above configuration is exactly
-equivalent to:
-
-.. code-block:: python
- :linenos:
+The ``cachebust`` option to
+:meth:`~pyramid.config.Configurator.add_static_view` may be set to any object
+that implements the interface :class:`~pyramid.interfaces.ICacheBuster`.
- from pyramid.static import PathSegmentMd5CacheBuster
-
- # config is an instance of pyramid.config.Configurator
- config.add_static_view(name='static', path='mypackage:folder/static',
- cachebust=PathSegmentMd5CacheBuster())
-
-:app:`Pyramid` includes a handful of ready to use cache buster implementations:
-:class:`~pyramid.static.PathSegmentMd5CacheBuster`, which inserts an md5
-checksum token in the path portion of the asset's URL,
-:class:`~pyramid.static.QueryStringMd5CacheBuster`, which adds an md5 checksum
-token to the query string of the asset's URL, and
+:app:`Pyramid` ships with a very simplistic
:class:`~pyramid.static.QueryStringConstantCacheBuster`, which adds an
-arbitrary token you provide to the query string of the asset's URL.
+arbitrary token you provide to the query string of the asset's URL. This
+is almost never what you want in production as it does not allow fine-grained
+busting of individual assets.
In order to implement your own cache buster, you can write your own class from
scratch which implements the :class:`~pyramid.interfaces.ICacheBuster`
interface. Alternatively you may choose to subclass one of the existing
implementations. One of the most likely scenarios is you'd want to change the
-way the asset token is generated. To do this just subclass either
-:class:`~pyramid.static.PathSegmentCacheBuster` or
+way the asset token is generated. To do this just subclass
:class:`~pyramid.static.QueryStringCacheBuster` and define a
-``tokenize(pathspec)`` method. Here is an example which just uses Git to get
-the hash of the currently checked out code:
+``tokenize(pathspec)`` method. Here is an example which uses Git to get
+the hash of the current commit:
.. code-block:: python
:linenos:
import os
import subprocess
- from pyramid.static import PathSegmentCacheBuster
+ from pyramid.static import QueryStringCacheBuster
- class GitCacheBuster(PathSegmentCacheBuster):
+ class GitCacheBuster(QueryStringCacheBuster):
"""
Assuming your code is installed as a Git checkout, as opposed to an egg
from an egg repository like PYPI, you can use this cachebuster to get
the current commit's SHA1 to use as the cache bust token.
"""
- def __init__(self):
+ def __init__(self, param='x'):
+ super(GitCacheBuster, self).__init__(param=param)
here = os.path.dirname(os.path.abspath(__file__))
self.sha1 = subprocess.check_output(
['git', 'rev-parse', 'HEAD'],
@@ -476,26 +464,60 @@ the hash of the currently checked out code:
Choosing a Cache Buster
~~~~~~~~~~~~~~~~~~~~~~~
-The default cache buster implementation,
-:class:`~pyramid.static.PathSegmentMd5CacheBuster`, works very well assuming
-that you're using :app:`Pyramid` to serve your static assets. The md5 checksum
-is fine grained enough that browsers should only request new versions of
-specific assets that have changed. Many caching HTTP proxies will fail to
-cache a resource if the URL contains a query string. In general, therefore,
-you should prefer a cache busting strategy which modifies the path segment to a
-strategy which adds a query string.
-
-It is possible, however, that your static assets are being served by another
-web server or externally on a CDN. In these cases modifying the path segment
-for a static asset URL would cause the external service to fail to find the
-asset, causing your customer to get a 404. In these cases you would need to
-fall back to a cache buster which adds a query string. It is even possible
-that there isn't a copy of your static assets available to the :app:`Pyramid`
-application, so a cache busting implementation that generates md5 checksums
-would fail since it can't access the assets. In such a case,
-:class:`~pyramid.static.QueryStringConstantCacheBuster` is a reasonable
-fallback. The following code would set up a cachebuster that just uses the
-time at start up as a cachebust token:
+Many caching HTTP proxies will fail to cache a resource if the URL contains
+a query string. Therefore, in general, you should prefer a cache busting
+strategy which modifies the path segment rather than methods which add a
+token to the query string.
+
+You will need to consider whether the :app:`Pyramid` application will be
+serving your static assets, whether you are using an external asset pipeline
+to handle rewriting urls internal to the css/javascript, and how fine-grained
+do you want the cache busting tokens to be.
+
+In many cases you will want to host the static assets on another web server
+or externally on a CDN. In these cases your :app:`Pyramid` application may not
+even have access to a copy of the static assets. In order to cache bust these
+assets you will need some information about them.
+
+If you are using an external asset pipeline to generate your static files you
+should consider using the :class:`~pyramid.static.ManifestCacheBuster`.
+This cache buster can load a standard JSON formatted file generated by your
+pipeline and use it to cache bust the assets. This has many performance
+advantages as :app:`Pyramid` does not need to look at the files to generate
+any cache busting tokens, but still supports fine-grained per-file tokens.
+
+Assuming an example ``manifest.json`` like:
+
+.. code-block:: json
+
+ {
+ "css/main.css": "css/main-678b7c80.css",
+ "images/background.png": "images/background-a8169106.png"
+ }
+
+The following code would set up a cachebuster:
+
+.. code-block:: python
+ :linenos:
+
+ from pyramid.path import AssetResolver
+ from pyramid.static import ManifestCacheBuster
+
+ resolver = AssetResolver()
+ manifest = resolver.resolve('myapp:static/manifest.json')
+ config.add_static_view(
+ name='http://mycdn.example.com/',
+ path='mypackage:static',
+ cachebust=ManifestCacheBuster(manifest.abspath()))
+
+A simpler approach is to use the
+:class:`~pyramid.static.QueryStringConstantCacheBuster` to generate a global
+token that will bust all of the assets at once. The advantage of this strategy
+is that it is simple and by using the query string there doesn't need to be
+any shared information between your application and the static assets.
+
+The following code would set up a cachebuster that just uses the time at
+start up as a cachebust token:
.. code-block:: python
:linenos:
@@ -506,7 +528,7 @@ time at start up as a cachebust token:
config.add_static_view(
name='http://mycdn.example.com/',
path='mypackage:static',
- cachebust=QueryStringConstantCacheBuster(str(time.time())))
+ cachebust=QueryStringConstantCacheBuster(str(int(time.time()))))
.. index::
single: static assets view
@@ -518,85 +540,24 @@ Often one needs to refer to images and other static assets inside CSS and
JavaScript files. If cache busting is active, the final static asset URL is not
available until the static assets have been assembled. These URLs cannot be
handwritten. Thus, when having static asset references in CSS and JavaScript,
-one needs to perform one of the following tasks.
+one needs to perform one of the following tasks:
* Process the files by using a precompiler which rewrites URLs to their final
- cache busted form.
+ cache busted form. Then, you can use the
+ :class:`~pyramid.static.ManifestCacheBuster` to synchronize your asset
+ pipeline with :app:`Pyramid`, allowing the pipeline to have full control
+ over the final URLs of your assets.
* Templatize JS and CSS, and call ``request.static_url()`` inside their
template code.
* Pass static URL references to CSS and JavaScript via other means.
-Below are some simple approaches for CSS and JS programming which consider
-asset cache busting. These approaches do not require additional tools or
-packages.
-
-Relative cache busted URLs in CSS
-+++++++++++++++++++++++++++++++++
-
-Consider a CSS file ``/static/theme/css/site.css`` which contains the following
-CSS code.
-
-.. code-block:: css
-
- body {
- background: url(/static/theme/img/background.jpg);
- }
-
-Any changes to ``background.jpg`` would not appear to the visitor because the
-URL path is not cache busted as it is. Instead we would have to construct an
-URL to the background image with the default ``PathSegmentCacheBuster`` cache
-busting mechanism::
-
- https://site/static/1eeb262c717/theme/img/background.jpg
-
-Every time the image is updated, the URL would need to be changed. It is not
-practical to write this non-human readable URL into a CSS file.
-
-However, the CSS file itself is cache busted and is located under the path for
-static assets. This lets us use relative references in our CSS to cache bust
-the image.
-
-.. code-block:: css
-
- body {
- background: url(../img/background.jpg);
- }
-
-The browser would interpret this as having the CSS file hash in URL::
-
- https://site/static/ab234b262c71/theme/css/../img/background.jpg
-
-The downside of this approach is that if the background image changes, one
-needs to bump the CSS file. The CSS file hash change signals the caches that
-the relative URL to the image in the CSS has been changed. When updating CSS
-and related image assets, updates usually happen hand in hand, so this does not
-add extra effort to theming workflow.
-
-Passing cache busted URLs to JavaScript
-+++++++++++++++++++++++++++++++++++++++
-
-For JavaScript, one can pass static asset URLs as function arguments or
-globals. The globals can be generated in page template code, having access to
-the ``request.static_url()`` function.
-
-Below is a simple example of passing a cached busted image URL in the Jinja2
-template language. Put the following code into the ``<head>`` section of the
-relevant page.
-
-.. code-block:: html
-
- <script>
- window.assets.backgroundImage =
- "{{ '/theme/img/background.jpg'|static_url() }}";
- </script>
-
-Then in your main ``site.js`` file, put the following code.
-
-.. code-block:: javascript
-
- var image = new Image(window.assets.backgroundImage);
+If your CSS and JavaScript assets use URLs to reference other assets it is
+recommended that you implement an external asset pipeline that can rewrite the
+generated static files with new URLs containing cache busting tokens. The
+machinery inside :app:`Pyramid` will not help with this step as it has very
+little knowledge of the asset types your application may use.
.. _advanced_static:
diff --git a/docs/narr/commandline.rst b/docs/narr/commandline.rst
index 430641a50..eb79dffb6 100644
--- a/docs/narr/commandline.rst
+++ b/docs/narr/commandline.rst
@@ -261,6 +261,8 @@ request is configured to generate urls from the host
>>> request.route_url('home')
'https://www.example.com/'
+.. _ipython_or_bpython:
+
Alternative Shells
~~~~~~~~~~~~~~~~~~
diff --git a/docs/narr/extconfig.rst b/docs/narr/extconfig.rst
index a61eca7b7..fee8d0d3a 100644
--- a/docs/narr/extconfig.rst
+++ b/docs/narr/extconfig.rst
@@ -7,9 +7,9 @@ Extending Pyramid Configuration
===============================
Pyramid allows you to extend its Configurator with custom directives. Custom
-directives can use other directives, they can add a custom :term:`action`,
-they can participate in :term:`conflict resolution`, and they can provide
-some number of :term:`introspectable` objects.
+directives can use other directives, they can add a custom :term:`action`, they
+can participate in :term:`conflict resolution`, and they can provide some
+number of :term:`introspectable` objects.
.. index::
single: add_directive
@@ -20,18 +20,17 @@ some number of :term:`introspectable` objects.
Adding Methods to the Configurator via ``add_directive``
--------------------------------------------------------
-Framework extension writers can add arbitrary methods to a
-:term:`Configurator` by using the
-:meth:`pyramid.config.Configurator.add_directive` method of the configurator.
-Using :meth:`~pyramid.config.Configurator.add_directive` makes it possible to
-extend a Pyramid configurator in arbitrary ways, and allows it to perform
-application-specific tasks more succinctly.
+Framework extension writers can add arbitrary methods to a :term:`Configurator`
+by using the :meth:`pyramid.config.Configurator.add_directive` method of the
+configurator. Using :meth:`~pyramid.config.Configurator.add_directive` makes it
+possible to extend a Pyramid configurator in arbitrary ways, and allows it to
+perform application-specific tasks more succinctly.
The :meth:`~pyramid.config.Configurator.add_directive` method accepts two
-positional arguments: a method name and a callable object. The callable
-object is usually a function that takes the configurator instance as its
-first argument and accepts other arbitrary positional and keyword arguments.
-For example:
+positional arguments: a method name and a callable object. The callable object
+is usually a function that takes the configurator instance as its first
+argument and accepts other arbitrary positional and keyword arguments. For
+example:
.. code-block:: python
:linenos:
@@ -48,8 +47,8 @@ For example:
add_newrequest_subscriber)
Once :meth:`~pyramid.config.Configurator.add_directive` is called, a user can
-then call the added directive by its given name as if it were a built-in
-method of the Configurator:
+then call the added directive by its given name as if it were a built-in method
+of the Configurator:
.. code-block:: python
:linenos:
@@ -59,9 +58,9 @@ method of the Configurator:
config.add_newrequest_subscriber(mysubscriber)
-A call to :meth:`~pyramid.config.Configurator.add_directive` is often
-"hidden" within an ``includeme`` function within a "frameworky" package meant
-to be included as per :ref:`including_configuration` via
+A call to :meth:`~pyramid.config.Configurator.add_directive` is often "hidden"
+within an ``includeme`` function within a "frameworky" package meant to be
+included as per :ref:`including_configuration` via
:meth:`~pyramid.config.Configurator.include`. For example, if you put this
code in a package named ``pyramid_subscriberhelpers``:
@@ -72,8 +71,8 @@ code in a package named ``pyramid_subscriberhelpers``:
config.add_directive('add_newrequest_subscriber',
add_newrequest_subscriber)
-The user of the add-on package ``pyramid_subscriberhelpers`` would then be
-able to install it and subsequently do:
+The user of the add-on package ``pyramid_subscriberhelpers`` would then be able
+to install it and subsequently do:
.. code-block:: python
:linenos:
@@ -91,13 +90,12 @@ Using ``config.action`` in a Directive
If a custom directive can't do its work exclusively in terms of existing
configurator methods (such as
-:meth:`pyramid.config.Configurator.add_subscriber`, as above), the directive
-may need to make use of the :meth:`pyramid.config.Configurator.action`
-method. This method adds an entry to the list of "actions" that Pyramid will
-attempt to process when :meth:`pyramid.config.Configurator.commit` is called.
-An action is simply a dictionary that includes a :term:`discriminator`,
-possibly a callback function, and possibly other metadata used by Pyramid's
-action system.
+:meth:`pyramid.config.Configurator.add_subscriber` as above), the directive may
+need to make use of the :meth:`pyramid.config.Configurator.action` method. This
+method adds an entry to the list of "actions" that Pyramid will attempt to
+process when :meth:`pyramid.config.Configurator.commit` is called. An action is
+simply a dictionary that includes a :term:`discriminator`, possibly a callback
+function, and possibly other metadata used by Pyramid's action system.
Here's an example directive which uses the "action" method:
@@ -122,15 +120,15 @@ closure function named ``register`` is passed as the second argument named
When the :meth:`~pyramid.config.Configurator.action` method is called, it
appends an action to the list of pending configuration actions. All pending
-actions with the same discriminator value are potentially in conflict with
-one another (see :ref:`conflict_detection`). When the
+actions with the same discriminator value are potentially in conflict with one
+another (see :ref:`conflict_detection`). When the
:meth:`~pyramid.config.Configurator.commit` method of the Configurator is
called (either explicitly or as the result of calling
:meth:`~pyramid.config.Configurator.make_wsgi_app`), conflicting actions are
-potentially automatically resolved as per
-:ref:`automatic_conflict_resolution`. If a conflict cannot be automatically
-resolved, a :exc:`pyramid.exceptions.ConfigurationConflictError` is raised
-and application startup is prevented.
+potentially automatically resolved as per :ref:`automatic_conflict_resolution`.
+If a conflict cannot be automatically resolved, a
+:exc:`pyramid.exceptions.ConfigurationConflictError` is raised and application
+startup is prevented.
In our above example, therefore, if a consumer of our ``add_jammyjam``
directive did this:
@@ -146,14 +144,14 @@ generated by the two calls are in direct conflict. Automatic conflict
resolution cannot resolve the conflict (because no ``config.include`` is
involved), and the user provided no intermediate
:meth:`pyramid.config.Configurator.commit` call between the calls to
-``add_jammyjam`` to ensure that the successive calls did not conflict with
-each other.
+``add_jammyjam`` to ensure that the successive calls did not conflict with each
+other.
This demonstrates the purpose of the discriminator argument to the action
method: it's used to indicate a uniqueness constraint for an action. Two
actions with the same discriminator will conflict unless the conflict is
-automatically or manually resolved. A discriminator can be any hashable
-object, but it is generally a string or a tuple. *You use a discriminator to
+automatically or manually resolved. A discriminator can be any hashable object,
+but it is generally a string or a tuple. *You use a discriminator to
declaratively ensure that the user doesn't provide ambiguous configuration
statements.*
@@ -169,21 +167,20 @@ appended to the pending actions list. When the pending configuration actions
are processed during :meth:`~pyramid.config.Configurator.commit`, and no
conflicts occur, the *callable* provided as the second argument to the
:meth:`~pyramid.config.Configurator.action` method within ``add_jammyjam`` is
-called with no arguments. The callable in ``add_jammyjam`` is the
-``register`` closure function. It simply sets the value
-``config.registry.jammyjam`` to whatever the user passed in as the
-``jammyjam`` argument to the ``add_jammyjam`` function. Therefore, the
-result of the user's call to our directive will set the ``jammyjam``
-attribute of the registry to the string ``first``. *A callable is used by a
-directive to defer the result of a user's call to the directive until
-conflict detection has had a chance to do its job*.
+called with no arguments. The callable in ``add_jammyjam`` is the ``register``
+closure function. It simply sets the value ``config.registry.jammyjam`` to
+whatever the user passed in as the ``jammyjam`` argument to the
+``add_jammyjam`` function. Therefore, the result of the user's call to our
+directive will set the ``jammyjam`` attribute of the registry to the string
+``first``. *A callable is used by a directive to defer the result of a user's
+call to the directive until conflict detection has had a chance to do its job*.
Other arguments exist to the :meth:`~pyramid.config.Configurator.action`
-method, including ``args``, ``kw``, ``order``, and ``introspectables``.
+method, including ``args``, ``kw``, ``order``, and ``introspectables``.
-``args`` and ``kw`` exist as values, which, if passed, will be used as
-arguments to the ``callable`` function when it is called back. For example
-our directive might use them like so:
+``args`` and ``kw`` exist as values, which if passed will be used as arguments
+to the ``callable`` function when it is called back. For example, our
+directive might use them like so:
.. code-block:: python
:linenos:
@@ -198,31 +195,33 @@ our directive might use them like so:
In the above example, when this directive is used to generate an action, and
that action is committed, ``config.registry.jammyjam_args`` will be set to
``('one',)`` and ``config.registry.jammyjam_kw`` will be set to
-``{'two':'two'}``. ``args`` and ``kw`` are honestly not very useful when
-your ``callable`` is a closure function, because you already usually have
-access to every local in the directive without needing them to be passed
-back. They can be useful, however, if you don't use a closure as a callable.
+``{'two':'two'}``. ``args`` and ``kw`` are honestly not very useful when your
+``callable`` is a closure function, because you already usually have access to
+every local in the directive without needing them to be passed back. They can
+be useful, however, if you don't use a closure as a callable.
``order`` is a crude order control mechanism. ``order`` defaults to the
integer ``0``; it can be set to any other integer. All actions that share an
order will be called before other actions that share a higher order. This
makes it possible to write a directive with callable logic that relies on the
-execution of the callable of another directive being done first. For
-example, Pyramid's :meth:`pyramid.config.Configurator.add_view` directive
-registers an action with a higher order than the
+execution of the callable of another directive being done first. For example,
+Pyramid's :meth:`pyramid.config.Configurator.add_view` directive registers an
+action with a higher order than the
:meth:`pyramid.config.Configurator.add_route` method. Due to this, the
-``add_view`` method's callable can assume that, if a ``route_name`` was
-passed to it, that a route by this name was already registered by
-``add_route``, and if such a route has not already been registered, it's a
-configuration error (a view that names a nonexistent route via its
-``route_name`` parameter will never be called). As of Pyramid 1.6 it is
-possible for one action to invoke another. See :ref:`ordering_actions` for
-more information.
-
-``introspectables`` is a sequence of :term:`introspectable` objects. You can
-pass a sequence of introspectables to the
-:meth:`~pyramid.config.Configurator.action` method, which allows you to
-augment Pyramid's configuration introspection system.
+``add_view`` method's callable can assume that, if a ``route_name`` was passed
+to it, that a route by this name was already registered by ``add_route``, and
+if such a route has not already been registered, it's a configuration error (a
+view that names a nonexistent route via its ``route_name`` parameter will never
+be called).
+
+.. versionchanged:: 1.6
+ As of Pyramid 1.6 it is possible for one action to invoke another. See
+ :ref:`ordering_actions` for more information.
+
+Finally, ``introspectables`` is a sequence of :term:`introspectable` objects.
+You can pass a sequence of introspectables to the
+:meth:`~pyramid.config.Configurator.action` method, which allows you to augment
+Pyramid's configuration introspection system.
.. _ordering_actions:
@@ -233,18 +232,17 @@ In Pyramid every :term:`action` has an inherent ordering relative to other
actions. The logic within actions is deferred until a call to
:meth:`pyramid.config.Configurator.commit` (which is automatically invoked by
:meth:`pyramid.config.Configurator.make_wsgi_app`). This means you may call
-``config.add_view(route_name='foo')`` **before**
-``config.add_route('foo', '/foo')`` because nothing actually happens until
-commit-time. During a commit cycle conflicts are resolved, actions are ordered
-and executed.
+``config.add_view(route_name='foo')`` **before** ``config.add_route('foo',
+'/foo')`` because nothing actually happens until commit-time. During a commit
+cycle, conflicts are resolved, and actions are ordered and executed.
By default, almost every action in Pyramid has an ``order`` of
:const:`pyramid.config.PHASE3_CONFIG`. Every action within the same order-level
-will be executed in the order it was called.
-This means that if an action must be reliably executed before or after another
-action, the ``order`` must be defined explicitly to make this work. For
-example, views are dependent on routes being defined. Thus the action created
-by :meth:`pyramid.config.Configurator.add_route` has an ``order`` of
+will be executed in the order it was called. This means that if an action must
+be reliably executed before or after another action, the ``order`` must be
+defined explicitly to make this work. For example, views are dependent on
+routes being defined. Thus the action created by
+:meth:`pyramid.config.Configurator.add_route` has an ``order`` of
:const:`pyramid.config.PHASE2_CONFIG`.
Pre-defined Phases
@@ -252,8 +250,8 @@ Pre-defined Phases
:const:`pyramid.config.PHASE0_CONFIG`
-- This phase is reserved for developers who want to execute actions prior
- to Pyramid's core directives.
+- This phase is reserved for developers who want to execute actions prior to
+ Pyramid's core directives.
:const:`pyramid.config.PHASE1_CONFIG`
@@ -274,17 +272,17 @@ Pre-defined Phases
- The default for all builtin or custom directives unless otherwise specified.
-Calling Actions From Actions
+Calling Actions from Actions
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
.. versionadded:: 1.6
-Pyramid's configurator allows actions to be added during a commit-cycle as
-long as they are added to the current or a later ``order`` phase. This means
-that your custom action can defer decisions until commit-time and then do
-things like invoke :meth:`pyramid.config.Configurator.add_route`. It can also
-provide better conflict detection if your addon needs to call more than one
-other action.
+Pyramid's configurator allows actions to be added during a commit-cycle as long
+as they are added to the current or a later ``order`` phase. This means that
+your custom action can defer decisions until commit-time and then do things
+like invoke :meth:`pyramid.config.Configurator.add_route`. It can also provide
+better conflict detection if your addon needs to call more than one other
+action.
For example, let's make an addon that invokes ``add_route`` and ``add_view``,
but we want it to conflict with any other call to our addon:
@@ -304,12 +302,12 @@ but we want it to conflict with any other call to our addon:
config.action(('auto route', name), register, order=PHASE0_CONFIG)
Now someone else can use your addon and be informed if there is a conflict
-between this route and another, or two calls to ``add_auto_route``.
-Notice how we had to invoke our action **before** ``add_view`` or
-``add_route``. If we tried to invoke this afterward, the subsequent calls to
-``add_view`` and ``add_route`` would cause conflicts because that phase had
-already been executed, and the configurator cannot go back in time to add more
-views during that commit-cycle.
+between this route and another, or two calls to ``add_auto_route``. Notice how
+we had to invoke our action **before** ``add_view`` or ``add_route``. If we
+tried to invoke this afterward, the subsequent calls to ``add_view`` and
+``add_route`` would cause conflicts because that phase had already been
+executed, and the configurator cannot go back in time to add more views during
+that commit-cycle.
.. code-block:: python
:linenos:
@@ -341,16 +339,16 @@ All built-in Pyramid directives (such as
introspectables when called. For example, when you register a view via
``add_view``, the directive registers at least one introspectable: an
introspectable about the view registration itself, providing human-consumable
-values for the arguments it was passed. You can later use the introspection
-query system to determine whether a particular view uses a renderer, or
-whether a particular view is limited to a particular request method, or which
-routes a particular view is registered against. The Pyramid "debug toolbar"
-makes use of the introspection system in various ways to display information
-to Pyramid developers.
+values for the arguments passed into it. You can later use the introspection
+query system to determine whether a particular view uses a renderer, or whether
+a particular view is limited to a particular request method, or against which
+routes a particular view is registered. The Pyramid "debug toolbar" makes use
+of the introspection system in various ways to display information to Pyramid
+developers.
-Introspection values are set when a sequence of :term:`introspectable`
-objects is passed to the :meth:`~pyramid.config.Configurator.action` method.
-Here's an example of a directive which uses introspectables:
+Introspection values are set when a sequence of :term:`introspectable` objects
+is passed to the :meth:`~pyramid.config.Configurator.action` method. Here's an
+example of a directive which uses introspectables:
.. code-block:: python
:linenos:
@@ -370,9 +368,9 @@ Here's an example of a directive which uses introspectables:
config.add_directive('add_jammyjam', add_jammyjam)
If you notice, the above directive uses the ``introspectable`` attribute of a
-Configurator (:attr:`pyramid.config.Configurator.introspectable`) to create
-an introspectable object. The introspectable object's constructor requires
-at least four arguments: the ``category_name``, the ``discriminator``, the
+Configurator (:attr:`pyramid.config.Configurator.introspectable`) to create an
+introspectable object. The introspectable object's constructor requires at
+least four arguments: the ``category_name``, the ``discriminator``, the
``title``, and the ``type_name``.
The ``category_name`` is a string representing the logical category for this
@@ -392,19 +390,19 @@ The ``type_name`` is a value that can be used to subtype this introspectable
within its category for sorting and presentation purposes. It can be any
value.
-An introspectable is also dictionary-like. It can contain any set of
-key/value pairs, typically related to the arguments passed to its related
-directive. While the category_name, discriminator, title and type_name are
-*metadata* about the introspectable, the values provided as key/value pairs
+An introspectable is also dictionary-like. It can contain any set of key/value
+pairs, typically related to the arguments passed to its related directive.
+While the ``category_name``, ``discriminator``, ``title``, and ``type_name``
+are *metadata* about the introspectable, the values provided as key/value pairs
are the actual data provided by the introspectable. In the above example, we
set the ``value`` key to the value of the ``value`` argument passed to the
directive.
Our directive above mutates the introspectable, and passes it in to the
``action`` method as the first element of a tuple as the value of the
-``introspectable`` keyword argument. This associates this introspectable
-with the action. Introspection tools will then display this introspectable
-in their index.
+``introspectable`` keyword argument. This associates this introspectable with
+the action. Introspection tools will then display this introspectable in their
+index.
Introspectable Relationships
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -435,30 +433,29 @@ Two introspectables may have relationships between each other.
config.add_directive('add_jammyjam', add_jammyjam)
In the above example, the ``add_jammyjam`` directive registers two
-introspectables. The first is related to the ``value`` passed to the
-directive; the second is related to the ``template`` passed to the directive.
-If you believe a concept within a directive is important enough to have its
-own introspectable, you can cause the same directive to register more than
-one introspectable, registering one introspectable for the "main idea" and
-another for a related concept.
+introspectables: the first is related to the ``value`` passed to the directive,
+and the second is related to the ``template`` passed to the directive. If you
+believe a concept within a directive is important enough to have its own
+introspectable, you can cause the same directive to register more than one
+introspectable, registering one introspectable for the "main idea" and another
+for a related concept.
The call to ``intr.relate`` above
-(:meth:`pyramid.interfaces.IIntrospectable.relate`) is passed two arguments:
-a category name and a directive. The example above effectively indicates
-that the directive wishes to form a relationship between the ``intr``
-introspectable and the ``tmpl_intr`` introspectable; the arguments passed to
-``relate`` are the category name and discriminator of the ``tmpl_intr``
-introspectable.
-
-Relationships need not be made between two introspectables created by the
-same directive. Instead, a relationship can be formed between an
-introspectable created in one directive and another introspectable created in
-another by calling ``relate`` on either side with the other directive's
-category name and discriminator. An error will be raised at configuration
-commit time if you attempt to relate an introspectable with another
-nonexistent introspectable, however.
+(:meth:`pyramid.interfaces.IIntrospectable.relate`) is passed two arguments: a
+category name and a directive. The example above effectively indicates that
+the directive wishes to form a relationship between the ``intr`` introspectable
+and the ``tmpl_intr`` introspectable; the arguments passed to ``relate`` are
+the category name and discriminator of the ``tmpl_intr`` introspectable.
+
+Relationships need not be made between two introspectables created by the same
+directive. Instead a relationship can be formed between an introspectable
+created in one directive and another introspectable created in another by
+calling ``relate`` on either side with the other directive's category name and
+discriminator. An error will be raised at configuration commit time if you
+attempt to relate an introspectable with another nonexistent introspectable,
+however.
Introspectable relationships will show up in frontend system renderings of
-introspection values. For example, if a view registration names a route
-name, the introspectable related to the view callable will show a reference
-to the route to which it relates to and vice versa.
+introspection values. For example, if a view registration names a route name,
+the introspectable related to the view callable will show a reference to the
+route to which it relates and vice versa.
diff --git a/docs/narr/extending.rst b/docs/narr/extending.rst
index 8462a9da7..d28eb341d 100644
--- a/docs/narr/extending.rst
+++ b/docs/narr/extending.rst
@@ -1,13 +1,13 @@
.. _extending_chapter:
-Extending An Existing :app:`Pyramid` Application
-===================================================
+Extending an Existing :app:`Pyramid` Application
+================================================
-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.
+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.
@@ -16,10 +16,10 @@ 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.
+ Another developer who wishes to reuse the application written by the original
+ application developer in an unanticipated context. They may also wish to
+ modify the original application without changing the original application's
+ source code.
The Difference Between "Extensible" and "Pluggable" Applications
----------------------------------------------------------------
@@ -27,31 +27,31 @@ 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.
+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.
+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 they have
+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 into Pyramid itself but should instead plug into a
-system written atop Pyramid.
+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 into 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
@@ -64,13 +64,13 @@ Pyramid applications are *extensible*.
.. _building_an_extensible_app:
-Rules for Building An Extensible Application
+Rules for Building an Extensible Application
--------------------------------------------
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
+overridable :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:
@@ -84,8 +84,8 @@ function in your application's ``__init__.py``. For example, rather than:
config.add_view('myapp.views.view1', name='view1')
config.add_view('myapp.views.view2', name='view2')
-You should move the calls to ``add_view`` outside of the (non-reusable)
-``if __name__ == '__main__'`` block, and into a reusable function:
+You should move the calls to ``add_view`` outside of the (non-reusable) ``if
+__name__ == '__main__'`` block, and into a reusable function:
.. code-block:: python
:linenos:
@@ -100,13 +100,12 @@ You should move the calls to ``add_view`` outside of the (non-reusable)
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".
+Doing this allows an integrator to maximally reuse the configuration statements
+that relate to your application by allowing them to selectively include or
+exclude 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
+Alternatively you can use :term:`ZCML` for the purpose of making configuration
+extensible and overridable. :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
@@ -115,16 +114,15 @@ it will automatically be maximally extensible without any manual effort. See
Fundamental Plugpoints
~~~~~~~~~~~~~~~~~~~~~~
-The fundamental "plug points" of an application developed using
-:app:`Pyramid` are *routes*, *views*, and *assets*. Routes are declarations
-made using the :meth:`pyramid.config.Configurator.add_route` method. Views
-are declarations made using the :meth:`pyramid.config.Configurator.add_view`
-method. 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, the
-``add_handler`` directive of the ``pyramid_handlers`` package adds a single
-route, and some number of views.
+The fundamental "plug points" of an application developed using :app:`Pyramid`
+are *routes*, *views*, and *assets*. Routes are declarations made using the
+:meth:`pyramid.config.Configurator.add_route` method. Views are declarations
+made using the :meth:`pyramid.config.Configurator.add_view` method. 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, the ``add_handler`` directive of the ``pyramid_handlers`` package
+adds a single route and some number of views.
.. index::
single: extending an existing application
@@ -133,10 +131,9 @@ 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.
+application does or does not use configuration decorators or imperative code.
-If The Application Has Configuration Decorations
+If the Application Has Configuration Decorations
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
You've inherited a :app:`Pyramid` application which you'd like to extend or
@@ -155,9 +152,9 @@ registers more views or routes.
config.add_view('mypackage.views.myview', name='myview')
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.
+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 perform overrides.
.. code-block:: python
:linenos:
@@ -170,11 +167,11 @@ views or routes which performs overrides.
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
+You can alternatively 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
+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`.
@@ -183,37 +180,37 @@ configuration or ZCML to a separate Python package as described in
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.
+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), to which they are referred within the original
+package.
-The general pattern for extending an existing application looks something
-like this:
+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 scaffold 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 assets as necessary.
+- In the new package, create Python files containing views and other overridden
+ elements, such as templates and static assets as necessary.
- Install the new package into the same Python environment as the original
- application (e.g. ``$VENV/bin/python setup.py develop`` or
+ application (e.g., ``$VENV/bin/python setup.py develop`` or
``$VENV/bin/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. This 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`.
+- 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. This 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
@@ -221,17 +218,17 @@ like this:
.. _overriding_views:
Overriding Views
-~~~~~~~~~~~~~~~~~
+~~~~~~~~~~~~~~~~
-The :term:`view configuration` declarations you make which *override*
+The :term:`view configuration` declarations that 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.
+attributes as the original that you wish to override. These ``<view>``
+declarations will point at "new" view code in the override package that you've
+created. The new view code itself will usually be copy-and-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:
+For example, if the original application has the following ``configure_views``
+configuration method:
.. code-block:: python
:linenos:
@@ -254,13 +251,13 @@ configuration function:
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.
+In this case, the ``theoriginalapp.views.theview`` view will never be executed.
+Instead, a new view, ``theoverrideapp.views.theview`` will be executed when
+request circumstances dictate.
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.
+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
@@ -270,13 +267,13 @@ to make sure the URLs it implies are available on some other page rendering.
Overriding Routes
~~~~~~~~~~~~~~~~~
-Route setup is currently typically performed in a sequence of ordered calls
-to :meth:`~pyramid.config.Configurator.add_route`. Because these calls are
+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.
+override. Typically this means *copying* all the ``add_route`` statements into
+the override package's file and changing them as necessary. Then exclude any
+``add_route`` statements from the original application.
.. index::
pair: overriding; assets
@@ -288,9 +285,8 @@ Overriding Assets
Assets are files on the filesystem that are accessible within a Python
*package*. An entire chapter is devoted to assets: :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
-assets with other assets 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.
+Within this chapter is a section named :ref:`overriding_assets_section`. This
+section of that chapter describes in detail how to override package assets with
+other assets 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/hooks.rst b/docs/narr/hooks.rst
index 4fd7670b9..6aa1a99c2 100644
--- a/docs/narr/hooks.rst
+++ b/docs/narr/hooks.rst
@@ -14,12 +14,12 @@ 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`. The default Not Found View
-can be overridden through application configuration.
+When :app:`Pyramid` can't map a URL to view code, it invokes a :term:`Not Found
+View`, which is a :term:`view callable`. The default Not Found View can be
+overridden through application configuration.
-If your application uses :term:`imperative configuration`, you can replace
-the Not Found View by using the
+If your application uses :term:`imperative configuration`, you can replace the
+Not Found View by using the
:meth:`pyramid.config.Configurator.add_notfound_view` method:
.. code-block:: python
@@ -77,14 +77,14 @@ Views can carry predicates limiting their applicability. For example:
config = Configurator()
config.scan()
-The ``notfound_get`` view will be called when a view could not be found and
-the request method was ``GET``. The ``notfound_post`` view will be called
-when a view could not be found and the request method was ``POST``.
+The ``notfound_get`` view will be called when a view could not be found and the
+request method was ``GET``. The ``notfound_post`` view will be called when a
+view could not be found and the request method was ``POST``.
Like any other view, the Not Found 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
+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.httpexceptions.HTTPNotFound` exception that caused the view to
be called.
@@ -106,13 +106,13 @@ callable:
.. note::
- When a Not Found View callable is invoked, it is passed a
- :term:`request`. The ``exception`` attribute of the request will be an
- instance of the :exc:`~pyramid.httpexceptions.HTTPNotFound` exception that
- caused the Not Found View to be called. The value of
- ``request.exception.message`` will be a value explaining why the Not Found
- error was raised. This message has different values depending whether the
- ``pyramid.debug_notfound`` environment setting is true or false.
+ When a Not Found View callable is invoked, it is passed a :term:`request`.
+ The ``exception`` attribute of the request will be an instance of the
+ :exc:`~pyramid.httpexceptions.HTTPNotFound` exception that caused the Not
+ Found View to be called. The value of ``request.exception.message`` will be
+ a value explaining why the Not Found exception was raised. This message has
+ different values depending on whether the ``pyramid.debug_notfound``
+ environment setting is true or false.
.. note::
@@ -124,9 +124,9 @@ callable:
.. warning::
- When a Not Found View callable accepts an argument list as
- described in :ref:`request_and_context_view_definitions`, the ``context``
- passed as the first argument to the view callable will be the
+ When a Not Found View callable accepts an argument list as described in
+ :ref:`request_and_context_view_definitions`, the ``context`` passed as the
+ first argument to the view callable will be the
:exc:`~pyramid.httpexceptions.HTTPNotFound` exception instance. If
available, the resource context will still be available as
``request.context``.
@@ -140,13 +140,13 @@ 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 403 status code and is very plain, but
-the view which generates it can be overridden as necessary.
+:term:`authorization policy` in use, it invokes a :term:`forbidden view`. The
+default forbidden response has a 403 status code and is very plain, but the
+view which generates it can be overridden as necessary.
The :term:`forbidden view` callable is a view callable like any other. The
-:term:`view configuration` which causes it to be a "forbidden" view consists
-of using the :meth:`pyramid.config.Configurator.add_forbidden_view` API or the
+:term:`view configuration` which causes it to be a "forbidden" view consists of
+using the :meth:`pyramid.config.Configurator.add_forbidden_view` API or the
:class:`pyramid.view.forbidden_view_config` decorator.
For example, you can add a forbidden view by using the
@@ -181,14 +181,11 @@ as a forbidden view:
config.scan()
Like any other view, the forbidden view must accept at least a ``request``
-parameter, or both ``context`` and ``request``. If a forbidden view
-callable accepts both ``context`` and ``request``, the HTTP Exception is passed
-as context. The ``context`` as found by the router when view was
-denied (that you normally would expect) is available as
-``request.context``. The ``request`` is the current :term:`request`
-representing the denied action.
-
-
+parameter, or both ``context`` and ``request``. If a forbidden view callable
+accepts both ``context`` and ``request``, the HTTP Exception is passed as
+context. The ``context`` as found by the router when the view was denied (which
+you normally would expect) is available as ``request.context``. The
+``request`` is the current :term:`request` representing the denied action.
Here's some sample code that implements a minimal forbidden view:
@@ -203,15 +200,15 @@ Here's some sample code that implements a minimal forbidden view:
.. note::
- When a forbidden view callable is invoked, it is passed a
- :term:`request`. The ``exception`` attribute of the request will be an
- instance of the :exc:`~pyramid.httpexceptions.HTTPForbidden` exception
- that caused the forbidden view to be called. The value of
- ``request.exception.message`` will be a value explaining why the forbidden
- was raised and ``request.exception.result`` will be extended information
- about the forbidden exception. These messages have different values
- depending whether the ``pyramid.debug_authorization`` environment setting
- is true or false.
+ When a forbidden view callable is invoked, it is passed a :term:`request`.
+ The ``exception`` attribute of the request will be an instance of the
+ :exc:`~pyramid.httpexceptions.HTTPForbidden` exception that caused the
+ forbidden view to be called. The value of ``request.exception.message``
+ will be a value explaining why the forbidden exception was raised, and
+ ``request.exception.result`` will be extended information about the
+ forbidden exception. These messages have different values depending on
+ whether the ``pyramid.debug_authorization`` environment setting is true or
+ false.
.. index::
single: request factory
@@ -223,11 +220,11 @@ Changing the Request Factory
Whenever :app:`Pyramid` handles a request from a :term:`WSGI` server, 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.
+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
+The class (a.k.a., "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.
@@ -242,7 +239,7 @@ callable or a :term:`dotted Python name` representing a callable.
config = Configurator(request_factory=MyRequest)
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
+already constructed a :term:`configurator`, it can also be registered via the
:meth:`pyramid.config.Configurator.set_request_factory` method:
.. code-block:: python
@@ -262,19 +259,19 @@ already constructed a :term:`configurator` it can also be registered via the
.. _adding_request_method:
-Adding Methods or Properties to Request Object
-----------------------------------------------
+Adding Methods or Properties to a Request Object
+------------------------------------------------
.. versionadded:: 1.4.
Since each Pyramid application can only have one :term:`request` factory,
-:ref:`changing the request factory <changing_the_request_factory>`
-is not that extensible, especially if you want to build composable features
-(e.g., Pyramid add-ons and plugins).
+:ref:`changing the request factory <changing_the_request_factory>` is not that
+extensible, especially if you want to build composable features (e.g., Pyramid
+add-ons and plugins).
A lazy property can be registered to the request object via the
-:meth:`pyramid.config.Configurator.add_request_method` API. This allows you
-to specify a callable that will be available on the request object, but will not
+:meth:`pyramid.config.Configurator.add_request_method` API. This allows you to
+specify a callable that will be available on the request object, but will not
actually execute the function until accessed.
.. warning::
@@ -298,9 +295,10 @@ actually execute the function until accessed.
config.add_request_method(total)
config.add_request_method(prop, reify=True)
-In the above example, ``total`` is added as a method. However, ``prop`` is added
-as a property and its result is cached per-request by setting ``reify=True``.
-This way, we eliminate the overhead of running the function multiple times.
+In the above example, ``total`` is added as a method. However, ``prop`` is
+added as a property and its result is cached per-request by setting
+``reify=True``. This way, we eliminate the overhead of running the function
+multiple times.
>>> request.total(1, 2, 3)
6
@@ -354,18 +352,18 @@ We attach and cache an object named ``extra`` to the ``request`` object.
.. _changing_the_response_factory:
Changing the Response Factory
--------------------------------
+-----------------------------
.. versionadded:: 1.6
-Whenever :app:`Pyramid` returns a response from a view it creates a
+Whenever :app:`Pyramid` returns a response from a view, it creates a
:term:`response` object. By default, an instance of the
:class:`pyramid.response.Response` class is created to represent the response
object.
-The factory that :app:`Pyramid` uses to create a response object instance can be
-changed by passing a :class:`pyramid.interfaces.IResponseFactory` argument to
-the constructor of the :term:`configurator`. This argument can be either a
+The factory that :app:`Pyramid` uses to create a response object instance can
+be changed by passing a :class:`pyramid.interfaces.IResponseFactory` 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 factory takes a single positional argument, which is a :term:`Request`
@@ -381,8 +379,8 @@ object. The argument may be ``None``.
config = Configurator(response_factory=lambda r: MyResponse())
-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
+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_response_factory` method:
.. code-block:: python
@@ -403,13 +401,13 @@ already constructed a :term:`configurator` it can also be registered via the
.. _beforerender_event:
-Using The Before Render Event
+Using the Before Render Event
-----------------------------
Subscribers to the :class:`pyramid.events.BeforeRender` event may introspect
and modify the set of :term:`renderer globals` before they are passed to a
-:term:`renderer`. This event object iself has a dictionary-like interface
-that can be used for this purpose. For example:
+:term:`renderer`. This event object iself has a dictionary-like interface that
+can be used for this purpose. For example:
.. code-block:: python
:linenos:
@@ -421,22 +419,22 @@ that can be used for this purpose. For example:
def add_global(event):
event['mykey'] = 'foo'
-An object of this type is sent as an event just before a :term:`renderer`
-is invoked.
+An object of this type is sent as an event just before a :term:`renderer` is
+invoked.
-If a subscriber attempts to add a key that already exist in the renderer
+If a subscriber attempts to add a key that already exists in the renderer
globals dictionary, a :exc:`KeyError` is raised. This limitation is enforced
because event subscribers do not possess any relative ordering. The set of
keys added to the renderer globals dictionary by all
-:class:`pyramid.events.BeforeRender` subscribers and renderer globals
-factories must be unique.
+:class:`pyramid.events.BeforeRender` subscribers and renderer globals factories
+must be unique.
The dictionary returned from the view is accessible through the
:attr:`rendering_val` attribute of a :class:`~pyramid.events.BeforeRender`
event.
-Suppose you return ``{'mykey': 'somevalue', 'mykey2': 'somevalue2'}`` from
-your view callable, like so:
+Suppose you return ``{'mykey': 'somevalue', 'mykey2': 'somevalue2'}`` from your
+view callable, like so:
.. code-block:: python
:linenos:
@@ -492,24 +490,23 @@ A response callback is a callable which accepts two positional parameters:
response.cache_control.max_age = 360
request.add_response_callback(cache_callback)
-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``.
+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``.
Response callbacks are called in the order they're added
-(first-to-most-recently-added). All response callbacks are called *before*
-the :class:`~pyramid.events.NewResponse` event is sent. Errors raised by
-response callbacks are not handled specially. They will be propagated to the
-caller of the :app:`Pyramid` router application.
+(first-to-most-recently-added). All response callbacks are called *before* the
+:class:`~pyramid.events.NewResponse` event is sent. Errors raised by response
+callbacks are not handled specially. They will be propagated to the caller of
+the :app:`Pyramid` router application.
A response callback has a lifetime of a *single* request. If you want a
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).
+re-register the callback into every new request (perhaps within a subscriber of
+a :class:`~pyramid.events.NewRequest` event).
.. index::
single: finished callback
@@ -520,15 +517,15 @@ 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
+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.
-A finished callback is a callable which accepts a single positional
-parameter: ``request``. For example:
+A finished callback is a callable which accepts a single positional parameter:
+``request``. For example:
.. code-block:: python
:linenos:
@@ -543,29 +540,27 @@ parameter: ``request``. For example:
request.add_finished_callback(log_callback)
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.
-
-Errors raised by finished callbacks are not handled specially. They
-will be propagated to the caller of the :app:`Pyramid` router
-application.
+(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.
+
+Errors raised by finished callbacks are not handled specially. They will be
+propagated to the caller of the :app:`Pyramid` router application.
A finished callback has a lifetime of a *single* request. If you want a
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).
+re-register the callback into every new request (perhaps within a subscriber of
+a :class:`~pyramid.events.NewRequest` event).
.. index::
single: traverser
@@ -577,8 +572,8 @@ 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.
+algorithm can be swapped out selectively for a different traversal pattern via
+configuration.
.. code-block:: python
:linenos:
@@ -624,10 +619,10 @@ that implements the following interface:
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"
+conditionally, you could claim that an alternative 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:
+used. Otherwise the default traverser would be used. For example:
.. code-block:: python
:linenos:
@@ -639,13 +634,13 @@ used. Otherwise, the default traverser would be used. For example:
config.add_traverser(Traverser, MyRoot)
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
+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.
.. index::
- single: url generator
+ single: URL generator
.. _changing_resource_url:
@@ -655,9 +650,8 @@ Changing How :meth:`pyramid.request.Request.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
:meth:`pyramid.request.Request.resource_url` API. However, since the way
-traversal is done will have been modified, the URLs it generates by default
-may be incorrect when used against resources derived from your custom
-traverser.
+traversal is done will have been modified, the URLs it generates by default may
+be incorrect when used against resources derived from your custom traverser.
If you've added a traverser, you can change how
:meth:`~pyramid.request.Request.resource_url` generates a URL for a specific
@@ -674,13 +668,13 @@ For example:
config.add_resource_url_adapter(ResourceURLAdapter, MyRoot)
-In the above example, the ``myapp.traversal.ResourceURLAdapter`` class will
-be used to provide services to :meth:`~pyramid.request.Request.resource_url`
-any time the :term:`resource` passed to ``resource_url`` is of the class
+In the above example, the ``myapp.traversal.ResourceURLAdapter`` class will be
+used to provide services to :meth:`~pyramid.request.Request.resource_url` any
+time the :term:`resource` passed to ``resource_url`` is of the class
``myapp.resources.MyRoot``. The ``resource_iface`` argument ``MyRoot``
represents the type of interface that must be possessed by the resource for
this resource url factory to be found. If the ``resource_iface`` argument is
-omitted, this resource url adapter will be used for *all* resources.
+omitted, this resource URL adapter will be used for *all* resources.
The API that must be implemented by a class that provides
:class:`~pyramid.interfaces.IResourceURL` is as follows:
@@ -693,8 +687,8 @@ The API that must be implemented by a class that provides
resource
"""
def __init__(self, resource, request):
- """ Accept the resource and request and set self.physical_path and
- self.virtual_path"""
+ """ Accept the resource and request and set self.physical_path and
+ self.virtual_path """
self.virtual_path = some_function_of(resource, request)
self.physical_path = some_other_function_of(resource, request)
@@ -703,7 +697,8 @@ The default context URL generator is available for perusal as the class
<https://github.com/Pylons/pyramid/blob/master/pyramid/traversal.py>`_ of the
:term:`Pylons` GitHub Pyramid repository.
-See :meth:`pyramid.config.add_resource_url_adapter` for more information.
+See :meth:`pyramid.config.Configurator.add_resource_url_adapter` for more
+information.
.. index::
single: IResponse
@@ -721,25 +716,24 @@ callable on a per-type basis by using a hook involving
:meth:`pyramid.config.Configurator.add_response_adapter` or the
:class:`~pyramid.response.response_adapter` decorator.
-Pyramid, in various places, adapts the result of calling a view callable to
-the :class:`~pyramid.interfaces.IResponse` interface to ensure that the
-object returned by the view callable is a "true" response object. The vast
-majority of time, the result of this adaptation is the result object itself,
-as view callables written by "civilians" who read the narrative documentation
-contained in this manual will always return something that implements the
-:class:`~pyramid.interfaces.IResponse` interface. Most typically, this will
-be an instance of the :class:`pyramid.response.Response` class or a subclass.
-If a civilian returns a non-Response object from a view callable that isn't
-configured to use a :term:`renderer`, he will typically expect the router to
+Pyramid, in various places, adapts the result of calling a view callable to the
+:class:`~pyramid.interfaces.IResponse` interface to ensure that the object
+returned by the view callable is a "true" response object. The vast majority
+of time, the result of this adaptation is the result object itself, as view
+callables written by "civilians" who read the narrative documentation contained
+in this manual will always return something that implements the
+:class:`~pyramid.interfaces.IResponse` interface. Most typically, this will be
+an instance of the :class:`pyramid.response.Response` class or a subclass. If a
+civilian returns a non-Response object from a view callable that isn't
+configured to use a :term:`renderer`, they will typically expect the router to
raise an error. However, you can hook Pyramid in such a way that users can
return arbitrary values from a view callable by providing an adapter which
converts the arbitrary return value into something that implements
:class:`~pyramid.interfaces.IResponse`.
For example, if you'd like to allow view callables to return bare string
-objects (without requiring a :term:`renderer` to convert a string to a
-response object), you can register an adapter which converts the string to a
-Response:
+objects (without requiring a :term:`renderer` to convert a string to a response
+object), you can register an adapter which converts the string to a Response:
.. code-block:: python
:linenos:
@@ -754,9 +748,9 @@ Response:
config.add_response_adapter(string_response_adapter, str)
-Likewise, if you want to be able to return a simplified kind of response
-object from view callables, you can use the IResponse hook to register an
-adapter to the more complex IResponse interface:
+Likewise, if you want to be able to return a simplified kind of response object
+from view callables, you can use the IResponse hook to register an adapter to
+the more complex IResponse interface:
.. code-block:: python
:linenos:
@@ -777,7 +771,7 @@ adapter to the more complex IResponse interface:
If you want to implement your own Response object instead of using the
:class:`pyramid.response.Response` object in any capacity at all, you'll have
-to make sure the object implements every attribute and method outlined in
+to make sure that the object implements every attribute and method outlined in
:class:`pyramid.interfaces.IResponse` and you'll have to ensure that it uses
``zope.interface.implementer(IResponse)`` as a class decorator.
@@ -789,7 +783,7 @@ to make sure the object implements every attribute and method outlined in
@implementer(IResponse)
class MyResponse(object):
- # ... an implementation of every method and attribute
+ # ... an implementation of every method and attribute
# documented in IResponse should follow ...
When an alternate response object implementation is returned by a view
@@ -804,8 +798,8 @@ startup time, as by their nature, instances of this class (and instances of
subclasses of the class) will natively provide IResponse. The adapter
registered for ``webob.Response`` simply returns the response object.
-Instead of using :meth:`pyramid.config.Configurator.add_response_adapter`,
-you can use the :class:`pyramid.response.response_adapter` decorator:
+Instead of using :meth:`pyramid.config.Configurator.add_response_adapter`, you
+can use the :class:`pyramid.response.response_adapter` decorator:
.. code-block:: python
:linenos:
@@ -841,31 +835,29 @@ callables by employing a :term:`view mapper`.
A view mapper is an object that accepts a set of keyword arguments and which
returns a callable. The returned callable is called with the :term:`view
-callable` object. The returned callable should itself return another
-callable which can be called with the "internal calling protocol" ``(context,
+callable` object. The returned callable should itself return another callable
+which can be called with the "internal calling protocol" ``(context,
request)``.
You can use a view mapper in a number of ways:
-- by setting a ``__view_mapper__`` attribute (which is the view mapper
- object) on the view callable itself
+- by setting a ``__view_mapper__`` attribute (which is the view mapper object)
+ on the view callable itself
-- by passing the mapper object to
- :meth:`pyramid.config.Configurator.add_view` (or its declarative/decorator
- equivalents) as the ``mapper`` argument.
+- by passing the mapper object to :meth:`pyramid.config.Configurator.add_view`
+ (or its declarative and decorator equivalents) as the ``mapper`` argument
-- by registering a *default* view mapper.
+- by registering a *default* view mapper
Here's an example of a view mapper that emulates (somewhat) a Pylons
"controller". The mapper is initialized with some keyword arguments. Its
``__call__`` method accepts the view object (which will be a class). It uses
-the ``attr`` keyword argument it is passed to determine which attribute
-should be used as an action method. The wrapper method it returns accepts
-``(context, request)`` and returns the result of calling the action method
-with keyword arguments implied by the :term:`matchdict` after popping the
-``action`` out of it. This somewhat emulates the Pylons style of calling
-action methods with routing parameters pulled out of the route matching dict
-as keyword arguments.
+the ``attr`` keyword argument it is passed to determine which attribute should
+be used as an action method. The wrapper method it returns accepts ``(context,
+request)`` and returns the result of calling the action method with keyword
+arguments implied by the :term:`matchdict` after popping the ``action`` out of
+it. This somewhat emulates the Pylons style of calling action methods with
+routing parameters pulled out of the route matching dict as keyword arguments.
.. code-block:: python
:linenos:
@@ -917,8 +909,8 @@ The :meth:`pyramid.config.Configurator.set_view_mapper` method can be used to
set a *default* view mapper (overriding the superdefault view mapper used by
Pyramid itself).
-A *single* view registration can use a view mapper by passing the mapper as
-the ``mapper`` argument to :meth:`~pyramid.config.Configurator.add_view`.
+A *single* view registration can use a view mapper by passing the mapper as the
+``mapper`` argument to :meth:`~pyramid.config.Configurator.add_view`.
.. index::
single: configuration decorator
@@ -928,14 +920,14 @@ the ``mapper`` argument to :meth:`~pyramid.config.Configurator.add_view`.
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`.
+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`.
+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"
@@ -945,8 +937,7 @@ 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:
+However, using :term:`Venusian`, the decorator could be written as follows:
.. code-block:: python
:linenos:
@@ -968,18 +959,17 @@ follows:
venusian.attach(wrapped, self.register)
return wrapped
-This decorator could then be used to register functions throughout
-your code:
+This decorator could then be used to register functions throughout your code:
.. code-block:: python
:linenos:
@registerFunction('/some/path')
def my_function():
- do_stuff()
+ do_stuff()
-However, the utility would only be looked up when a :term:`scan` was
-performed, enabling you to set up the utility in advance:
+However, the utility would only be looked up when a :term:`scan` was performed,
+enabling you to set up the utility in advance:
.. code-block:: python
:linenos:
@@ -994,10 +984,10 @@ performed, enabling you to set up the utility in advance:
class UtilityImplementation:
def __init__(self):
- self.registrations = {}
+ self.registrations = {}
def register(self, path, callable_):
- self.registrations[path] = callable_
+ self.registrations[path] = callable_
if __name__ == '__main__':
config = Configurator()
@@ -1021,27 +1011,27 @@ Registering Tweens
A :term:`tween` (a contraction of the word "between") is a bit of code that
sits between the Pyramid router's main request handling function and the
upstream WSGI component that uses :app:`Pyramid` as its "app". This is a
-feature that may be used by Pyramid framework extensions, to provide, for
+feature that may be used by Pyramid framework extensions to provide, for
example, Pyramid-specific view timing support bookkeeping code that examines
exceptions before they are returned to the upstream WSGI application. Tweens
-behave a bit like :term:`WSGI` :term:`middleware` but they have the benefit of
+behave a bit like :term:`WSGI` :term:`middleware`, but they have the benefit of
running in a context in which they have access to the Pyramid :term:`request`,
-:term:`response` and :term:`application registry` as well as the Pyramid
+:term:`response`, and :term:`application registry`, as well as the Pyramid
rendering machinery.
Creating a Tween
~~~~~~~~~~~~~~~~
-To create a tween, you must write a "tween factory". A tween factory
-must be a globally importable callable which accepts two arguments:
-``handler`` and ``registry``. ``handler`` will be either the main
-Pyramid request handling function or another tween. ``registry`` will be the
-Pyramid :term:`application registry` represented by this Configurator. A
-tween factory must return the tween (a callable object) when it is called.
+To create a tween, you must write a "tween factory". A tween factory must be a
+globally importable callable which accepts two arguments: ``handler`` and
+``registry``. ``handler`` will be either the main Pyramid request handling
+function or another tween. ``registry`` will be the Pyramid :term:`application
+registry` represented by this Configurator. A tween factory must return the
+tween (a callable object) when it is called.
A tween is called with a single argument, ``request``, which is the
-:term:`request` created by Pyramid's router when it receives a WSGI request.
-A tween should return a :term:`response`, usually the one generated by the
+:term:`request` created by Pyramid's router when it receives a WSGI request. A
+tween should return a :term:`response`, usually the one generated by the
downstream Pyramid application.
You can write the tween factory as a simple closure-returning function:
@@ -1089,14 +1079,14 @@ method:
return response
-You should avoid mutating any state on the tween instance. The tween is
-invoked once per request and any shared mutable state needs to be carefully
-handled to avoid any race conditions.
+You should avoid mutating any state on the tween instance. The tween is invoked
+once per request and any shared mutable state needs to be carefully handled to
+avoid any race conditions.
The closure style performs slightly better and enables you to conditionally
omit the tween from the request processing pipeline (see the following timing
tween example), whereas the class style makes it easier to have shared mutable
-state, and it allows subclassing.
+state and allows subclassing.
Here's a complete example of a tween that logs the time spent processing each
request:
@@ -1131,13 +1121,12 @@ request:
In the above example, the tween factory defines a ``timing_tween`` tween and
returns it if ``asbool(registry.settings.get('do_timing'))`` is true. It
-otherwise simply returns the handler it was given. The ``registry.settings``
-attribute is a handle to the deployment settings provided by the user
-(usually in an ``.ini`` file). In this case, if the user has defined a
-``do_timing`` setting, and that setting is ``True``, the user has said she
-wants to do timing, so the tween factory returns the timing tween; it
-otherwise just returns the handler it has been provided, preventing any
-timing.
+otherwise simply returns the handler which it was given. The
+``registry.settings`` attribute is a handle to the deployment settings provided
+by the user (usually in an ``.ini`` file). In this case, if the user has
+defined a ``do_timing`` setting and that setting is ``True``, the user has said
+they want to do timing, so the tween factory returns the timing tween; it
+otherwise just returns the handler it has been provided, preventing any timing.
The example timing tween simply records the start time, calls the downstream
handler, logs the number of seconds consumed by the downstream handler, and
@@ -1163,29 +1152,28 @@ Pyramid application:
Note that you must use a :term:`dotted Python name` as the first argument to
:meth:`pyramid.config.Configurator.add_tween`; this must point at a tween
factory. You cannot pass the tween factory object itself to the method: it
-must be :term:`dotted Python name` that points to a globally importable
-object. In the above example, we assume that a ``timing_tween_factory``
-tween factory was defined in a module named ``myapp.tweens``, so the tween
-factory is importable as ``myapp.tweens.timing_tween_factory``.
-
-When you use :meth:`pyramid.config.Configurator.add_tween`, you're
-instructing the system to use your tween factory at startup time unless the
-user has provided an explicit tween list in his configuration. This is
-what's meant by an "implicit" tween. A user can always elect to supply an
-explicit tween list, reordering or disincluding implicitly added tweens. See
+must be :term:`dotted Python name` that points to a globally importable object.
+In the above example, we assume that a ``timing_tween_factory`` tween factory
+was defined in a module named ``myapp.tweens``, so the tween factory is
+importable as ``myapp.tweens.timing_tween_factory``.
+
+When you use :meth:`pyramid.config.Configurator.add_tween`, you're instructing
+the system to use your tween factory at startup time unless the user has
+provided an explicit tween list in their configuration. This is what's meant
+by an "implicit" tween. A user can always elect to supply an explicit tween
+list, reordering or disincluding implicitly added tweens. See
:ref:`explicit_tween_ordering` for more information about explicit tween
ordering.
-If more than one call to :meth:`pyramid.config.Configurator.add_tween` is
-made within a single application configuration, the tweens will be chained
-together at application startup time. The *first* tween factory added via
-``add_tween`` will be called with the Pyramid exception view tween factory as
-its ``handler`` argument, then the tween factory added directly after that
-one will be called with the result of the first tween factory as its
-``handler`` argument, and so on, ad infinitum until all tween factories have
-been called. The Pyramid router will use the outermost tween produced by this
-chain (the tween generated by the very last tween factory added) as its
-request handler function. For example:
+If more than one call to :meth:`pyramid.config.Configurator.add_tween` is made
+within a single application configuration, the tweens will be chained together
+at application startup time. The *first* tween factory added via ``add_tween``
+will be called with the Pyramid exception view tween factory as its ``handler``
+argument, then the tween factory added directly after that one will be called
+with the result of the first tween factory as its ``handler`` argument, and so
+on, ad infinitum until all tween factories have been called. The Pyramid router
+will use the outermost tween produced by this chain (the tween generated by the
+very last tween factory added) as its request handler function. For example:
.. code-block:: python
:linenos:
@@ -1196,8 +1184,7 @@ request handler function. For example:
config.add_tween('myapp.tween_factory1')
config.add_tween('myapp.tween_factory2')
-The above example will generate an implicit tween chain that looks like
-this::
+The above example will generate an implicit tween chain that looks like this::
INGRESS (implicit)
myapp.tween_factory2
@@ -1211,37 +1198,36 @@ Suggesting Implicit Tween Ordering
By default, as described above, the ordering of the chain is controlled
entirely by the relative ordering of calls to
:meth:`pyramid.config.Configurator.add_tween`. However, the caller of
-add_tween can provide an optional hint that can influence the implicit tween
-chain ordering by supplying ``under`` or ``over`` (or both) arguments to
-:meth:`~pyramid.config.Configurator.add_tween`. These hints are only
-used when an explicit tween ordering is not used. See
-:ref:`explicit_tween_ordering` for a description of how to set an explicit
-tween ordering.
+``add_tween`` can provide an optional hint that can influence the implicit
+tween chain ordering by supplying ``under`` or ``over`` (or both) arguments to
+:meth:`~pyramid.config.Configurator.add_tween`. These hints are only used when
+an explicit tween ordering is not used. See :ref:`explicit_tween_ordering` for
+a description of how to set an explicit tween ordering.
Allowable values for ``under`` or ``over`` (or both) are:
-- ``None`` (the default).
+- ``None`` (the default),
-- A :term:`dotted Python name` to a tween factory: a string representing the
- predicted dotted name of a tween factory added in a call to ``add_tween``
- in the same configuration session.
+- a :term:`dotted Python name` to a tween factory: a string representing the
+ predicted dotted name of a tween factory added in a call to ``add_tween`` in
+ the same configuration session,
-- One of the constants :attr:`pyramid.tweens.MAIN`,
- :attr:`pyramid.tweens.INGRESS`, or :attr:`pyramid.tweens.EXCVIEW`.
+- one of the constants :attr:`pyramid.tweens.MAIN`,
+ :attr:`pyramid.tweens.INGRESS`, or :attr:`pyramid.tweens.EXCVIEW`, or
-- An iterable of any combination of the above. This allows the user to specify
+- an iterable of any combination of the above. This allows the user to specify
fallbacks if the desired tween is not included, as well as compatibility
with multiple other tweens.
-Effectively, ``over`` means "closer to the request ingress than" and
-``under`` means "closer to the main Pyramid application than".
-You can think of an onion with outer layers over the inner layers,
-the application being under all the layers at the center.
+Effectively, ``over`` means "closer to the request ingress than" and ``under``
+means "closer to the main Pyramid application than". You can think of an onion
+with outer layers over the inner layers, the application being under all the
+layers at the center.
For example, the following call to
-:meth:`~pyramid.config.Configurator.add_tween` will attempt to place the
-tween factory represented by ``myapp.tween_factory`` directly 'above' (in
-``ptweens`` order) the main Pyramid request handler.
+:meth:`~pyramid.config.Configurator.add_tween` will attempt to place the tween
+factory represented by ``myapp.tween_factory`` directly "above" (in ``ptweens``
+order) the main Pyramid request handler.
.. code-block:: python
:linenos:
@@ -1250,8 +1236,7 @@ tween factory represented by ``myapp.tween_factory`` directly 'above' (in
config.add_tween('myapp.tween_factory', over=pyramid.tweens.MAIN)
-The above example will generate an implicit tween chain that looks like
-this::
+The above example will generate an implicit tween chain that looks like this::
INGRESS (implicit)
pyramid.tweens.excview_tween_factory (implicit)
@@ -1259,9 +1244,8 @@ this::
MAIN (implicit)
Likewise, calling the following call to
-:meth:`~pyramid.config.Configurator.add_tween` will attempt to place this
-tween factory 'above' the main handler but 'below' a separately added tween
-factory:
+:meth:`~pyramid.config.Configurator.add_tween` will attempt to place this tween
+factory "above" the main handler but "below" a separately added tween factory:
.. code-block:: python
:linenos:
@@ -1274,8 +1258,7 @@ factory:
over=pyramid.tweens.MAIN,
under='myapp.tween_factory1')
-The above example will generate an implicit tween chain that looks like
-this::
+The above example will generate an implicit tween chain that looks like this::
INGRESS (implicit)
pyramid.tweens.excview_tween_factory (implicit)
@@ -1288,28 +1271,28 @@ Specifying neither ``over`` nor ``under`` is equivalent to specifying
If all options for ``under`` (or ``over``) cannot be found in the current
configuration, it is an error. If some options are specified purely for
-compatibilty with other tweens, just add a fallback of MAIN or INGRESS.
-For example, ``under=('someothertween', 'someothertween2', INGRESS)``.
-This constraint will require the tween to be located under both the
-'someothertween' tween, the 'someothertween2' tween, and INGRESS. If any of
-these is not in the current configuration, this constraint will only organize
-itself based on the tweens that are present.
+compatibilty with other tweens, just add a fallback of ``MAIN`` or ``INGRESS``.
+For example, ``under=('someothertween', 'someothertween2', INGRESS)``. This
+constraint will require the tween to be located under the ``someothertween``
+tween, the ``someothertween2`` tween, and ``INGRESS``. If any of these is not
+in the current configuration, this constraint will only organize itself based
+on the tweens that are present.
.. _explicit_tween_ordering:
Explicit Tween Ordering
~~~~~~~~~~~~~~~~~~~~~~~
-Implicit tween ordering is obviously only best-effort. Pyramid will attempt
-to provide an implicit order of tweens as best it can using hints provided by
-calls to :meth:`~pyramid.config.Configurator.add_tween`, but because it's
-only best-effort, if very precise tween ordering is required, the only
-surefire way to get it is to use an explicit tween order. The deploying user
-can override the implicit tween inclusion and ordering implied by calls to
+Implicit tween ordering is obviously only best-effort. Pyramid will attempt to
+provide an implicit order of tweens as best it can using hints provided by
+calls to :meth:`~pyramid.config.Configurator.add_tween`. But because it's only
+best-effort, if very precise tween ordering is required, the only surefire way
+to get it is to use an explicit tween order. The deploying user can override
+the implicit tween inclusion and ordering implied by calls to
:meth:`~pyramid.config.Configurator.add_tween` entirely by using the
``pyramid.tweens`` settings value. When used, this settings value must be a
-list of Python dotted names which will override the ordering (and inclusion)
-of tween factories in the implicit tween chain. For example:
+list of Python dotted names which will override the ordering (and inclusion) of
+tween factories in the implicit tween chain. For example:
.. code-block:: ini
:linenos:
@@ -1327,19 +1310,19 @@ of tween factories in the implicit tween chain. For example:
In the above configuration, calls made during configuration to
:meth:`pyramid.config.Configurator.add_tween` are ignored, and the user is
telling the system to use the tween factories he has listed in the
-``pyramid.tweens`` configuration setting (each is a :term:`dotted Python
-name` which points to a tween factory) instead of any tween factories added
-via :meth:`pyramid.config.Configurator.add_tween`. The *first* tween factory
-in the ``pyramid.tweens`` list will be used as the producer of the effective
+``pyramid.tweens`` configuration setting (each is a :term:`dotted Python name`
+which points to a tween factory) instead of any tween factories added via
+:meth:`pyramid.config.Configurator.add_tween`. The *first* tween factory in
+the ``pyramid.tweens`` list will be used as the producer of the effective
:app:`Pyramid` request handling function; it will wrap the tween factory
-declared directly "below" it, ad infinitum. The "main" Pyramid request
-handler is implicit, and always "at the bottom".
+declared directly "below" it, ad infinitum. The "main" Pyramid request handler
+is implicit, and always "at the bottom".
.. note::
- Pyramid's own :term:`exception view` handling logic is implemented
- as a tween factory function: :func:`pyramid.tweens.excview_tween_factory`.
- If Pyramid exception view handling is desired, and tween factories are
+ Pyramid's own :term:`exception view` handling logic is implemented as a
+ tween factory function: :func:`pyramid.tweens.excview_tween_factory`. If
+ Pyramid exception view handling is desired, and tween factories are
specified via the ``pyramid.tweens`` configuration setting, the
:func:`pyramid.tweens.excview_tween_factory` function must be added to the
``pyramid.tweens`` configuration setting list explicitly. If it is not
@@ -1348,30 +1331,30 @@ handler is implicit, and always "at the bottom".
Tween Conflicts and Ordering Cycles
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-Pyramid will prevent the same tween factory from being added to the tween
-chain more than once using configuration conflict detection. If you wish to
-add the same tween factory more than once in a configuration, you should
-either: a) use a tween factory that is a separate globally importable
-instance object from the factory that it conflicts with b) use a function or
-class as a tween factory with the same logic as the other tween factory it
-conflicts with but with a different ``__name__`` attribute or c) call
+Pyramid will prevent the same tween factory from being added to the tween chain
+more than once using configuration conflict detection. If you wish to add the
+same tween factory more than once in a configuration, you should either: (a)
+use a tween factory that is a separate globally importable instance object from
+the factory that it conflicts with; (b) use a function or class as a tween
+factory with the same logic as the other tween factory it conflicts with, but
+with a different ``__name__`` attribute; or (c) call
:meth:`pyramid.config.Configurator.commit` between calls to
:meth:`pyramid.config.Configurator.add_tween`.
If a cycle is detected in implicit tween ordering when ``over`` and ``under``
-are used in any call to "add_tween", an exception will be raised at startup
+are used in any call to ``add_tween``, an exception will be raised at startup
time.
Displaying Tween Ordering
~~~~~~~~~~~~~~~~~~~~~~~~~
-The ``ptweens`` command-line utility can be used to report the current
-implict and explicit tween chains used by an application. See
+The ``ptweens`` command-line utility can be used to report the current implict
+and explicit tween chains used by an application. See
:ref:`displaying_tweens`.
.. _registering_thirdparty_predicates:
-Adding A Third Party View, Route, or Subscriber Predicate
+Adding a Third Party View, Route, or Subscriber Predicate
---------------------------------------------------------
.. versionadded:: 1.4
@@ -1381,10 +1364,10 @@ Adding A Third Party View, Route, or Subscriber Predicate
View and Route Predicates
~~~~~~~~~~~~~~~~~~~~~~~~~
-View and route predicates used during configuration allow you to narrow the
-set of circumstances under which a view or route will match. For example,
-the ``request_method`` view predicate can be used to ensure a view callable
-is only invoked when the request's method is ``POST``:
+View and route predicates used during configuration allow you to narrow the set
+of circumstances under which a view or route will match. For example, the
+``request_method`` view predicate can be used to ensure a view callable is only
+invoked when the request's method is ``POST``:
.. code-block:: python
@@ -1398,9 +1381,9 @@ Likewise, a similar predicate can be used as a *route* predicate:
config.add_route('name', '/foo', request_method='POST')
-Many other built-in predicates exists (``request_param``, and others). You
-can add third-party predicates to the list of available predicates by using
-one of :meth:`pyramid.config.Configurator.add_view_predicate` or
+Many other built-in predicates exists (``request_param``, and others). You can
+add third-party predicates to the list of available predicates by using one of
+:meth:`pyramid.config.Configurator.add_view_predicate` or
:meth:`pyramid.config.Configurator.add_route_predicate`. The former adds a
view predicate, the latter a route predicate.
@@ -1428,7 +1411,7 @@ the name, is a string representing the name that is expected to be passed to
The second argument is a view or route predicate factory, or a :term:`dotted
Python name` which refers to a view or route predicate factory. A view or
route predicate factory is most often a class with a constructor
-(``__init__``), a ``text`` method, a ``phash`` method and a ``__call__``
+(``__init__``), a ``text`` method, a ``phash`` method, and a ``__call__``
method. For example:
.. code-block:: python
@@ -1448,27 +1431,27 @@ method. For example:
The constructor of a predicate factory takes two arguments: ``val`` and
``config``. The ``val`` argument will be the argument passed to
-``view_config`` (or ``add_view``). In the example above, it will be the
-string ``File``. The second arg, ``config`` will be the Configurator
-instance at the time of configuration.
+``view_config`` (or ``add_view``). In the example above, it will be the string
+``File``. The second argument, ``config``, will be the Configurator instance
+at the time of configuration.
-The ``text`` method must return a string. It should be useful to describe
-the behavior of the predicate in error messages.
+The ``text`` method must return a string. It should be useful to describe the
+behavior of the predicate in error messages.
-The ``phash`` method must return a string or a sequence of strings. It's
-most often the same as ``text``, as long as ``text`` uniquely describes the
-predicate's name and the value passed to the constructor. If ``text`` is
-more general, or doesn't describe things that way, ``phash`` should return a
-string with the name and the value serialized. The result of ``phash`` is
-not seen in output anywhere, it just informs the uniqueness constraints for
-view configuration.
+The ``phash`` method must return a string or a sequence of strings. It's most
+often the same as ``text``, as long as ``text`` uniquely describes the
+predicate's name and the value passed to the constructor. If ``text`` is more
+general, or doesn't describe things that way, ``phash`` should return a string
+with the name and the value serialized. The result of ``phash`` is not seen in
+output anywhere, it just informs the uniqueness constraints for view
+configuration.
The ``__call__`` method of a predicate factory must accept a resource
-(``context``) and a request, and must return ``True`` or ``False``. It is
-the "meat" of the predicate.
+(``context``) and a request, and must return ``True`` or ``False``. It is the
+"meat" of the predicate.
-You can use the same predicate factory as both a view predicate and as a
-route predicate, but you'll need to call ``add_view_predicate`` and
+You can use the same predicate factory as both a view predicate and as a route
+predicate, but you'll need to call ``add_view_predicate`` and
``add_route_predicate`` separately with the same factory.
.. _subscriber_predicates:
@@ -1476,16 +1459,16 @@ route predicate, but you'll need to call ``add_view_predicate`` and
Subscriber Predicates
~~~~~~~~~~~~~~~~~~~~~
-Subscriber predicates work almost exactly like view and route predicates.
-They narrow the set of circumstances in which a subscriber will be called.
-There are several minor differences between a subscriber predicate and a
-view/route predicate:
+Subscriber predicates work almost exactly like view and route predicates. They
+narrow the set of circumstances in which a subscriber will be called. There are
+several minor differences between a subscriber predicate and a view or route
+predicate:
- There are no default subscriber predicates. You must register one to use
one.
-- The ``__call__`` method of a subscriber predicate accepts a single
- ``event`` object instead of a ``context`` and a ``request``.
+- The ``__call__`` method of a subscriber predicate accepts a single ``event``
+ object instead of a ``context`` and a ``request``.
- Not every subscriber predicate can be used with every event type. Some
subscriber predicates will assume a certain event type.
@@ -1519,8 +1502,8 @@ Once you've created a subscriber predicate, it may registered via
Once a subscriber predicate is registered, you can use it in a call to
:meth:`pyramid.config.Configurator.add_subscriber` or to
-:class:`pyramid.events.subscriber`. Here's an example of using the
-previously registered ``request_path_startswith`` predicate in a call to
+:class:`pyramid.events.subscriber`. Here's an example of using the previously
+registered ``request_path_startswith`` predicate in a call to
:meth:`~pyramid.config.Configurator.add_subscriber`:
.. code-block:: python
@@ -1533,7 +1516,7 @@ previously registered ``request_path_startswith`` predicate in a call to
# and at configuration time
- config.add_subscriber(yosubscriber, NewRequest,
+ config.add_subscriber(yosubscriber, NewRequest,
request_path_startswith='/add_yo')
Here's the same subscriber/predicate/event-type combination used via
@@ -1548,22 +1531,19 @@ Here's the same subscriber/predicate/event-type combination used via
def yosubscriber(event):
event.request.yo = 'YO!'
-In either of the above configurations, the ``yosubscriber`` callable will
-only be called if the request path starts with ``/add_yo``. Otherwise the
-event subscriber will not be called.
+In either of the above configurations, the ``yosubscriber`` callable will only
+be called if the request path starts with ``/add_yo``. Otherwise the event
+subscriber will not be called.
Note that the ``request_path_startswith`` subscriber you defined can be used
with events that have a ``request`` attribute, but not ones that do not. So,
for example, the predicate can be used with subscribers registered for
:class:`pyramid.events.NewRequest` and :class:`pyramid.events.ContextFound`
events, but it cannot be used with subscribers registered for
-:class:`pyramid.events.ApplicationCreated` because the latter type of event
-has no ``request`` attribute. The point being: unlike route and view
-predicates, not every type of subscriber predicate will necessarily be
-applicable for use in every subscriber registration. It is not the
-responsibility of the predicate author to make every predicate make sense for
-every event type; it is the responsibility of the predicate consumer to use
-predicates that make sense for a particular event type registration.
-
-
-
+:class:`pyramid.events.ApplicationCreated` because the latter type of event has
+no ``request`` attribute. The point being, unlike route and view predicates,
+not every type of subscriber predicate will necessarily be applicable for use
+in every subscriber registration. It is not the responsibility of the
+predicate author to make every predicate make sense for every event type; it is
+the responsibility of the predicate consumer to use predicates that make sense
+for a particular event type registration.
diff --git a/docs/narr/hybrid.rst b/docs/narr/hybrid.rst
index 1c324d22b..ff26d52ec 100644
--- a/docs/narr/hybrid.rst
+++ b/docs/narr/hybrid.rst
@@ -12,28 +12,26 @@ dispatch. However, to solve a limited set of problems, it's useful to use
.. warning::
Reasoning about the behavior of a "hybrid" URL dispatch + traversal
- application can be challenging. To successfully reason about using
- URL dispatch and traversal together, you need to understand URL
- pattern matching, root factories, and the :term:`traversal`
- algorithm, and the potential interactions between them. Therefore,
- we don't recommend creating an application that relies on hybrid
- behavior unless you must.
+ application can be challenging. To successfully reason about using URL
+ dispatch and traversal together, you need to understand URL pattern
+ matching, root factories, and the :term:`traversal` algorithm, and the
+ potential interactions between them. Therefore, we don't recommend creating
+ an application that relies on hybrid behavior unless you must.
A Review of Non-Hybrid Applications
-----------------------------------
-When used according to the tutorials in its documentation
-:app:`Pyramid` is a "dual-mode" framework: the tutorials explain
-how to create an application in terms of using either :term:`url
-dispatch` *or* :term:`traversal`. This chapter details how you might
-combine these two dispatch mechanisms, but we'll review how they work
-in isolation before trying to combine them.
+When used according to the tutorials in its documentation, :app:`Pyramid` is a
+"dual-mode" framework: the tutorials explain how to create an application in
+terms of using either :term:`URL dispatch` *or* :term:`traversal`. This
+chapter details how you might combine these two dispatch mechanisms, but we'll
+review how they work in isolation before trying to combine them.
URL Dispatch Only
~~~~~~~~~~~~~~~~~
-An application that uses :term:`url dispatch` exclusively to map URLs to code
-will often have statements like this within application startup
+An application that uses :term:`URL dispatch` exclusively to map URLs to code
+will often have statements like this within its application startup
configuration:
.. code-block:: python
@@ -48,11 +46,11 @@ configuration:
config.add_view('myproject.views.bazbuz', route_name='bazbuz')
Each :term:`route` corresponds to one or more view callables. Each view
-callable is associated with a route by passing a ``route_name`` parameter
-that matches its name during a call to
-:meth:`~pyramid.config.Configurator.add_view`. When a route is matched
-during a request, :term:`view lookup` is used to match the request to its
-associated view callable. The presence of calls to
+callable is associated with a route by passing a ``route_name`` parameter that
+matches its name during a call to
+:meth:`~pyramid.config.Configurator.add_view`. When a route is matched during
+a request, :term:`view lookup` is used to match the request to its associated
+view callable. The presence of calls to
:meth:`~pyramid.config.Configurator.add_route` signify that an application is
using URL dispatch.
@@ -72,12 +70,11 @@ declarations that look like this:
When the above configuration is applied to an application, the
``mypackage.views.foobar`` view callable above will be called when the URL
-``/foobar`` is visited. Likewise, the view ``mypackage.views.bazbuz`` will
-be called when the URL ``/bazbuz`` is visited.
+``/foobar`` is visited. Likewise, the view ``mypackage.views.bazbuz`` will be
+called when the URL ``/bazbuz`` is visited.
Typically, an application that uses traversal exclusively won't perform any
-calls to :meth:`pyramid.config.Configurator.add_route` in its startup
-code.
+calls to :meth:`pyramid.config.Configurator.add_route` in its startup code.
.. index::
single: hybrid applications
@@ -85,149 +82,139 @@ code.
Hybrid Applications
-------------------
-Either traversal or url dispatch alone can be used to create a
-:app:`Pyramid` application. However, it is also possible to
-combine the concepts of traversal and url dispatch when building an
-application: the result is a hybrid application. In a hybrid
-application, traversal is performed *after* a particular route has
-matched.
-
-A hybrid application is a lot more like a "pure" traversal-based
-application than it is like a "pure" URL-dispatch based application.
-But unlike in a "pure" traversal-based application, in a hybrid
-application, :term:`traversal` is performed during a request after a
-route has already matched. This means that the URL pattern that
-represents the ``pattern`` argument of a route must match the
-``PATH_INFO`` of a request, and after the route pattern has matched,
-most of the "normal" rules of traversal with respect to :term:`resource
-location` and :term:`view lookup` apply.
+Either traversal or URL dispatch alone can be used to create a :app:`Pyramid`
+application. However, it is also possible to combine the concepts of traversal
+and URL dispatch when building an application, the result of which is a hybrid
+application. In a hybrid application, traversal is performed *after* a
+particular route has matched.
+
+A hybrid application is a lot more like a "pure" traversal-based application
+than it is like a "pure" URL-dispatch based application. But unlike in a "pure"
+traversal-based application, in a hybrid application :term:`traversal` is
+performed during a request after a route has already matched. This means that
+the URL pattern that represents the ``pattern`` argument of a route must match
+the ``PATH_INFO`` of a request, and after the route pattern has matched, most
+of the "normal" rules of traversal with respect to :term:`resource location`
+and :term:`view lookup` apply.
There are only four real differences between a purely traversal-based
application and a hybrid application:
-- In a purely traversal based application, no routes are defined; in a
- hybrid application, at least one route will be defined.
+- In a purely traversal-based application, no routes are defined. In a hybrid
+ application, at least one route will be defined.
-- In a purely traversal based application, the root object used is
- global, implied by the :term:`root factory` provided at startup
- time; in a hybrid application, the :term:`root` object at which
- traversal begins may be varied on a per-route basis.
+- In a purely traversal-based application, the root object used is global,
+ implied by the :term:`root factory` provided at startup time. In a hybrid
+ application, the :term:`root` object at which traversal begins may be varied
+ on a per-route basis.
-- In a purely traversal-based application, the ``PATH_INFO`` of the
- underlying :term:`WSGI` environment is used wholesale as a traversal
- path; in a hybrid application, the traversal path is not the entire
- ``PATH_INFO`` string, but a portion of the URL determined by a
- matching pattern in the matched route configuration's pattern.
+- In a purely traversal-based application, the ``PATH_INFO`` of the underlying
+ :term:`WSGI` environment is used wholesale as a traversal path. In a hybrid
+ application, the traversal path is not the entire ``PATH_INFO`` string, but a
+ portion of the URL determined by a matching pattern in the matched route
+ configuration's pattern.
-- In a purely traversal based application, view configurations which
- do not mention a ``route_name`` argument are considered during
- :term:`view lookup`; in a hybrid application, when a route is
- matched, only view configurations which mention that route's name as
- a ``route_name`` are considered during :term:`view lookup`.
+- In a purely traversal-based application, view configurations which do not
+ mention a ``route_name`` argument are considered during :term:`view lookup`.
+ In a hybrid application, when a route is matched, only view configurations
+ which mention that route's name as a ``route_name`` are considered during
+ :term:`view lookup`.
-More generally, a hybrid application *is* a traversal-based
-application except:
+More generally, a hybrid application *is* a traversal-based application except:
-- the traversal *root* is chosen based on the route configuration of
- the route that matched instead of from the ``root_factory`` supplied
- during application startup configuration.
+- the traversal *root* is chosen based on the route configuration of the route
+ that matched, instead of from the ``root_factory`` supplied during
+ application startup configuration.
-- the traversal *path* is chosen based on the route configuration of
- the route that matched rather than from the ``PATH_INFO`` of a
- request.
+- the traversal *path* is chosen based on the route configuration of the route
+ that matched, rather than from the ``PATH_INFO`` of a request.
-- the set of views that may be chosen during :term:`view lookup` when
- a route matches are limited to those which specifically name a
- ``route_name`` in their configuration that is the same as the
- matched route's ``name``.
+- the set of views that may be chosen during :term:`view lookup` when a route
+ matches are limited to those which specifically name a ``route_name`` in
+ their configuration that is the same as the matched route's ``name``.
-To create a hybrid mode application, use a :term:`route configuration`
-that implies a particular :term:`root factory` and which also includes
-a ``pattern`` argument that contains a special dynamic part: either
-``*traverse`` or ``*subpath``.
+To create a hybrid mode application, use a :term:`route configuration` that
+implies a particular :term:`root factory` and which also includes a ``pattern``
+argument that contains a special dynamic part: either ``*traverse`` or
+``*subpath``.
The Root Object for a Route Match
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-A hybrid application implies that traversal is performed during a
-request after a route has matched. Traversal, by definition, must
-always begin at a root object. Therefore it's important to know
-*which* root object will be traversed after a route has matched.
+A hybrid application implies that traversal is performed during a request after
+a route has matched. Traversal, by definition, must always begin at a root
+object. Therefore it's important to know *which* root object will be traversed
+after a route has matched.
-Figuring out which :term:`root` object results from a particular route
-match is straightforward. When a route is matched:
+Figuring out which :term:`root` object results from a particular route match is
+straightforward. When a route is matched:
-- If the route's configuration has a ``factory`` argument which
- points to a :term:`root factory` callable, that callable will be
- called to generate a :term:`root` object.
+- If the route's configuration has a ``factory`` argument which points to a
+ :term:`root factory` callable, that callable will be called to generate a
+ :term:`root` object.
-- If the route's configuration does not have a ``factory``
- argument, the *global* :term:`root factory` will be called to
- generate a :term:`root` object. The global root factory is the
- callable implied by the ``root_factory`` argument passed to the
- :class:`~pyramid.config.Configurator` at application
- startup time.
+- If the route's configuration does not have a ``factory`` argument, the
+ *global* :term:`root factory` will be called to generate a :term:`root`
+ object. The global root factory is the callable implied by the
+ ``root_factory`` argument passed to the :class:`~pyramid.config.Configurator`
+ at application startup time.
- If a ``root_factory`` argument is not provided to the
- :class:`~pyramid.config.Configurator` at startup time, a
- *default* root factory is used. The default root factory is used to
- generate a root object.
+ :class:`~pyramid.config.Configurator` at startup time, a *default* root
+ factory is used. The default root factory is used to generate a root object.
.. note::
Root factories related to a route were explained previously within
- :ref:`route_factories`. Both the global root factory and default
- root factory were explained previously within
- :ref:`the_resource_tree`.
+ :ref:`route_factories`. Both the global root factory and default root
+ factory were explained previously within :ref:`the_resource_tree`.
.. index::
pair: hybrid applications; *traverse route pattern
.. _using_traverse_in_a_route_pattern:
-Using ``*traverse`` In a Route Pattern
+Using ``*traverse`` in a Route Pattern
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-A hybrid application most often implies the inclusion of a route
-configuration that contains the special token ``*traverse`` at the end
-of a route's pattern:
+A hybrid application most often implies the inclusion of a route configuration
+that contains the special token ``*traverse`` at the end of a route's pattern:
.. code-block:: python
:linenos:
config.add_route('home', '{foo}/{bar}/*traverse')
-A ``*traverse`` token at the end of the pattern in a route's
-configuration implies a "remainder" *capture* value. When it is used,
-it will match the remainder of the path segments of the URL. This
-remainder becomes the path used to perform traversal.
+A ``*traverse`` token at the end of the pattern in a route's configuration
+implies a "remainder" *capture* value. When it is used, it will match the
+remainder of the path segments of the URL. This remainder becomes the path
+used to perform traversal.
.. note::
- The ``*remainder`` route pattern syntax is explained in more
- detail within :ref:`route_pattern_syntax`.
+ The ``*remainder`` route pattern syntax is explained in more detail within
+ :ref:`route_pattern_syntax`.
A hybrid mode application relies more heavily on :term:`traversal` to do
:term:`resource location` and :term:`view lookup` than most examples indicate
within :ref:`urldispatch_chapter`.
-Because the pattern of the above route ends with ``*traverse``, when this
-route configuration is matched during a request, :app:`Pyramid` will attempt
-to use :term:`traversal` against the :term:`root` object implied by the
-:term:`root factory` that is implied by the route's configuration. Since no
+Because the pattern of the above route ends with ``*traverse``, when this route
+configuration is matched during a request, :app:`Pyramid` will attempt to use
+:term:`traversal` against the :term:`root` object implied by the :term:`root
+factory` that is implied by the route's configuration. Since no
``root_factory`` argument is explicitly specified for this route, this will
-either be the *global* root factory for the application, or the *default*
-root factory. Once :term:`traversal` has found a :term:`context` resource,
+either be the *global* root factory for the application, or the *default* root
+factory. Once :term:`traversal` has found a :term:`context` resource,
:term:`view lookup` will be invoked in almost exactly the same way it would
have been invoked in a "pure" traversal-based application.
-Let's assume there is no *global* :term:`root factory` configured in
-this application. The *default* :term:`root factory` cannot be traversed:
-it has no useful ``__getitem__`` method. So we'll need to associate
-this route configuration with a custom root factory in order to
-create a useful hybrid application. To that end, let's imagine that
-we've created a root factory that looks like so in a module named
-``routes.py``:
+Let's assume there is no *global* :term:`root factory` configured in this
+application. The *default* :term:`root factory` cannot be traversed; it has no
+useful ``__getitem__`` method. So we'll need to associate this route
+configuration with a custom root factory in order to create a useful hybrid
+application. To that end, let's imagine that we've created a root factory that
+looks like so in a module named ``routes.py``:
.. code-block:: python
:linenos:
@@ -246,7 +233,7 @@ we've created a root factory that looks like so in a module named
def root_factory(request):
return root
-Above, we've defined a (bogus) resource tree that can be traversed, and a
+Above we've defined a (bogus) resource tree that can be traversed, and a
``root_factory`` function that can be used as part of a particular route
configuration statement:
@@ -256,8 +243,8 @@ configuration statement:
config.add_route('home', '{foo}/{bar}/*traverse',
factory='mypackage.routes.root_factory')
-The ``factory`` above points at the function we've defined. It will return
-an instance of the ``Resource`` class as a root object whenever this route is
+The ``factory`` above points at the function we've defined. It will return an
+instance of the ``Resource`` class as a root object whenever this route is
matched. Instances of the ``Resource`` class can be used for tree traversal
because they have a ``__getitem__`` method that does something nominally
useful. Since traversal uses ``__getitem__`` to walk the resources of a
@@ -266,39 +253,37 @@ statement is a reasonable thing to do.
.. note::
- We could have also used our ``root_factory`` function as the
- ``root_factory`` argument of the
- :class:`~pyramid.config.Configurator` constructor, instead
- of associating it with a particular route inside the route's
- configuration. Every hybrid route configuration that is matched but
- which does *not* name a ``factory`` attribute will use the use
- global ``root_factory`` function to generate a root object.
+ We could have also used our ``root_factory`` function as the ``root_factory``
+ argument of the :class:`~pyramid.config.Configurator` constructor, instead of
+ associating it with a particular route inside the route's configuration.
+ Every hybrid route configuration that is matched, but which does *not* name a
+ ``factory`` attribute, will use the global ``root_factory`` function to
+ generate a root object.
-When the route configuration named ``home`` above is matched during a
-request, the matchdict generated will be based on its pattern:
+When the route configuration named ``home`` above is matched during a request,
+the matchdict generated will be based on its pattern:
``{foo}/{bar}/*traverse``. The "capture value" implied by the ``*traverse``
element in the pattern will be used to traverse the resource tree in order to
find a context resource, starting from the root object returned from the root
factory. In the above example, the :term:`root` object found will be the
instance named ``root`` in ``routes.py``.
-If the URL that matched a route with the pattern ``{foo}/{bar}/*traverse``,
-is ``http://example.com/one/two/a/b/c``, the traversal path used
-against the root object will be ``a/b/c``. As a result,
-:app:`Pyramid` will attempt to traverse through the edges ``'a'``,
-``'b'``, and ``'c'``, beginning at the root object.
+If the URL that matched a route with the pattern ``{foo}/{bar}/*traverse`` is
+``http://example.com/one/two/a/b/c``, the traversal path used against the root
+object will be ``a/b/c``. As a result, :app:`Pyramid` will attempt to traverse
+through the edges ``'a'``, ``'b'``, and ``'c'``, beginning at the root object.
-In our above example, this particular set of traversal steps will mean that
-the :term:`context` resource of the view would be the ``Resource`` object
-we've named ``'c'`` in our bogus resource tree and the :term:`view name`
-resulting from traversal will be the empty string; if you need a refresher
-about why this outcome is presumed, see :ref:`traversal_algorithm`.
+In our above example, this particular set of traversal steps will mean that the
+:term:`context` resource of the view would be the ``Resource`` object we've
+named ``'c'`` in our bogus resource tree, and the :term:`view name` resulting
+from traversal will be the empty string. If you need a refresher about why
+this outcome is presumed, see :ref:`traversal_algorithm`.
-At this point, a suitable view callable will be found and invoked
-using :term:`view lookup` as described in :ref:`view_configuration`,
-but with a caveat: in order for view lookup to work, we need to define
-a view configuration that will match when :term:`view lookup` is
-invoked after a route matches:
+At this point, a suitable view callable will be found and invoked using
+:term:`view lookup` as described in :ref:`view_configuration`, but with a
+caveat: in order for view lookup to work, we need to define a view
+configuration that will match when :term:`view lookup` is invoked after a route
+matches:
.. code-block:: python
:linenos:
@@ -307,28 +292,28 @@ invoked after a route matches:
factory='mypackage.routes.root_factory')
config.add_view('mypackage.views.myview', route_name='home')
-Note that the above call to
-:meth:`~pyramid.config.Configurator.add_view` includes a ``route_name``
-argument. View configurations that include a ``route_name`` argument are
-meant to associate a particular view declaration with a route, using the
-route's name, in order to indicate that the view should *only be invoked when
-the route matches*.
+Note that the above call to :meth:`~pyramid.config.Configurator.add_view`
+includes a ``route_name`` argument. View configurations that include a
+``route_name`` argument are meant to associate a particular view declaration
+with a route, using the route's name, in order to indicate that the view should
+*only be invoked when the route matches*.
Calls to :meth:`~pyramid.config.Configurator.add_view` may pass a
``route_name`` attribute, which refers to the value of an existing route's
-``name`` argument. In the above example, the route name is ``home``,
-referring to the name of the route defined above it.
+``name`` argument. In the above example, the route name is ``home``, referring
+to the name of the route defined above it.
-The above ``mypackage.views.myview`` view callable will be invoked when:
+The above ``mypackage.views.myview`` view callable will be invoked when the
+following conditions are met:
-- the route named "home" is matched
+- The route named "home" is matched.
-- the :term:`view name` resulting from traversal is the empty string.
+- The :term:`view name` resulting from traversal is the empty string.
-- the :term:`context` resource is any object.
+- The :term:`context` resource is any object.
-It is also possible to declare alternate views that may be invoked
-when a hybrid route is matched:
+It is also possible to declare alternative views that may be invoked when a
+hybrid route is matched:
.. code-block:: python
:linenos:
@@ -340,37 +325,37 @@ when a hybrid route is matched:
name='another')
The ``add_view`` call for ``mypackage.views.another_view`` above names a
-different view and, more importantly, a different :term:`view name`. The
-above ``mypackage.views.another_view`` view will be invoked when:
+different view and, more importantly, a different :term:`view name`. The above
+``mypackage.views.another_view`` view will be invoked when the following
+conditions are met:
-- the route named "home" is matched
+- The route named "home" is matched.
-- the :term:`view name` resulting from traversal is ``another``.
+- The :term:`view name` resulting from traversal is ``another``.
-- the :term:`context` resource is any object.
+- The :term:`context` resource is any object.
For instance, if the URL ``http://example.com/one/two/a/another`` is provided
to an application that uses the previously mentioned resource tree, the
-``mypackage.views.another`` view callable will be called instead of the
-``mypackage.views.myview`` view callable because the :term:`view name` will
-be ``another`` instead of the empty string.
+``mypackage.views.another_view`` view callable will be called instead of the
+``mypackage.views.myview`` view callable because the :term:`view name` will be
+``another`` instead of the empty string.
More complicated matching can be composed. All arguments to *route*
-configuration statements and *view* configuration statements are
-supported in hybrid applications (such as :term:`predicate`
-arguments).
+configuration statements and *view* configuration statements are supported in
+hybrid applications (such as :term:`predicate` arguments).
-Using the ``traverse`` Argument In a Route Definition
+Using the ``traverse`` Argument in a Route Definition
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-Rather than using the ``*traverse`` remainder marker in a pattern, you
-can use the ``traverse`` argument to the
-:meth:`~pyramid.config.Configurator.add_route` method.
+Rather than using the ``*traverse`` remainder marker in a pattern, you can use
+the ``traverse`` argument to the :meth:`~pyramid.config.Configurator.add_route`
+method.
-When you use the ``*traverse`` remainder marker, the traversal path is
-limited to being the remainder segments of a request URL when a route
-matches. However, when you use the ``traverse`` argument or
-attribute, you have more control over how to compose a traversal path.
+When you use the ``*traverse`` remainder marker, the traversal path is limited
+to being the remainder segments of a request URL when a route matches.
+However, when you use the ``traverse`` argument or attribute, you have more
+control over how to compose a traversal path.
Here's a use of the ``traverse`` pattern in a call to
:meth:`~pyramid.config.Configurator.add_route`:
@@ -381,30 +366,27 @@ Here's a use of the ``traverse`` pattern in a call to
config.add_route('abc', '/articles/{article}/edit',
traverse='/{article}')
-The syntax of the ``traverse`` argument is the same as it is for
-``pattern``.
+The syntax of the ``traverse`` argument is the same as it is for ``pattern``.
-If, as above, the ``pattern`` provided is ``/articles/{article}/edit``,
-and the ``traverse`` argument provided is ``/{article}``, when a
-request comes in that causes the route to match in such a way that the
-``article`` match value is ``1`` (when the request URI is
-``/articles/1/edit``), the traversal path will be generated as ``/1``.
-This means that the root object's ``__getitem__`` will be called with
-the name ``1`` during the traversal phase. If the ``1`` object
-exists, it will become the :term:`context` of the request.
-The :ref:`traversal_chapter` chapter has more information about traversal.
+If, as above, the ``pattern`` provided is ``/articles/{article}/edit``, and the
+``traverse`` argument provided is ``/{article}``, when a request comes in that
+causes the route to match in such a way that the ``article`` match value is
+``1`` (when the request URI is ``/articles/1/edit``), the traversal path will
+be generated as ``/1``. This means that the root object's ``__getitem__`` will
+be called with the name ``1`` during the traversal phase. If the ``1`` object
+exists, it will become the :term:`context` of the request. The
+:ref:`traversal_chapter` chapter has more information about traversal.
-If the traversal path contains segment marker names which are not
-present in the pattern argument, a runtime error will occur. The
-``traverse`` pattern should not contain segment markers that do not
-exist in the ``path``.
+If the traversal path contains segment marker names which are not present in
+the pattern argument, a runtime error will occur. The ``traverse`` pattern
+should not contain segment markers that do not exist in the ``path``.
-Note that the ``traverse`` argument is ignored when attached to a
-route that has a ``*traverse`` remainder marker in its pattern.
+Note that the ``traverse`` argument is ignored when attached to a route that
+has a ``*traverse`` remainder marker in its pattern.
-Traversal will begin at the root object implied by this route (either
-the global root, or the object returned by the ``factory`` associated
-with this route).
+Traversal will begin at the root object implied by this route (either the
+global root, or the object returned by the ``factory`` associated with this
+route).
.. index::
pair: hybrid applications; global views
@@ -412,14 +394,13 @@ with this route).
Making Global Views Match
+++++++++++++++++++++++++
-By default, only view configurations that mention a ``route_name``
-will be found during view lookup when a route that has a ``*traverse``
-in its pattern matches. You can allow views without a ``route_name``
-attribute to match a route by adding the ``use_global_views`` flag to
-the route definition. For example, the ``myproject.views.bazbuz``
-view below will be found if the route named ``abc`` below is matched
-and the ``PATH_INFO`` is ``/abc/bazbuz``, even though the view
-configuration statement does not have the ``route_name="abc"``
+By default, only view configurations that mention a ``route_name`` will be
+found during view lookup when a route that has a ``*traverse`` in its pattern
+matches. You can allow views without a ``route_name`` attribute to match a
+route by adding the ``use_global_views`` flag to the route definition. For
+example, the ``myproject.views.bazbuz`` view below will be found if the route
+named ``abc`` below is matched and the ``PATH_INFO`` is ``/abc/bazbuz``, even
+though the view configuration statement does not have the ``route_name="abc"``
attribute.
.. code-block:: python
@@ -445,10 +426,10 @@ traversal. For instance, the :func:`pyramid.wsgi.wsgiapp2` decorator and the
from the request's subpath when its ``use_subpath`` argument is ``True``, so
it's useful to be able to influence this value.
-When ``*subpath`` exists in a pattern, no path is actually traversed,
-but the traversal algorithm will return a :term:`subpath` list implied
-by the capture value of ``*subpath``. You'll see this pattern most
-commonly in route declarations that look like this:
+When ``*subpath`` exists in a pattern, no path is actually traversed, but the
+traversal algorithm will return a :term:`subpath` list implied by the capture
+value of ``*subpath``. You'll see this pattern most commonly in route
+declarations that look like this:
.. code-block:: python
:linenos:
@@ -460,98 +441,13 @@ commonly in route declarations that look like this:
config.add_route('static', '/static/*subpath')
config.add_view(www, route_name='static')
-``mypackage.views.www`` is an instance of
-:class:`pyramid.static.static_view`. This effectively tells the static
-helper to traverse everything in the subpath as a filename.
-
-.. index::
- pair: hybrid applications; corner cases
-
-Corner Cases
-------------
-
-A number of corner case "gotchas" exist when using a hybrid
-application. We'll detail them here.
-
-Registering a Default View for a Route That Has a ``view`` Attribute
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-.. warning:: As of :app:`Pyramid` 1.1 this section is slated to be removed in
- a later documentation release because the ability to add views
- directly to the :term:`route configuration` by passing a ``view`` argument
- to ``add_route`` has been deprecated.
-
-It is an error to provide *both* a ``view`` argument to a :term:`route
-configuration` *and* a :term:`view configuration` which names a
-``route_name`` that has no ``name`` value or the empty ``name`` value. For
-example, this pair of declarations will generate a conflict error at startup
-time.
-
-.. code-block:: python
- :linenos:
-
- config.add_route('home', '{foo}/{bar}/*traverse',
- view='myproject.views.home')
- config.add_view('myproject.views.another', route_name='home')
-
-This is because the ``view`` argument to the
-:meth:`~pyramid.config.Configurator.add_route` above is an *implicit*
-default view when that route matches. ``add_route`` calls don't *need* to
-supply a view attribute. For example, this ``add_route`` call:
-
-.. code-block:: python
- :linenos:
-
- config.add_route('home', '{foo}/{bar}/*traverse',
- view='myproject.views.home')
+``mypackage.views.www`` is an instance of :class:`pyramid.static.static_view`.
+This effectively tells the static helper to traverse everything in the subpath
+as a filename.
-Can also be spelled like so:
-
-.. code-block:: python
- :linenos:
-
- config.add_route('home', '{foo}/{bar}/*traverse')
- config.add_view('myproject.views.home', route_name='home')
-
-The two spellings are logically equivalent. In fact, the former is just a
-syntactical shortcut for the latter.
-
-Binding Extra Views Against a Route Configuration that Doesn't Have a ``*traverse`` Element In Its Pattern
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-Here's another corner case that just makes no sense:
-
-.. code-block:: python
- :linenos:
-
- config.add_route('abc', '/abc', view='myproject.views.abc')
- config.add_view('myproject.views.bazbuz', name='bazbuz',
- route_name='abc')
-
-The above view declaration is useless, because it will never be matched when
-the route it references has matched. Only the view associated with the route
-itself (``myproject.views.abc``) will ever be invoked when the route matches,
-because the default view is always invoked when a route matches and when no
-post-match traversal is performed.
-
-To make the above view declaration useful, the special ``*traverse``
-token must end the route's pattern. For example:
-
-.. code-block:: python
- :linenos:
-
- config.add_route('abc', '/abc/*traverse', view='myproject.views.abc')
- config.add_view('myproject.views.bazbuz', name='bazbuz',
- route_name='abc')
-
-With the above configuration, the ``myproject.views.bazbuz`` view will
-be invoked when the request URI is ``/abc/bazbuz``, assuming there is
-no object contained by the root object with the key ``bazbuz``. A
-different request URI, such as ``/abc/foo/bar``, would invoke the
-default ``myproject.views.abc`` view.
.. index::
- pair: hybrid urls; generating
+ pair: hybrid URLs; generating
.. _generating_hybrid_urls:
@@ -560,16 +456,16 @@ Generating Hybrid URLs
.. versionadded:: 1.5
-The :meth:`pyramid.request.Request.resource_url` method and the
-:meth:`pyramid.request.Request.resource_path` method both accept optional
+The :meth:`pyramid.request.Request.resource_url` method and the
+:meth:`pyramid.request.Request.resource_path` method both accept optional
keyword arguments that make it easier to generate route-prefixed URLs that
-contain paths to traversal resources:``route_name``, ``route_kw``, and
+contain paths to traversal resources: ``route_name``, ``route_kw``, and
``route_remainder_name``.
Any route that has a pattern that contains a ``*remainder`` pattern (any
-stararg remainder pattern, such as ``*traverse`` or ``*subpath`` or ``*fred``)
-can be used as the target name for ``request.resource_url(..., route_name=)``
-and ``request.resource_path(..., route_name=)``.
+stararg remainder pattern, such as ``*traverse``, ``*subpath``, or ``*fred``)
+can be used as the target name for ``request.resource_url(..., route_name=)``
+and ``request.resource_path(..., route_name=)``.
For example, let's imagine you have a route defined in your Pyramid application
like so:
@@ -578,7 +474,7 @@ like so:
config.add_route('mysection', '/mysection*traverse')
-If you'd like to generate the URL ``http://example.com/mysection/a/``, you can
+If you'd like to generate the URL ``http://example.com/mysection/a/``, you can
use the following incantation, assuming that the variable ``a`` below points to
a resource that is a child of the root with a ``__name__`` of ``a``:
@@ -592,14 +488,14 @@ You can generate only the path portion ``/mysection/a/`` assuming the same:
request.resource_path(a, route_name='mysection')
-The path is virtual host aware, so if the ``X-Vhm-Root`` environ variable is
-present in the request, and it's set to ``/a``, the above call to
-``request.resource_url`` would generate ``http://example.com/mysection/``
-and the above call to ``request.resource_path`` would generate ``/mysection/``.
-See :ref:`virtual_root_support` for more information.
+The path is virtual host aware, so if the ``X-Vhm-Root`` environment variable
+is present in the request, and it's set to ``/a``, the above call to
+``request.resource_url`` would generate ``http://example.com/mysection/``, and
+the above call to ``request.resource_path`` would generate ``/mysection/``. See
+:ref:`virtual_root_support` for more information.
If the route you're trying to use needs simple dynamic part values to be filled
-in to succesfully generate the URL, you can pass these as the ``route_kw``
+in to succesfully generate the URL, you can pass these as the ``route_kw``
argument to ``resource_url`` and ``resource_path``. For example, assuming that
the route definition is like so:
@@ -613,15 +509,15 @@ You can pass ``route_kw`` in to fill in ``{id}`` above:
request.resource_url(a, route_name='mysection', route_kw={'id':'1'})
-If you pass ``route_kw`` but do not pass ``route_name``, ``route_kw`` will
-be ignored.
+If you pass ``route_kw`` but do not pass ``route_name``, ``route_kw`` will be
+ignored.
-By default this feature works by calling ``route_url`` under the hood,
-and passing the value of the resource path to that function as ``traverse``.
-If your route has a different ``*stararg`` remainder name (such as
-``*subpath``), you can tell ``resource_url`` or ``resource_path`` to use that
-instead of ``traverse`` by passing ``route_remainder_name``. For example,
-if you have the following route:
+By default this feature works by calling ``route_url`` under the hood, and
+passing the value of the resource path to that function as ``traverse``. If
+your route has a different ``*stararg`` remainder name (such as ``*subpath``),
+you can tell ``resource_url`` or ``resource_path`` to use that instead of
+``traverse`` by passing ``route_remainder_name``. For example, if you have the
+following route:
.. code-block:: python
@@ -631,10 +527,10 @@ You can fill in the ``*subpath`` value using ``resource_url`` by doing:
.. code-block:: python
- request.resource_path(a, route_name='mysection',
+ request.resource_path(a, route_name='mysection',
route_remainder_name='subpath')
-If you pass ``route_remainder_name`` but do not pass ``route_name``,
+If you pass ``route_remainder_name`` but do not pass ``route_name``,
``route_remainder_name`` will be ignored.
If you try to use ``resource_path`` or ``resource_url`` when the ``route_name``
@@ -642,12 +538,11 @@ argument points at a route that does not have a remainder stararg, an error
will not be raised, but the generated URL will not contain any remainder
information either.
-All other values that are normally passable to ``resource_path`` and
-``resource_url`` (such as ``query``, ``anchor``, ``host``, ``port``, and
+All other values that are normally passable to ``resource_path`` and
+``resource_url`` (such as ``query``, ``anchor``, ``host``, ``port``, and
positional elements) work as you might expect in this configuration.
Note that this feature is incompatible with the ``__resource_url__`` feature
(see :ref:`overriding_resource_url_generation`) implemented on resource
objects. Any ``__resource_url__`` supplied by your resource will be ignored
when you pass ``route_name``.
-
diff --git a/docs/narr/introspector.rst b/docs/narr/introspector.rst
index 8caba522c..98315ac9f 100644
--- a/docs/narr/introspector.rst
+++ b/docs/narr/introspector.rst
@@ -20,8 +20,7 @@ configuration settings.
Using the Introspector
----------------------
-Here's an example of using Pyramid's introspector from within a view
-callable:
+Here's an example of using Pyramid's introspector from within a view callable:
.. code-block:: python
:linenos:
@@ -36,10 +35,10 @@ callable:
route_intr = introspector.get('routes', route_name)
return Response(str(route_intr['pattern']))
-This view will return a response that contains the "pattern" argument
-provided to the ``add_route`` method of the route which matched when the view
-was called. It uses the :meth:`pyramid.interfaces.IIntrospector.get` method
-to return an introspectable in the category ``routes`` with a
+This view will return a response that contains the "pattern" argument provided
+to the ``add_route`` method of the route which matched when the view was
+called. It uses the :meth:`pyramid.interfaces.IIntrospector.get` method to
+return an introspectable in the category ``routes`` with a
:term:`discriminator` equal to the matched route name. It then uses the
returned introspectable to obtain a "pattern" value.
@@ -56,9 +55,9 @@ can be used to query for introspectables.
Introspectable Objects
----------------------
-Introspectable objects are returned from query methods of an introspector.
-Each introspectable object implements the attributes and methods
-documented at :class:`pyramid.interfaces.IIntrospectable`.
+Introspectable objects are returned from query methods of an introspector. Each
+introspectable object implements the attributes and methods documented at
+:class:`pyramid.interfaces.IIntrospectable`.
The important attributes shared by all introspectables are the following:
@@ -74,12 +73,12 @@ The important attributes shared by all introspectables are the following:
``discriminator``
- A hashable object representing the unique value of this introspectable
- within its category.
+ A hashable object representing the unique value of this introspectable within
+ its category.
``discriminator_hash``
- The integer hash of the discriminator (useful for using in HTML links).
+ The integer hash of the discriminator (useful in HTML links).
``type_name``
@@ -90,8 +89,8 @@ The important attributes shared by all introspectables are the following:
``action_info``
- An object describing the directive call site which caused this
- introspectable to be registered; contains attributes described in
+ An object describing the directive call site which caused this introspectable
+ to be registered. It contains attributes described in
:class:`pyramid.interfaces.IActionInfo`.
Besides having the attributes described above, an introspectable is a
@@ -116,7 +115,7 @@ introspectables in categories not described here.
Each introspectable in the ``subscribers`` category represents a call to
:meth:`pyramid.config.Configurator.add_subscriber` (or the decorator
- equivalent); each will have the following data.
+ equivalent). Each will have the following data.
``subscriber``
@@ -137,7 +136,7 @@ introspectables in categories not described here.
``predicates``
The predicate objects created as the result of passing predicate arguments
- to ``add_subscriber``
+ to ``add_subscriber``.
``derived_predicates``
@@ -149,7 +148,7 @@ introspectables in categories not described here.
Each introspectable in the ``response adapters`` category represents a call
to :meth:`pyramid.config.Configurator.add_response_adapter` (or a decorator
- equivalent); each will have the following data.
+ equivalent). Each will have the following data.
``adapter``
@@ -158,15 +157,14 @@ introspectables in categories not described here.
``type``
- The resolved ``type_or_iface`` argument passed to
- ``add_response_adapter``.
+ The resolved ``type_or_iface`` argument passed to ``add_response_adapter``.
``root factories``
Each introspectable in the ``root factories`` category represents a call to
:meth:`pyramid.config.Configurator.set_root_factory` (or the Configurator
constructor equivalent) *or* a ``factory`` argument passed to
- :meth:`pyramid.config.Configurator.add_route`; each will have the following
+ :meth:`pyramid.config.Configurator.add_route`. Each will have the following
data.
``factory``
@@ -184,7 +182,7 @@ introspectables in categories not described here.
Only one introspectable will exist in the ``session factory`` category. It
represents a call to :meth:`pyramid.config.Configurator.set_session_factory`
- (or the Configurator constructor equivalent); it will have the following
+ (or the Configurator constructor equivalent). It will have the following
data.
``factory``
@@ -196,7 +194,7 @@ introspectables in categories not described here.
Only one introspectable will exist in the ``request factory`` category. It
represents a call to :meth:`pyramid.config.Configurator.set_request_factory`
- (or the Configurator constructor equivalent); it will have the following
+ (or the Configurator constructor equivalent). It will have the following
data.
``factory``
@@ -206,10 +204,10 @@ introspectables in categories not described here.
``locale negotiator``
- Only one introspectable will exist in the ``locale negotiator`` category.
- It represents a call to
+ Only one introspectable will exist in the ``locale negotiator`` category. It
+ represents a call to
:meth:`pyramid.config.Configurator.set_locale_negotiator` (or the
- Configurator constructor equivalent); it will have the following data.
+ Configurator constructor equivalent). It will have the following data.
``negotiator``
@@ -218,9 +216,9 @@ introspectables in categories not described here.
``renderer factories``
- Each introspectable in the ``renderer factories`` category represents a
- call to :meth:`pyramid.config.Configurator.add_renderer` (or the
- Configurator constructor equivalent); each will have the following data.
+ Each introspectable in the ``renderer factories`` category represents a call
+ to :meth:`pyramid.config.Configurator.add_renderer` (or the Configurator
+ constructor equivalent). Each will have the following data.
``name``
@@ -229,13 +227,12 @@ introspectables in categories not described here.
``factory``
- The factory object (the resolved ``factory`` argument to
- ``add_renderer``).
+ The factory object (the resolved ``factory`` argument to ``add_renderer``).
``routes``
Each introspectable in the ``routes`` category represents a call to
- :meth:`pyramid.config.Configurator.add_route`; each will have the following
+ :meth:`pyramid.config.Configurator.add_route`. Each will have the following
data.
``name``
@@ -310,7 +307,7 @@ introspectables in categories not described here.
There will be one and only one introspectable in the ``authentication
policy`` category. It represents a call to the
:meth:`pyramid.config.Configurator.set_authentication_policy` method (or
- its Configurator constructor equivalent); it will have the following data.
+ its Configurator constructor equivalent). It will have the following data.
``policy``
@@ -319,10 +316,10 @@ introspectables in categories not described here.
``authorization policy``
- There will be one and only one introspectable in the ``authorization
- policy`` category. It represents a call to the
+ There will be one and only one introspectable in the ``authorization policy``
+ category. It represents a call to the
:meth:`pyramid.config.Configurator.set_authorization_policy` method (or its
- Configurator constructor equivalent); it will have the following data.
+ Configurator constructor equivalent). It will have the following data.
``policy``
@@ -334,7 +331,7 @@ introspectables in categories not described here.
There will be one and only one introspectable in the ``default permission``
category. It represents a call to the
:meth:`pyramid.config.Configurator.set_default_permission` method (or its
- Configurator constructor equivalent); it will have the following data.
+ Configurator constructor equivalent). It will have the following data.
``value``
@@ -343,7 +340,7 @@ introspectables in categories not described here.
``views``
Each introspectable in the ``views`` category represents a call to
- :meth:`pyramid.config.Configurator.add_view`; each will have the following
+ :meth:`pyramid.config.Configurator.add_view`. Each will have the following
data.
``name``
@@ -423,8 +420,8 @@ introspectables in categories not described here.
Each introspectable in the ``permissions`` category represents a call to
:meth:`pyramid.config.Configurator.add_view` that has an explicit
- ``permission`` argument to *or* a call to
- :meth:`pyramid.config.Configurator.set_default_permission`; each will have
+ ``permission`` argument *or* a call to
+ :meth:`pyramid.config.Configurator.set_default_permission`. Each will have
the following data.
``value``
@@ -435,7 +432,7 @@ introspectables in categories not described here.
Each introspectable in the ``templates`` category represents a call to
:meth:`pyramid.config.Configurator.add_view` that has a ``renderer``
- argument which points to a template; each will have the following data.
+ argument which points to a template. Each will have the following data.
``name``
@@ -447,15 +444,15 @@ introspectables in categories not described here.
``renderer``
- The :class:`pyramid.interfaces.IRendererInfo` object which represents
- this template's renderer.
+ The :class:`pyramid.interfaces.IRendererInfo` object which represents this
+ template's renderer.
``view mappers``
Each introspectable in the ``view mappers`` category represents a call to
- :meth:`pyramid.config.Configurator.add_view` that has an explicit
- ``mapper`` argument to *or* a call to
- :meth:`pyramid.config.Configurator.set_view_mapper`; each will have
+ :meth:`pyramid.config.Configurator.add_view` that has an explicit ``mapper``
+ argument *or* a call to
+ :meth:`pyramid.config.Configurator.set_view_mapper`. Each will have
the following data.
``mapper``
@@ -465,14 +462,13 @@ introspectables in categories not described here.
``asset overrides``
- Each introspectable in the ``asset overrides`` category represents a call
- to :meth:`pyramid.config.Configurator.override_asset`; each will have the
+ Each introspectable in the ``asset overrides`` category represents a call to
+ :meth:`pyramid.config.Configurator.override_asset`. Each will have the
following data.
``to_override``
- The ``to_override`` argument (an asset spec) passed to
- ``override_asset``.
+ The ``to_override`` argument (an asset spec) passed to ``override_asset``.
``override_with``
@@ -481,10 +477,10 @@ introspectables in categories not described here.
``translation directories``
- Each introspectable in the ``translation directories`` category represents
- an individual element in a ``specs`` argument passed to
- :meth:`pyramid.config.Configurator.add_translation_dirs`; each will have
- the following data.
+ Each introspectable in the ``translation directories`` category represents an
+ individual element in a ``specs`` argument passed to
+ :meth:`pyramid.config.Configurator.add_translation_dirs`. Each will have the
+ following data.
``directory``
@@ -497,13 +493,13 @@ introspectables in categories not described here.
``tweens``
Each introspectable in the ``tweens`` category represents a call to
- :meth:`pyramid.config.Configurator.add_tween`; each will have the following
+ :meth:`pyramid.config.Configurator.add_tween`. Each will have the following
data.
``name``
- The dotted name to the tween factory as a string (passed as
- the ``tween_factory`` argument to ``add_tween``).
+ The dotted name to the tween factory as a string (passed as the
+ ``tween_factory`` argument to ``add_tween``).
``factory``
@@ -524,7 +520,7 @@ introspectables in categories not described here.
``static views``
Each introspectable in the ``static views`` category represents a call to
- :meth:`pyramid.config.Configurator.add_static_view`; each will have the
+ :meth:`pyramid.config.Configurator.add_static_view`. Each will have the
following data.
``name``
@@ -539,13 +535,13 @@ introspectables in categories not described here.
``traversers``
Each introspectable in the ``traversers`` category represents a call to
- :meth:`pyramid.config.Configurator.add_traverser`; each will have the
+ :meth:`pyramid.config.Configurator.add_traverser`. Each will have the
following data.
``iface``
The (resolved) interface or class object that represents the return value
- of a root factory that this traverser will be used for.
+ of a root factory for which this traverser will be used.
``adapter``
@@ -554,7 +550,7 @@ introspectables in categories not described here.
``resource url adapters``
Each introspectable in the ``resource url adapters`` category represents a
- call to :meth:`pyramid.config.Configurator.add_resource_url_adapter`; each
+ call to :meth:`pyramid.config.Configurator.add_resource_url_adapter`. Each
will have the following data.
``adapter``
@@ -564,19 +560,20 @@ introspectables in categories not described here.
``resource_iface``
The (resolved) interface or class object that represents the resource
- interface that this url adapter is registered for.
+ interface for which this URL adapter is registered.
``request_iface``
The (resolved) interface or class object that represents the request
- interface that this url adapter is registered for.
+ interface for which this URL adapter is registered.
Introspection in the Toolbar
----------------------------
The Pyramid debug toolbar (part of the ``pyramid_debugtoolbar`` package)
provides a canned view of all registered introspectables and their
-relationships. It looks something like this:
+relationships. It is currently under the "Global" tab in the main navigation,
+and it looks something like this:
.. image:: tb_introspector.png
diff --git a/docs/narr/scaffolding.rst b/docs/narr/scaffolding.rst
index 4fcdeb537..8677359de 100644
--- a/docs/narr/scaffolding.rst
+++ b/docs/narr/scaffolding.rst
@@ -4,8 +4,8 @@ Creating Pyramid Scaffolds
==========================
You can extend Pyramid by creating a :term:`scaffold` template. A scaffold
-template is useful if you'd like to distribute a customizable configuration
-of Pyramid to other users. Once you've created a scaffold, and someone has
+template is useful if you'd like to distribute a customizable configuration of
+Pyramid to other users. Once you've created a scaffold, and someone has
installed the distribution that houses the scaffold, they can use the
``pcreate`` script to create a custom version of your scaffold's template.
Pyramid itself uses scaffolds to allow people to bootstrap new projects. For
@@ -15,22 +15,22 @@ example, ``pcreate -s alchemy MyStuff`` causes Pyramid to render the
Basics
------
-A scaffold template is just a bunch of source files and directories on disk.
-A small definition class points at this directory; it is in turn pointed at
-by a :term:`setuptools` "entry point" which registers the scaffold so it can
-be found by the ``pcreate`` command.
+A scaffold template is just a bunch of source files and directories on disk. A
+small definition class points at this directory. It is in turn pointed at by a
+:term:`setuptools` "entry point" which registers the scaffold so it can be
+found by the ``pcreate`` command.
To create a scaffold template, create a Python :term:`distribution` to house
the scaffold which includes a ``setup.py`` that relies on the ``setuptools``
package. See `Creating a Package
-<http://guide.python-distribute.org/creation.html>`_ for more information
-about how to do this. For the sake of example, we'll pretend the
-distribution you create is named ``CoolExtension``, and it has a package
-directory within it named ``coolextension``
+<http://guide.python-distribute.org/creation.html>`_ for more information about
+how to do this. For example, we'll pretend the distribution you create is
+named ``CoolExtension``, and it has a package directory within it named
+``coolextension``.
-Once you've created the distribution put a "scaffolds" directory within your
-distribution's package directory, and create a file within that directory
-named ``__init__.py`` with something like the following:
+Once you've created the distribution, put a "scaffolds" directory within your
+distribution's package directory, and create a file within that directory named
+``__init__.py`` with something like the following:
.. code-block:: python
:linenos:
@@ -54,12 +54,12 @@ As you create files and directories within the template directory, note that:
the string value of the variable named ``var`` provided to the scaffold.
- Files and directories with filenames that contain the string ``+var+`` will
- have that string replaced with the value of the ``var`` variable provided
- to the scaffold.
+ have that string replaced with the value of the ``var`` variable provided to
+ the scaffold.
- Files that start with a dot (e.g., ``.env``) are ignored and will not be
copied over to the destination directory. If you want to include a file with
- a leading dot then you must replace the dot with ``+dot+`` (e.g.,
+ a leading dot, then you must replace the dot with ``+dot+`` (e.g.,
``+dot+env``).
Otherwise, files and directories which live in the template directory will be
@@ -67,14 +67,14 @@ copied directly without modification to the ``pcreate`` output location.
The variables provided by the default ``PyramidTemplate`` include ``project``
(the project name provided by the user as an argument to ``pcreate``),
-``package`` (a lowercasing and normalizing of the project name provided by
-the user), ``random_string`` (a long random string), and ``package_logger``
-(the name of the package's logger).
+``package`` (a lowercasing and normalizing of the project name provided by the
+user), ``random_string`` (a long random string), and ``package_logger`` (the
+name of the package's logger).
See Pyramid's "scaffolds" package
-(https://github.com/Pylons/pyramid/tree/master/pyramid/scaffolds) for
-concrete examples of scaffold directories (``zodb``, ``alchemy``, and
-``starter``, for example).
+(https://github.com/Pylons/pyramid/tree/master/pyramid/scaffolds) for concrete
+examples of scaffold directories (``zodb``, ``alchemy``, and ``starter``, for
+example).
After you've created the template directory, add the following to the
``entry_points`` value of your distribution's ``setup.py``:
@@ -96,17 +96,16 @@ For example:
"""
)
-Run your distribution's ``setup.py develop`` or ``setup.py install``
-command. After that, you should be able to see your scaffolding template
-listed when you run ``pcreate -l``. It will be named ``coolextension``
-because that's the name we gave it in the entry point setup. Running
-``pcreate -s coolextension MyStuff`` will then render your scaffold to an
-output directory named ``MyStuff``.
+Run your distribution's ``setup.py develop`` or ``setup.py install`` command.
+After that, you should be able to see your scaffolding template listed when you
+run ``pcreate -l``. It will be named ``coolextension`` because that's the name
+we gave it in the entry point setup. Running ``pcreate -s coolextension
+MyStuff`` will then render your scaffold to an output directory named
+``MyStuff``.
-See the module documentation for :mod:`pyramid.scaffolds` for information
-about the API of the :class:`pyramid.scaffolds.Template` class and
-related classes. You can override methods of this class to get special
-behavior.
+See the module documentation for :mod:`pyramid.scaffolds` for information about
+the API of the :class:`pyramid.scaffolds.Template` class and related classes.
+You can override methods of this class to get special behavior.
Supporting Older Pyramid Versions
---------------------------------
@@ -139,21 +138,22 @@ defining your scaffold template:
And then in the setup.py of the package that contains your scaffold, define
the template as a target of both ``paste.paster_create_template`` (for
-``paster create``) and ``pyramid.scaffold`` (for ``pcreate``)::
+``paster create``) and ``pyramid.scaffold`` (for ``pcreate``).
- [paste.paster_create_template]
- coolextension=coolextension.scaffolds:CoolExtensionTemplate
- [pyramid.scaffold]
- coolextension=coolextension.scaffolds:CoolExtensionTemplate
+.. code-block:: ini
+
+ [paste.paster_create_template]
+ coolextension=coolextension.scaffolds:CoolExtensionTemplate
+ [pyramid.scaffold]
+ coolextension=coolextension.scaffolds:CoolExtensionTemplate
-Doing this hideousness will allow your scaffold to work as a ``paster
-create`` target (under 1.0, 1.1, or 1.2) or as a ``pcreate`` target (under
-1.3). If an invoker tries to run ``paster create`` against a scaffold
-defined this way under 1.3, an error is raised instructing them to use
-``pcreate`` instead.
+Doing this hideousness will allow your scaffold to work as a ``paster create``
+target (under 1.0, 1.1, or 1.2) or as a ``pcreate`` target (under 1.3). If an
+invoker tries to run ``paster create`` against a scaffold defined this way
+under 1.3, an error is raised instructing them to use ``pcreate`` instead.
-If you want only to support Pyramid 1.3 only, it's much cleaner, and the API
-is stable:
+If you want to support Pyramid 1.3 only, it's much cleaner, and the API is
+stable:
.. code-block:: python
:linenos:
@@ -164,17 +164,17 @@ is stable:
_template_dir = 'coolextension_scaffold'
summary = 'My cool_extension'
-You only need to specify a ``paste.paster_create_template`` entry point
-target in your ``setup.py`` if you want your scaffold to be consumable by
-users of Pyramid 1.0, 1.1, or 1.2. To support only 1.3, specifying only the
+You only need to specify a ``paste.paster_create_template`` entry point target
+in your ``setup.py`` if you want your scaffold to be consumable by users of
+Pyramid 1.0, 1.1, or 1.2. To support only 1.3, specifying only the
``pyramid.scaffold`` entry point is good enough. If you want to support both
-``paster create`` and ``pcreate`` (meaning you want to support Pyramid 1.2
-and some older version), you'll need to define both.
+``paster create`` and ``pcreate`` (meaning you want to support Pyramid 1.2 and
+some older version), you'll need to define both.
Examples
--------
Existing third-party distributions which house scaffolding are available via
-:term:`PyPI`. The ``pyramid_jqm``, ``pyramid_zcml`` and ``pyramid_jinja2``
+:term:`PyPI`. The ``pyramid_jqm``, ``pyramid_zcml``, and ``pyramid_jinja2``
packages house scaffolds. You can install and examine these packages to see
how they work in the quest to develop your own scaffolding.
diff --git a/docs/narr/security.rst b/docs/narr/security.rst
index 75f4dc7c5..7cbea113c 100644
--- a/docs/narr/security.rst
+++ b/docs/narr/security.rst
@@ -6,64 +6,59 @@
Security
========
-:app:`Pyramid` provides an optional, declarative, security system.
-Security in :app:`Pyramid` is separated into authentication and
-authorization. The two systems communicate via :term:`principal`
-identifiers. Authentication is merely the mechanism by which credentials
-provided in the :term:`request` are resolved to one or more
-:term:`principal` identifiers. These identifiers represent the users and
-groups that are in effect during the request. Authorization then determines
-access based on the :term:`principal` identifiers, the requested
+:app:`Pyramid` provides an optional, declarative, security system. Security in
+:app:`Pyramid` is separated into authentication and authorization. The two
+systems communicate via :term:`principal` identifiers. Authentication is merely
+the mechanism by which credentials provided in the :term:`request` are resolved
+to one or more :term:`principal` identifiers. These identifiers represent the
+users and groups that are in effect during the request. Authorization then
+determines access based on the :term:`principal` identifiers, the requested
:term:`permission`, and a :term:`context`.
-The :app:`Pyramid` authorization system
-can prevent a :term:`view` from being invoked based on an
-:term:`authorization policy`. Before a view is invoked, the
-authorization system can use the credentials in the :term:`request`
-along with the :term:`context` resource to determine if access will be
-allowed. Here's how it works at a high level:
+The :app:`Pyramid` authorization system can prevent a :term:`view` from being
+invoked based on an :term:`authorization policy`. Before a view is invoked, the
+authorization system can use the credentials in the :term:`request` along with
+the :term:`context` resource to determine if access will be allowed. Here's
+how it works at a high level:
-- A user may or may not have previously visited the application and
- supplied authentication credentials, including a :term:`userid`. If
- so, the application may have called
- :func:`pyramid.security.remember` to remember these.
+- A user may or may not have previously visited the application and supplied
+ authentication credentials, including a :term:`userid`. If so, the
+ application may have called :func:`pyramid.security.remember` to remember
+ these.
- A :term:`request` is generated when a user visits the application.
- Based on the request, a :term:`context` resource is located through
:term:`resource location`. A context is located differently depending on
- whether the application uses :term:`traversal` or :term:`URL dispatch`, but
- a context is ultimately found in either case. See
- the :ref:`urldispatch_chapter` chapter for more information.
+ whether the application uses :term:`traversal` or :term:`URL dispatch`, but a
+ context is ultimately found in either case. See the
+ :ref:`urldispatch_chapter` chapter for more information.
-- A :term:`view callable` is located by :term:`view lookup` using the
- context as well as other attributes of the request.
+- A :term:`view callable` is located by :term:`view lookup` using the context
+ as well as other attributes of the request.
-- If an :term:`authentication policy` is in effect, it is passed the
- request. It will return some number of :term:`principal` identifiers.
- To do this, the policy would need to determine the authenticated
- :term:`userid` present in the request.
+- If an :term:`authentication policy` is in effect, it is passed the request.
+ It will return some number of :term:`principal` identifiers. To do this, the
+ policy would need to determine the authenticated :term:`userid` present in
+ the request.
- If an :term:`authorization policy` is in effect and the :term:`view
- configuration` associated with the view callable that was found has
- a :term:`permission` associated with it, the authorization policy is
- passed the :term:`context`, some number of :term:`principal`
- identifiers returned by the authentication policy, and the
- :term:`permission` associated with the view; it will allow or deny
- access.
+ configuration` associated with the view callable that was found has a
+ :term:`permission` associated with it, the authorization policy is passed the
+ :term:`context`, some number of :term:`principal` identifiers returned by the
+ authentication policy, and the :term:`permission` associated with the view;
+ it will allow or deny access.
-- If the authorization policy allows access, the view callable is
- invoked.
+- If the authorization policy allows access, the view callable is invoked.
-- If the authorization policy denies access, the view callable is not
- invoked; instead the :term:`forbidden view` is invoked.
+- If the authorization policy denies access, the view callable is not invoked.
+ Instead the :term:`forbidden view` is invoked.
Authorization is enabled by modifying your application to include an
-:term:`authentication policy` and :term:`authorization policy`.
-:app:`Pyramid` comes with a variety of implementations of these
-policies. To provide maximal flexibility, :app:`Pyramid` also
-allows you to create custom authentication policies and authorization
-policies.
+:term:`authentication policy` and :term:`authorization policy`. :app:`Pyramid`
+comes with a variety of implementations of these policies. To provide maximal
+flexibility, :app:`Pyramid` also allows you to create custom authentication
+policies and authorization policies.
.. index::
single: authorization policy
@@ -73,23 +68,22 @@ policies.
Enabling an Authorization Policy
--------------------------------
-:app:`Pyramid` does not enable any authorization policy by default. All
-views are accessible by completely anonymous users. In order to begin
-protecting views from execution based on security settings, you need
-to enable an authorization policy.
+:app:`Pyramid` does not enable any authorization policy by default. All views
+are accessible by completely anonymous users. In order to begin protecting
+views from execution based on security settings, you need to enable an
+authorization policy.
Enabling an Authorization Policy Imperatively
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-Use the :meth:`~pyramid.config.Configurator.set_authorization_policy` method
-of the :class:`~pyramid.config.Configurator` to enable an authorization
-policy.
+Use the :meth:`~pyramid.config.Configurator.set_authorization_policy` method of
+the :class:`~pyramid.config.Configurator` to enable an authorization policy.
You must also enable an :term:`authentication policy` in order to enable the
-authorization policy. This is because authorization, in general, depends
-upon authentication. Use the
-:meth:`~pyramid.config.Configurator.set_authentication_policy` method
-during application setup to specify the authentication policy.
+authorization policy. This is because authorization, in general, depends upon
+authentication. Use the
+:meth:`~pyramid.config.Configurator.set_authentication_policy` method during
+application setup to specify the authentication policy.
For example:
@@ -105,28 +99,27 @@ For example:
config.set_authentication_policy(authn_policy)
config.set_authorization_policy(authz_policy)
-.. note:: The ``authentication_policy`` and ``authorization_policy``
- arguments may also be passed to their respective methods mentioned above
- as :term:`dotted Python name` values, each representing the dotted name
- path to a suitable implementation global defined at Python module scope.
+.. note:: The ``authentication_policy`` and ``authorization_policy`` arguments
+ may also be passed to their respective methods mentioned above as
+ :term:`dotted Python name` values, each representing the dotted name path to
+ a suitable implementation global defined at Python module scope.
The above configuration enables a policy which compares the value of an "auth
ticket" cookie passed in the request's environment which contains a reference
-to a single :term:`userid` and matches that userid's
-:term:`principals <principal>` against the principals present in any
-:term:`ACL` found in the resource tree when attempting to call some
-:term:`view`.
+to a single :term:`userid`, and matches that userid's :term:`principals
+<principal>` against the principals present in any :term:`ACL` found in the
+resource tree when attempting to call some :term:`view`.
While it is possible to mix and match different authentication and
-authorization policies, it is an error to configure a Pyramid application
-with an authentication policy but without the authorization policy or vice
-versa. If you do this, you'll receive an error at application startup time.
+authorization policies, it is an error to configure a Pyramid application with
+an authentication policy but without the authorization policy or vice versa. If
+you do this, you'll receive an error at application startup time.
.. seealso::
- See also the :mod:`pyramid.authorization` and
- :mod:`pyramid.authentication` modules for alternate implementations of
- authorization and authentication policies.
+ See also the :mod:`pyramid.authorization` and :mod:`pyramid.authentication`
+ modules for alternative implementations of authorization and authentication
+ policies.
.. index::
single: permissions
@@ -139,14 +132,13 @@ Protecting Views with Permissions
To protect a :term:`view callable` from invocation based on a user's security
settings when a particular type of resource becomes the :term:`context`, you
-must pass a :term:`permission` to :term:`view configuration`. Permissions
-are usually just strings, and they have no required composition: you can name
+must pass a :term:`permission` to :term:`view configuration`. Permissions are
+usually just strings, and they have no required composition: you can name
permissions whatever you like.
For example, the following view declaration protects the view named
``add_entry.html`` when the context resource is of type ``Blog`` with the
-``add`` permission using the :meth:`pyramid.config.Configurator.add_view`
-API:
+``add`` permission using the :meth:`pyramid.config.Configurator.add_view` API:
.. code-block:: python
:linenos:
@@ -158,8 +150,8 @@ API:
context='mypackage.resources.Blog',
permission='add')
-The equivalent view registration including the ``add`` permission name
-may be performed via the ``@view_config`` decorator:
+The equivalent view registration including the ``add`` permission name may be
+performed via the ``@view_config`` decorator:
.. code-block:: python
:linenos:
@@ -173,11 +165,11 @@ may be performed via the ``@view_config`` decorator:
pass
As a result of any of these various view configuration statements, if an
-authorization policy is in place when the view callable is found during
-normal application operations, the requesting user will need to possess the
-``add`` permission against the :term:`context` resource in order to be able
-to invoke the ``blog_entry_add_view`` view. If he does not, the
-:term:`Forbidden view` will be invoked.
+authorization policy is in place when the view callable is found during normal
+application operations, the requesting user will need to possess the ``add``
+permission against the :term:`context` resource in order to be able to invoke
+the ``blog_entry_add_view`` view. If they do not, the :term:`Forbidden view`
+will be invoked.
.. index::
pair: permission; default
@@ -187,18 +179,17 @@ to invoke the ``blog_entry_add_view`` view. If he does not, the
Setting a Default Permission
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-If a permission is not supplied to a view configuration, the registered
-view will always be executable by entirely anonymous users: any
-authorization policy in effect is ignored.
+If a permission is not supplied to a view configuration, the registered view
+will always be executable by entirely anonymous users: any authorization policy
+in effect is ignored.
-In support of making it easier to configure applications which are
-"secure by default", :app:`Pyramid` allows you to configure a
-*default* permission. If supplied, the default permission is used as
-the permission string to all view registrations which don't otherwise
-name a ``permission`` argument.
+In support of making it easier to configure applications which are "secure by
+default", :app:`Pyramid` allows you to configure a *default* permission. If
+supplied, the default permission is used as the permission string to all view
+registrations which don't otherwise name a ``permission`` argument.
-The :meth:`pyramid.config.Configurator.set_default_permission` method
-supports configuring a default permission for an application.
+The :meth:`pyramid.config.Configurator.set_default_permission` method supports
+configuring a default permission for an application.
When a default permission is registered:
@@ -207,8 +198,8 @@ When a default permission is registered:
view-configuration-named permission is used.
- If a view configuration names the permission
- :data:`pyramid.security.NO_PERMISSION_REQUIRED`, the default permission
- is ignored, and the view is registered *without* a permission (making it
+ :data:`pyramid.security.NO_PERMISSION_REQUIRED`, the default permission is
+ ignored, and the view is registered *without* a permission (making it
available to all callers regardless of their credentials).
.. warning::
@@ -226,19 +217,18 @@ When a default permission is registered:
.. _assigning_acls:
-Assigning ACLs to your Resource Objects
+Assigning ACLs to Your Resource Objects
---------------------------------------
-When the default :app:`Pyramid` :term:`authorization policy` determines
-whether a user possesses a particular permission with respect to a resource,
-it examines the :term:`ACL` associated with the resource. An ACL is
-associated with a resource by adding an ``__acl__`` attribute to the resource
-object. This attribute can be defined on the resource *instance* if you need
+When the default :app:`Pyramid` :term:`authorization policy` determines whether
+a user possesses a particular permission with respect to a resource, it
+examines the :term:`ACL` associated with the resource. An ACL is associated
+with a resource by adding an ``__acl__`` attribute to the resource object.
+This attribute can be defined on the resource *instance* if you need
instance-level security, or it can be defined on the resource *class* if you
just need type-level security.
-For example, an ACL might be attached to the resource for a blog via its
-class:
+For example, an ACL might be attached to the resource for a blog via its class:
.. code-block:: python
:linenos:
@@ -273,11 +263,11 @@ Or, if your resources are persistent, an ACL might be specified via the
(Allow, 'group:editors', 'edit'),
]
-Whether an ACL is attached to a resource's class or an instance of the
-resource itself, the effect is the same. It is useful to decorate individual
-resource instances with an ACL (as opposed to just decorating their class) in
-applications such as "CMS" systems where fine-grained access is required on
-an object-by-object basis.
+Whether an ACL is attached to a resource's class or an instance of the resource
+itself, the effect is the same. It is useful to decorate individual resource
+instances with an ACL (as opposed to just decorating their class) in
+applications such as content management systems where fine-grained access is
+required on an object-by-object basis.
Dynamic ACLs are also possible by turning the ACL into a callable on the
resource. This may allow the ACL to dynamically generate rules based on
@@ -321,30 +311,27 @@ Here's an example ACL:
(Allow, 'group:editors', 'edit'),
]
-The example ACL indicates that the
-:data:`pyramid.security.Everyone` principal -- a special
-system-defined principal indicating, literally, everyone -- is allowed
-to view the blog, the ``group:editors`` principal is allowed to add to
-and edit the blog.
+The example ACL indicates that the :data:`pyramid.security.Everyone`
+principal—a special system-defined principal indicating, literally, everyone—is
+allowed to view the blog, and the ``group:editors`` principal is allowed to add
+to and edit the blog.
-Each element of an ACL is an :term:`ACE` or access control entry.
-For example, in the above code block, there are three ACEs: ``(Allow,
-Everyone, 'view')``, ``(Allow, 'group:editors', 'add')``, and
-``(Allow, 'group:editors', 'edit')``.
+Each element of an ACL is an :term:`ACE`, or access control entry. For example,
+in the above code block, there are three ACEs: ``(Allow, Everyone, 'view')``,
+``(Allow, 'group:editors', 'add')``, and ``(Allow, 'group:editors', 'edit')``.
-The first element of any ACE is either
-:data:`pyramid.security.Allow`, or
-:data:`pyramid.security.Deny`, representing the action to take when
-the ACE matches. The second element is a :term:`principal`. The
-third argument is a permission or sequence of permission names.
+The first element of any ACE is either :data:`pyramid.security.Allow`, or
+:data:`pyramid.security.Deny`, representing the action to take when the ACE
+matches. The second element is a :term:`principal`. The third argument is a
+permission or sequence of permission names.
A principal is usually a user id, however it also may be a group id if your
authentication system provides group information and the effective
:term:`authentication policy` policy is written to respect group information.
See :ref:`extending_default_authentication_policies`.
-Each ACE in an ACL is processed by an authorization policy *in the
-order dictated by the ACL*. So if you have an ACL like this:
+Each ACE in an ACL is processed by an authorization policy *in the order
+dictated by the ACL*. So if you have an ACL like this:
.. code-block:: python
:linenos:
@@ -358,10 +345,9 @@ order dictated by the ACL*. So if you have an ACL like this:
(Deny, Everyone, 'view'),
]
-The default authorization policy will *allow* everyone the view
-permission, even though later in the ACL you have an ACE that denies
-everyone the view permission. On the other hand, if you have an ACL
-like this:
+The default authorization policy will *allow* everyone the view permission,
+even though later in the ACL you have an ACE that denies everyone the view
+permission. On the other hand, if you have an ACL like this:
.. code-block:: python
:linenos:
@@ -375,14 +361,13 @@ like this:
(Allow, Everyone, 'view'),
]
-The authorization policy will deny everyone the view permission, even
-though later in the ACL is an ACE that allows everyone.
+The authorization policy will deny everyone the view permission, even though
+later in the ACL, there is an ACE that allows everyone.
-The third argument in an ACE can also be a sequence of permission
-names instead of a single permission name. So instead of creating
-multiple ACEs representing a number of different permission grants to
-a single ``group:editors`` group, we can collapse this into a single
-ACE, as below.
+The third argument in an ACE can also be a sequence of permission names instead
+of a single permission name. So instead of creating multiple ACEs representing
+a number of different permission grants to a single ``group:editors`` group, we
+can collapse this into a single ACE, as below.
.. code-block:: python
:linenos:
@@ -403,23 +388,21 @@ ACE, as below.
Special Principal Names
-----------------------
-Special principal names exist in the :mod:`pyramid.security`
-module. They can be imported for use in your own code to populate
-ACLs, e.g. :data:`pyramid.security.Everyone`.
+Special principal names exist in the :mod:`pyramid.security` module. They can
+be imported for use in your own code to populate ACLs, e.g.,
+:data:`pyramid.security.Everyone`.
:data:`pyramid.security.Everyone`
- Literally, everyone, no matter what. This object is actually a
- string "under the hood" (``system.Everyone``). Every user "is" the
- principal named Everyone during every request, even if a security
- policy is not in use.
+ Literally, everyone, no matter what. This object is actually a string under
+ the hood (``system.Everyone``). Every user *is* the principal named
+ "Everyone" during every request, even if a security policy is not in use.
:data:`pyramid.security.Authenticated`
- Any user with credentials as determined by the current security
- policy. You might think of it as any user that is "logged in".
- This object is actually a string "under the hood"
- (``system.Authenticated``).
+ Any user with credentials as determined by the current security policy. You
+ might think of it as any user that is "logged in". This object is actually a
+ string under the hood (``system.Authenticated``).
.. index::
single: permission names
@@ -428,19 +411,19 @@ ACLs, e.g. :data:`pyramid.security.Everyone`.
Special Permissions
-------------------
-Special permission names exist in the :mod:`pyramid.security`
-module. These can be imported for use in ACLs.
+Special permission names exist in the :mod:`pyramid.security` module. These
+can be imported for use in ACLs.
.. _all_permissions:
:data:`pyramid.security.ALL_PERMISSIONS`
- An object representing, literally, *all* permissions. Useful in an
- ACL like so: ``(Allow, 'fred', ALL_PERMISSIONS)``. The
- ``ALL_PERMISSIONS`` object is actually a stand-in object that has a
- ``__contains__`` method that always returns ``True``, which, for all
- known authorization policies, has the effect of indicating that a
- given principal "has" any permission asked for by the system.
+ An object representing, literally, *all* permissions. Useful in an ACL like
+ so: ``(Allow, 'fred', ALL_PERMISSIONS)``. The ``ALL_PERMISSIONS`` object is
+ actually a stand-in object that has a ``__contains__`` method that always
+ returns ``True``, which, for all known authorization policies, has the effect
+ of indicating that a given principal has any permission asked for by the
+ system.
.. index::
single: special ACE
@@ -451,11 +434,11 @@ Special ACEs
A convenience :term:`ACE` is defined representing a deny to everyone of all
permissions in :data:`pyramid.security.DENY_ALL`. This ACE is often used as
-the *last* ACE of an ACL to explicitly cause inheriting authorization
-policies to "stop looking up the traversal tree" (effectively breaking any
-inheritance). For example, an ACL which allows *only* ``fred`` the view
-permission for a particular resource despite what inherited ACLs may say when
-the default authorization policy is in effect might look like so:
+the *last* ACE of an ACL to explicitly cause inheriting authorization policies
+to "stop looking up the traversal tree" (effectively breaking any inheritance).
+For example, an ACL which allows *only* ``fred`` the view permission for a
+particular resource, despite what inherited ACLs may say when the default
+authorization policy is in effect, might look like so:
.. code-block:: python
:linenos:
@@ -465,8 +448,8 @@ the default authorization policy is in effect might look like so:
__acl__ = [ (Allow, 'fred', 'view'), DENY_ALL ]
-"Under the hood", the :data:`pyramid.security.DENY_ALL` ACE equals
-the following:
+Under the hood, the :data:`pyramid.security.DENY_ALL` ACE equals the
+following:
.. code-block:: python
:linenos:
@@ -483,14 +466,14 @@ ACL Inheritance and Location-Awareness
While the default :term:`authorization policy` is in place, if a resource
object does not have an ACL when it is the context, its *parent* is consulted
-for an ACL. If that object does not have an ACL, *its* parent is consulted
-for an ACL, ad infinitum, until we've reached the root and there are no more
+for an ACL. If that object does not have an ACL, *its* parent is consulted for
+an ACL, ad infinitum, until we've reached the root and there are no more
parents left.
In order to allow the security machinery to perform ACL inheritance, resource
objects must provide *location-awareness*. Providing *location-awareness*
-means two things: the root object in the resource tree must have a
-``__name__`` attribute and a ``__parent__`` attribute.
+means two things: the root object in the resource tree must have a ``__name__``
+attribute and a ``__parent__`` attribute.
.. code-block:: python
:linenos:
@@ -499,10 +482,10 @@ means two things: the root object in the resource tree must have a
__name__ = ''
__parent__ = None
-An object with a ``__parent__`` attribute and a ``__name__`` attribute
-is said to be *location-aware*. Location-aware objects define an
-``__parent__`` attribute which points at their parent object. The
-root object's ``__parent__`` is ``None``.
+An object with a ``__parent__`` attribute and a ``__name__`` attribute is said
+to be *location-aware*. Location-aware objects define a ``__parent__``
+attribute which points at their parent object. The root object's
+``__parent__`` is ``None``.
.. seealso::
@@ -519,12 +502,11 @@ root object's ``__parent__`` is ``None``.
Changing the Forbidden View
---------------------------
-When :app:`Pyramid` denies a view invocation due to an
-authorization denial, the special ``forbidden`` view is invoked. "Out
-of the box", this forbidden view is very plain. See
-:ref:`changing_the_forbidden_view` within :ref:`hooks_chapter` for
-instructions on how to create a custom forbidden view and arrange for
-it to be called when view authorization is denied.
+When :app:`Pyramid` denies a view invocation due to an authorization denial,
+the special ``forbidden`` view is invoked. Out of the box, this forbidden view
+is very plain. See :ref:`changing_the_forbidden_view` within
+:ref:`hooks_chapter` for instructions on how to create a custom forbidden view
+and arrange for it to be called when view authorization is denied.
.. index::
single: debugging authorization failures
@@ -534,8 +516,8 @@ it to be called when view authorization is denied.
Debugging View Authorization Failures
-------------------------------------
-If your application in your judgment is allowing or denying view
-access inappropriately, start your application under a shell using the
+If your application in your judgment is allowing or denying view access
+inappropriately, start your application under a shell using the
``PYRAMID_DEBUG_AUTHORIZATION`` environment variable set to ``1``. For
example:
@@ -543,14 +525,13 @@ example:
$ PYRAMID_DEBUG_AUTHORIZATION=1 $VENV/bin/pserve myproject.ini
-When any authorization takes place during a top-level view rendering,
-a message will be logged to the console (to stderr) about what ACE in
-which ACL permitted or denied the authorization based on
-authentication information.
+When any authorization takes place during a top-level view rendering, a message
+will be logged to the console (to stderr) about what ACE in which ACL permitted
+or denied the authorization based on authentication information.
-This behavior can also be turned on in the application ``.ini`` file
-by setting the ``pyramid.debug_authorization`` key to ``true`` within the
-application's configuration section, e.g.:
+This behavior can also be turned on in the application ``.ini`` file by setting
+the ``pyramid.debug_authorization`` key to ``true`` within the application's
+configuration section, e.g.:
.. code-block:: ini
:linenos:
@@ -559,26 +540,24 @@ application's configuration section, e.g.:
use = egg:MyProject
pyramid.debug_authorization = true
-With this debug flag turned on, the response sent to the browser will
-also contain security debugging information in its body.
+With this debug flag turned on, the response sent to the browser will also
+contain security debugging information in its body.
Debugging Imperative Authorization Failures
-------------------------------------------
The :meth:`pyramid.request.Request.has_permission` API is used to check
-security within view functions imperatively. It returns instances of
-objects that are effectively booleans. But these objects are not raw
-``True`` or ``False`` objects, and have information attached to them
-about why the permission was allowed or denied. The object will be
-one of :data:`pyramid.security.ACLAllowed`,
-:data:`pyramid.security.ACLDenied`,
-:data:`pyramid.security.Allowed`, or
-:data:`pyramid.security.Denied`, as documented in
-:ref:`security_module`. At the very minimum these objects will have a
-``msg`` attribute, which is a string indicating why the permission was
-denied or allowed. Introspecting this information in the debugger or
-via print statements when a call to
-:meth:`~pyramid.request.Request.has_permission` fails is often useful.
+security within view functions imperatively. It returns instances of objects
+that are effectively booleans. But these objects are not raw ``True`` or
+``False`` objects, and have information attached to them about why the
+permission was allowed or denied. The object will be one of
+:data:`pyramid.security.ACLAllowed`, :data:`pyramid.security.ACLDenied`,
+:data:`pyramid.security.Allowed`, or :data:`pyramid.security.Denied`, as
+documented in :ref:`security_module`. At the very minimum, these objects will
+have a ``msg`` attribute, which is a string indicating why the permission was
+denied or allowed. Introspecting this information in the debugger or via print
+statements when a call to :meth:`~pyramid.request.Request.has_permission` fails
+is often useful.
.. index::
single: authentication policy (extending)
@@ -588,27 +567,26 @@ via print statements when a call to
Extending Default Authentication Policies
-----------------------------------------
-Pyramid ships with some builtin authentication policies for use in your
-applications. See :mod:`pyramid.authentication` for the available
-policies. They differ on their mechanisms for tracking authentication
-credentials between requests, however they all interface with your
-application in mostly the same way.
+Pyramid ships with some built in authentication policies for use in your
+applications. See :mod:`pyramid.authentication` for the available policies.
+They differ on their mechanisms for tracking authentication credentials between
+requests, however they all interface with your application in mostly the same
+way.
-Above you learned about :ref:`assigning_acls`. Each :term:`principal` used
-in the :term:`ACL` is matched against the list returned from
+Above you learned about :ref:`assigning_acls`. Each :term:`principal` used in
+the :term:`ACL` is matched against the list returned from
:meth:`pyramid.interfaces.IAuthenticationPolicy.effective_principals`.
Similarly, :meth:`pyramid.request.Request.authenticated_userid` maps to
:meth:`pyramid.interfaces.IAuthenticationPolicy.authenticated_userid`.
You may control these values by subclassing the default authentication
policies. For example, below we subclass the
-:class:`pyramid.authentication.AuthTktAuthenticationPolicy` and define
-extra functionality to query our database before confirming that the
-:term:`userid` is valid in order to avoid blindly trusting the value in the
-cookie (what if the cookie is still valid but the user has deleted their
-account?). We then use that :term:`userid` to augment the
-``effective_principals`` with information about groups and other state for
-that user.
+:class:`pyramid.authentication.AuthTktAuthenticationPolicy` and define extra
+functionality to query our database before confirming that the :term:`userid`
+is valid in order to avoid blindly trusting the value in the cookie (what if
+the cookie is still valid, but the user has deleted their account?). We then
+use that :term:`userid` to augment the ``effective_principals`` with
+information about groups and other state for that user.
.. code-block:: python
:linenos:
@@ -630,8 +608,8 @@ that user.
return principals
In most instances ``authenticated_userid`` and ``effective_principals`` are
-application-specific whereas ``unauthenticated_userid``, ``remember`` and
-``forget`` are generic and focused on transport/serialization of data
+application-specific, whereas ``unauthenticated_userid``, ``remember``, and
+``forget`` are generic and focused on transport and serialization of data
between consecutive requests.
.. index::
@@ -642,12 +620,11 @@ between consecutive requests.
Creating Your Own Authentication Policy
---------------------------------------
-:app:`Pyramid` ships with a number of useful out-of-the-box
-security policies (see :mod:`pyramid.authentication`). However,
-creating your own authentication policy is often necessary when you
-want to control the "horizontal and vertical" of how your users
-authenticate. Doing so is a matter of creating an instance of something
-that implements the following interface:
+:app:`Pyramid` ships with a number of useful out-of-the-box security policies
+(see :mod:`pyramid.authentication`). However, creating your own authentication
+policy is often necessary when you want to control the "horizontal and
+vertical" of how your users authenticate. Doing so is a matter of creating an
+instance of something that implements the following interface:
.. code-block:: python
:linenos:
@@ -717,21 +694,19 @@ Creating Your Own Authorization Policy
--------------------------------------
An authorization policy is a policy that allows or denies access after a user
-has been authenticated. Most :app:`Pyramid` applications will use the
-default :class:`pyramid.authorization.ACLAuthorizationPolicy`.
-
-However, in some cases, it's useful to be able to use a different
-authorization policy than the default
-:class:`~pyramid.authorization.ACLAuthorizationPolicy`. For example, it
-might be desirable to construct an alternate authorization policy which
-allows the application to use an authorization mechanism that does not
-involve :term:`ACL` objects.
-
-:app:`Pyramid` ships with only a single default authorization
-policy, so you'll need to create your own if you'd like to use a
-different one. Creating and using your own authorization policy is a
-matter of creating an instance of an object that implements the
-following interface:
+has been authenticated. Most :app:`Pyramid` applications will use the default
+:class:`pyramid.authorization.ACLAuthorizationPolicy`.
+
+However, in some cases, it's useful to be able to use a different authorization
+policy than the default :class:`~pyramid.authorization.ACLAuthorizationPolicy`.
+For example, it might be desirable to construct an alternate authorization
+policy which allows the application to use an authorization mechanism that does
+not involve :term:`ACL` objects.
+
+:app:`Pyramid` ships with only a single default authorization policy, so you'll
+need to create your own if you'd like to use a different one. Creating and
+using your own authorization policy is a matter of creating an instance of an
+object that implements the following interface:
.. code-block:: python
:linenos:
@@ -782,4 +757,3 @@ which would allow the attacker to control the content of the payload. Re-using
a secret across two different subsystems might drop the security of signing to
zero. Keys should not be re-used across different contexts where an attacker
has the possibility of providing a chosen plaintext.
-
diff --git a/docs/narr/subrequest.rst b/docs/narr/subrequest.rst
index 4b4e99d41..02ae14aa5 100644
--- a/docs/narr/subrequest.rst
+++ b/docs/narr/subrequest.rst
@@ -17,6 +17,7 @@ application.
Here's an example application which uses a subrequest:
.. code-block:: python
+ :linenos:
from wsgiref.simple_server import make_server
from pyramid.config import Configurator
@@ -41,16 +42,16 @@ Here's an example application which uses a subrequest:
server = make_server('0.0.0.0', 8080, app)
server.serve_forever()
-When ``/view_one`` is visted in a browser, the text printed in the browser
-pane will be ``This came from view_two``. The ``view_one`` view used the
-:meth:`pyramid.request.Request.invoke_subrequest` API to obtain a response
-from another view (``view_two``) within the same application when it
-executed. It did so by constructing a new request that had a URL that it
-knew would match the ``view_two`` view registration, and passed that new
-request along to :meth:`pyramid.request.Request.invoke_subrequest`. The
-``view_two`` view callable was invoked, and it returned a response. The
-``view_one`` view callable then simply returned the response it obtained from
-the ``view_two`` view callable.
+When ``/view_one`` is visted in a browser, the text printed in the browser pane
+will be ``This came from view_two``. The ``view_one`` view used the
+:meth:`pyramid.request.Request.invoke_subrequest` API to obtain a response from
+another view (``view_two``) within the same application when it executed. It
+did so by constructing a new request that had a URL that it knew would match
+the ``view_two`` view registration, and passed that new request along to
+:meth:`pyramid.request.Request.invoke_subrequest`. The ``view_two`` view
+callable was invoked, and it returned a response. The ``view_one`` view
+callable then simply returned the response it obtained from the ``view_two``
+view callable.
Note that it doesn't matter if the view callable invoked via a subrequest
actually returns a *literal* Response object. Any view callable that uses a
@@ -60,6 +61,8 @@ adapter when found and invoked via
object:
.. code-block:: python
+ :linenos:
+ :emphasize-lines: 11
from wsgiref.simple_server import make_server
from pyramid.config import Configurator
@@ -83,19 +86,19 @@ object:
server = make_server('0.0.0.0', 8080, app)
server.serve_forever()
-Even though the ``view_two`` view callable returned a string, it was invoked
-in such a way that the ``string`` renderer associated with the view
-registration that was found turned it into a "real" response object for
-consumption by ``view_one``.
+Even though the ``view_two`` view callable returned a string, it was invoked in
+such a way that the ``string`` renderer associated with the view registration
+that was found turned it into a "real" response object for consumption by
+``view_one``.
Being able to unconditionally obtain a response object by invoking a view
callable indirectly is the main advantage to using
-:meth:`pyramid.request.Request.invoke_subrequest` instead of simply importing
-a view callable and executing it directly. Note that there's not much
-advantage to invoking a view using a subrequest if you *can* invoke a view
-callable directly. Subrequests are slower and are less convenient if you
-actually do want just the literal information returned by a function that
-happens to be a view callable.
+:meth:`pyramid.request.Request.invoke_subrequest` instead of simply importing a
+view callable and executing it directly. Note that there's not much advantage
+to invoking a view using a subrequest if you *can* invoke a view callable
+directly. Subrequests are slower and are less convenient if you actually do
+want just the literal information returned by a function that happens to be a
+view callable.
Note that, by default, if a view callable invoked by a subrequest raises an
exception, the exception will be raised to the caller of
@@ -103,6 +106,8 @@ exception, the exception will be raised to the caller of
:term:`exception view` configured:
.. code-block:: python
+ :linenos:
+ :emphasize-lines: 11-16
from wsgiref.simple_server import make_server
from pyramid.config import Configurator
@@ -136,15 +141,21 @@ When we run the above code and visit ``/view_one`` in a browser, the
``excview`` :term:`exception view` will *not* be executed. Instead, the call
to :meth:`~pyramid.request.Request.invoke_subrequest` will cause a
:exc:`ValueError` exception to be raised and a response will never be
-generated. We can change this behavior; how to do so is described below in
-our discussion of the ``use_tweens`` argument.
+generated. We can change this behavior; how to do so is described below in our
+discussion of the ``use_tweens`` argument.
+
+.. index::
+ pair: subrequest; use_tweens
+
+Subrequests with Tweens
+-----------------------
The :meth:`pyramid.request.Request.invoke_subrequest` API accepts two
-arguments: a positional argument ``request`` that must be provided, and
-``use_tweens`` keyword argument that is optional; it defaults to ``False``.
+arguments: a required positional argument ``request``, and an optional keyword
+argument ``use_tweens`` which defaults to ``False``.
-The ``request`` object passed to the API must be an object that implements
-the Pyramid request interface (such as a :class:`pyramid.request.Request`
+The ``request`` object passed to the API must be an object that implements the
+Pyramid request interface (such as a :class:`pyramid.request.Request`
instance). If ``use_tweens`` is ``True``, the request will be sent to the
:term:`tween` in the tween stack closest to the request ingress. If
``use_tweens`` is ``False``, the request will be sent to the main router
@@ -153,9 +164,9 @@ handler, and no tweens will be invoked.
In the example above, the call to
:meth:`~pyramid.request.Request.invoke_subrequest` will always raise an
exception. This is because it's using the default value for ``use_tweens``,
-which is ``False``. You can pass ``use_tweens=True`` instead to ensure that
-it will convert an exception to a Response if an :term:`exception view` is
-configured instead of raising the exception. This is because exception views
+which is ``False``. Alternatively, you can pass ``use_tweens=True`` to ensure
+that it will convert an exception to a Response if an :term:`exception view` is
+configured, instead of raising the exception. This is because exception views
are called by the exception view :term:`tween` as described in
:ref:`exception_views` when any view raises an exception.
@@ -164,6 +175,8 @@ We can cause the subrequest to be run through the tween stack by passing
:meth:`~pyramid.request.Request.invoke_subrequest`, like this:
.. code-block:: python
+ :linenos:
+ :emphasize-lines: 7
from wsgiref.simple_server import make_server
from pyramid.config import Configurator
@@ -199,71 +212,70 @@ attempted invocation of ``view_two``, because the tween which invokes an
exception view to generate a response is run, and therefore ``excview`` is
executed.
-This is one of the major differences between specifying the
-``use_tweens=True`` and ``use_tweens=False`` arguments to
+This is one of the major differences between specifying the ``use_tweens=True``
+and ``use_tweens=False`` arguments to
:meth:`~pyramid.request.Request.invoke_subrequest`. ``use_tweens=True`` may
-also imply invoking transaction commit/abort for the logic executed in the
-subrequest if you've got ``pyramid_tm`` in the tween list, injecting debug
-HTML if you've got ``pyramid_debugtoolbar`` in the tween list, and other
+also imply invoking a transaction commit or abort for the logic executed in the
+subrequest if you've got ``pyramid_tm`` in the tween list, injecting debug HTML
+if you've got ``pyramid_debugtoolbar`` in the tween list, and other
tween-related side effects as defined by your particular tween list.
The :meth:`~pyramid.request.Request.invoke_subrequest` function also
-unconditionally:
-
-- manages the threadlocal stack so that
+unconditionally does the following:
+
+- It manages the threadlocal stack so that
:func:`~pyramid.threadlocal.get_current_request` and
- :func:`~pyramid.threadlocal.get_current_registry` work during a request
- (they will return the subrequest instead of the original request)
+ :func:`~pyramid.threadlocal.get_current_registry` work during a request (they
+ will return the subrequest instead of the original request).
-- Adds a ``registry`` attribute and a ``invoke_subrequest`` attribute (a
- callable) to the request object it's handed.
+- It adds a ``registry`` attribute and an ``invoke_subrequest`` attribute (a
+ callable) to the request object to which it is handed.
-- sets request extensions (such as those added via
+- It sets request extensions (such as those added via
:meth:`~pyramid.config.Configurator.add_request_method` or
:meth:`~pyramid.config.Configurator.set_request_property`) on the subrequest
- object passed as ``request``
+ object passed as ``request``.
-- causes a :class:`~pyramid.events.NewRequest` event to be sent at the
+- It causes a :class:`~pyramid.events.NewRequest` event to be sent at the
beginning of request processing.
-- causes a :class:`~pyramid.events.ContextFound` event to be sent when a
+- It causes a :class:`~pyramid.events.ContextFound` event to be sent when a
context resource is found.
-- Ensures that the user implied by the request passed has the necessary
- authorization to invoke view callable before calling it.
+- It ensures that the user implied by the request passed in has the necessary
+ authorization to invoke the view callable before calling it.
-- Calls any :term:`response callback` functions defined within the subrequest's
- lifetime if a response is obtained from the Pyramid application.
+- It calls any :term:`response callback` functions defined within the
+ subrequest's lifetime if a response is obtained from the Pyramid application.
-- causes a :class:`~pyramid.events.NewResponse` event to be sent if a response
- is obtained.
+- It causes a :class:`~pyramid.events.NewResponse` event to be sent if a
+ response is obtained.
-- Calls any :term:`finished callback` functions defined within the subrequest's
- lifetime.
+- It calls any :term:`finished callback` functions defined within the
+ subrequest's lifetime.
-The invocation of a subrequest has more or less exactly the same effect as
-the invocation of a request received by the Pyramid router from a web client
+The invocation of a subrequest has more or less exactly the same effect as the
+invocation of a request received by the :app:`Pyramid` router from a web client
when ``use_tweens=True``. When ``use_tweens=False``, the tweens are skipped
but all the other steps take place.
It's a poor idea to use the original ``request`` object as an argument to
-:meth:`~pyramid.request.Request.invoke_subrequest`. You should construct a
-new request instead as demonstrated in the above example, using
+:meth:`~pyramid.request.Request.invoke_subrequest`. You should construct a new
+request instead as demonstrated in the above example, using
:meth:`pyramid.request.Request.blank`. Once you've constructed a request
-object, you'll need to massage it to match the view callable you'd like
-to be executed during the subrequest. This can be done by adjusting the
+object, you'll need to massage it to match the view callable that you'd like to
+be executed during the subrequest. This can be done by adjusting the
subrequest's URL, its headers, its request method, and other attributes. The
documentation for :class:`pyramid.request.Request` exposes the methods you
-should call and attributes you should set on the request you create to
-massage it into something that will actually match the view you'd like to
-call via a subrequest.
-
-We've demonstrated use of a subrequest from within a view callable, but you
-can use the :meth:`~pyramid.request.Request.invoke_subrequest` API from
-within a tween or an event handler as well. It's usually a poor idea to
-invoke :meth:`~pyramid.request.Request.invoke_subrequest` from within a
-tween, because tweens already by definition have access to a function that
-will cause a subrequest (they are passed a ``handle`` function), but you can
-do it. It's fine to invoke
-:meth:`~pyramid.request.Request.invoke_subrequest` from within an event
-handler, however.
+should call and attributes you should set on the request that you create, then
+massage it into something that will actually match the view you'd like to call
+via a subrequest.
+
+We've demonstrated use of a subrequest from within a view callable, but you can
+use the :meth:`~pyramid.request.Request.invoke_subrequest` API from within a
+tween or an event handler as well. Even though you can do it, it's usually a
+poor idea to invoke :meth:`~pyramid.request.Request.invoke_subrequest` from
+within a tween, because tweens already, by definition, have access to a
+function that will cause a subrequest (they are passed a ``handle`` function).
+It's fine to invoke :meth:`~pyramid.request.Request.invoke_subrequest` from
+within an event handler, however.
diff --git a/docs/narr/tb_introspector.png b/docs/narr/tb_introspector.png
index 4ae406a86..b00d36067 100644
--- a/docs/narr/tb_introspector.png
+++ b/docs/narr/tb_introspector.png
Binary files differ
diff --git a/docs/tutorials/wiki2/basiclayout.rst b/docs/tutorials/wiki2/basiclayout.rst
index 80ae4b34e..695d7f15b 100644
--- a/docs/tutorials/wiki2/basiclayout.rst
+++ b/docs/tutorials/wiki2/basiclayout.rst
@@ -220,7 +220,7 @@ We also need to create a declarative ``Base`` object to use as a
base class for our model:
.. literalinclude:: src/basiclayout/tutorial/models.py
- :lines: 17
+ :lines: 18
:language: py
Our model classes will inherit from this ``Base`` class so they can be