summaryrefslogtreecommitdiff
path: root/docs/narr
diff options
context:
space:
mode:
Diffstat (limited to 'docs/narr')
-rw-r--r--docs/narr/MyProject/myproject/templates/mytemplate.pt172
-rw-r--r--docs/narr/MyProject/myproject/tests.py6
-rw-r--r--docs/narr/advconfig.rst34
-rw-r--r--docs/narr/assets.rst6
-rw-r--r--docs/narr/configuration.rst8
-rw-r--r--docs/narr/csrf.rst63
-rw-r--r--docs/narr/declarative.rst1436
-rw-r--r--docs/narr/environment.rst17
-rw-r--r--docs/narr/events.rst65
-rw-r--r--docs/narr/extending.rst16
-rw-r--r--docs/narr/firstapp.rst6
-rw-r--r--docs/narr/flash.rst107
-rw-r--r--docs/narr/forms.rst126
-rw-r--r--docs/narr/hooks.rst125
-rw-r--r--docs/narr/i18n.rst15
-rw-r--r--docs/narr/install.rst2
-rw-r--r--docs/narr/introduction.rst4
-rw-r--r--docs/narr/muchadoabouttraversal.rst311
-rw-r--r--docs/narr/project.rst61
-rw-r--r--docs/narr/renderers.rst72
-rw-r--r--docs/narr/resourcelocation.rst103
-rw-r--r--docs/narr/resources.rst46
-rw-r--r--docs/narr/router.rst4
-rw-r--r--docs/narr/security.rst37
-rw-r--r--docs/narr/sessions.rst190
-rw-r--r--docs/narr/templates.rst6
-rw-r--r--docs/narr/testing.rst154
-rw-r--r--docs/narr/threadlocals.rst4
-rw-r--r--docs/narr/traversal.rst201
-rw-r--r--docs/narr/urldispatch.rst55
-rw-r--r--docs/narr/viewconfig.rst737
-rw-r--r--docs/narr/views.rst1162
-rw-r--r--docs/narr/zca.rst47
33 files changed, 2026 insertions, 3372 deletions
diff --git a/docs/narr/MyProject/myproject/templates/mytemplate.pt b/docs/narr/MyProject/myproject/templates/mytemplate.pt
index 02fc00eeb..0bfea9d53 100644
--- a/docs/narr/MyProject/myproject/templates/mytemplate.pt
+++ b/docs/narr/MyProject/myproject/templates/mytemplate.pt
@@ -1,76 +1,106 @@
-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
-<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" xmlns:tal="http://xml.zope.org/namespaces/tal">
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml"
+ xml:lang="en"
+ xmlns:tal="http://xml.zope.org/namespaces/tal">
<head>
- <title>The Pyramid Web Application Development Framework</title>
- <meta http-equiv="Content-Type" content="text/html;charset=UTF-8"/>
- <meta name="keywords" content="python web application" />
- <meta name="description" content="pyramid web application" />
- <link rel="shortcut icon" href="${request.application_url}/static/favicon.ico" />
- <link rel="stylesheet" href="${request.application_url}/static/pylons.css" type="text/css" media="screen" charset="utf-8" />
- <link href="http://fonts.googleapis.com/css?family=Neuton&amp;subset=latin" rel="stylesheet" type="text/css" media="screen" charset="utf-8" />
- <link rel="stylesheet" href="http://fonts.googleapis.com/css?family=Nobile:regular,italic,bold,bolditalic&amp;subset=latin" type="text/css" media="screen" charset="utf-8" />
- <!--[if lte IE 6]>
- <link rel="stylesheet" href="${request.application_url}/static/ie6.css" type="text/css" media="screen" charset="utf-8" />
- <![endif]-->
+ <title>The Pyramid Web Application Development Framework</title>
+ <meta http-equiv="Content-Type" content="text/html;charset=UTF-8"/>
+ <meta name="keywords" content="python web application" />
+ <meta name="description" content="pyramid web application" />
+ <link rel="shortcut icon"
+ href="${request.static_url('myproject:static/favicon.ico')}" />
+ <link rel="stylesheet"
+ href="${request.static_url('myproject:static/pylons.css')}"
+ type="text/css" media="screen" charset="utf-8" />
+ <link rel="stylesheet"
+ href="http://fonts.googleapis.com/css?family=Neuton|Nobile:regular,i,b,bi&amp;subset=latin"
+ type="text/css" media="screen" charset="utf-8" />
+ <!--[if lte IE 6]>
+ <link rel="stylesheet"
+ href="${request.static_url('myproject:static/ie6.css')}"
+ type="text/css" media="screen" charset="utf-8" />
+ <![endif]-->
</head>
<body>
- <div id="wrap">
- <div id="top">
- <div class="top align-center">
- <div><img src="${request.application_url}/static/pyramid.png" width="750" height="169" alt="pyramid"/></div>
- </div>
- </div>
- <div id="middle">
- <div class="middle align-center">
- <p class="app-welcome">
- Welcome to <span class="app-name">${project}</span>, an application generated by<br/>
- the Pyramid web application development framework.
- </p>
- </div>
- </div>
- <div id="bottom">
- <div class="bottom">
- <div id="left" class="align-right">
- <h2>Search documentation</h2>
- <form method="get" action="http://docs.pylonshq.com/pyramid/dev/search.html">
- <input type="text" id="q" name="q" value="" />
- <input type="submit" id="x" value="Go" />
- </form>
- </div>
- <div id="right" class="align-left">
- <h2>Pyramid links</h2>
- <ul class="links">
- <li>
- <a href="http://pylonshq.com">Pylons Website</a>
- </li>
- <li>
- <a href="http://docs.pylonshq.com/pyramid/dev/#narrative-documentation">Narrative Documentation</a>
- </li>
- <li>
- <a href="http://docs.pylonshq.com/pyramid/dev/#api-documentation">API Documentation</a>
- </li>
- <li>
- <a href="http://docs.pylonshq.com/pyramid/dev/#tutorials">Tutorials</a>
- </li>
- <li>
- <a href="http://docs.pylonshq.com/pyramid/dev/#change-history">Change History</a>
- </li>
- <li>
- <a href="http://docs.pylonshq.com/pyramid/dev/#sample-applications">Sample Applications</a>
- </li>
- <li>
- <a href="http://docs.pylonshq.com/pyramid/dev/#support-and-development">Support and Development</a>
- </li>
- <li>
- <a href="irc://irc.freenode.net#pyramid">IRC Channel</a>
- </li>
- </ul>
- </div>
- </div>
- </div>
- </div>
- <div id="footer">
- <div class="footer">© Copyright 2008-2010, Agendaless Consulting.</div>
- </div>
+ <div id="wrap">
+ <div id="top">
+ <div class="top align-center">
+ <div>
+ <img src="${request.static_url('myproject:static/pyramid.png')}"
+ width="750" height="169" alt="pyramid"/>
+ </div>
+ </div>
+ </div>
+ <div id="middle">
+ <div class="middle align-center">
+ <p class="app-welcome">
+ Welcome to <span class="app-name">${project}</span>,
+ an application generated by<br/>
+ the Pyramid web application development framework.
+ </p>
+ </div>
+ </div>
+ <div id="bottom">
+ <div class="bottom">
+ <div id="left" class="align-right">
+ <h2>Search documentation</h2>
+ <form method="get"
+ action="http://docs.pylonsproject.org/pyramid/dev/search.html">
+ <input type="text" id="q" name="q" value="" />
+ <input type="submit" id="x" value="Go" />
+ </form>
+ </div>
+ <div id="right" class="align-left">
+ <h2>Pyramid links</h2>
+ <ul class="links">
+ <li>
+ <a href="http://pylonsproject.org">
+ Pylons Website
+ </a>
+ </li>
+ <li>
+ <a href="http://docs.pylonsproject.org/projects/pyramid/dev/#narrative-documentation">
+ Narrative Documentation
+ </a>
+ </li>
+ <li>
+ <a href="http://docs.pylonsproject.org/projects/pyramid/dev/#api-documentation">
+ API Documentation
+ </a>
+ </li>
+ <li>
+ <a href="http://docs.pylonsproject.org/projects/pyramid/dev/#tutorials">
+ Tutorials
+ </a>
+ </li>
+ <li>
+ <a href="http://docs.pylonsproject.org/projects/pyramid/dev/#change-history">
+ Change History
+ </a>
+ </li>
+ <li>
+ <a href="http://docs.pylonsproject.org/projects/pyramid/dev/#sample-applications">
+ Sample Applications
+ </a>
+ </li>
+ <li>
+ <a href="http://docs.pylonsproject.org/projects/pyramid/dev/#support-and-development">
+ Support and Development
+ </a>
+ </li>
+ <li>
+ <a href="irc://irc.freenode.net#pyramid">
+ IRC Channel
+ </a>
+ </li>
+ </ul>
+ </div>
+ </div>
+ </div>
+ </div>
+ <div id="footer">
+ <div class="footer">© Copyright 2008-2010, Agendaless Consulting.</div>
+ </div>
</body>
</html> \ No newline at end of file
diff --git a/docs/narr/MyProject/myproject/tests.py b/docs/narr/MyProject/myproject/tests.py
index b14fb37af..5fa710278 100644
--- a/docs/narr/MyProject/myproject/tests.py
+++ b/docs/narr/MyProject/myproject/tests.py
@@ -1,15 +1,13 @@
import unittest
-from pyramid.config import Configurator
from pyramid import testing
class ViewTests(unittest.TestCase):
def setUp(self):
- self.config = Configurator(autocommit=True)
- self.config.begin()
+ self.config = testing.setUp()
def tearDown(self):
- self.config.end()
+ testing.tearDown()
def test_my_view(self):
from myproject.views import my_view
diff --git a/docs/narr/advconfig.rst b/docs/narr/advconfig.rst
index f8b3ee191..30f76e456 100644
--- a/docs/narr/advconfig.rst
+++ b/docs/narr/advconfig.rst
@@ -115,11 +115,8 @@ allowing the circumstance to go unreported, by default Pyramid raises a
running.
Conflict detection happens for any kind of configuration: imperative
-configuration, :term:`ZCML` configuration, or configuration that results from
-the execution of a :term:`scan`.
-
-.. note:: If you use, ZCML, its conflict detection algorithm is described in
- :ref:`zcml_conflict_detection`.
+configuration or configuration that results from the execution of a
+:term:`scan`.
Manually Resolving Conflicts
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -274,7 +271,7 @@ 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. See also
+the "include" method.
Automatic conflict resolution supports this goal: if a user wants to reuse a
Pyramid application, and they want to customize the configuration of this
@@ -301,9 +298,6 @@ These are the methods of the configurator which provide conflict detection:
Some other methods of the configurator also indirectly provide conflict
detection, because they're implemented in terms of conflict-aware methods:
-- :meth:`~pyramid.config.Configurator.add_handler`, a frontend for
- ``add_route`` and ``add_view``.
-
- :meth:`~pyramid.config.Configurator.add_route` does a second type of
conflict detection when a ``view`` parameter is passed (it calls
``add_view``).
@@ -338,6 +332,23 @@ Instead, use :meth:`pyramid.config.Configuration.include`:
Using ``include`` rather than calling the function directly will allow
:ref:`automatic_conflict_resolution` to work.
+:meth:`pyramid.config.Configuration.include` can also accept a :term:`module`
+as an argument:
+
+.. code-block:: python
+ :linenos:
+
+ import myapp
+
+ config.include(myapp)
+
+For this to work properly, the ``myapp`` module must contain a callable with
+the special name ``includeme``, which should perform configuration (like the
+``add_routes`` callable we showed above as an example).
+
+:meth:`pyramid.config.Configuration.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
:meth:`pyramid.config.Configurator.include`.
@@ -387,9 +398,8 @@ 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` and
-:meth:`pyramid.config.Configurator.add_handler` have internal ordering
-constraints: they routes they imply require relative ordering. Such ordering
+:meth:`pyramid.config.Configurator.add_route` have internal ordering
+constraints: the routes they imply require relative ordering. Such ordering
constraints are not absolved by two-phase configuration. Routes are still
added in configuration execution order.
diff --git a/docs/narr/assets.rst b/docs/narr/assets.rst
index f147426ce..b1c1c419c 100644
--- a/docs/narr/assets.rst
+++ b/docs/narr/assets.rst
@@ -98,7 +98,7 @@ directory on a filesystem to an application user's browser. Use the
mechanism makes a directory of static files available at a name relative to
the application root URL, e.g. ``/static`` or as an external URL.
-.. note:: `~pyramid.config.Configurator.add_static_view` cannot serve a
+.. note:: :meth:`~pyramid.config.Configurator.add_static_view` cannot serve a
single file, nor can it serve a directory of static files directly
relative to the root URL of a :app:`Pyramid` application. For these
features, see :ref:`advanced_static`.
@@ -282,7 +282,7 @@ create such a circumstance, we suggest using the
in the application ``.ini`` file named ``media_location``. Then set the
value of ``media_location`` to either a prefix or a URL depending on whether
the application is being run in development or in production (use a different
-`.ini`` file for production than you do for development). This is just a
+``.ini`` file for production than you do for development). This is just a
suggestion for a pattern; any setting name other than ``media_location``
could be used.
@@ -345,7 +345,7 @@ application's startup code.
.. code-block:: python
:linenos:
- # .. every other add_route and/or add_handler declaration should come
+ # .. every other add_route declaration should come
# before this one, as it will, by default, catch all requests
config.add_route('catchall_static', '/*subpath', 'myapp.static.static_view')
diff --git a/docs/narr/configuration.rst b/docs/narr/configuration.rst
index 394603946..05bc4d6cc 100644
--- a/docs/narr/configuration.rst
+++ b/docs/narr/configuration.rst
@@ -151,9 +151,7 @@ Declarative Configuration
A third mode of configuration can be employed when you create a
:app:`Pyramid` application named *declarative configuration*. This mode uses
an XML language known as :term:`ZCML` to represent configuration statements
-rather than Python. ZCML is often used when application extensibility is
-important. Most of the examples in the narrative portion of this
-documentation concentrate on imperative configuration rather than ZCML, but
-almost everything that can be configured imperatively can also be configured
-via ZCML. See :ref:`declarative_chapter` for more information about ZCML.
+rather than Python. ZCML is not built-in to Pyramid, but almost everything
+that can be configured imperatively can also be configured via ZCML if you
+install the :term:`pyramid_zcml` package.
diff --git a/docs/narr/csrf.rst b/docs/narr/csrf.rst
deleted file mode 100644
index 7586b0ed7..000000000
--- a/docs/narr/csrf.rst
+++ /dev/null
@@ -1,63 +0,0 @@
-.. _csrf_chapter:
-
-Preventing Cross-Site Request Forgery Attacks
-=============================================
-
-`Cross-site request forgery
-<http://en.wikipedia.org/wiki/Cross-site_request_forgery>`_ attacks are a
-phenomenon whereby a user with an identity on your website might click on a
-URL or button on another website which unwittingly redirects the user to your
-application to perform some command that requires elevated privileges.
-
-You can avoid most of these attacks by making sure that a the correct *CSRF
-token* has been set in an :app:`Pyramid` session object before performing any
-actions in code which requires elevated privileges and is invoked via a form
-post. To use CSRF token support, you must enable a :term:`session factory`
-as described in :ref:`using_the_default_session_factory` or
-:ref:`using_alternate_session_factories`.
-
-Using the ``session.new_csrf_token`` Method
--------------------------------------------
-
-To add a CSRF token to the session, use the ``session.new_csrf_token`` method.
-
-.. code-block:: python
- :linenos:
-
- token = request.session.new_csrf_token()
-
-The ``.new_csrf_token`` method accepts no arguments. It returns a *token*
-string, which will be opaque and randomized. This token will also be set
-into the session, awaiting pickup by the ``session.get_csrf_token`` method.
-You can subsequently use the returned token as the value of a hidden field in
-a form that posts to a method that requires elevated privileges. The handler
-for the form post should use ``session.get_csrf_token`` (explained below) to
-obtain the current CSRF token related to the user from the session, and
-compare it to the value of the hidden form field.
-
-Using the ``session.get_csrf_token`` Method
--------------------------------------------
-
-To get the current CSRF token from the session, use the
-``session.get_csrf_token`` method.
-
-.. code-block:: python
- :linenos:
-
- token = request.session.get_csrf_token()
-
-The ``get_csrf_token`` method accepts no arguments. It returns the "current"
-*token* string (as per the last call to ``session.new_csrf_token``). You can
-then use it to compare against the token provided within form post hidden
-value data. For example, if your form rendering included the CSRF token
-obtained via ``session.new_csrf_token`` as a hidden input field named
-``csrf_token``:
-
-.. code-block:: python
- :linenos:
-
- token = request.session.get_csrf_token()
- if token != request.POST['csrf_token']:
- raise ValueError('CSRF token did not match')
-
-
diff --git a/docs/narr/declarative.rst b/docs/narr/declarative.rst
deleted file mode 100644
index f36e55b29..000000000
--- a/docs/narr/declarative.rst
+++ /dev/null
@@ -1,1436 +0,0 @@
-.. _declarative_chapter:
-
-Declarative Configuration
-=========================
-
-The mode of configuration detailed in the majority of examples within this
-this book is "imperative" configuration. This is the configuration mode in
-which a developer cedes the least amount of control to the framework; it's
-"imperative" because you express the configuration directly in Python code,
-and you have the full power of Python at your disposal as you issue
-configuration statements. However, another mode of configuration exists
-within :app:`Pyramid` named :term:`ZCML` which often provides better
-opportunity for extensibility.
-
-A complete listing of ZCML directives is available within
-:ref:`zcml_directives`. This chapter provides an overview of how you might
-get started with ZCML and highlights some common tasks performed when you use
-ZCML.
-
-.. index::
- single: declarative configuration
-
-.. _declarative_configuration:
-
-ZCML Configuration
-------------------
-
-A :app:`Pyramid` application can be configured "declaratively", if so
-desired. Declarative configuration relies on *declarations* made external to
-the code in a configuration file format named :term:`ZCML` (Zope
-Configuration Markup Language), an XML dialect.
-
-A :app:`Pyramid` application configured declaratively requires not
-one, but two files: a Python file and a :term:`ZCML` file.
-
-In a file named ``helloworld.py``:
-
-.. code-block:: python
- :linenos:
-
- from paste.httpserver import serve
- from pyramid.response import Response
- from pyramid.config import Configurator
-
- def hello_world(request):
- return Response('Hello world!')
-
- if __name__ == '__main__':
- config = Configurator()
- config.load_zcml('configure.zcml')
- app = config.make_wsgi_app()
- serve(app, host='0.0.0.0')
-
-In a file named ``configure.zcml`` in the same directory as the
-previously created ``helloworld.py``:
-
-.. code-block:: xml
- :linenos:
-
- <configure xmlns="http://pylonshq.com/pyramid">
-
- <include package="pyramid.includes" />
-
- <view
- view="helloworld.hello_world"
- />
-
- </configure>
-
-This pair of files forms an application functionally equivalent to the
-application we created earlier in :ref:`imperative_configuration`.
-Let's examine the differences between that code listing and the code
-above.
-
-In :ref:`imperative_configuration`, we had the following lines within
-the ``if __name__ == '__main__'`` section of ``helloworld.py``:
-
-.. code-block:: python
- :linenos:
-
- if __name__ == '__main__':
- config = Configurator()
- config.add_view(hello_world)
- app = config.make_wsgi_app()
- serve(app, host='0.0.0.0')
-
-In our "declarative" code, we've removed the call to ``add_view`` and
-replaced it with a call to the
-:meth:`pyramid.config.Configurator.load_zcml` method so that
-it now reads as:
-
-.. code-block:: python
- :linenos:
-
- if __name__ == '__main__':
- config = Configurator()
- config.load_zcml('configure.zcml')
- app = config.make_wsgi_app()
- serve(app, host='0.0.0.0')
-
-Everything else is much the same.
-
-The ``config.load_zcml('configure.zcml')`` line tells the configurator
-to load configuration declarations from the file named
-``configure.zcml`` which sits next to ``helloworld.py`` on the
-filesystem. Let's take a look at that ``configure.zcml`` file again:
-
-.. code-block:: xml
- :linenos:
-
- <configure xmlns="http://pylonshq.com/pyramid">
-
- <include package="pyramid.includes" />
-
- <view
- view="helloworld.hello_world"
- />
-
- </configure>
-
-Note that this file contains some XML, and that the XML contains a
-``<view>`` :term:`configuration declaration` tag that references a
-:term:`dotted Python name`. This dotted name refers to the
-``hello_world`` function that lives in our ``helloworld`` Python
-module.
-
-This ``<view>`` declaration tag performs the same function as the
-``add_view`` method that was employed within
-:ref:`imperative_configuration`. In fact, the ``<view>`` tag is
-effectively a "macro" which calls the
-:meth:`pyramid.config.Configurator.add_view` method on your
-behalf.
-
-The ``<view>`` tag is an example of a :app:`Pyramid` declaration
-tag. Other such tags include ``<route>`` and ``<scan>``. Each of
-these tags is effectively a "macro" which calls methods of a
-:class:`pyramid.config.Configurator` object on your behalf.
-
-Essentially, using a :term:`ZCML` file and loading it from the
-filesystem allows us to put our configuration statements within this
-XML file rather as declarations, rather than representing them as
-method calls to a :term:`Configurator` object. Otherwise, declarative
-and imperative configuration are functionally equivalent.
-
-Using declarative configuration has a number of benefits, the primary
-benefit being that applications configured declaratively can be
-*overridden* and *extended* by third parties without requiring the
-third party to change application code. If you want to build a
-framework or an extensible application, using declarative
-configuration is a good idea.
-
-Declarative configuration has an obvious downside: you can't use
-plain-old-Python syntax you probably already know and understand to
-configure your application; instead you need to use :term:`ZCML`.
-
-.. index::
- single: ZCML conflict detection
-
-.. _zcml_conflict_detection:
-
-ZCML Conflict Detection
-~~~~~~~~~~~~~~~~~~~~~~~
-
-A minor additional feature of ZCML is *conflict detection*. If you
-define two declaration tags within the same ZCML file which logically
-"collide", an exception will be raised, and the application will not
-start. For example, the following ZCML file has two conflicting
-``<view>`` tags:
-
-.. code-block:: xml
- :linenos:
-
- <configure xmlns="http://pylonshq.com/pyramid">
-
- <include package="pyramid.includes" />
-
- <view
- view="helloworld.hello_world"
- />
-
- <view
- view="helloworld.hello_world"
- />
-
- </configure>
-
-If you try to use this ZCML file as the source of ZCML for an
-application, an error will be raised when you attempt to start the
-application. This error will contain information about which tags
-might have conflicted.
-
-.. index::
- single: helloworld (declarative)
-
-.. _helloworld_declarative:
-
-Hello World, Goodbye World (Declarative)
-----------------------------------------
-
-Another almost entirely equivalent mode of application configuration
-exists named *declarative* configuration. :app:`Pyramid` can be
-configured for the same "hello world" application "declaratively", if
-so desired.
-
-To do so, first, create a file named ``helloworld.py``:
-
-.. code-block:: python
- :linenos:
-
- from pyramid.config import Configurator
- from pyramid.response import Response
- from paste.httpserver import serve
-
- def hello_world(request):
- return Response('Hello world!')
-
- def goodbye_world(request):
- return Response('Goodbye world!')
-
- if __name__ == '__main__':
- config = Configurator()
- config.load_zcml('configure.zcml')
- app = config.make_wsgi_app()
- serve(app, host='0.0.0.0')
-
-Then create a file named ``configure.zcml`` in the same directory as
-the previously created ``helloworld.py``:
-
-.. code-block:: xml
- :linenos:
-
- <configure xmlns="http://pylonshq.com/pyramid">
-
- <include package="pyramid.includes" />
-
- <view
- view="helloworld.hello_world"
- />
-
- <view
- name="goodbye"
- view="helloworld.goodbye_world"
- />
-
- </configure>
-
-This pair of files forms an application functionally equivalent to the
-application we created earlier in :ref:`helloworld_imperative`. We can run
-it the same way.
-
-.. code-block:: text
-
- $ python helloworld.py
- serving on 0.0.0.0:8080 view at http://127.0.0.1:8080
-
-Let's examine the differences between the code in that section and the code
-above. In :ref:`helloworld_imperative_appconfig`, we had the following lines
-within the ``if __name__ == '__main__'`` section of ``helloworld.py``:
-
-.. code-block:: python
- :linenos:
-
- if __name__ == '__main__':
- config = Configurator()
- config.add_view(hello_world)
- config.add_view(goodbye_world, name='goodbye')
- app = config.make_wsgi_app()
- serve(app, host='0.0.0.0')
-
-In our "declarative" code, we've added a call to the
-:meth:`pyramid.config.Configurator.load_zcml` method with
-the value ``configure.zcml``, and we've removed the lines which read
-``config.add_view(hello_world)`` and ``config.add_view(goodbye_world,
-name='goodbye')``, so that it now reads as:
-
-.. code-block:: python
- :linenos:
-
- if __name__ == '__main__':
- config = Configurator()
- config.load_zcml('configure.zcml')
- app = config.make_wsgi_app()
- serve(app, host='0.0.0.0')
-
-Everything else is much the same.
-
-The ``config.load_zcml('configure.zcml')`` line tells the configurator
-to load configuration declarations from the ``configure.zcml`` file
-which sits next to ``helloworld.py``. Let's take a look at the
-``configure.zcml`` file now:
-
-.. code-block:: xml
- :linenos:
-
- <configure xmlns="http://pylonshq.com/pyramid">
-
- <include package="pyramid.includes" />
-
- <view
- view="helloworld.hello_world"
- />
-
- <view
- name="goodbye"
- view="helloworld.goodbye_world"
- />
-
- </configure>
-
-We already understand what the view code does, because the application
-is functionally equivalent to the application described in
-:ref:`helloworld_imperative`, but use of :term:`ZCML` is new. Let's
-break that down tag-by-tag.
-
-The ``<configure>`` Tag
-~~~~~~~~~~~~~~~~~~~~~~~
-
-The ``configure.zcml`` ZCML file contains this bit of XML:
-
-.. code-block:: xml
- :linenos:
-
- <configure xmlns="http://pylonshq.com/pyramid">
-
- <!-- other directives -->
-
- </configure>
-
-Because :term:`ZCML` is XML, and because XML requires a single root
-tag for each document, every ZCML file used by :app:`Pyramid` must
-contain a ``configure`` container directive, which acts as the root
-XML tag. It is a "container" directive because its only job is to
-contain other directives.
-
-See also :ref:`configure_directive` and :ref:`word_on_xml_namespaces`.
-
-.. _the_include_tag:
-
-The ``<include>`` Tag
-~~~~~~~~~~~~~~~~~~~~~
-
-The ``configure.zcml`` ZCML file contains this bit of XML within the
-``<configure>`` root tag:
-
-.. code-block:: xml
- :linenos:
-
- <include package="pyramid.includes" />
-
-This self-closing tag instructs :app:`Pyramid` to load a ZCML file
-from the Python package with the :term:`dotted Python name`
-``pyramid.includes``, as specified by its ``package`` attribute.
-This particular ``<include>`` declaration is required because it
-actually allows subsequent declaration tags (such as ``<view>``, which
-we'll see shortly) to be recognized. The ``<include>`` tag
-effectively just includes another ZCML file, causing its declarations
-to be executed. In this case, we want to load the declarations from
-the file named ``configure.zcml`` within the
-:mod:`pyramid.includes` Python package. We know we want to load
-the ``configure.zcml`` from this package because ``configure.zcml`` is
-the default value for another attribute of the ``<include>`` tag named
-``file``. We could have spelled the include tag more verbosely, but
-equivalently as:
-
-.. code-block:: xml
- :linenos:
-
- <include package="pyramid.includes"
- file="configure.zcml"/>
-
-The ``<include>`` tag that includes the ZCML statements implied by the
-``configure.zcml`` file from the Python package named
-:mod:`pyramid.includes` is basically required to come before any
-other named declaration in an application's ``configure.zcml``. If it
-is not included, subsequent declaration tags will fail to be
-recognized, and the configuration system will generate an error at
-startup. However, the ``<include package="pyramid.includes"/>``
-tag needs to exist only in a "top-level" ZCML file, it needn't also
-exist in ZCML files *included by* a top-level ZCML file.
-
-See also :ref:`include_directive`.
-
-The ``<view>`` Tag
-~~~~~~~~~~~~~~~~~~
-
-The ``configure.zcml`` ZCML file contains these bits of XML *after* the
-``<include>`` tag, but *within* the ``<configure>`` root tag:
-
-.. code-block:: xml
- :linenos:
-
- <view
- view="helloworld.hello_world"
- />
-
- <view
- name="goodbye"
- view="helloworld.goodbye_world"
- />
-
-These ``<view>`` declaration tags direct :app:`Pyramid` to create
-two :term:`view configuration` registrations. The first ``<view>``
-tag has an attribute (the attribute is also named ``view``), which
-points at a :term:`dotted Python name`, referencing the
-``hello_world`` function defined within the ``helloworld`` package.
-The second ``<view>`` tag has a ``view`` attribute which points at a
-:term:`dotted Python name`, referencing the ``goodbye_world`` function
-defined within the ``helloworld`` package. The second ``<view>`` tag
-also has an attribute called ``name`` with a value of ``goodbye``.
-
-These effect of the ``<view>`` tag declarations we've put into our
-``configure.zcml`` is functionally equivalent to the effect of lines
-we've already seen in an imperatively-configured application. We're
-just spelling things differently, using XML instead of Python.
-
-In our previously defined application, in which we added view
-configurations imperatively, we saw this code:
-
-.. ignore-next-block
-.. code-block:: python
- :linenos:
-
- config.add_view(hello_world)
- config.add_view(goodbye_world, name='goodbye')
-
-Each ``<view>`` declaration tag encountered in a ZCML file effectively
-invokes the :meth:`pyramid.config.Configurator.add_view`
-method on the behalf of the developer. Various attributes can be
-specified on the ``<view>`` tag which influence the :term:`view
-configuration` it creates.
-
-Since the relative ordering of calls to
-:meth:`pyramid.config.Configurator.add_view` doesn't matter
-(see the sidebar entitled *View Dispatch and Ordering* within
-:ref:`adding_configuration`), the relative order of ``<view>`` tags in
-ZCML doesn't matter either. The following ZCML orderings are
-completely equivalent:
-
-.. topic:: Hello Before Goodbye
-
- .. code-block:: xml
- :linenos:
-
- <view
- view="helloworld.hello_world"
- />
-
- <view
- name="goodbye"
- view="helloworld.goodbye_world"
- />
-
-.. topic:: Goodbye Before Hello
-
- .. code-block:: xml
- :linenos:
-
- <view
- name="goodbye"
- view="helloworld.goodbye_world"
- />
-
- <view
- view="helloworld.hello_world"
- />
-
-We've now configured a :app:`Pyramid` helloworld application
-declaratively. More information about this mode of configuration is
-available in :ref:`declarative_configuration` and within
-:ref:`zcml_reference`.
-
-.. index::
- single: ZCML granularity
-
-ZCML Granularity
-~~~~~~~~~~~~~~~~
-
-It's extremely helpful to third party application "extenders" (aka
-"integrators") if the :term:`ZCML` that composes the configuration for an
-application is broken up into separate files which do very specific things.
-These more specific ZCML files can be reintegrated within the application's
-main ``configure.zcml`` via ``<include file="otherfile.zcml"/>``
-declarations. When ZCML files contain sets of specific declarations, an
-integrator can avoid including any ZCML he does not want by including only
-ZCML files which contain the declarations he needs. He is not forced to
-"accept everything" or "use nothing".
-
-For example, it's often useful to put all ``<route>`` declarations in a
-separate ZCML file, as ``<route>`` statements have a relative ordering that
-is extremely important to the application: if an extender wants to add a
-route to the "middle" of the routing table, he will always need to disuse all
-the routes and cut and paste the routing configuration into his own
-application. It's useful for the extender to be able to disuse just a
-*single* ZCML file in this case, accepting the remainder of the configuration
-from other :term:`ZCML` files in the original application.
-
-Granularizing ZCML is not strictly required. An extender can always disuse
-*all* your ZCML, choosing instead to copy and paste it into his own package,
-if necessary. However, doing so is considerate, and allows for the best
-reusability. Sometimes it's possible to include only certain ZCML files from
-an application that contain only the registrations you really need, omitting
-others. But sometimes it's not. For brute force purposes, when you're
-getting ``view`` or ``route`` registrations that you don't actually want in
-your overridden application, it's always appropriate to just *not include*
-any ZCML file from the overridden application. Instead, just cut and paste
-the entire contents of the ``configure.zcml`` (and any ZCML file included by
-the overridden application's ``configure.zcml``) into your own package and
-omit the ``<include package=""/>`` ZCML declaration in the overriding
-package's ``configure.zcml``.
-
-.. _zcml_scanning:
-
-Scanning via ZCML
------------------
-
-:term:`ZCML` can invoke a :term:`scan` via its ``<scan>`` directive. If a
-ZCML file is processed that contains a scan directive, the package the ZCML
-file points to is scanned.
-
-.. code-block:: python
- :linenos:
-
- # helloworld.py
-
- from paste.httpserver import serve
- from pyramid.response import Response
- from pyramid.view import view_config
-
- @view_config()
- def hello(request):
- return Response('Hello')
-
- if __name__ == '__main__':
- from pyramid.config import Configurator
- config = Configurator()
- config.load_zcml('configure.zcml')
- app = config.make_wsgi_app()
- serve(app, host='0.0.0.0')
-
-.. code-block:: xml
- :linenos:
-
- <configure xmlns="http://namespaces.repoze.org">
-
- <!-- configure.zcml -->
-
- <include package="pyramid.includes"/>
- <scan package="."/>
-
- </configure>
-
-See also :ref:`scan_directive`.
-
-Which Mode Should I Use?
-------------------------
-
-A combination of imperative configuration, declarative configuration
-via ZCML and scanning can be used to configure any application. They
-are not mutually exclusive.
-
-The :app:`Pyramid` authors often recommend using mostly declarative
-configuration, because it's the more traditional form of configuration
-used in :app:`Pyramid` applications, it can be overridden and
-extended by third party deployers, and there are more examples for it
-"in the wild".
-
-However, imperative mode configuration can be simpler to understand,
-and the framework is not "opinionated" about the choice. This book
-presents examples in both styles, mostly interchangeably. You can
-choose the mode that best fits your brain as necessary.
-
-.. index::
- single: ZCML view configuration
-
-.. _mapping_views_using_zcml_section:
-
-View Configuration Via ZCML
-~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-You may associate a view with a URL by adding :ref:`view_directive`
-declarations via :term:`ZCML` in a ``configure.zcml`` file. An
-example of a view declaration in ZCML is as follows:
-
-.. code-block:: xml
- :linenos:
-
- <view
- context=".resources.Hello"
- view=".views.hello_world"
- name="hello.html"
- />
-
-The above maps the ``.views.hello_world`` view callable function to
-the following set of :term:`resource location` results:
-
-- A :term:`context` object which is an instance (or subclass) of the
- Python class represented by ``.resources.Hello``
-
-- A :term:`view name` equalling ``hello.html``.
-
-.. note:: Values prefixed with a period (``.``) for the ``context``
- and ``view`` attributes of a ``view`` declaration (such as those
- above) mean "relative to the Python package directory in which this
- :term:`ZCML` file is stored". So if the above ``view`` declaration
- was made inside a ``configure.zcml`` file that lived in the
- ``hello`` package, you could replace the relative ``.resources.Hello``
- with the absolute ``hello.resources.Hello``; likewise you could
- replace the relative ``.views.hello_world`` with the absolute
- ``hello.views.hello_world``. Either the relative or absolute form
- is functionally equivalent. It's often useful to use the relative
- form, in case your package's name changes. It's also shorter to
- type.
-
-You can also declare a *default view callable* for a :term:`resource` type:
-
-.. code-block:: xml
- :linenos:
-
- <view
- context=".resources.Hello"
- view=".views.hello_world"
- />
-
-A *default view callable* simply has no ``name`` attribute. For the above
-registration, when a :term:`context` is found that is of the type
-``.resources.Hello`` and there is no :term:`view name` associated with the
-result of :term:`resource location`, the *default view callable* will be
-used. In this case, it's the view at ``.views.hello_world``.
-
-A default view callable can alternately be defined by using the empty
-string as its ``name`` attribute:
-
-.. code-block:: xml
- :linenos:
-
- <view
- context=".resources.Hello"
- view=".views.hello_world"
- name=""
- />
-
-You may also declare that a view callable is good for any context type
-by using the special ``*`` character as the value of the ``context``
-attribute:
-
-.. code-block:: xml
- :linenos:
-
- <view
- context="*"
- view=".views.hello_world"
- name="hello.html"
- />
-
-This indicates that when :app:`Pyramid` identifies that the
-:term:`view name` is ``hello.html`` and the context is of any type,
-the ``.views.hello_world`` view callable will be invoked.
-
-A ZCML ``view`` declaration's ``view`` attribute can also name a
-class. In this case, the rules described in :ref:`class_as_view`
-apply for the class which is named.
-
-See :ref:`view_directive` for complete ZCML directive documentation.
-
-.. index::
- single: ZCML directive; route
-
-.. _zcml_route_configuration:
-
-Configuring a Route via ZCML
-----------------------------
-
-Instead of using the imperative :meth:`pyramid.config.Configurator.add_route`
-method to add a new route, you can alternately use :term:`ZCML`.
-:ref:`route_directive` statements in a :term:`ZCML` file. For example, the
-following :term:`ZCML declaration` causes a route to be added to the
-application.
-
-.. code-block:: xml
- :linenos:
-
- <route
- name="myroute"
- pattern="/prefix/{one}/{two}"
- view=".views.myview"
- />
-
-.. note::
-
- Values prefixed with a period (``.``) within the values of ZCML
- attributes such as the ``view`` attribute of a ``route`` mean
- "relative to the Python package directory in which this
- :term:`ZCML` file is stored". So if the above ``route``
- declaration was made inside a ``configure.zcml`` file that lived in
- the ``hello`` package, you could replace the relative
- ``.views.myview`` with the absolute ``hello.views.myview`` Either
- the relative or absolute form is functionally equivalent. It's
- often useful to use the relative form, in case your package's name
- changes. It's also shorter to type.
-
-The order that routes are evaluated when declarative configuration is used
-is the order that they appear relative to each other in the ZCML file.
-
-See :ref:`route_directive` for full ``route`` ZCML directive
-documentation.
-
-.. _zcml_handler_configuration:
-
-Configuring a Handler via ZCML
-------------------------------
-
-Instead of using the imperative
-:meth:`pyramid.config.Configurator.add_handler` method to add a new
-route, you can alternately use :term:`ZCML`. :ref:`handler_directive`
-statements in a :term:`ZCML` file used by your application is a sign that
-you're using :term:`URL dispatch`. For example, the following :term:`ZCML
-declaration` causes a route to be added to the application.
-
-.. code-block:: xml
- :linenos:
-
- <handler
- route_name="myroute"
- pattern="/prefix/{action}"
- handler=".handlers.MyHandler"
- />
-
-.. note::
-
- Values prefixed with a period (``.``) within the values of ZCML attributes
- such as the ``handler`` attribute of a ``handler`` directive mean
- "relative to the Python package directory in which this :term:`ZCML` file
- is stored". So if the above ``handler`` declaration was made inside a
- ``configure.zcml`` file that lived in the ``hello`` package, you could
- replace the relative ``.views.MyHandler`` with the absolute
- ``hello.views.MyHandler`` Either the relative or absolute form is
- functionally equivalent. It's often useful to use the relative form, in
- case your package's name changes. It's also shorter to type.
-
-The order that the routes attached to handlers are evaluated when declarative
-configuration is used is the order that they appear relative to each other in
-the ZCML file.
-
-See :ref:`handler_directive` for full ``handler`` ZCML directive
-documentation.
-
-.. index::
- triple: view; zcml; static resource
-
-.. _zcml_static_assets_section:
-
-Serving Static Assets Using ZCML
---------------------------------
-
-Use of the ``static`` ZCML directive makes static assets available at a name
-relative to the application root URL, e.g. ``/static``.
-
-Note that the ``path`` provided to the ``static`` ZCML directive may be a
-fully qualified :term:`asset specification`, a package-relative path, or
-an *absolute path*. The ``path`` with the value ``a/b/c/static`` of a
-``static`` directive in a ZCML file that resides in the "mypackage" package
-will resolve to a package-qualified assets such as
-``some_package:a/b/c/static``.
-
-Here's an example of a ``static`` ZCML directive that will serve files
-up under the ``/static`` URL from the ``/var/www/static`` directory of
-the computer which runs the :app:`Pyramid` application using an
-absolute path.
-
-.. code-block:: xml
- :linenos:
-
- <static
- name="static"
- path="/var/www/static"
- />
-
-Here's an example of a ``static`` directive that will serve files up
-under the ``/static`` URL from the ``a/b/c/static`` directory of the
-Python package named ``some_package`` using a fully qualified
-:term:`asset specification`.
-
-.. code-block:: xml
- :linenos:
-
- <static
- name="static"
- path="some_package:a/b/c/static"
- />
-
-Here's an example of a ``static`` directive that will serve files up
-under the ``/static`` URL from the ``static`` directory of the Python
-package in which the ``configure.zcml`` file lives using a
-package-relative path.
-
-.. code-block:: xml
- :linenos:
-
- <static
- name="static"
- path="static"
- />
-
-Whether you use for ``path`` a fully qualified asset specification,
-an absolute path, or a package-relative path, When you place your
-static files on the filesystem in the directory represented as the
-``path`` of the directive, you will then be able to view the static
-files in this directory via a browser at URLs prefixed with the
-directive's ``name``. For instance if the ``static`` directive's
-``name`` is ``static`` and the static directive's ``path`` is
-``/path/to/static``, ``http://localhost:6543/static/foo.js`` will
-return the file ``/path/to/static/dir/foo.js``. The static directory
-may contain subdirectories recursively, and any subdirectories may
-hold files; these will be resolved by the static view as you would
-expect.
-
-While the ``path`` argument can be a number of different things, the
-``name`` argument of the ``static`` ZCML directive can also be one of
-a number of things: a *view name* or a *URL*. The above examples have
-shown usage of the ``name`` argument as a view name. When ``name`` is
-a *URL* (or any string with a slash (``/``) in it), static assets
-can be served from an external webserver. In this mode, the ``name``
-is used as the URL prefix when generating a URL using
-:func:`pyramid.url.static_url`.
-
-For example, the ``static`` ZCML directive may be fed a ``name``
-argument which is ``http://example.com/images``:
-
-.. code-block:: xml
- :linenos:
-
- <static
- name="http://example.com/images"
- path="mypackage:images"
- />
-
-Because the ``static`` ZCML directive is provided with a ``name`` argument
-that is the URL prefix ``http://example.com/images``, subsequent calls to
-:func:`pyramid.url.static_url` with paths that start with the ``path``
-argument passed to :meth:`pyramid.url.static_url` will generate a URL
-something like ``http://example.com/logo.png``. The external webserver
-listening on ``example.com`` must be itself configured to respond properly to
-such a request. The :func:`pyramid.url.static_url` API is discussed in more
-detail later in this chapter.
-
-The :meth:`pyramid.config.Configurator.add_static_view` method offers
-an imperative equivalent to the ``static`` ZCML directive. Use of the
-``add_static_view`` imperative configuration method is completely equivalent
-to using ZCML for the same purpose. See :ref:`static_assets_section` for
-more information.
-
-.. index::
- pair: ZCML directive; asset
-
-.. _asset_zcml_directive:
-
-The ``asset`` ZCML Directive
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-Instead of using :meth:`pyramid.config.Configurator.override_asset` during
-:term:`imperative configuration`, an equivalent ZCML directive can be used.
-The ZCML ``asset`` tag is a frontend to using
-:meth:`pyramid.config.Configurator.override_asset`.
-
-An individual :app:`Pyramid` ``asset`` ZCML statement can override a
-single asset. For example:
-
-.. code-block:: xml
- :linenos:
-
- <asset
- to_override="some.package:templates/mytemplate.pt"
- override_with="another.package:othertemplates/anothertemplate.pt"
- />
-
-The string value passed to both ``to_override`` and ``override_with``
-attached to an ``asset`` directive is called an "asset specification". The
-colon separator in a specification separates the *package name* from the
-*asset name*. The colon and the following asset name are optional. If they
-are not specified, the override attempts to resolve every lookup into a
-package from the directory of another package. For example:
-
-.. code-block:: xml
- :linenos:
-
- <asset
- to_override="some.package"
- override_with="another.package"
- />
-
-Individual subdirectories within a package can also be overridden:
-
-.. code-block:: xml
- :linenos:
-
- <asset
- to_override="some.package:templates/"
- override_with="another.package:othertemplates/"
- />
-
-If you wish to override an asset directory with another directory, you *must*
-make sure to attach the slash to the end of both the ``to_override``
-specification and the ``override_with`` specification. If you fail to attach
-a slash to the end of an asset specification that points to a directory, you
-will get unexpected results.
-
-The package name in an asset specification may start with a dot, meaning that
-the package is relative to the package in which the ZCML file resides. For
-example:
-
-.. code-block:: xml
- :linenos:
-
- <asset
- to_override=".subpackage:templates/"
- override_with="another.package:templates/"
- />
-
-See also :ref:`asset_directive`.
-
-.. _zcml_authorization_policy:
-
-Enabling an Authorization Policy Via ZCML
------------------------------------------
-
-If you'd rather use :term:`ZCML` to specify an authorization policy
-than imperative configuration, modify the ZCML file loaded by your
-application (usually named ``configure.zcml``) to enable an
-authorization policy.
-
-For example, to enable 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:`principal` against the principals present in any :term:`ACL`
-found in the resource tree when attempting to call some :term:`view`, modify
-your ``configure.zcml`` to look something like this:
-
-.. code-block:: xml
- :linenos:
-
- <configure xmlns="http://pylonshq.com/pyramid">
-
- <!-- views and other directives before this... -->
-
- <authtktauthenticationpolicy
- secret="iamsosecret"/>
-
- <aclauthorizationpolicy/>
-
- </configure>
-
-"Under the hood", these statements cause an instance of the class
-:class:`pyramid.authentication.AuthTktAuthenticationPolicy` to be
-injected as the :term:`authentication policy` used by this application
-and an instance of the class
-:class:`pyramid.authorization.ACLAuthorizationPolicy` to be
-injected as the :term:`authorization policy` used by this application.
-
-:app:`Pyramid` ships with a number of authorization and
-authentication policy ZCML directives that should prove useful. See
-:ref:`authentication_policies_directives_section` and
-:ref:`authorization_policies_directives_section` for more information.
-
-.. index::
- pair: ZCML directive; authentication policy
-
-.. _authentication_policies_directives_section:
-
-Built-In Authentication Policy ZCML Directives
-----------------------------------------------
-
-Instead of configuring an authentication policy and authorization
-policy imperatively, :app:`Pyramid` ships with a few "pre-chewed"
-authentication policy ZCML directives that you can make use of within
-your application.
-
-``authtktauthenticationpolicy``
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-When this directive is used, authentication information is obtained
-from an "auth ticket" cookie value, assumed to be set by a custom
-login form.
-
-An example of its usage, with all attributes fully expanded:
-
-.. code-block:: xml
- :linenos:
-
- <authtktauthenticationpolicy
- secret="goshiamsosecret"
- callback=".somemodule.somefunc"
- cookie_name="mycookiename"
- secure="false"
- include_ip="false"
- timeout="86400"
- reissue_time="600"
- max_age="31536000"
- path="/"
- http_only="false"
- />
-
-See :ref:`authtktauthenticationpolicy_directive` for details about
-this directive.
-
-``remoteuserauthenticationpolicy``
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-When this directive is used, authentication information is obtained
-from a ``REMOTE_USER`` key in the WSGI environment, assumed to
-be set by a WSGI server or an upstream middleware component.
-
-An example of its usage, with all attributes fully expanded:
-
-.. code-block:: xml
- :linenos:
-
- <remoteuserauthenticationpolicy
- environ_key="REMOTE_USER"
- callback=".somemodule.somefunc"
- />
-
-See :ref:`remoteuserauthenticationpolicy_directive` for detailed
-information.
-
-``repozewho1authenticationpolicy``
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-When this directive is used, authentication information is obtained
-from a ``repoze.who.identity`` key in the WSGI environment, assumed to
-be set by :term:`repoze.who` middleware.
-
-An example of its usage, with all attributes fully expanded:
-
-.. code-block:: xml
- :linenos:
-
- <repozewho1authenticationpolicy
- identifier_name="auth_tkt"
- callback=".somemodule.somefunc"
- />
-
-See :ref:`repozewho1authenticationpolicy_directive` for detailed
-information.
-
-.. index::
- pair: ZCML directive; authorization policy
-
-.. _authorization_policies_directives_section:
-
-Built-In Authorization Policy ZCML Directives
----------------------------------------------
-
-``aclauthorizationpolicy``
-
-When this directive is used, authorization information is obtained
-from :term:`ACL` objects attached to resources.
-
-An example of its usage, with all attributes fully expanded:
-
-.. code-block:: xml
- :linenos:
-
- <aclauthorizationpolicy/>
-
-In other words, it has no configuration attributes; its existence in a
-``configure.zcml`` file enables it.
-
-See :ref:`aclauthorizationpolicy_directive` for detailed information.
-
-.. _zcml_adding_and_overriding_renderers:
-
-Adding and Overriding Renderers via ZCML
-----------------------------------------
-
-New templating systems and serializers can be associated with :app:`Pyramid`
-renderer names. To this end, configuration declarations can be made which
-override an existing :term:`renderer factory` and which add a new renderer
-factory.
-
-Adding or overriding a renderer via ZCML is accomplished via the
-:ref:`renderer_directive` ZCML directive.
-
-For example, to add a renderer which renders views which have a
-``renderer`` attribute that is a path that ends in ``.jinja2``:
-
-.. code-block:: xml
- :linenos:
-
- <renderer
- name=".jinja2"
- factory="my.package.MyJinja2Renderer"
- />
-
-The ``factory`` attribute is a :term:`dotted Python name` that must
-point to an implementation of a :term:`renderer factory`.
-
-The ``name`` attribute is the renderer name.
-
-Registering a Renderer Factory
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-See :ref:`adding_a_renderer` for more information for the definition of a
-:term:`renderer factory`. Here's an example of the registration of a simple
-:term:`renderer factory` via ZCML:
-
-.. code-block:: xml
- :linenos:
-
- <renderer
- name="amf"
- factory="my.package.MyAMFRenderer"
- />
-
-Adding the above ZCML to your application will allow you to use the
-``my.package.MyAMFRenderer`` renderer factory implementation in view
-configurations by subseqently referring to it as ``amf`` in the ``renderer``
-attribute of a :term:`view configuration`:
-
-.. code-block:: xml
- :linenos:
-
- <view
- view="mypackage.views.my_view"
- renderer="amf"
- />
-
-Here's an example of the registration of a more complicated renderer
-factory, which expects to be passed a filesystem path:
-
-.. code-block:: xml
- :linenos:
-
- <renderer
- name=".jinja2"
- factory="my.package.MyJinja2Renderer"
- />
-
-Adding the above ZCML to your application will allow you to use the
-``my.package.MyJinja2Renderer`` renderer factory implementation in
-view configurations by referring to any ``renderer`` which *ends in*
-``.jinja`` in the ``renderer`` attribute of a :term:`view
-configuration`:
-
-.. code-block:: xml
- :linenos:
-
- <view
- view="mypackage.views.my_view"
- renderer="templates/mytemplate.jinja2"
- />
-
-When a :term:`view configuration` which has a ``name`` attribute that does
-contain a dot, such as ``templates/mytemplate.jinja2`` above is encountered at
-startup time, the value of the name attribute is split on its final dot. The
-second element of the split is typically the filename extension. This
-extension is used to look up a renderer factory for the configured view. Then
-the value of ``renderer`` is passed to the factory to create a renderer for the
-view. In this case, the view configuration will create an instance of a
-``Jinja2Renderer`` for each view configuration which includes anything ending
-with ``.jinja2`` as its ``renderer`` value. The ``name`` passed to the
-``Jinja2Renderer`` constructor will be whatever the user passed as
-``renderer=`` to the view configuration.
-
-See also :ref:`renderer_directive` and
-:meth:`pyramid.config.Configurator.add_renderer`.
-
-Overriding an Existing Renderer
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-You can associate more than one filename extension with the same
-existing renderer implementation as necessary if you need to use a
-different file extension for the same kinds of templates. For
-example, to associate the ``.zpt`` extension with the Chameleon ZPT
-renderer factory, use:
-
-.. code-block:: xml
- :linenos:
-
- <renderer
- name=".zpt"
- factory="pyramid.chameleon_zpt.renderer_factory"
- />
-
-After you do this, :app:`Pyramid` will treat templates ending in
-both the ``.pt`` and ``.zpt`` filename extensions as Chameleon ZPT
-templates.
-
-To override the default mapping in which files with a ``.pt``
-extension are rendered via a Chameleon ZPT page template renderer, use
-a variation on the following in your application's ZCML:
-
-.. code-block:: xml
- :linenos:
-
- <renderer
- name=".pt"
- factory="my.package.pt_renderer"
- />
-
-After you do this, the :term:`renderer factory` in
-``my.package.pt_renderer`` will be used to render templates which end
-in ``.pt``, replacing the default Chameleon ZPT renderer.
-
-To override the default mapping in which files with a ``.txt``
-extension are rendered via a Chameleon text template renderer, use a
-variation on the following in your application's ZCML:
-
-.. code-block:: xml
- :linenos:
-
- <renderer
- name=".txt"
- factory="my.package.text_renderer"
- />
-
-After you do this, the :term:`renderer factory` in
-``my.package.text_renderer`` will be used to render templates which
-end in ``.txt``, replacing the default Chameleon text renderer.
-
-To associate a *default* renderer with *all* view configurations (even
-ones which do not possess a ``renderer`` attribute), use a variation
-on the following (ie. omit the ``name`` attribute to the renderer
-tag):
-
-.. code-block:: xml
- :linenos:
-
- <renderer
- factory="pyramid.renderers.json_renderer_factory"
- />
-
-See also :ref:`renderer_directive` and
-:meth:`pyramid.config.Configurator.add_renderer`.
-
-.. _zcml_adding_a_translation_directory:
-
-Adding a Translation Directory via ZCML
----------------------------------------
-
-You can add a translation directory via ZCML by using the
-:ref:`translationdir_directive` ZCML directive:
-
-.. code-block:: xml
- :linenos:
-
- <translationdir dir="my.application:locale/"/>
-
-A message catalog in a translation directory added via
-:ref:`translationdir_directive` will be merged into translations from
-a message catalog added earlier if both translation directories
-contain translations for the same locale and :term:`translation
-domain`.
-
-See also :ref:`translationdir_directive` and
-:ref:`adding_a_translation_directory`.
-
-.. _zcml_adding_a_locale_negotiator:
-
-Adding a Custom Locale Negotiator via ZCML
-------------------------------------------
-
-You can add a custom locale negotiator via ZCML by using the
-:ref:`localenegotiator_directive` ZCML directive:
-
-.. code-block:: xml
- :linenos:
-
- <localenegotiator
- negotiator="my_application.my_module.my_locale_negotiator"
- />
-
-See also :ref:`custom_locale_negotiator` and
-:ref:`localenegotiator_directive`.
-
-.. index::
- pair: subscriber; ZCML directive
-
-.. _zcml_event_listener:
-
-Configuring an Event Listener via ZCML
---------------------------------------
-
-You can configure an :term:`subscriber` by modifying your application's
-``configure.zcml``. Here's an example of a bit of XML you can add to the
-``configure.zcml`` file which registers the above ``mysubscriber`` function,
-which we assume lives in a ``subscribers.py`` module within your application:
-
-.. code-block:: xml
- :linenos:
-
- <subscriber
- for="pyramid.events.NewRequest"
- handler=".subscribers.mysubscriber"
- />
-
-See also :ref:`subscriber_directive` and :ref:`events_chapter`.
-
-.. index::
- single: not found view
-
-.. _notfound_zcml:
-
-Configuring a Not Found View via ZCML
--------------------------------------
-
-If your application uses :term:`ZCML`, you can replace the Not Found view by
-placing something like the following ZCML in your ``configure.zcml`` file.
-
-.. code-block:: xml
- :linenos:
-
- <view
- view="helloworld.views.notfound_view"
- context="pyramid.exceptions.NotFound"
- />
-
-Replace ``helloworld.views.notfound_view`` with the Python dotted name to the
-notfound view you want to use.
-
-See :ref:`changing_the_notfound_view` for more information.
-
-.. index::
- single: forbidden view
-
-.. _forbidden_zcml:
-
-Configuring a Forbidden View via ZCML
--------------------------------------
-
-If your application uses :term:`ZCML`, you can replace the Forbidden view by
-placing something like the following ZCML in your ``configure.zcml`` file.
-
-.. code-block:: xml
- :linenos:
-
- <view
- view="helloworld.views.notfound_view"
- context="pyramid.exceptions.Forbidden"
- />
-
-Replace ``helloworld.views.forbidden_view`` with the Python dotted name to
-the forbidden view you want to use.
-
-See :ref:`changing_the_forbidden_view` for more information.
-
-.. _changing_traverser_zcml:
-
-Configuring an Alternate Traverser via ZCML
--------------------------------------------
-
-Use an ``adapter`` stanza in your application's ``configure.zcml`` to
-change the default traverser:
-
-.. code-block:: xml
- :linenos:
-
- <adapter
- factory="myapp.traversal.Traverser"
- provides="pyramid.interfaces.ITraverser"
- for="*"
- />
-
-Or to register a traverser for a specific resource type:
-
-.. code-block:: xml
- :linenos:
-
- <adapter
- factory="myapp.traversal.Traverser"
- provides="pyramid.interfaces.ITraverser"
- for="myapp.resources.MyRoot"
- />
-
-See :ref:`changing_the_traverser` for more information.
-
-.. index::
- single: url generator
-
-.. _changing_resource_url_zcml:
-
-Changing ``resource_url`` URL Generation via ZCML
--------------------------------------------------
-
-You can change how :func:`pyramid.url.resource_url` generates a URL for a
-specific type of resource by adding an adapter statement to your
-``configure.zcml``.
-
-.. code-block:: xml
- :linenos:
-
- <adapter
- factory="myapp.traversal.URLGenerator"
- provides="pyramid.interfaces.IContextURL"
- for="myapp.resources.MyRoot *"
- />
-
-See :ref:`changing_resource_url` for more information.
-
-.. _changing_request_factory_zcml:
-
-Changing the Request Factory via ZCML
--------------------------------------
-
-A ``MyRequest`` class can be registered via ZCML as a request factory through
-the use of the ZCML ``utility`` directive. In the below, we assume it lives
-in a package named ``mypackage.mymodule``.
-
-.. code-block:: xml
- :linenos:
-
- <utility
- component="mypackage.mymodule.MyRequest"
- provides="pyramid.interfaces.IRequestFactory"
- />
-
-See :ref:`changing_request_factory` for more information.
-
-.. _adding_renderer_globals_zcml:
-
-Changing the Renderer Globals Factory via ZCML
-----------------------------------------------
-
-A renderer globals factory can be registered via ZCML as a through the use of
-the ZCML ``utility`` directive. In the below, we assume a
-``renderers_globals_factory`` function lives in a package named
-``mypackage.mymodule``.
-
-.. code-block:: xml
- :linenos:
-
- <utility
- component="mypackage.mymodule.renderer_globals_factory"
- provides="pyramid.interfaces.IRendererGlobalsFactory"
- />
-
-See :ref:`adding_renderer_globals` for more information.
-
diff --git a/docs/narr/environment.rst b/docs/narr/environment.rst
index 7caa1dcc6..7b7946aae 100644
--- a/docs/narr/environment.rst
+++ b/docs/narr/environment.rst
@@ -38,10 +38,11 @@ application-specific configuration settings.
Reloading Templates
-------------------
-When this value is true, reload templates without a restart, so you can see
-changes to templates take effect immediately during development. This flag
-is meaningful to Chameleon and Mako templates, as well as most third-party
-template rendering extensions.
+When this value is true, templates are automatically reloaded whenever
+they are modified without restarting the application, so you can see
+changes to templates take effect immediately during development. This
+flag is meaningful to Chameleon and Mako templates, as well as most
+third-party template rendering extensions.
+---------------------------------+-----------------------------+
| Environment Variable Name | Config File Setting Name |
@@ -335,6 +336,14 @@ with ``reload_``). on in one fell swoop, you can use
affect settings that do not start with ``reload_*`` such as
``debug_notfound``.
+.. note::
+ Specifying configuration settings via environment variables is generally
+ most useful during development, where you may wish to augment or
+ override the more permanent settings in the configuration file.
+ This is useful because many of the reload and debug settings may
+ have performance or security (i.e., disclosure) implications
+ that make them undesirable in a production environment.
+
.. index::
single: reload_templates
single: reload_assets
diff --git a/docs/narr/events.rst b/docs/narr/events.rst
index 06b30883f..224eeca16 100644
--- a/docs/narr/events.rst
+++ b/docs/narr/events.rst
@@ -38,52 +38,51 @@ you'll need to use the
need to use the :func:`pyramid.events.subscriber` decorator to decorate a
function found via a :term:`scan`.
-.. topic:: Configuring an Event Listener Imperatively
+Configuring an Event Listener Imperatively
+------------------------------------------
- You can imperatively configure a subscriber function to be called
- for some event type via the
- :meth:`pyramid.config.Configurator.add_subscriber`
- method (see also :term:`Configurator`):
+You can imperatively configure a subscriber function to be called
+for some event type via the
+:meth:`pyramid.config.Configurator.add_subscriber`
+method (see also :term:`Configurator`):
- .. code-block:: python
- :linenos:
-
- from pyramid.events import NewRequest
+.. code-block:: python
+ :linenos:
- from subscribers import mysubscriber
+ from pyramid.events import NewRequest
- # "config" below is assumed to be an instance of a
- # pyramid.config.Configurator object
+ from subscribers import mysubscriber
- config.add_subscriber(mysubscriber, NewRequest)
+ # "config" below is assumed to be an instance of a
+ # pyramid.config.Configurator object
- The first argument to
- :meth:`pyramid.config.Configurator.add_subscriber` is the
- subscriber function (or a :term:`dotted Python name` which refers
- to a subscriber callable); the second argument is the event type.
+ config.add_subscriber(mysubscriber, NewRequest)
-.. topic:: Configuring an Event Listener Using a Decorator
+The first argument to
+:meth:`pyramid.config.Configurator.add_subscriber` is the
+subscriber function (or a :term:`dotted Python name` which refers
+to a subscriber callable); the second argument is the event type.
- You can configure a subscriber function to be called for some event
- type via the :func:`pyramid.events.subscriber` function.
+Configuring an Event Listener Using a Decorator
+-----------------------------------------------
- .. code-block:: python
- :linenos:
+You can configure a subscriber function to be called for some event
+type via the :func:`pyramid.events.subscriber` function.
- from pyramid.events import NewRequest
- from pyramid.events import subscriber
+.. code-block:: python
+ :linenos:
- @subscriber(NewRequest)
- def mysubscriber(event):
- event.request.foo = 1
+ from pyramid.events import NewRequest
+ from pyramid.events import subscriber
- When the :func:`pyramid.subscriber` decorator is used a
- :term:`scan` must be performed against the package containing the
- decorated function for the decorator to have any effect. See
- :func:`pyramid.subscriber` for more information.
+ @subscriber(NewRequest)
+ def mysubscriber(event):
+ event.request.foo = 1
-.. note:: You can also configure an event listener via ZCML. See
- :ref:`zcml_event_listener`.
+When the :func:`pyramid.subscriber` decorator is used a
+:term:`scan` must be performed against the package containing the
+decorated function for the decorator to have any effect. See
+:func:`pyramid.subscriber` for more information.
Either of the above registration examples implies that every time the
:app:`Pyramid` framework emits an event object that supplies an
diff --git a/docs/narr/extending.rst b/docs/narr/extending.rst
index 524dcb2ac..c709e1f8f 100644
--- a/docs/narr/extending.rst
+++ b/docs/narr/extending.rst
@@ -108,7 +108,7 @@ extensible and overrideable. :term:`ZCML` declarations that belong to an
application can be overridden and extended by integrators as necessary in a
similar fashion. If you use only :term:`ZCML` to configure your application,
it will automatically be maximally extensible without any manual effort. See
-:ref:`declarative_chapter` for information about using ZCML.
+:term:`pyramid_zcml` for information about using ZCML.
Fundamental Plugpoints
~~~~~~~~~~~~~~~~~~~~~~
@@ -121,9 +121,9 @@ ZCML ``<route>`` directive). Views are declarations made using the
directive). Assets are files that are accessed by :app:`Pyramid` using the
:term:`pkg_resources` API such as static files and templates via a
:term:`asset specification`. Other directives and configurator methods also
-deal in routes, views, and assets. For example,
-:meth:`pyramid.config.Configurator.add_handler` adds a single route, and some
-number of views.
+deal in routes, views, and assets. For example, ``add_handler`` directive of
+the ``pyramid_handlers`` package adds a single route, and some number of
+views.
.. index::
single: extending an existing application
@@ -196,7 +196,7 @@ like this:
:ref:`creating_a_project` for more information.
- In the new package, create Python files containing views and other
- overridden elements, such as templates and static resources as necessary.
+ 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. ``python setup.py develop`` or ``python setup.py
@@ -278,7 +278,7 @@ into the override package's file and changing them as necessary. Then
disinclude any ``add_route`` statements from the original application.
.. index::
- pair: overriding; resources
+ pair: overriding; assets
.. _overriding_resources:
@@ -286,10 +286,10 @@ Overriding Assets
~~~~~~~~~~~~~~~~~
Assets are files on the filesystem that are accessible within a Python
-*package*. An entire chapter is devoted to resources: :ref:`assets_chapter`.
+*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
-resources with other resources by using the
+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/firstapp.rst b/docs/narr/firstapp.rst
index cb1e54b19..34e6981a4 100644
--- a/docs/narr/firstapp.rst
+++ b/docs/narr/firstapp.rst
@@ -10,7 +10,7 @@ more detail how it works.
.. note::
If you're a "theory-first" kind of person, you might choose to read
- :ref:`resourcelocation_chapter` and :ref:`views_chapter` before diving into
+ :ref:`urldispatch_chapter` and :ref:`views_chapter` before diving into
the code that follows, but it's not necessary if -- like many programmers
-- you're willing to "go with the flow".
@@ -323,8 +323,8 @@ For more information about the API of a :term:`Configurator` object,
see :class:`pyramid.config.Configurator` .
For more information about :term:`view configuration`, see
-:ref:`views_chapter`.
+:ref:`view_config_chapter`.
An example of using *declarative* configuration (:term:`ZCML`) instead of
imperative configuration to create a similar "hello world" is available
-within :ref:`declarative_configuration`.
+within the documentation for :term:`pyramid_zcml`.
diff --git a/docs/narr/flash.rst b/docs/narr/flash.rst
deleted file mode 100644
index d41c2cdaf..000000000
--- a/docs/narr/flash.rst
+++ /dev/null
@@ -1,107 +0,0 @@
-.. _flash_chapter:
-
-Flash Messages
-==============
-
-"Flash messages" are simply a queue of message strings stored in the
-:term:`session`. To use flash messaging, you must enable a :term:`session
-factory` as described in :ref:`using_the_default_session_factory` or
-:ref:`using_alternate_session_factories`.
-
-Flash messaging has two main uses: to display a status message only once to
-the user after performing an internal redirect, and to allow generic code to
-log messages for single-time display without having direct access to an HTML
-template. The user interface consists of a number of methods of the
-:term:`session` object.
-
-Using the ``session.flash`` Method
-----------------------------------
-
-To add a message to a flash message queue, use a session object's ``flash``
-method:
-
-.. code-block:: python
- :linenos:
-
- request.session.flash('mymessage')
-
-The ``.flash`` method appends a message to a flash queue, creating the queue
-if necessary.
-
-``.flash`` accepts three arguments:
-
-.. method:: flash(message, queue='', allow_duplicate=True)
-
-The ``message`` argument is required. It represents a message you wish to
-later display to a user. It is usually a string but the ``message`` you
-provide is not modified in any way.
-
-The ``queue`` argument allows you to choose a queue to which to append the
-message you provide. This can be used to push different kinds of messages
-into flash storage for later display in different places on a page. You cam
-pass any name for your queue, but it must be a string. The default value is
-the empty string, which chooses the default queue. Each queue is independent,
-and can be popped by ``pop_flash`` or examined via ``peek_flash`` separately.
-``queue`` defaults to the empty string. The empty string represents the
-default flash message queue.
-
-.. code-block:: python
-
- request.session.flash(msg, 'myappsqueue')
-
-The ``allow_duplicate`` argument, which defaults to ``True``. If this is
-``False``, if you attempt to add a message to a queue which is already
-present in the queue, it will not be added.
-
-Using the ``session.pop_flash`` Method
---------------------------------------
-
-Once one or more messages has been added to a flash queue by the
-``session.flash`` API, the ``session.pop_flash`` API can be used to pop that
-queue and return it for use.
-
-To pop a particular queue of messages from the flash object, use the session
-object's ``pop_flash`` method.
-
-.. code-block:: python
- :linenos:
-
- >>> request.session.flash('info message')
- >>> request.session.pop_flash()
- ['info message']
-
-Calling ``session.pop_flash()`` again like above without a corresponding call
-to ``session.flash`` will return an empty list, because the queue has already
-been popped.
-
-.. code-block:: python
- :linenos:
-
- >>> request.session.flash('info message')
- >>> request.session.pop_flash()
- ['info message']
- >>> request.session.pop_flash()
- []
-
-The object returned from ``pop_flash`` is a list.
-
-Using the ``session.pop_flash`` Method
---------------------------------------
-
-Once one or more messages has been added to a flash queue by the
-``session.flash`` API, the ``session.peek_flash`` API can be used to "peek"
-at that queue. Unlike ``session.pop_flash``, the queue is not popped from
-flash storage.
-
-.. code-block:: python
- :linenos:
-
- >>> request.session.flash('info message')
- >>> request.session.peek_flash()
- ['info message']
- >>> request.session.peek_flash()
- ['info message']
- >>> request.session.pop_flash()
- ['info message']
- >>> request.session.peek_flash()
- []
diff --git a/docs/narr/forms.rst b/docs/narr/forms.rst
new file mode 100644
index 000000000..080f02159
--- /dev/null
+++ b/docs/narr/forms.rst
@@ -0,0 +1,126 @@
+.. _forms_chapter:
+
+.. index::
+ single: unicode, views, and forms
+ single: forms, views, and unicode
+ single: views, forms, and unicode
+
+Form Handling
+=============
+
+Handling Form Submissions in View Callables (Unicode and Character Set Issues)
+------------------------------------------------------------------------------
+
+Most web applications need to accept form submissions from web browsers and
+various other clients. In :app:`Pyramid`, form submission handling logic is
+always part of a :term:`view`. For a general overview of how to handle form
+submission data using the :term:`WebOb` API, see :ref:`webob_chapter` and
+`"Query and POST variables" within the WebOb documentation
+<http://pythonpaste.org/webob/reference.html#query-post-variables>`_.
+:app:`Pyramid` defers to WebOb for its request and response implementations,
+and handling form submission data is a property of the request
+implementation. Understanding WebOb's request API is the key to
+understanding how to process form submission data.
+
+There are some defaults that you need to be aware of when trying to handle
+form submission data in a :app:`Pyramid` view. Having high-order (i.e.,
+non-ASCII) characters in data contained within form submissions is
+exceedingly common, and the UTF-8 encoding is the most common encoding used
+on the web for character data. Since Unicode values are much saner than
+working with and storing bytestrings, :app:`Pyramid` configures the
+:term:`WebOb` request machinery to attempt to decode form submission values
+into Unicode from UTF-8 implicitly. This implicit decoding happens when view
+code obtains form field values via the ``request.params``, ``request.GET``,
+or ``request.POST`` APIs (see :ref:`request_module` for details about these
+APIs).
+
+.. note::
+
+ Many people find the difference between Unicode and UTF-8 confusing.
+ Unicode is a standard for representing text that supports most of the
+ world's writing systems. However, there are many ways that Unicode data
+ can be encoded into bytes for transit and storage. UTF-8 is a specific
+ encoding for Unicode, that is backwards-compatible with ASCII. This makes
+ UTF-8 very convenient for encoding data where a large subset of that data
+ is ASCII characters, which is largely true on the web. UTF-8 is also the
+ standard character encoding for URLs.
+
+As an example, let's assume that the following form page is served up to a
+browser client, and its ``action`` points at some :app:`Pyramid` view code:
+
+.. code-block:: xml
+ :linenos:
+
+ <html xmlns="http://www.w3.org/1999/xhtml">
+ <head>
+ <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
+ </head>
+ <form method="POST" action="myview">
+ <div>
+ <input type="text" name="firstname"/>
+ </div>
+ <div>
+ <input type="text" name="lastname"/>
+ </div>
+ <input type="submit" value="Submit"/>
+ </form>
+ </html>
+
+The ``myview`` view code in the :app:`Pyramid` application *must* expect that
+the values returned by ``request.params`` will be of type ``unicode``, as
+opposed to type ``str``. The following will work to accept a form post from
+the above form:
+
+.. code-block:: python
+ :linenos:
+
+ def myview(request):
+ firstname = request.params['firstname']
+ lastname = request.params['lastname']
+
+But the following ``myview`` view code *may not* work, as it tries to decode
+already-decoded (``unicode``) values obtained from ``request.params``:
+
+.. code-block:: python
+ :linenos:
+
+ def myview(request):
+ # the .decode('utf-8') will break below if there are any high-order
+ # characters in the firstname or lastname
+ firstname = request.params['firstname'].decode('utf-8')
+ lastname = request.params['lastname'].decode('utf-8')
+
+For implicit decoding to work reliably, you should ensure that every form you
+render that posts to a :app:`Pyramid` view explicitly defines a charset
+encoding of UTF-8. This can be done via a response that has a
+``;charset=UTF-8`` in its ``Content-Type`` header; or, as in the form above,
+with a ``meta http-equiv`` tag that implies that the charset is UTF-8 within
+the HTML ``head`` of the page containing the form. This must be done
+explicitly because all known browser clients assume that they should encode
+form data in the same character set implied by ``Content-Type`` value of the
+response containing the form when subsequently submitting that form. There is
+no other generally accepted way to tell browser clients which charset to use
+to encode form data. If you do not specify an encoding explicitly, the
+browser client will choose to encode form data in its default character set
+before submitting it, which may not be UTF-8 as the server expects. If a
+request containing form data encoded in a non-UTF8 charset is handled by your
+view code, eventually the request code accessed within your view will throw
+an error when it can't decode some high-order character encoded in another
+character set within form data, e.g., when ``request.params['somename']`` is
+accessed.
+
+If you are using the :class:`pyramid.response.Response` class to generate a
+response, or if you use the ``render_template_*`` templating APIs, the UTF-8
+charset is set automatically as the default via the ``Content-Type`` header.
+If you return a ``Content-Type`` header without an explicit charset, a
+request will add a ``;charset=utf-8`` trailer to the ``Content-Type`` header
+value for you, for response content types that are textual
+(e.g. ``text/html``, ``application/xml``, etc) as it is rendered. If you are
+using your own response object, you will need to ensure you do this yourself.
+
+.. note:: Only the *values* of request params obtained via
+ ``request.params``, ``request.GET`` or ``request.POST`` are decoded
+ to Unicode objects implicitly in the :app:`Pyramid` default
+ configuration. The keys are still (byte) strings.
+
+
diff --git a/docs/narr/hooks.rst b/docs/narr/hooks.rst
index 2917b5254..b3b41046f 100644
--- a/docs/narr/hooks.rst
+++ b/docs/narr/hooks.rst
@@ -70,9 +70,6 @@ Here's some sample code that implements a minimal NotFound view callable:
:exc:`pyramid.exceptions.NotFound` exception instance. If available, the
resource context will still be available as ``request.context``.
-For information about how to configure a not found view via :term:`ZCML`, see
-:ref:`notfound_zcml`.
-
.. index::
single: forbidden view
@@ -83,7 +80,7 @@ Changing the Forbidden View
When :app:`Pyramid` can't authorize execution of a view based on the
:term:`authorization policy` in use, it invokes a :term:`forbidden view`.
-The default forbidden response has a 401 status code and is very plain, but
+The 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
@@ -132,15 +129,6 @@ Here's some sample code that implements a minimal forbidden view:
``debug_authorization`` environment setting is true than it is when
it is false.
-.. warning:: the default forbidden view sends a response with a ``401
- Unauthorized`` status code for backwards compatibility reasons.
- You can influence the status code of Forbidden responses by using
- an alternate forbidden view. For example, it would make sense to
- return a response with a ``403 Forbidden`` status code.
-
-For information about how to configure a forbidden view via :term:`ZCML`, see
-:ref:`forbidden_zcml`.
-
.. index::
single: request factory
@@ -185,8 +173,6 @@ already constructed a :term:`configurator` it can also be registered via the
config = Configurator()
config.set_request_factory(MyRequest)
-To use ZCML for the same purpose, see :ref:`changing_request_factory_zcml`.
-
.. index::
single: renderer globals
@@ -242,9 +228,6 @@ already constructed a :term:`configurator` it can also be registered via the
Another mechanism which allows event subscribers to add renderer global values
exists in :ref:`beforerender_event`.
-If you'd rather ZCML to register a renderer globals factory, see
-:ref:`adding_renderer_globals_zcml`.
-
.. index::
single: before render event
@@ -365,10 +348,11 @@ parameter: ``request``. For example:
transaction.commit()
request.add_finished_callback(commit_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.
+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
@@ -474,9 +458,6 @@ when the application :term:`root factory` returned an instance of the
``myapp.resources.MyRoot`` object. Otherwise it would use the default
:app:`Pyramid` traverser to do traversal.
-For information about how to configure an alternate traverser via
-:term:`ZCML`, see :ref:`changing_traverser_zcml`.
-
.. index::
single: url generator
@@ -541,6 +522,98 @@ The default context URL generator is available for perusal as the class
:term:`Pylons` GitHub Pyramid repository.
.. index::
+ single: view mapper
+
+.. _using_a_view_mapper:
+
+Using a View Mapper
+-------------------
+
+The default calling conventions for view callables are documented in the
+:ref:`views_chapter` chapter. You can change the way users define view
+callbles 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,
+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 passing the mapper object to
+ :meth:`pyramid.config.Configurator.add_view` (or its declarative/decorator
+ equivalents) as the ``mapper`` argument.
+
+- 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.
+
+.. code-block:: python
+ :linenos:
+
+ # framework
+
+ class PylonsControllerViewMapper(object):
+ def __init__(self, **kw):
+ self.kw = kw
+
+ def __call__(self, view):
+ attr = self.kw['attr']
+ def wrapper(context, request):
+ matchdict = request.matchdict.copy()
+ matchdict.pop('action', None)
+ inst = view()
+ meth = getattr(inst, attr)
+ return meth(**matchdict)
+ return wrapper
+
+ class BaseController(object):
+ __view_mapper__ = PylonsControllerViewMapper
+
+A user might make use of these framework components like so:
+
+.. code-block:: python
+ :linenos:
+
+ # user application
+
+ from webob import Response
+ from pyramid.config import Configurator
+ import pyramid_handlers
+ from paste.httpserver import serve
+
+ class MyController(BaseController):
+ def index(self, id):
+ return Response(id)
+
+ if __name__ == '__main__':
+ config = Configurator()
+ config.include(pyramid_handlers)
+ config.add_handler('one', '/{id}', MyController, action='index')
+ config.add_handler('two', '/{action}/{id}', MyController)
+ serve(config.make_wsgi_app())
+
+The :meth:`pyramid.config.Configurator.set_default_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.Configuration.add_view`.
+
+.. index::
single: configuration decorator
.. _registering_configuration_decorators:
@@ -581,7 +654,7 @@ follows:
self.path = path
def register(self, scanner, name, wrapped):
- registry = get_current_registry()
+ registry = scanner.config.registry
registry.getUtility(IMyUtility).register(
self.path, wrapped
)
diff --git a/docs/narr/i18n.rst b/docs/narr/i18n.rst
index c2a5b8ce7..83973a17e 100644
--- a/docs/narr/i18n.rst
+++ b/docs/narr/i18n.rst
@@ -867,11 +867,11 @@ which itself includes an ``LC_MESSAGES`` directory. Each
Each ``.mo`` file represents a :term:`message catalog`, which is used
to provide translations to your application.
-Adding a :term:`translation directory` registers all of its
-constituent :term:`message catalog` files (all of the ``.mo`` files
-found within all ``LC_MESSAGES`` directories within each locale
-directory in the translation directory) within your :app:`Pyramid`
-application to be available to use for translation services.
+Adding a :term:`translation directory` registers all of its constituent
+:term:`message catalog` files within your :app:`Pyramid` application to
+be available to use for translation services. This includes all of the
+``.mo`` files found within all ``LC_MESSAGES`` directories within each
+locale directory in the translation directory.
You can add a translation directory imperatively by using the
:meth:`pyramid.config.Configurator.add_translation_dirs` during
@@ -890,9 +890,6 @@ will be merged into translations from a message catalog added earlier
if both translation directories contain translations for the same
locale and :term:`translation domain`.
-.. note:: You can also add a translation directory via ZCML. See
- :ref:`zcml_adding_a_translation_directory`
-
Setting the Locale
~~~~~~~~~~~~~~~~~~
@@ -1019,5 +1016,3 @@ For example:
config = Configurator()
config.set_locale_negotiator(my_locale_negotiator)
-.. note:: You can also add a custom locale negotiator via ZCML. See
- :ref:`zcml_adding_a_locale_negotiator`
diff --git a/docs/narr/install.rst b/docs/narr/install.rst
index e32d0c6c3..c5ec14aa1 100644
--- a/docs/narr/install.rst
+++ b/docs/narr/install.rst
@@ -295,7 +295,7 @@ Installing :app:`Pyramid` on a Windows System
c:\> cd env
-#. (Optional) Consider using ``bin\activate.bat`` to make your shell
+#. (Optional) Consider using ``Scripts\activate.bat`` to make your shell
environment wired to use the virtualenv.
#. Use ``easy_install`` pointed at the "current" index to get
diff --git a/docs/narr/introduction.rst b/docs/narr/introduction.rst
index 3ade3726c..2da75df39 100644
--- a/docs/narr/introduction.rst
+++ b/docs/narr/introduction.rst
@@ -63,7 +63,7 @@ A Sense of Fun
Minimalism
:app:`Pyramid` provides only the very basics: *URL to code
- mapping*, *templating*, *security*, and *resources*. There is not
+ mapping*, *templating*, *security*, and *assets*. There is not
much more to the framework than these pieces: you are expected to
provide the rest.
@@ -104,7 +104,7 @@ What Is The Pylons Project?
:app:`Pyramid` is a member of the collection of software published under the
Pylons Project. Pylons software is written by a loose-knit community of
-contributors. The `Pylons Project website <http://docs.pylonshq.com>`_
+contributors. The `Pylons Project website <http://docs.pylonsproject.org>`_
includes details about how :app:`Pyramid` relates to the Pylons Project.
.. index::
diff --git a/docs/narr/muchadoabouttraversal.rst b/docs/narr/muchadoabouttraversal.rst
new file mode 100644
index 000000000..c57e58cd0
--- /dev/null
+++ b/docs/narr/muchadoabouttraversal.rst
@@ -0,0 +1,311 @@
+.. _much_ado_about_traversal_chapter:
+
+========================
+Much Ado About Traversal
+========================
+
+.. note:: This chapter was adapted, with permission, from a blog post by `Rob
+ Miller <http://blog.nonsequitarian.org/>`_, originally published at
+ `http://blog.nonsequitarian.org/2010/much-ado-about-traversal/
+ <http://blog.nonsequitarian.org/2010/much-ado-about-traversal/>`_.
+
+Traversal is an alternative to :term:`URL dispatch` which allows
+:app:`Pyramid` applications to map URLs to code.
+
+.. note::
+
+ Ex-Zope users whom are already familiar with traversal and view lookup
+ conceptually may want to skip directly to the :ref:`traversal_chapter`
+ chapter, which discusses technical details. This chapter is mostly aimed
+ at people who have previous :term:`Pylons` experience or experience in
+ another framework which does not provide traversal, and need an
+ introduction to the "why" of traversal.
+
+Some folks who have been using Pylons and its Routes-based URL matching for a
+long time are being exposed for the first time, via :app:`Pyramid`, to new
+ideas such as ":term:`traversal`" and ":term:`view lookup`" as a way to route
+incoming HTTP requests to callable code. Some of the same folks believe that
+traversal is hard to understand. Others question its usefulness; URL
+matching has worked for them so far, why should they even consider dealing
+with another approach, one which doesn't fit their brain and which doesn't
+provide any immediately obvious value?
+
+You can be assured that if you don't want to understand traversal, you don't
+have to. You can happily build :app:`Pyramid` applications with only
+:term:`URL dispatch`. However, there are some straightforward, real-world
+use cases that are much more easily served by a traversal-based approach than
+by a pattern-matching mechanism. Even if you haven't yet hit one of these
+use cases yourself, understanding these new ideas is worth the effort for any
+web developer so you know when you might want to use them. :term:`Traversal`
+is actually a straightforward metaphor easily comprehended by anyone who's
+ever used a run-of-the-mill file system with folders and files.
+
+URL Dispatch
+------------
+
+Let's step back and consider the problem we're trying to solve. An
+HTTP request for a particular path has been routed to our web
+application. The requested path will possibly invoke a specific
+:term:`view callable` function defined somewhere in our app. We're
+trying to determine *which* callable function, if any, should be
+invoked for a given requested URL.
+
+Many systems, including Pyramid, offer a simple solution. They offer the
+concept of "URL matching". URL matching approaches this problem by parsing
+the URL path and comparing the results to a set of registered "patterns",
+defined by a set of regular expressions, or some other URL path templating
+syntax. Each pattern is mapped to a callable function somewhere; if the
+request path matches a specific pattern, the associated function is called.
+If the request path matches more than one pattern, some conflict resolution
+scheme is used, usually a simple order precedence so that the first match
+will take priority over any subsequent matches. If a request path doesn't
+match any of the defined patterns, a "404 Not Found" response is returned.
+
+In Pyramid, we offer an implementation of URL matching which we call
+:term:`URL dispatch`. Using :app:`Pyramid` syntax, we might have a match
+pattern such as ``/{userid}/photos/{photoid}``, mapped to a ``photo_view()``
+function defined somewhere in our code. Then a request for a path such as
+``/joeschmoe/photos/photo1`` would be a match, and the ``photo_view()``
+function would be invoked to handle the request. Similarly,
+``/{userid}/blog/{year}/{month}/{postid}`` might map to a
+``blog_post_view()`` function, so ``/joeschmoe/blog/2010/12/urlmatching``
+would trigger the function, which presumably would know how to find and
+render the ``urlmatching`` blog post.
+
+Historical Refresher
+--------------------
+
+Now that we've refreshed our understanding of :term:`URL dispatch`, we'll dig
+in to the idea of traversal. Before we do, though, let's take a trip down
+memory lane. If you've been doing web work for a while, you may remember a
+time when we didn't have fancy web frameworks like :term:`Pylons` and
+:app:`Pyramid`. Instead, we had general purpose HTTP servers that primarily
+served files off of a file system. The "root" of a given site mapped to a
+particular folder somewhere on the file system. Each segment of the request
+URL path represented a subdirectory. The final path segment would be either
+a directory or a file, and once the server found the right file it would
+package it up in an HTTP response and send it back to the client. So serving
+up a request for ``/joeschmoe/photos/photo1`` literally meant that there was
+a ``joeschmoe`` folder somewhere, which contained a ``photos`` folder, which
+in turn contained a ``photo1`` file. If at any point along the way we find
+that there is not a folder or file matching the requested path, we return a
+404 response.
+
+As the web grew more dynamic, however, a little bit of extra complexity was
+added. Technologies such as CGI and HTTP server modules were developed.
+Files were still looked up on the file system, but if the file ended with
+(for example) ``.cgi`` or ``.php``, or if it lived in a special folder,
+instead of simply sending the file to the client the server would read the
+file, execute it using an interpreter of some sort, and then send the output
+from this process to the client as the final result. The server
+configuration specified which files would trigger some dynamic code, with the
+default case being to just serve the static file.
+
+Traversal (aka Resource Location)
+---------------------------------
+
+.. index::
+ single: traversal overview
+
+Believe it or not, if you understand how serving files from a file system
+works,you understand traversal. And if you understand that a server might do
+something different based on what type of file a given request specifies,
+then you understand view lookup.
+
+The major difference between file system lookup and traversal is that a file
+system lookup steps through nested directories and files in a file system
+tree, while traversal steps through nested dictionary-type objects in a
+:term:`resource tree`. Let's take a detailed look at one of our example
+paths, so we can see what I mean:
+
+The path ``/joeschmoe/photos/photo1``, has four segments: ``/``,
+``joeschmoe``, ``photos`` and ``photo1``. With file system lookup we might
+have a root folder (``/``) containing a nested folder (``joeschmoe``), which
+contains another nested folder (``photos``), which finally contains a JPG
+file (``photo1``). With traversal, we instead have a dictionary-like root
+object. Asking for the ``joeschmoe`` key gives us another dictionary-like
+object. Asking this in turn for the ``photos`` key gives us yet another
+mapping object, which finally (hopefully) contains the resource that we're
+looking for within its values, referenced by the ``photo1`` key.
+
+In pure Python terms, then, the traversal or "resource location"
+portion of satisfying the ``/joeschmoe/photos/photo1`` request
+will look something like this pseudocode::
+
+ get_root()['joeschmoe']['photos']['photo1']
+
+``get_root()`` is some function that returns a root traversal
+:term:`resource`. If all of the specified keys exist, then the returned
+object will be the resource that is being requested, analogous to the JPG
+file that was retrieved in the file system example. If a :exc:`KeyError` is
+generated anywhere along the way, :app:`Pyramid` will return 404. (This
+isn't precisely true, as you'll see when we learn about view lookup below,
+but the basic idea holds.)
+
+What Is a "Resource"?
+---------------------
+
+"Files on a file system I understand", you might say. "But what are these
+nested dictionary things? Where do these objects, these 'resources', live?
+What *are* they?"
+
+Since :app:`Pyramid` is not a highly opinionated framework, it makes no
+restriction on how a :term:`resource` is implemented; a developer can
+implement them as he wishes. One common pattern used is to persist all of
+the resources, including the root, in a database as a graph. The root object
+is a dictionary-like object. Dictionary-like objects in Python supply a
+``__getitem__`` method which is called when key lookup is done. Under the
+hood, when ``adict`` is a dictionary-like object, Python translates
+``adict['a']`` to ``adict.__getitem__('a')``. Try doing this in a Python
+interpreter prompt if you don't believe us:
+
+.. code-block:: text
+ :linenos:
+
+ Python 2.4.6 (#2, Apr 29 2010, 00:31:48)
+ [GCC 4.4.3] on linux2
+ Type "help", "copyright", "credits" or "license" for more information.
+ >>> adict = {}
+ >>> adict['a'] = 1
+ >>> adict['a']
+ 1
+ >>> adict.__getitem__('a')
+ 1
+
+
+The dictionary-like root object stores the ids of all of its subresources as
+keys, and provides a ``__getitem__`` implementation that fetches them. So
+``get_root()`` fetches the unique root object, while
+``get_root()['joeschmoe']`` returns a different object, also stored in the
+database, which in turn has its own subresources and ``__getitem__``
+implementation, etc. These resources might be persisted in a relational
+database, one of the many "NoSQL" solutions that are becoming popular these
+days, or anywhere else, it doesn't matter. As long as the returned objects
+provide the dictionary-like API (i.e. as long as they have an appropriately
+implemented ``__getitem__`` method) then traversal will work.
+
+In fact, you don't need a "database" at all. You could use plain
+dictionaries, with your site's URL structure hard-coded directly in
+the Python source. Or you could trivially implement a set of objects
+with ``__getitem__`` methods that search for files in specific
+directories, and thus precisely recreate the traditional mechanism of
+having the URL path mapped directly to a folder structure on the file
+system. Traversal is in fact a superset of file system lookup.
+
+.. note:: See the chapter entitled :ref:`resources_chapter` for a more
+ technical overview of resources.
+
+View Lookup
+-----------
+
+At this point we're nearly there. We've covered traversal, which is the
+process by which a specific resource is retrieved according to a specific URL
+path. But what is "view lookup"?
+
+The need for view lookup is simple: there is more than one possible action
+that you might want to take after finding a :term:`resource`. With our photo
+example, for instance, you might want to view the photo in a page, but you
+might also want to provide a way for the user to edit the photo and any
+associated metadata. We'll call the former the ``view`` view, and the latter
+will be the ``edit`` view. (Original, I know.) :app:`Pyramid` has a
+centralized view :term:`application registry` where named views can be
+associated with specific resource types. So in our example, we'll assume
+that we've registered ``view`` and ``edit`` views for photo objects, and that
+we've specified the ``view`` view as the default, so that
+``/joeschmoe/photos/photo1/view`` and ``/joeschmoe/photos/photo1`` are
+equivalent. The edit view would sensibly be provided by a request for
+``/joeschmoe/photos/photo1/edit``.
+
+Hopefully it's clear that the first portion of the edit view's URL path is
+going to resolve to the same resource as the non-edit version, specifically
+the resource returned by ``get_root()['joeschmoe']['photos']['photo1']``.
+But traveral ends there; the ``photo1`` resource doesn't have an ``edit``
+key. In fact, it might not even be a dictionary-like object, in which case
+``photo1['edit']`` would be meaningless. When the :app:`Pyramid` resource
+location has been resolved to a *leaf* resource, but the entire request path
+has not yet been expended, the *very next* path segment is treated as a
+:term:`view name`. The registry is then checked to see if a view of the
+given name has been specified for a resource of the given type. If so, the
+view callable is invoked, with the resource passed in as the related
+``context`` object (also available as ``request.context``). If a view
+callable could not be found, :app:`Pyramid` will return a "404 Not Found"
+response.
+
+You might conceptualize a request for ``/joeschmoe/photos/photo1/edit`` as
+ultimately converted into the following piece of Pythonic pseudocode::
+
+ context = get_root()['joeschmoe']['photos']['photo1']
+ view_callable = get_view(context, 'edit')
+ request.context = context
+ view_callable(request)
+
+The ``get_root`` and ``get_view`` functions don't really exist. Internally,
+:app:`Pyramid` does something more complicated. But the example above
+is a reasonable approximation of the view lookup algorithm in pseudocode.
+
+Use Cases
+---------
+
+Why should we care about traversal? URL matching is easier to explain, and
+it's good enough, right?
+
+In some cases, yes, but certainly not in all cases. So far we've had very
+structured URLs, where our paths have had a specific, small number of pieces,
+like this::
+
+ /{userid}/{typename}/{objectid}[/{view_name}]
+
+In all of the examples thus far, we've hard coded the typename value,
+assuming that we'd know at development time what names were going to be used
+("photos", "blog", etc.). But what if we don't know what these names will
+be? Or, worse yet, what if we don't know *anything* about the structure of
+the URLs inside a user's folder? We could be writing a CMS where we want the
+end user to be able to arbitrarily add content and other folders inside his
+folder. He might decide to nest folders dozens of layers deep. How will you
+construct matching patterns that could account for every possible combination
+of paths that might develop?
+
+It might be possible, but it certainly won't be easy. The matching
+patterns are going to become complex quickly as you try to handle all
+of the edge cases.
+
+With traversal, however, it's straightforward. 20 layers of nesting would be
+no problem. :app:`Pyramid` will happily call ``__getitem__`` as many times
+as it needs to, until it runs out of path segments or until a resource raises
+a :exc:`KeyError`. Each resource only needs to know how to fetch its
+immediate children, the traversal algorithm takes care of the rest. Also,
+since the structure of the resource tree can live in the database and not in
+the code, it's simple to let users modify the tree at runtime to set up their
+own personalized "directory" structures.
+
+Another use case in which traversal shines is when there is a need to support
+a context-dependent security policy. One example might be a document
+management infrastructure for a large corporation, where members of different
+departments have varying access levels to the various other departments'
+files. Reasonably, even specific files might need to be made available to
+specific individuals. Traversal does well here if your resources actually
+represent the data objects related to your documents, because the idea of a
+resource authorization is baked right into the code resolution and calling
+process. Resource objects can store ACLs, which can be inherited and/or
+overridden by the subresources.
+
+If each resource can thus generate a context-based ACL, then whenever view
+code is attempting to perform a sensitive action, it can check against that
+ACL to see whether the current user should be allowed to perform the action.
+In this way you achieve so called "instance based" or "row level" security
+which is considerably harder to model using a traditional tabular approach.
+:app:`Pyramid` actively supports such a scheme, and in fact if you register
+your views with guard permissions and use an authorization policy,
+:app:`Pyramid` can check against a resource's ACL when deciding whether or
+not the view itself is available to the current user.
+
+In summary, there are entire classes of problems that are more easily served
+by traversal and view lookup than by :term:`URL dispatch`. If your problems
+don't require it, great: stick with :term:`URL dispatch`. But if you're
+using :app:`Pyramid` and you ever find that you *do* need to support one of
+these use cases, you'll be glad you have traversal in your toolkit.
+
+.. note::
+ It is even possible to mix and match :term:`traversal` with
+ :term:`URL dispatch` in the same :app:`Pyramid` application. See the
+ :ref:`hybrid_chapter` chapter for details.
diff --git a/docs/narr/project.rst b/docs/narr/project.rst
index 55a2711f3..f0ee91164 100644
--- a/docs/narr/project.rst
+++ b/docs/narr/project.rst
@@ -8,13 +8,13 @@ As we saw in :ref:`firstapp_chapter`, it's possible to create a
convenient to use a *template* to generate a basic :app:`Pyramid`
:term:`project`.
-A project is a directory that contains at least one :term:`package`. You'll
-use a template to create a project, and you'll create your application logic
-within a package that lives inside the project. Even if your application is
-extremely simple, it is useful to place code that drives the application
-within a package, because a package is more easily extended with new code.
-An application that lives inside a package can also be distributed more
-easily than one which does not live within a package.
+A project is a directory that contains at least one Python :term:`package`.
+You'll use a template to create a project, and you'll create your application
+logic within a package that lives inside the project. Even if your
+application is extremely simple, it is useful to place code that drives the
+application within a package, because a package is more easily extended with
+new code. An application that lives inside a package can also be distributed
+more easily than one which does not live within a package.
:app:`Pyramid` comes with a variety of templates that you can use to generate
a project. Each template makes different configuration assumptions about
@@ -26,13 +26,9 @@ and so therefore they are often referred to as "paster templates".
.. index::
single: paster templates
single: pyramid_starter paster template
- single: pyramid_starter_zcml paster template
single: pyramid_zodb paster template
single: pyramid_alchemy paster template
single: pyramid_routesalchemy paster template
- single: pylons_minimal paster template
- single: pylons_basic paster template
- single: pylons_sqla paster template
.. _additional_paster_templates:
@@ -48,8 +44,6 @@ each other on a number of axes:
- the mechanism they use to map URLs to code (:term:`traversal` or :term:`URL
dispatch`).
-- the type of configuration used (:term:`ZCML` vs. imperative configuration).
-
- whether or not the ``pyramid_beaker`` library is relied upon as the
sessioning implementation (as opposed to no sessioning or default
sessioning).
@@ -59,10 +53,6 @@ The included templates are these:
``pyramid_starter``
URL mapping via :term:`traversal` and no persistence mechanism.
-``pyramid_starter_zcml``
- URL mapping via :term:`traversal` and no persistence mechanism, using
- :term:`ZCML` (declarative configuration).
-
``pyramid_zodb``
URL mapping via :term:`traversal` and persistence via :term:`ZODB`.
@@ -74,20 +64,6 @@ The included templates are these:
URL mapping via :term:`traversal` and persistence via
:term:`SQLAlchemy`
-``pylons_minimal``
- URL mapping via :term:`URL dispatch` and Pylons-style view handlers,
- minimal setup, uses ``pyramid_beaker`` as a sessioning implementation.
-
-``pylons_basic``
- URL mapping via :term:`URL dispatch` and Pylons-style view handlers, and
- some extra functionality, uses ``pyramid_beaker`` as a sessioning
- implementation.
-
-``pylons_sqla``
- URL mapping via :term:`URL dispatch` and Pylons-style view handlers, some
- extra functionality, and SQLAlchemy set up, uses ``pyramid_beaker`` as a
- sessioning implementation.
-
.. index::
single: creating a project
single: project
@@ -180,7 +156,7 @@ Installing your Newly Created Project for Development
To install a newly created project for development, you should ``cd`` to the
newly created project directory and use the Python interpreter from the
:term:`virtualenv` you created during :ref:`installing_chapter` to invoke the
-command ``python setup.py develop.py``
+command ``python setup.py develop``
The file named ``setup.py`` will be in the root of the paster-generated
project directory. The ``python`` you're invoking should be the one that
@@ -601,7 +577,7 @@ or influencing runtime behavior of a :app:`Pyramid` application. See
default 'application' (although it's actually a pipeline of middleware and an
application) run by ``paster serve`` when it is invoked against this
configuration file. The name ``main`` is a convention used by PasteDeploy
-signifying that it the default application.
+signifying that it is the default application.
The ``[server:main]`` section of the configuration file configures a WSGI
server which listens on TCP port 6543. It is configured to listen on all
@@ -705,7 +681,8 @@ who want to use your application.
be included in the tarball. If you don't use Subversion, and instead use
a different version control system, you may need to install a setuptools
add-on such as ``setuptools-git`` or ``setuptools-hg`` for this behavior
- to work properly.
+ to work properly. Alternatively, you can specify the non-Python-source
+ files by hand in a ``manifest template``, called ``MANIFEST.in`` by default.
``setup.cfg``
~~~~~~~~~~~~~
@@ -876,9 +853,6 @@ represent the root.
This directory contains static assets which support the ``mytemplate.pt``
template. It includes CSS and images.
-.. index::
- single: tests.py
-
``templates/mytemplate.pt``
~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -892,6 +866,9 @@ Templates are accessed and used by view configurations and sometimes by view
functions themselves. See :ref:`templates_used_directly` and
:ref:`templates_used_as_renderers`.
+.. index::
+ single: tests.py
+
``tests.py``
~~~~~~~~~~~~
@@ -910,6 +887,8 @@ example.
See :ref:`testing_chapter` for more information about writing :app:`Pyramid`
unit tests.
+.. _modifying_package_structure:
+
Modifying Package Structure
----------------------------
@@ -958,12 +937,14 @@ To this:
.. code-block:: python
:linenos:
- config.add_view('myproject.views.blogs.my_view',
+ config.add_view('myproject.views.blog.my_view',
renderer='myproject:templates/mytemplate.pt')
You can then continue to add files to the ``views`` directory, and refer to
-views or handler classes/functions within those files via the dotted name
-passed as the first argument to ``add_view``. For example:
+view classes or functions within those files via the dotted name passed as
+the first argument to ``add_view``. For example, if you added a file named
+``anothermodule.py`` to the ``views`` subdirectory, and added a view callable
+named ``my_view`` to it:
.. code-block:: python
:linenos:
diff --git a/docs/narr/renderers.rst b/docs/narr/renderers.rst
index 3804fcf42..a80c5a9c2 100644
--- a/docs/narr/renderers.rst
+++ b/docs/narr/renderers.rst
@@ -3,18 +3,10 @@
Renderers
=========
-In the :ref:`views_chapter` chapter, we said that a view callable must
-return a :term:`Response` object. We lied. A :term:`renderer` is a service
-that attempts to convert a non-Response return value of a function, class, or
-instance that acts as a :term:`view callable` to a :term:`Response` object.
-
-Overview
---------
-
-A view needn't *always* return a Response object. If a view happens to
-return something which does not implement the Pyramid Response interface,
-:app:`Pyramid` will attempt to use a :term:`renderer` to construct a
-response. For example:
+A view needn't *always* return a :term:`Response` object. If a view
+happens to return something which does not implement the Pyramid
+Response interface, :app:`Pyramid` will attempt to use a
+:term:`renderer` to construct a response. For example:
.. code-block:: python
:linenos:
@@ -22,6 +14,7 @@ response. For example:
from pyramid.response import Response
from pyramid.view import view_config
+ @view_config(renderer='json')
def hello_world(request):
return {'content':'Hello!'}
@@ -396,21 +389,17 @@ documentation in :ref:`request_module`.
.. _adding_and_overriding_renderers:
-Adding and Overriding Renderers
--------------------------------
+Adding and Changing Renderers
+-----------------------------
New templating systems and serializers can be associated with :app:`Pyramid`
renderer names. To this end, configuration declarations can be made which
-override an existing :term:`renderer factory`, and which add a new renderer
+change an existing :term:`renderer factory`, and which add a new renderer
factory.
Renderers can be registered imperatively using the
:meth:`pyramid.config.Configurator.add_renderer` API.
-.. note:: The tasks described in this section can also be performed via
- :term:`declarative configuration`. See
- :ref:`zcml_adding_and_overriding_renderers`.
-
For example, to add a renderer which renders views which have a
``renderer`` attribute that is a path that ends in ``.jinja2``:
@@ -553,7 +542,7 @@ set as ``renderer=`` in the view configuration.
See also :ref:`renderer_directive` and
:meth:`pyramid.config.Configurator.add_renderer`.
-Overriding an Existing Renderer
+Changing an Existing Renderer
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
You can associate more than one filename extension with the same existing
@@ -570,7 +559,7 @@ extension for the same kinds of templates. For example, to associate the
After you do this, :app:`Pyramid` will treat templates ending in both the
``.pt`` and ``.zpt`` filename extensions as Chameleon ZPT templates.
-To override the default mapping in which files with a ``.pt`` extension are
+To change the default mapping in which files with a ``.pt`` extension are
rendered via a Chameleon ZPT page template renderer, use a variation on the
following in your application's startup code:
@@ -592,3 +581,44 @@ the ``name`` attribute to the renderer tag:
config.add_renderer(None, 'mypackage.json_renderer_factory')
+Overriding A Renderer At Runtime
+--------------------------------
+
+.. warning:: This is an advanced feature, not typically used by "civilians".
+
+In some circumstances, it is necessary to instruct the system to ignore the
+static renderer declaration provided by the developer in view configuration,
+replacing the renderer with another *after a request starts*. For example,
+an "omnipresent" XML-RPC implementation that detects that the request is from
+an XML-RPC client might override a view configuration statement made by the
+user instructing the view to use a template renderer with one that uses an
+XML-RPC renderer. This renderer would produce an XML-RPC representation of
+the data returned by an arbitrary view callable.
+
+To use this feature, create a :class:`pyramid.events.NewRequest`
+:term:`subscriber` which sniffs at the request data and which conditionally
+sets an ``override_renderer`` attribute on the request itself, which is the
+*name* of a registered renderer. For example:
+
+.. code-block:: python
+ :linenos:
+
+ from pyramid.event import subscriber
+ from pyramid.event import NewRequest
+
+ @subscriber(NewRequest)
+ def set_xmlrpc_params(event):
+ request = event.request
+ if (request.content_type == 'text/xml'
+ and request.method == 'POST'
+ and not 'soapaction' in request.headers
+ and not 'x-pyramid-avoid-xmlrpc' in request.headers):
+ params, method = parse_xmlrpc_request(request)
+ request.xmlrpc_params, request.xmlrpc_method = params, method
+ request.is_xmlrpc = True
+ request.override_renderer = 'xmlrpc'
+ return True
+
+The result of such a subscriber will be to replace any existing static
+renderer configured by the developer with a (notional, nonexistent) XML-RPC
+renderer if the request appears to come from an XML-RPC client.
diff --git a/docs/narr/resourcelocation.rst b/docs/narr/resourcelocation.rst
deleted file mode 100644
index 8ddc890ed..000000000
--- a/docs/narr/resourcelocation.rst
+++ /dev/null
@@ -1,103 +0,0 @@
-.. index::
- single: resource location
-
-.. _resourcelocation_chapter:
-
-Resource Location and View Lookup
----------------------------------
-
-:app:`Pyramid` uses two separate but cooperating subsystems to find and
-invoke :term:`view callable` code written by the application developer:
-:term:`resource location` and :term:`view lookup`.
-
-- First, a :app:`Pyramid` :term:`resource location` subsystem is given a
- :term:`request`; it is responsible for finding a :term:`resource` object
- based on information present in the request. When a resource is found via
- resource location, it becomes known as the :term:`context`.
-
-- Next, using the context resource found by :term:`resource location` and the
- :term:`request`, :term:`view lookup` is then responsible for finding and
- invoking a :term:`view callable`. A view callable is a specific bit of
- code written and registered by the application developer which receives the
- :term:`request` and which returns a :term:`response`.
-
-These two subsystems are used by :app:`Pyramid` serially: first, a
-:term:`resource location` subsystem does its job. Then the result of
-resource location is passed to the :term:`view lookup` subsystem. The view
-lookup system finds a :term:`view callable` written by an application
-developer, and invokes it. A view callable returns a :term:`response`. The
-response is returned to the requesting user.
-
-There are two separate :term:`resource location` subsystems in
-:app:`Pyramid`: :term:`traversal` and :term:`URL dispatch`. They can be used
-separately or they can be combined. Three chapters which follow describe
-:term:`resource location`: :ref:`traversal_chapter`,
-:ref:`urldispatch_chapter` and :ref:`hybrid_chapter`.
-
-There is only one :term:`view lookup` subsystem present in :app:`Pyramid`.
-Where appropriate, we will describe how view lookup interacts with context
-finding. One chapter which follows describes :term:`view lookup`:
-:ref:`views_chapter`.
-
-Should I Use Traversal or URL Dispatch for Resource Location?
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-When you use :app:`Pyramid`, you have a choice about how you'd like to
-resolve URLs to code: you can use either :term:`traversal` or :term:`URL
-dispatch`. The choice to use traversal vs. URL dispatch is largely
-"religious". Since :app:`Pyramid` provides support for both approaches, you
-can use either exclusively or combine them as you see fit.
-
-:term:`URL dispatch` is very straightforward. When you limit your
-application to using URL dispatch, you know every URL that your application
-might generate or respond to, all the URL matching elements are listed in a
-single place, and you needn't think about :term:`resource location` or
-:term:`view lookup` at all.
-
-URL dispatch can easily handle URLs such as
-``http://example.com/members/Chris``, where it's assumed that each item
-"below" ``members`` in the URL represents a single member in some system.
-You just match everything "below" ``members`` to a particular :term:`view
-callable`, e.g. ``/members/{memberid}``.
-
-However, URL dispatch is not very convenient if you'd like your URLs to
-represent an arbitrary-depth hierarchy. For example, if you need to infer
-the difference between sets of URLs such as these, where the ``document`` in
-the first URL represents a PDF document, and ``/stuff/page`` in the second
-represents an OpenOffice document in a "stuff" folder.
-
-.. code-block:: text
-
- http://example.com/members/Chris/document
- http://example.com/members/Chris/stuff/page
-
-It takes more pattern matching assertions to be able to make hierarchies work
-in URL-dispatch based systems, and some assertions just aren't possible.
-URL-dispatch based systems just don't deal very well with URLs that represent
-arbitrary-depth hierarchies.
-
-:term:`URL dispatch` tends to collapse the two steps of :term:`resource
-location` and :term:`view lookup` into a single step. Thus, a URL can map
-*directly* to a view callable. This makes URL dispatch easier to understand
-than traversal, because traversal makes you understand how :term:`resource
-location` works. But explicitly locating a resource provides extra
-flexibility. For example, it makes it possible to protect your application
-with declarative context-sensitive instance-level :term:`authorization`.
-
-Unlike URL dispatch, :term:`traversal` works well for URLs that represent
-arbitrary-depth hierarchies. Since the path segments that compose a URL are
-addressed separately, it becomes very easy to form URLs that represent
-arbitrary depth hierarchies in a system that uses traversal. When you're
-willing to treat your application resources as a tree that can be traversed,
-it also becomes easy to provide "instance-level security": you just attach an
-:term:`ACL` security declaration to each resource in the tree. This is not
-nearly as easy to do when using URL dispatch.
-
-Traversal probably just doesn't make any sense when you possess completely
-"square" data stored in a relational database because it requires the
-construction and maintenance of a resource tree and requires that the
-developer think about mapping URLs to code in terms of traversing that tree.
-
-We'll examine both :term:`URL dispatch` and :term:`traversal` in the next two
-chapters.
-
diff --git a/docs/narr/resources.rst b/docs/narr/resources.rst
index ac88afdfd..c97b4c676 100644
--- a/docs/narr/resources.rst
+++ b/docs/narr/resources.rst
@@ -1,21 +1,23 @@
+.. _resources_chapter:
+
Resources
=========
-A :term:`resource` is an object that represents a "place" in a tree related
-to your application. Every :app:`Pyramid` application has at least one
-resource object: the :term:`root` resource (even if you don't define one
-manually, a default root resource is created for you). The root resource is
-the root of a :term:`resource tree`. A resource tree is a set of nested
-dictionary-like objects which you can use to represent your website's
-structure.
+A :term:`resource` is an object that represents a "place" in a tree
+related to your application. Every :app:`Pyramid` application has at
+least one resource object: the :term:`root` resource. Even if you don't
+define a root resource manually, a default one is created for you. The
+root resource is the root of a :term:`resource tree`. A resource tree
+is a set of nested dictionary-like objects which you can use to
+represent your website's structure.
In an application which uses :term:`traversal` to map URLs to code, the
-resource tree structure is used heavily to map a URL to a :term:`view
-callable`. :app:`Pyramid` will walk "up" the resource tree by traversing
-through the nested dictionary structure of the tree when :term:`traversal` is
-used in order to find a :term:`context` resource. Once a context resource is
-found, the context resource and data in the request will be used to find a
-:term:`view callable`.
+resource tree structure is used heavily to map each URL to a :term:`view
+callable`. When :term:`traversal` is used, :app:`Pyramid` will walk
+through the resource tree by traversing through its nested dictionary
+structure in order to find a :term:`context` resource. Once a context
+resource is found, the context resource and data in the request will be
+used to find a :term:`view callable`.
In an application which uses :term:`URL dispatch`, the resource tree is only
used indirectly, and is often "invisible" to the developer. In URL dispatch
@@ -26,7 +28,7 @@ much less important in applications that use URL dispatch than applications
that use traversal.
In "Zope-like" :app:`Pyramid` applications, resource objects also often store
-data persistently and offer methods related to mutating that persistent data.
+data persistently, and offer methods related to mutating that persistent data.
In these kinds of applications, resources not only represent the site
structure of your website, but they become the :term:`domain model` of the
application.
@@ -72,8 +74,8 @@ tree:
the container's ``__getitem__`` should return the sub-resource.
- Leaf resources, which do not contain other resources, must not implement a
- ``__getitem__``, or if they do, their ``__getitem__`` method must raise a
- :exc:`KeyError`.
+ ``__getitem__``, or if they do, their ``__getitem__`` method must always
+ raise a :exc:`KeyError`.
See :ref:`traversal_chapter` for more information about how traversal
works against resource instances.
@@ -184,7 +186,7 @@ you will reach the filesystem root directory.
objects "by hand". Instead, as necessary, during traversal :app:`Pyramid`
will wrap each resource (even the root resource) in a ``LocationProxy``
which will dynamically assign a ``__name__`` and a ``__parent__`` to the
- traversed resrouce (based on the last traversed resource and the name
+ traversed resource (based on the last traversed resource and the name
supplied to ``__getitem__``). The root resource will have a ``__name__``
attribute of ``None`` and a ``__parent__`` attribute of ``None``.
@@ -239,7 +241,7 @@ A slash is appended to all resource URLs when
:func:`~pyramid.url.resource_url` is used to generate them in this simple
manner, because resources are "places" in the hierarchy, and URLs are meant
to be clicked on to be visited. Relative URLs that you include on HTML pages
-rendered as the result of the default view of a resource are typically more
+rendered as the result of the default view of a resource are more
apt to be relative to these resources than relative to their parent.
You can also pass extra elements to :func:`~pyramid.url.resource_url`:
@@ -404,7 +406,7 @@ Obtaining the Lineage of a Resource
-----------------------------------
:func:`pyramid.location.lineage` returns a generator representing the
-:term:`lineage` of the :term:`location` aware:term:`resource` object.
+:term:`lineage` of the :term:`location` aware :term:`resource` object.
The :func:`~pyramid.location.lineage` function returns the resource it is
passed, then each parent of the resource, in order. For example, if the
@@ -533,7 +535,7 @@ declares that the blog entry implements an :term:`interface`.
implements(IBlogEntry)
def __init__(self, title, body, author):
self.title = title
- self.body = body
+ self.body = body
self.author = author
self.created = datetime.datetime.now()
@@ -568,7 +570,7 @@ To do so, use the :func:`zope.interface.directlyProvides` function:
class BlogEntry(object):
def __init__(self, title, body, author):
self.title = title
- self.body = body
+ self.body = body
self.author = author
self.created = datetime.datetime.now()
@@ -596,7 +598,7 @@ the :func:`zope.interface.alsoProvides` function:
class BlogEntry(object):
def __init__(self, title, body, author):
self.title = title
- self.body = body
+ self.body = body
self.author = author
self.created = datetime.datetime.now()
diff --git a/docs/narr/router.rst b/docs/narr/router.rst
index d3d5bd370..782098bac 100644
--- a/docs/narr/router.rst
+++ b/docs/narr/router.rst
@@ -44,7 +44,7 @@ processing?
#. If any route matches, the request is mutated; a ``matchdict`` and
``matched_route`` attributes are added to the request object; the
- former contains a dictionary representign the matched dynamic
+ former contains a dictionary representing the matched dynamic
elements of the request's ``PATH_INFO`` value, the latter contains
the :class:`pyramid.interfaces.IRoute` object representing the
route which matched. The root object associated with the route
@@ -133,6 +133,6 @@ processing?
This is a very high-level overview that leaves out various details.
For more detail about subsystems invoked by the :app:`Pyramid` router
such as traversal, URL dispatch, views, and event processing, see
-:ref:`resourcelocation_chapter`, :ref:`views_chapter`, and
+:ref:`urldispatch_chapter`, :ref:`views_chapter`, and
:ref:`events_chapter`.
diff --git a/docs/narr/security.rst b/docs/narr/security.rst
index c5262faa2..e395b15f1 100644
--- a/docs/narr/security.rst
+++ b/docs/narr/security.rst
@@ -6,20 +6,20 @@
Security
========
-:app:`Pyramid` provides an optional declarative authorization system that
-prevents a :term:`view` from being invoked when the user represented by
-credentials in the :term:`request` does not have an appropriate level of
-access when a particular resource is the :term:`context`. Here's how it
-works at a high level:
+:app:`Pyramid` provides an optional declarative authorization system
+that 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 :term:`request` is generated when a user visits our application.
+- 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
- :ref:`resourcelocation_chapter` for more information about resource
- location.
+ 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.
@@ -41,6 +41,15 @@ works at a high level:
- If the authorization policy denies access, the view callable is not
invoked; instead the :term:`forbidden view` is invoked.
+Security in :app:`Pyramid`, unlike many systems, cleanly and explicitly
+separates authentication and authorization. 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 in effect during the request.
+Authorization then determines access based on the :term:`principal`
+identifiers, the :term:`view callable` being invoked, and the
+:term:`context` resource.
+
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
@@ -107,9 +116,6 @@ See also the :mod:`pyramid.authorization` and
:mod:`pyramid.authentication` modules for alternate implementations
of authorization and authentication policies.
-You can also enable a security policy declaratively via ZCML. See
-:ref:`zcml_authorization_policy`.
-
.. index::
single: permissions
single: protecting views
@@ -155,9 +161,6 @@ may be performed via the ``@view_config`` decorator:
""" Add blog entry code goes here """
pass
-Or the same thing can be done using the ``permission`` attribute of the ZCML
-:ref:`view_directive` directive.
-
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
@@ -170,8 +173,8 @@ 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 always be executable by entirely anonymous users: any
+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
@@ -190,8 +193,6 @@ application:
:meth:`pyramid.config.Configurator.set_default_permission`
method.
-- The :ref:`default_permission_directive` ZCML directive.
-
When a default permission is registered:
- if a view configuration names an explicit ``permission``, the default
diff --git a/docs/narr/sessions.rst b/docs/narr/sessions.rst
index de9add3b7..0ed52b563 100644
--- a/docs/narr/sessions.rst
+++ b/docs/narr/sessions.rst
@@ -3,13 +3,18 @@
.. _sessions_chapter:
-Session Objects
-===============
+Sessions
+========
A :term:`session` is a namespace which is valid for some period of
continual activity that can be used to represent a user's interaction
with a web application.
+This chapter describes how to configure sessions, what session
+implementations :app:`Pyramid` provides out of the box, how to store and
+retrieve data from sessions, and two session-specific features: flash
+messages, and cross-site request forgery attack prevention.
+
.. _using_the_default_session_factory:
Using The Default Session Factory
@@ -32,7 +37,7 @@ limitation:
representation of the session is fewer than 4000. This is
suitable only for very small data sets.
-It is, however, digitally signed, and thus its data cannot easily be
+It is digitally signed, however, and thus its data cannot easily be
tampered with.
You can configure this session factory in your :app:`Pyramid`
@@ -113,7 +118,7 @@ documentation.
Some gotchas:
- Keys and values of session data must be *pickleable*. This means,
- typically, that they must be instances of basic types of objects,
+ typically, that they are instances of basic types of objects,
such as strings, lists, dictionaries, tuples, integers, etc. If you
place an object in a session data key or value that is not
pickleable, an error will be raised when the session is serialized.
@@ -162,3 +167,180 @@ both types are available in
:class:`pyramid.interfaces.ISession`. You might use the cookie
implementation in the :mod:`pyramid.session` module as inspiration.
+.. index::
+ single: flash messages
+
+Flash Messages
+--------------
+
+"Flash messages" are simply a queue of message strings stored in the
+:term:`session`. To use flash messaging, you must enable a :term:`session
+factory` as described in :ref:`using_the_default_session_factory` or
+:ref:`using_alternate_session_factories`.
+
+Flash messaging has two main uses: to display a status message only once to
+the user after performing an internal redirect, and to allow generic code to
+log messages for single-time display without having direct access to an HTML
+template. The user interface consists of a number of methods of the
+:term:`session` object.
+
+Using the ``session.flash`` Method
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+To add a message to a flash message queue, use a session object's ``flash()``
+method:
+
+.. code-block:: python
+
+ request.session.flash('mymessage')
+
+The ``flash()`` method appends a message to a flash queue, creating the queue
+if necessary.
+
+``flash()`` accepts three arguments:
+
+.. method:: flash(message, queue='', allow_duplicate=True)
+
+The ``message`` argument is required. It represents a message you wish to
+later display to a user. It is usually a string but the ``message`` you
+provide is not modified in any way.
+
+The ``queue`` argument allows you to choose a queue to which to append
+the message you provide. This can be used to push different kinds of
+messages into flash storage for later display in different places on a
+page. You can pass any name for your queue, but it must be a string.
+Each queue is independent, and can be popped by ``pop_flash()`` or
+examined via ``peek_flash()`` separately. ``queue`` defaults to the
+empty string. The empty string represents the default flash message
+queue.
+
+.. code-block:: python
+
+ request.session.flash(msg, 'myappsqueue')
+
+The ``allow_duplicate`` argument defaults to ``True``. If this is
+``False``, and you attempt to add a message value which is already
+present in the queue, it will not be added.
+
+Using the ``session.pop_flash`` Method
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Once one or more messages have been added to a flash queue by the
+``session.flash()`` API, the ``session.pop_flash()`` API can be used to
+pop an entire queue and return it for use.
+
+To pop a particular queue of messages from the flash object, use the session
+object's ``pop_flash()`` method. This returns a list of the messages
+that were added to the flash queue, and empties the queue.
+
+.. method:: pop_flash(queue='')
+
+.. code-block:: python
+ :linenos:
+
+ >>> request.session.flash('info message')
+ >>> request.session.pop_flash()
+ ['info message']
+
+Calling ``session.pop_flash()`` again like above without a corresponding call
+to ``session.flash()`` will return an empty list, because the queue has already
+been popped.
+
+.. code-block:: python
+ :linenos:
+
+ >>> request.session.flash('info message')
+ >>> request.session.pop_flash()
+ ['info message']
+ >>> request.session.pop_flash()
+ []
+
+Using the ``session.peek_flash`` Method
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Once one or more messages has been added to a flash queue by the
+``session.flash()`` API, the ``session.peek_flash()`` API can be used to
+"peek" at that queue. Unlike ``session.pop_flash()``, the queue is not
+popped from flash storage.
+
+.. method:: peek_flash(queue='')
+
+.. code-block:: python
+ :linenos:
+
+ >>> request.session.flash('info message')
+ >>> request.session.peek_flash()
+ ['info message']
+ >>> request.session.peek_flash()
+ ['info message']
+ >>> request.session.pop_flash()
+ ['info message']
+ >>> request.session.peek_flash()
+ []
+
+.. index::
+ single: preventing cross-site request forgery attacks
+ single: cross-site request forgery attacks, prevention
+
+Preventing Cross-Site Request Forgery Attacks
+---------------------------------------------
+
+`Cross-site request forgery
+<http://en.wikipedia.org/wiki/Cross-site_request_forgery>`_ attacks are a
+phenomenon whereby a user with an identity on your website might click on a
+URL or button on another website which unwittingly redirects the user to your
+application to perform some command that requires elevated privileges.
+
+You can avoid most of these attacks by making sure that the correct *CSRF
+token* has been set in an :app:`Pyramid` session object before performing any
+actions in code which requires elevated privileges that is invoked via a form
+post. To use CSRF token support, you must enable a :term:`session factory`
+as described in :ref:`using_the_default_session_factory` or
+:ref:`using_alternate_session_factories`.
+
+Using the ``session.get_csrf_token`` Method
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+To get the current CSRF token from the session, use the
+``session.get_csrf_token()`` method.
+
+.. code-block:: python
+
+ token = request.session.get_csrf_token()
+
+The ``session.get_csrf_token()`` method accepts no arguments. It returns a
+CSRF *token* string. If ``session.get_csrf_token()`` or
+``session.new_csrf_token()`` was invoked previously for this session, the
+existing token will be returned. If no CSRF token previously existed for
+this session, a new token will be will be set into the session and returned.
+The newly created token will be opaque and randomized.
+
+You can use the returned token as the value of a hidden field in a form that
+posts to a method that requires elevated privileges. The handler for the
+form post should use ``session.get_csrf_token()`` *again* to obtain the
+current CSRF token related to the user from the session, and compare it to
+the value of the hidden form field. For example, if your form rendering
+included the CSRF token obtained via ``session.get_csrf_token()`` as a hidden
+input field named ``csrf_token``:
+
+.. code-block:: python
+ :linenos:
+
+ token = request.session.get_csrf_token()
+ if token != request.POST['csrf_token']:
+ raise ValueError('CSRF token did not match')
+
+Using the ``session.new_csrf_token`` Method
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+To explicitly add a new CSRF token to the session, use the
+``session.new_csrf_token()`` method. This differs only from
+``session.get_csrf_token()`` inasmuch as it clears any existing CSRF token,
+creates a new CSRF token, sets the token into the session, and returns the
+token.
+
+.. code-block:: python
+
+ token = request.session.new_csrf_token()
+
+
diff --git a/docs/narr/templates.rst b/docs/narr/templates.rst
index 437b823e9..b97cc7be6 100644
--- a/docs/narr/templates.rst
+++ b/docs/narr/templates.rst
@@ -448,7 +448,7 @@ Here's what a simple :term:`Chameleon` ZPT template used under
<body>
<h1 class="title">Welcome to <code>${project}</code>, an
application generated by the <a
- href="http://pylonshq.com/pyramid">pyramid</a> web
+ href="http://docs.pylonsproject.org/projects/pyramid/dev/">pyramid</a> web
application framework.</h1>
</body>
</html>
@@ -628,7 +628,7 @@ application's configuration section, e.g.:
.. code-block:: ini
:linenos:
- [app:main]
+ [app:MyProject]
use = egg:MyProject#app
debug_templates = true
@@ -744,7 +744,7 @@ look like:
<body>
<h1 class="title">Welcome to <code>${project}</code>, an
application generated by the <a
- href="http://pylonshq.com/pyramid">pyramid</a> web
+ href="http://docs.pylonsproject.org/projects/pyramid/dev/">pyramid</a> web
application framework.</h1>
</body>
</html>
diff --git a/docs/narr/testing.rst b/docs/narr/testing.rst
index 007b96c2a..0968ad229 100644
--- a/docs/narr/testing.rst
+++ b/docs/narr/testing.rst
@@ -78,81 +78,84 @@ See :ref:`threadlocals_chapter` for information about these functions and the
data structures they return.
If your code uses these ``get_current_*`` functions or calls :app:`Pyramid`
-code which uses ``get_current_*`` functions, you will need to construct a
-:term:`Configurator` and call its ``begin`` method within the ``setUp``
-method of your unit test and call the same Configurator's ``end`` method
-within the ``tearDown`` method of your unit test.
-
-We'll also instruct the Configurator we use during testing to *autocommit*.
-Normally when a Configurator is used by an application, it defers performing
-any "real work" until its ``.commit`` method is called (often implicitly by
-the :meth:`pyramid.config.Configurator.make_wsgi_app` method). Passing
-``autocommit=True`` to the Configurator constructor causes the Configurator
-to perform all actions implied by methods called on it immediately, which is
-more convenient for unit-testing purposes than needing to call
-:meth:`pyramid.config.Configurator.commit` in each test.
-
-The use of a Configurator and its ``begin`` and ``end`` methods allows you to
-supply each unit test method in a test case with an environment that has an
-isolated registry and an isolated request for the duration of a single test.
-Here's an example of using this feature:
+code which uses ``get_current_*`` functions, you will need to call
+:func:`pyramid.testing.setUp` in your test setup and you will need to call
+:func:`pyramid.testing.tearDown` in your test teardown.
+:func:`~pyramid.testing.setUp` pushes a registry onto the :term:`thread
+local` stack, which makes the ``get_current_*`` functions work. It returns a
+:term:`Configurator` object which can be used to perform extra configuration
+required by the code under test. :func:`~pyramid.testing.tearDown` pops the
+thread local stack.
+
+Normally when a Configurator is used directly with the ``main`` block of
+a Pyramid application, it defers performing any "real work" until its
+``.commit`` method is called (often implicitly by the
+:meth:`pyramid.config.Configurator.make_wsgi_app` method). The
+Configurator returned by :func:`~pyramid.testing.setUp` is an
+*autocommitting* Configurator, however, which performs all actions
+implied by methods called on it immediately. This is more convenient
+for unit-testing purposes than needing to call
+:meth:`pyramid.config.Configurator.commit` in each test after adding
+extra configuration statements.
+
+The use of the :func:`~pyramid.testing.setUp` and
+:func:`~pyramid.testing.tearDown` functions allows you to supply each unit
+test method in a test case with an environment that has an isolated registry
+and an isolated request for the duration of a single test. Here's an example
+of using this feature:
.. code-block:: python
:linenos:
import unittest
- from pyramid.config import Configurator
+ from pyramid import testing
class MyTest(unittest.TestCase):
def setUp(self):
- self.config = Configurator(autocommit=True)
- self.config.begin()
+ self.config = testing.setUp()
def tearDown(self):
- self.config.end()
+ testing.tearDown()
The above will make sure that
-:func:`pyramid.threadlocal.get_current_registry` will return the
-:term:`application registry` associated with the ``config`` Configurator
-instance when :func:`pyramid.threadlocal.get_current_registry` is called in a
-test case method attached to ``MyTest``. Each test case method attached to
-``MyTest`` will use an isolated registry.
+:func:`pyramid.threadlocal.get_current_registry` called within a test
+case method of ``MyTest`` will return the :term:`application registry`
+associated with the ``config`` Configurator instance. Each test case
+method attached to ``MyTest`` will use an isolated registry.
-The :meth:`pyramid.config.Configurator.begin` method accepts various
-arguments that influence the code run during the test. See the
-:ref:`configuration_module` chapter for information about the API of a
-:term:`Configurator`, including its ``begin`` and ``end`` methods.
+The :func:`~pyramid.testing.setUp` and :func:`~pyramid.testing.tearDown`
+functions accepts various arguments that influence the environment of the
+test. See the :ref:`testing_module` chapter for information about the extra
+arguments supported by these functions.
If you also want to make :func:`pyramid.get_current_request` return something
other than ``None`` during the course of a single test, you can pass a
-:term:`request` object into the :meth:`pyramid.config.Configurator.begin`
-method of the Configurator within the ``setUp`` method of your test:
+:term:`request` object into the :func:`pyramid.testing.setUp` within the
+``setUp`` method of your test:
.. code-block:: python
:linenos:
import unittest
- from pyramid.config import Configurator
from pyramid import testing
class MyTest(unittest.TestCase):
def setUp(self):
- self.config = Configurator(autocommit=True)
request = testing.DummyRequest()
- self.config.begin(request=request)
+ self.config = testing.setUp(request=request)
def tearDown(self):
- self.config.end()
-
-If you pass a :term:`request` object into the ``begin`` method of the
-configurator within your test case's ``setUp``, any test method attached to
-the ``MyTest`` test case that directly or indirectly calls
-:func:`pyramid.threadlocal.get_current_request` will receive the request you
-passed into the ``begin`` method. Otherwise, during testing,
-:func:`pyramid.threadlocal.get_current_request` will return ``None``. We use
-a "dummy" request implementation supplied by
-:class:`pyramid.testing.DummyRequest` because it's easier to construct than a
-"real" :app:`Pyramid` request object.
+ testing.tearDown()
+
+If you pass a :term:`request` object into :func:`pyramid.testing.setUp`
+within your test case's ``setUp``, any test method attached to the
+``MyTest`` test case that directly or indirectly calls
+:func:`pyramid.threadlocal.get_current_request` will receive the request
+object. Otherwise, during testing,
+:func:`pyramid.threadlocal.get_current_request` will return ``None``.
+We use a "dummy" request implementation supplied by
+:class:`pyramid.testing.DummyRequest` because it's easier to construct
+than a "real" :app:`Pyramid` request object.
What?
~~~~~
@@ -162,18 +165,18 @@ they're used by frameworks. Sorry. So here's a rule of thumb: if you don't
*know* whether you're calling code that uses the
:func:`pyramid.threadlocal.get_current_registry` or
:func:`pyramid.threadlocal.get_current_request` functions, or you don't care
-about any of this, but you still want to write test code, just always create
-an autocommitting Configurator instance and call its ``begin`` method within
-the ``setUp`` of a unit test, then subsequently call its ``end`` method in
-the test's ``tearDown``. This won't really hurt anything if the application
-you're testing does not call any ``get_current*`` function.
+about any of this, but you still want to write test code, just always call
+:func:`pyramid.testing.setUp` in your test's ``setUp`` method and
+:func:`pyramid.testing.tearDown` in your tests' ``tearDown`` method. This
+won't really hurt anything if the application you're testing does not call
+any ``get_current*`` function.
.. index::
single: pyramid.testing
single: Configurator testing API
Using the ``Configurator`` and ``pyramid.testing`` APIs in Unit Tests
-------------------------------------------------------------------------
+---------------------------------------------------------------------
The ``Configurator`` API and the ``pyramid.testing`` module provide a number
of functions which can be used during unit testing. These functions make
@@ -198,13 +201,11 @@ Without invoking any startup code or using the testing API, an attempt to run
this view function in a unit test will result in an error. When a
:app:`Pyramid` application starts normally, it will populate a
:term:`application registry` using :term:`configuration declaration` calls
-made against a :term:`Configurator` (sometimes deferring to the application's
-``configure.zcml`` :term:`ZCML` file via ``load_zcml``). But if this
-application registry is not created and populated (e.g. with an
+made against a :term:`Configurator`. But if this application registry is not
+created and populated (e.g. with an
:meth:`pyramid.config.Configurator.add_view` :term:`configuration
-declaration` or ``view`` declarations in :term:`ZCML`), like when you invoke
-application code via a unit test, :app:`Pyramid` API functions will tend to
-fail.
+declaration`), like when you invoke application code via a unit test,
+:app:`Pyramid` API functions will tend to fail.
The testing API provided by :app:`Pyramid` allows you to simulate various
application registry registrations for use under a unit testing framework
@@ -217,16 +218,14 @@ without needing to invoke the actual application configuration implied by its
:linenos:
import unittest
- from pyramid.config import Configurator
from pyramid import testing
class MyTest(unittest.TestCase):
def setUp(self):
- self.config = Configurator(autocommit=True)
- self.config.begin()
+ self.config = testing.setUp()
def tearDown(self):
- self.config.end()
+ testing.tearDown()
def test_view_fn_not_submitted(self):
from my.package import view_fn
@@ -277,8 +276,8 @@ performs a similar template registration and assertion. We assert at the end
of this that the renderer's ``say`` attribute is ``Yo``, as this is what is
expected of the view function in the branch it's testing.
-Note that the test calls the :meth:`pyramid.config.Configurator.begin` method
-in its ``setUp`` method and the ``end`` method of the same in its
+Note that the test calls the :func:`pyramid.testing.setUp` function in its
+``setUp`` method and the :func:`pyramid.testing.tearDown` function in its
``tearDown`` method. If you use any of the
:class:`pyramid.config.Configurator` APIs during testing, be sure to use this
pattern in your test case's ``setUp`` and ``tearDown``; these methods make
@@ -309,12 +308,13 @@ implementations to give the code under test only enough context to run.
some code *and* its integration with the rest of the :app:`Pyramid`
framework.
-In :app:`Pyramid` applications that use :term:`ZCML`, you can create an
-integration test by *loading its ZCML* in the test's setup code. This causes
-the entire :app:`Pyramid` environment to be set up and torn down as if your
-application was running "for real". This is a heavy-hammer way of making
-sure that your tests have enough context to run properly, and it tests your
-code's integration with the rest of :app:`Pyramid`.
+In :app:`Pyramid` applications that are plugins to Pyramid, you can create an
+integration test by including it's ``includeme`` function via
+:meth:`pyramid.config.Configurator.include` in the test's setup code. This
+causes the entire :app:`Pyramid` environment to be set up and torn down as if
+your application was running "for real". This is a heavy-hammer way of
+making sure that your tests have enough context to run properly, and it tests
+your code's integration with the rest of :app:`Pyramid`.
Let's demonstrate this by showing an integration test for a view. The below
test assumes that your application's package name is ``myapp``, and that
@@ -327,23 +327,21 @@ after accessing some values that require a fully set up environment.
import unittest
- from pyramid.config import Configurator
from pyramid import testing
class ViewIntegrationTests(unittest.TestCase):
def setUp(self):
""" This sets up the application registry with the
- registrations your application declares in its configure.zcml
- (including dependent registrations for pyramid itself).
+ registrations your application declares in its ``includeme``
+ function.
"""
import myapp
- self.config = Configurator(package=myapp, autocommit=True)
- self.config.begin()
- self.config.load_zcml('myapp:configure.zcml')
+ self.config = testing.setUp()
+ self.config.include('myapp')
def tearDown(self):
""" Clear out the application registry """
- self.config.end()
+ testing.tearDown()
def test_my_view(self):
from myapp.views import my_view
diff --git a/docs/narr/threadlocals.rst b/docs/narr/threadlocals.rst
index 171eaa1c7..13bfe41cb 100644
--- a/docs/narr/threadlocals.rst
+++ b/docs/narr/threadlocals.rst
@@ -111,8 +111,8 @@ follows:
each as ``request``).
- ``get_current_request`` should never be called in :term:`resource` code.
- If a resource needs access to the request, it should be passed the request
- by a :term:`view callable`.
+ If a resource needs access to the request, it should be passed the request
+ by a :term:`view callable`.
- ``get_current_request`` function should never be called because it's
"easier" or "more elegant" to think about calling it than to pass a
diff --git a/docs/narr/traversal.rst b/docs/narr/traversal.rst
index 2d7878265..7c6280ba1 100644
--- a/docs/narr/traversal.rst
+++ b/docs/narr/traversal.rst
@@ -3,33 +3,22 @@
Traversal
=========
-:term:`Traversal` provides an alternative to using :term:`URL dispatch` to
-map a URL to a :term:`view callable`. It is the act of locating a
-:term:`context` resource by walking over a :term:`resource tree`, starting
-from a :term:`root` resource, using a :term:`request` object as a source of
-path information. Once a context resource is found, a view callable is
-looked up and invoked.
-
-Using :term:`Traversal` to map a URL to code is optional. It is often less
-easy to understand than URL dispatch, so if you're a rank beginner, it
-probably makes sense to use URL dispatch to map URLs to code instead of
-traversal. In that case, you can skip this chapter.
-
-.. index::
- single: traversal overview
-
-A High-Level Overview of Traversal
-----------------------------------
-
A :term:`traversal` uses the URL (Universal Resource Locator) to find a
-:term:`resource`. This is done by mapping each segment of the path portion
-of the URL into a set of nested dictionary-like objects called the
-:term:`resource tree`. You might think of this as looking up files and
-directories in a file system. Traversal walks down the path until it finds a
-published "directory" or "file". The resource we find as the result of a
-traversal becomes the :term:`context`. A separate :term:`view lookup`
-subsystem is used to then find some view code willing "publish" the context
-resource.
+:term:`resource` located in a :term:`resource tree`, which is a set of
+nested dictionary-like objects. Traversal is done by using each segment
+of the path portion of the URL to navigate through the :term:`resource
+tree`. You might think of this as looking up files and directories in a
+file system. Traversal walks down the path until it finds a published
+resource, analogous to a file system "directory" or "file". The
+resource found as the result of a traversal becomes the
+:term:`context` of the :term:`request`. Then, the :term:`view lookup`
+subsystem is used to find some view code willing "publish" this
+resource by generating a :term:`response`.
+
+Using :term:`Traversal` to map a URL to code is optional. It is often
+less easy to understand than :term:`URL dispatch`, so if you're a rank
+beginner, it probably makes sense to use URL dispatch to map URLs to
+code instead of traversal. In that case, you can skip this chapter.
.. index::
single: traversal details
@@ -37,62 +26,65 @@ resource.
Traversal Details
-----------------
-:term:`Traversal` is dependent on information in a :term:`request` object.
-Every :term:`request` object contains URL path information in the
-``PATH_INFO`` portion of the :term:`WSGI` environment. The ``PATH_INFO``
-portion of the WSGI environment is the portion of a request's URL following
-the hostname and port number, but before any query string elements or
+:term:`Traversal` is dependent on information in a :term:`request`
+object. Every :term:`request` object contains URL path information in
+the ``PATH_INFO`` portion of the :term:`WSGI` environment. The
+``PATH_INFO`` string is the portion of a request's URL following the
+hostname and port number, but before any query string elements or
fragment element. For example the ``PATH_INFO`` portion of the URL
``http://example.com:8080/a/b/c?foo=1`` is ``/a/b/c``.
-Traversal treats the ``PATH_INFO`` segment of a URL as a sequence of path
-segments. For example, the ``PATH_INFO`` string ``/a/b/c`` is converted to
-the sequence ``['a', 'b', 'c']``.
+Traversal treats the ``PATH_INFO`` segment of a URL as a sequence of
+path segments. For example, the ``PATH_INFO`` string ``/a/b/c`` is
+converted to the sequence ``['a', 'b', 'c']``.
-After the path info is converted, a lookup is performed against the resource
-tree for each path segment. Each lookup uses the ``__getitem__`` method of a
-resource in the tree.
+This path sequence is then used to descend through the :term:`resource
+tree`, looking up a resource for each path segment. Each lookup uses the
+``__getitem__`` method of a resource in the tree.
For example, if the path info sequence is ``['a', 'b', 'c']``:
-- :term:`Traversal` pops the first element (``a``) from the path segment
- sequence and attempts to call the root resource's ``__getitem__`` method
- using that value (``a``) as an argument; we'll presume it succeeds.
+- :term:`Traversal` starts by acquiring the :term:`root` resource of the
+ application by calling the :term:`root factory`. The :term:`root factory`
+ can be configured to return whatever object is appropriate as the
+ traversal root of your application.
-- When the root resource's ``__getitem__`` succeeds it will return another
- resource, which we'll call "A". The :term:`context` temporarily becomes
- the "A" resource.
+- Next, the first element (``a``) is popped from the path segment
+ sequence and is used as a key to lookup the corresponding resource
+ in the root. This invokes the root resource's ``__getitem__`` method
+ using that value (``a``) as an argument.
+
+- If the root resource "contains" a resource with key ``a``, its
+ ``__getitem__`` method will return it. The :term:`context` temporarily
+ becomes the "A" resource.
- The next segment (``b``) is popped from the path sequence, and the "A"
resource's ``__getitem__`` is called with that value (``b``) as an
argument; we'll presume it succeeds.
-- When the "A" resource's ``__getitem__`` succeeds it will return another
- resource, which we'll call "B". The :term:`context` temporarily becomes
- the "B" resource.
-
-This process continues until the path segment sequence is exhausted or a path
-element cannot be resolved to a resource. In either case, a :term:`context`
-resource is chosen.
-
-Traversal "stops" when it either reaches a leaf level resource in your
-resource tree or when the path segments implied by the URL "run out". The
-resource that traversal "stops on" becomes the :term:`context`. If at any
-point during traversal any resource in the tree doesn't have a
-``__getitem__`` method, or if the ``__getitem__`` method of a resource raises
-a :exc:`KeyError`, traversal ends immediately, and that resource becomes the
-:term:`context`.
-
-The results of a :term:`traversal` also include a :term:`view name`. The
-:term:`view name` is the *first* URL path segment in the set of ``PATH_INFO``
-segments "left over" in the path segment list popped by the traversal process
-*after* traversal finds a context resource.
-
-The combination of the context resource and the :term:`view name` found via
-traversal is used later in the same request by a separate :app:`Pyramid`
-subsystem -- the :term:`view lookup` subsystem -- to find a :term:`view
-callable` later within the same request. How :app:`Pyramid` performs view
-lookup is explained within the :ref:`views_chapter` chapter.
+- The "A" resource's ``__getitem__`` returns another resource, which
+ we'll call "B". The :term:`context` temporarily becomes the "B"
+ resource.
+
+Traversal continues until the path segment sequence is exhausted or a
+path element cannot be resolved to a resource. In either case, the
+:term:`context` resource is the last object that the traversal
+successfully resolved. If any resource found during traversal lacks a
+``__getitem__`` method, or if its ``__getitem__`` method raises a
+:exc:`KeyError`, traversal ends immediately, and that resource becomes
+the :term:`context`.
+
+The results of a :term:`traversal` also include a :term:`view name`. If
+traversal ends before the path segment sequence is exhausted, the
+:term:`view name` is the *next* remaining path segment element. If the
+:term:`traversal` expends all of the path segments, then the :term:`view
+name` is the empty string (`''`).
+
+The combination of the context resource and the :term:`view name` found
+via traversal is used later in the same request by the :term:`view
+lookup` subsystem to find a :term:`view callable`. How :app:`Pyramid`
+performs view lookup is explained within the :ref:`view_config_chapter`
+chapter.
.. index::
single: object tree
@@ -104,19 +96,20 @@ lookup is explained within the :ref:`views_chapter` chapter.
The Resource Tree
-----------------
-When your application uses :term:`traversal` to resolve URLs to code, the
-application must supply a :term:`resource tree` to :app:`Pyramid`. The
-resource tree is a set of nested dictionary-like objects. The root of the
-tree is represented by a :term:`root` resource. The tree is effectively a
-nested set of dictionary-like objects.
+The resource tree is a set of nested dictionary-like resource objects
+that begins with a :term:`root` resource. In order to use
+:term:`traversal` to resolve URLs to code, your application must supply
+a :term:`resource tree` to :app:`Pyramid`.
-In order to supply a root resource for an application, at system startup
-time, the :app:`Pyramid` :term:`Router` is configured with a callback known
-as a :term:`root factory`. The root factory is supplied by the application
-developer as the ``root_factory`` argument to the application's
-:term:`Configurator`.
+In order to supply a root resource for an application the :app:`Pyramid`
+:term:`Router` is configured with a callback known as a :term:`root
+factory`. The root factory is supplied by the application, at startup
+time, as the ``root_factory`` argument to the :term:`Configurator`.
-Here's an example of a simple root factory:
+The root factory is a Python callable that accepts a :term:`request`
+object, and returns the root object of the :term:`resource tree`. A
+function, or class is typically used as an application's root factory.
+Here's an example of a simple root factory class:
.. code-block:: python
:linenos:
@@ -133,24 +126,23 @@ passing it to an instance of a :term:`Configurator` named ``config``:
config = Configurator(root_factory=Root)
-Using the ``root_factory`` argument to a :class:`pyramid.config.Configurator`
-constructor tells your :app:`Pyramid` application to call this root factory
-to generate a root resource whenever a request enters the application. This
-root factory is also known as the global root factory. A root factory can
-alternately be passed to the ``Configurator`` as a :term:`dotted Python name`
-which refers to a root factory defined in a different module.
-
-A root factory is passed a :term:`request` object and it is expected to
-return an object which represents the root of the resource tree. All
-:term:`traversal` will begin at this root resource. Usually a root factory
-for a traversal-based application will be more complicated than the above
-``Root`` class; in particular it may be associated with a database connection
-or another persistence mechanism.
+The ``root_factory`` argument to the
+:class:`pyramid.config.Configurator` constructor registers this root
+factory to be called to generate a root resource whenever a request
+enters the application. The root factory registered this way is also
+known as the global root factory. A root factory can alternately be
+passed to the ``Configurator`` as a :term:`dotted Python name` which can
+refer to a root factory defined in a different module.
If no :term:`root factory` is passed to the :app:`Pyramid`
-:term:`Configurator` constructor, or the ``root_factory`` is specified as the
-value ``None``, a *default* root factory is used. The default root factory
-always returns a resource that has no child resources.
+:term:`Configurator` constructor, or if the ``root_factory`` value
+specified is ``None``, a *default* root factory is used. The default
+root factory always returns a resource that has no child resources; it
+is effectively empty.
+
+Usually a root factory for a traversal-based application will be more
+complicated than the above ``Root`` class; in particular it may be
+associated with a database connection or another persistence mechanism.
.. sidebar:: Emulating the Default Root Factory
@@ -225,13 +217,14 @@ We'll provide a description of the algorithm, a diagram of how the algorithm
works, and some example traversal scenarios that might help you understand
how the algorithm operates against a specific resource tree.
-We'll also talk a bit about :term:`view lookup`. The :ref:`views_chapter`
-chapter discusses :term:`view lookup` in detail, and it is the canonical
-source for information about views. Technically, :term:`view lookup` is a
-:app:`Pyramid` subsystem that is separated from traversal entirely. However,
-we'll describe the fundamental behavior of view lookup in the examples in the
-next few sections to give you an idea of how traversal and view lookup
-cooperate, because they are almost always used together.
+We'll also talk a bit about :term:`view lookup`. The
+:ref:`view_config_chapter` chapter discusses :term:`view lookup` in
+detail, and it is the canonical source for information about views.
+Technically, :term:`view lookup` is a :app:`Pyramid` subsystem that is
+separated from traversal entirely. However, we'll describe the
+fundamental behavior of view lookup in the examples in the next few
+sections to give you an idea of how traversal and view lookup cooperate,
+because they are almost always used together.
.. index::
single: view name
@@ -469,7 +462,7 @@ References
A tutorial showing how :term:`traversal` can be used within a :app:`Pyramid`
application exists in :ref:`bfg_wiki_tutorial`.
-See the :ref:`views_chapter` chapter for detailed information about
+See the :ref:`view_config_chapter` chapter for detailed information about
:term:`view lookup`.
The :mod:`pyramid.traversal` module contains API functions that deal with
diff --git a/docs/narr/urldispatch.rst b/docs/narr/urldispatch.rst
index 4c601340f..a9057003f 100644
--- a/docs/narr/urldispatch.rst
+++ b/docs/narr/urldispatch.rst
@@ -6,16 +6,28 @@
URL Dispatch
============
-:term:`URL dispatch` provides a simple way to map URLs :term:`view` code
-using a simple pattern matching language. An ordered set of patterns is
-checked one-by-one. If one of the patterns matches the path information
-associated with a request, a particular :term:`view callable` is invoked. If
-no route matches, :app:`Pyramid` falls back to trying to use
-:term:`traversal` to map the current request to a :term:`view callable`.
-
-The presence of calls to the :meth:`pyramid.config.Configurator.add_route`
-method within your application is a sign that you're using :term:`URL
-dispatch`.
+:term:`URL dispatch` provides a simple way to map URLs to :term:`view`
+code using a simple pattern matching language. An ordered set of
+patterns is checked one-by-one. If one of the patterns matches the path
+information associated with a request, a particular :term:`view
+callable` is invoked.
+
+:term:`URL dispatch` is one of two ways to perform :term:`resource
+location` in :app:`Pyramid`; the other way is using :term:`traversal`.
+If no route is matched using :term:`URL dispatch`, :app:`Pyramid` falls
+back to :term:`traversal` to handle the :term:`request`.
+
+It is the responsibility of the :term:`resource location` subsystem
+(i.e., :term:`URL dispatch` or :term:`traversal`) to find the resource
+object that is the :term:`context` of the :term:`request`. Once the
+:term:`context` is determined, :term:`view lookup` is then responsible
+for finding and invoking a :term:`view callable`. A view callable is a
+specific bit of code, defined in your application, that receives the
+:term:`request` and returns a :term:`response` object.
+
+Where appropriate, we will describe how view lookup interacts with
+:term:`resource location`. The :ref:`view_config_chapter` chapter describes
+the details of :term:`view lookup`.
High-Level Operational Overview
-------------------------------
@@ -24,10 +36,9 @@ If route configuration is present in an application, the :app:`Pyramid`
:term:`Router` checks every incoming request against an ordered set of URL
matching patterns present in a *route map*.
-If any route pattern matches the information in the :term:`request` provided
-to :app:`Pyramid`, :app:`Pyramid` will shortcut :term:`traversal`, and will
-invoke :term:`view lookup` using a :term:`context` resource generated by the
-route match.
+If any route pattern matches the information in the :term:`request`,
+:app:`Pyramid` will invoke :term:`view lookup` using a :term:`context`
+resource generated by the route match.
However, if no route pattern matches the information in the :term:`request`
provided to :app:`Pyramid`, it will fail over to using :term:`traversal` to
@@ -72,7 +83,7 @@ example:
.. versionchanged:: 1.0a4
Prior to 1.0a4, routes allow for a marker starting with a ``:``, for
- example ``/prefix/:one/:two``. Starting in 1.0a4, this style is deprecated
+ example ``/prefix/:one/:two``. This style is now deprecated
in favor or ``{}`` usage which allows for additional functionality.
.. index::
@@ -84,7 +95,7 @@ Route Configuration That Names a View Callable
When a route configuration declaration names a ``view`` attribute, the value
of the attribute will reference a :term:`view callable`. This view callable
will be invoked when the route matches. A view callable, as described in
-:ref:`views_chapter`, is developer-supplied code that "does stuff" as the
+:ref:`view_chapter`, is developer-supplied code that "does stuff" as the
result of a request. For more information about how to create view
callables, see :ref:`views_chapter`.
@@ -533,12 +544,12 @@ neither predicates nor view configuration information.
callables. Use custom predicates when no set of predefined predicates does
what you need. Custom predicates can be combined with predefined
predicates as necessary. Each custom predicate callable should accept two
- arguments: ``context`` and ``request`` and should return either ``True`` or
+ arguments: ``info`` and ``request`` and should return either ``True`` or
``False`` after doing arbitrary evaluation of the context resource and/or
the request. If all callables return ``True``, the associated route will
be considered viable for a given request. If any custom predicate returns
- ``False``, route matching continues. Note that the value ``context`` will
- always be ``None`` when passed to a custom route predicate.
+ ``False``, route matching continues. See :ref:`custom_route_predicates`
+ for more information.
**View-Related Arguments**
@@ -854,7 +865,8 @@ The ``mypackage.views`` module referred to above might look like so:
The view has access to the matchdict directly via the request, and can access
variables within it that match keys present as a result of the route pattern.
-See :ref:`views_chapter` for more information about views.
+See :ref:`views_chapter`, and :ref:`view_config_chapter` for more
+information about views.
Example 2
~~~~~~~~~
@@ -1275,6 +1287,3 @@ References
A tutorial showing how :term:`URL dispatch` can be used to create a
:app:`Pyramid` application exists in :ref:`bfg_sql_wiki_tutorial`.
-Route configuration may also be added to the system via :term:`ZCML` (see
-:ref:`zcml_route_configuration`).
-
diff --git a/docs/narr/viewconfig.rst b/docs/narr/viewconfig.rst
new file mode 100644
index 000000000..3f2b1b179
--- /dev/null
+++ b/docs/narr/viewconfig.rst
@@ -0,0 +1,737 @@
+.. _view_config_chapter:
+
+.. _view_configuration:
+
+View Configuration
+==================
+
+.. index::
+ single: view lookup
+
+:term:`View configuration` controls how :term:`view lookup` operates in
+your application. In earlier chapters, you have been exposed to a few
+simple view configuration declarations without much explanation. In this
+chapter we will explore the subject in detail.
+
+.. _view_lookup:
+
+View Lookup and Invocation
+--------------------------
+
+:term:`View lookup` is the :app:`Pyramid` subsystem responsible for finding
+an invoking a :term:`view callable`. The view lookup subsystem is passed a
+:term:`context` and a :term:`request` object.
+
+:term:`View configuration` information stored within in the
+:term:`application registry` is compared against the context and request by
+the view lookup subsystem in order to find the "best" view callable for the
+set of circumstances implied by the context and request.
+
+:term:`View predicate` attributes are an important part of view
+configuration that enables the :term:`View lookup` subsystem to find and
+invoke the appropriate view. Predicate attributes can be thought of
+like "narrowers". In general, the greater number of predicate
+attributes possessed by a view's configuration, the more specific the
+circumstances need to be before the registered view callable will be
+invoked.
+
+Mapping a Resource or URL Pattern to a View Callable
+----------------------------------------------------
+
+A developer makes a :term:`view callable` available for use within a
+:app:`Pyramid` application via :term:`view configuration`. A view
+configuration associates a view callable with a set of statements that
+determine the set of circumstances which must be true for the view callable
+to be invoked.
+
+A view configuration statement is made about information present in the
+:term:`context` resource and the :term:`request`.
+
+View configuration is performed in one of these ways:
+
+- by running a :term:`scan` against application source code which has a
+ :class:`pyramid.view.view_config` decorator attached to a Python object as
+ per :class:`pyramid.view.view_config` and
+ :ref:`mapping_views_using_a_decorator_section`.
+
+- by using the :meth:`pyramid.config.Configurator.add_view` method as per
+ :meth:`pyramid.config.Configurator.add_view` and
+ :ref:`mapping_views_using_imperative_config_section`.
+
+- By specifying a view within a :term:`route configuration`. View
+ configuration via a route configuration is performed by using the
+ :meth:`pyramid.config.Configurator.add_route` method, passing a ``view``
+ argument specifying a view callable.
+
+.. note:: A package named ``pyramid_handlers`` (available from PyPI) provides
+ an analogue of :term:`Pylons` -style "controllers", which are a special
+ kind of view class which provides more automation when your application
+ uses :term:`URL dispatch` solely.
+
+.. _view_configuration_parameters:
+
+View Configuration Parameters
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+All forms of view configuration accept the same general types of arguments.
+
+Many arguments supplied during view configuration are :term:`view predicate`
+arguments. View predicate arguments used during view configuration are used
+to narrow the set of circumstances in which :term:`view lookup` will find a
+particular view callable.
+
+In general, the fewer number of predicates which are supplied to a
+particular view configuration, the more likely it is that the associated
+view callable will be invoked. The greater the number supplied, the
+less likely. A view with five predicates will always be found and
+evaluated before a view with two, for example. All predicates must
+match for the associated view to be called.
+
+This does not mean however, that :app:`Pyramid` "stops looking" when it
+finds a view registration with predicates that don't match. If one set
+of view predicates does not match, the "next most specific" view (if
+any) is consulted for predicates, and so on, until a view is found, or
+no view can be matched up with the request. The first view with a set
+of predicates all of which match the request environment will be
+invoked.
+
+If no view can be found with predicates which allow it to be matched up with
+the request, :app:`Pyramid` will return an error to the user's browser,
+representing a "not found" (404) page. See :ref:`changing_the_notfound_view`
+for more information about changing the default notfound view.
+
+Some view configuration arguments are non-predicate arguments. These tend to
+modify the response of the view callable or prevent the view callable from
+being invoked due to an authorization policy. The presence of non-predicate
+arguments in a view configuration does not narrow the circumstances in which
+the view callable will be invoked.
+
+Non-Predicate Arguments
++++++++++++++++++++++++
+
+``permission``
+ The name of a :term:`permission` that the user must possess in order to
+ invoke the :term:`view callable`. See :ref:`view_security_section` for
+ more information about view security and permissions.
+
+ If ``permission`` is not supplied, no permission is registered for this
+ view (it's accessible by any caller).
+
+``attr``
+ The view machinery defaults to using the ``__call__`` method of the
+ :term:`view callable` (or the function itself, if the view callable is a
+ function) to obtain a response. The ``attr`` value allows you to vary the
+ method attribute used to obtain the response. For example, if your view
+ was a class, and the class has a method named ``index`` and you wanted to
+ use this method instead of the class' ``__call__`` method to return the
+ response, you'd say ``attr="index"`` in the view configuration for the
+ view. This is most useful when the view definition is a class.
+
+ If ``attr`` is not supplied, ``None`` is used (implying the function itself
+ if the view is a function, or the ``__call__`` callable attribute if the
+ view is a class).
+
+``renderer``
+ Denotes the :term:`renderer` implementation which will be used to construct
+ a :term:`response` from the associated view callable's return value. (see
+ also :ref:`renderers_chapter`).
+
+ This is either a single string term (e.g. ``json``) or a string implying a
+ path or :term:`asset specification` (e.g. ``templates/views.pt``) naming a
+ :term:`renderer` implementation. If the ``renderer`` value does not
+ contain a dot (``.``), the specified string will be used to look up a
+ renderer implementation, and that renderer implementation will be used to
+ construct a response from the view return value. If the ``renderer`` value
+ contains a dot (``.``), the specified term will be treated as a path, and
+ the filename extension of the last element in the path will be used to look
+ up the renderer implementation, which will be passed the full path.
+
+ When the renderer is a path, although a path is usually just a simple
+ relative pathname (e.g. ``templates/foo.pt``, implying that a template
+ named "foo.pt" is in the "templates" directory relative to the directory of
+ the current :term:`package`), a path can be absolute, starting with a slash
+ on UNIX or a drive letter prefix on Windows. The path can alternately be a
+ :term:`asset specification` in the form
+ ``some.dotted.package_name:relative/path``, making it possible to address
+ template assets which live in a separate package.
+
+ The ``renderer`` attribute is optional. If it is not defined, the "null"
+ renderer is assumed (no rendering is performed and the value is passed back
+ to the upstream :app:`Pyramid` machinery unmolested). Note that if the
+ view callable itself returns a :term:`response` (see :ref:`the_response`),
+ the specified renderer implementation is never called.
+
+``wrapper``
+ The :term:`view name` of a different :term:`view configuration` which will
+ receive the response body of this view as the ``request.wrapped_body``
+ attribute of its own :term:`request`, and the :term:`response` returned by
+ this view as the ``request.wrapped_response`` attribute of its own request.
+ Using a wrapper makes it possible to "chain" views together to form a
+ composite response. The response of the outermost wrapper view will be
+ returned to the user. The wrapper view will be found as any view is found:
+ see :ref:`view_lookup`. The "best" wrapper view will be found based on the
+ lookup ordering: "under the hood" this wrapper view is looked up via
+ ``pyramid.view.render_view_to_response(context, request,
+ 'wrapper_viewname')``. The context and request of a wrapper view is the
+ same context and request of the inner view.
+
+ If ``wrapper`` is not supplied, no wrapper view is used.
+
+``decorator``
+ A :term:`dotted Python name` to function (or the function itself) which
+ will be used to decorate the registered :term:`view callable`. The
+ decorator function will be called with the view callable as a single
+ argument. The view callable it is passed will accept ``(context,
+ request)``. The decorator must return a replacement view callable which
+ also accepts ``(context, request)``.
+
+``mapper``
+ A Python object or :term:`dotted Python name` which refers to a :term:`view
+ mapper`, or ``None``. By default it is ``None``, which indicates that the
+ view should use the default view mapper. This plug-point is useful for
+ Pyramid extension developers, but it's not very useful for 'civilians' who
+ are just developing stock Pyramid applications. Pay no attention to the man
+ behind the curtain.
+
+Predicate Arguments
++++++++++++++++++++
+
+These arguments modify view lookup behavior. In general, the more predicate
+arguments that are supplied, the more specific, and narrower the usage of the
+configured view.
+
+``name``
+ The :term:`view name` required to match this view callable. Read
+ :ref:`traversal_chapter` to understand the concept of a view name.
+
+ If ``name`` is not supplied, the empty string is used (implying the default
+ view).
+
+``context``
+ An object representing a Python class that the :term:`context` resource
+ must be an instance of *or* the :term:`interface` that the :term:`context`
+ resource must provide in order for this view to be found and called. This
+ predicate is true when the :term:`context` resource is an instance of the
+ represented class or if the :term:`context` resource provides the
+ represented interface; it is otherwise false.
+
+ If ``context`` is not supplied, the value ``None``, which matches any
+ resource, is used.
+
+``route_name``
+ If ``route_name`` is supplied, the view callable will be invoked only when
+ the named route has matched.
+
+ This value must match the ``name`` of a :term:`route configuration`
+ declaration (see :ref:`urldispatch_chapter`) that must match before this
+ view will be called. Note that the ``route`` configuration referred to by
+ ``route_name`` will usually have a ``*traverse`` token in the value of its
+ ``pattern``, representing a part of the path that will be used by
+ :term:`traversal` against the result of the route's :term:`root factory`.
+
+ If ``route_name`` is not supplied, the view callable will be have a chance
+ of being invoked if no other route was matched. This is when the
+ request/context pair found via :term:`resource location` does not indicate
+ it matched any configured route.
+
+``request_type``
+ This value should be an :term:`interface` that the :term:`request` must
+ provide in order for this view to be found and called.
+
+ If ``request_type`` is not supplied, the value ``None`` is used, implying
+ any request type.
+
+ *This is an advanced feature, not often used by "civilians"*.
+
+``request_method``
+ This value can either be one of the strings ``GET``, ``POST``, ``PUT``,
+ ``DELETE``, or ``HEAD`` representing an HTTP ``REQUEST_METHOD``. A view
+ declaration with this argument ensures that the view will only be called
+ when the request's ``method`` attribute (aka the ``REQUEST_METHOD`` of the
+ WSGI environment) string matches the supplied value.
+
+ If ``request_method`` is not supplied, the view will be invoked regardless
+ of the ``REQUEST_METHOD`` of the :term:`WSGI` environment.
+
+``request_param``
+ This value can be any string. A view declaration with this argument
+ ensures that the view will only be called when the :term:`request` has a
+ key in the ``request.params`` dictionary (an HTTP ``GET`` or ``POST``
+ variable) that has a name which matches the supplied value.
+
+ If the value supplied has a ``=`` sign in it,
+ e.g. ``request_params="foo=123"``, then the key (``foo``) must both exist
+ in the ``request.params`` dictionary, *and* the value must match the right
+ hand side of the expression (``123``) for the view to "match" the current
+ request.
+
+ If ``request_param`` is not supplied, the view will be invoked without
+ consideration of keys and values in the ``request.params`` dictionary.
+
+``containment``
+ This value should be a reference to a Python class or :term:`interface`
+ that a parent object in the context resource's :term:`lineage` must provide
+ in order for this view to be found and called. The resources in your
+ resource tree must be "location-aware" to use this feature.
+
+ If ``containment`` is not supplied, the interfaces and classes in the
+ lineage are not considered when deciding whether or not to invoke the view
+ callable.
+
+ See :ref:`location_aware` for more information about location-awareness.
+
+``xhr``
+ This value should be either ``True`` or ``False``. If this value is
+ specified and is ``True``, the :term:`WSGI` environment must possess an
+ ``HTTP_X_REQUESTED_WITH`` (aka ``X-Requested-With``) header that has the
+ value ``XMLHttpRequest`` for the associated view callable to be found and
+ called. This is useful for detecting AJAX requests issued from jQuery,
+ Prototype and other Javascript libraries.
+
+ If ``xhr`` is not specified, the ``HTTP_X_REQUESTED_WITH`` HTTP header is
+ not taken into consideration when deciding whether or not to invoke the
+ associated view callable.
+
+``accept``
+ The value of this argument represents a match query for one or more
+ mimetypes in the ``Accept`` HTTP request header. If this value is
+ specified, it must be in one of the following forms: a mimetype match token
+ in the form ``text/plain``, a wildcard mimetype match token in the form
+ ``text/*`` or a match-all wildcard mimetype match token in the form
+ ``*/*``. If any of the forms matches the ``Accept`` header of the request,
+ this predicate will be true.
+
+ If ``accept`` is not specified, the ``HTTP_ACCEPT`` HTTP header is not
+ taken into consideration when deciding whether or not to invoke the
+ associated view callable.
+
+``header``
+ This value represents an HTTP header name or a header name/value pair.
+
+ If ``header`` is specified, it must be a header name or a
+ ``headername:headervalue`` pair.
+
+ If ``header`` is specified without a value (a bare header name only,
+ e.g. ``If-Modified-Since``), the view will only be invoked if the HTTP
+ header exists with any value in the request.
+
+ If ``header`` is specified, and possesses a name/value pair
+ (e.g. ``User-Agent:Mozilla/.*``), the view will only be invoked if the HTTP
+ header exists *and* the HTTP header matches the value requested. When the
+ ``headervalue`` contains a ``:`` (colon), it will be considered a
+ name/value pair (e.g. ``User-Agent:Mozilla/.*`` or ``Host:localhost``).
+ The value portion should be a regular expression.
+
+ Whether or not the value represents a header name or a header name/value
+ pair, the case of the header name is not significant.
+
+ If ``header`` is not specified, the composition, presence or absence of
+ HTTP headers is not taken into consideration when deciding whether or not
+ to invoke the associated view callable.
+
+``path_info``
+ This value represents a regular expression pattern that will be tested
+ against the ``PATH_INFO`` WSGI environment variable to decide whether or
+ not to call the associated view callable. If the regex matches, this
+ predicate will be ``True``.
+
+ If ``path_info`` is not specified, the WSGI ``PATH_INFO`` is not taken into
+ consideration when deciding whether or not to invoke the associated view
+ callable.
+
+``custom_predicates``
+ If ``custom_predicates`` is specified, it must be a sequence of references
+ to custom predicate callables. Use custom predicates when no set of
+ predefined predicates do what you need. Custom predicates can be combined
+ with predefined predicates as necessary. Each custom predicate callable
+ should accept two arguments: ``context`` and ``request`` and should return
+ either ``True`` or ``False`` after doing arbitrary evaluation of the
+ context resource and/or the request. If all callables return ``True``, the
+ associated view callable will be considered viable for a given request.
+
+ If ``custom_predicates`` is not specified, no custom predicates are
+ used.
+
+.. index::
+ single: view_config decorator
+
+.. _mapping_views_using_a_decorator_section:
+
+View Configuration Using the ``@view_config`` Decorator
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+For better locality of reference, you may use the
+:class:`pyramid.view.view_config` decorator to associate your view functions
+with URLs instead of using :term:`ZCML` or imperative configuration for the
+same purpose.
+
+.. warning::
+
+ Using this feature tends to slows down application startup slightly, as
+ more work is performed at application startup to scan for view
+ declarations.
+
+Usage of the ``view_config`` decorator is a form of :term:`declarative
+configuration`, like ZCML, but in decorator form.
+:class:`pyramid.view.view_config` can be used to associate :term:`view
+configuration` information -- as done via the equivalent imperative code or
+ZCML -- with a function that acts as a :app:`Pyramid` view callable. All
+arguments to the :meth:`pyramid.config.Configurator.add_view` method (save
+for the ``view`` argument) are available in decorator form and mean precisely
+the same thing.
+
+An example of the :class:`pyramid.view.view_config` decorator might reside in
+a :app:`Pyramid` application module ``views.py``:
+
+.. ignore-next-block
+.. code-block:: python
+ :linenos:
+
+ from resources import MyResource
+ from pyramid.view import view_config
+ from pyramid.response import Response
+
+ @view_config(name='my_view', request_method='POST', context=MyResource,
+ permission='read')
+ def my_view(request):
+ return Response('OK')
+
+Using this decorator as above replaces the need to add this imperative
+configuration stanza:
+
+.. ignore-next-block
+.. code-block:: python
+ :linenos:
+
+ config.add_view('.views.my_view', name='my_view', request_method='POST',
+ context=MyResource, permission='read')
+
+All arguments to ``view_config`` may be omitted. For example:
+
+.. code-block:: python
+ :linenos:
+
+ from pyramid.response import Response
+ from pyramid.view import view_config
+
+ @view_config()
+ def my_view(request):
+ """ My view """
+ return Response()
+
+Such a registration as the one directly above implies that the view name will
+be ``my_view``, registered with a ``context`` argument that matches any
+resource type, using no permission, registered against requests with any
+request method, request type, request param, route name, or containment.
+
+The mere existence of a ``@view_config`` decorator doesn't suffice to perform
+view configuration. All that the decorator does is "annotate" the function
+with your configuration declarations, it doesn't process them. To make
+:app:`Pyramid` process your :class:`pyramid.view.view_config` declarations,
+you *must* do use the ``scan`` method of a
+:class:`pyramid.config.Configurator`:
+
+.. code-block:: python
+ :linenos:
+
+ # config is assumed to be an instance of the
+ # pyramid.config.Configurator class
+ config.scan()
+
+Please see :ref:`decorations_and_code_scanning` for detailed information
+about what happens when code is scanned for configuration declarations
+resulting from use of decorators like :class:`pyramid.view.view_config`.
+
+See :ref:`configuration_module` for additional API arguments to the
+:meth:`pyramid.config.Configurator.scan` method. For example, the method
+allows you to supply a ``package`` argument to better control exactly *which*
+code will be scanned.
+
+``@view_config`` Placement
+++++++++++++++++++++++++++
+
+A :class:`pyramid.view.view_config` decorator can be placed in various points
+in your application.
+
+If your view callable is a function, it may be used as a function decorator:
+
+.. code-block:: python
+ :linenos:
+
+ from pyramid.view import view_config
+ from pyramid.response import Response
+
+ @view_config(name='edit')
+ def edit(request):
+ return Response('edited!')
+
+If your view callable is a class, the decorator can also be used as a class
+decorator in Python 2.6 and better (Python 2.5 and below do not support class
+decorators). All the arguments to the decorator are the same when applied
+against a class as when they are applied against a function. For example:
+
+.. code-block:: python
+ :linenos:
+
+ from pyramid.response import Response
+ from pyramid.view import view_config
+
+ @view_config()
+ class MyView(object):
+ def __init__(self, request):
+ self.request = request
+
+ def __call__(self):
+ return Response('hello')
+
+You can use the :class:`pyramid.view.view_config` decorator as a simple
+callable to manually decorate classes in Python 2.5 and below without the
+decorator syntactic sugar, if you wish:
+
+.. code-block:: python
+ :linenos:
+
+ from pyramid.response import Response
+ from pyramid.view import view_config
+
+ class MyView(object):
+ def __init__(self, request):
+ self.request = request
+
+ def __call__(self):
+ return Response('hello')
+
+ my_view = view_config()(MyView)
+
+More than one :class:`pyramid.view.view_config` decorator can be stacked on
+top of any number of others. Each decorator creates a separate view
+registration. For example:
+
+.. code-block:: python
+ :linenos:
+
+ from pyramid.view import view_config
+ from pyramid.response import Response
+
+ @view_config(name='edit')
+ @view_config(name='change')
+ def edit(request):
+ return Response('edited!')
+
+This registers the same view under two different names.
+
+The decorator can also be used against class methods:
+
+.. code-block:: python
+ :linenos:
+
+ from pyramid.response import Response
+ from pyramid.view import view_config
+
+ class MyView(object):
+ def __init__(self, request):
+ self.request = request
+
+ @view_config(name='hello')
+ def amethod(self):
+ return Response('hello')
+
+When the decorator is used against a class method, a view is registered for
+the *class*, so the class constructor must accept an argument list in one of
+two forms: either it must accept a single argument ``request`` or it must
+accept two arguments, ``context, request``.
+
+The method which is decorated must return a :term:`response`.
+
+Using the decorator against a particular method of a class is equivalent to
+using the ``attr`` parameter in a decorator attached to the class itself.
+For example, the above registration implied by the decorator being used
+against the ``amethod`` method could be spelled equivalently as the below:
+
+.. code-block:: python
+ :linenos:
+
+ from pyramid.response import Response
+ from pyramid.view import view_config
+
+ @view_config(attr='amethod', name='hello')
+ class MyView(object):
+ def __init__(self, request):
+ self.request = request
+
+ def amethod(self):
+ return Response('hello')
+
+.. index::
+ single: add_view
+
+.. _mapping_views_using_imperative_config_section:
+
+View Registration Using :meth:`~pyramid.config.Configurator.add_view`
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+The :meth:`pyramid.config.Configurator.add_view` method within
+:ref:`configuration_module` is used to configure a view imperatively. The
+arguments to this method are very similar to the arguments that you provide
+to the ``@view_config`` decorator. For example:
+
+.. code-block:: python
+ :linenos:
+
+ from pyramid.response import Response
+
+ def hello_world(request):
+ return Response('hello!')
+
+ # config is assumed to be an instance of the
+ # pyramid.config.Configurator class
+ config.add_view(hello_world, name='hello.html')
+
+The first argument, ``view``, is required. It must either be a Python object
+which is the view itself or a :term:`dotted Python name` to such an object.
+All other arguments are optional. See
+:meth:`pyramid.config.Configurator.add_view` for more information.
+
+.. index::
+ single: resource interfaces
+
+.. _using_resource_interfaces:
+
+Using Resource Interfaces In View Configuration
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Instead of registering your views with a ``context`` that names a Python
+resource *class*, you can optionally register a view callable with a
+``context`` which is an :term:`interface`. An interface can be attached
+arbitrarily to any resource object. View lookup treats context interfaces
+specially, and therefore the identity of a resource can be divorced from that
+of the class which implements it. As a result, associating a view with an
+interface can provide more flexibility for sharing a single view between two
+or more different implementations of a resource type. For example, if two
+resource objects of different Python class types share the same interface,
+you can use the same view configuration to specify both of them as a
+``context``.
+
+In order to make use of interfaces in your application during view dispatch,
+you must create an interface and mark up your resource classes or instances
+with interface declarations that refer to this interface.
+
+To attach an interface to a resource *class*, you define the interface and
+use the :func:`zope.interface.implements` function to associate the interface
+with the class.
+
+.. code-block:: python
+ :linenos:
+
+ from zope.interface import Interface
+ from zope.interface import implements
+
+ class IHello(Interface):
+ """ A marker interface """
+
+ class Hello(object):
+ implements(IHello)
+
+To attach an interface to a resource *instance*, you define the interface and
+use the :func:`zope.interface.alsoProvides` function to associate the
+interface with the instance. This function mutates the instance in such a
+way that the interface is attached to it.
+
+.. code-block:: python
+ :linenos:
+
+ from zope.interface import Interface
+ from zope.interface import alsoProvides
+
+ class IHello(Interface):
+ """ A marker interface """
+
+ class Hello(object):
+ pass
+
+ def make_hello():
+ hello = Hello()
+ alsoProvides(hello, IHello)
+ return hello
+
+Regardless of how you associate an interface, with a resource instance, or a
+resource class, the resulting code to associate that interface with a view
+callable is the same. Assuming the above code that defines an ``IHello``
+interface lives in the root of your application, and its module is named
+"resources.py", the interface declaration below will associate the
+``mypackage.views.hello_world`` view with resources that implement, or
+provide, this interface.
+
+.. code-block:: python
+ :linenos:
+
+ # config is an instance of pyramid.config.Configurator
+
+ config.add_view('mypackage.views.hello_world', name='hello.html',
+ context='mypackage.resources.IHello')
+
+Any time a resource that is determined to be the :term:`context` provides
+this interface, and a view named ``hello.html`` is looked up against it as
+per the URL, the ``mypackage.views.hello_world`` view callable will be
+invoked.
+
+Note, in cases where a view is registered against a resource class, and a
+view is also registered against an interface that the resource class
+implements, an ambiguity arises. Views registered for the resource class take
+precedence over any views registered for any interface the resource class
+implements. Thus, if one view configuration names a ``context`` of both the
+class type of a resource, and another view configuration names a ``context``
+of interface implemented by the resource's class, and both view
+configurations are otherwise identical, the view registered for the context's
+class will "win".
+
+For more information about defining resources with interfaces for use within
+view configuration, see :ref:`resources_which_implement_interfaces`.
+
+.. index::
+ single: view security
+ pair: security; view
+
+.. _view_security_section:
+
+Configuring View Security
+~~~~~~~~~~~~~~~~~~~~~~~~~
+
+If an :term:`authorization policy` is active, any :term:`permission` attached
+to a :term:`view configuration` found during view lookup will be verified.
+This will ensure that the currently authenticated user possesses that
+permission against the :term:`context` resource before the view function is
+actually called. Here's an example of specifying a permission in a view
+configuration using :meth:`pyramid.config.Configurator.add_view`:
+
+.. code-block:: python
+ :linenos:
+
+ # config is an instance of pyramid.config.Configurator
+
+ config.add_view('myproject.views.add_entry', name='add.html',
+ context='myproject.resources.IBlog', permission='add')
+
+When an :term:`authorization policy` is enabled, this view will be protected
+with the ``add`` permission. The view will *not be called* if the user does
+not possess the ``add`` permission relative to the current :term:`context`.
+Instead the :term:`forbidden view` result will be returned to the client as
+per :ref:`protecting_views`.
+
+.. index::
+ single: debugging not found errors
+ single: not found error (debugging)
+
+.. _debug_notfound_section:
+
+:exc:`NotFound` Errors
+~~~~~~~~~~~~~~~~~~~~~~
+
+It's useful to be able to debug :exc:`NotFound` error responses when they
+occur unexpectedly due to an application registry misconfiguration. To debug
+these errors, use the ``PYRAMID_DEBUG_NOTFOUND`` environment variable or the
+``debug_notfound`` configuration file setting. Details of why a view was not
+found will be printed to ``stderr``, and the browser representation of the
+error will include the same information. See :ref:`environment_chapter` for
+more information about how, and where to set these values.
+
diff --git a/docs/narr/views.rst b/docs/narr/views.rst
index ad28e48d4..e1eacfeae 100644
--- a/docs/narr/views.rst
+++ b/docs/narr/views.rst
@@ -17,11 +17,12 @@ request made to your application.
that implements a view *callable*, and the process of view
*lookup*.
-The chapter :ref:`resourcelocation_chapter` describes how, using information
-from the :term:`request`, a :term:`context` resource is computed. But the
-context resource itself isn't very useful without an associated :term:`view
-callable`. A view callable returns a response to a user, often using the
-context resource to do so.
+The :ref:`urldispatch_chapter`, and :ref:`traversal_chapter` chapters
+describes how, using information from the :term:`request`, a
+:term:`context` resource is computed. But the context resource itself
+isn't very useful without an associated :term:`view callable`. A view
+callable returns a response to a user, often using the context resource
+to do so.
The job of actually locating and invoking the "best" :term:`view callable` is
the job of the :term:`view lookup` subsystem. The view lookup subsystem
@@ -30,31 +31,34 @@ in the :term:`request` against :term:`view configuration` statements made by
the developer to choose the most appropriate view callable for a specific
set of circumstances.
-This chapter provides documentation detailing the process of creating
-view callables, documentation about performing view configuration, and
-a detailed explanation of view lookup.
+This chapter describes how view callables work. In the
+:ref:`view_config_chapter` chapter, there are details about performing
+view configuration, and a detailed explanation of view lookup.
View Callables
--------------
-No matter how a view callable is eventually found, all view callables
-used by :app:`Pyramid` must be constructed in the same way, and
-must return the same kind of return value.
-
-Most view callables accept a single argument named ``request``. This
-argument represents a :app:`Pyramid` :term:`Request` object. A request
-object encapsulates a WSGI environment as represented to :app:`Pyramid` by
-the upstream :term:`WSGI` server.
-
-In general, a view callable must return a :mod:`Pyramid` :term:`Response`
-object.
-
-.. note:: The above statement, though it sounds definitive, isn't always
- true. See :ref:`renderers_chapter` for information related to using a
- :term:`renderer` to convert a non-Response view callable return value into
- a Response object.
-
-View callables can be functions, instances, or classes.
+View callables are, at the risk of sounding obvious, callable Python
+objects. Specifically, view callables can be functions, classes, or
+instances that implement an ``__call__`` method (making the
+instance callable).
+
+View callables must, at a minimum, accept a single argument named
+``request``. This argument represents a :app:`Pyramid` :term:`Request`
+object. A request object encapsulates a WSGI environment provided to
+:app:`Pyramid` by the upstream :term:`WSGI` server. As you might expect,
+the request object contains everything your application needs to know
+about the specific HTTP request being made.
+
+A view callable's ultimate responsibility is to create a :mod:`Pyramid`
+:term:`Response` object. This can be done by creating the response
+object in the view callable code and returning it directly, as we will
+be doing in this chapter. However, if a view callable does not return a
+response itself, it can be configured to use a :term:`renderer` that
+converts its return value into a :term:`Response` object. Using
+renderers is the common way that templates are used with view callables
+to generate markup. See the :ref:`renderers_chapter` chapter for
+details.
.. index::
single: view calling convention
@@ -63,7 +67,7 @@ View callables can be functions, instances, or classes.
.. _function_as_view:
Defining a View Callable as a Function
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+--------------------------------------
One of the easiest way to define a view callable is to create a function that
accepts a single argument named ``request``, and which returns a
@@ -85,7 +89,7 @@ implemented as a function:
.. _class_as_view:
Defining a View Callable as a Class
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+-----------------------------------
A view callable may also be represented by a Python class instead of a
function. When a view callable is a class, the calling semantics are
@@ -126,8 +130,10 @@ method expected to return a response, you can either:
values, each pointing at a different method of the class if you'd like the
class to represent a collection of related view callables.
-- treat the class as a :term:`view handler` by using it as the ``handler=``
- argument of a call to :meth:`pyramid.config.Configurator.add_handler`.
+.. note:: A package named :term:`pyramid_handlers` (available from PyPI)
+ provides an analogue of :term:`Pylons` -style "controllers", which are a
+ special kind of view class which provides more automation when your
+ application uses :term:`URL dispatch` solely.
.. index::
single: view calling convention
@@ -135,7 +141,7 @@ method expected to return a response, you can either:
.. _request_and_context_view_definitions:
Alternate View Callable Argument/Calling Conventions
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+----------------------------------------------------
Usually, view callables are defined to accept only a single argument:
``request``. However, view callables may alternately be defined as classes,
@@ -210,7 +216,7 @@ access to the context via ``request.context``.
.. _the_response:
View Callable Responses
-~~~~~~~~~~~~~~~~~~~~~~~
+-----------------------
A view callable may always return an object that implements the :app:`Pyramid`
:term:`Response` interface. The easiest way to return something that
@@ -256,7 +262,7 @@ These attributes form the notional "Pyramid Response interface".
.. _http_redirect:
Using a View Callable to Do an HTTP Redirect
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+--------------------------------------------
You can issue an HTTP redirect from within a view by returning a particular
kind of response.
@@ -295,7 +301,7 @@ Unauthorized``.
.. _special_exceptions_in_callables:
Using Special Exceptions In View Callables
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+------------------------------------------
Usually when a Python exception is raised within a view callable,
:app:`Pyramid` allows the exception to propagate all the way out to the
@@ -325,7 +331,7 @@ available to the view which :app:`Pyramid` invokes as
.. _exception_views:
Exception Views
-~~~~~~~~~~~~~~~~
+---------------
The machinery which allows the special :exc:`pyramid.exceptions.NotFound` and
:exc:`pyramid.exceptions.Forbidden` exceptions to be caught by specialized
@@ -404,1089 +410,3 @@ exception views which have a name will be ignored.
Exception views can be configured with any view registration mechanism:
``@view_config`` decorator, ZCML, or imperative ``add_view`` styles.
-.. index::
- single: unicode, views, and forms
- single: forms, views, and unicode
- single: views, forms, and unicode
-
-Handling Form Submissions in View Callables (Unicode and Character Set Issues)
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-Most web applications need to accept form submissions from web browsers and
-various other clients. In :app:`Pyramid`, form submission handling logic is
-always part of a :term:`view`. For a general overview of how to handle form
-submission data using the :term:`WebOb` API, see :ref:`webob_chapter` and
-`"Query and POST variables" within the WebOb documentation
-<http://pythonpaste.org/webob/reference.html#query-post-variables>`_.
-:app:`Pyramid` defers to WebOb for its request and response implementations,
-and handling form submission data is a property of the request
-implementation. Understanding WebOb's request API is the key to
-understanding how to process form submission data.
-
-There are some defaults that you need to be aware of when trying to handle
-form submission data in a :app:`Pyramid` view. Having high-order (i.e.,
-non-ASCII) characters in data contained within form submissions is
-exceedingly common, and the UTF-8 encoding is the most common encoding used
-on the web for character data. Since Unicode values are much saner than
-working with and storing bytestrings, :app:`Pyramid` configures the
-:term:`WebOb` request machinery to attempt to decode form submission values
-into Unicode from UTF-8 implicitly. This implicit decoding happens when view
-code obtains form field values via the ``request.params``, ``request.GET``,
-or ``request.POST`` APIs (see :ref:`request_module` for details about these
-APIs).
-
-.. note::
-
- Many people find the difference between Unicode and UTF-8 confusing.
- Unicode is a standard for representing text that supports most of the
- world's writing systems. However, there are many ways that Unicode data
- can be encoded into bytes for transit and storage. UTF-8 is a specific
- encoding for Unicode, that is backwards-compatible with ASCII. This makes
- UTF-8 very convenient for encoding data where a large subset of that data
- is ASCII characters, which is largely true on the web. UTF-8 is also the
- standard character encoding for URLs.
-
-As an example, let's assume that the following form page is served up to a
-browser client, and its ``action`` points at some :app:`Pyramid` view code:
-
-.. code-block:: xml
- :linenos:
-
- <html xmlns="http://www.w3.org/1999/xhtml">
- <head>
- <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
- </head>
- <form method="POST" action="myview">
- <div>
- <input type="text" name="firstname"/>
- </div>
- <div>
- <input type="text" name="lastname"/>
- </div>
- <input type="submit" value="Submit"/>
- </form>
- </html>
-
-The ``myview`` view code in the :app:`Pyramid` application *must* expect that
-the values returned by ``request.params`` will be of type ``unicode``, as
-opposed to type ``str``. The following will work to accept a form post from
-the above form:
-
-.. code-block:: python
- :linenos:
-
- def myview(request):
- firstname = request.params['firstname']
- lastname = request.params['lastname']
-
-But the following ``myview`` view code *may not* work, as it tries to decode
-already-decoded (``unicode``) values obtained from ``request.params``:
-
-.. code-block:: python
- :linenos:
-
- def myview(request):
- # the .decode('utf-8') will break below if there are any high-order
- # characters in the firstname or lastname
- firstname = request.params['firstname'].decode('utf-8')
- lastname = request.params['lastname'].decode('utf-8')
-
-For implicit decoding to work reliably, you should ensure that every form you
-render that posts to a :app:`Pyramid` view explicitly defines a charset
-encoding of UTF-8. This can be done via a response that has a
-``;charset=UTF-8`` in its ``Content-Type`` header; or, as in the form above,
-with a ``meta http-equiv`` tag that implies that the charset is UTF-8 within
-the HTML ``head`` of the page containing the form. This must be done
-explicitly because all known browser clients assume that they should encode
-form data in the same character set implied by ``Content-Type`` value of the
-response containing the form when subsequently submitting that form. There is
-no other generally accepted way to tell browser clients which charset to use
-to encode form data. If you do not specify an encoding explicitly, the
-browser client will choose to encode form data in its default character set
-before submitting it, which may not be UTF-8 as the server expects. If a
-request containing form data encoded in a non-UTF8 charset is handled by your
-view code, eventually the request code accessed within your view will throw
-an error when it can't decode some high-order character encoded in another
-character set within form data, e.g., when ``request.params['somename']`` is
-accessed.
-
-If you are using the :class:`pyramid.response.Response` class to generate a
-response, or if you use the ``render_template_*`` templating APIs, the UTF-8
-charset is set automatically as the default via the ``Content-Type`` header.
-If you return a ``Content-Type`` header without an explicit charset, a
-request will add a ``;charset=utf-8`` trailer to the ``Content-Type`` header
-value for you, for response content types that are textual
-(e.g. ``text/html``, ``application/xml``, etc) as it is rendered. If you are
-using your own response object, you will need to ensure you do this yourself.
-
-.. note:: Only the *values* of request params obtained via
- ``request.params``, ``request.GET`` or ``request.POST`` are decoded
- to Unicode objects implicitly in the :app:`Pyramid` default
- configuration. The keys are still (byte) strings.
-
-.. index::
- single: view configuration
-
-.. _view_configuration:
-
-View Configuration: Mapping a Resource or URL Pattern to a View Callable
-------------------------------------------------------------------------
-
-A developer makes a :term:`view callable` available for use within a
-:app:`Pyramid` application via :term:`view configuration`. A view
-configuration associates a view callable with a set of statements that
-determine the set of circumstances which must be true for the view callable
-to be invoked.
-
-A view configuration statement is made about information present in the
-:term:`context` resource and the :term:`request`.
-
-View configuration is performed in one of these ways:
-
-- by running a :term:`scan` against application source code which has a
- :class:`pyramid.view.view_config` decorator attached to a Python object as
- per :class:`pyramid.view.view_config` and
- :ref:`mapping_views_using_a_decorator_section`.
-
-- by using the :meth:`pyramid.config.Configurator.add_view` method as per
- :meth:`pyramid.config.Configurator.add_view` and
- :ref:`mapping_views_using_imperative_config_section`.
-
-- By specifying a view within a :term:`route configuration`. View
- configuration via a route configuration is performed by using the
- :meth:`pyramid.config.Configurator.add_route` method, passing a ``view``
- argument specifying a view callable.
-
-- by using the :meth:`pyramid.config.Configurator.add_handler` against a
- :term:`view handler` class (useful only for :term:`URL dispatch`
- applications).
-
-.. note:: You can also add view configuration by adding a ``<view>``,
- ``<route>`` or ``<handler>`` declaration to :term:`ZCML` used by your
- application as per :ref:`mapping_views_using_zcml_section`,
- :ref:`view_directive`, :ref:`route_directive` or :ref:`handler_directive`.
-
-.. _view_configuration_parameters:
-
-View Configuration Parameters
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-All forms of view configuration accept the same general types of arguments.
-
-Many arguments supplied during view configuration are :term:`view predicate`
-arguments. View predicate arguments used during view configuration are used
-to narrow the set of circumstances in which :mod:`view lookup` will find a
-particular view callable. In general, the fewer number of predicates which
-are supplied to a particular view configuration, the more likely it is that
-the associated view callable will be invoked. The greater the number
-supplied, the less likely.
-
-Some view configuration arguments are non-predicate arguments. These tend to
-modify the response of the view callable or prevent the view callable from
-being invoked due to an authorization policy. The presence of non-predicate
-arguments in a view configuration does not narrow the circumstances in which
-the view callable will be invoked.
-
-Non-Predicate Arguments
-+++++++++++++++++++++++
-
-``permission``
- The name of a :term:`permission` that the user must possess in order to
- invoke the :term:`view callable`. See :ref:`view_security_section` for
- more information about view security and permissions.
-
- If ``permission`` is not supplied, no permission is registered for this
- view (it's accessible by any caller).
-
-``attr``
- The view machinery defaults to using the ``__call__`` method of the
- :term:`view callable` (or the function itself, if the view callable is a
- function) to obtain a response. The ``attr`` value allows you to vary the
- method attribute used to obtain the response. For example, if your view
- was a class, and the class has a method named ``index`` and you wanted to
- use this method instead of the class' ``__call__`` method to return the
- response, you'd say ``attr="index"`` in the view configuration for the
- view. This is most useful when the view definition is a class.
-
- If ``attr`` is not supplied, ``None`` is used (implying the function itself
- if the view is a function, or the ``__call__`` callable attribute if the
- view is a class).
-
-``renderer``
- Denotes the :term:`renderer` implementation which will be used to construct
- a :term:`response` from the associated view callable's return value. (see
- also :ref:`renderers_chapter`).
-
- This is either a single string term (e.g. ``json``) or a string implying a
- path or :term:`asset specification` (e.g. ``templates/views.pt``) naming a
- :term:`renderer` implementation. If the ``renderer`` value does not
- contain a dot (``.``), the specified string will be used to look up a
- renderer implementation, and that renderer implementation will be used to
- construct a response from the view return value. If the ``renderer`` value
- contains a dot (``.``), the specified term will be treated as a path, and
- the filename extension of the last element in the path will be used to look
- up the renderer implementation, which will be passed the full path.
-
- When the renderer is a path, although a path is usually just a simple
- relative pathname (e.g. ``templates/foo.pt``, implying that a template
- named "foo.pt" is in the "templates" directory relative to the directory of
- the current :term:`package`), a path can be absolute, starting with a slash
- on UNIX or a drive letter prefix on Windows. The path can alternately be a
- :term:`asset specification` in the form
- ``some.dotted.package_name:relative/path``, making it possible to address
- template assets which live in a separate package.
-
- The ``renderer`` attribute is optional. If it is not defined, the "null"
- renderer is assumed (no rendering is performed and the value is passed back
- to the upstream :app:`Pyramid` machinery unmolested). Note that if the
- view callable itself returns a :term:`response` (see :ref:`the_response`),
- the specified renderer implementation is never called.
-
-``wrapper``
- The :term:`view name` of a different :term:`view configuration` which will
- receive the response body of this view as the ``request.wrapped_body``
- attribute of its own :term:`request`, and the :term:`response` returned by
- this view as the ``request.wrapped_response`` attribute of its own request.
- Using a wrapper makes it possible to "chain" views together to form a
- composite response. The response of the outermost wrapper view will be
- returned to the user. The wrapper view will be found as any view is found:
- see :ref:`view_lookup`. The "best" wrapper view will be found based on the
- lookup ordering: "under the hood" this wrapper view is looked up via
- ``pyramid.view.render_view_to_response(context, request,
- 'wrapper_viewname')``. The context and request of a wrapper view is the
- same context and request of the inner view.
-
- If ``wrapper`` is not supplied, no wrapper view is used.
-
-Predicate Arguments
-+++++++++++++++++++
-
-These arguments modify view lookup behavior. In general, the more predicate
-arguments that are supplied, the more specific, and narrower the usage of the
-configured view.
-
-``name``
- The :term:`view name` required to match this view callable. Read
- :ref:`traversal_chapter` to understand the concept of a view name.
-
- If ``name`` is not supplied, the empty string is used (implying the default
- view).
-
-``context``
- An object representing a Python class that the :term:`context` resource
- must be an instance of *or* the :term:`interface` that the :term:`context`
- resource must provide in order for this view to be found and called. This
- predicate is true when the :term:`context` resource is an instance of the
- represented class or if the :term:`context` resource provides the
- represented interface; it is otherwise false.
-
- If ``context`` is not supplied, the value ``None``, which matches any
- resource, is used.
-
-``route_name``
- If ``route_name`` is supplied, the view callable will be invoked only when
- the named route has matched.
-
- This value must match the ``name`` of a :term:`route configuration`
- declaration (see :ref:`urldispatch_chapter`) that must match before this
- view will be called. Note that the ``route`` configuration referred to by
- ``route_name`` will usually have a ``*traverse`` token in the value of its
- ``pattern``, representing a part of the path that will be used by
- :term:`traversal` against the result of the route's :term:`root factory`.
-
- If ``route_name`` is not supplied, the view callable will be have a chance
- of being invoked if no other route was matched. This is when the
- request/context pair found via :term:`resource location` does not indicate
- it matched any configured route.
-
-``request_type``
- This value should be an :term:`interface` that the :term:`request` must
- provide in order for this view to be found and called.
-
- If ``request_type`` is not supplied, the value ``None`` is used, implying
- any request type.
-
- *This is an advanced feature, not often used by "civilians"*.
-
-``request_method``
- This value can either be one of the strings ``GET``, ``POST``, ``PUT``,
- ``DELETE``, or ``HEAD`` representing an HTTP ``REQUEST_METHOD``. A view
- declaration with this argument ensures that the view will only be called
- when the request's ``method`` attribute (aka the ``REQUEST_METHOD`` of the
- WSGI environment) string matches the supplied value.
-
- If ``request_method`` is not supplied, the view will be invoked regardless
- of the ``REQUEST_METHOD`` of the :term:`WSGI` environment.
-
-``request_param``
- This value can be any string. A view declaration with this argument
- ensures that the view will only be called when the :term:`request` has a
- key in the ``request.params`` dictionary (an HTTP ``GET`` or ``POST``
- variable) that has a name which matches the supplied value.
-
- If the value supplied has a ``=`` sign in it,
- e.g. ``request_params="foo=123"``, then the key (``foo``) must both exist
- in the ``request.params`` dictionary, *and* the value must match the right
- hand side of the expression (``123``) for the view to "match" the current
- request.
-
- If ``request_param`` is not supplied, the view will be invoked without
- consideration of keys and values in the ``request.params`` dictionary.
-
-``containment``
- This value should be a reference to a Python class or :term:`interface`
- that a parent object in the context resource's :term:`lineage` must provide
- in order for this view to be found and called. The resources in your
- resource tree must be "location-aware" to use this feature.
-
- If ``containment`` is not supplied, the interfaces and classes in the
- lineage are not considered when deciding whether or not to invoke the view
- callable.
-
- See :ref:`location_aware` for more information about location-awareness.
-
-``xhr``
- This value should be either ``True`` or ``False``. If this value is
- specified and is ``True``, the :term:`WSGI` environment must possess an
- ``HTTP_X_REQUESTED_WITH`` (aka ``X-Requested-With``) header that has the
- value ``XMLHttpRequest`` for the associated view callable to be found and
- called. This is useful for detecting AJAX requests issued from jQuery,
- Prototype and other Javascript libraries.
-
- If ``xhr`` is not specified, the ``HTTP_X_REQUESTED_WITH`` HTTP header is
- not taken into consideration when deciding whether or not to invoke the
- associated view callable.
-
-``accept``
- The value of this argument represents a match query for one or more
- mimetypes in the ``Accept`` HTTP request header. If this value is
- specified, it must be in one of the following forms: a mimetype match token
- in the form ``text/plain``, a wildcard mimetype match token in the form
- ``text/*`` or a match-all wildcard mimetype match token in the form
- ``*/*``. If any of the forms matches the ``Accept`` header of the request,
- this predicate will be true.
-
- If ``accept`` is not specified, the ``HTTP_ACCEPT`` HTTP header is not
- taken into consideration when deciding whether or not to invoke the
- associated view callable.
-
-``header``
- This value represents an HTTP header name or a header name/value pair.
-
- If ``header`` is specified, it must be a header name or a
- ``headername:headervalue`` pair.
-
- If ``header`` is specified without a value (a bare header name only,
- e.g. ``If-Modified-Since``), the view will only be invoked if the HTTP
- header exists with any value in the request.
-
- If ``header`` is specified, and possesses a name/value pair
- (e.g. ``User-Agent:Mozilla/.*``), the view will only be invoked if the HTTP
- header exists *and* the HTTP header matches the value requested. When the
- ``headervalue`` contains a ``:`` (colon), it will be considered a
- name/value pair (e.g. ``User-Agent:Mozilla/.*`` or ``Host:localhost``).
- The value portion should be a regular expression.
-
- Whether or not the value represents a header name or a header name/value
- pair, the case of the header name is not significant.
-
- If ``header`` is not specified, the composition, presence or absence of
- HTTP headers is not taken into consideration when deciding whether or not
- to invoke the associated view callable.
-
-``path_info``
- This value represents a regular expression pattern that will be tested
- against the ``PATH_INFO`` WSGI environment variable to decide whether or
- not to call the associated view callable. If the regex matches, this
- predicate will be ``True``.
-
- If ``path_info`` is not specified, the WSGI ``PATH_INFO`` is not taken into
- consideration when deciding whether or not to invoke the associated view
- callable.
-
-``custom_predicates``
- If ``custom_predicates`` is specified, it must be a sequence of references
- to custom predicate callables. Use custom predicates when no set of
- predefined predicates do what you need. Custom predicates can be combined
- with predefined predicates as necessary. Each custom predicate callable
- should accept two arguments: ``context`` and ``request`` and should return
- either ``True`` or ``False`` after doing arbitrary evaluation of the
- context resource and/or the request. If all callables return ``True``, the
- associated view callable will be considered viable for a given request.
-
- If ``custom_predicates`` is not specified, no custom predicates are
- used.
-
-.. index::
- single: view_config decorator
-
-.. _mapping_views_using_a_decorator_section:
-
-View Configuration Using the ``@view_config`` Decorator
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-For better locality of reference, you may use the
-:class:`pyramid.view.view_config` decorator to associate your view functions
-with URLs instead of using :term:`ZCML` or imperative configuration for the
-same purpose.
-
-.. warning::
-
- Using this feature tends to slows down application startup slightly, as
- more work is performed at application startup to scan for view
- declarations.
-
-Usage of the ``view_config`` decorator is a form of :term:`declarative
-configuration`, like ZCML, but in decorator form.
-:class:`pyramid.view.view_config` can be used to associate :term:`view
-configuration` information -- as done via the equivalent imperative code or
-ZCML -- with a function that acts as a :app:`Pyramid` view callable. All
-arguments to the :meth:`pyramid.config.Configurator.add_view` method (save
-for the ``view`` argument) are available in decorator form and mean precisely
-the same thing.
-
-An example of the :class:`pyramid.view.view_config` decorator might reside in
-a :app:`Pyramid` application module ``views.py``:
-
-.. ignore-next-block
-.. code-block:: python
- :linenos:
-
- from resources import MyResource
- from pyramid.view import view_config
- from pyramid.response import Response
-
- @view_config(name='my_view', request_method='POST', context=MyResource,
- permission='read')
- def my_view(request):
- return Response('OK')
-
-Using this decorator as above replaces the need to add this imperative
-configuration stanza:
-
-.. ignore-next-block
-.. code-block:: python
- :linenos:
-
- config.add_view('.views.my_view', name='my_view', request_method='POST',
- context=MyResource, permission='read')
-
-All arguments to ``view_config`` may be omitted. For example:
-
-.. code-block:: python
- :linenos:
-
- from pyramid.response import Response
- from pyramid.view import view_config
-
- @view_config()
- def my_view(request):
- """ My view """
- return Response()
-
-Such a registration as the one directly above implies that the view name will
-be ``my_view``, registered with a ``context`` argument that matches any
-resource type, using no permission, registered against requests with any
-request method, request type, request param, route name, or containment.
-
-The mere existence of a ``@view_config`` decorator doesn't suffice to perform
-view configuration. All that the decorator does is "annotate" the function
-with your configuration declarations, it doesn't process them. To make
-:app:`Pyramid` process your :class:`pyramid.view.view_config` declarations,
-you *must* do use the ``scan`` method of a
-:class:`pyramid.config.Configurator`:
-
-.. code-block:: python
- :linenos:
-
- # config is assumed to be an instance of the
- # pyramid.config.Configurator class
- config.scan()
-
-.. note:: See :ref:`zcml_scanning` for information about how to invoke a scan
- via ZCML (if you're not using imperative configuration).
-
-Please see :ref:`decorations_and_code_scanning` for detailed information
-about what happens when code is scanned for configuration declarations
-resulting from use of decorators like :class:`pyramid.view.view_config`.
-
-See :ref:`configuration_module` for additional API arguments to the
-:meth:`pyramid.config.Configurator.scan` method. For example, the method
-allows you to supply a ``package`` argument to better control exactly *which*
-code will be scanned.
-
-``@view_config`` Placement
-++++++++++++++++++++++++++
-
-A :class:`pyramid.view.view_config` decorator can be placed in various points
-in your application.
-
-If your view callable is a function, it may be used as a function decorator:
-
-.. code-block:: python
- :linenos:
-
- from pyramid.view import view_config
- from pyramid.response import Response
-
- @view_config(name='edit')
- def edit(request):
- return Response('edited!')
-
-If your view callable is a class, the decorator can also be used as a class
-decorator in Python 2.6 and better (Python 2.5 and below do not support class
-decorators). All the arguments to the decorator are the same when applied
-against a class as when they are applied against a function. For example:
-
-.. code-block:: python
- :linenos:
-
- from pyramid.response import Response
- from pyramid.view import view_config
-
- @view_config()
- class MyView(object):
- def __init__(self, request):
- self.request = request
-
- def __call__(self):
- return Response('hello')
-
-You can use the :class:`pyramid.view.view_config` decorator as a simple
-callable to manually decorate classes in Python 2.5 and below without the
-decorator syntactic sugar, if you wish:
-
-.. code-block:: python
- :linenos:
-
- from pyramid.response import Response
- from pyramid.view import view_config
-
- class MyView(object):
- def __init__(self, request):
- self.request = request
-
- def __call__(self):
- return Response('hello')
-
- my_view = view_config()(MyView)
-
-More than one :class:`pyramid.view.view_config` decorator can be stacked on
-top of any number of others. Each decorator creates a separate view
-registration. For example:
-
-.. code-block:: python
- :linenos:
-
- from pyramid.view import view_config
- from pyramid.response import Response
-
- @view_config(name='edit')
- @view_config(name='change')
- def edit(request):
- return Response('edited!')
-
-This registers the same view under two different names.
-
-The decorator can also be used against class methods:
-
-.. code-block:: python
- :linenos:
-
- from pyramid.response import Response
- from pyramid.view import view_config
-
- class MyView(object):
- def __init__(self, request):
- self.request = request
-
- @view_config(name='hello')
- def amethod(self):
- return Response('hello')
-
-When the decorator is used against a class method, a view is registered for
-the *class*, so the class constructor must accept an argument list in one of
-two forms: either it must accept a single argument ``request`` or it must
-accept two arguments, ``context, request``.
-
-The method which is decorated must return a :term:`response`.
-
-Using the decorator against a particular method of a class is equivalent to
-using the ``attr`` parameter in a decorator attached to the class itself.
-For example, the above registration implied by the decorator being used
-against the ``amethod`` method could be spelled equivalently as the below:
-
-.. code-block:: python
- :linenos:
-
- from pyramid.response import Response
- from pyramid.view import view_config
-
- @view_config(attr='amethod', name='hello')
- class MyView(object):
- def __init__(self, request):
- self.request = request
-
- def amethod(self):
- return Response('hello')
-
-.. index::
- single: add_view
-
-.. _mapping_views_using_imperative_config_section:
-
-View Registration Using :meth:`~pyramid.config.Configurator.add_view`
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-The :meth:`pyramid.config.Configurator.add_view` method within
-:ref:`configuration_module` is used to configure a view imperatively. The
-arguments to this method are very similar to the arguments that you provide
-to the ``@view_config`` decorator. For example:
-
-.. code-block:: python
- :linenos:
-
- from pyramid.response import Response
-
- def hello_world(request):
- return Response('hello!')
-
- # config is assumed to be an instance of the
- # pyramid.config.Configurator class
- config.add_view(hello_world, name='hello.html')
-
-The first argument, ``view``, is required. It must either be a Python object
-which is the view itself or a :term:`dotted Python name` to such an object.
-All other arguments are optional. See
-:meth:`pyramid.config.Configurator.add_view` for more information.
-
-.. _using_add_handler:
-
-Handler Registration Using :meth:`~pyramid.config.Configurator.add_handler`
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-:app:`Pyramid` provides the special concept of a :term:`view handler`. View
-handlers are view classes that implement a number of methods, each of which
-is a :term:`view callable` as a convenience for :term:`URL dispatch` users.
-
-.. note::
-
- View handlers are *not* useful when using :term:`traversal`, only when using
- :term:`url dispatch`.
-
-Using a view handler instead of a plain function or class :term:`view
-callable` makes it unnecessary to call
-:meth:`pyramid.config.Configurator.add_route` (and/or
-:meth:`pyramid.config.Configurator.add_view`) "by hand" multiple times,
-making it more pleasant to register a collection of views as a single class
-when using :term:`url dispatch`. The view handler machinery also introduces
-the concept of an ``action``, which is used as a :term:`view predicate` to
-control which method of the handler is called. The method name is the
-default *action name* of a handler view callable.
-
-The concept of a view handler is analogous to a "controller" in Pylons 1.0.
-
-The view handler class is initialized by :app:`Pyramid` in the same manner as
-a "plain" view class. Its ``__init__`` is called with a request object (see
-:ref:`class_as_view`). It implements methods, each of which is a :term:`view
-callable`. When a request enters the system which corresponds with an
-*action* related to one of its view callable methods, this method is called,
-and it is expected to return a response.
-
-Here's an example view handler class:
-
-.. code-block:: python
- :linenos:
-
- from pyramid.response import Response
-
- from pyramid.view import action
-
- class Hello(object):
- def __init__(self, request):
- self.request = request
-
- def index(self):
- return Response('Hello world!')
-
- @action(renderer="mytemplate.mak")
- def bye(self):
- return {}
-
-The :class:`pyramid.view.action` decorator is used to fine-tune the view
-parameters for each potential view callable which is a method of the handler.
-
-Handlers are added to application configuration via the
-:meth:`pyramid.config.Configurator.add_handler` API. The
-:meth:`~pyramid.config.Configurator.add_handler` method will scan a
-:term:`view handler` class and automatically set up view configurations for
-its methods that represent "auto-exposed" view callable, or those that were
-decorated explicitly with the :class:`~pyramid.view.action` decorator. This
-decorator is used to setup additional view configuration information for
-individual methods of the class, and can be used repeatedly for a single view
-method to register multiple view configurations for it.
-
-.. code-block:: python
- :linenos:
-
- from myapp.handlers import Hello
- config.add_handler('hello', '/hello/{action}', handler=Hello)
-
-This example will result in a route being added for the pattern
-``/hello/{action}``, and each method of the ``Hello`` class will then be
-examined to see if it should be registered as a potential view callable when
-the ``/hello/{action}`` pattern matches. The value of ``{action}`` in the
-route pattern will be used to determine which view should be called, and each
-view in the class will be setup with a view predicate that requires a
-specific ``action`` name. By default, the action name for a method of a
-handler is the method name.
-
-If the URL was ``/hello/index``, the above example pattern would match, and,
-by default, the ``index`` method of the ``Hello`` class would be called.
-
-Alternatively, the action can be declared specifically for a URL to be
-registered for a *specific* ``action`` name:
-
-.. code-block:: python
- :linenos:
-
- from myapp.handlers import Hello
- config.add_handler('hello_index', '/hello/index',
- handler=Hello, action='index')
-
-This will result one of the methods that are configured for the ``action`` of
-'index' in the ``Hello`` handler class to be called. In this case the name of
-the method is the same as the action name: ``index``. However, this need not
-be the case, as we will see below.
-
-When calling :meth:`~pyramid.config.Configurator.add_handler`, an ``action``
-is required in either the route pattern or as a keyword argument, but
-**cannot appear in both places**. A ``handler`` argument must also be
-supplied, which can be either a :term:`asset specification` or a Python
-reference to the handler class. Additional keyword arguments are passed
-directly through to :meth:`pyramid.config.Configurator.add_route`.
-
-For example:
-
-.. code-block:: python
- :linenos:
-
- config.add_handler('hello', '/hello/{action}',
- handler='mypackage.handlers.MyHandler')
-
-Multiple :meth:`~pyramid.config.Configurator.add_handler` calls can specify
-the same handler, to register specific route names for different
-handler/action combinations. For example:
-
-.. code-block:: python
- :linenos:
-
- config.add_handler('hello_index', '/hello/index',
- handler=Hello, action='index')
- config.add_handler('bye_index', '/hello/bye',
- handler=Hello, action='bye')
-
-.. note::
-
- Handler configuration may also be added to the system via :term:`ZCML` (see
- :ref:`zcml_handler_configuration`).
-
-View Setup in the Handler Class
-+++++++++++++++++++++++++++++++
-
-A handler class can have a single class level attribute called
-``__autoexpose__`` which should be a regular expression or the value
-``None``. It's used to determine which method names will result in additional
-view configurations being registered.
-
-When :meth:`~pyramid.config.Configurator.add_handler` runs, every method in
-the handler class will be searched and a view registered if the method name
-matches the ``__autoexpose__`` regular expression, or if the method was
-decorated with :class:`~pyramid.view.action`.
-
-Every method in the handler class that has a name meeting the
-``__autoexpose__`` regular expression will have a view registered for an
-``action`` name corresponding to the method name. This functionality can be
-disabled by setting the ``__autoexpose__`` attribute to ``None``:
-
-.. code-block:: python
- :linenos:
-
- from pyramid.view import action
-
- class Hello(object):
- __autoexpose__ = None
-
- def __init__(self, request):
- self.request = request
-
- @action()
- def index(self):
- return Response('Hello world!')
-
- @action(renderer="mytemplate.mak")
- def bye(self):
- return {}
-
-With auto-expose effectively disabled, no views will be registered for a
-method unless it is specifically decorated with
-:class:`~pyramid.view.action`.
-
-Action Decorators in a Handler
-++++++++++++++++++++++++++++++
-
-The :class:`~pyramid.view.action` decorator registers view configuration
-information on the handler method, which is used by
-:meth:`~pyramid.config.Configurator.add_handler` to setup the view
-configuration.
-
-All keyword arguments are recorded, and passed to
-:meth:`~pyramid.config.Configurator.add_view`. Any valid keyword arguments
-for :meth:`~pyramid.config.Configurator.add_view` can thus be used with the
-:class:`~pyramid.view.action` decorator to further restrict when the view
-will be called.
-
-One important difference is that a handler method can respond to an
-``action`` name that is different from the method name by passing in a
-``name`` argument.
-
-Example:
-
-.. code-block:: python
- :linenos:
-
- from pyramid.view import action
-
- class Hello(object):
- def __init__(self, request):
- self.request = request
-
- @action(name='index', renderer='created.mak', request_method='POST')
- def create(self):
- return {}
-
- @action(renderer="view_all.mak", request_method='GET')
- def index(self):
- return {}
-
-This will register two views that require the ``action`` to be ``index``,
-with the additional view predicate requiring a specific request method.
-
-It can be useful to decorate a single method multiple times with
-:class:`~pyramid.view.action`. Each action decorator will register a new view
-for the method. By specifying different names and renderers for each action,
-the same view logic can be exposed and rendered differently on multiple URLs.
-
-Example:
-
-.. code-block:: python
- :linenos:
-
- from pyramid.view import action
-
- class Hello(object):
- def __init__(self, request):
- self.request = request
-
- @action(name='home', renderer='home.mak')
- @action(name='about', renderer='about.mak')
- def show_template(self):
- # prep some template vars
- return {}
-
- # in the config
- config.add_handler('hello', '/hello/{action}', handler=Hello)
-
-With this configuration, the url ``/hello/home`` will find a view
-configuration that results in calling the ``show_template`` method, then
-rendering the template with ``home.mak``, and the url ``/hello/about`` will
-call the same method and render the ``about.mak`` template.
-
-.. index::
- single: resource interfaces
-
-.. _using_resource_interfaces:
-
-Using Resource Interfaces In View Configuration
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-Instead of registering your views with a ``context`` that names a Python
-resource *class*, you can optionally register a view callable with a
-``context`` which is an :term:`interface`. An interface can be attached
-arbitrarily to any resource object. View lookup treats context interfaces
-specially, and therefore the identity of a resource can be divorced from that
-of the class which implements it. As a result, associating a view with an
-interface can provide more flexibility for sharing a single view between two
-or more different implementations of a resource type. For example, if two
-resource objects of different Python class types share the same interface,
-you can use the same view configuration to specify both of them as a
-``context``.
-
-In order to make use of interfaces in your application during view dispatch,
-you must create an interface and mark up your resource classes or instances
-with interface declarations that refer to this interface.
-
-To attach an interface to a resource *class*, you define the interface and
-use the :func:`zope.interface.implements` function to associate the interface
-with the class.
-
-.. code-block:: python
- :linenos:
-
- from zope.interface import Interface
- from zope.interface import implements
-
- class IHello(Interface):
- """ A marker interface """
-
- class Hello(object):
- implements(IHello)
-
-To attach an interface to a resource *instance*, you define the interface and
-use the :func:`zope.interface.alsoProvides` function to associate the
-interface with the instance. This function mutates the instance in such a
-way that the interface is attached to it.
-
-.. code-block:: python
- :linenos:
-
- from zope.interface import Interface
- from zope.interface import alsoProvides
-
- class IHello(Interface):
- """ A marker interface """
-
- class Hello(object):
- pass
-
- def make_hello():
- hello = Hello()
- alsoProvides(hello, IHello)
- return hello
-
-Regardless of how you associate an interface, with a resource instance, or a
-resource class, the resulting code to associate that interface with a view
-callable is the same. Assuming the above code that defines an ``IHello``
-interface lives in the root of your application, and its module is named
-"resources.py", the interface declaration below will associate the
-``mypackage.views.hello_world`` view with resources that implement, or
-provide, this interface.
-
-.. code-block:: python
- :linenos:
-
- # config is an instance of pyramid.config.Configurator
-
- config.add_view('mypackage.views.hello_world', name='hello.html',
- context='mypackage.resources.IHello')
-
-Any time a resource that is determined to be the :term:`context` provides
-this interface, and a view named ``hello.html`` is looked up against it as
-per the URL, the ``mypackage.views.hello_world`` view callable will be
-invoked.
-
-Note, in cases where a view is registered against a resource class, and a
-view is also registered against an interface that the resource class
-implements, an ambiguity arises. Views registered for the resource class take
-precedence over any views registered for any interface the resource class
-implements. Thus, if one view configuration names a ``context`` of both the
-class type of a resource, and another view configuration names a ``context``
-of interface implemented by the resource's class, and both view
-configurations are otherwise identical, the view registered for the context's
-class will "win".
-
-For more information about defining resources with interfaces for use within
-view configuration, see :ref:`resources_which_implement_interfaces`.
-
-.. index::
- single: view security
- pair: security; view
-
-.. _view_security_section:
-
-Configuring View Security
-~~~~~~~~~~~~~~~~~~~~~~~~~
-
-If an :term:`authorization policy` is active, any :term:`permission` attached
-to a :term:`view configuration` found during view lookup will be verified.
-This will ensure that the currently authenticated user possesses that
-permission against the :term:`context` resource before the view function is
-actually called. Here's an example of specifying a permission in a view
-configuration using :meth:`pyramid.config.Configurator.add_view`:
-
-.. code-block:: python
- :linenos:
-
- # config is an instance of pyramid.config.Configurator
-
- config.add_view('myproject.views.add_entry', name='add.html',
- context='myproject.resources.IBlog', permission='add')
-
-When an :term:`authorization policy` is enabled, this view will be protected
-with the ``add`` permission. The view will *not be called* if the user does
-not possess the ``add`` permission relative to the current :term:`context`.
-Instead the :term:`forbidden view` result will be returned to the client as
-per :ref:`protecting_views`.
-
-.. index::
- single: view lookup
-
-.. _view_lookup:
-
-View Lookup and Invocation
---------------------------
-
-:term:`View lookup` is the :app:`Pyramid` subsystem responsible for finding
-an invoking a :term:`view callable`. The view lookup subsystem is passed a
-:term:`context` and a :term:`request` object.
-
-:term:`View configuration` information stored within in the
-:term:`application registry` is compared against the context and request by
-the view lookup subsystem in order to find the "best" view callable for the
-set of circumstances implied by the context and request.
-
-Predicate attributes of view configuration can be thought of like
-"narrowers". In general, the greater number of predicate attributes
-possessed by a view's configuration, the more specific the circumstances need
-to be before the registered view callable will be invoked.
-
-For any given request, a view with five predicates will always be found and
-evaluated before a view with two, for example. All predicates must match for
-the associated view to be called.
-
-This does not mean however, that :app:`Pyramid` "stops looking" when it finds
-a view registration with predicates that don't match. If one set of view
-predicates does not match, the "next most specific" view (if any) view is
-consulted for predicates, and so on, until a view is found, or no view can be
-matched up with the request. The first view with a set of predicates all of
-which match the request environment will be invoked.
-
-If no view can be found with predicates which allow it to be matched up with
-the request, :app:`Pyramid` will return an error to the user's browser,
-representing a "not found" (404) page. See :ref:`changing_the_notfound_view`
-for more information about changing the default notfound view.
-
-.. index::
- single: debugging not found errors
- single: not found error (debugging)
-
-.. _debug_notfound_section:
-
-:exc:`NotFound` Errors
-~~~~~~~~~~~~~~~~~~~~~~
-
-It's useful to be able to debug :exc:`NotFound` error responses when they
-occur unexpectedly due to an application registry misconfiguration. To debug
-these errors, use the ``PYRAMID_DEBUG_NOTFOUND`` environment variable or the
-``debug_notfound`` configuration file setting. Details of why a view was not
-found will be printed to ``stderr``, and the browser representation of the
-error will include the same information. See :ref:`environment_chapter` for
-more information about how, and where to set these values.
-
-Further Information
--------------------
-
-The chapter entitled :ref:`renderers_chapter` explains how to create
-functions (or instances/classes) which do not return a :term:`Response`
-object, yet which still can be used as view callables.
-
diff --git a/docs/narr/zca.rst b/docs/narr/zca.rst
index f330fd551..78a7b0b75 100644
--- a/docs/narr/zca.rst
+++ b/docs/narr/zca.rst
@@ -57,7 +57,7 @@ Using the ZCA Global API in a :app:`Pyramid` Application
-----------------------------------------------------------
:term:`Zope` uses a single ZCA registry -- the "global" ZCA registry
--- for all Zope applications run in the same Python process,
+-- for all Zope applications that run in the same Python process,
effectively making it impossible to run more than one Zope application
in a single process.
@@ -158,9 +158,7 @@ Consider the following bit of idiomatic :app:`Pyramid` startup code:
def app(global_settings, **settings):
config = Configurator(settings=settings)
- config.begin()
- config.load_zcml('configure.zcml')
- config.end()
+ config.include('some.other.package')
return config.make_wsgi_app()
When the ``app`` function above is run, a :term:`Configurator` is
@@ -198,9 +196,7 @@ setup code. For example:
def app(global_settings, **settings):
config = Configurator(settings=settings)
config.hook_zca()
- config.begin()
- config.load_zcml('configure.zcml')
- config.end()
+ config.include('some.other.application')
return config.make_wsgi_app()
We've added a line to our original startup code, line number 6, which
@@ -250,9 +246,7 @@ registry at startup time instead of constructing a new one:
config = Configurator(registry=globalreg)
config.setup_registry(settings=settings)
config.hook_zca()
- config.begin()
- config.load_zcml('configure.zcml')
- config.end()
+ config.include('some.other.application')
return config.make_wsgi_app()
Lines 5, 6, and 7 above are the interesting ones. Line 5 retrieves
@@ -268,36 +262,3 @@ rather than creating a new application-specific registry; since by
default the ZCA global API will use this registry, things will work as
you might expect a Zope app to when you use the global ZCA API.
-.. index::
- single: Zope ZCML directives
- single: getGlobalSiteManager
- single: getSiteManager
-
-Using Broken ZCML Directives
-----------------------------
-
-Some :term:`Zope` and third-party :term:`ZCML` directives use the
-``zope.component.getGlobalSiteManager`` API to get "the registry" when
-they should actually be calling ``zope.component.getSiteManager``.
-
-``zope.component.getSiteManager`` can be overridden by
-:app:`Pyramid` via
-:meth:`pyramid.config.Configurator.hook_zca`, while
-``zope.component.getGlobalSiteManager`` cannot. Directives that use
-``zope.component.getGlobalSiteManager`` are effectively broken; no
-ZCML directive should be using this function to find a registry to
-populate.
-
-You cannot use ZCML directives which use
-``zope.component.getGlobalSiteManager`` within a :app:`Pyramid`
-application without passing the ZCA global registry to the
-:term:`Configurator` constructor at application startup, as per
-:ref:`using_the_zca_global_registry`.
-
-One alternative exists: fix the ZCML directive to use
-``getSiteManager`` rather than ``getGlobalSiteManager``. If a
-directive disuses ``getGlobalSiteManager``, the ``hook_zca`` method of
-using a component registry as documented in :ref:`hook_zca` will begin
-to work, allowing you to make use of the ZCML directive without
-also using the ZCA global registry.
-