summaryrefslogtreecommitdiff
path: root/docs
diff options
context:
space:
mode:
Diffstat (limited to 'docs')
-rw-r--r--docs/Makefile8
-rw-r--r--docs/api.rst3
-rw-r--r--docs/api/chameleon_text.rst31
-rw-r--r--docs/api/chameleon_zpt.rst28
-rw-r--r--docs/api/config.rst6
-rw-r--r--docs/api/decorator.rst9
-rw-r--r--docs/api/registry.rst14
-rw-r--r--docs/api/request.rst56
-rw-r--r--docs/api/settings.rst2
-rw-r--r--docs/api/testing.rst2
-rw-r--r--docs/changes.rst2
-rw-r--r--docs/designdefense.rst14
-rw-r--r--docs/glossary.rst27
-rw-r--r--docs/index.rst15
-rw-r--r--docs/latexindex.rst3
-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
-rw-r--r--docs/tutorials/modwsgi/index.rst31
-rw-r--r--docs/tutorials/wiki/definingviews.rst2
-rw-r--r--docs/tutorials/wiki/src/authorization/tutorial/views.py10
-rw-r--r--docs/tutorials/wiki/src/tests/tutorial/views.py10
-rw-r--r--docs/tutorials/wiki/src/views/tutorial/views.py10
-rw-r--r--docs/tutorials/wiki2/authorization.rst2
-rw-r--r--docs/tutorials/wiki2/basiclayout.rst4
-rw-r--r--docs/tutorials/wiki2/definingviews.rst2
-rw-r--r--docs/tutorials/wiki2/design.rst5
-rw-r--r--docs/tutorials/wiki2/src/authorization/tutorial/views.py16
-rw-r--r--docs/tutorials/wiki2/src/tests/tutorial/views.py16
-rw-r--r--docs/tutorials/wiki2/src/views/tutorial/views.py16
-rw-r--r--docs/whatsnew-1.4.rst267
42 files changed, 1456 insertions, 275 deletions
diff --git a/docs/Makefile b/docs/Makefile
index e4a325022..c98fdc65e 100644
--- a/docs/Makefile
+++ b/docs/Makefile
@@ -25,7 +25,7 @@ help:
clean:
-rm -rf _build/*
-html: _themes
+html: themes
mkdir -p _build/html _build/doctrees
$(SPHINXBUILD) -b html $(ALLSPHINXOPTS) _build/html
@echo
@@ -47,7 +47,7 @@ pickle:
web: pickle
-htmlhelp: _themes
+htmlhelp: themes
mkdir -p _build/htmlhelp _build/doctrees
$(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) _build/htmlhelp
@echo
@@ -84,5 +84,5 @@ epub:
@echo
@echo "Build finished. The epub file is in _build/epub."
-_themes:
- git submodule update --init
+themes:
+ cd ..; git submodule update --init --recursive; cd docs;
diff --git a/docs/api.rst b/docs/api.rst
index d510c0d27..9e540b49b 100644
--- a/docs/api.rst
+++ b/docs/api.rst
@@ -10,10 +10,9 @@ documentation is organized alphabetically by module name.
api/authorization
api/authentication
- api/chameleon_text
- api/chameleon_zpt
api/compat
api/config
+ api/decorator
api/events
api/exceptions
api/httpexceptions
diff --git a/docs/api/chameleon_text.rst b/docs/api/chameleon_text.rst
deleted file mode 100644
index 494f5b464..000000000
--- a/docs/api/chameleon_text.rst
+++ /dev/null
@@ -1,31 +0,0 @@
-.. _chameleon_text_module:
-
-:mod:`pyramid.chameleon_text`
-----------------------------------
-
-.. automodule:: pyramid.chameleon_text
-
- .. autofunction:: get_template
-
- .. autofunction:: render_template
-
- .. autofunction:: render_template_to_response
-
-These APIs will will work against template files which contain simple
-``${Genshi}`` - style replacement markers.
-
-The API of :mod:`pyramid.chameleon_text` is identical to that of
-:mod:`pyramid.chameleon_zpt`; only its import location is
-different. If you need to import an API functions from this module as
-well as the :mod:`pyramid.chameleon_zpt` module within the same
-view file, use the ``as`` feature of the Python import statement,
-e.g.:
-
-.. code-block:: python
- :linenos:
-
- from pyramid.chameleon_zpt import render_template as zpt_render
- from pyramid.chameleon_text import render_template as text_render
-
-
-
diff --git a/docs/api/chameleon_zpt.rst b/docs/api/chameleon_zpt.rst
deleted file mode 100644
index df9a36a56..000000000
--- a/docs/api/chameleon_zpt.rst
+++ /dev/null
@@ -1,28 +0,0 @@
-.. _chameleon_zpt_module:
-
-:mod:`pyramid.chameleon_zpt`
--------------------------------
-
-.. automodule:: pyramid.chameleon_zpt
-
- .. autofunction:: get_template
-
- .. autofunction:: render_template
-
- .. autofunction:: render_template_to_response
-
-These APIs will work against files which supply template text which
-matches the :term:`ZPT` specification.
-
-The API of :mod:`pyramid.chameleon_zpt` is identical to that of
-:mod:`pyramid.chameleon_text`; only its import location is
-different. If you need to import an API functions from this module as
-well as the :mod:`pyramid.chameleon_text` module within the same
-view file, use the ``as`` feature of the Python import statement,
-e.g.:
-
-.. code-block:: python
- :linenos:
-
- from pyramid.chameleon_zpt import render_template as zpt_render
- from pyramid.chameleon_text import render_template as text_render
diff --git a/docs/api/config.rst b/docs/api/config.rst
index cd58e74d3..5d2bce23e 100644
--- a/docs/api/config.rst
+++ b/docs/api/config.rst
@@ -36,9 +36,11 @@
.. automethod:: set_authentication_policy
.. automethod:: set_authorization_policy
.. automethod:: set_default_permission
+ .. automethod:: add_permission
- :methodcategory:`Setting Request Properties`
+ :methodcategory:`Extending the Request Object`
+ .. automethod:: add_request_method
.. automethod:: set_request_property
:methodcategory:`Using I18N`
@@ -66,6 +68,8 @@
.. automethod:: add_response_adapter
.. automethod:: add_traverser
.. automethod:: add_tween
+ .. automethod:: add_route_predicate
+ .. automethod:: add_view_predicate
.. automethod:: set_request_factory
.. automethod:: set_root_factory
.. automethod:: set_session_factory
diff --git a/docs/api/decorator.rst b/docs/api/decorator.rst
new file mode 100644
index 000000000..35d9131df
--- /dev/null
+++ b/docs/api/decorator.rst
@@ -0,0 +1,9 @@
+.. _decorator_module:
+
+:mod:`pyramid.decorator`
+--------------------------
+
+.. automodule:: pyramid.decorator
+
+.. autofunction:: reify
+
diff --git a/docs/api/registry.rst b/docs/api/registry.rst
index e62e2ba6f..1d5d52248 100644
--- a/docs/api/registry.rst
+++ b/docs/api/registry.rst
@@ -38,3 +38,17 @@
This class is new as of :app:`Pyramid` 1.3.
+.. autoclass:: Deferred
+
+ This class is new as of :app:`Pyramid` 1.4.
+
+.. autofunction:: undefer
+
+ This function is new as of :app:`Pyramid` 1.4.
+
+.. autoclass:: predvalseq
+
+ This class is new as of :app:`Pyramid` 1.4.
+
+
+
diff --git a/docs/api/request.rst b/docs/api/request.rst
index 1112ea069..3a1439874 100644
--- a/docs/api/request.rst
+++ b/docs/api/request.rst
@@ -161,6 +161,62 @@
request, the value of this attribute will be ``None``. See
:ref:`matched_route`.
+ .. method:: invoke_subrequest(request, use_tweens=False)
+
+ .. warning::
+
+ This API was added in Pyramid 1.4a1.
+
+ Obtain a response object from the Pyramid application based on
+ information in the ``request`` object provided. The ``request`` object
+ 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.
+
+ This function also:
+
+ - manages the threadlocal stack (so that
+ :func:`~pyramid.threadlocal.get_current_request` and
+ :func:`~pyramid.threadlocal.get_current_registry` work during a
+ request)
+
+ - Adds a ``registry`` attribute (the current Pyramid registry) 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
+ request it's passed.
+
+ - 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
+ request's lifetime if a response is obtained from the Pyramid
+ application.
+
+ - Calls any :term:`finished callback` functions defined within the
+ request's lifetime.
+
+ ``invoke_subrequest`` isn't *actually* a method of the Request object;
+ it's a callable added when the Pyramid router is invoked, or when a
+ subrequest is invoked. This means that it's not available for use on a
+ request provided by e.g. the ``pshell`` environment. For more
+ information, see :ref:`subrequest_chapter`.
+
.. automethod:: add_response_callback
.. automethod:: add_finished_callback
diff --git a/docs/api/settings.rst b/docs/api/settings.rst
index 6b12c038c..cd802e138 100644
--- a/docs/api/settings.rst
+++ b/docs/api/settings.rst
@@ -5,8 +5,6 @@
.. automodule:: pyramid.settings
- .. autofunction:: get_settings
-
.. autofunction:: asbool
.. autofunction:: aslist
diff --git a/docs/api/testing.rst b/docs/api/testing.rst
index f388dc263..1366a1795 100644
--- a/docs/api/testing.rst
+++ b/docs/api/testing.rst
@@ -9,6 +9,8 @@
.. autofunction:: tearDown
+ .. autofunction:: testConfig(registry=None, request=None, hook_zca=True, autocommit=True, settings=None)
+
.. autofunction:: cleanUp
.. autoclass:: DummyResource
diff --git a/docs/changes.rst b/docs/changes.rst
index 6294123ed..fdeaf1e99 100644
--- a/docs/changes.rst
+++ b/docs/changes.rst
@@ -1,3 +1,5 @@
+.. _changelog:
+
:app:`Pyramid` Change History
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
diff --git a/docs/designdefense.rst b/docs/designdefense.rst
index d896022e6..b468ddac6 100644
--- a/docs/designdefense.rst
+++ b/docs/designdefense.rst
@@ -390,20 +390,6 @@ completely optional. No ZCML is required at all to use :app:`Pyramid`, nor
any other sort of frameworky declarative frontend to application
configuration.
-.. _model_traversal_confusion:
-
-Pyramid Uses "Model" To Represent A Node In The Graph of Objects Traversed
---------------------------------------------------------------------------
-
-The ``repoze.bfg`` documentation used to refer to the graph being traversed
-when :term:`traversal` is used as a "model graph". A terminology overlap
-confused people who wrote applications that always use ORM packages such as
-SQLAlchemy, which has a different notion of the definition of a "model". As
-a result, in Pyramid 1.0a7, the tree of objects traversed is now renamed to
-:term:`resource tree` and its components are now named :term:`resource`
-objects. Associated APIs have been changed. This hopefully alleviates the
-terminology confusion caused by overriding the term "model".
-
Pyramid Does Traversal, And I Don't Like Traversal
--------------------------------------------------
diff --git a/docs/glossary.rst b/docs/glossary.rst
index 45a79326f..2b006da20 100644
--- a/docs/glossary.rst
+++ b/docs/glossary.rst
@@ -41,14 +41,20 @@ Glossary
setuptools
`Setuptools <http://peak.telecommunity.com/DevCenter/setuptools>`_
builds on Python's ``distutils`` to provide easier building,
- distribution, and installation of libraries and applications.
+ distribution, and installation of libraries and applications. As of
+ this writing, setuptools runs under Python 2, but not under Python 3.
+ You can use :term:`distribute` under Python 3 instead.
+
+ distribute
+ `Distribute <http://packages.python.org/distribute/>`_ is a fork of
+ :term:`setuptools` which runs on both Python 2 and Python 3.
pkg_resources
- A module which ships with :term:`setuptools` that provides an API for
- addressing "asset files" within a Python :term:`package`. Asset files
- are static files, template files, etc; basically anything
- non-Python-source that lives in a Python package can be considered a
- asset file. See also `PkgResources
+ A module which ships with :term:`setuptools` and :term:`distribute` that
+ provides an API for addressing "asset files" within a Python
+ :term:`package`. Asset files are static files, template files, etc;
+ basically anything non-Python-source that lives in a Python package can
+ be considered a asset file. See also `PkgResources
<http://peak.telecommunity.com/DevCenter/PkgResources>`_
asset
@@ -84,7 +90,7 @@ Glossary
(Setuptools/distutils terminology). A file representing an
installable library or application. Distributions are usually
files that have the suffix of ``.egg``, ``.tar.gz``, or ``.zip``.
- Distributions are the target of Setuptools commands such as
+ Distributions are the target of Setuptools-related commands such as
``easy_install``.
entry point
@@ -994,3 +1000,10 @@ Glossary
Aka ``gunicorn``, a fast :term:`WSGI` server that runs on UNIX under
Python 2.5+ (although at the time of this writing does not support
Python 3). See http://gunicorn.org/ for detailed information.
+
+ predicate factory
+ A callable which is used by a third party during the registration of a
+ route, view, or subscriber predicates to extend the configuration
+ system. See :ref:`registering_thirdparty_predicates` for more
+ information.
+
diff --git a/docs/index.rst b/docs/index.rst
index 31c2fde6b..faf8258c1 100644
--- a/docs/index.rst
+++ b/docs/index.rst
@@ -13,15 +13,9 @@ Here is one of the simplest :app:`Pyramid` applications you can make:
.. literalinclude:: narr/helloworld.py
-When saved to ``helloworld.py``, the above application can be run via:
-
-.. code-block:: text
-
- $ easy_install pyramid
- $ python helloworld.py
-
-When you visit ``http://localhost:8080/hello/world`` in a browser, you will
-see the text ``Hello, world!``.
+After you install :app:`Pyramid` and run this application, when you visit
+``http://localhost:8080/hello/world`` in a browser, you will see the text
+``Hello, world!``
See :ref:`firstapp_chapter` for a full explanation of how this application
works. Read the :ref:`html_narrative_documentation` to understand how
@@ -43,6 +37,7 @@ What's New
.. toctree::
:maxdepth: 1
+ whatsnew-1.4
whatsnew-1.3
whatsnew-1.2
whatsnew-1.1
@@ -88,12 +83,14 @@ Narrative documentation in chapter form explaining how to use
narr/traversal
narr/security
narr/hybrid
+ narr/subrequest
narr/hooks
narr/introspector
narr/extending
narr/advconfig
narr/extconfig
narr/scaffolding
+ narr/upgrading
narr/threadlocals
narr/zca
diff --git a/docs/latexindex.rst b/docs/latexindex.rst
index 99ec2f54d..6bb875f73 100644
--- a/docs/latexindex.rst
+++ b/docs/latexindex.rst
@@ -54,6 +54,7 @@ Narrative Documentation
narr/traversal
narr/security
narr/hybrid
+ narr/subrequest
narr/hooks
narr/introspector
narr/extending
@@ -85,8 +86,6 @@ API Reference
api/authorization
api/authentication
- api/chameleon_text
- api/chameleon_zpt
api/config
api/events
api/exceptions
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)
diff --git a/docs/tutorials/modwsgi/index.rst b/docs/tutorials/modwsgi/index.rst
index e070f8eda..a22f12610 100644
--- a/docs/tutorials/modwsgi/index.rst
+++ b/docs/tutorials/modwsgi/index.rst
@@ -7,12 +7,11 @@ Running a :app:`Pyramid` Application under ``mod_wsgi``
It allows :term:`WSGI` programs to be served using the Apache web
server.
-This guide will outline broad steps that can be used to get a
-:app:`Pyramid` application running under Apache via ``mod_wsgi``.
-This particular tutorial was developed under Apple's Mac OS X platform
-(Snow Leopard, on a 32-bit Mac), but the instructions should be
-largely the same for all systems, delta specific path information for
-commands and files.
+This guide will outline broad steps that can be used to get a :app:`Pyramid`
+application running under Apache via ``mod_wsgi``. This particular tutorial
+was developed under Apple's Mac OS X platform (Snow Leopard, on a 32-bit
+Mac), but the instructions should be largely the same for all systems, delta
+specific path information for commands and files.
.. note:: Unfortunately these instructions almost certainly won't work for
deploying a :app:`Pyramid` application on a Windows system using
@@ -73,9 +72,10 @@ commands and files.
.. code-block:: python
- from pyramid.paster import get_app
- application = get_app(
- '/Users/chrism/modwsgi/env/myapp/production.ini', 'main')
+ from pyramid.paster import get_app, setup_logging
+ ini_path = '/Users/chrism/modwsgi/env/myapp/production.ini'
+ setup_logging(ini_path)
+ application = get_app(ini_path, 'main')
The first argument to ``get_app`` is the project configuration file
name. It's best to use the ``production.ini`` file provided by your
@@ -85,12 +85,15 @@ commands and files.
``application`` is important: mod_wsgi requires finding such an
assignment when it opens the file.
-#. Make the ``pyramid.wsgi`` script executable.
+ The call to ``setup_logging`` initializes the standard library's
+ `logging` module to allow logging within your application.
+ See :ref:`logging_config`.
- .. code-block:: text
-
- $ cd ~/modwsgi/env
- $ chmod 755 pyramid.wsgi
+ There is no need to make the ``pyramid.wsgi`` script executable.
+ However, you'll need to make sure that *two* users have access to change
+ into the ``~/modwsgi/env`` directory: your current user (mine is
+ ``chrism`` and the user that Apache will run as often named ``apache`` or
+ ``httpd``). Make sure both of these users can "cd" into that directory.
#. Edit your Apache configuration and add some stuff. I happened to
create a file named ``/etc/apache2/other/modwsgi.conf`` on my own
diff --git a/docs/tutorials/wiki/definingviews.rst b/docs/tutorials/wiki/definingviews.rst
index 28cecb787..529603546 100644
--- a/docs/tutorials/wiki/definingviews.rst
+++ b/docs/tutorials/wiki/definingviews.rst
@@ -251,7 +251,7 @@ wiki page. It includes:
- A ``div`` element that is replaced with the ``content``
value provided by the view (rows 45-47). ``content``
contains HTML, so the ``structure`` keyword is used
- to prevent escaping it (i.e. changing ">" to &gt;, etc.)
+ to prevent escaping it (i.e. changing ">" to "&gt;", etc.)
- A link that points
at the "edit" URL which invokes the ``edit_page`` view for
the page being viewed (rows 49-51).
diff --git a/docs/tutorials/wiki/src/authorization/tutorial/views.py b/docs/tutorials/wiki/src/authorization/tutorial/views.py
index 21f12b31d..50485d279 100644
--- a/docs/tutorials/wiki/src/authorization/tutorial/views.py
+++ b/docs/tutorials/wiki/src/authorization/tutorial/views.py
@@ -51,17 +51,17 @@ def view_page(context, request):
renderer='templates/edit.pt',
permission='edit')
def add_page(context, request):
- name = request.subpath[0]
+ pagename = request.subpath[0]
if 'form.submitted' in request.params:
body = request.params['body']
page = Page(body)
- page.__name__ = name
+ page.__name__ = pagename
page.__parent__ = context
- context[name] = page
+ context[pagename] = page
return HTTPFound(location = request.resource_url(page))
- save_url = request.resource_url(context, 'add_page', name)
+ save_url = request.resource_url(context, 'add_page', pagename)
page = Page('')
- page.__name__ = name
+ page.__name__ = pagename
page.__parent__ = context
return dict(page = page, save_url = save_url,
diff --git a/docs/tutorials/wiki/src/tests/tutorial/views.py b/docs/tutorials/wiki/src/tests/tutorial/views.py
index 21f12b31d..50485d279 100644
--- a/docs/tutorials/wiki/src/tests/tutorial/views.py
+++ b/docs/tutorials/wiki/src/tests/tutorial/views.py
@@ -51,17 +51,17 @@ def view_page(context, request):
renderer='templates/edit.pt',
permission='edit')
def add_page(context, request):
- name = request.subpath[0]
+ pagename = request.subpath[0]
if 'form.submitted' in request.params:
body = request.params['body']
page = Page(body)
- page.__name__ = name
+ page.__name__ = pagename
page.__parent__ = context
- context[name] = page
+ context[pagename] = page
return HTTPFound(location = request.resource_url(page))
- save_url = request.resource_url(context, 'add_page', name)
+ save_url = request.resource_url(context, 'add_page', pagename)
page = Page('')
- page.__name__ = name
+ page.__name__ = pagename
page.__parent__ = context
return dict(page = page, save_url = save_url,
diff --git a/docs/tutorials/wiki/src/views/tutorial/views.py b/docs/tutorials/wiki/src/views/tutorial/views.py
index 016f5b6bb..b0c15297f 100644
--- a/docs/tutorials/wiki/src/views/tutorial/views.py
+++ b/docs/tutorials/wiki/src/views/tutorial/views.py
@@ -35,17 +35,17 @@ def view_page(context, request):
@view_config(name='add_page', context='.models.Wiki',
renderer='templates/edit.pt')
def add_page(context, request):
- name = request.subpath[0]
+ pagename = request.subpath[0]
if 'form.submitted' in request.params:
body = request.params['body']
page = Page(body)
- page.__name__ = name
+ page.__name__ = pagename
page.__parent__ = context
- context[name] = page
+ context[pagename] = page
return HTTPFound(location = request.resource_url(page))
- save_url = request.resource_url(context, 'add_page', name)
+ save_url = request.resource_url(context, 'add_page', pagename)
page = Page('')
- page.__name__ = name
+ page.__name__ = pagename
page.__parent__ = context
return dict(page = page, save_url = save_url)
diff --git a/docs/tutorials/wiki2/authorization.rst b/docs/tutorials/wiki2/authorization.rst
index 2ef55d15b..d7bd24a53 100644
--- a/docs/tutorials/wiki2/authorization.rst
+++ b/docs/tutorials/wiki2/authorization.rst
@@ -353,7 +353,7 @@ when we're done:
.. literalinclude:: src/authorization/tutorial/views.py
:linenos:
- :emphasize-lines: 11,14-18,31,37,58,61,73,76,88,91-117,119-123
+ :emphasize-lines: 11,14-18,25,31,37,58,61,73,76,88,91-117,119-123
:language: python
(Only the highlighted lines need to be added.)
diff --git a/docs/tutorials/wiki2/basiclayout.rst b/docs/tutorials/wiki2/basiclayout.rst
index 5f4ea671c..b3184c4fc 100644
--- a/docs/tutorials/wiki2/basiclayout.rst
+++ b/docs/tutorials/wiki2/basiclayout.rst
@@ -100,7 +100,7 @@ used when the URL is ``/``:
:language: py
Since this route has a ``pattern`` equalling ``/`` it is the route that will
-be matched when the URL ``/`` is visted, e.g. ``http://localhost:6543/``.
+be matched when the URL ``/`` is visited, e.g. ``http://localhost:6543/``.
``main`` next calls the ``scan`` method of the configurator, which will
recursively scan our ``tutorial`` package, looking for ``@view_config`` (and
@@ -190,7 +190,7 @@ Next we set up a SQLAlchemy "DBSession" object:
``scoped_session`` allows us to access our database connection globally.
``sessionmaker`` creates a database session object. We pass to
``sessionmaker`` the ``extension=ZopeTransactionExtension()`` extension
-option in order to allow the system to automatically manage datbase
+option in order to allow the system to automatically manage database
transactions. With ``ZopeTransactionExtension`` activated, our application
will automatically issue a transaction commit after every request unless an
exception is raised, in which case the transaction will be aborted.
diff --git a/docs/tutorials/wiki2/definingviews.rst b/docs/tutorials/wiki2/definingviews.rst
index efb72230e..24ac4338d 100644
--- a/docs/tutorials/wiki2/definingviews.rst
+++ b/docs/tutorials/wiki2/definingviews.rst
@@ -248,7 +248,7 @@ wiki page. It includes:
- A ``div`` element that is replaced with the ``content``
value provided by the view (rows 45-47). ``content``
contains HTML, so the ``structure`` keyword is used
- to prevent escaping it (i.e. changing ">" to &gt;, etc.)
+ to prevent escaping it (i.e. changing ">" to "&gt;", etc.)
- A link that points
at the "edit" URL which invokes the ``edit_page`` view for
the page being viewed (rows 49-51).
diff --git a/docs/tutorials/wiki2/design.rst b/docs/tutorials/wiki2/design.rst
index 2e6fc0e77..6e41e00aa 100644
--- a/docs/tutorials/wiki2/design.rst
+++ b/docs/tutorials/wiki2/design.rst
@@ -20,7 +20,7 @@ Models
We'll be using a SQLite database to hold our wiki data, and we'll be using
:term:`SQLAlchemy` to access the data in this database.
-Within the database, we define a single table named `tables`, whose elements
+Within the database, we define a single table named `pages`, whose elements
will store the wiki pages. There are two columns: `name` and `data`.
URLs like ``/PageName`` will try to find an element in
@@ -115,7 +115,8 @@ listed in the following table:
| | redirect to | | | |
| | /PageName | | | |
+----------------------+-----------------------+-------------+------------+------------+
-| /login | Display login form. | login | login.pt | |
+| /login | Display login form, | login | login.pt | |
+| | Forbidden [3]_ | | | |
| | | | | |
| | If the form was | | | |
| | submitted, | | | |
diff --git a/docs/tutorials/wiki2/src/authorization/tutorial/views.py b/docs/tutorials/wiki2/src/authorization/tutorial/views.py
index c7670b049..0d085b0e2 100644
--- a/docs/tutorials/wiki2/src/authorization/tutorial/views.py
+++ b/docs/tutorials/wiki2/src/authorization/tutorial/views.py
@@ -60,14 +60,14 @@ def view_page(request):
@view_config(route_name='add_page', renderer='templates/edit.pt',
permission='edit')
def add_page(request):
- name = request.matchdict['pagename']
+ pagename = request.matchdict['pagename']
if 'form.submitted' in request.params:
body = request.params['body']
- page = Page(name, body)
+ page = Page(pagename, body)
DBSession.add(page)
return HTTPFound(location = request.route_url('view_page',
- pagename=name))
- save_url = request.route_url('add_page', pagename=name)
+ pagename=pagename))
+ save_url = request.route_url('add_page', pagename=pagename)
page = Page('', '')
return dict(page=page, save_url=save_url,
logged_in=authenticated_userid(request))
@@ -75,16 +75,16 @@ def add_page(request):
@view_config(route_name='edit_page', renderer='templates/edit.pt',
permission='edit')
def edit_page(request):
- name = request.matchdict['pagename']
- page = DBSession.query(Page).filter_by(name=name).one()
+ pagename = request.matchdict['pagename']
+ page = DBSession.query(Page).filter_by(name=pagename).one()
if 'form.submitted' in request.params:
page.data = request.params['body']
DBSession.add(page)
return HTTPFound(location = request.route_url('view_page',
- pagename=name))
+ pagename=pagename))
return dict(
page=page,
- save_url = request.route_url('edit_page', pagename=name),
+ save_url = request.route_url('edit_page', pagename=pagename),
logged_in=authenticated_userid(request),
)
diff --git a/docs/tutorials/wiki2/src/tests/tutorial/views.py b/docs/tutorials/wiki2/src/tests/tutorial/views.py
index f2a33af1e..42ac0eb7f 100644
--- a/docs/tutorials/wiki2/src/tests/tutorial/views.py
+++ b/docs/tutorials/wiki2/src/tests/tutorial/views.py
@@ -61,15 +61,15 @@ def view_page(request):
@view_config(route_name='add_page', renderer='templates/edit.pt',
permission='edit')
def add_page(request):
- name = request.matchdict['pagename']
+ pagename = request.matchdict['pagename']
if 'form.submitted' in request.params:
session = DBSession()
body = request.params['body']
- page = Page(name, body)
+ page = Page(pagename, body)
session.add(page)
return HTTPFound(location = request.route_url('view_page',
- pagename=name))
- save_url = request.route_url('add_page', pagename=name)
+ pagename=pagename))
+ save_url = request.route_url('add_page', pagename=pagename)
page = Page('', '')
return dict(page=page, save_url=save_url,
logged_in=authenticated_userid(request))
@@ -77,17 +77,17 @@ def add_page(request):
@view_config(route_name='edit_page', renderer='templates/edit.pt',
permission='edit')
def edit_page(request):
- name = request.matchdict['pagename']
+ pagename = request.matchdict['pagename']
session = DBSession()
- page = session.query(Page).filter_by(name=name).one()
+ page = session.query(Page).filter_by(name=pagename).one()
if 'form.submitted' in request.params:
page.data = request.params['body']
session.add(page)
return HTTPFound(location = request.route_url('view_page',
- pagename=name))
+ pagename=pagename))
return dict(
page=page,
- save_url = request.route_url('edit_page', pagename=name),
+ save_url = request.route_url('edit_page', pagename=pagename),
logged_in=authenticated_userid(request),
)
diff --git a/docs/tutorials/wiki2/src/views/tutorial/views.py b/docs/tutorials/wiki2/src/views/tutorial/views.py
index c2a94a96b..5a9c75a61 100644
--- a/docs/tutorials/wiki2/src/views/tutorial/views.py
+++ b/docs/tutorials/wiki2/src/views/tutorial/views.py
@@ -44,27 +44,27 @@ def view_page(request):
@view_config(route_name='add_page', renderer='templates/edit.pt')
def add_page(request):
- name = request.matchdict['pagename']
+ pagename = request.matchdict['pagename']
if 'form.submitted' in request.params:
body = request.params['body']
- page = Page(name, body)
+ page = Page(pagename, body)
DBSession.add(page)
return HTTPFound(location = request.route_url('view_page',
- pagename=name))
- save_url = request.route_url('add_page', pagename=name)
+ pagename=pagename))
+ save_url = request.route_url('add_page', pagename=pagename)
page = Page('', '')
return dict(page=page, save_url=save_url)
@view_config(route_name='edit_page', renderer='templates/edit.pt')
def edit_page(request):
- name = request.matchdict['pagename']
- page = DBSession.query(Page).filter_by(name=name).one()
+ pagename = request.matchdict['pagename']
+ page = DBSession.query(Page).filter_by(name=pagename).one()
if 'form.submitted' in request.params:
page.data = request.params['body']
DBSession.add(page)
return HTTPFound(location = request.route_url('view_page',
- pagename=name))
+ pagename=pagename))
return dict(
page=page,
- save_url = request.route_url('edit_page', pagename=name),
+ save_url = request.route_url('edit_page', pagename=pagename),
)
diff --git a/docs/whatsnew-1.4.rst b/docs/whatsnew-1.4.rst
new file mode 100644
index 000000000..f57178db1
--- /dev/null
+++ b/docs/whatsnew-1.4.rst
@@ -0,0 +1,267 @@
+What's New In Pyramid 1.4
+=========================
+
+This article explains the new features in :app:`Pyramid` version 1.4 as
+compared to its predecessor, :app:`Pyramid` 1.3. It also documents backwards
+incompatibilities between the two versions and deprecations added to
+:app:`Pyramid` 1.4, as well as software dependency changes and notable
+documentation additions.
+
+Major Feature Additions
+-----------------------
+
+The major feature additions in Pyramid 1.4 follow.
+
+Third-Party Predicates
+~~~~~~~~~~~~~~~~~~~~~~~
+
+- Third-party custom view, route, and subscriber predicates can now be added
+ for use by view authors via
+ :meth:`pyramid.config.Configurator.add_view_predicate`,
+ :meth:`pyramid.config.Configurator.add_route_predicate` and
+ :meth:`pyramid.config.Configurator.add_subscriber_predicate`. So, for
+ example, doing this::
+
+ config.add_view_predicate('abc', my.package.ABCPredicate)
+
+ Might allow a view author to do this in an application that configured that
+ predicate::
+
+ @view_config(abc=1)
+
+ Similar features exist for :meth:`pyramid.config.Configurator.add_route`,
+ and :meth:`pyramid.config.Configurator.add_subscriber`. See
+ :ref:`registering_thirdparty_predicates` for more information.
+
+Easy Custom JSON Serialization
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+- Views can now return custom objects which will be serialized to JSON by a
+ JSON renderer by defining a ``__json__`` method on the object's class. This
+ method should return values natively serializable by ``json.dumps`` (such
+ as ints, lists, dictionaries, strings, and so forth). See
+ :ref:`json_serializing_custom_objects` for more information. The JSON
+ renderer now also allows for the definition of custom type adapters to
+ convert unknown objects to JSON serializations, in case you can't add a
+ ``__json__`` method to returned objects.
+
+Partial Mako and Chameleon Template Renderings
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+- The Mako renderer now supports using a def name in an asset spec. When the
+ def name is present in the asset spec, the system will render the template
+ named def within the template instead of rendering the entire template. An
+ example asset spec which names a def is
+ ``package:path/to/template#defname.mako``. This will render the def named
+ ``defname`` inside the ``template.mako`` template instead of rendering the
+ entire template. The old way of returning a tuple in the form
+ ``('defname', {})`` from the view is supported for backward compatibility.
+
+- The Chameleon ZPT renderer now supports using a macro name in an asset
+ spec. When the macro name is present in the asset spec, the system will
+ render the macro listed as a ``define-macro`` and return the result instead
+ of rendering the entire template. An example asset spec:
+ ``package:path/to/template#macroname.pt``. This will render the macro
+ defined as ``macroname`` within the ``template.pt`` template instead of the
+ entire templae.
+
+Subrequest Support
+~~~~~~~~~~~~~~~~~~
+
+- Developers may invoke a subrequest by using the
+ :meth:`pyramid.request.Request.invoke_subrequest` API. This allows a
+ developer to obtain a response from one view callable by issuing a subrequest
+ from within a different view callable. See :ref:`subrequest_chapter` for
+ more information.
+
+Minor Feature Additions
+-----------------------
+
+- :meth:`pyramid.config.Configurator.add_directive` now accepts arbitrary
+ callables like partials or objects implementing ``__call__`` which dont
+ have ``__name__`` and ``__doc__`` attributes. See
+ https://github.com/Pylons/pyramid/issues/621 and
+ https://github.com/Pylons/pyramid/pull/647.
+
+- As of this release, the ``request_method`` view/route predicate, when used,
+ will also imply that ``HEAD`` is implied when you use ``GET``. For
+ example, using ``@view_config(request_method='GET')`` is equivalent to
+ using ``@view_config(request_method=('GET', 'HEAD'))``. Using
+ ``@view_config(request_method=('GET', 'POST')`` is equivalent to using
+ ``@view_config(request_method=('GET', 'HEAD', 'POST')``. This is because
+ HEAD is a variant of GET that omits the body, and WebOb has special support
+ to return an empty body when a HEAD is used.
+
+- :meth:`pyramid.config.Configurator.add_request_method` has been introduced
+ to support extending request objects with arbitrary callables. This method
+ expands on the previous
+ :meth:`pyramid.config.Configurator.set_request_property` by supporting
+ methods as well as properties. This method causes less code to be executed
+ at request construction time than
+ :meth:`~pyramid.config.Configurator.set_request_property`.
+
+- The static view machinery now raises rather than returns
+ :class:`pyramid.httpexceptions.HTTPNotFound` and
+ :class:`pyramid.httpexceptions.HTTPMovedPermanently` exceptions, so these can
+ be caught by the notfound view (and other exception views).
+
+- When there is a predicate mismatch exception (seen when no view matches for
+ a given request due to predicates not working), the exception now contains
+ a textual description of the predicate which didn't match.
+
+- An :meth:`pyramid.config.Configurator.add_permission` directive method was
+ added to the Configurator. This directive registers a free-standing
+ permission introspectable into the Pyramid introspection system.
+ Frameworks built atop Pyramid can thus use the the ``permissions``
+ introspectable category data to build a comprehensive list of permissions
+ supported by a running system. Before this method was added, permissions
+ were already registered in this introspectable category as a side effect of
+ naming them in an :meth:`pyramid.config.Configurator.add_view` call, this
+ method just makes it possible to arrange for a permission to be put into
+ the ``permissions`` introspectable category without naming it along with an
+ associated view. Here's an example of usage of ``add_permission``::
+
+ config = Configurator()
+ config.add_permission('view')
+
+- The :func:`pyramid.session.UnencryptedCookieSessionFactoryConfig` function
+ now accepts ``signed_serialize`` and ``signed_deserialize`` hooks which may
+ be used to influence how the sessions are marshalled (by default this is
+ done with HMAC+pickle).
+
+- :class:`pyramid.testing.DummyRequest` now supports methods supplied by the
+ ``pyramid.util.InstancePropertyMixin`` class such as ``set_property``.
+
+- Request properties and methods added via
+ :meth:`pyramid.config.Configurator.set_request_property` or
+ :meth:`pyramid.config.Configurator.add_request_method` are now available to
+ tweens.
+
+- Request properties and methods added via
+ :meth:`pyramid.config.Configurator.set_request_property` or
+ :meth:`pyramid.config.Configurator.add_request_method` are now available
+ in the request object returned from :func:`pyramid.paster.bootstrap`.
+
+- ``request.context`` of environment request during
+ :func:`pyramid.paster.bootstrap` is now the root object if a context isn't
+ already set on a provided request.
+
+- :class:`pyramid.decorator.reify` is now an API, and was added to
+ the API documentation.
+
+- Added the :func:`pyramid.testing.testConfig` context manager, which can be
+ used to generate a configurator in a test, e.g. ``with
+ testing.testConfig(...):``.
+
+Backwards Incompatibilities
+---------------------------
+
+- The Pyramid router no longer adds the values ``bfg.routes.route`` or
+ ``bfg.routes.matchdict`` to the request's WSGI environment dictionary.
+ These values were docs-deprecated in ``repoze.bfg`` 1.0 (effectively seven
+ minor releases ago). If your code depended on these values, use
+ request.matched_route and request.matchdict instead.
+
+- It is no longer possible to pass an environ dictionary directly to
+ ``pyramid.traversal.ResourceTreeTraverser.__call__`` (aka
+ ``ModelGraphTraverser.__call__``). Instead, you must pass a request
+ object. Passing an environment instead of a request has generated a
+ deprecation warning since Pyramid 1.1.
+
+- Pyramid will no longer work properly if you use the
+ ``webob.request.LegacyRequest`` as a request factory. Instances of the
+ LegacyRequest class have a ``request.path_info`` which return a string.
+ This Pyramid release assumes that ``request.path_info`` will
+ unconditionally be Unicode.
+
+- The functions from ``pyramid.chameleon_zpt`` and ``pyramid.chameleon_text``
+ named ``get_renderer``, ``get_template``, ``render_template``, and
+ ``render_template_to_response`` have been removed. These have issued a
+ deprecation warning upon import since Pyramid 1.0. Use
+ :func:`pyramid.renderers.get_renderer`,
+ ``pyramid.renderers.get_renderer().implementation()``,
+ :func:`pyramid.renderers.render` or
+ :func:`pyramid.renderers.render_to_response` respectively instead of these
+ functions.
+
+- The ``pyramid.configuration`` module was removed. It had been deprecated
+ since Pyramid 1.0 and printed a deprecation warning upon its use. Use
+ :mod:`pyramid.config` instead.
+
+- The ``pyramid.paster.PyramidTemplate`` API was removed. It had been
+ deprecated since Pyramid 1.1 and issued a warning on import. If your code
+ depended on this, adjust your code to import
+ :class:`pyramid.scaffolds.PyramidTemplate` instead.
+
+- The ``pyramid.settings.get_settings()`` API was removed. It had been
+ printing a deprecation warning since Pyramid 1.0. If your code depended on
+ this API, use ``pyramid.threadlocal.get_current_registry().settings``
+ instead or use the ``settings`` attribute of the registry available from
+ the request (``request.registry.settings``).
+
+- These APIs from the ``pyramid.testing`` module were removed. They have
+ been printing deprecation warnings since Pyramid 1.0:
+
+ * ``registerDummySecurityPolicy``, use
+ :meth:`pyramid.config.Configurator.testing_securitypolicy` instead.
+
+ * ``registerResources`` (aka ``registerModels``), use
+ :meth:`pyramid.config.Configurator.testing_resources` instead.
+
+ * ``registerEventListener``, use
+ :meth:`pyramid.config.Configurator.testing_add_subscriber` instead.
+
+ * ``registerTemplateRenderer`` (aka `registerDummyRenderer``), use
+ :meth:`pyramid.config.Configurator.testing_add_template` instead.
+
+ * ``registerView``, use :meth:`pyramid.config.Configurator.add_view` instead.
+
+ * ``registerUtility``, use
+ :meth:`pyramid.config.Configurator.registry.registerUtility` instead.
+
+ * ``registerAdapter``, use
+ :meth:`pyramid.config.Configurator.registry.registerAdapter` instead.
+
+ * ``registerSubscriber``, use
+ :meth:`pyramid.config.Configurator.add_subscriber` instead.
+
+ * ``registerRoute``, use
+ :meth:`pyramid.config.Configurator.add_route` instead.
+
+ * ``registerSettings``, use
+ :meth:`pyramid.config.Configurator.add_settings` instead.
+
+- In Pyramid 1.3 and previous, the ``__call__`` method of a Response object
+ returned by a view was invoked before any finished callbacks were executed.
+ As of this release, the ``__call__`` method of a Response object is invoked
+ *after* finished callbacks are executed. This is in support of the
+ :meth:`pyramid.request.Request.invoke_subrequest` feature.
+
+Deprecations
+------------
+
+- The :meth:`pyramid.config.Configurator.set_request_property` directive has
+ been documentation-deprecated. The method remains usable but the more
+ featureful :meth:`pyramid.config.Configurator.add_request_method` should be
+ used in its place (it has all of the same capabilities but can also extend
+ the request object with methods).
+
+Documentation Enhancements
+--------------------------
+
+- Added an :ref:`upgrading_chapter` chapter to the narrative documentation.
+ It describes how to cope with deprecations and removals of Pyramid APIs and
+ how to show Pyramid-generated deprecation warnings while running tests and
+ while running a server.
+
+- Added a :ref:`subrequest_chapter` chapter to the narrative documentation.
+
+- Many cleanups and improvements to narrative and API docs.
+
+Dependency Changes
+------------------
+
+- Pyramid now requires WebOb 1.2b3+ (the prior Pyramid release only relied on
+ 1.2dev+). This is to ensure that we obtain a version of WebOb that returns
+ ``request.path_info`` as text.
+