summaryrefslogtreecommitdiff
path: root/docs/narr
diff options
context:
space:
mode:
Diffstat (limited to 'docs/narr')
-rw-r--r--docs/narr/advconfig.rst8
-rw-r--r--docs/narr/commandline.rst4
-rw-r--r--docs/narr/firstapp.rst13
-rw-r--r--docs/narr/helloworld.py15
-rw-r--r--docs/narr/hooks.rst200
-rw-r--r--docs/narr/install.rst213
-rw-r--r--docs/narr/introduction.rst4
-rw-r--r--docs/narr/project.rst41
-rw-r--r--docs/narr/renderers.rst4
-rw-r--r--docs/narr/subrequest.rst271
-rw-r--r--docs/narr/templates.rst75
-rw-r--r--docs/narr/testing.rst26
-rw-r--r--docs/narr/upgrading.rst234
-rw-r--r--docs/narr/views.rst12
14 files changed, 1005 insertions, 115 deletions
diff --git a/docs/narr/advconfig.rst b/docs/narr/advconfig.rst
index 2949dc808..ad22a82c9 100644
--- a/docs/narr/advconfig.rst
+++ b/docs/narr/advconfig.rst
@@ -294,6 +294,7 @@ These are the methods of the configurator which provide conflict detection:
:meth:`~pyramid.config.Configurator.add_view`,
:meth:`~pyramid.config.Configurator.add_route`,
:meth:`~pyramid.config.Configurator.add_renderer`,
+:meth:`~pyramid.config.Configurator.add_request_method`,
:meth:`~pyramid.config.Configurator.set_request_factory`,
:meth:`~pyramid.config.Configurator.set_session_factory`,
:meth:`~pyramid.config.Configurator.set_request_property`,
@@ -413,3 +414,10 @@ 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.
+More Information
+----------------
+
+For more information, see the article entitled `"A Whirlwind Rour of Advanced
+Configuration Tactics"
+<http://docs.pylonsproject.org/projects/pyramid_cookbook/en/latest/configuration/whirlwind_tour.html>`_
+in the Pyramid Cookbook.
diff --git a/docs/narr/commandline.rst b/docs/narr/commandline.rst
index af53c1f78..3bdf8c5cd 100644
--- a/docs/narr/commandline.rst
+++ b/docs/narr/commandline.rst
@@ -349,7 +349,7 @@ setting) orderings using the ``ptweens`` command. Tween factories
will show up represented by their standard Python dotted name in the
``ptweens`` output.
-For example, here's the ``pwteens`` command run against a system
+For example, here's the ``ptweens`` command run against a system
configured without any explicit tweens:
.. code-block:: text
@@ -367,7 +367,7 @@ configured without any explicit tweens:
1 pyramid.tweens.excview_tween_factory excview
- - MAIN
-Here's the ``pwteens`` command run against a system configured *with*
+Here's the ``ptweens`` command run against a system configured *with*
explicit tweens defined in its ``development.ini`` file:
.. code-block:: text
diff --git a/docs/narr/firstapp.rst b/docs/narr/firstapp.rst
index 1ca188d7e..ccaa6e9e2 100644
--- a/docs/narr/firstapp.rst
+++ b/docs/narr/firstapp.rst
@@ -8,7 +8,8 @@ Creating Your First :app:`Pyramid` Application
In this chapter, we will walk through the creation of a tiny :app:`Pyramid`
application. After we're finished creating the application, we'll explain in
-more detail how it works.
+more detail how it works. It assumes you already have :app:`Pyramid` installed.
+If you do not, head over to the :ref:`installing_chapter` section.
.. _helloworld_imperative:
@@ -126,7 +127,7 @@ defined imports and function definitions, placed within the confines of an
.. literalinclude:: helloworld.py
:linenos:
- :lines: 8-13
+ :lines: 9-15
Let's break this down piece-by-piece.
@@ -135,7 +136,7 @@ Configurator Construction
.. literalinclude:: helloworld.py
:linenos:
- :lines: 8-9
+ :lines: 9-10
The ``if __name__ == '__main__':`` line in the code sample above represents a
Python idiom: the code inside this if clause is not invoked unless the script
@@ -168,7 +169,7 @@ Adding Configuration
.. ignore-next-block
.. literalinclude:: helloworld.py
:linenos:
- :lines: 10-11
+ :lines: 11-12
First line above calls the :meth:`pyramid.config.Configurator.add_route`
method, which registers a :term:`route` to match any URL path that begins
@@ -188,7 +189,7 @@ WSGI Application Creation
.. ignore-next-block
.. literalinclude:: helloworld.py
:linenos:
- :lines: 12
+ :lines: 13
After configuring views and ending configuration, the script creates a WSGI
*application* via the :meth:`pyramid.config.Configurator.make_wsgi_app`
@@ -217,7 +218,7 @@ WSGI Application Serving
.. ignore-next-block
.. literalinclude:: helloworld.py
:linenos:
- :lines: 13
+ :lines: 14-15
Finally, we actually serve the application to requestors by starting up a
WSGI server. We happen to use the :mod:`wsgiref` ``make_server`` server
diff --git a/docs/narr/helloworld.py b/docs/narr/helloworld.py
index 7c26c8cdc..c01329af9 100644
--- a/docs/narr/helloworld.py
+++ b/docs/narr/helloworld.py
@@ -2,14 +2,15 @@ from wsgiref.simple_server import make_server
from pyramid.config import Configurator
from pyramid.response import Response
+
def hello_world(request):
- return Response('Hello %(name)s!' % request.matchdict)
+ return Response('Hello %(name)s!' % request.matchdict)
if __name__ == '__main__':
- config = Configurator()
- config.add_route('hello', '/hello/{name}')
- config.add_view(hello_world, route_name='hello')
- app = config.make_wsgi_app()
- server = make_server('0.0.0.0', 8080, app)
- server.serve_forever()
+ config = Configurator()
+ config.add_route('hello', '/hello/{name}')
+ config.add_view(hello_world, route_name='hello')
+ app = config.make_wsgi_app()
+ server = make_server('0.0.0.0', 8080, app)
+ server.serve_forever()
diff --git a/docs/narr/hooks.rst b/docs/narr/hooks.rst
index 332805152..96fa77a07 100644
--- a/docs/narr/hooks.rst
+++ b/docs/narr/hooks.rst
@@ -1232,3 +1232,203 @@ Displaying Tween Ordering
The ``ptweens`` command-line utility can be used to report the current
implict and explicit tween chains used by an application. See
:ref:`displaying_tweens`.
+
+.. _registering_thirdparty_predicates:
+
+Adding A Third Party View, Route, or Subscriber Predicate
+---------------------------------------------------------
+
+.. note::
+
+ Third-party view, route, and subscriber predicates are a feature new as of
+ Pyramid 1.4.
+
+.. _view_and_route_predicates:
+
+View and Route Predicates
+~~~~~~~~~~~~~~~~~~~~~~~~~
+
+View and route predicates used during configuration allow you to narrow the
+set of circumstances under which a view or route will match. For example,
+the ``request_method`` view predicate can be used to ensure a view callable
+is only invoked when the request's method is ``POST``:
+
+.. code-block:: python
+
+ @view_config(request_method='POST')
+ def someview(request):
+ ...
+
+Likewise, a similar predicate can be used as a *route* predicate:
+
+.. code-block:: python
+
+ config.add_route('name', '/foo', request_method='POST')
+
+Many other built-in predicates exists (``request_param``, and others). You
+can add third-party predicates to the list of available predicates by using
+one of :meth:`pyramid.config.Configurator.add_view_predicate` or
+:meth:`pyramid.config.Configurator.add_route_predicate`. The former adds a
+view predicate, the latter a route predicate.
+
+When using one of those APIs, you pass a *name* and a *factory* to add a
+predicate during Pyramid's configuration stage. For example:
+
+.. code-block:: python
+
+ config.add_view_predicate('content_type', ContentTypePredicate)
+
+The above example adds a new predicate named ``content_type`` to the list of
+available predicates for views. This will allow the following view
+configuration statement to work:
+
+.. code-block:: python
+ :linenos:
+
+ @view_config(content_type='File')
+ def aview(request): ...
+
+The first argument to :meth:`pyramid.config.Configurator.add_view_predicate`,
+the name, is a string representing the name that is expected to be passed to
+``view_config`` (or its imperative analogue ``add_view``).
+
+The second argument is a view or route predicate factory. A view or route
+predicate factory is most often a class with a constructor (``__init__``), a
+``text`` method, a ``phash`` method and a ``__call__`` method. For example:
+
+.. code-block:: python
+ :linenos:
+
+ class ContentTypePredicate(object):
+ def __init__(self, val, config):
+ self.val = val
+
+ def text(self):
+ return 'content_type = %s' % (self.val,)
+
+ phash = text
+
+ def __call__(self, context, request):
+ return getattr(context, 'content_type', None) == self.val
+
+The constructor of a predicate factory takes two arguments: ``val`` and
+``config``. The ``val`` argument will be the argument passed to
+``view_config`` (or ``add_view``). In the example above, it will be the
+string ``File``. The second arg, ``config`` will be the Configurator
+instance at the time of configuration.
+
+The ``text`` method must return a string. It should be useful to describe
+the behavior of the predicate in error messages.
+
+The ``phash`` method must return a string or a sequence of strings. It's
+most often the same as ``text``, as long as ``text`` uniquely describes the
+predicate's name and the value passed to the constructor. If ``text`` is
+more general, or doesn't describe things that way, ``phash`` should return a
+string with the name and the value serialized. The result of ``phash`` is
+not seen in output anywhere, it just informs the uniqueness constraints for
+view configuration.
+
+The ``__call__`` method of a predicate factory must accept a resource
+(``context``) and a request, and must return ``True`` or ``False``. It is
+the "meat" of the predicate.
+
+You can use the same predicate factory as both a view predicate and as a
+route predicate, but you'll need to call ``add_view_predicate`` and
+``add_route_predicate`` separately with the same factory.
+
+.. _subscriber_predicates:
+
+Subscriber Predicates
+~~~~~~~~~~~~~~~~~~~~~
+
+Subscriber predicates work almost exactly like view and route predicates.
+They narrow the set of circumstances in which a subscriber will be called.
+There are several minor differences between a subscriber predicate and a
+view/route predicate:
+
+- There are no default subscriber predicates. You must register one to use
+ one.
+
+- The ``__call__`` method of a subscriber predicate accepts a single
+ ``event`` object instead of a ``context`` and a ``request``.
+
+- Not every subscriber predicate can be used with every event type. Some
+ subscriber predicates will assume a certain event type.
+
+Here's an example of a subscriber predicate that can be used in conjunction
+with a subscriber that subscribes to the :class:`pyramid.events.NewReqest`
+event type.
+
+.. code-block:: python
+ :linenos:
+
+ class RequestPathStartsWith(object):
+ def __init__(self, val, config):
+ self.val = val
+
+ def text(self):
+ return 'path_startswith = %s' % (self.val,)
+
+ phash = text
+
+ def __call__(self, event):
+ return event.request.path.startswith(self.val)
+
+Once you've created a subscriber predicate, it may registered via
+:meth:`pyramid.config.Configurator.add_subscriber_predicate`. For example:
+
+.. code-block:: python
+
+ config.add_subscriber_predicate(
+ 'request_path_startswith', RequestPathStartsWith)
+
+Once a subscriber predicate is registered, you can use it in a call to
+:meth:`pyramid.config.Configurator.add_subscriber` or to
+:class:`pyramid.events.subscriber`. Here's an example of using the
+previously registered ``request_path_startswith`` predicate in a call to
+:meth:`~pyramid.config.Configurator.add_subscriber`:
+
+.. code-block:: python
+ :linenos:
+
+ # define a subscriber in your code
+
+ def yosubscriber(event):
+ event.request.yo = 'YO!'
+
+ # and at configuration time
+
+ config.add_subscriber(yosubscriber, NewRequest,
+ request_path_startswith='/add_yo')
+
+Here's the same subscriber/predicate/event-type combination used via
+:class:`~pyramid.events.subscriber`.
+
+.. code-block:: python
+ :linenos:
+
+ from pyramid.events import subscriber
+
+ @subscriber(NewRequest, request_path_startswith='/add_yo')
+ def yosubscriber(event):
+ event.request.yo = 'YO!'
+
+In either of the above configurations, the ``yosubscriber`` callable will
+only be called if the request path starts with ``/add_yo``. Otherwise the
+event subscriber will not be called.
+
+Note that the ``request_path_startswith`` subscriber you defined can be used
+with events that have a ``request`` attribute, but not ones that do not. So,
+for example, the predicate can be used with subscribers registered for
+:class:`pyramid.events.NewRequest` and :class:`pyramid.events.ContextFound`
+events, but it cannot be used with subscribers registered for
+:class:`pyramid.events.ApplicationCreated` because the latter type of event
+has no ``request`` attribute. The point being: unlike route and view
+predicates, not every type of subscriber predicate will necessarily be
+applicable for use in every subscriber registration. It is not the
+responsibility of the predicate author to make every predicate make sense for
+every event type; it is the responsibility of the predicate consumer to use
+predicates that make sense for a particular event type registration.
+
+
+
diff --git a/docs/narr/install.rst b/docs/narr/install.rst
index 172cfd6d3..e8482a289 100644
--- a/docs/narr/install.rst
+++ b/docs/narr/install.rst
@@ -14,13 +14,13 @@ run :app:`Pyramid`.
.. sidebar:: Python Versions
- As of this writing, :app:`Pyramid` has been tested under Python 2.6.6,
- Python 2.7.2, and Python 3.2. :app:`Pyramid` does not run under any
- version of Python before 2.6.
+ As of this writing, :app:`Pyramid` has been tested under Python 2.6.8,
+ Python 2.7.3, Python 3.2.3, and Python 3.3b1. :app:`Pyramid` does not
+ run under any version of Python before 2.6.
:app:`Pyramid` is known to run on all popular UNIX-like systems such as
Linux, MacOS X, and FreeBSD as well as on Windows platforms. It is also
-known to run on :term:`PyPy` (1.6+).
+known to run on :term:`PyPy` (1.9+).
:app:`Pyramid` installation does not require the compilation of any
C code, so you need only a Python interpreter that meets the
@@ -45,15 +45,15 @@ system's package manager is slightly different, but the "flavor" of
them is usually the same.
For example, on an Ubuntu Linux system, to use the system package
-manager to install a Python 2.6 interpreter, use the following
+manager to install a Python 2.7 interpreter, use the following
command:
.. code-block:: text
- $ sudo apt-get install python2.6-dev
+ $ sudo apt-get install python2.7-dev
Once these steps are performed, the Python interpreter will usually be
-invokable via ``python2.6`` from a shell prompt.
+invokable via ``python2.7`` from a shell prompt.
.. index::
pair: install; Python (from source, UNIX)
@@ -80,7 +80,7 @@ On Mac OS X, installing `XCode
<http://developer.apple.com/tools/xcode/>`_ has much the same effect.
Once you've got development tools installed on your system, you can
-install a Python 2.6 interpreter from *source*, on the same system,
+install a Python 2.7 interpreter from *source*, on the same system,
using the following commands:
.. code-block:: text
@@ -90,15 +90,15 @@ using the following commands:
[chrism@vitaminf ~]$ mkdir opt
[chrism@vitaminf ~]$ cd tmp
[chrism@vitaminf tmp]$ wget \
- http://www.python.org/ftp/python/2.6.4/Python-2.6.4.tgz
- [chrism@vitaminf tmp]$ tar xvzf Python-2.6.4.tgz
- [chrism@vitaminf tmp]$ cd Python-2.6.4
- [chrism@vitaminf Python-2.6.4]$ ./configure \
- --prefix=$HOME/opt/Python-2.6.4
- [chrism@vitaminf Python-2.6.4]$ make; make install
+ http://www.python.org/ftp/python/2.7.3/Python-2.7.3.tgz
+ [chrism@vitaminf tmp]$ tar xvzf Python-2.7.3.tgz
+ [chrism@vitaminf tmp]$ cd Python-2.7.3
+ [chrism@vitaminf Python-2.7.3]$ ./configure \
+ --prefix=$HOME/opt/Python-2.7.3
+ [chrism@vitaminf Python-2.7.3]$ make; make install
Once these steps are performed, the Python interpreter will be
-invokable via ``$HOME/opt/Python-2.6.4/bin/python`` from a shell
+invokable via ``$HOME/opt/Python-2.7.3/bin/python`` from a shell
prompt.
.. index::
@@ -108,7 +108,7 @@ If You Don't Yet Have A Python Interpreter (Windows)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
If your Windows system doesn't have a Python interpreter, you'll need
-to install it by downloading a Python 2.6-series interpreter
+to install it by downloading a Python 2.7-series interpreter
executable from `python.org's download section
<http://python.org/download/>`_ (the files labeled "Windows
Installer"). Once you've downloaded it, double click on the
@@ -119,7 +119,7 @@ extensions <http://sourceforge.net/projects/pywin32/files/>`_.
.. warning::
After you install Python on Windows, you may need to add the
- ``C:\Python26`` directory to your environment's ``Path`` in order
+ ``C:\Python27`` directory to your environment's ``Path`` in order
to make it possible to invoke Python from a command prompt by
typing ``python``. To do so, right click ``My Computer``, select
``Properties`` --> ``Advanced Tab`` --> ``Environment Variables``
@@ -141,39 +141,62 @@ done by using the :term:`virtualenv` package. Using a virtualenv will
also prevent :app:`Pyramid` from globally installing versions of
packages that are not compatible with your system Python.
-To set up a virtualenv in which to install :app:`Pyramid`, first
-ensure that :term:`setuptools` is installed. Invoke ``import
-setuptools`` within the Python interpreter you'd like to run
-:app:`Pyramid` under:
+To set up a virtualenv in which to install :app:`Pyramid`, first ensure that
+:term:`setuptools` or :term:`distribute` is installed. To do so, invoke
+``import setuptools`` within the Python interpreter you'd like to run
+:app:`Pyramid` under.
+
+Here's the output you'll expect if setuptools or distribute is already
+installed:
.. code-block:: text
- [chrism@vitaminf pyramid]$ python
- Python 2.6.5 (r265:79063, Apr 29 2010, 00:31:32)
- [GCC 4.4.3] on linux2
+ [chrism@thinko docs]$ python2.7
+ Python 2.7.3 (default, Aug 1 2012, 05:14:39)
+ [GCC 4.6.3] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import setuptools
+ >>>
-If running ``import setuptools`` does not raise an ``ImportError``, it
-means that setuptools is already installed into your Python
-interpreter. If ``import setuptools`` fails, you will need to install
-setuptools manually. Note that above we're using a Python 2.6-series
-interpreter on Mac OS X; your output may differ if you're using a
-later Python version or a different platform.
-
-If you are using a "system" Python (one installed by your OS
-distributor or a 3rd-party packager such as Fink or MacPorts), you can
-usually install the setuptools package by using your system's package
-manager. If you cannot do this, or if you're using a self-installed
-version of Python, you will need to install setuptools "by hand".
-Installing setuptools "by hand" is always a reasonable thing to do,
-even if your package manager already has a pre-chewed version of
-setuptools for installation.
-
-To install setuptools by hand, first download `ez_setup.py
-<http://peak.telecommunity.com/dist/ez_setup.py>`_ then invoke it
-using the Python interpreter into which you want to install
-setuptools.
+Here's the output you can expect if setuptools or distribute is not already
+installed:
+
+.. code-block:: text
+
+ [chrism@thinko docs]$ python2.7
+ Python 2.7.3 (default, Aug 1 2012, 05:14:39)
+ [GCC 4.6.3] on linux2
+ Type "help", "copyright", "credits" or "license" for more information.
+ >>> import setutptools
+ Traceback (most recent call last):
+ File "<stdin>", line 1, in <module>
+ ImportError: No module named setutptools
+ >>>
+
+If ``import setuptools`` raises an :exc:`ImportError` as it does above, you
+will need to install setuptools or distribute manually. Note that above
+we're using a Python 2.7-series interpreter on Mac OS X; your output may
+differ if you're using a later Python version or a different platform.
+
+If you are using a "system" Python (one installed by your OS distributor or a
+3rd-party packager such as Fink or MacPorts), you can usually install the
+setuptools or distribute package by using your system's package manager. If
+you cannot do this, or if you're using a self-installed version of Python,
+you will need to install setuptools or distribute "by hand". Installing
+setuptools or distribute "by hand" is always a reasonable thing to do, even
+if your package manager already has a pre-chewed version of setuptools for
+installation.
+
+If you're using Python 2, you'll want to install ``setuptools``. If you're
+using Python 3, you'll want to install ``distribute``. Below we tell you how
+to do both.
+
+Installing Setuptools On Python 2
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+To install setuptools by hand under Python 2, first download `ez_setup.py
+<http://peak.telecommunity.com/dist/ez_setup.py>`_ then invoke it using the
+Python interpreter into which you want to install setuptools.
.. code-block:: text
@@ -188,16 +211,37 @@ the script. To remediate this, you may need to do:
$ sudo python ez_setup.py
+Installing Distribute On Python 3
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+``setuptools`` doesn't work under Python 3. Instead, you can use
+``distribute``, which is a fork of setuptools that does work on Python 3. To
+install it, first download `distribute_setup.py
+<http://python-distribute.org/distribute_setup.py>`_ then invoke it using the
+Python interpreter into which you want to install setuptools.
+
+.. code-block:: text
+
+ $ python3 distribute_setup.py
+
+Once this command is invoked, distribute should be installed on your system.
+If the command fails due to permission errors, you may need to be the
+administrative user on your system to successfully invoke the script. To
+remediate this, you may need to do:
+
+.. code-block:: text
+
+ $ sudo python3 distribute_setup.py
+
.. index::
pair: install; virtualenv
Installing the ``virtualenv`` Package
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-Once you've got setuptools installed, you should install the
-:term:`virtualenv` package. To install the :term:`virtualenv` package
-into your setuptools-enabled Python interpreter, use the
-``easy_install`` command.
+Once you've got setuptools or distribute installed, you should install the
+:term:`virtualenv` package. To install the :term:`virtualenv` package into
+your setuptools-enabled Python interpreter, use the ``easy_install`` command.
.. code-block:: text
@@ -269,35 +313,90 @@ complete, as it downloads and installs a number of dependencies.
Installing :app:`Pyramid` on a Windows System
-------------------------------------------------
-#. Install, or find `Python 2.6
- <http://python.org/download/releases/2.6.4/>`_ for your system.
+You can use Pyramid on Windows under Python 2 or under Python 3. Directions
+for both versions are included below.
+
+Windows Using Python 2
+~~~~~~~~~~~~~~~~~~~~~~
+
+#. Install, or find `Python 2.7
+ <http://www.python.org/download/releases/2.7.3/>`_ for your system.
#. Install the `Python for Windows extensions
<http://sourceforge.net/projects/pywin32/files/>`_. Make sure to
- pick the right download for Python 2.6 and install it using the
+ pick the right download for Python 2.7 and install it using the
same Python installation from the previous step.
#. Install latest :term:`setuptools` distribution into the Python you
obtained/installed/found in the step above: download `ez_setup.py
<http://peak.telecommunity.com/dist/ez_setup.py>`_ and run it using
- the ``python`` interpreter of your Python 2.6 installation using a
+ the ``python`` interpreter of your Python 2.7 installation using a
command prompt:
.. code-block:: text
- c:\> c:\Python26\python ez_setup.py
+ c:\> c:\Python27\python ez_setup.py
+
+#. Use that Python's `bin/easy_install` to install `virtualenv`:
+
+ .. code-block:: text
+
+ c:\> c:\Python27\Scripts\easy_install virtualenv
+
+#. Use that Python's virtualenv to make a workspace:
+
+ .. code-block:: text
+
+ c:\> c:\Python27\Scripts\virtualenv --no-site-packages env
+
+#. Switch to the ``env`` directory:
+
+ .. code-block:: text
+
+ c:\> cd env
+
+#. (Optional) Consider using ``Scripts\activate.bat`` to make your shell
+ environment wired to use the virtualenv.
+
+#. Use ``easy_install`` to get :app:`Pyramid` and its direct dependencies
+ installed:
+
+ .. code-block:: text
+
+ c:\env> Scripts\easy_install pyramid
+
+Windows Using Python 3
+~~~~~~~~~~~~~~~~~~~~~~
+
+#. Install, or find `Python 3.2
+ <http://www.python.org/download/releases/3.2.3/>`_ for your system.
+
+#. Install the `Python for Windows extensions
+ <http://sourceforge.net/projects/pywin32/files/>`_. Make sure to
+ pick the right download for Python 3.2 and install it using the
+ same Python installation from the previous step.
+
+#. Install latest :term:`distribute` distribution into the Python you
+ obtained/installed/found in the step above: download `distribute_setup.py
+ <http://python-distribute.org/distribute_setup.py>`_ and run it using the
+ ``python`` interpreter of your Python 3.2 installation using a command
+ prompt:
+
+ .. code-block:: text
+
+ c:\> c:\Python32\python distribute_setup.py
#. Use that Python's `bin/easy_install` to install `virtualenv`:
.. code-block:: text
- c:\> c:\Python26\Scripts\easy_install virtualenv
+ c:\> c:\Python32\Scripts\easy_install virtualenv
#. Use that Python's virtualenv to make a workspace:
.. code-block:: text
- c:\> c:\Python26\Scripts\virtualenv --no-site-packages env
+ c:\> c:\Python32\Scripts\virtualenv --no-site-packages env
#. Switch to the ``env`` directory:
@@ -308,8 +407,8 @@ Installing :app:`Pyramid` on a Windows System
#. (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
- :app:`Pyramid` and its direct dependencies installed:
+#. Use ``easy_install`` to get :app:`Pyramid` and its direct dependencies
+ installed:
.. code-block:: text
diff --git a/docs/narr/introduction.rst b/docs/narr/introduction.rst
index b5fa6a9f7..7c0f9223f 100644
--- a/docs/narr/introduction.rst
+++ b/docs/narr/introduction.rst
@@ -803,7 +803,7 @@ within a function called when another user uses the
See also :ref:`add_directive`.
Programmatic Introspection
---------------------------
+~~~~~~~~~~~~~~~~~~~~~~~~~~
If you're building a large system that other users may plug code into, it's
useful to be able to get an enumeration of what code they plugged in *at
@@ -831,7 +831,7 @@ callable:
See also :ref:`using_introspection`.
Python 3 Compatibility
-----------------------
+~~~~~~~~~~~~~~~~~~~~~~
Pyramid and most of its add-ons are Python 3 compatible. If you develop a
Pyramid application today, you won't need to worry that five years from now
diff --git a/docs/narr/project.rst b/docs/narr/project.rst
index 1e2c225d2..b08948e43 100644
--- a/docs/narr/project.rst
+++ b/docs/narr/project.rst
@@ -286,11 +286,39 @@ Here's sample output from a run of ``pserve`` on UNIX:
$ ../bin/pserve development.ini
Starting server in PID 16601.
- serving on 0.0.0.0:6543 view at http://127.0.0.1:6543
+ serving on http://0.0.0.0:6543
-By default, :app:`Pyramid` applications generated from a scaffold
-will listen on TCP port 6543. You can shut down a server started this way by
-pressing ``Ctrl-C``.
+When you use ``pserve`` to start the application implied by the default
+rendering of a scaffold, it will respond to requests on *all* IP addresses
+possessed by your system, not just requests to ``localhost``. This is what
+the ``0.0.0.0`` in ``serving on http://0.0.0.0:6543`` means. The server will
+respond to requests made to ``127.0.0.1`` and on any external IP address.
+For example, your system might be configured to have an external IP address
+``192.168.1.50``. If that's the case, if you use a browser running on the
+same system as Pyramid, it will be able to access the application via
+``http://127.0.0.1:6543/`` as well as via
+``http://129.168.1.50:6543/``. However, *other people* on other computers on
+the same network will also be able to visit your Pyramid application in their
+browser by visiting ``http://192.168.1.50:6543/``.
+
+If you want to restrict access such that only a browser running on the same
+machine as Pyramid will be able to access your Pyramid application, edit the
+``development.ini`` file, and replace the ``host`` value in the
+``[server:main]`` section. Change it from ``0.0.0.0`` to ``127.0.0.1``. For
+example::
+
+ [server:main]
+ use = egg:waitress#main
+ host = 127.0.0.1
+ port = 6543
+
+You can change the port on which the server runs on by changing the same
+portion of the ``development.ini`` file. For example, you can change the
+``port = 6543`` line in the ``development.ini`` file's ``[server:main]``
+section to ``port = 8080`` to run the server on port 8080 instead of
+port 6543.
+
+You can shut down a server started this way by pressing ``Ctrl-C``.
The default server used to run your Pyramid application when a project is
created from a scaffold is named :term:`Waitress`. This server is what
@@ -309,11 +337,6 @@ under the default server, it will almost certainly work under any other
server in production if you eventually choose to use a different one. Don't
worry about it right now.
-You can change the port on which the server runs on by changing the
-``development.ini`` file. For example, you can change the ``port = 6543``
-line in the ``development.ini`` file's ``[server:main]`` section to ``port =
-8080`` to run the server on port 8080 instead of port 6543.
-
For more detailed information about the startup process, see
:ref:`startup_chapter`. For more information about environment variables and
configuration file settings that influence startup and runtime behavior, see
diff --git a/docs/narr/renderers.rst b/docs/narr/renderers.rst
index 57b5bc65b..63287e2cd 100644
--- a/docs/narr/renderers.rst
+++ b/docs/narr/renderers.rst
@@ -306,7 +306,9 @@ See :class:`pyramid.renderers.JSON` and
JSONP Renderer
~~~~~~~~~~~~~~
-.. note:: This feature is new in Pyramid 1.1.
+.. note::
+
+ This feature is new in Pyramid 1.1.
:class:`pyramid.renderers.JSONP` is a `JSONP
<http://en.wikipedia.org/wiki/JSONP>`_ renderer factory helper which
diff --git a/docs/narr/subrequest.rst b/docs/narr/subrequest.rst
new file mode 100644
index 000000000..89551ab35
--- /dev/null
+++ b/docs/narr/subrequest.rst
@@ -0,0 +1,271 @@
+.. index::
+ single: subrequest
+
+.. _subrequest_chapter:
+
+Invoking a Subrequest
+=====================
+
+.. warning::
+
+ This feature was added in Pyramid 1.4a1.
+
+:app:`Pyramid` allows you to invoke a subrequest at any point during the
+processing of a request. Invoking a subrequest allows you to obtain a
+:term:`response` object from a view callable within your :app:`Pyramid`
+application while you're executing a different view callable within the same
+application.
+
+Here's an example application which uses a subrequest:
+
+.. code-block:: python
+
+ from wsgiref.simple_server import make_server
+ from pyramid.config import Configurator
+ from pyramid.request import Request
+
+ def view_one(request):
+ subreq = Request.blank('/view_two')
+ response = request.invoke_subrequest(subreq)
+ return response
+
+ def view_two(request):
+ request.response.body = 'This came from view_two'
+ return request.response
+
+ if __name__ == '__main__':
+ config = Configurator()
+ config.add_route('one', '/view_one')
+ config.add_route('two', '/view_two')
+ config.add_view(view_one, route_name='one')
+ config.add_view(view_two, route_name='two')
+ app = config.make_wsgi_app()
+ server = make_server('0.0.0.0', 8080, app)
+ server.serve_forever()
+
+When ``/view_one`` is visted in a browser, the text printed in the browser
+pane will be ``This came from view_two``. The ``view_one`` view used the
+:meth:`pyramid.request.Request.invoke_subrequest` API to obtain a response
+from another view (``view_two``) within the same application when it
+executed. It did so by constructing a new request that had a URL that it
+knew would match the ``view_two`` view registration, and passed that new
+request along to :meth:`pyramid.request.Request.invoke_subrequest`. The
+``view_two`` view callable was invoked, and it returned a response. The
+``view_one`` view callable then simply returned the response it obtained from
+the ``view_two`` view callable.
+
+Note that it doesn't matter if the view callable invoked via a subrequest
+actually returns a *literal* Response object. Any view callable that uses a
+renderer or which returns an object that can be interpreted by a response
+adapter when found and invoked via
+:meth:`pyramid.request.Request.invoke_subrequest` will return a Response
+object:
+
+.. code-block:: python
+
+ from wsgiref.simple_server import make_server
+ from pyramid.config import Configurator
+ from pyramid.request import Request
+
+ def view_one(request):
+ subreq = Request.blank('/view_two')
+ response = request.invoke_subrequest(subreq)
+ return response
+
+ def view_two(request):
+ return 'This came from view_two'
+
+ if __name__ == '__main__':
+ config = Configurator()
+ config.add_route('one', '/view_one')
+ config.add_route('two', '/view_two')
+ config.add_view(view_one, route_name='one')
+ config.add_view(view_two, route_name='two', renderer='string')
+ app = config.make_wsgi_app()
+ server = make_server('0.0.0.0', 8080, app)
+ server.serve_forever()
+
+Even though the ``view_two`` view callable returned a string, it was invoked
+in such a way that the ``string`` renderer associated with the view
+registration that was found turned it into a "real" response object for
+consumption by ``view_one``.
+
+Being able to unconditionally obtain a response object by invoking a view
+callable indirectly is the main advantage to using
+:meth:`pyramid.request.Request.invoke_subrequest` instead of simply importing
+a view callable and executing it directly. Note that there's not much
+advantage to invoking a view using a subrequest if you *can* invoke a view
+callable directly. Subrequests are slower and are less convenient if you
+actually do want just the literal information returned by a function that
+happens to be a view callable.
+
+Note that, by default, if a view callable invoked by a subrequest raises an
+exception, the exception will be raised to the caller of
+:meth:`~pyramid.request.Request.invoke_subrequest` even if you have a
+:term:`exception view` configured:
+
+.. code-block:: python
+
+ from wsgiref.simple_server import make_server
+ from pyramid.config import Configurator
+ from pyramid.request import Request
+
+ def view_one(request):
+ subreq = Request.blank('/view_two')
+ response = request.invoke_subrequest(subreq)
+ return response
+
+ def view_two(request):
+ raise ValueError('foo')
+
+ def excview(request):
+ request.response.body = b'An exception was raised'
+ request.response.status_int = 500
+ return request.response
+
+ if __name__ == '__main__':
+ config = Configurator()
+ config.add_route('one', '/view_one')
+ config.add_route('two', '/view_two')
+ config.add_view(view_one, route_name='one')
+ config.add_view(view_two, route_name='two', renderer='string')
+ config.add_view(excview, context=Exception)
+ app = config.make_wsgi_app()
+ server = make_server('0.0.0.0', 8080, app)
+ server.serve_forever()
+
+When we run the above code and visit ``/view_one`` in a browser, the
+``excview`` :term:`exception view` will *not* be executed. Instead, the call
+to :meth:`~pyramid.request.Request.invoke_subrequest` will cause a
+:exc:`ValueError` exception to be raised and a response will never be
+generated. We can change this behavior; how to do so is described below in
+our discussion of the ``use_tweens`` argument.
+
+The :meth:`pyramid.request.Request.invoke_subrequest` API accepts two
+arguments: a positional argument ``request`` that must be provided, and and
+``use_tweens`` keyword argument that is optional; it defaults to ``False``.
+
+The ``request`` object passed to the API must be an object that implements
+the Pyramid request interface (such as a :class:`pyramid.request.Request`
+instance). If ``use_tweens`` is ``True``, the request will be sent to the
+:term:`tween` in the tween stack closest to the request ingress. If
+``use_tweens`` is ``False``, the request will be sent to the main router
+handler, and no tweens will be invoked.
+
+In the example above, the call to
+:meth:`~pyramid.request.Request.invoke_subrequest` will always raise an
+exception. This is because it's using the default value for ``use_tweens``,
+which is ``False``. You can pass ``use_tweens=True`` instead to ensure that
+it will convert an exception to a Response if an :term:`exception view` is
+configured instead of raising the exception. This because exception views
+are called by the exception view :term:`tween` as described in
+:ref:`exception_views` when any view raises an exception.
+
+We can cause the subrequest to be run through the tween stack by passing
+``use_tweens=True`` to the call to
+:meth:`~pyramid.request.Request.invoke_subrequest`, like this:
+
+.. code-block:: python
+
+ from wsgiref.simple_server import make_server
+ from pyramid.config import Configurator
+ from pyramid.request import Request
+
+ def view_one(request):
+ subreq = Request.blank('/view_two')
+ response = request.invoke_subrequest(subreq, use_tweens=True)
+ return response
+
+ def view_two(request):
+ raise ValueError('foo')
+
+ def excview(request):
+ request.response.body = b'An exception was raised'
+ request.response.status_int = 500
+ return request.response
+
+ if __name__ == '__main__':
+ config = Configurator()
+ config.add_route('one', '/view_one')
+ config.add_route('two', '/view_two')
+ config.add_view(view_one, route_name='one')
+ config.add_view(view_two, route_name='two', renderer='string')
+ config.add_view(excview, context=Exception)
+ app = config.make_wsgi_app()
+ server = make_server('0.0.0.0', 8080, app)
+ server.serve_forever()
+
+In the above case, the call to ``request.invoke_subrequest(subreq)`` will not
+raise an exception. Instead, it will retrieve a "500" response from the
+attempted invocation of ``view_two``, because the tween which invokes an
+exception view to generate a response is run, and therefore ``excview`` is
+executed.
+
+This is one of the major differences between specifying the
+``use_tweens=True`` and ``use_tweens=False`` arguments to
+:meth:`~pyramid.request.Request.invoke_subrequest`. ``use_tweens=True`` may
+also imply invoking transaction commit/abort for the logic executed in the
+subrequest if you've got ``pyramid_tm`` in the tween list, injecting debug
+HTML if you've got ``pyramid_debugtoolbar`` in the tween list, and other
+tween-related side effects as defined by your particular tween list.
+
+The :meth:`~pyramid.request.Request.invoke_subrequest` function also
+unconditionally:
+
+- manages the threadlocal stack so that
+ :func:`~pyramid.threadlocal.get_current_request` and
+ :func:`~pyramid.threadlocal.get_current_registry` work during a request
+ (they will return the subrequest instead of the original request)
+
+- Adds a ``registry`` attribute and a ``invoke_subrequest`` attribute (a
+ callable) to the request object it's handed.
+
+- sets request extensions (such as those added via
+ :meth:`~pyramid.config.Configurator.add_request_method` or
+ :meth:`~pyramid.config.Configurator.set_request_property`) on the subrequest
+ object passed as ``request``
+
+- causes a :class:`~pyramid.event.NewRequest` event to be sent at the
+ beginning of request processing.
+
+- causes a :class:`~pyramid.event.ContextFound` event to be sent when a
+ context resource is found.
+
+- Ensures that the user implied by the request passed has the necessary
+ authorization to invoke view callable before calling it.
+
+- causes a :class:`~pyramid.event.NewResponse` event to be sent when the
+ Pyramid application returns a response.
+
+- Calls any :term:`response callback` functions defined within the subrequest's
+ lifetime if a response is obtained from the Pyramid application.
+
+- Calls any :term:`finished callback` functions defined within the subrequest's
+ lifetime.
+
+The invocation of a subrequest has more or less exactly the same effect as
+the invocation of a request received by the Pyramid router from a web client
+when ``use_tweens=True``. When ``use_tweens=False``, the tweens are skipped
+but all the other steps take place.
+
+It's a poor idea to use the original ``request`` object as an argument to
+:meth:`~pyramid.request.Request.invoke_subrequest`. You should construct a
+new request instead as demonstrated in the above example, using
+:meth:`pyramid.request.Request.blank`. Once you've constructed a request
+object, you'll need to massage the it to match the view callable you'd like
+to be executed during the subrequest. This can be done by adjusting the
+subrequest's URL, its headers, its request method, and other attributes. The
+documentation for :class:`pyramid.request.Request` exposes the methods you
+should call and attributes you should set on the request you create to
+massage it into something that will actually match the view you'd like to
+call via a subrequest.
+
+We've demonstrated use of a subrequest from within a view callable, but you
+can use the :meth:`~pyramid.request.Request.invoke_subrequest` API from
+within a tween or an event handler as well. It's usually a poor idea to
+invoke :meth:`~pyramid.request.Request.invoke_subrequest` from within a
+tween, because tweens already by definition have access to a function that
+will cause a subrequest (they are passed a ``handle`` function), but you can
+do it. It's fine to invoke
+:meth:`~pyramid.request.Request.invoke_subrequest` from within an event
+handler, however.
diff --git a/docs/narr/templates.rst b/docs/narr/templates.rst
index 860010a1a..ba72ebfbf 100644
--- a/docs/narr/templates.rst
+++ b/docs/narr/templates.rst
@@ -46,20 +46,6 @@ within the body of a view callable like so:
{'foo':1, 'bar':2},
request=request)
-.. warning::
-
- Earlier iterations of this documentation
- (pre-version-1.3) encouraged the application developer to use
- ZPT-specific APIs such as
- :func:`pyramid.chameleon_zpt.render_template_to_response` and
- :func:`pyramid.chameleon_zpt.render_template` to render templates
- directly. This style of rendering still works, but at least for
- purposes of this documentation, those functions are deprecated.
- Application developers are encouraged instead to use the functions
- available in the :mod:`pyramid.renderers` module to perform
- rendering tasks. This set of functions works to render templates
- for all renderer extensions registered with :app:`Pyramid`.
-
The ``sample_view`` :term:`view callable` function above returns a
:term:`response` object which contains the body of the
``templates/foo.pt`` template. In this case, the ``templates``
@@ -79,12 +65,12 @@ prefix on Windows.
.. warning::
Only :term:`Chameleon` templates support defining a renderer for a
- template relative to the location of the module where the view
- callable is defined. Mako templates, and other templating system
- bindings work differently. In particular, Mako templates use a
- "lookup path" as defined by the ``mako.directories`` configuration
- file instead of treating relative paths as relative to the current
- view module. See :ref:`mako_templates`.
+ template relative to the location of the module where the view callable is
+ defined. Mako templates, and other templating system bindings work
+ differently. In particular, Mako templates use a "lookup path" as defined
+ by the ``mako.directories`` configuration file instead of treating
+ relative paths as relative to the current view module. See
+ :ref:`mako_templates`.
The path can alternately be a :term:`asset specification` in the form
``some.dotted.package_name:relative/path``. This makes it possible to
@@ -534,6 +520,33 @@ And ``templates/mytemplate.pt`` might look like so:
</span>
</html>
+
+Using A Chameleon Macro Name Within a Renderer Name
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Sommetime you'd like to render a macro inside of a Chameleon ZPT template
+instead of the full Chameleon ZPT template. To render the content of a
+``define-macro`` field inside a Chameleon ZPT template, given a Chameleon
+template file named ``foo.pt`` and a macro named ``bar`` defined within it
+(e.g. ``<div metal:define-macro="bar">...</div>``), you can configure the
+template as a :term:`renderer` like so:
+
+.. code-block:: python
+ :linenos:
+
+ from pyramid.view import view_config
+
+ @view_config(renderer='foo#bar.pt')
+ def my_view(request):
+ return {'project':'my project'}
+
+The above will render only the ``bar`` macro defined within the ``foo.pt``
+template instead of the entire template.
+
+.. note::
+
+ This feature is new in Pyramid 1.4.
+
.. index::
single: Chameleon text templates
@@ -573,10 +586,6 @@ When the template is rendered, it will show:
Hello, world!
-If you'd rather use templates directly within a view callable (without
-the indirection of using a renderer), see :ref:`chameleon_text_module`
-for the API description.
-
See also :ref:`built_in_renderers` for more general information about
renderers, including Chameleon text renderers.
@@ -714,12 +723,13 @@ This template doesn't use any advanced features of Mako, only the
:term:`renderer globals`. See the `the Mako documentation
<http://www.makotemplates.org/>`_ to use more advanced features.
-Using def inside Mako Templates
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+Using A Mako def name Within a Renderer Name
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-To use a def inside a Mako template, given a :term:`Mako` template file named
-``foo.mak`` and a def named ``bar``, you can configure the template as a
-:term:`renderer` like so:
+Sommetime you'd like to render a ``def`` inside of a Mako template instead of
+the full Mako template. To render a def inside a Mako template, given a
+:term:`Mako` template file named ``foo.mak`` and a def named ``bar``, you can
+configure the template as a :term:`renderer` like so:
.. code-block:: python
:linenos:
@@ -730,6 +740,13 @@ To use a def inside a Mako template, given a :term:`Mako` template file named
def my_view(request):
return {'project':'my project'}
+The above will render the ``bar`` def from within the ``foo.mak`` template
+instead of the entire template.
+
+.. note::
+
+ This feature is new in Pyramid 1.4.
+
.. index::
single: automatic reloading of templates
single: template automatic reload
diff --git a/docs/narr/testing.rst b/docs/narr/testing.rst
index 5ce2c8a66..20017064b 100644
--- a/docs/narr/testing.rst
+++ b/docs/narr/testing.rst
@@ -52,7 +52,7 @@ The suggested mechanism for unit and integration testing of a :app:`Pyramid`
application is the Python :mod:`unittest` module. Although this module is
named :mod:`unittest`, it is actually capable of driving both unit and
integration tests. A good :mod:`unittest` tutorial is available within `Dive
-Into Python <http://diveintopython.nfshost.com/unit_testing/index.html>`_ by Mark
+Into Python <http://www.diveintopython.net/unit_testing/index.html>`_ by Mark
Pilgrim.
:app:`Pyramid` provides a number of facilities that make unit, integration,
@@ -157,6 +157,30 @@ 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.
+Test setup using a context manager
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+An alternative style of setting up a test configuration is to use the
+`with` statement and :func:`pyramid.testing.testConfig` to create a
+context manager. The context manager will call
+:func:`pyramid.testing.setUp` before the code under test and
+:func:`pyramid.testing.tearDown` afterwards.
+
+This style is useful for small self-contained tests. For example:
+
+.. code-block:: python
+ :linenos:
+
+ import unittest
+
+ class MyTest(unittest.TestCase):
+
+ def test_my_function(self):
+ from pyramid import testing
+ with testing.testConfig() as config:
+ config.add_route('bar', '/bar/{id}')
+ my_function_which_needs_route_bar()
+
What?
~~~~~
diff --git a/docs/narr/upgrading.rst b/docs/narr/upgrading.rst
new file mode 100644
index 000000000..839f59c35
--- /dev/null
+++ b/docs/narr/upgrading.rst
@@ -0,0 +1,234 @@
+.. _upgrading_chapter:
+
+Upgrading Pyramid
+=================
+
+When a new version of Pyramid is released, it will sometimes deprecate a
+feature or remove a feature that was deprecated in an older release. When
+features are removed from Pyramid, applications that depend on those features
+will begin to break. This chapter explains how to ensure your Pyramid
+applications keep working when you upgrade the Pyramid version you're using.
+
+.. sidebar:: About Release Numbering
+
+ Conventionally, application version numbering in Python is described as
+ ``major.minor.micro``. If your Pyramid version is "1.2.3", it means
+ you're running a version of Pyramid with the major version "1", the minor
+ version "2" and the micro version "3". A "major" release is one that
+ increments the first-dot number; 2.X.X might follow 1.X.X. A "minor"
+ release is one that increments the second-dot number; 1.3.X might follow
+ 1.2.X. A "micro" release is one that increments the third-dot number;
+ 1.2.3 might follow 1.2.2. In general, micro releases are "bugfix-only",
+ and contain no new features, minor releases contain new features but are
+ largely backwards compatible with older versions, and a major release
+ indicates a large set of backwards incompatibilities.
+
+The Pyramid core team is conservative when it comes to removing features. We
+don't remove features unnecessarily, but we're human, and we make mistakes
+which cause some features to be evolutionary dead ends. Though we are
+willing to support dead-end features for some amount of time, some eventually
+have to be removed when the cost of supporting them outweighs the benefit of
+keeping them around, because each feature in Pyramid represents a certain
+documentation and maintenance burden.
+
+Deprecation and Removal Policy
+------------------------------
+
+When a feature is scheduled for removal from Pyramid or any of its official
+add-ons, the core development team takes these steps:
+
+- Using the feature will begin to generate a `DeprecationWarning`, indicating
+ the version in which the feature became deprecated.
+
+- A note is added to the documentation indicating that the feature is
+ deprecated.
+
+- A note is added to the :ref:`changelog` about the deprecation.
+
+When a deprecated feature is eventually removed:
+
+- The feature is removed.
+
+- A note is added to the :ref:`changelog` about the removal.
+
+Features are never removed in *micro* releases. They are only removed in
+minor and major releases. Deprecated features are kept around for at least
+*three* minor releases from the time the feature became deprecated.
+Therefore, if a feature is added in Pyramid 1.0, but it's deprecated in
+Pyramid 1.1, it will be kept around through all 1.1.X releases, all 1.2.X
+releases and all 1.3.X releases. It will finally be removed in the first
+1.4.X release.
+
+Sometimes features are "docs-deprecated" instead of formally deprecated.
+This means that the feature will be kept around indefinitely, but it will be
+removed from the documentation or a note will be added to the documentation
+telling folks to use some other newer feature. This happens when the cost of
+keeping an old feature around is very minimal and the support and
+documentation burden is very low. For example, we might rename a function
+that is an API without changing the arguments it accepts. In this case,
+we'll often rename the function, and change the docs to point at the new
+function name, but leave around a backwards compatibility alias to the old
+function name so older code doesn't break.
+
+"Docs deprecated" features tend to work "forever", meaning that they won't be
+removed, and they'll never generate a deprecation warning. However, such
+changes are noted in the :ref:`changelog`, so it's possible to know that you
+should change older spellings to newer ones to ensure that people reading
+your code can find the APIs you're using in the Pyramid docs.
+
+Consulting the Change History
+-----------------------------
+
+Your first line of defense against application failures caused by upgrading
+to a newer Pyramid release is always to read the :ref:`changelog`. to find
+the deprecations and removals for each release between the release you're
+currently running and the one you wish to upgrade to. The change history
+notes every deprecation within a ``Deprecation`` section and every removal
+within a ``Backwards Incompatibilies`` section for each release.
+
+The change history often contains instructions for changing your code to
+avoid deprecation warnings and how to change docs-deprecated spellings to
+newer ones. You can follow along with each deprecation explanation in the
+change history, simply doing a grep or other code search to your application,
+using the change log examples to remediate each potential problem.
+
+.. _testing_under_new_release:
+
+Testing Your Application Under a New Pyramid Release
+----------------------------------------------------
+
+Once you've upgraded your application to a new Pyramid release and you've
+remediated as much as possible by using the change history notes, you'll want
+to run your application's tests (see :ref:`running_tests`) in such a way that
+you can see DeprecationWarnings printed to the console when the tests run.
+
+.. code-block:: bash
+
+ $ python -Wd setup.py test -q
+
+The ``-Wd`` argument is an argument that tells Python to print deprecation
+warnings to the console. Note that the ``-Wd`` flag is only required for
+Python 2.7 and better: Python versions 2.6 and older print deprecation
+warnings to the console by default. See `the Python -W flag documentation
+<http://docs.python.org/using/cmdline.html#cmdoption-W>`_ for more
+information.
+
+As your tests run, deprecation warnings will be printed to the console
+explaining the deprecation and providing instructions about how to prevent
+the deprecation warning from being issued. For example:
+
+.. code-block:: text
+
+ $ python -Wd setup.py test -q
+ # .. elided ...
+ running build_ext
+ /home/chrism/projects/pyramid/env27/myproj/myproj/views.py:3:
+ DeprecationWarning: static: The "pyramid.view.static" class is deprecated
+ as of Pyramid 1.1; use the "pyramid.static.static_view" class instead with
+ the "use_subpath" argument set to True.
+ from pyramid.view import static
+ .
+ ----------------------------------------------------------------------
+ Ran 1 test in 0.014s
+
+ OK
+
+In the above case, it's line #3 in the ``myproj.views`` module (``from
+pyramid.view import static``) that is causing the problem:
+
+.. code-block:: python
+ :linenos:
+
+ from pyramid.view import view_config
+
+ from pyramid.view import static
+ myview = static('static', 'static')
+
+The deprecation warning tells me how to fix it, so I can change the code to
+do things the newer way:
+
+.. code-block:: python
+ :linenos:
+
+ from pyramid.view. import view_config
+
+ from pyramid.static import static_view
+ myview = static_view('static', 'static', use_subpath=True)
+
+When I run the tests again, the deprecation warning is no longer printed to
+my console:
+
+.. code-block:: text
+
+ $ python -Wd setup.py test -q
+ # .. elided ...
+ running build_ext
+ .
+ ----------------------------------------------------------------------
+ Ran 1 test in 0.014s
+
+ OK
+
+
+My Application Doesn't Have Any Tests or Has Few Tests
+------------------------------------------------------
+
+If your application has no tests, or has only moderate test coverage, running
+tests won't tell you very much, because the Pyramid codepaths that generate
+deprecation warnings won't be executed.
+
+In this circumstance, you can start your application interactively under a
+server run with the ``PYTHONWARNINGS`` environment variable set to
+``default``. On UNIX, you can do that via:
+
+.. code-block:: bash
+
+ $ PYTHONWARNINGS=default bin/pserve development.ini
+
+On Windows, you need to issue two commands:
+
+.. code-block:: bash
+
+ C:\> set PYTHONWARNINGS=default
+ C:\> Scripts/pserve.exe development.ini
+
+At this point, it's ensured that deprecation warnings will be printed to the
+console whenever a codepath is hit that generates one. You can then click
+around in your application interactively to try to generate them, and
+remediate as explained in :ref:`testing_under_new_release`.
+
+See `the PYTHONWARNINGS environment variable documentation
+<http://docs.python.org/using/cmdline.html#envvar-PYTHONWARNINGS>`_ or `the
+Python -W flag documentation
+<http://docs.python.org/using/cmdline.html#cmdoption-W>`_ for more
+information.
+
+Upgrading to the Very Latest Pyramid Release
+--------------------------------------------
+
+When you upgrade your application to the very most recent Pyramid release,
+it's advisable to upgrade step-wise through each most recent minor release,
+beginning with the one that you know your application currently runs under,
+and ending on the most recent release. For example, if your application is
+running in production on Pyramid 1.2.1, and the most recent Pyramid 1.3
+release is Pyramid 1.3.3, and the most recent Pyramid release is 1.4.4, it's
+advisable to do this:
+
+- Upgrade your environment to the most recent 1.2 release. For example, the
+ most recent 1.2 release might be 1.2.3, so upgrade to it. Then run your
+ application's tests under 1.2.3 as described in
+ :ref:`testing_under_new_release`. Note any deprecation warnings and
+ remediate.
+
+- Upgrade to the most recent 1.3 release, 1.3.3. Run your application's
+ tests, note any deprecation warnings and remediate.
+
+- Upgrade to 1.4.4. Run your application's tests, note any deprecation
+ warnings and remediate.
+
+If you skip testing your application under each minor release (for example if
+you upgrade directly from 1.2.1 to 1.4.4), you might miss a deprecation
+warning and waste more time trying to figure out an error caused by a feature
+removal than it would take to upgrade stepwise through each minor release.
+
+
diff --git a/docs/narr/views.rst b/docs/narr/views.rst
index f6ee9a8d5..07d018127 100644
--- a/docs/narr/views.rst
+++ b/docs/narr/views.rst
@@ -177,7 +177,7 @@ HTTP Exceptions
~~~~~~~~~~~~~~~
All classes documented in the :mod:`pyramid.httpexceptions` module documented
-as inheriting from the :class:`pryamid.httpexceptions.HTTPException` are
+as inheriting from the :class:`pyramid.httpexceptions.HTTPException` are
:term:`http exception` objects. Instances of an HTTP exception object may
either be *returned* or *raised* from within view code. In either case
(return or raise) the instance will be used as as the view's response.
@@ -338,6 +338,16 @@ exception views which have a name will be ignored.
Exception views can be configured with any view registration mechanism:
``@view_config`` decorator or imperative ``add_view`` styles.
+.. note::
+
+ Pyramid's :term:`exception view` handling logic is implemented as a tween
+ factory function: :func:`pyramid.tweens.excview_tween_factory`. If
+ Pyramid exception view handling is desired, and tween factories are
+ specified via the ``pyramid.tweens`` configuration setting, the
+ :func:`pyramid.tweens.excview_tween_factory` function must be added to the
+ ``pyramid.tweens`` configuration setting list explicitly. If it is not
+ present, Pyramid will not perform exception view handling.
+
.. index::
single: view http redirect
single: http redirect (from a view)